From 4c85efff2ed5d3c6fcec38a52b7098a68b951288 Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Thu, 21 Mar 2013 17:18:58 +0100 Subject: [PATCH] OO-535: lof of works on list, metadatas, import and export especially QTI 1.2, previews... --- .../securitygroup/gui/GroupController.java | 11 +- .../SecurityGroupMembershipImpl.java | 2 + .../_content/editTermAndSynonym_old.html | 53 - .../persistence/_spring/core_persistence.xml | 7 + .../impl/elements/FileElementImpl.java | 2 +- .../impl/elements/FileElementRenderer.java | 2 - .../impl/elements/IntegerElementImpl.java | 8 +- .../MultipleSelectionElementImpl.java | 4 +- .../_static/js/jscripts/movieviewer.js | 12 +- .../elements/table/BooleanCellRenderer.java | 54 + .../table/CSSIconFlexiCellRenderer.java | 16 +- .../table/DefaultFlexiColumnModel.java | 13 +- .../table/StaticFlexiCellRenderer.java | 30 +- .../table/StaticFlexiColumnModel.java | 18 + .../elements/table/TextFlexiCellRenderer.java | 2 +- .../rules/FormItemDependencyRuleImpl.java | 4 +- .../olat/core/logging/AssertException.java | 2 + .../olat/core/logging/DBRuntimeException.java | 3 +- .../core/logging/KnownIssueException.java | 1 + .../java/org/olat/core/logging/LogHelper.java | 109 -- .../core/logging/OLATRuntimeException.java | 1 + .../java/org/olat/core/util/ImageInfo.java | 1167 ----------------- .../org/olat/core/util/i18n/I18nManager.java | 4 + ...TranslationInterceptHandlerController.java | 2 +- ...lationToolI18nItemEditCrumbController.java | 14 +- .../_content/translationToolI18nItemEdit.html | 46 +- .../org/olat/core/util/vfs/VFSManager.java | 31 + .../org/olat/core/util/vfs/VFSTestMain.java | 203 --- .../filters/VFSItemExcludePrefixFilter.java | 10 +- .../util/vfs/filters/VFSItemSuffixFilter.java | 10 +- .../olat/ims/qti/QTI12MetadataController.java | 125 ++ .../olat/ims/qti/QTI12PreviewController.java | 15 +- .../java/org/olat/ims/qti/QTIConstants.java | 9 + .../olat/ims/qti/_content/qti_metadatas.html | 34 + .../olat/ims/qti/_content/qti_preview.html | 11 + .../ims/qti/qpool/QTIExportProcessor.java | 274 +++- .../ims/qti/qpool/QTIImportProcessor.java | 89 +- .../qti/qpool/QTIQPoolServiceProvider.java | 34 +- .../java/org/olat/modules/qpool/Pool.java | 4 + .../java/org/olat/modules/qpool/QPoolSPI.java | 7 + .../org/olat/modules/qpool/QPoolService.java | 92 +- .../org/olat/modules/qpool/QuestionItem.java | 11 +- .../olat/modules/qpool/QuestionItemShort.java | 6 +- .../PoolRow.java => QuestionItemView.java} | 25 +- .../manager/AbstractQPoolServiceProvider.java | 10 +- .../modules/qpool/manager/CollectionDAO.java | 13 +- .../modules/qpool/manager/LOMConverter.java | 106 ++ .../qpool/manager/NullPoolService.java | 18 +- .../olat/modules/qpool/manager/PoolDAO.java | 57 +- .../qpool/manager/QEducationalContextDAO.java | 87 ++ .../modules/qpool/manager/QItemTypeDAO.java | 111 ++ .../modules/qpool/manager/QLicenseDAO.java | 116 ++ .../qpool/manager/QuestionItemDAO.java | 126 +- .../manager/QuestionItemDocumentFactory.java | 15 +- .../manager/QuestionPoolServiceImpl.java | 270 ++-- .../modules/qpool/model/AuthorItemView.java | 346 +++++ .../olat/modules/qpool/model/ItemView.java | 337 +++++ .../olat/modules/qpool/model/LOMDuration.java | 87 ++ .../modules/qpool/model/PoolItemView.java | 351 +++++ .../qpool/model/QEducationalContext.java | 126 ++ .../olat/modules/qpool/model/QItemType.java | 126 ++ .../olat/modules/qpool/model/QLicense.java | 138 ++ .../modules/qpool/model/QuestionItemImpl.java | 58 +- .../modules/qpool/model/SharedItemView.java | 351 +++++ .../org/olat/modules/qpool/ui/ItemRow.java | 39 +- .../modules/qpool/ui/MetadatasController.java | 19 +- .../olat/modules/qpool/ui/PoolDataModel.java | 139 -- .../org/olat/modules/qpool/ui/QItemEvent.java | 8 +- .../qpool/ui/QuestionItemDataModel.java | 15 +- .../ui/QuestionItemDetailsController.java | 10 +- .../ui/QuestionItemSummaryController.java | 15 +- .../modules/qpool/ui/QuestionItemsSource.java | 4 +- .../qpool/ui/QuestionListController.java | 101 +- .../ui/QuestionPoolMainEditorController.java | 62 +- .../modules/qpool/ui/QuestionsController.java | 18 +- .../qpool/ui/ShareItemOptionController.java | 124 ++ .../modules/qpool/ui/_content/item_list.html | 1 + .../qpool/ui/_content/share_options.html | 3 + .../qpool/ui/_i18n/LocalStrings_de.properties | 15 +- .../qpool/ui/_i18n/LocalStrings_en.properties | 10 +- .../ui/{ => admin}/PoolEditController.java | 35 +- .../ui/{ => admin}/PoolsAdminController.java | 176 ++- .../QEducationalContextEditController.java | 105 ++ .../QEducationalContextsAdminController.java | 308 +++++ .../ui/admin/QItemTypeEditController.java | 105 ++ .../ui/admin/QItemTypesAdminController.java | 308 +++++ .../ui/admin/QLicenseEditController.java | 105 ++ .../ui/admin/QLicensesAdminController.java | 258 ++++ .../qpool/ui/admin/_content/levels_admin.html | 14 + .../ui/admin/_content/licenses_admin.html | 14 + .../ui/{ => admin}/_content/pools_admin.html | 0 .../qpool/ui/admin/_content/types_admin.html | 14 + .../ui/admin/_i18n/LocalStrings_de.properties | 18 + .../ui/admin/_i18n/LocalStrings_en.properties | 2 + .../datasource/CollectionOfItemsSource.java | 6 +- .../ui/datasource/MarkedItemsSource.java | 6 +- .../ui/datasource/MyQuestionItemsSource.java | 6 +- .../ui/datasource/PooledItemsSource.java | 4 +- .../ui/datasource/SharedItemsSource.java | 4 +- .../edit/EducationalMetadataController.java | 27 +- .../EducationalMetadataEditController.java | 48 +- .../ui/edit/GeneralMetadataController.java | 21 +- .../edit/GeneralMetadataEditController.java | 105 +- .../ui/edit/LifecycleMetadataController.java | 12 +- .../ui/edit/QuestionMetadataController.java | 21 +- .../edit/QuestionMetadataEditController.java | 23 +- .../ui/edit/RightsMetadataController.java | 21 +- .../ui/edit/RightsMetadataEditController.java | 60 +- .../ui/edit/TechnicalMetadataController.java | 12 +- .../ui/edit/_content/edit_edu_context.html | 1 + .../modules/qpool/ui/edit/_content/view.html | 8 +- .../ui/wizard/ExportOverviewController.java | 58 + .../qpool/ui/wizard/ExportTypeController.java | 58 + .../qpool/ui/wizard/Export_1_TypeStep.java | 61 + .../ui/wizard/Export_2_OverviewStep.java | 56 + .../wizard/_i18n/LocalStrings_de.properties | 4 +- .../database/mysql/alter_8_4_0_to_9_0_0.sql | 169 ++- src/main/resources/ehcache.xml | 129 -- src/main/webapp/static/js/functions.js | 30 +- .../ims/qti/qpool/QTIExportProcessorTest.java | 91 ++ .../ims/qti/qpool/QTIImportProcessorTest.java | 57 +- .../org/olat/ims/qti/qpool/mchc_i_001.xml | 1 + .../qpool/manager/CollectionDAOTest.java | 33 +- .../qpool/manager/LOMConverterTest.java | 48 +- .../modules/qpool/manager/PoolDAOTest.java | 75 +- .../manager/QEducationalContextDAOTest.java | 136 ++ .../qpool/manager/QItemTypeDAOTest.java | 138 ++ .../qpool/manager/QLicenseDAOTest.java | 136 ++ .../qpool/manager/QuestionDAOTest.java | 168 ++- .../manager/QuestionPoolServiceTest.java | 26 +- .../java/org/olat/test/AllTestsJunit4.java | 6 + 131 files changed, 6804 insertions(+), 2532 deletions(-) delete mode 100644 src/main/java/org/olat/core/commons/modules/glossary/_content/editTermAndSynonym_old.html create mode 100644 src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/BooleanCellRenderer.java delete mode 100644 src/main/java/org/olat/core/logging/LogHelper.java delete mode 100644 src/main/java/org/olat/core/util/ImageInfo.java delete mode 100644 src/main/java/org/olat/core/util/vfs/VFSTestMain.java create mode 100644 src/main/java/org/olat/ims/qti/QTI12MetadataController.java create mode 100644 src/main/java/org/olat/ims/qti/_content/qti_metadatas.html create mode 100644 src/main/java/org/olat/ims/qti/_content/qti_preview.html rename src/main/java/org/olat/modules/qpool/{ui/PoolRow.java => QuestionItemView.java} (71%) create mode 100644 src/main/java/org/olat/modules/qpool/manager/QEducationalContextDAO.java create mode 100644 src/main/java/org/olat/modules/qpool/manager/QItemTypeDAO.java create mode 100644 src/main/java/org/olat/modules/qpool/manager/QLicenseDAO.java create mode 100644 src/main/java/org/olat/modules/qpool/model/AuthorItemView.java create mode 100644 src/main/java/org/olat/modules/qpool/model/ItemView.java create mode 100644 src/main/java/org/olat/modules/qpool/model/LOMDuration.java create mode 100644 src/main/java/org/olat/modules/qpool/model/PoolItemView.java create mode 100644 src/main/java/org/olat/modules/qpool/model/QEducationalContext.java create mode 100644 src/main/java/org/olat/modules/qpool/model/QItemType.java create mode 100644 src/main/java/org/olat/modules/qpool/model/QLicense.java create mode 100644 src/main/java/org/olat/modules/qpool/model/SharedItemView.java delete mode 100644 src/main/java/org/olat/modules/qpool/ui/PoolDataModel.java create mode 100644 src/main/java/org/olat/modules/qpool/ui/ShareItemOptionController.java create mode 100644 src/main/java/org/olat/modules/qpool/ui/_content/share_options.html rename src/main/java/org/olat/modules/qpool/ui/{ => admin}/PoolEditController.java (72%) rename src/main/java/org/olat/modules/qpool/ui/{ => admin}/PoolsAdminController.java (55%) create mode 100644 src/main/java/org/olat/modules/qpool/ui/admin/QEducationalContextEditController.java create mode 100644 src/main/java/org/olat/modules/qpool/ui/admin/QEducationalContextsAdminController.java create mode 100644 src/main/java/org/olat/modules/qpool/ui/admin/QItemTypeEditController.java create mode 100644 src/main/java/org/olat/modules/qpool/ui/admin/QItemTypesAdminController.java create mode 100644 src/main/java/org/olat/modules/qpool/ui/admin/QLicenseEditController.java create mode 100644 src/main/java/org/olat/modules/qpool/ui/admin/QLicensesAdminController.java create mode 100644 src/main/java/org/olat/modules/qpool/ui/admin/_content/levels_admin.html create mode 100644 src/main/java/org/olat/modules/qpool/ui/admin/_content/licenses_admin.html rename src/main/java/org/olat/modules/qpool/ui/{ => admin}/_content/pools_admin.html (100%) create mode 100644 src/main/java/org/olat/modules/qpool/ui/admin/_content/types_admin.html create mode 100644 src/main/java/org/olat/modules/qpool/ui/admin/_i18n/LocalStrings_de.properties create mode 100644 src/main/java/org/olat/modules/qpool/ui/admin/_i18n/LocalStrings_en.properties create mode 100644 src/main/java/org/olat/modules/qpool/ui/edit/_content/edit_edu_context.html create mode 100644 src/main/java/org/olat/modules/qpool/ui/wizard/ExportOverviewController.java create mode 100644 src/main/java/org/olat/modules/qpool/ui/wizard/ExportTypeController.java create mode 100644 src/main/java/org/olat/modules/qpool/ui/wizard/Export_1_TypeStep.java create mode 100644 src/main/java/org/olat/modules/qpool/ui/wizard/Export_2_OverviewStep.java delete mode 100644 src/main/resources/ehcache.xml create mode 100644 src/test/java/org/olat/ims/qti/qpool/QTIExportProcessorTest.java create mode 100644 src/test/java/org/olat/ims/qti/qpool/mchc_i_001.xml create mode 100644 src/test/java/org/olat/modules/qpool/manager/QEducationalContextDAOTest.java create mode 100644 src/test/java/org/olat/modules/qpool/manager/QItemTypeDAOTest.java create mode 100644 src/test/java/org/olat/modules/qpool/manager/QLicenseDAOTest.java diff --git a/src/main/java/org/olat/admin/securitygroup/gui/GroupController.java b/src/main/java/org/olat/admin/securitygroup/gui/GroupController.java index 27b0d78034c..88adaec2e40 100644 --- a/src/main/java/org/olat/admin/securitygroup/gui/GroupController.java +++ b/src/main/java/org/olat/admin/securitygroup/gui/GroupController.java @@ -76,7 +76,6 @@ import org.olat.core.util.mail.MailerResult; import org.olat.core.util.mail.MailerWithTemplate; import org.olat.core.util.session.UserSessionManager; import org.olat.group.ui.main.OnlineIconRenderer; -import org.olat.group.ui.main.MemberListTableModel.Cols; import org.olat.instantMessaging.InstantMessagingModule; import org.olat.instantMessaging.InstantMessagingService; import org.olat.instantMessaging.OpenInstantMessageEvent; @@ -145,6 +144,8 @@ public class GroupController extends BasicController { private InstantMessagingModule imModule; private InstantMessagingService imService; private UserSessionManager sessionManager; + + public Object userObject; /** * @param ureq @@ -218,6 +219,14 @@ public class GroupController extends BasicController { putInitialPanel(groupmemberview); } + public Object getUserObject() { + return userObject; + } + + public void setUserObject(Object userObject) { + this.userObject = userObject; + } + /** * @param addUserMailDefaultTempl Set a template to send mail when adding * users to group diff --git a/src/main/java/org/olat/basesecurity/SecurityGroupMembershipImpl.java b/src/main/java/org/olat/basesecurity/SecurityGroupMembershipImpl.java index 42540917b57..ce564070b97 100644 --- a/src/main/java/org/olat/basesecurity/SecurityGroupMembershipImpl.java +++ b/src/main/java/org/olat/basesecurity/SecurityGroupMembershipImpl.java @@ -37,6 +37,8 @@ import org.olat.core.id.ModifiedInfo; * @author Felix Jost */ public class SecurityGroupMembershipImpl extends PersistentObject implements ModifiedInfo { + private static final long serialVersionUID = 2466302280763907357L; + private Identity identity; private SecurityGroup securityGroup; private Date lastModified; diff --git a/src/main/java/org/olat/core/commons/modules/glossary/_content/editTermAndSynonym_old.html b/src/main/java/org/olat/core/commons/modules/glossary/_content/editTermAndSynonym_old.html deleted file mode 100644 index c0e023ddd75..00000000000 --- a/src/main/java/org/olat/core/commons/modules/glossary/_content/editTermAndSynonym_old.html +++ /dev/null @@ -1,53 +0,0 @@ -<fieldset> - <legend>$r.translate("glossary.form.glossaryKey")</legend> - $r.render("termLayout") -</fieldset> - -<br/><br/> - -<fieldset> - <legend>$r.translate("synonym.add")</legend> - <p>$r.translate("synonym.intro")</p> - <table> - <tbody> - #foreach ($synonym in $glossItemSynonyms) - <tr> - <td>$r.render("synonym.$velocityCount")</td> - <td>$r.render("delete.synonym.$velocityCount")</td> - </tr> - #end - <tr> - <td>$r.render("synonym.inputfield")</td> - <td></td> - </tr> - </tbody> - </table> - - <br/> - $r.render("synonym.button") -</fieldset> - - -<script type="text/javascript"> -/* <![CDATA[ */ -//FIXME:FG:6.2: Implement Java way of setting flexi form link buttons dirty on change -function b_SetTermSaveLinkDirty() { - var save=$("$f.getItemId("form.submit")"); - if (!save.hasClassName('b_button_dirty')) { - save.addClassName('b_button_dirty'); - } -} -$("$f.getItemId("glossTerm.inputfield")").observe("keyup", b_SetTermSaveLinkDirty); - -function b_SetSynonymSaveLinkDirty() { - var save=$("$f.getItemId("synonym.button")"); - if (!save.hasClassName('b_button_dirty')) { - save.addClassName('b_button_dirty'); - } -} -#foreach ($synonym in $glossItemSynonyms) - $("$f.getItemId("synonym.$velocityCount")").observe("keyup", b_SetSynonymSaveLinkDirty); -#end - -/* ]]> */ -</script> \ No newline at end of file diff --git a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml index ac4478a8eba..812e17d32f6 100644 --- a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml +++ b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml @@ -97,12 +97,19 @@ <class>org.olat.instantMessaging.model.InstantMessageNotificationImpl</class> <class>org.olat.modules.qpool.model.PoolImpl</class> <class>org.olat.modules.qpool.model.PoolToItem</class> + <class>org.olat.modules.qpool.model.PoolItemView</class> + <class>org.olat.modules.qpool.model.AuthorItemView</class> + <class>org.olat.modules.qpool.model.ItemView</class> <class>org.olat.modules.qpool.model.QuestionItemImpl</class> + <class>org.olat.modules.qpool.model.SharedItemView</class> <class>org.olat.modules.qpool.model.ResourceShareImpl</class> <class>org.olat.modules.qpool.model.TaxonomyLevelImpl</class> <class>org.olat.modules.qpool.model.ResourceShareImpl</class> <class>org.olat.modules.qpool.model.ItemCollectionImpl</class> <class>org.olat.modules.qpool.model.CollectionToItem</class> + <class>org.olat.modules.qpool.model.QEducationalContext</class> + <class>org.olat.modules.qpool.model.QItemType</class> + <class>org.olat.modules.qpool.model.QLicense</class> <properties> <property name="hibernate.generate_statistics" value="true"/> <property name="hibernate.archive.autodetection" value=""/> diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/FileElementImpl.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/FileElementImpl.java index 63db270ae1a..6497c8a1bc1 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/FileElementImpl.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/FileElementImpl.java @@ -167,7 +167,7 @@ public class FileElementImpl extends FormItemImpl implements FileElement, Dispos /** * @see org.olat.core.gui.components.form.flexible.impl.FormItemImpl#validate(java.util.List) */ - public void validate(List validationResults) { + public void validate(List<ValidationStatus> validationResults) { int lastFormError = getRootForm().getLastRequestError(); if (lastFormError == Form.REQUEST_ERROR_UPLOAD_LIMIT_EXCEEDED) { // check if total upload limit is exceeded (e.g. sum of files) diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/FileElementRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/FileElementRenderer.java index 57af613912d..3cec1c158fd 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/FileElementRenderer.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/FileElementRenderer.java @@ -21,8 +21,6 @@ package org.olat.core.gui.components.form.flexible.impl.elements; import java.io.File; -import java.util.Iterator; -import java.util.Set; import org.apache.commons.lang.StringEscapeUtils; import org.olat.core.defaults.dispatcher.StaticMediaDispatcher; diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/IntegerElementImpl.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/IntegerElementImpl.java index bd3de85a3b9..e171aa0c513 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/IntegerElementImpl.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/IntegerElementImpl.java @@ -26,6 +26,7 @@ package org.olat.core.gui.components.form.flexible.impl.elements; import java.util.ArrayList; +import java.util.List; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormBaseComponentIdProvider; @@ -149,7 +150,7 @@ public class IntegerElementImpl extends TextElementImpl implements //validate the inline element to check for error transientValue = getValue(); super.setValue(paramVal); - validate(new ArrayList()); + validate(new ArrayList<ValidationStatus>()); if(hasError()){ //in any case, if an error is there -> set Inline Editing on isInlineEditingOn(true); @@ -186,15 +187,13 @@ public class IntegerElementImpl extends TextElementImpl implements * @see org.olat.core.gui.components.form.flexible.impl.elements.AbstractTextElement#setValue(java.lang.String) */ @Override - @SuppressWarnings("unused") public void setValue(String value) { throw new AssertException( "Please use setIntValue for an IntegerElement!"); } @Override - @SuppressWarnings("unchecked") - public void validate(java.util.List validationResults) { + public void validate(List<ValidationStatus> validationResults) { // super.validate(validationResults); if (hasError()) { @@ -240,7 +239,6 @@ public class IntegerElementImpl extends TextElementImpl implements } @Override - @SuppressWarnings("unused") public void setIsEqualCheck(String otherValue, String errorKey) { throw new AssertException( "Please use setIsEqualCheck(int otherValue, String errorKey) for an IntegerElement!"); diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/MultipleSelectionElementImpl.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/MultipleSelectionElementImpl.java index 7aade4d9f22..19c30d69443 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/MultipleSelectionElementImpl.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/MultipleSelectionElementImpl.java @@ -40,6 +40,7 @@ import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.logging.AssertException; import org.olat.core.logging.Tracing; import org.olat.core.util.Util; +import org.olat.core.util.ValidationStatus; /** * Description:<br> @@ -226,8 +227,7 @@ public class MultipleSelectionElementImpl extends FormItemImpl implements Multip } @Override - @SuppressWarnings("unused") - public void validate(List validationResults) { + public void validate(List<ValidationStatus> validationResults) { // no constraint to be checked } diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/plugins/olatmovieviewer/_static/js/jscripts/movieviewer.js b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/plugins/olatmovieviewer/_static/js/jscripts/movieviewer.js index 125cf075414..1b29b2e1dbb 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/plugins/olatmovieviewer/_static/js/jscripts/movieviewer.js +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/plugins/olatmovieviewer/_static/js/jscripts/movieviewer.js @@ -216,13 +216,13 @@ function generatePreview() { var address = document.getElementById('address'); var browserLink = document.getElementById('srcbrowser_link'); if(pl.provider == "rtmp" || pl.provider == "http") { - streaming.style.display = ""; - browserLink.style.display = "none"; - address.style.width = '300px'; + jQuery(streaming).css('display',''); + jQuery(browserLink).css('display','none'); + jQuery(address).width(300); } else { - streaming.style.display = "none"; - browserLink.style.display = ""; - address.style.width = '280px'; + jQuery(streaming).css('display','none'); + jQuery(browserLink).css('display',''); + jQuery(address).width(280); } return; } diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/BooleanCellRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/BooleanCellRenderer.java new file mode 100644 index 00000000000..3c4f86e13fd --- /dev/null +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/BooleanCellRenderer.java @@ -0,0 +1,54 @@ +/** + * <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.core.gui.components.form.flexible.impl.elements.table; + +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.translator.Translator; + +/** + * + * Delegate will be rendered or not. + * + * Initial date: 15.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class BooleanCellRenderer implements FlexiCellRenderer { + + private final FlexiCellRenderer delegate; + private final FlexiCellRenderer delegateAlt; + + public BooleanCellRenderer(FlexiCellRenderer delegate, FlexiCellRenderer delegateAlt) { + this.delegate = delegate; + this.delegateAlt = delegateAlt; + } + + @Override + public void render(StringOutput target, Object cellValue, int row, FlexiTableComponent source, URLBuilder ubu, Translator translator) { + if(cellValue != null && Boolean.TRUE.equals(cellValue)) { + if(delegate != null) { + delegate.render(target, cellValue, row, source, ubu, translator); + } + } else if(delegateAlt != null) { + delegateAlt.render(target, cellValue, row, source, ubu, translator); + } + } +} diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/CSSIconFlexiCellRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/CSSIconFlexiCellRenderer.java index 6bdd8b5c4de..ed9730b6672 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/CSSIconFlexiCellRenderer.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/CSSIconFlexiCellRenderer.java @@ -58,6 +58,16 @@ import org.olat.core.util.StringHelper; * @author Florian Gnaegi, frentix GmbH, http://www.frentix.com */ public abstract class CSSIconFlexiCellRenderer implements FlexiCellRenderer { + + private FlexiCellRenderer delegate; + + public CSSIconFlexiCellRenderer() { + // + } + + public CSSIconFlexiCellRenderer(FlexiCellRenderer delegate) { + this.delegate = delegate; + } /** * Render Date type with Formatter depending on locale. Render all other types with toString. @@ -76,7 +86,11 @@ public abstract class CSSIconFlexiCellRenderer implements FlexiCellRenderer { target.append(StringEscapeUtils.escapeHtml(hoverText)); } target.append("\">"); - target.append(getCellValue(cellValue)); + if(delegate == null) { + target.append(getCellValue(cellValue)); + } else { + delegate.render(target, cellValue, row, source, ubu, translator); + } target.append("</span>"); } diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DefaultFlexiColumnModel.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DefaultFlexiColumnModel.java index eab508c3e3d..064aacf2ef9 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DefaultFlexiColumnModel.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DefaultFlexiColumnModel.java @@ -36,11 +36,11 @@ public class DefaultFlexiColumnModel implements FlexiColumnModel { private String headerKey; private String columnKey; private int columnIndex; + private String action; private boolean sortable; private String sortedKey; - private int alignment; private FlexiCellRenderer cellRenderer; @@ -48,6 +48,11 @@ public class DefaultFlexiColumnModel implements FlexiColumnModel { this(headerKey, columnIndex, false, null); } + public DefaultFlexiColumnModel(String headerKey, int columnIndex, String action) { + this(headerKey, columnIndex, false, null); + this.action = action; + } + public DefaultFlexiColumnModel(String headerKey, int columnIndex, boolean sortable, String sortKey) { this(headerKey, columnIndex, sortable, sortKey, FlexiColumnModel.ALIGNMENT_LEFT, new TextFlexiCellRenderer()); } @@ -64,7 +69,11 @@ public class DefaultFlexiColumnModel implements FlexiColumnModel { @Override public String getAction() { - return null; + return action; + } + + public void setAction(String action) { + this.action = action; } @Override diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/StaticFlexiCellRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/StaticFlexiCellRenderer.java index a0335de004b..101895fb303 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/StaticFlexiCellRenderer.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/StaticFlexiCellRenderer.java @@ -38,10 +38,22 @@ public class StaticFlexiCellRenderer implements FlexiCellRenderer { private String label; private String action; + private String cssClass; + private FlexiCellRenderer labelDelegate; public StaticFlexiCellRenderer(String label, String action) { + this(label, action, null); + } + + public StaticFlexiCellRenderer(String label, String action, String cssClass) { this.label = label; this.action = action; + this.cssClass = cssClass; + } + + public StaticFlexiCellRenderer(String action, FlexiCellRenderer labelDelegate) { + this.labelDelegate = labelDelegate; + this.action = action; } /** @@ -57,13 +69,25 @@ public class StaticFlexiCellRenderer implements FlexiCellRenderer { String action = getAction(); if(StringHelper.containsNonWhitespace(action)) { FlexiTableElementImpl ftE = source.getFlexiTableElement(); - String id =source.getFormDispatchId(); + String id = source.getFormDispatchId(); Form rootForm = ftE.getRootForm(); NameValuePair pair = new NameValuePair(action, Integer.toString(row)); String jsCode = FormJSHelper.getXHRFnCallFor(rootForm, id, 1, pair); - target.append("<a href=\"javascript:").append(jsCode).append("\">").append(getLabel()).append("</a>"); - } else { + target.append("<a href=\"javascript:").append(jsCode).append("\""); + if(StringHelper.containsNonWhitespace(cssClass)) { + target.append(" class=\"").append(cssClass).append("\""); + } + target.append(">"); + if(labelDelegate == null) { + target.append(getLabel()); + } else { + labelDelegate.render(target, cellValue, row, source, ubu, translator); + } + target.append("</a>"); + } else if(labelDelegate == null) { target.append(getLabel()); + } else { + labelDelegate.render(target, cellValue, row, source, ubu, translator); } } diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/StaticFlexiColumnModel.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/StaticFlexiColumnModel.java index e841f8c661e..5a464362a5d 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/StaticFlexiColumnModel.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/StaticFlexiColumnModel.java @@ -29,10 +29,28 @@ public class StaticFlexiColumnModel extends AbstractFlexiColumnModel { private final String action; + /** + * Used the standard renderer + * @param headerKey + * @param label + * @param action + */ public StaticFlexiColumnModel(String headerKey, String label, String action) { super(headerKey, -1, FlexiColumnModel.ALIGNMENT_LEFT, new StaticFlexiCellRenderer(label, action)); this.action = action; } + + /** + * Use a custom renderer + * @param headerKey + * @param columnIndex + * @param action + * @param renderer + */ + public StaticFlexiColumnModel(String headerKey, int columnIndex, String action, FlexiCellRenderer renderer) { + super(headerKey, columnIndex, FlexiColumnModel.ALIGNMENT_LEFT, renderer); + this.action = action; + } @Override public String getAction() { diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/TextFlexiCellRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/TextFlexiCellRenderer.java index 3b6a5e22522..c01756fe3a2 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/TextFlexiCellRenderer.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/TextFlexiCellRenderer.java @@ -37,7 +37,7 @@ import org.olat.core.util.Formatter; * Render value with toString. Render Date value with Formatter depending on locale. * @author Christian Guretzki */ -class TextFlexiCellRenderer implements FlexiCellRenderer { +public class TextFlexiCellRenderer implements FlexiCellRenderer { /** * Render Date type with Formatter depending on locale. Render all other types with toString. diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/rules/FormItemDependencyRuleImpl.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/rules/FormItemDependencyRuleImpl.java index 7520b9d5b06..eca2dedef80 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/rules/FormItemDependencyRuleImpl.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/rules/FormItemDependencyRuleImpl.java @@ -92,8 +92,8 @@ public abstract class FormItemDependencyRuleImpl implements FormItemDependencyRu if (actiontype == FormItemDependencyRuleImpl.CUSTOM) { applayable.apply(triggerElement, triggerVal, targets); } else { - for (Iterator iter = targets.iterator(); iter.hasNext();) { - FormItem element = (FormItem) iter.next(); + for (Iterator<FormItem> iter = targets.iterator(); iter.hasNext();) { + FormItem element = iter.next(); switch (actiontype) { case FormItemDependencyRuleImpl.MAKE_INVISIBLE: element.setVisible(false); diff --git a/src/main/java/org/olat/core/logging/AssertException.java b/src/main/java/org/olat/core/logging/AssertException.java index dee867d6808..143e55be260 100644 --- a/src/main/java/org/olat/core/logging/AssertException.java +++ b/src/main/java/org/olat/core/logging/AssertException.java @@ -34,6 +34,8 @@ package org.olat.core.logging; */ public class AssertException extends OLATRuntimeException { + private static final long serialVersionUID = -1358866897360073605L; + /** * Includes throwable. * @param logMsg diff --git a/src/main/java/org/olat/core/logging/DBRuntimeException.java b/src/main/java/org/olat/core/logging/DBRuntimeException.java index d90c6eff2b2..24a2e09b04b 100644 --- a/src/main/java/org/olat/core/logging/DBRuntimeException.java +++ b/src/main/java/org/olat/core/logging/DBRuntimeException.java @@ -34,7 +34,8 @@ package org.olat.core.logging; * */ public class DBRuntimeException extends OLATRuntimeException { - + + private static final long serialVersionUID = 3380967499323008264L; /** * @param logMsg diff --git a/src/main/java/org/olat/core/logging/KnownIssueException.java b/src/main/java/org/olat/core/logging/KnownIssueException.java index d4887056b11..3664c3b02de 100644 --- a/src/main/java/org/olat/core/logging/KnownIssueException.java +++ b/src/main/java/org/olat/core/logging/KnownIssueException.java @@ -38,6 +38,7 @@ package org.olat.core.logging; */ public class KnownIssueException extends OLATRuntimeException { + private static final long serialVersionUID = -2238916925857721010L; private int jiraNumber; /** diff --git a/src/main/java/org/olat/core/logging/LogHelper.java b/src/main/java/org/olat/core/logging/LogHelper.java deleted file mode 100644 index a3016a8c504..00000000000 --- a/src/main/java/org/olat/core/logging/LogHelper.java +++ /dev/null @@ -1,109 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <p> -* Licensed under the Apache License, Version 2.0 (the "License"); <br> -* you may not use this file except in compliance with the License.<br> -* You may obtain a copy of the License at -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <p> -* Unless required by applicable law or agreed to in writing,<br> -* software distributed under the License is distributed on an "AS IS" BASIS, <br> -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> -* See the License for the specific language governing permissions and <br> -* limitations under the License. -* <p> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -* <p> -*/ - -package org.olat.core.logging; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.olat.core.util.vfs.LocalFileImpl; -import org.olat.core.util.vfs.VFSLeaf; - -public class LogHelper { - private final static Pattern patWci = Pattern.compile(".*\\[(.*?)\\] DEBUG Window\\$WindowStats.*\\^%\\^ wci:(.*):%%.*"); - private final static Pattern patTime = Pattern.compile("([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]),.*\\[(.*?)\\] DEBUG Window.*\\^%\\^ time total to serve inline:([0-9]+)"); - - /** - * @param args - */ - public static void main(String[] args) { - File lo = new File("c:/tmp/otemp.txt"); - VFSLeaf l = new LocalFileImpl(lo); - VFSLeaf to = new LocalFileImpl(new File("c:/tmp/output.txt")); - System.out.println(buildUsageAndTimeStats(l, to)); - } - - public static String buildUsageAndTimeStats(VFSLeaf logfile, VFSLeaf toFile) { - - try { - //String test = "2006-12-05 07:16:07,605 [TP-Processor15] DEBUG Window$WindowStats - OLAT::DEBUG ^%^ D1207948 ^%^ org.olat.core.gui.components ^%^ adminfj ^%^ 212.203.56.165 ^%^ http://www.olat.unizh.ch/olat/auth/1%3A4%3A58039%3A0%3A0%3Acid%3Asetlevel/?logger=org.olat.core.gui.components.Window&level=debug ^%^ Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.0.8) Gecko/20061025 Firefox/1.5.0.8 ^%^ n/a ^%^ wci:org.olat.core.commons.chiefcontrollers.FullChiefController:org.olat.admin.SystemAdminMainController:org.olat.admin.sysinfo.SysinfoController:%%loglevels%%dsf [TP-Processor15] DEBUG Window$WindowStats - OLAT::DEBUG ^%^ wci:oab.sdf:aasd.dsfdsf:%%dsfdsf "; - //String test = "[TP-Processor15] DEBUG Window - ...i ^%^ time total to serve inline:178"; - int level = 3; - BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(toFile.getOutputStream(false))); - BufferedReader br = new BufferedReader(new InputStreamReader(logfile.getInputStream(), "utf-8")); - String line; - StringBuilder sb = new StringBuilder(); - Map<String,String> temp = new HashMap<String,String>(); - while ((line = br.readLine()) != null) { - // if curline has DEBUG Window$WindowStats -> grep wci:.... part - Matcher m = patWci.matcher(line); - if (m.matches()) { - String procnum = m.group(1); - String wci = m.group(2); - // bla:blu:blö -> if level = 1 -> bla, if 2 -> blu, etc. - String[] cuts = wci.split(":"); - String to = ""; - for (int i = 0; i < cuts.length && i < level; i++) { - to+= cuts[i] + ":"; - } - - temp.put(procnum, to); - } else { - // try second matcher - Matcher mt = patTime.matcher(line); - if (mt.matches()) { - String timestamp = mt.group(1); - String procnum = mt.group(2); - String time = mt.group(3); - // retrieve previously logged wci - String wci = temp.get(procnum); - temp.remove(procnum); - if (wci != null) { - String all = timestamp+";"+time+";"+wci; - //System.out.println(all); - bw.write(all+"\r\n"); - } // else WARN, inconsistent log, maybe in progress of appending - } - } - } - br.close(); - bw.close(); - return sb.toString(); - } catch (IOException e) { - //throw new OLATRuntimeException(LogHelper.class, "error reading OLAT error log at " + logfile.getName(), e); - } - return null; // some i/o error? can that happen since the log is only opened for appending? - } - -} diff --git a/src/main/java/org/olat/core/logging/OLATRuntimeException.java b/src/main/java/org/olat/core/logging/OLATRuntimeException.java index dda7f6a4b1b..d781cfaea45 100644 --- a/src/main/java/org/olat/core/logging/OLATRuntimeException.java +++ b/src/main/java/org/olat/core/logging/OLATRuntimeException.java @@ -28,6 +28,7 @@ package org.olat.core.logging; */ public class OLATRuntimeException extends RuntimeException { + private static final long serialVersionUID = -1627846608356883591L; private String logMsg; private String usrMsgKey; private String usrMsgPackage; diff --git a/src/main/java/org/olat/core/util/ImageInfo.java b/src/main/java/org/olat/core/util/ImageInfo.java deleted file mode 100644 index 1f1f502344e..00000000000 --- a/src/main/java/org/olat/core/util/ImageInfo.java +++ /dev/null @@ -1,1167 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <p> -* Licensed under the Apache License, Version 2.0 (the "License"); <br> -* you may not use this file except in compliance with the License.<br> -* You may obtain a copy of the License at -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <p> -* Unless required by applicable law or agreed to in writing,<br> -* software distributed under the License is distributed on an "AS IS" BASIS, <br> -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> -* See the License for the specific language governing permissions and <br> -* limitations under the License. -* <p> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -* <p> -*/ - -package org.olat.core.util; - - -import java.io.DataInput; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.Vector; - -/** - * ImageInfo.java Version 1.4 A Java class to determine image width, height and - * color depth for a number of image file formats. Written by Marco Schmidt - * <http://www.geocities.com/marcoschmidt.geo/contact.html>. Contributed to the - * Public Domain. Last modification 2003-07-28 - * - * - * Get file format, image resolution, number of bits per pixel and optionally - * number of images, comments and physical resolution from JPEG, GIF, BMP, PCX, - * PNG, IFF, RAS, PBM, PGM, PPM, PSD and SWF files (or input streams). - * <p> - * Use the class like this: - * - * <pre> - * ImageInfo ii = new ImageInfo(); - * ii.setInput(in); // in can be InputStream or RandomAccessFile - * ii.setDetermineImageNumber(true); // default is false - * ii.setCollectComments(true); // default is false - * if (!ii.check()) { - * System.err.println("Not a supported image file format."); - * return; - * } - * System.out.println(ii.getFormatName() + ", " + ii.getMimeType() + ", " + ii.getWidth() + " x " + ii.getHeight() + " pixels, " - * + ii.getBitsPerPixel() + " bits per pixel, " + ii.getNumberOfImages() + " image(s), " + ii.getNumberOfComments() + " comment(s)."); - * </pre> - * - * You can also use this class as a command line program. Call it with a number - * of image file names as parameters: - * - * <pre> - * - * - * java ImageInfo *.jpg *.png *.gif - * - * - * </pre> - * - * or call it without parameters and pipe data to it: - * - * <pre> - * - * - * cat image.jpg | java ImageInfo - * - * - * </pre> - * - * <p> - * Known limitations: - * <ul> - * <li>When the determination of the number of images is turned off, GIF bits - * per pixel are only read from the global header. For some GIFs, local palettes - * change this to a typically larger value. To be certain to get the correct - * color depth, call setDetermineImageNumber(true) before calling check(). The - * complete scan over the GIF file will take additional time.</li> - * <li>Transparency information is not included in the bits per pixel count. - * Actually, it was my decision not to include those bits, so it's a feature! - * ;-)</li> - * </ul> - * <p> - * Requirements: - * <ul> - * <li>Java 1.1 or higher</li> - * </ul> - * <p> - * The latest version can be found at <a - * href="http://www.geocities.com/marcoschmidt.geo/image-info.html">http://www.geocities.com/marcoschmidt.geo/image-info.html - * </a>. - * <p> - * Written by <a href="mailto:marcoschmidt@users.sourceforge.net">Marco Schmidt - * </a>. - * <p> - * This class is contributed to the Public Domain. Use it at your own risk. - * <p> - * Last modification 2003-07-28. - * <p> - * History: - * <ul> - * <li><strong>2001-08-24 </strong> Initial version.</li> - * <li><strong>2001-10-13 </strong> Added support for the file formats BMP and - * PCX.</li> - * <li><strong>2001-10-16 </strong> Fixed bug in read(int[], int, int) that - * returned - * <li><strong>2002-01-22 </strong> Added support for file formats Amiga IFF - * and Sun Raster (RAS).</li> - * <li><strong>2002-01-24 </strong> Added support for file formats Portable - * Bitmap / Graymap / Pixmap (PBM, PGM, PPM) and Adobe Photoshop (PSD). Added - * new method getMimeType() to return the MIME type associated with a particular - * file format.</li> - * <li><strong>2002-03-15 </strong> Added support to recognize number of images - * in file. Only works with GIF. Use {@link #setDetermineImageNumber}with - * <code>true</code> as argument to identify animated GIFs ( - * {@link #getNumberOfImages()}will return a value larger than <code>1</code>). - * </li> - * <li><strong>2002-04-10 </strong> Fixed a bug in the feature 'determine - * number of images in animated GIF' introduced with version 1.1. Thanks to - * Marcelo P. Lima for sending in the bug report. Released as 1.1.1.</li> - * <li><strong>2002-04-18 </strong> Added {@link #setCollectComments(boolean)}. - * That new method lets the user specify whether textual comments are to be - * stored in an internal list when encountered in an input image file / stream. - * Added two methods to return the physical width and height of the image in - * dpi: {@link #getPhysicalWidthDpi()}and {@link #getPhysicalHeightDpi()}. If - * the physical resolution could not be retrieved, these methods return - * <code>-1</code>.</li> - * <li><strong>2002-04-23 </strong> Added support for the new properties - * physical resolution and comments for some formats. Released as 1.2.</li> - * <li><strong>2002-06-17 </strong> Added support for SWF, sent in by Michael - * Aird. Changed checkJpeg() so that other APP markers than APP0 will not lead - * to a failure anymore. Released as 1.3.</li> - * <li><strong>2003-07-28 </strong> Bug fix - skip method now takes return - * values into consideration. Less bytes than necessary may have been skipped, - * leading to flaws in the retrieved information in some cases. Thanks to - * Bernard Bernstein for pointing that out. Released as 1.4.</li> - * </ul> - */ -public class ImageInfo { - /** - * Return value of {@link #getFormat()}for JPEG streams. ImageInfo can - * extract physical resolution and comments from JPEGs (only from APP0 - * headers). Only one image can be stored in a file. - */ - public static final int FORMAT_JPEG = 0; - - /** - * Return value of {@link #getFormat()}for GIF streams. ImageInfo can extract - * comments from GIFs and count the number of images (GIFs with more than one - * image are animations). If you know of a place where GIFs store the physical - * resolution of an image, please <a - * href="http://www.geocities.com/marcoschmidt.geo/contact.html">send me a - * mail </a>! - */ - public static final int FORMAT_GIF = 1; - - /** - * Return value of {@link #getFormat()}for PNG streams. PNG only supports one - * image per file. Both physical resolution and comments can be stored with - * PNG, but ImageInfo is currently not able to extract those. - */ - public static final int FORMAT_PNG = 2; - - /** - * Return value of {@link #getFormat()}for BMP streams. BMP only supports one - * image per file. BMP does not allow for comments. The physical resolution - * can be stored. - * <em>The specification that I have says that the values must be - * interpreted as dots per meter. However, given that I only - * encounter typical dpi values like 72 or 300, I currently - * consider those values dpi. Maybe someone can shed some light - * on this, please send me a mail in that case.</em> - */ - public static final int FORMAT_BMP = 3; - - /** - * Return value of {@link #getFormat()}for PCX streams. PCX does not allow - * for comments or more than one image per file. However, the physical - * resolution can be stored. - */ - public static final int FORMAT_PCX = 4; - - /** - * Return value of {@link #getFormat()}for IFF streams. - */ - public static final int FORMAT_IFF = 5; - - /** - * Return value of {@link #getFormat()}for RAS streams. Sun Raster allows for - * one image per file only and is not able to store physical resolution or - * comments. - */ - public static final int FORMAT_RAS = 6; - - /** Return value of {@link #getFormat()}for PBM streams. */ - public static final int FORMAT_PBM = 7; - - /** Return value of {@link #getFormat()}for PGM streams. */ - public static final int FORMAT_PGM = 8; - - /** Return value of {@link #getFormat()}for PPM streams. */ - public static final int FORMAT_PPM = 9; - - /** Return value of {@link #getFormat()}for PSD streams. */ - public static final int FORMAT_PSD = 10; - - /** Return value of {@link #getFormat()}for SWF (Shockwave) streams. */ - public static final int FORMAT_SWF = 11; - - /** - * <code>COLOR_TYPE_UNKNOWN</code> - */ - public static final int COLOR_TYPE_UNKNOWN = -1; - /** - * <code>COLOR_TYPE_TRUECOLOR_RGB</code> - */ - public static final int COLOR_TYPE_TRUECOLOR_RGB = 0; - /** - * <code>COLOR_TYPE_PALETTED</code> - */ - public static final int COLOR_TYPE_PALETTED = 1; - /** - * <code>COLOR_TYPE_GRAYSCALE</code> - */ - public static final int COLOR_TYPE_GRAYSCALE = 2; - /** - * <code>COLOR_TYPE_BLACK_AND_WHITE</code> - */ - public static final int COLOR_TYPE_BLACK_AND_WHITE = 3; - - /** - * The names of all supported file formats. The FORMAT_xyz int constants can - * be used as index values for this array. - */ - private static final String[] FORMAT_NAMES = { "JPEG", "GIF", "PNG", "BMP", "PCX", "IFF", "RAS", "PBM", "PGM", "PPM", "PSD", "SWF" }; - - /** - * The names of the MIME types for all supported file formats. The FORMAT_xyz - * int constants can be used as index values for this array. - */ - private static final String[] MIME_TYPE_STRINGS = { "image/jpeg", "image/gif", "image/png", "image/bmp", "image/pcx", "image/iff", - "image/ras", "image/x-portable-bitmap", "image/x-portable-graymap", "image/x-portable-pixmap", "image/psd", - "application/x-shockwave-flash" }; - - private int width; - private int height; - private int bitsPerPixel; - private int format; - private InputStream in; - private DataInput din; - private boolean collectComments = true; - private Vector comments; - private boolean determineNumberOfImages; - private int numberOfImages; - private int physicalHeightDpi; - private int physicalWidthDpi; - private int bitBuf; - private int bitPos; - - private void addComment(String s) { - if (comments == null) { - comments = new Vector(); - } - comments.addElement(s); - } - - /** - * Call this method after you have provided an input stream or file using - * {@link #setInput(InputStream)}or {@link #setInput(DataInput)}. If true is - * returned, the file format was known and information on the file's content - * can be retrieved using the various getXyz methods. - * - * @return if information could be retrieved from input - */ - public boolean check() { - format = -1; - width = -1; - height = -1; - bitsPerPixel = -1; - numberOfImages = 1; - physicalHeightDpi = -1; - physicalWidthDpi = -1; - comments = null; - try { - int b1 = read() & 0xff; - int b2 = read() & 0xff; - if (b1 == 0x47 && b2 == 0x49) { - return checkGif(); - } else if (b1 == 0x89 && b2 == 0x50) { - return checkPng(); - } else if (b1 == 0xff && b2 == 0xd8) { - return checkJpeg(); - } else if (b1 == 0x42 && b2 == 0x4d) { - return checkBmp(); - } else if (b1 == 0x0a && b2 < 0x06) { - return checkPcx(); - } else if (b1 == 0x46 && b2 == 0x4f) { - return checkIff(); - } else if (b1 == 0x59 && b2 == 0xa6) { - return checkRas(); - } else if (b1 == 0x50 && b2 >= 0x31 && b2 <= 0x36) { - return checkPnm(b2 - '0'); - } else if (b1 == 0x38 && b2 == 0x42) { - return checkPsd(); - } else if (b1 == 0x46 && b2 == 0x57) { - return checkSwf(); - } else { - return false; - } - } catch (IOException ioe) { - return false; - } - } - - private boolean checkBmp() throws IOException { - byte[] a = new byte[44]; - if (read(a) != a.length) { return false; } - width = getIntLittleEndian(a, 16); - height = getIntLittleEndian(a, 20); - if (width < 1 || height < 1) { return false; } - bitsPerPixel = getShortLittleEndian(a, 26); - if (bitsPerPixel != 1 && bitsPerPixel != 4 && bitsPerPixel != 8 && bitsPerPixel != 16 && bitsPerPixel != 24 && bitsPerPixel != 32) { return false; } - int x = getIntLittleEndian(a, 36); - if (x > 0) { - setPhysicalWidthDpi(x); - } - int y = getIntLittleEndian(a, 40); - if (y > 0) { - setPhysicalHeightDpi(y); - } - format = FORMAT_BMP; - return true; - } - - private boolean checkGif() throws IOException { - final byte[] GIF_MAGIC_87A = { 0x46, 0x38, 0x37, 0x61 }; - final byte[] GIF_MAGIC_89A = { 0x46, 0x38, 0x39, 0x61 }; - byte[] a = new byte[11]; // 4 from the GIF signature + 7 from the global - // header - if (read(a) != 11) { return false; } - if ((!equals(a, 0, GIF_MAGIC_89A, 0, 4)) && (!equals(a, 0, GIF_MAGIC_87A, 0, 4))) { return false; } - format = FORMAT_GIF; - width = getShortLittleEndian(a, 4); - height = getShortLittleEndian(a, 6); - int flags = a[8] & 0xff; - bitsPerPixel = ((flags >> 4) & 0x07) + 1; - if (!determineNumberOfImages) { return true; } - // skip global color palette - if ((flags & 0x80) != 0) { - int tableSize = (1 << ((flags & 7) + 1)) * 3; - skip(tableSize); - } - numberOfImages = 0; - int blockType; - do { - blockType = read(); - switch (blockType) { - case (0x2c): // image separator - { - if (read(a, 0, 9) != 9) { return false; } - flags = a[8] & 0xff; - int localBitsPerPixel = (flags & 0x07) + 1; - if (localBitsPerPixel > bitsPerPixel) { - bitsPerPixel = localBitsPerPixel; - } - if ((flags & 0x80) != 0) { - skip((1 << localBitsPerPixel) * 3); - } - skip(1); // initial code length - int n; - do { - n = read(); - if (n > 0) { - skip(n); - } else if (n == -1) { return false; } - } while (n > 0); - numberOfImages++; - break; - } - case (0x21): // extension - { - int extensionType = read(); - if (collectComments && extensionType == 0xfe) { - StringBuilder sb = new StringBuilder(); - int n; - do { - n = read(); - if (n == -1) { return false; } - if (n > 0) { - for (int i = 0; i < n; i++) { - int ch = read(); - if (ch == -1) { return false; } - sb.append((char) ch); - } - } - } while (n > 0); - } else { - int n; - do { - n = read(); - if (n > 0) { - skip(n); - } else if (n == -1) { return false; } - } while (n > 0); - } - break; - } - case (0x3b): // end of file - { - break; - } - default: { - return false; - } - } - } while (blockType != 0x3b); - return true; - } - - private boolean checkIff() throws IOException { - byte[] a = new byte[10]; - // read remaining 2 bytes of file id, 4 bytes file size - // and 4 bytes IFF subformat - if (read(a, 0, 10) != 10) { return false; } - final byte[] IFF_RM = { 0x52, 0x4d }; - if (!equals(a, 0, IFF_RM, 0, 2)) { return false; } - int type = getIntBigEndian(a, 6); - if (type != 0x494c424d && // type must be ILBM... - type != 0x50424d20) { // ...or PBM - return false; - } - // loop chunks to find BMHD chunk - do { - if (read(a, 0, 8) != 8) { return false; } - int chunkId = getIntBigEndian(a, 0); - int size = getIntBigEndian(a, 4); - if ((size & 1) == 1) { - size++; - } - if (chunkId == 0x424d4844) { // BMHD chunk - if (read(a, 0, 9) != 9) { return false; } - format = FORMAT_IFF; - width = getShortBigEndian(a, 0); - height = getShortBigEndian(a, 2); - bitsPerPixel = a[8] & 0xff; - return (width > 0 && height > 0 && bitsPerPixel > 0 && bitsPerPixel < 33); - } else { - skip(size); - } - } while (true); - } - - private boolean checkJpeg() throws IOException { - byte[] data = new byte[12]; - while (true) { - if (read(data, 0, 4) != 4) { return false; } - int marker = getShortBigEndian(data, 0); - int size = getShortBigEndian(data, 2); - if ((marker & 0xff00) != 0xff00) { return false; // not a valid marker - } - if (marker == 0xffe0) { // APPx - if (size < 14) { return false; // APPx header must be >= 14 bytes - } - if (read(data, 0, 12) != 12) { return false; } - final byte[] APP0_ID = { 0x4a, 0x46, 0x49, 0x46, 0x00 }; - if (equals(APP0_ID, 0, data, 0, 5)) { - //System.out.println("data 7=" + data[7]); - if (data[7] == 1) { - setPhysicalWidthDpi(getShortBigEndian(data, 8)); - setPhysicalHeightDpi(getShortBigEndian(data, 10)); - } else if (data[7] == 2) { - int x = getShortBigEndian(data, 8); - int y = getShortBigEndian(data, 10); - setPhysicalWidthDpi((int) (x * 2.54f)); - setPhysicalHeightDpi((int) (y * 2.54f)); - } - } - skip(size - 14); - } else if (collectComments && size > 2 && marker == 0xfffe) { // comment - size -= 2; - byte[] chars = new byte[size]; - if (read(chars, 0, size) != size) { return false; } - String comment = new String(chars, "iso-8859-1"); - comment = comment.trim(); - //System.out.println(comment); - addComment(comment); - } else if (marker >= 0xffc0 && marker <= 0xffcf && marker != 0xffc4 && marker != 0xffc8) { - if (read(data, 0, 6) != 6) { return false; } - format = FORMAT_JPEG; - bitsPerPixel = (data[0] & 0xff) * (data[5] & 0xff); - width = getShortBigEndian(data, 3); - height = getShortBigEndian(data, 1); - return true; - } else { - skip(size - 2); - } - } - } - - private boolean checkPcx() throws IOException { - byte[] a = new byte[64]; - if (read(a) != a.length) { return false; } - if (a[0] != 1) { // encoding, 1=RLE is only valid value - return false; - } - // width / height - int x1 = getShortLittleEndian(a, 2); - int y1 = getShortLittleEndian(a, 4); - int x2 = getShortLittleEndian(a, 6); - int y2 = getShortLittleEndian(a, 8); - if (x1 < 0 || x2 < x1 || y1 < 0 || y2 < y1) { return false; } - width = x2 - x1 + 1; - height = y2 - y1 + 1; - // color depth - int bits = a[1]; - int planes = a[63]; - if (planes == 1 && (bits == 1 || bits == 2 || bits == 4 || bits == 8)) { - // paletted - bitsPerPixel = bits; - } else if (planes == 3 && bits == 8) { - // RGB truecolor - bitsPerPixel = 24; - } else { - return false; - } - setPhysicalWidthDpi(getShortLittleEndian(a, 10)); - setPhysicalHeightDpi(getShortLittleEndian(a, 10)); - format = FORMAT_PCX; - return true; - } - - private boolean checkPng() throws IOException { - final byte[] PNG_MAGIC = { 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a }; - byte[] a = new byte[24]; - if (read(a) != 24) { return false; } - if (!equals(a, 0, PNG_MAGIC, 0, 6)) { return false; } - format = FORMAT_PNG; - width = getIntBigEndian(a, 14); - height = getIntBigEndian(a, 18); - bitsPerPixel = a[22] & 0xff; - int colorType = a[23] & 0xff; - if (colorType == 2 || colorType == 6) { - bitsPerPixel *= 3; - } - return true; - } - - private boolean checkPnm(int id) throws IOException { - if (id < 1 || id > 6) { return false; } - final int[] PNM_FORMATS = { FORMAT_PBM, FORMAT_PGM, FORMAT_PPM }; - format = PNM_FORMATS[(id - 1) % 3]; - boolean hasPixelResolution = false; - String s; - while (true) { - s = readLine(); - if (s != null) { - s = s.trim(); - } - if (s == null || s.length() < 1) { - continue; - } - if (s.charAt(0) == '#') { // comment - if (collectComments && s.length() > 1) { - addComment(s.substring(1)); - } - continue; - } - if (!hasPixelResolution) { // split "343 966" into width=343, height=966 - int spaceIndex = s.indexOf(' '); - if (spaceIndex == -1) { return false; } - String widthString = s.substring(0, spaceIndex); - spaceIndex = s.lastIndexOf(' '); - if (spaceIndex == -1) { return false; } - String heightString = s.substring(spaceIndex + 1); - try { - width = Integer.parseInt(widthString); - height = Integer.parseInt(heightString); - } catch (NumberFormatException nfe) { - return false; - } - if (width < 1 || height < 1) { return false; } - if (format == FORMAT_PBM) { - bitsPerPixel = 1; - return true; - } - hasPixelResolution = true; - } else { - int maxSample; - try { - maxSample = Integer.parseInt(s); - } catch (NumberFormatException nfe) { - return false; - } - if (maxSample < 0) { return false; } - for (int i = 0; i < 25; i++) { - if (maxSample < (1 << (i + 1))) { - bitsPerPixel = i + 1; - if (format == FORMAT_PPM) { - bitsPerPixel *= 3; - } - return true; - } - } - return false; - } - } - } - - private boolean checkPsd() throws IOException { - byte[] a = new byte[24]; - if (read(a) != a.length) { return false; } - final byte[] PSD_MAGIC = { 0x50, 0x53 }; - if (!equals(a, 0, PSD_MAGIC, 0, 2)) { return false; } - format = FORMAT_PSD; - width = getIntBigEndian(a, 16); - height = getIntBigEndian(a, 12); - int channels = getShortBigEndian(a, 10); - int depth = getShortBigEndian(a, 20); - bitsPerPixel = channels * depth; - return (width > 0 && height > 0 && bitsPerPixel > 0 && bitsPerPixel <= 64); - } - - private boolean checkRas() throws IOException { - byte[] a = new byte[14]; - if (read(a) != a.length) { return false; } - final byte[] RAS_MAGIC = { 0x6a, (byte) 0x95 }; - if (!equals(a, 0, RAS_MAGIC, 0, 2)) { return false; } - format = FORMAT_RAS; - width = getIntBigEndian(a, 2); - height = getIntBigEndian(a, 6); - bitsPerPixel = getIntBigEndian(a, 10); - return (width > 0 && height > 0 && bitsPerPixel > 0 && bitsPerPixel <= 24); - } - - // Written by Michael Aird. - private boolean checkSwf() throws IOException { - //get rid of the last byte of the signature, the byte of the version and 4 - // bytes of the size - byte[] a = new byte[6]; - if (read(a) != a.length) { return false; } - format = FORMAT_SWF; - int bitSize = (int) readUBits(5); - //int minX = (int)readSBits( bitSize ); - int maxX = readSBits(bitSize); - //int minY = (int)readSBits( bitSize ); - int maxY = readSBits(bitSize); - width = maxX / 20; //cause we're in twips - height = maxY / 20; //cause we're in twips - setPhysicalWidthDpi(72); - setPhysicalHeightDpi(72); - return (width > 0 && height > 0); - } - - /** - * Run over String list, return false iff at least one of the arguments equals - * <code>-c</code>. - */ - private static boolean determineVerbosity(String[] args) { - if (args != null && args.length > 0) { - for (int i = 0; i < args.length; i++) { - if ("-c".equals(args[i])) { return false; } - } - } - return true; - } - - private boolean equals(byte[] a1, int offs1, byte[] a2, int offs2, int num) { - while (num-- > 0) { - if (a1[offs1++] != a2[offs2++]) { return false; } - } - return true; - } - - /** - * If {@link #check()}was successful, returns the image's number of bits per - * pixel. Does not include transparency information like the alpha channel. - * - * @return number of bits per image pixel - */ - public int getBitsPerPixel() { - return bitsPerPixel; - } - - /** - * Returns the index'th comment retrieved from the image. - * - * @param index - * @return @throws IllegalArgumentException if index is smaller than 0 or - * larger than or equal to the number of comments retrieved - * @see #getNumberOfComments - */ - public String getComment(int index) { - if (comments == null || index < 0 || index >= comments.size()) { throw new IllegalArgumentException("Not a valid comment index: " - + index); } - return (String) comments.elementAt(index); - } - - /** - * If {@link #check()}was successful, returns the image format as one of the - * FORMAT_xyz constants from this class. Use {@link #getFormatName()}to get a - * textual description of the file format. - * - * @return file format as a FORMAT_xyz constant - */ - public int getFormat() { - return format; - } - - /** - * If {@link #check()}was successful, returns the image format's name. Use - * {@link #getFormat()}to get a unique number. - * - * @return file format name - */ - public String getFormatName() { - if (format >= 0 && format < FORMAT_NAMES.length) { - return FORMAT_NAMES[format]; - } else { - return "?"; - } - } - - /** - * If {@link #check()}was successful, returns one the image's vertical - * resolution in pixels. - * - * @return image height in pixels - */ - public int getHeight() { - return height; - } - - private int getIntBigEndian(byte[] a, int offs) { - return (a[offs] & 0xff) << 24 | (a[offs + 1] & 0xff) << 16 | (a[offs + 2] & 0xff) << 8 | a[offs + 3] & 0xff; - } - - private int getIntLittleEndian(byte[] a, int offs) { - return (a[offs + 3] & 0xff) << 24 | (a[offs + 2] & 0xff) << 16 | (a[offs + 1] & 0xff) << 8 | a[offs] & 0xff; - } - - /** - * If {@link #check()}was successful, returns a String with the MIME type of - * the format. - * - * @return MIME type, e.g. <code>image/jpeg</code> - */ - public String getMimeType() { - if (format >= 0 && format < MIME_TYPE_STRINGS.length) { - return MIME_TYPE_STRINGS[format]; - } else { - return null; - } - } - - /** - * If {@link #check()}was successful and {@link #setCollectComments(boolean)} - * was called with <code>true</code> as argument, returns the number of - * comments retrieved from the input image stream / file. Any number >= 0 - * and smaller than this number of comments is then a valid argument for the - * {@link #getComment(int)}method. - * - * @return number of comments retrieved from input image - */ - public int getNumberOfComments() { - if (comments == null) { - return 0; - } else { - return comments.size(); - } - } - - /** - * Returns the number of images in the examined file. Assumes that - * <code>setDetermineImageNumber(true);</code> was called before a - * successful call to {@link #check()}. This value can currently be only - * different from <code>1</code> for GIF images. - * - * @return number of images in file - */ - public int getNumberOfImages() { - return numberOfImages; - } - - /** - * Returns the physical height of this image in dots per inch (dpi). Assumes - * that {@link #check()}was successful. Returns <code>-1</code> on failure. - * - * @return physical height (in dpi) - * @see #getPhysicalWidthDpi() - * @see #getPhysicalHeightInch() - */ - public int getPhysicalHeightDpi() { - return physicalHeightDpi; - } - - /** - * If {@link #check()}was successful, returns the physical width of this - * image in dpi (dots per inch) or -1 if no value could be found. - * - * @return physical height (in dpi) - * @see #getPhysicalHeightDpi() - * @see #getPhysicalWidthDpi() - * @see #getPhysicalWidthInch() - */ - public float getPhysicalHeightInch() { - int h = getHeight(); - int ph = getPhysicalHeightDpi(); - if (h > 0 && ph > 0) { - return ((float) h) / ((float) ph); - } else { - return -1.0f; - } - } - - /** - * If {@link #check()}was successful, returns the physical width of this - * image in dpi (dots per inch) or -1 if no value could be found. - * - * @return physical width (in dpi) - * @see #getPhysicalHeightDpi() - * @see #getPhysicalWidthInch() - * @see #getPhysicalHeightInch() - */ - public int getPhysicalWidthDpi() { - return physicalWidthDpi; - } - - /** - * Returns the physical width of an image in inches, or <code>-1.0f</code> - * if width information is not available. Assumes that {@link #check}has been - * called successfully. - * - * @return physical width in inches or <code>-1.0f</code> on failure - * @see #getPhysicalWidthDpi - * @see #getPhysicalHeightInch - */ - public float getPhysicalWidthInch() { - int w = getWidth(); - int pw = getPhysicalWidthDpi(); - if (w > 0 && pw > 0) { - return ((float) w) / ((float) pw); - } else { - return -1.0f; - } - } - - private int getShortBigEndian(byte[] a, int offs) { - return (a[offs] & 0xff) << 8 | (a[offs + 1] & 0xff); - } - - private int getShortLittleEndian(byte[] a, int offs) { - return (a[offs] & 0xff) | (a[offs + 1] & 0xff) << 8; - } - - /** - * If {@link #check()}was successful, returns one the image's horizontal - * resolution in pixels. - * - * @return image width in pixels - */ - public int getWidth() { - return width; - } - - /** - * To use this class as a command line application, give it either some file - * names as parameters (information on them will be printed to standard - * output, one line per file) or call it with no parameters. It will then - * check data given to it via standard input. - * - * @param args the program arguments which must be file names - */ - public static void main(String[] args) { - ImageInfo imageInfo = new ImageInfo(); - imageInfo.setDetermineImageNumber(true); - boolean verbose = determineVerbosity(args); - if (args.length == 0) { - run(null, System.in, imageInfo, verbose); - } else { - int index = 0; - while (index < args.length) { - InputStream in = null; - try { - String name = args[index++]; - System.out.print(name + ";"); - if (name.startsWith("http://")) { - in = new URL(name).openConnection().getInputStream(); - } else { - in = new FileInputStream(name); - } - run(name, in, imageInfo, verbose); - in.close(); - } catch (Exception e) { - System.out.println(e); - try { - in.close(); - } catch (Exception ee) { - // - } - } - } - } - } - - private static void print(String sourceName, ImageInfo ii, boolean verbose) { - if (verbose) { - printVerbose(sourceName, ii); - } else { - printCompact(sourceName, ii); - } - } - - private static void printCompact(String sourceName, ImageInfo imageInfo) { - System.out.println(sourceName + ";" + imageInfo.getFormatName() + ";" + imageInfo.getMimeType() + ";" + imageInfo.getWidth() + ";" - + imageInfo.getHeight() + ";" + imageInfo.getBitsPerPixel() + ";" + imageInfo.getNumberOfImages() + ";" - + imageInfo.getPhysicalWidthDpi() + ";" + imageInfo.getPhysicalHeightDpi() + ";" + imageInfo.getPhysicalWidthInch() + ";" - + imageInfo.getPhysicalHeightInch()); - } - - private static void printLine(int indentLevels, String text, float value, float minValidValue) { - if (value < minValidValue) { return; } - printLine(indentLevels, text, Float.toString(value)); - } - - private static void printLine(int indentLevels, String text, int value, int minValidValue) { - if (value >= minValidValue) { - printLine(indentLevels, text, Integer.toString(value)); - } - } - - private static void printLine(int indentLevels, String text, String value) { - if (value == null || value.length() == 0) { return; } - while (indentLevels-- > 0) { - System.out.print("\t"); - } - if (text != null && text.length() > 0) { - System.out.print(text); - System.out.print(" "); - } - System.out.println(value); - } - - private static void printVerbose(String sourceName, ImageInfo ii) { - printLine(0, null, sourceName); - printLine(1, "File format: ", ii.getFormatName()); - printLine(1, "MIME type: ", ii.getMimeType()); - printLine(1, "Width (pixels): ", ii.getWidth(), 1); - printLine(1, "Height (pixels): ", ii.getHeight(), 1); - printLine(1, "Bits per pixel: ", ii.getBitsPerPixel(), 1); - printLine(1, "Number of images: ", ii.getNumberOfImages(), 1); - printLine(1, "Physical width (dpi): ", ii.getPhysicalWidthDpi(), 1); - printLine(1, "Physical height (dpi): ", ii.getPhysicalHeightDpi(), 1); - printLine(1, "Physical width (inches): ", ii.getPhysicalWidthInch(), 1.0f); - printLine(1, "Physical height (inches): ", ii.getPhysicalHeightInch(), 1.0f); - int numComments = ii.getNumberOfComments(); - printLine(1, "Number of textual comments: ", numComments, 1); - if (numComments > 0) { - for (int i = 0; i < numComments; i++) { - printLine(2, null, ii.getComment(i)); - } - } - } - - private int read() throws IOException { - if (in != null) { - return in.read(); - } else { - return din.readByte(); - } - } - - private int read(byte[] a) throws IOException { - if (in != null) { - return in.read(a); - } else { - din.readFully(a); - return a.length; - } - } - - private int read(byte[] a, int offset, int num) throws IOException { - if (in != null) { - return in.read(a, offset, num); - } else { - din.readFully(a, offset, num); - return num; - } - } - - private String readLine() throws IOException { - return readLine(new StringBuilder()); - } - - private String readLine(StringBuilder sb) throws IOException { - boolean finished; - do { - int value = read(); - finished = (value == -1 || value == 10); - if (!finished) { - sb.append((char) value); - } - } while (!finished); - return sb.toString(); - } - - /** - * Read an unsigned value from the given number of bits - * @param numBits - * @return - * @throws IOException - */ - public long readUBits(int numBits) throws IOException { - if (numBits == 0) { return 0; } - int bitsLeft = numBits; - long result = 0; - if (bitPos == 0) { //no value in the buffer - read a byte - if (in != null) { - bitBuf = in.read(); - } else { - bitBuf = din.readByte(); - } - bitPos = 8; - } - - while (true) { - int shift = bitsLeft - bitPos; - if (shift > 0) { - // Consume the entire buffer - result |= bitBuf << shift; - bitsLeft -= bitPos; - - // Get the next byte from the input stream - if (in != null) { - bitBuf = in.read(); - } else { - bitBuf = din.readByte(); - } - bitPos = 8; - } else { - // Consume a portion of the buffer - result |= bitBuf >> -shift; - bitPos -= bitsLeft; - bitBuf &= 0xff >> (8 - bitPos); // mask off the consumed bits - - return result; - } - } - } - - /** - * Read a signed value from the given number of bits - */ - private int readSBits(int numBits) throws IOException { - // Get the number as an unsigned value. - long uBits = readUBits(numBits); - - // Is the number negative? - if ((uBits & (1L << (numBits - 1))) != 0) { - // Yes. Extend the sign. - uBits |= -1L << numBits; - } - - return (int) uBits; - } - - /** - * Reset the bit buffer - */ - public void synchBits() { - bitBuf = 0; - bitPos = 0; - } - - private static void run(String sourceName, InputStream in, ImageInfo imageInfo, boolean verbose) { - imageInfo.setInput(in); - imageInfo.setDetermineImageNumber(false); - imageInfo.setCollectComments(verbose); - if (imageInfo.check()) { - print(sourceName, imageInfo, verbose); - } - } - - /** - * Specify whether textual comments are supposed to be extracted from input. - * Default is <code>false</code>. If enabled, comments will be added to an - * internal list. - * - * @param newValue if <code>true</code>, this class will read comments - * @see #getNumberOfComments - * @see #getComment - */ - public void setCollectComments(boolean newValue) { - collectComments = newValue; - } - - /** - * Specify whether the number of images in a file is to be determined - - * default is <code>false</code>. This is a special option because some - * file formats require running over the entire file to find out the number of - * images, a rather time-consuming task. Not all file formats support more - * than one image. If this method is called with <code>true</code> as - * argument, the actual number of images can be queried via - * {@link #getNumberOfImages()}after a successful call to {@link #check()}. - * - * @param newValue will the number of images be determined? - * @see #getNumberOfImages - */ - public void setDetermineImageNumber(boolean newValue) { - determineNumberOfImages = newValue; - } - - /** - * Set the input stream to the argument stream (or file). Note that - * {@link java.io.RandomAccessFile}implements {@link java.io.DataInput}. - * - * @param dataInput the input stream to read from - */ - public void setInput(DataInput dataInput) { - din = dataInput; - in = null; - } - - /** - * Set the input stream to the argument stream (or file). - * - * @param inputStream the input stream to read from - */ - public void setInput(InputStream inputStream) { - in = inputStream; - din = null; - } - - private void setPhysicalHeightDpi(int newValue) { - physicalWidthDpi = newValue; - } - - private void setPhysicalWidthDpi(int newValue) { - physicalHeightDpi = newValue; - } - - private void skip(int num) throws IOException { - while (num > 0) { - long result; - if (in != null) { - result = in.skip(num); - } else { - result = din.skipBytes(num); - } - if (result > 0) { - num -= result; - } - } - } -} \ No newline at end of file diff --git a/src/main/java/org/olat/core/util/i18n/I18nManager.java b/src/main/java/org/olat/core/util/i18n/I18nManager.java index ed8832d751d..3d32df3ee22 100644 --- a/src/main/java/org/olat/core/util/i18n/I18nManager.java +++ b/src/main/java/org/olat/core/util/i18n/I18nManager.java @@ -1682,6 +1682,10 @@ public class I18nManager extends BasicManager { * @return */ public String getLocaleKey(Locale locale) { + if(locale == null) { + System.out.println(); + } + String langKey = locale.getLanguage(); String country = locale.getCountry(); // Only add country when available - in case of an overlay country is diff --git a/src/main/java/org/olat/core/util/i18n/ui/InlineTranslationInterceptHandlerController.java b/src/main/java/org/olat/core/util/i18n/ui/InlineTranslationInterceptHandlerController.java index 93670bce1b0..7d0152ccc35 100644 --- a/src/main/java/org/olat/core/util/i18n/ui/InlineTranslationInterceptHandlerController.java +++ b/src/main/java/org/olat/core/util/i18n/ui/InlineTranslationInterceptHandlerController.java @@ -114,7 +114,7 @@ public class InlineTranslationInterceptHandlerController extends BasicController public void renderBodyOnLoadJSFunctionCall(Renderer renderer, StringOutput sb, Component source, RenderingState rstate) { // trigger js method that adds hover events - in some conditions method is not available (in iframes) - sb.append("if (jQuery.isFunction(b_attach_i18n_inline_editing)) {b_attach_i18n_inline_editing();}"); + sb.append("if (jQuery.isFunction(b_attach_i18n_inline_editing)){b_attach_i18n_inline_editing();}"); } }); delegatingComponent.addListener(this); diff --git a/src/main/java/org/olat/core/util/i18n/ui/TranslationToolI18nItemEditCrumbController.java b/src/main/java/org/olat/core/util/i18n/ui/TranslationToolI18nItemEditCrumbController.java index 3cf6b391239..72fc2a5673e 100644 --- a/src/main/java/org/olat/core/util/i18n/ui/TranslationToolI18nItemEditCrumbController.java +++ b/src/main/java/org/olat/core/util/i18n/ui/TranslationToolI18nItemEditCrumbController.java @@ -60,7 +60,7 @@ import org.olat.core.util.prefs.Preferences; * @author Florian Gnaegi, frentix GmbH, http://www.frentix.com */ -class TranslationToolI18nItemEditCrumbController extends CrumbFormBasicController { +public class TranslationToolI18nItemEditCrumbController extends CrumbFormBasicController { private Locale referenceLocale; private Locale compareLocale; private List<I18nItem> i18nItems; @@ -241,11 +241,15 @@ class TranslationToolI18nItemEditCrumbController extends CrumbFormBasicControlle annotationArea.setEnabled(false); // target lang flags and lang name Locale origLocale = I18nModule.getAllLocales().get(i18nMgr.createOrigianlLocaleKeyForOverlay(currentItem.getLocale())); - this.flc.contextPut("targetLanguageKey", i18nMgr.getLocaleKey(origLocale)); - this.flc.contextPut("targetLanguage", i18nMgr.getLanguageTranslated(i18nMgr.getLocaleKey(origLocale), true)); + if(origLocale == null) { + origLocale = currentItem.getLocale(); + } + String localeKey = i18nMgr.getLocaleKey(origLocale); + flc.contextPut("targetLanguageKey", localeKey); + flc.contextPut("targetLanguage", i18nMgr.getLanguageTranslated(localeKey, true)); } - this.flc.contextPut("customizingMode", Boolean.valueOf(customizingMode)); - this.flc.contextPut("customizingPrefix", (customizingMode ? "customize." : "")); + flc.contextPut("customizingMode", Boolean.valueOf(customizingMode)); + flc.contextPut("customizingPrefix", (customizingMode ? "customize." : "")); } diff --git a/src/main/java/org/olat/core/util/i18n/ui/_content/translationToolI18nItemEdit.html b/src/main/java/org/olat/core/util/i18n/ui/_content/translationToolI18nItemEdit.html index 15968b4d52b..8815e3d9cda 100644 --- a/src/main/java/org/olat/core/util/i18n/ui/_content/translationToolI18nItemEdit.html +++ b/src/main/java/org/olat/core/util/i18n/ui/_content/translationToolI18nItemEdit.html @@ -68,16 +68,16 @@ //FIXME:FG:6.2: Implement Java way of setting flexi form link buttons dirty on change function b_SetTranslationSaveLinksDirty() { - var save=$("$f.getItemId("saveLink")"); + var save=jQuery("#$f.getItemId("saveLink")"); if (!save.hasClassName('b_button_dirty')) { save.addClassName('b_button_dirty'); #if ($hasNext) - $("$f.getItemId("saveNextLink")").addClassName('b_button_dirty'); + jQuery("#$f.getItemId("saveNextLink")").addClass('b_button_dirty'); #end } } -$("$f.getItemId("targetArea")").observe("keyup", b_SetTranslationSaveLinksDirty); +jQuery("#$f.getItemId("targetArea")").on("keyup", b_SetTranslationSaveLinksDirty); ## Code to check for user click on key references within the textarea fields @@ -88,7 +88,7 @@ $("$f.getItemId("targetArea")").observe("keyup", b_SetTranslationSaveLinksDirty) ## for the given language code function checkClick(wrapperName, langCode) { ## Get content from text area within this wrapper - var area = $$('div.' + wrapperName + ' textarea')[0]; + var area = jQuery('div.' + wrapperName + ' textarea')[0]; var cursorPos = area.selectionStart; var content = area.getValue(); ## Find the start position of the next i18n reference supported style: @@ -96,7 +96,7 @@ function checkClick(wrapperName, langCode) { while (content.indexOf("$") != -1 && counter < 10) { var startPos = content.search("\\$\\{?([\\w\\.\\-]*):([\\w\\.\\-]*[\\w\\-])\\}?"); var endPos = startPos + content.substring(startPos).search("[^\\{\\w\\.\\-:\\}]|$"); - ##console.log("cursorPos::" + cursorPos + " startPos::"+ startPos + " endPos::"+ endPos + " KEY::" + content.substring(startPos, endPos)); + console.log("cursorPos::" + cursorPos + " startPos::"+ startPos + " endPos::"+ endPos + " KEY::" + content.substring(startPos, endPos)); if (startPos <= cursorPos && endPos >= cursorPos) { var reference = content.substring(startPos, endPos); @@ -107,7 +107,7 @@ function checkClick(wrapperName, langCode) { if (reference.startsWith(":")) { ## of type ':my.key' - get current bundle from bundles selction dropdown key = reference.substring(1, reference.length); - var select = $$("#bundlesSelectionContainer select")[0]; + var select = jQuery("#bundlesSelectionContainer select")[0]; bundleName = select.options[select.selectedIndex].value; } else { ## of type 'org.olat.core:my.key' - parse bundle from reference @@ -119,12 +119,12 @@ function checkClick(wrapperName, langCode) { var trans = jQuery(document).ooTranslator().getTranslator(langCode, bundleName); if (trans) { var translated = trans.translate(key); - ##console.log("WORD FOUND::" + reference + " translated as::" + translated); + console.log("WORD FOUND::" + reference + " translated as::" + translated); if (translated != reference) { ## set new key and value, make element visible - $$('div.' + wrapperName + ' div.b_translation_refKey code')[0].update(reference); - $$('div.' + wrapperName + ' div.b_translation_refKey span')[0].update(translated); - $$('div.' + wrapperName + ' div.b_translation_refKey')[0].setStyle('display: inline'); + jQuery('div.' + wrapperName + ' div.b_translation_refKey code')[0].update(reference); + jQuery('div.' + wrapperName + ' div.b_translation_refKey span')[0].update(translated); + jQuery('div.' + wrapperName + ' div.b_translation_refKey')[0].setStyle('display: inline'); } } break; @@ -138,16 +138,26 @@ function checkClick(wrapperName, langCode) { } ## Initialize observers -Ext.onReady(function() { - var area = $$('div.b_translation_edit_reference textarea')[0]; - area.observe('click', function(){checkClick('b_translation_edit_reference', '${referenceLanguageKey}');}); +jQuery(function() { + jQuery('div.b_translation_edit_reference textarea').each(function(index, el) { + jQuery(el).on('click', function() { + checkClick('b_translation_edit_reference','${referenceLanguageKey}'); + }); + }); + #if ($compareSwitchEnabled) - area = $$('div.b_translation_edit_compare textarea')[0]; - area.observe('click', function(){checkClick('b_translation_edit_compare', '${compareLanguageKey}');}); + jQuery('div.b_translation_edit_compare textarea').each(function(index, el) { + jQuery(el).on('click', function() { + checkClick('b_translation_edit_compare','${compareLanguageKey}'); + }); + }); #end - area = $$('div.b_translation_edit_target textarea')[0]; - area.observe('click', function(){checkClick('b_translation_edit_target', '${targetLanguageKey}');}); - area.focus(); + jQuery('div.b_translation_edit_target textarea').each(function(index, el) { + jQuery(el).on('click', function(){ + checkClick('b_translation_edit_target','${targetLanguageKey}'); + }); + jQuery(el).focus(); + }); }); /* ]]> */ </script> \ No newline at end of file diff --git a/src/main/java/org/olat/core/util/vfs/VFSManager.java b/src/main/java/org/olat/core/util/vfs/VFSManager.java index 1010d3704b1..dcc61daebc9 100644 --- a/src/main/java/org/olat/core/util/vfs/VFSManager.java +++ b/src/main/java/org/olat/core/util/vfs/VFSManager.java @@ -499,6 +499,37 @@ public class VFSManager extends BasicManager { return successful; } + /** + * Copy the content of the source container to the target container. + * @param source + * @param target + * @return + */ + public static boolean copyContent(VFSContainer source, VFSContainer target) { + if(!source.exists()) { + return false; + } + if(isSelfOrParent(source, target)) { + return false; + } + + if(source instanceof NamedContainerImpl) { + source = ((NamedContainerImpl)source).getDelegate(); + } + if(target instanceof NamedContainerImpl) { + target = ((NamedContainerImpl)target).getDelegate(); + } + + if(source instanceof LocalImpl && target instanceof LocalImpl) { + LocalImpl localSource = (LocalImpl)source; + LocalImpl localTarget = (LocalImpl)target; + File localSourceFile = localSource.getBasefile(); + File localTargetFile = localTarget.getBasefile(); + return FileUtils.copyDirContentsToDir(localSourceFile, localTargetFile, false, "VFScopyDir"); + } + return false; + } + /** * Copies the stream to the target leaf. * diff --git a/src/main/java/org/olat/core/util/vfs/VFSTestMain.java b/src/main/java/org/olat/core/util/vfs/VFSTestMain.java deleted file mode 100644 index 675ccb06ed2..00000000000 --- a/src/main/java/org/olat/core/util/vfs/VFSTestMain.java +++ /dev/null @@ -1,203 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <p> -* Licensed under the Apache License, Version 2.0 (the "License"); <br> -* you may not use this file except in compliance with the License.<br> -* You may obtain a copy of the License at -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <p> -* Unless required by applicable law or agreed to in writing,<br> -* software distributed under the License is distributed on an "AS IS" BASIS, <br> -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> -* See the License for the specific language governing permissions and <br> -* limitations under the License. -* <p> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -* <p> -*/ - -package org.olat.core.util.vfs; - -import java.io.File; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; - -/** - * Description:<br> - * TODO: Felix Jost Class Description for Test - * - * <P> - * Initial Date: 23.06.2005 <br> - * - * @author Felix Jost - */ -public class VFSTestMain { - - /** - * @param args - */ - public static void main(String[] args) { - VFSTestMain t = new VFSTestMain(); - t.doit(); - } - - /** - * - */ - private void doit() { - VFSContainer cont = new LocalFolderImpl(new File("c:/temp/aaa"), null); - stats(cont); - //dump(cont, 0); - - VFSItem q = cont.resolve("/"); - //dump(q,0); - if (q instanceof VFSContainer) { - VFSContainer qc = (VFSContainer) q; - List items = cont.getItems(); - items.size(); - } - - - VFSItem r = cont.resolve("/testfile.bla"); - VFSItem s = cont.resolve("/echopoint/FontChooser.class"); - - // ------------------------------------------------------- - VFSContainer cc2 = new LocalFolderImpl(new File("c:/temp/in"), null); - MergeSource c2 = new MergeSource(null, null); - c2.addContainersChildren(cont, true); - c2.addContainersChildren(cc2, false); - VFSItem q2 = c2.resolve("/"); - VFSItem r2 = c2.resolve("/testfile.bla"); - VFSItem s2 = c2.resolve("/echopoint"); - VFSItem s21 = s2.resolve("/FontChooser.class"); - VFSItem s22 = s2.resolve("/"); - VFSItem s23 = s2.resolve("/glabab/blub.txt"); - - - - - VFSItem t2 = c2.resolve("/echopoint/FontChooser.class"); - - VFSItem u2 = c2.resolve("/demo.zip"); - VFSItem v2 = c2.resolve("/subin"); - VFSItem w2 = c2.resolve("/subin/xep.bat"); - - - // ------------------------------------------------------- - - VFSContainer cc3 = new LocalFolderImpl(new File("c:/temp/in"), null); - NamedContainerImpl ccc3 = new NamedContainerImpl("virtual1", cc3); - MergeSource c3 = new MergeSource(null, null); - c3.addContainersChildren(cont, true); - c3.addContainersChildren(ccc3, false); - VFSItem q3 = c3.resolve("/"); - VFSItem r3 = c3.resolve("/testfile.bla"); - VFSItem s3 = c3.resolve("/echopoint"); - VFSItem t3 = c3.resolve("/echopoint/FontChooser.class"); - - VFSItem x3 = c3.resolve("/virtual1"); - VFSItem y3 = c3.resolve("/virtual12"); - VFSItem z3 = c3.resolve("/virtual12/aaa"); - VFSItem u3 = c3.resolve("/virtual1/demo.zip"); - VFSItem v3 = c3.resolve("/virtual1/subin"); - VFSItem w3 = c3.resolve("/virtual1/subin/xep.bat"); - - int i = 1; - -/* - VFSContainer c2 = new LocalFolderImpl(new File("c:/temp/f2")); - stats(c2); - - VFSContainer named = new NamedContainerImpl("namedcontainer", c2, true); - stats(named); - - MergeSource m = new MergeSource(cont, new VFSContainer[] { named}); - stats(m); - - VFSItem q = m.resolveFile("/bookmarks.html"); - VFSItem a = m.resolveFile("/ifa/sammlung.zip"); - VFSItem d = m.resolveFile("/ifa"); - VFSItem b = m.resolveFile("/namedcontainer/zzz/zzztest.txt"); - VFSItem f = m.resolveFile("/namedcontainer"); - VFSItem g = m.resolveFile("/namedcontainer/zzz"); - VFSItem e = m.resolveFile("/"); - - - //c2.copyFrom(cont); - - dump(m, 0); - - - */ - //VFSContainer del = new LocalFolderImpl(new File("c:/temp/f2/felix/ifa")); - //del.delete(); - - /*try { - StreamedImpl st = new StreamedImpl("testit.html",new FileInputStream("c:/temp/felix/bookmarks.html")); - c2.copyFrom(st); - } catch (FileNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - }*/ - - } - - - /** - * @param it - */ - private void stats(VFSItem it) { - boolean copyFrom = it.canCopy() == VFSConstants.YES; - boolean del = (it.canDelete() == VFSConstants.YES); - boolean ren = (it.canRename() == VFSConstants.YES); - boolean copyTo = it.canWrite() == VFSConstants.YES; - - String name = it.getName(); - - System.out.println(name +" cfrom "+copyFrom+" del "+del+" ren "+ren+" cTo "+copyTo); - - } - - private void dump(VFSItem item, int indent) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < indent; i++) { - sb.append(" "); - } - sb.append("name of container:" +item.getName()); - if (item instanceof VFSContainer) { - sb.append("/"); - } - System.out.println(sb.toString()); - - if (item instanceof VFSContainer) { - VFSContainer cont = (VFSContainer) item; - List items = cont.getItems(); - Collections.sort(items, new Comparator() { - public int compare(Object a, Object b) { - VFSItem va = (VFSItem)a; - VFSItem vb = (VFSItem)b; - boolean ac = (va instanceof VFSContainer); - boolean bc = (vb instanceof VFSContainer); - if (ac && !bc) return -1; - if (!ac && bc) return 1; - return va.getName().compareTo(vb.getName()); - }}); - - for (Iterator iter = items.iterator(); iter.hasNext();) { - VFSItem chditem = (VFSItem) iter.next(); - dump(chditem, indent+1); - } - } - } -} - diff --git a/src/main/java/org/olat/core/util/vfs/filters/VFSItemExcludePrefixFilter.java b/src/main/java/org/olat/core/util/vfs/filters/VFSItemExcludePrefixFilter.java index cf90d16fd60..9c281376e21 100644 --- a/src/main/java/org/olat/core/util/vfs/filters/VFSItemExcludePrefixFilter.java +++ b/src/main/java/org/olat/core/util/vfs/filters/VFSItemExcludePrefixFilter.java @@ -41,7 +41,7 @@ import org.olat.core.util.vfs.VFSItem; */ public class VFSItemExcludePrefixFilter implements VFSItemFilter { - private Hashtable excludedPrefixes = new Hashtable(); + private Hashtable<String,String> excludedPrefixes = new Hashtable<String,String>(); /** * Constrtuctor @@ -58,14 +58,14 @@ public class VFSItemExcludePrefixFilter implements VFSItemFilter { */ public void addExcludedPrefix(String prefix) { prefix = prefix.toLowerCase(); - this.excludedPrefixes.put(prefix, prefix); + excludedPrefixes.put(prefix, prefix); } /** * @param prefix */ public void removeSuffix(String prefix) { - this.excludedPrefixes.remove(prefix.toLowerCase()); + excludedPrefixes.remove(prefix.toLowerCase()); } /** @@ -73,9 +73,9 @@ public class VFSItemExcludePrefixFilter implements VFSItemFilter { */ public boolean accept(VFSItem vfsItem) { String name = vfsItem.getName().toLowerCase(); - Enumeration elements = excludedPrefixes.elements(); + Enumeration<String> elements = excludedPrefixes.elements(); while (elements.hasMoreElements() ) { - String excludedPrefix = (String)elements.nextElement(); + String excludedPrefix = elements.nextElement(); if (name.startsWith(excludedPrefix)) { return false; } diff --git a/src/main/java/org/olat/core/util/vfs/filters/VFSItemSuffixFilter.java b/src/main/java/org/olat/core/util/vfs/filters/VFSItemSuffixFilter.java index e10dcd1441e..faa66c09642 100644 --- a/src/main/java/org/olat/core/util/vfs/filters/VFSItemSuffixFilter.java +++ b/src/main/java/org/olat/core/util/vfs/filters/VFSItemSuffixFilter.java @@ -39,7 +39,7 @@ import org.olat.core.util.vfs.VFSItem; * */ public class VFSItemSuffixFilter implements VFSItemFilter { - private Hashtable suffixes = new Hashtable(); + private Hashtable<String,String> suffixes = new Hashtable<String,String>(); /** * Constructor @@ -56,14 +56,14 @@ public class VFSItemSuffixFilter implements VFSItemFilter { */ public void addSuffix(String suffix) { suffix = suffix.toLowerCase(); - this.suffixes.put(suffix, suffix); + suffixes.put(suffix, suffix); } /** * @param suffix */ public void removeSuffix(String suffix) { - this.suffixes.remove(suffix.toLowerCase()); + suffixes.remove(suffix.toLowerCase()); } /** @@ -72,7 +72,9 @@ public class VFSItemSuffixFilter implements VFSItemFilter { public boolean accept(VFSItem vfsItem) { String name = vfsItem.getName().toLowerCase(); int idx = name.lastIndexOf('.'); - if (idx >= 0) { return this.suffixes.containsKey(name.substring(idx + 1)); } + if (idx >= 0) { + return suffixes.containsKey(name.substring(idx + 1)); + } return suffixes.containsKey(name); } diff --git a/src/main/java/org/olat/ims/qti/QTI12MetadataController.java b/src/main/java/org/olat/ims/qti/QTI12MetadataController.java new file mode 100644 index 00000000000..9d1aaa8810e --- /dev/null +++ b/src/main/java/org/olat/ims/qti/QTI12MetadataController.java @@ -0,0 +1,125 @@ +package org.olat.ims.qti; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.StaticTextElement; +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.core.util.Util; +import org.olat.ims.qti.editor.ItemNodeTabbedFormController; +import org.olat.ims.qti.editor.QTIEditHelper; +import org.olat.ims.qti.editor.beecom.objects.ChoiceQuestion; +import org.olat.ims.qti.editor.beecom.objects.ChoiceResponse; +import org.olat.ims.qti.editor.beecom.objects.Item; +import org.olat.ims.qti.editor.beecom.objects.Material; +import org.olat.ims.qti.editor.beecom.objects.Question; + +/** + * + * Initial date: 20.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QTI12MetadataController extends FormBasicController { + + private final Item item; + + public QTI12MetadataController(UserRequest ureq, WindowControl wControl, Item item) { + super(ureq, wControl, "qti_metadatas"); + setTranslator(Util.createPackageTranslator(ItemNodeTabbedFormController.class, getLocale(), getTranslator())); + this.item = item; + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + Question question = item.getQuestion(); + + if(question != null) { + //settings + FormLayoutContainer leftSettingsCont = FormLayoutContainer.createDefaultFormLayout("left_settings", getTranslator()); + leftSettingsCont.setRootForm(mainForm); + formLayout.add("leftSettings", leftSettingsCont); + + String shuffleStr = Boolean.toString(question.isShuffle()); + uifactory.addStaticTextElement("form.imd.shuffle", shuffleStr, leftSettingsCont); + + String duration = ""; + if(item.getDuration() != null) { + duration = item.getDuration().getMin() + ":" + item.getDuration().getSec(); + } + uifactory.addStaticTextElement("form.metadata.duration", duration, leftSettingsCont); + + FormLayoutContainer rightSettingsCont = FormLayoutContainer.createDefaultFormLayout("right_settings", getTranslator()); + rightSettingsCont.setRootForm(mainForm); + formLayout.add("rightSettings", rightSettingsCont); + if(question instanceof ChoiceQuestion) { + ChoiceQuestion choice = (ChoiceQuestion)question; + if(item.getQuestion().getType() == Question.TYPE_SC) { + String score = Float.toString(question.getSingleCorrectScore()); + uifactory.addStaticTextElement("score", score, rightSettingsCont); + + } else if(item.getQuestion().getType() == Question.TYPE_MC) { + String minVal = Float.toString(choice.getMinValue()); + String maxVal = Float.toString(choice.getMaxValue()); + uifactory.addStaticTextElement("score.min", minVal, rightSettingsCont); + uifactory.addStaticTextElement("score.max", maxVal, rightSettingsCont); + } + } + } + + //feedbacks + boolean hasFeedbacks = false; + + FormLayoutContainer leftFeedbackCont = FormLayoutContainer.createDefaultFormLayout("left_feedback", getTranslator()); + leftFeedbackCont.setRootForm(mainForm); + + Material masteryMat = QTIEditHelper.getFeedbackMasteryMaterial(item); + if(masteryMat != null) { + String text = masteryMat.renderAsText(); + uifactory.addStaticTextElement("item_feedback_mastery", text, leftFeedbackCont); + hasFeedbacks = true; + } + + FormLayoutContainer rightFeedbackCont = FormLayoutContainer.createDefaultFormLayout("right_feedback", getTranslator()); + rightFeedbackCont.setRootForm(mainForm); + + Material failureMat = QTIEditHelper.getFeedbackFailMaterial(item); + if(failureMat != null) { + String text = failureMat.renderAsText(); + uifactory.addStaticTextElement("item_feedback_fail", text, rightFeedbackCont); + hasFeedbacks = true; + } + + if (question != null && question.getType() <= Question.TYPE_MC) { + int count = 0; + for (Object obj : question.getResponses()) { + ChoiceResponse response = (ChoiceResponse) obj; + Material responseFeedbackMat = QTIEditHelper.getFeedbackOlatRespMaterial(item, response.getIdent()); + if(responseFeedbackMat != null) { + boolean left = (count++ % 2 == 0); + String text = responseFeedbackMat.renderAsText(); + StaticTextElement el = uifactory.addStaticTextElement("item_feedback_" + count, text, left ? leftFeedbackCont : rightFeedbackCont); + el.setLabel(null, null); + } + } + hasFeedbacks = count > 0; + } + if(hasFeedbacks) { + formLayout.add("leftFeedback", leftFeedbackCont); + formLayout.add("rightFeedback", rightFeedbackCont); + } + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void formOK(UserRequest ureq) { + // + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti/QTI12PreviewController.java b/src/main/java/org/olat/ims/qti/QTI12PreviewController.java index c0aa7b6875b..38d76dd8f32 100644 --- a/src/main/java/org/olat/ims/qti/QTI12PreviewController.java +++ b/src/main/java/org/olat/ims/qti/QTI12PreviewController.java @@ -30,6 +30,7 @@ import org.olat.core.dispatcher.mapper.Mapper; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.panel.Panel; +import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; @@ -47,8 +48,8 @@ import org.olat.ims.qti.editor.QTIEditorPackage; import org.olat.ims.qti.editor.beecom.objects.Item; import org.olat.ims.qti.editor.beecom.parser.ParserManager; import org.olat.ims.resources.IMSEntityResolver; -import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionItem; /** * * Initial date: 21.02.2013<br> @@ -58,12 +59,17 @@ import org.olat.modules.qpool.QPoolService; public class QTI12PreviewController extends BasicController { private final Panel mainPanel; + private final VelocityContainer mainVC; private ItemPreviewController previewCtrl; + private QTI12MetadataController metadataCtrl; + private final QPoolService qpoolService; public QTI12PreviewController(UserRequest ureq, WindowControl wControl, QuestionItem qitem) { super(ureq, wControl); qpoolService = CoreSpringFactory.getImpl(QPoolService.class); + + mainVC = createVelocityContainer("qti_preview"); mainPanel = new Panel("qti12preview"); VFSLeaf leaf = qpoolService.getRootFile(qitem); @@ -78,10 +84,15 @@ public class QTI12PreviewController extends BasicController { previewCtrl = new ItemPreviewController(wControl, item, mapperUrl, translator); listenTo(previewCtrl); mainPanel.setContent(previewCtrl.getInitialComponent()); + + metadataCtrl = new QTI12MetadataController(ureq, getWindowControl(), item); + listenTo(metadataCtrl); + mainVC.put("metadatas", metadataCtrl.getInitialComponent()); } } - putInitialPanel(mainPanel); + mainVC.put("preview", mainPanel); + putInitialPanel(mainVC); } private Item readItemXml(VFSLeaf leaf) { diff --git a/src/main/java/org/olat/ims/qti/QTIConstants.java b/src/main/java/org/olat/ims/qti/QTIConstants.java index c2356bd4f12..61e256ad2f2 100644 --- a/src/main/java/org/olat/ims/qti/QTIConstants.java +++ b/src/main/java/org/olat/ims/qti/QTIConstants.java @@ -76,6 +76,15 @@ public class QTIConstants { public static final String ATTR_AIID = "aiid"; public static final String ATTR_PREVIEWDOC = "previewDoc"; + //xml doctype + public static final String XML_DOCUMENT_ROOT = "questestinterop"; + public static final String XML_DOCUMENT_DTD = "ims_qtiasiv1p2p1.dtd"; + + //metadata + public static final String META_LEVEL_OF_DIFFICULTY = "qmd_levelofdifficulty"; + public static final String META_ITEM_TYPE = "qmd_itemtype"; + public static final String META_TOOLVENDOR = "qmd_toolvendor"; + // question pool public static final String QTI_12_FORMAT = "IMS QTI 1.2"; diff --git a/src/main/java/org/olat/ims/qti/_content/qti_metadatas.html b/src/main/java/org/olat/ims/qti/_content/qti_metadatas.html new file mode 100644 index 00000000000..420ebb195d9 --- /dev/null +++ b/src/main/java/org/olat/ims/qti/_content/qti_metadatas.html @@ -0,0 +1,34 @@ +#if($r.available("leftSettings") || $r.available("rightSettings")) + <fieldset> + <legend>Settings</legend> + <div class="b_clearfix"> + <div class="b_c50l"> + <div class="b_subcl"> + $r.render("leftSettings") + </div> + </div> + <div class="b_c50r"> + <div class="b_subcr"> + $r.render("rightSettings") + </div> + </div> + </div> + </fieldset> +#end +#if($r.available("leftFeedback") || $r.available("rightFeedback")) + <fieldset> + <legend>Feedbacks</legend> + <div class="b_clearfix"> + <div class="b_c50l"> + <div class="b_subcl"> + $r.render("leftFeedback") + </div> + </div> + <div class="b_c50r"> + <div class="b_subcr"> + $r.render("rightFeedback") + </div> + </div> + </div> + </fieldset> +#end diff --git a/src/main/java/org/olat/ims/qti/_content/qti_preview.html b/src/main/java/org/olat/ims/qti/_content/qti_preview.html new file mode 100644 index 00000000000..565141c63c4 --- /dev/null +++ b/src/main/java/org/olat/ims/qti/_content/qti_preview.html @@ -0,0 +1,11 @@ +#if($r.available("preview")) + $r.render("preview") +#else + No preview +#end + +#if($r.available("metadatas")) + $r.render("metadatas") +#else + No metadatas +#end \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java b/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java index 7a73b8d029e..ab384683def 100644 --- a/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java +++ b/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java @@ -19,10 +19,30 @@ */ package org.olat.ims.qti.qpool; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; import java.util.zip.ZipOutputStream; +import org.dom4j.Document; +import org.dom4j.DocumentFactory; +import org.dom4j.Element; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.XMLWriter; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.CodeHelper; import org.olat.core.util.ZipUtil; import org.olat.core.util.vfs.VFSContainer; +import org.olat.core.util.vfs.VFSItem; +import org.olat.core.util.vfs.VFSLeaf; +import org.olat.core.util.xml.XMLParser; +import org.olat.ims.qti.QTIConstants; +import org.olat.ims.resources.IMSEntityResolver; import org.olat.modules.qpool.QuestionItemFull; import org.olat.modules.qpool.manager.FileStorage; @@ -34,17 +54,263 @@ import org.olat.modules.qpool.manager.FileStorage; */ public class QTIExportProcessor { - private final QuestionItemFull fullItem; + private static final OLog log = Tracing.createLoggerFor(QTIExportProcessor.class); + private final FileStorage qpoolFileStorage; - public QTIExportProcessor(QuestionItemFull fullItem, FileStorage qpoolFileStorage) { - this.fullItem = fullItem; + public QTIExportProcessor(FileStorage qpoolFileStorage) { this.qpoolFileStorage = qpoolFileStorage; } - public void process(ZipOutputStream zout) { + public void process(QuestionItemFull fullItem, ZipOutputStream zout) { String dir = fullItem.getDirectory(); VFSContainer container = qpoolFileStorage.getContainer(dir); ZipUtil.addToZip(container, "", zout); } + + public void assembleTest(List<QuestionItemFull> fullItems) { + Element sectionEl = createSectionBasedAssessment("Assessment"); + for(QuestionItemFull fullItem:fullItems) { + String dir = fullItem.getDirectory(); + String rootFilename = fullItem.getRootFilename(); + VFSContainer container = qpoolFileStorage.getContainer(dir); + VFSItem rootItem = container.resolve(rootFilename); + List<String> path = new ArrayList<String>(); + collectResource(container, "", path); + System.out.println(path); + + if(rootItem instanceof VFSLeaf) { + VFSLeaf rootLeaf = (VFSLeaf)rootItem; + Element el = readItemXml(rootLeaf); + Element cloneEl = (Element)el.clone(); + enrichScore(cloneEl); + enrichWithMetadata(fullItem, cloneEl); + sectionEl.add(cloneEl); + } + } + + writeDocument(sectionEl); + } + + private void collectResource(VFSContainer container, String currentPath, List<String> path) { + List<VFSItem> items = container.getItems(); + for(VFSItem item:items) { + String itemPath = currentPath + "/" + item.getName(); + if(item instanceof VFSLeaf) { + path.add(itemPath); + } else if(item instanceof VFSContainer) { + collectResource((VFSContainer)item, itemPath, path); + } + } + } + + private void writeDocument(Element el) { + try { + Document doc = el.getDocument(); + OutputStream os = new FileOutputStream(new File("/HotCoffee/test.xml")); + XMLWriter xw = new XMLWriter(os, new OutputFormat(" ", true)); + xw.write(doc); + xw.close(); + os.close(); + } catch (IOException e) { + log.error("", e); + } + } + + private Element createSectionBasedAssessment(String title) { + DocumentFactory df = DocumentFactory.getInstance(); + Document doc = df.createDocument(); + doc.addDocType(QTIConstants.XML_DOCUMENT_ROOT, null, QTIConstants.XML_DOCUMENT_DTD); + + /* + <questestinterop> + <assessment ident="frentix_9_87230240084930" title="SR Test"> + */ + Element questestinterop = doc.addElement(QTIConstants.XML_DOCUMENT_ROOT); + Element assessment = questestinterop.addElement("assessment"); + assessment.addAttribute("ident", CodeHelper.getGlobalForeverUniqueID()); + assessment.addAttribute("title", title); + //metadata + /* + <qtimetadata> + <qtimetadatafield> + <fieldlabel>qmd_assessmenttype</fieldlabel> + <fieldentry>Assessment</fieldentry> + </qtimetadatafield> + </qtimetadata> + */ + Element qtimetadata = assessment.addElement("qtimetadata"); + addMetadataField("qmd_assessmenttype", "Assessment", qtimetadata); + //section + /* + <section ident="frentix_9_87230240084931" title="Section"> + <selection_ordering> + <selection/> + <order order_type="Sequential"/> + </selection_ordering> + */ + Element section = assessment.addElement("section"); + section.addAttribute("ident", CodeHelper.getGlobalForeverUniqueID()); + section.addAttribute("title", "Section"); + Element selectionOrdering = section.addElement("selection_ordering"); + selectionOrdering.addElement("selection"); + Element order = selectionOrdering.addElement("order"); + order.addAttribute("order_type", "Sequential"); + return section; + } + + private Element readItemXml(VFSLeaf leaf) { + Document doc = null; + try { + InputStream is = leaf.getInputStream(); + XMLParser xmlParser = new XMLParser(new IMSEntityResolver()); + doc = xmlParser.parse(is, false); + + Element item = (Element)doc.selectSingleNode("questestinterop/item"); + is.close(); + return item; + } catch (Exception e) { + log.error("", e); + return null; + } + } + + /** + * OpenOLAT QTI 1.2 runtime need it: + <resprocessing> + <outcomes> + <decvar varname="SCORE" vartype="Decimal" defaultval="0" minvalue="0.0" maxvalue="1.0" cutvalue="1.0"/> + </outcomes> + * @param fullItem + * @param item + */ + private void enrichScore(Element item) { + @SuppressWarnings("unchecked") + List<Element> sv = item.selectNodes("./resprocessing/outcomes/decvar[@varname='SCORE']"); + // the QTIv1.2 system relies on the SCORE variable of items + if (sv.isEmpty()) { + //create resprocessing if needed + Element resprocessing; + if(item.selectNodes("./resprocessing").isEmpty()) { + resprocessing = item.addElement("resprocessing"); + } else { + resprocessing = (Element)item.selectNodes("./resprocessing").get(0); + } + + //create outcomes if needed + Element outcomes; + if(resprocessing.selectNodes("./outcomes").isEmpty()) { + outcomes = resprocessing.addElement("outcomes"); + } else { + outcomes = (Element)resprocessing.selectNodes("./outcomes").get(0); + } + + //create decvar if needed + Element decvar = outcomes.addElement("decvar"); + decvar.addAttribute("varname", "SCORE"); + decvar.addAttribute("vartype", "Decimal"); + decvar.addAttribute("defaultval", "0"); + decvar.addAttribute("minvalue", "0.0"); + decvar.addAttribute("maxvalue", "1.0"); + decvar.addAttribute("cutvalue", "1.0"); + } + } + + private void enrichWithMetadata(QuestionItemFull fullItem, Element item) { + Element qtimetadata = (Element)item.selectSingleNode("./itemmetadata/qtimetadata"); + String path = fullItem.getTaxonomicPath(); + System.out.println(qtimetadata + " " + path); + } + + private void addMetadataField(String label, String entry, Element qtimetadata) { + Element qtimetadatafield = qtimetadata.addElement("qtimetadatafield"); + qtimetadatafield.addElement("fieldlabel").setText(label); + qtimetadatafield.addElement("fieldentry").setText(entry); + } + + + /* + * + * <itemmetadata> + <qtimetadata> + <qtimetadatafield> + <fieldlabel>qmd_levelofdifficulty</fieldlabel> + <fieldentry>basic</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>qmd_topic</fieldlabel> + <fieldentry>qtiv1p2test</fieldentry> + </qtimetadatafield> + </qtimetadata> + </itemmetadata> + + <qtimetadata> + <vocabulary uri="imsqtiv1p2_metadata.txt" vocab_type="text/plain"/> + <qtimetadatafield> + <fieldlabel>qmd_weighting</fieldlabel> + <fieldentry>2</fieldentry> + </qtimetadatafield> + ... + </qtimetadata> + + + + http://qtimigration.googlecode.com/svn-history/r29/trunk/pyslet/unittests/data_imsqtiv1p2p1/input/ + + +<qtimetadatafield> + <fieldlabel>name</fieldlabel> + <fieldentry>Metadata New-Style</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>marks</fieldlabel> + <fieldentry>50.0</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>syllabusarea</fieldlabel> + <fieldentry>Migration</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>author</fieldlabel> + <fieldentry>Steve Author</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>creator</fieldlabel> + <fieldentry>Steve Creator</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>owner</fieldlabel> + <fieldentry>Steve Owner</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>item type</fieldlabel> + <fieldentry>MCQ</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>status</fieldlabel> + <fieldentry>Experimental</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>qmd_levelofdifficulty</fieldlabel> + <fieldentry>Professional Development</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>qmd_toolvendor</fieldlabel> + <fieldentry>Steve Lay</fieldentry> + </qtimetadatafield> + <qtimetadatafield> + <fieldlabel>description</fieldlabel> + <fieldentry>General Description Extension</fieldentry> + </qtimetadatafield> + + + <itemmetadata> + <qmd_itemtype>MCQ</qmd_itemtype> + <qmd_levelofdifficulty>Professional Development</qmd_levelofdifficulty> + <qmd_maximumscore>50.0</qmd_maximumscore> + <qmd_status>Experimental</qmd_status> + <qmd_toolvendor>Steve Lay</qmd_toolvendor> + <qmd_topic>Migration</qmd_topic> + </itemmetadata> + */ } diff --git a/src/main/java/org/olat/ims/qti/qpool/QTIImportProcessor.java b/src/main/java/org/olat/ims/qti/qpool/QTIImportProcessor.java index 4d6f7142359..3bc313278e4 100644 --- a/src/main/java/org/olat/ims/qti/qpool/QTIImportProcessor.java +++ b/src/main/java/org/olat/ims/qti/qpool/QTIImportProcessor.java @@ -55,7 +55,11 @@ import org.olat.ims.resources.IMSEntityResolver; import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QuestionType; import org.olat.modules.qpool.manager.FileStorage; +import org.olat.modules.qpool.manager.QEducationalContextDAO; +import org.olat.modules.qpool.manager.QItemTypeDAO; import org.olat.modules.qpool.manager.QuestionItemDAO; +import org.olat.modules.qpool.model.QEducationalContext; +import org.olat.modules.qpool.model.QItemType; import org.olat.modules.qpool.model.QuestionItemImpl; import org.xml.sax.Attributes; import org.xml.sax.InputSource; @@ -76,15 +80,21 @@ class QTIImportProcessor { private final Identity owner; private final String importedFilename; private final File importedFile; + + private final QItemTypeDAO qItemTypeDao; private final FileStorage qpoolFileStorage; private final QuestionItemDAO questionItemDao; + private final QEducationalContextDAO qEduContextDao; public QTIImportProcessor(Identity owner, String importedFilename, File importedFile, - QuestionItemDAO questionItemDao, FileStorage qpoolFileStorage) { + QuestionItemDAO questionItemDao, QItemTypeDAO qItemTypeDao, QEducationalContextDAO qEduContextDao, + FileStorage qpoolFileStorage) { this.owner = owner; this.importedFilename = importedFilename; this.importedFile = importedFile; + this.qItemTypeDao = qItemTypeDao; this.questionItemDao = questionItemDao; + this.qEduContextDao = qEduContextDao; this.qpoolFileStorage = qpoolFileStorage; } @@ -154,15 +164,87 @@ class QTIImportProcessor { QuestionItemImpl poolItem = questionItemDao.create(title, QTIConstants.QTI_12_FORMAT, dir, filename); //description poolItem.setDescription(itemInfos.getComment()); + //question type first processItemQuestionType(poolItem, ident, itemEl); + //if question type not found, can be overridden by the metadatas processItemMetadata(poolItem, itemEl); questionItemDao.persist(owner, poolItem); return poolItem; } private void processItemMetadata(QuestionItemImpl poolItem, Element itemEl) { + @SuppressWarnings("unchecked") + List<Element> qtiMetadataFieldList = itemEl.selectNodes("./itemmetadata/qtimetadata/qtimetadatafield"); + for(Element qtiMetadataField:qtiMetadataFieldList) { + Element labelEl = (Element)qtiMetadataField.selectSingleNode("./fieldlabel"); + Element entryEl = (Element)qtiMetadataField.selectSingleNode("./fieldentry"); + if(labelEl != null && entryEl != null) { + processMetadataField(poolItem, labelEl, entryEl); + } + } + } + + /** + * <ul> + * <li>qmd_computerscored</li> + * <li>qmd_feedbackpermitted</li> + * <li>qmd_hintspermitted</li> + * <li>qmd_itemtype -> (check is made on the content of the item)</li> + * <li>qmd_levelofdifficulty -> educational context</li> + * <li>qmd_maximumscore</li> + * <li>qmd_renderingtype</li> + * <li>qmd_responsetype</li> + * <li>qmd_scoringpermitted</li> + * <li>qmd_solutionspermitted</li> + * <li>qmd_status</li> + * <li>qmd_timedependence</li> + * <li>qmd_timelimit</li> + * <li>qmd_toolvendor -> editor</li> + * <li>qmd_topic</li> + * <li>qmd_material</li> + * <li>qmd_typeofsolution</li> + * <li>qmd_weighting</li> + * </ul> + * @param poolItem + * @param labelEl + * @param entryEl + */ + private void processMetadataField(QuestionItemImpl poolItem, Element labelEl, Element entryEl) { + String label = labelEl.getText(); + String entry = entryEl.getText(); - + if(QTIConstants.META_LEVEL_OF_DIFFICULTY.equals(label)) { + if(StringHelper.containsNonWhitespace(entry)) { + QEducationalContext context = qEduContextDao.loadByLevel(entry); + if(context == null) { + context = qEduContextDao.create(entry, true); + } + poolItem.setEducationalContext(context); + } + } else if(QTIConstants.META_ITEM_TYPE.equals(label)) { + if(poolItem.getType() == null && StringHelper.containsNonWhitespace(entry)) { + //some heuristic + String typeStr = entry; + if(typeStr.equalsIgnoreCase("MCQ") || typeStr.equalsIgnoreCase("Multiple choice")) { + typeStr = QuestionType.MC.name(); + } else if(typeStr.equalsIgnoreCase("SCQ") || typeStr.equalsIgnoreCase("Single choice")) { + typeStr = QuestionType.SC.name(); + } else if(typeStr.equalsIgnoreCase("fill-in") || typeStr.equals("Fill-in-the-Blank") + || typeStr.equalsIgnoreCase("Fill-in-Blank") || typeStr.equalsIgnoreCase("Fill In the Blank")) { + typeStr = QuestionType.FIB.name(); + } else if(typeStr.equalsIgnoreCase("Essay")) { + typeStr = QuestionType.ESSAY.name(); + } + + QItemType type = qItemTypeDao.loadByType(entry); + if(type == null) { + type = qItemTypeDao.create(entry, true); + } + poolItem.setType(type); + } + } else if(QTIConstants.META_TOOLVENDOR.equals(label)) { + poolItem.setEditor(entry); + } } /** @@ -366,7 +448,8 @@ class QTIImportProcessor { type = QuestionType.FIB; } if(type != null) { - poolItem.setType(type.name()); + QItemType itemType = qItemTypeDao.loadByType(type.name()); + poolItem.setType(itemType); } } diff --git a/src/main/java/org/olat/ims/qti/qpool/QTIQPoolServiceProvider.java b/src/main/java/org/olat/ims/qti/qpool/QTIQPoolServiceProvider.java index f1f6a8101b9..a1c812ee70a 100644 --- a/src/main/java/org/olat/ims/qti/qpool/QTIQPoolServiceProvider.java +++ b/src/main/java/org/olat/ims/qti/qpool/QTIQPoolServiceProvider.java @@ -20,6 +20,7 @@ package org.olat.ims.qti.qpool; import java.io.File; +import java.util.ArrayList; import java.util.List; import java.util.zip.ZipOutputStream; @@ -27,13 +28,18 @@ import org.olat.core.gui.UserRequest; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.id.Identity; +import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSLeaf; +import org.olat.core.util.vfs.VFSManager; import org.olat.ims.qti.QTI12PreviewController; import org.olat.ims.qti.QTIConstants; import org.olat.modules.qpool.QPoolSPI; import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QuestionItemFull; +import org.olat.modules.qpool.QuestionItemShort; import org.olat.modules.qpool.manager.FileStorage; +import org.olat.modules.qpool.manager.QEducationalContextDAO; +import org.olat.modules.qpool.manager.QItemTypeDAO; import org.olat.modules.qpool.manager.QuestionItemDAO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -50,7 +56,11 @@ public class QTIQPoolServiceProvider implements QPoolSPI { @Autowired private FileStorage qpoolFileStorage; @Autowired + private QItemTypeDAO qItemTypeDao; + @Autowired private QuestionItemDAO questionItemDao; + @Autowired + private QEducationalContextDAO qEduContextDao; public QTIQPoolServiceProvider() { // @@ -79,14 +89,32 @@ public class QTIQPoolServiceProvider implements QPoolSPI { @Override public List<QuestionItem> importItems(Identity owner, String filename, File file) { - QTIImportProcessor processor = new QTIImportProcessor(owner, filename, file, questionItemDao, qpoolFileStorage); + QTIImportProcessor processor = new QTIImportProcessor(owner, filename, file, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage); return processor.process(); } @Override public void exportItem(QuestionItemFull item, ZipOutputStream zout) { - QTIExportProcessor processor = new QTIExportProcessor(item, qpoolFileStorage); - processor.process(zout); + QTIExportProcessor processor = new QTIExportProcessor(qpoolFileStorage); + processor.process(item, zout); + } + + public void assembleTest(List<QuestionItemShort> items) { + List<Long> itemKeys = new ArrayList<Long>(); + for(QuestionItemShort item:items) { + itemKeys.add(item.getKey()); + } + + List<QuestionItemFull> fullItems = questionItemDao.loadByIds(itemKeys); + QTIExportProcessor processor = new QTIExportProcessor(qpoolFileStorage); + processor.assembleTest(fullItems); + } + + @Override + public void copyItem(QuestionItemFull original, QuestionItemFull copy) { + VFSContainer originalDir = qpoolFileStorage.getContainer(original.getDirectory()); + VFSContainer copyDir = qpoolFileStorage.getContainer(copy.getDirectory()); + VFSManager.copyContent(originalDir, copyDir); } @Override diff --git a/src/main/java/org/olat/modules/qpool/Pool.java b/src/main/java/org/olat/modules/qpool/Pool.java index 06ace8a52f5..d3912b7915c 100644 --- a/src/main/java/org/olat/modules/qpool/Pool.java +++ b/src/main/java/org/olat/modules/qpool/Pool.java @@ -38,5 +38,9 @@ public interface Pool { public String getName(); public void setName(String name); + + public boolean isPublicPool(); + + public void setPublicPool(boolean publicPool); } diff --git a/src/main/java/org/olat/modules/qpool/QPoolSPI.java b/src/main/java/org/olat/modules/qpool/QPoolSPI.java index a7f01f0f28e..1a238dde191 100644 --- a/src/main/java/org/olat/modules/qpool/QPoolSPI.java +++ b/src/main/java/org/olat/modules/qpool/QPoolSPI.java @@ -54,6 +54,13 @@ public interface QPoolSPI { */ public void exportItem(QuestionItemFull item, ZipOutputStream out); + /** + * Copy the item attachment... + * @param original + * @param copy + */ + public void copyItem(QuestionItemFull original, QuestionItemFull copy); + /** * Return the preview controller used in the main list panel of * the question poll. diff --git a/src/main/java/org/olat/modules/qpool/QPoolService.java b/src/main/java/org/olat/modules/qpool/QPoolService.java index 737861a99f3..12086bccdef 100644 --- a/src/main/java/org/olat/modules/qpool/QPoolService.java +++ b/src/main/java/org/olat/modules/qpool/QPoolService.java @@ -26,9 +26,13 @@ import java.util.zip.ZipOutputStream; import org.olat.core.commons.persistence.ResultInfos; import org.olat.core.commons.persistence.SortKey; import org.olat.core.id.Identity; +import org.olat.core.id.Roles; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSLeaf; import org.olat.group.BusinessGroup; +import org.olat.modules.qpool.model.QEducationalContext; +import org.olat.modules.qpool.model.QItemType; +import org.olat.modules.qpool.model.QLicense; import org.olat.modules.qpool.model.SearchQuestionItemParams; import org.olat.resource.OLATResource; @@ -40,23 +44,7 @@ import org.olat.resource.OLATResource; */ public interface QPoolService { - public String getTaxonomicPath(QuestionItem item); - - public void deleteItems(List<QuestionItemShort> items); - - public List<Identity> getAuthors(QuestionItem item); - - public void addAuthors(List<Identity> authors, List<QuestionItemShort> items); - - public void removeAuthors(List<Identity> authors, List<QuestionItemShort> items); - - public void exportItem(QuestionItemShort item, ZipOutputStream zout); - - public List<QuestionItem> importItems(Identity owner, String filename, File file); - - public VFSLeaf getRootFile(QuestionItem item); - - public VFSContainer getRootDirectory(QuestionItem item); + /** * Create a new item and persist it on the database @@ -70,48 +58,71 @@ public interface QPoolService { * @param type * @return */ - public QuestionItem createAndPersistItem(Identity owner, String subject, String format, String language, TaxonomyLevel taxonLevel, String dir, String rootFilename, QuestionType type); + public QuestionItem createAndPersistItem(Identity owner, String subject, String format, String language, TaxonomyLevel taxonLevel, + String dir, String rootFilename, QItemType type); public QuestionItem loadItemById(Long key); + public List<QuestionItem> getAllItems(int firstResult, int maxResults); + public QuestionItem updateItem(QuestionItem item); - public List<QuestionItem> copyItems(Identity cloner, List<QuestionItemShort> itemsToCopy); + public void deleteItems(List<QuestionItemShort> items); + + + //manage authors + public boolean isAuthor(QuestionItem item, Identity identity); + + public List<Identity> getAuthors(QuestionItem item); + + public void addAuthors(List<Identity> authors, List<QuestionItemShort> items); + + public void removeAuthors(List<Identity> authors, List<QuestionItemShort> items); - public int countItems(Identity author); - public ResultInfos<QuestionItemShort> getItems(Identity author, SearchQuestionItemParams params, int firstResult, int maxResults, SortKey... orderBy); + public ResultInfos<QuestionItemView> getItems(Identity author, SearchQuestionItemParams params, int firstResult, int maxResults, SortKey... orderBy); - public List<QuestionItem> getAllItems(int firstResult, int maxResults); + //import / export + public void exportItem(QuestionItemShort item, ZipOutputStream zout); + + public List<QuestionItem> importItems(Identity owner, String filename, File file); + public VFSLeaf getRootFile(QuestionItem item); + public VFSContainer getRootDirectory(QuestionItem item); + public List<QuestionItem> copyItems(Identity cloner, List<QuestionItemShort> itemsToCopy); + //pools - public List<Pool> getPools(Identity identity); + public List<Pool> getPools(Identity identity, Roles roles); + + public void addOwners(List<Identity> owners, List<Pool> pools); + + public void removeOwners(List<Identity> owners, List<Pool> pools); public int getNumOfItemsInPool(Pool pool); - public ResultInfos<QuestionItemShort> getItemsOfPool(Pool pool, SearchQuestionItemParams params, int firstResult, int maxResults, SortKey... orderBy); + public ResultInfos<QuestionItemView> getItemsOfPool(Pool pool, SearchQuestionItemParams params, int firstResult, int maxResults, SortKey... orderBy); - public void addItemToPool(QuestionItemShort item, Pool pool); + public void shareItemsInPools(List<QuestionItemShort> items, List<Pool> pools, boolean editable); //favorit public int getNumOfFavoritItems(Identity identity); - public ResultInfos<QuestionItemShort> getFavoritItems(Identity identity, SearchQuestionItemParams params, int firstResult, int maxResults, SortKey... orderBy); + public ResultInfos<QuestionItemView> getFavoritItems(Identity identity, SearchQuestionItemParams params, int firstResult, int maxResults, SortKey... orderBy); //share - public void shareItems(List<QuestionItemShort> items, List<BusinessGroup> groups); + public void shareItemsWithGroups(List<QuestionItemShort> items, List<BusinessGroup> groups, boolean editable); public List<BusinessGroup> getResourcesWithSharedItems(Identity identity); public int countSharedItemByResource(OLATResource resource); - public ResultInfos<QuestionItemShort> getSharedItemByResource(OLATResource resource, SearchQuestionItemParams params, int firstResult, int maxResults, SortKey... orderBy); + public ResultInfos<QuestionItemView> getSharedItemByResource(OLATResource resource, SearchQuestionItemParams params, int firstResult, int maxResults, SortKey... orderBy); //list public QuestionItemCollection createCollection(Identity owner, String collectionName, List<QuestionItemShort> initialItems); @@ -122,7 +133,7 @@ public interface QPoolService { public int countItemsOfCollection(QuestionItemCollection collection); - public ResultInfos<QuestionItemShort> getItemsOfCollection(QuestionItemCollection collection, SearchQuestionItemParams params, int firstResult, int maxResults, SortKey... orderBy); + public ResultInfos<QuestionItemView> getItemsOfCollection(QuestionItemCollection collection, SearchQuestionItemParams params, int firstResult, int maxResults, SortKey... orderBy); //study field admin @@ -130,7 +141,7 @@ public interface QPoolService { //pool administration - public void createPool(Identity identity, String name); + public void createPool(Identity identity, String name, boolean publicPool); public Pool updatePool(Pool pool); @@ -140,5 +151,26 @@ public interface QPoolService { public ResultInfos<Pool> getPools(int firstResult, int maxResults, SortKey... orderBy); + //item types administration + public QItemType createItemType(String type, boolean deletable); + + public List<QItemType> getAllItemTypes(); + + public QItemType getItemType(String type); + + //item levels administration + public QEducationalContext createEducationalContext(String level); + + public List<QEducationalContext> getAllEducationlContexts(); + + public QEducationalContext getEducationlContextByLevel(String level); + + //licenses administration + public QLicense createLicense(String licenseKey); + + public List<QLicense> getAllLicenses(); + + public QLicense getLicense(String licenseKey); + } diff --git a/src/main/java/org/olat/modules/qpool/QuestionItem.java b/src/main/java/org/olat/modules/qpool/QuestionItem.java index bae7ba8422f..39a0cb8609f 100644 --- a/src/main/java/org/olat/modules/qpool/QuestionItem.java +++ b/src/main/java/org/olat/modules/qpool/QuestionItem.java @@ -19,6 +19,10 @@ */ package org.olat.modules.qpool; +import org.olat.modules.qpool.model.QEducationalContext; +import org.olat.modules.qpool.model.QItemType; +import org.olat.modules.qpool.model.QLicense; + /** * * Initial date: 21.01.2013<br> @@ -42,15 +46,20 @@ public interface QuestionItem extends QuestionItemShort { * @return */ public String getTaxonomicPath(); + + //educational + public QEducationalContext getEducationalContext(); //question + public QItemType getType(); + public String getAssessmentType(); //lifecycle public String getItemVersion(); //rights - public String getCopyright(); + public QLicense getLicense(); //technics public String getEditor(); diff --git a/src/main/java/org/olat/modules/qpool/QuestionItemShort.java b/src/main/java/org/olat/modules/qpool/QuestionItemShort.java index 5bcdadddf00..77b8d1ec9e6 100644 --- a/src/main/java/org/olat/modules/qpool/QuestionItemShort.java +++ b/src/main/java/org/olat/modules/qpool/QuestionItemShort.java @@ -51,14 +51,12 @@ public interface QuestionItemShort extends OLATResourceable { public String getTaxonomyLevelName(); //educational - public String getEducationalContext(); + public String getEducationalContextLevel(); public String getEducationalLearningTime(); //question - public String getType(); - - public QuestionType getQuestionType(); + public String getItemType(); public BigDecimal getDifficulty(); diff --git a/src/main/java/org/olat/modules/qpool/ui/PoolRow.java b/src/main/java/org/olat/modules/qpool/QuestionItemView.java similarity index 71% rename from src/main/java/org/olat/modules/qpool/ui/PoolRow.java rename to src/main/java/org/olat/modules/qpool/QuestionItemView.java index c77df18698a..9563ea7e90e 100644 --- a/src/main/java/org/olat/modules/qpool/ui/PoolRow.java +++ b/src/main/java/org/olat/modules/qpool/QuestionItemView.java @@ -17,33 +17,18 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.modules.qpool.ui; - -import org.olat.modules.qpool.Pool; +package org.olat.modules.qpool; /** * - * Initial date: 28.02.2013<br> + * Initial date: 21.03.2013<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class PoolRow { +public interface QuestionItemView extends QuestionItemShort { - private final Pool pool; + public boolean isEditable(); - public PoolRow(Pool pool) { - this.pool = pool; - } - - public Long getKey() { - return pool.getKey(); - } + public Double getRating(); - public String getName() { - return pool.getName(); - } - - public Pool getPool() { - return pool; - } } diff --git a/src/main/java/org/olat/modules/qpool/manager/AbstractQPoolServiceProvider.java b/src/main/java/org/olat/modules/qpool/manager/AbstractQPoolServiceProvider.java index 0a153331148..74e4adf4794 100644 --- a/src/main/java/org/olat/modules/qpool/manager/AbstractQPoolServiceProvider.java +++ b/src/main/java/org/olat/modules/qpool/manager/AbstractQPoolServiceProvider.java @@ -38,10 +38,11 @@ import org.olat.core.logging.Tracing; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; +import org.olat.core.util.vfs.VFSManager; import org.olat.modules.qpool.QPoolSPI; +import org.olat.modules.qpool.QPoolService; import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QuestionItemFull; -import org.olat.modules.qpool.QPoolService; /** * @@ -112,4 +113,11 @@ public abstract class AbstractQPoolServiceProvider implements QPoolSPI { IOUtils.closeQuietly(in); } } + + @Override + public void copyItem(QuestionItemFull original, QuestionItemFull copy) { + VFSContainer originalDir = getFileStorage().getContainer(original.getDirectory()); + VFSContainer copyDir = getFileStorage().getContainer(copy.getDirectory()); + VFSManager.copyContent(originalDir, copyDir); + } } diff --git a/src/main/java/org/olat/modules/qpool/manager/CollectionDAO.java b/src/main/java/org/olat/modules/qpool/manager/CollectionDAO.java index 74ac0ee4832..79a8da3ab57 100644 --- a/src/main/java/org/olat/modules/qpool/manager/CollectionDAO.java +++ b/src/main/java/org/olat/modules/qpool/manager/CollectionDAO.java @@ -31,6 +31,7 @@ import org.olat.core.commons.persistence.SortKey; import org.olat.core.id.Identity; import org.olat.modules.qpool.QuestionItemCollection; import org.olat.modules.qpool.QuestionItemShort; +import org.olat.modules.qpool.QuestionItemView; import org.olat.modules.qpool.model.CollectionToItem; import org.olat.modules.qpool.model.ItemCollectionImpl; import org.olat.modules.qpool.model.QuestionItemImpl; @@ -117,20 +118,18 @@ public class CollectionDAO { .getSingleResult().intValue(); } - public List<QuestionItemShort> getItemsOfCollection(QuestionItemCollection collection, List<Long> inKeys, + public List<QuestionItemView> getItemsOfCollection(QuestionItemCollection collection, List<Long> inKeys, int firstResult, int maxResults, SortKey... orderBy) { StringBuilder sb = new StringBuilder(); - sb.append("select item from qcollection2item coll2item ") - .append(" inner join coll2item.item item ") - .append(" left join fetch item.taxonomyLevel taxonomyLevel ") - .append(" where coll2item.collection.key=:collectionKey"); + sb.append("select item from qitemview item ") + .append(" where item in (select coll2item.item from qcollection2item coll2item where coll2item.collection.key=:collectionKey)"); if(inKeys != null && !inKeys.isEmpty()) { sb.append(" and item.key in (:itemKeys)"); } PersistenceHelper.appendGroupBy(sb, "coll2item.item", orderBy); - TypedQuery<QuestionItemShort> query = dbInstance.getCurrentEntityManager() - .createQuery(sb.toString(), QuestionItemShort.class) + TypedQuery<QuestionItemView> query = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), QuestionItemView.class) .setParameter("collectionKey", collection.getKey()); if(inKeys != null && !inKeys.isEmpty()) { query.setParameter("itemKeys", inKeys); diff --git a/src/main/java/org/olat/modules/qpool/manager/LOMConverter.java b/src/main/java/org/olat/modules/qpool/manager/LOMConverter.java index 2a31a0fca85..65920902678 100644 --- a/src/main/java/org/olat/modules/qpool/manager/LOMConverter.java +++ b/src/main/java/org/olat/modules/qpool/manager/LOMConverter.java @@ -31,6 +31,8 @@ import javax.xml.transform.stream.StreamResult; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; +import org.olat.modules.qpool.model.LOMDuration; import org.olat.modules.qpool.model.QuestionItemImpl; import org.springframework.stereotype.Service; import org.w3c.dom.Document; @@ -49,6 +51,110 @@ public class LOMConverter { private static final OLog log = Tracing.createLoggerFor(LOMConverter.class); + /** + * P[yY][mM][dD][T[hH][nM][s[.s]S]] where:<br> + * y = number of years (integer, > 0, not restricted)<br> + * m = number of months (integer, > 0, not restricted, e.g., > 12 is acceptable)<br> + * d = number of days (integer, > 0, not restricted, e.g., > 31 is acceptable)<br> + * h = number of hours (integer, > 0, not restricted, e.g., > 23 is acceptable)<br> + * n = number of minutes (integer, > 0, not restricted, e.g., > 59 is acceptable)<br> + * s = number of seconds or fraction of seconds (integer, > 0, not restricted, e.g., > 59 is acceptable)<br> + * + * The character literal designators "P", "Y", "M", "D", "T", "H", "M", "S" must appear if the corresponding nonzero + * value is present. If the value of years, months, days, hours, minutes or seconds is zero, the value and + * corresponding designation (e.g., "M") may be omitted, but at least one designator and value must always be present. + * The designator "P" is always present. The designator "T" shall be omitted if all of the time (hours/minutes/seconds) + * are zero. Negative durations are not supported. NOTE 1:--This value space is based on ISO8601:2000. + * (see also http://www.w3.org/TR/xmlschema-2/#duration) + * PT1H30M, PT1M45S + * @return + */ + public static String convertDuration(int day, int hour, int minute, int seconds) { + StringBuilder sb = new StringBuilder(); + boolean hasD = day > 0; + boolean hasT = (hour > 0 || minute > 0 || seconds > 0); + if(hasD || hasT) { + sb.append("P"); + if(hasD) { + sb.append(day).append("D"); + } + if(hasT) { + sb.append("T"); + if(hour > 0) { + sb.append(hour).append("H"); + } + if(minute > 0) { + sb.append(minute).append("M"); + } + if(seconds > 0) { + sb.append(seconds).append("S"); + } + } + } + return sb.toString(); + } + + public static LOMDuration convertDuration(String durationStr) { + LOMDuration duration = new LOMDuration(); + if(StringHelper.containsNonWhitespace(durationStr) && durationStr.startsWith("P")) { + //remove p + durationStr = durationStr.substring(1, durationStr.length()); + int indexT = durationStr.indexOf('T'); + if(indexT < 0) { + convertDurationP(durationStr, duration); + } else { + String pDurationStr = durationStr.substring(0, indexT); + convertDurationP(pDurationStr, duration); + String tDurationStr = durationStr.substring(indexT + 1, durationStr.length()); + convertDurationT(tDurationStr, duration); + } + } + return duration; + } + + private static void convertDurationP(String durationStr, LOMDuration duration) { + int indexY = durationStr.indexOf('Y'); + if(indexY >= 0) { + duration.setYear(extractValueFromDuration(durationStr, indexY)); + durationStr = durationStr.substring(indexY + 1, durationStr.length()); + } + int indexM = durationStr.indexOf('M'); + if(indexM >= 0) { + duration.setMonth(extractValueFromDuration(durationStr, indexM)); + durationStr = durationStr.substring(indexM + 1, durationStr.length()); + } + int indexD = durationStr.indexOf('D'); + if(indexD >= 0) { + duration.setDay(extractValueFromDuration(durationStr, indexD)); + durationStr = durationStr.substring(indexD + 1, durationStr.length()); + } + } + + private static void convertDurationT(String durationStr, LOMDuration duration) { + int indexH = durationStr.indexOf('H'); + if(indexH >= 0) { + duration.setHour(extractValueFromDuration(durationStr, indexH)); + durationStr = durationStr.substring(indexH + 1, durationStr.length()); + } + int indexMin = durationStr.indexOf('M'); + if(indexMin >= 0) { + duration.setMinute(extractValueFromDuration(durationStr, indexMin)); + durationStr = durationStr.substring(indexMin + 1, durationStr.length()); + } + int indexS = durationStr.indexOf('S'); + if(indexS >= 0) { + duration.setSeconds(extractValueFromDuration(durationStr, indexS)); + durationStr = durationStr.substring(indexS + 1, durationStr.length()); + } + } + + private static int extractValueFromDuration(String durationStr, int index) + throws NumberFormatException { + if(index <= 0) return 0; + String intVal = durationStr.substring(0, index); + return Integer.parseInt(intVal); + } + protected void toLom(QuestionItemImpl item, OutputStream out) { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); diff --git a/src/main/java/org/olat/modules/qpool/manager/NullPoolService.java b/src/main/java/org/olat/modules/qpool/manager/NullPoolService.java index 92ebbe74760..765ef081f8f 100644 --- a/src/main/java/org/olat/modules/qpool/manager/NullPoolService.java +++ b/src/main/java/org/olat/modules/qpool/manager/NullPoolService.java @@ -29,6 +29,7 @@ import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QuestionPoolModule; import org.olat.modules.qpool.QuestionType; import org.olat.modules.qpool.TaxonomyLevel; +import org.olat.modules.qpool.model.QItemType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; @@ -50,12 +51,16 @@ public class NullPoolService implements ApplicationListener<ContextRefreshedEven @Autowired private TaxonomyLevelDAO taxonomyLevelDao; @Autowired + private QItemTypeDAO qItemTypeDao; + @Autowired private QuestionItemDAO questionItemDao; @Autowired private QuestionPoolModule qpoolModule; @Override public void onApplicationEvent(ContextRefreshedEvent event) { + qItemTypeDao.createDefaultTypes(); + int numOfPools = poolDao.countPools(); if(numOfPools == 0) { //create a pool if there isn't any @@ -66,7 +71,7 @@ public class NullPoolService implements ApplicationListener<ContextRefreshedEven } private void createPools() { - poolDao.createPool(null, "Catalog"); + poolDao.createPool(null, "Catalog", true); dbInstance.commit(); } @@ -90,23 +95,24 @@ public class NullPoolService implements ApplicationListener<ContextRefreshedEven private void createQuestions() { List<TaxonomyLevel> fields = taxonomyLevelDao.loadAllLevels(); + List<QItemType> types = qItemTypeDao.getItemTypes(); int numOfQuestions = questionItemDao.getNumOfQuestions(); if(numOfQuestions < 3) { - List<Pool> pools = poolDao.getPools(0, -1); + List<Pool> pools = poolDao.getPools(0, 1); for(int i=0; i<200; i++) { long randomIndex = Math.round(Math.random() * (fields.size() - 1)); TaxonomyLevel field = fields.get((int)randomIndex); - QuestionItem item = questionItemDao.createAndPersist(null, "NGC " + i, QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), field, null, null, randomType()); - poolDao.addItemToPool(item, pools.get(0)); + QuestionItem item = questionItemDao.createAndPersist(null, "NGC " + i, QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), field, null, null, randomType(types)); + poolDao.addItemToPool(item, pools, false); } } dbInstance.commit(); } - private QuestionType randomType() { + private QItemType randomType(List<QItemType> types) { long t = Math.round(Math.random() * (QuestionType.values().length - 1)); - return QuestionType.values()[(int)t]; + return types.get((int)t); } diff --git a/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java b/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java index 069e202ef47..95aacc18a7d 100644 --- a/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java +++ b/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java @@ -27,6 +27,7 @@ import javax.persistence.TypedQuery; import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.SecurityGroup; +import org.olat.basesecurity.SecurityGroupMembershipImpl; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.PersistenceHelper; import org.olat.core.commons.persistence.SortKey; @@ -34,6 +35,7 @@ import org.olat.core.id.Identity; import org.olat.modules.qpool.Pool; import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QuestionItemShort; +import org.olat.modules.qpool.QuestionItemView; import org.olat.modules.qpool.model.PoolImpl; import org.olat.modules.qpool.model.PoolToItem; import org.springframework.beans.factory.annotation.Autowired; @@ -55,12 +57,12 @@ public class PoolDAO { @Autowired private BaseSecurity securityManager; - public PoolImpl createPool(Identity owner, String name) { + public PoolImpl createPool(Identity owner, String name, boolean publicPool) { PoolImpl pool = new PoolImpl(); pool.setCreationDate(new Date()); pool.setLastModified(new Date()); pool.setName(name); - pool.setPublicPool(false); + pool.setPublicPool(publicPool); SecurityGroup ownerGroup = securityManager.createAndPersistSecurityGroup(); pool.setOwnerGroup(ownerGroup); dbInstance.getCurrentEntityManager().persist(pool); @@ -123,6 +125,26 @@ public class PoolDAO { return query.getResultList(); } + public List<Pool> getPools(Identity identity, int firstResult, int maxResults) { + StringBuilder sb = new StringBuilder(); + sb.append("select pool from qpool pool") + .append(" inner join fetch pool.ownerGroup ownerGroup ") + .append(" where pool.publicPool=true") + .append(" or exists (from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as vmember ") + .append(" where vmember.identity.key=:identityKey and vmember.securityGroup=ownerGroup)"); + + TypedQuery<Pool> query = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Pool.class) + .setParameter("identityKey", identity.getKey()); + if(firstResult >= 0) { + query.setFirstResult(firstResult); + } + if(maxResults > 0) { + query.setMaxResults(maxResults); + } + return query.getResultList(); + } + public List<Pool> getPools(QuestionItem item) { StringBuilder sb = new StringBuilder(); sb.append("select distinct(pool) from qpool2item pool2item") @@ -135,14 +157,17 @@ public class PoolDAO { return query.getResultList(); } - public void addItemToPool(QuestionItemShort item, Pool pool) { + public void addItemToPool(QuestionItemShort item, List<Pool> pools, boolean editable) { QuestionItem lockedItem = questionItemDao.loadForUpdate(item.getKey()); - if(!isInPool(lockedItem, pool)) { - PoolToItem p2i = new PoolToItem(); - p2i.setCreationDate(new Date()); - p2i.setItem(lockedItem); - p2i.setPool(pool); - dbInstance.getCurrentEntityManager().persist(p2i); + for(Pool pool:pools) { + if(!isInPool(lockedItem, pool)) { + PoolToItem p2i = new PoolToItem(); + p2i.setCreationDate(new Date()); + p2i.setItem(lockedItem); + p2i.setEditable(editable); + p2i.setPool(pool); + dbInstance.getCurrentEntityManager().persist(p2i); + } } dbInstance.commit();//release lock asap } @@ -167,20 +192,16 @@ public class PoolDAO { .getSingleResult().intValue(); } - public List<QuestionItemShort> getItemsOfPool(Pool pool, List<Long> inKeys, int firstResult, int maxResults, SortKey... orderBy) { + public List<QuestionItemView> getItemsOfPool(Pool pool, List<Long> inKeys, int firstResult, int maxResults, SortKey... orderBy) { StringBuilder sb = new StringBuilder(); - sb.append("select item from qpool2item pool2item") - .append(" inner join pool2item.item item ") - .append(" left join fetch item.taxonomyLevel taxonomyLevel ") - .append(" where pool2item.pool.key=:poolKey"); + sb.append("select item from qpoolitem item where item.poolKey=:poolKey"); if(inKeys != null && inKeys.size() > 0) { sb.append(" and item.key in (:inKeys)"); } + PersistenceHelper.appendGroupBy(sb, "item", orderBy); - PersistenceHelper.appendGroupBy(sb, "pool2item.item", orderBy); - - TypedQuery<QuestionItemShort> query = dbInstance.getCurrentEntityManager() - .createQuery(sb.toString(), QuestionItemShort.class) + TypedQuery<QuestionItemView> query = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), QuestionItemView.class) .setParameter("poolKey", pool.getKey()); if(inKeys != null && inKeys.size() > 0) { query.setParameter("inKeys", inKeys); diff --git a/src/main/java/org/olat/modules/qpool/manager/QEducationalContextDAO.java b/src/main/java/org/olat/modules/qpool/manager/QEducationalContextDAO.java new file mode 100644 index 00000000000..ff5170843f8 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/manager/QEducationalContextDAO.java @@ -0,0 +1,87 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.manager; + +import java.util.Date; +import java.util.List; + +import org.olat.core.commons.persistence.DB; +import org.olat.modules.qpool.model.QEducationalContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 18.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Service("qEduContextDao") +public class QEducationalContextDAO { + + @Autowired + private DB dbInstance; + + public QEducationalContext create(String level, boolean deletable) { + QEducationalContext itemLevel = new QEducationalContext(); + itemLevel.setCreationDate(new Date()); + itemLevel.setLevel(level); + itemLevel.setDeletable(deletable); + dbInstance.getCurrentEntityManager().persist(itemLevel); + return itemLevel; + } + + public QEducationalContext loadById(Long key) { + List<QEducationalContext> contexts = dbInstance.getCurrentEntityManager() + .createNamedQuery("loadQEduContextById", QEducationalContext.class) + .setParameter("contextKey", key) + .getResultList(); + if(contexts.isEmpty()) { + return null; + } + return contexts.get(0); + } + + public QEducationalContext loadByLevel(String level) { + List<QEducationalContext> contexts = dbInstance.getCurrentEntityManager() + .createNamedQuery("loadQEduContextByLevel", QEducationalContext.class) + .setParameter("level", level) + .getResultList(); + if(contexts.isEmpty()) { + return null; + } + return contexts.get(0); + } + + public boolean delete(QEducationalContext level) { + QEducationalContext reloadLevel = loadById(level.getKey()); + if(reloadLevel.isDeletable()) { + dbInstance.getCurrentEntityManager().remove(reloadLevel); + return true; + } + return false; + } + + public List<QEducationalContext> getEducationalContexts() { + return dbInstance.getCurrentEntityManager() + .createNamedQuery("loadQEduContexts", QEducationalContext.class) + .getResultList(); + } +} diff --git a/src/main/java/org/olat/modules/qpool/manager/QItemTypeDAO.java b/src/main/java/org/olat/modules/qpool/manager/QItemTypeDAO.java new file mode 100644 index 00000000000..62c94bfa56d --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/manager/QItemTypeDAO.java @@ -0,0 +1,111 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.manager; + +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.olat.core.commons.persistence.DB; +import org.olat.modules.qpool.QuestionType; +import org.olat.modules.qpool.model.QItemType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 15.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +@Service("qpoolItemTypeDao") +public class QItemTypeDAO implements ApplicationListener<ContextRefreshedEvent> { + + @Autowired + private DB dbInstance; + + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + createDefaultTypes(); + } + + + protected void createDefaultTypes() { + List<QItemType> types = getItemTypes(); + Set<String> typeKeys = new HashSet<String>(); + for(QItemType type:types) { + typeKeys.add(type.getType()); + } + for(QuestionType defaultType:QuestionType.values()) { + if(!typeKeys.contains(defaultType.name())) { + create(defaultType.name(), false); + } + } + dbInstance.commitAndCloseSession(); + } + + public QItemType create(String type, boolean deletable) { + QItemType itemType = new QItemType(); + itemType.setCreationDate(new Date()); + itemType.setType(type.toLowerCase()); + itemType.setDeletable(deletable); + dbInstance.getCurrentEntityManager().persist(itemType); + return itemType; + } + + public QItemType loadById(Long key) { + List<QItemType> types = dbInstance.getCurrentEntityManager() + .createNamedQuery("loadQItemTypeById", QItemType.class) + .setParameter("itemTypeKey", key) + .getResultList(); + if(types.isEmpty()) { + return null; + } + return types.get(0); + } + + public QItemType loadByType(String type) { + List<QItemType> types = dbInstance.getCurrentEntityManager() + .createNamedQuery("loadQItemTypeByType", QItemType.class) + .setParameter("itemType", type.toLowerCase()) + .getResultList(); + if(types.isEmpty()) { + return null; + } + return types.get(0); + } + + public boolean delete(QItemType type) { + QItemType reloadType = loadById(type.getKey()); + if(reloadType.isDeletable()) { + dbInstance.getCurrentEntityManager().remove(reloadType); + return true; + } + return false; + } + + public List<QItemType> getItemTypes() { + return dbInstance.getCurrentEntityManager() + .createNamedQuery("loadQItemTypes", QItemType.class) + .getResultList(); + } +} diff --git a/src/main/java/org/olat/modules/qpool/manager/QLicenseDAO.java b/src/main/java/org/olat/modules/qpool/manager/QLicenseDAO.java new file mode 100644 index 00000000000..a2c15c07bda --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/manager/QLicenseDAO.java @@ -0,0 +1,116 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.manager; + +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.olat.core.commons.persistence.DB; +import org.olat.modules.qpool.model.QLicense; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 18.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Service("qpoolLicenseDao") +public class QLicenseDAO implements ApplicationListener<ContextRefreshedEvent> { + + @Autowired + private DB dbInstance; + + protected static final String[] defaultLicenses = new String[] { + "all rights reserved", + "CC by", "CC by-sa", "CC by-nd", "CC by-nc", "CC by-nc-sa", "CC by-nc-nd" + }; + + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + createDefaultLicenses(); + } + + protected void createDefaultLicenses() { + List<QLicense> licenses = getLicenses(); + Set<String> licenseKeys = new HashSet<String>(); + for(QLicense license:licenses) { + licenseKeys.add(license.getLicenseKey()); + } + for(String defaultLicenseKey:defaultLicenses) { + if(!licenseKeys.contains(defaultLicenseKey)) { + create(defaultLicenseKey, false); + } + } + dbInstance.commitAndCloseSession(); + } + + public QLicense create(String licenseKey, boolean deletable) { + QLicense license = new QLicense(); + license.setCreationDate(new Date()); + license.setLicenseKey(licenseKey); + license.setDeletable(deletable); + dbInstance.getCurrentEntityManager().persist(license); + return license; + } + + public QLicense loadById(Long key) { + List<QLicense> licenses = dbInstance.getCurrentEntityManager() + .createNamedQuery("loadQLicenseById", QLicense.class) + .setParameter("licenseKey", key) + .getResultList(); + if(licenses.isEmpty()) { + return null; + } + return licenses.get(0); + } + + public QLicense loadByLicenseKey(String licenseKey) { + List<QLicense> licenses = dbInstance.getCurrentEntityManager() + .createNamedQuery("loadQLicenseByLicenseKey", QLicense.class) + .setParameter("licenseKey", licenseKey) + .getResultList(); + if(licenses.isEmpty()) { + return null; + } + return licenses.get(0); + } + + + public boolean delete(QLicense license) { + QLicense reloadLicense = loadById(license.getKey()); + if(reloadLicense.isDeletable()) { + dbInstance.getCurrentEntityManager().remove(reloadLicense); + return true; + } + return false; + } + + public List<QLicense> getLicenses() { + return dbInstance.getCurrentEntityManager() + .createNamedQuery("loadQLicenses", QLicense.class) + .getResultList(); + } +} diff --git a/src/main/java/org/olat/modules/qpool/manager/QuestionItemDAO.java b/src/main/java/org/olat/modules/qpool/manager/QuestionItemDAO.java index d304bbef4d6..70b5644742d 100644 --- a/src/main/java/org/olat/modules/qpool/manager/QuestionItemDAO.java +++ b/src/main/java/org/olat/modules/qpool/manager/QuestionItemDAO.java @@ -20,6 +20,7 @@ package org.olat.modules.qpool.manager; import java.util.ArrayList; +import java.util.Collection; import java.util.Date; import java.util.List; import java.util.UUID; @@ -32,15 +33,18 @@ import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.SecurityGroup; import org.olat.basesecurity.SecurityGroupMembershipImpl; import org.olat.core.commons.persistence.DB; +import org.olat.core.commons.persistence.PersistenceHelper; import org.olat.core.commons.persistence.SortKey; import org.olat.core.commons.services.mark.impl.MarkImpl; import org.olat.core.id.Identity; import org.olat.group.BusinessGroup; import org.olat.modules.qpool.QuestionItem; +import org.olat.modules.qpool.QuestionItemFull; import org.olat.modules.qpool.QuestionItemShort; +import org.olat.modules.qpool.QuestionItemView; import org.olat.modules.qpool.QuestionStatus; -import org.olat.modules.qpool.QuestionType; import org.olat.modules.qpool.TaxonomyLevel; +import org.olat.modules.qpool.model.QItemType; import org.olat.modules.qpool.model.QuestionItemImpl; import org.olat.modules.qpool.model.ResourceShareImpl; import org.olat.resource.OLATResource; @@ -86,10 +90,10 @@ public class QuestionItemDAO { } public QuestionItemImpl createAndPersist(Identity owner, String subject, String format, String language, - TaxonomyLevel taxonLevel, String dir, String rootFilename, QuestionType type) { + TaxonomyLevel taxonLevel, String dir, String rootFilename, QItemType type) { QuestionItemImpl item = create(subject, format, dir, rootFilename); if(type != null) { - item.setType(type.name()); + item.setType(type); } item.setLanguage(language); item.setTaxonomyLevel(taxonLevel); @@ -108,46 +112,44 @@ public class QuestionItemDAO { } } - public QuestionItemImpl copy(Identity owner, QuestionItemShort itemToCopyRef) { - QuestionItemImpl itemToCopy = loadById(itemToCopyRef.getKey()); - - String subject = "(Copy) " + itemToCopy.getTitle(); - QuestionItemImpl copy = create(subject, itemToCopy.getFormat(), null, itemToCopy.getRootFilename()); + public QuestionItemImpl copy(Identity owner, QuestionItemImpl original) { + String subject = "(Copy) " + original.getTitle(); + QuestionItemImpl copy = create(subject, original.getFormat(), null, original.getRootFilename()); //general - copy.setMasterIdentifier(itemToCopy.getIdentifier()); - copy.setDescription(itemToCopy.getDescription()); - copy.setKeywords(itemToCopy.getKeywords()); - copy.setCoverage(itemToCopy.getCoverage()); - copy.setAdditionalInformations(itemToCopy.getAdditionalInformations()); - copy.setLanguage(itemToCopy.getLanguage()); + copy.setMasterIdentifier(original.getIdentifier()); + copy.setDescription(original.getDescription()); + copy.setKeywords(original.getKeywords()); + copy.setCoverage(original.getCoverage()); + copy.setAdditionalInformations(original.getAdditionalInformations()); + copy.setLanguage(original.getLanguage()); //classification - copy.setTaxonomyLevel(itemToCopy.getTaxonomyLevel()); + copy.setTaxonomyLevel(original.getTaxonomyLevel()); //educational - copy.setEducationalContext(itemToCopy.getEducationalContext()); - copy.setEducationalLearningTime(itemToCopy.getEducationalLearningTime()); + copy.setEducationalContext(original.getEducationalContext()); + copy.setEducationalLearningTime(original.getEducationalLearningTime()); //item - copy.setType(itemToCopy.getType()); - copy.setDifficulty(itemToCopy.getDifficulty()); - copy.setStdevDifficulty(itemToCopy.getStdevDifficulty()); - copy.setDifferentiation(itemToCopy.getDifferentiation()); - copy.setNumOfAnswerAlternatives(itemToCopy.getNumOfAnswerAlternatives()); + copy.setType(original.getType()); + copy.setDifficulty(original.getDifficulty()); + copy.setStdevDifficulty(original.getStdevDifficulty()); + copy.setDifferentiation(original.getDifferentiation()); + copy.setNumOfAnswerAlternatives(original.getNumOfAnswerAlternatives()); copy.setUsage(0); - copy.setAssessmentType(itemToCopy.getAssessmentType()); + copy.setAssessmentType(original.getAssessmentType()); //lifecycle - copy.setItemVersion(itemToCopy.getItemVersion()); + copy.setItemVersion(original.getItemVersion()); copy.setStatus(QuestionStatus.draft.name()); //rights - copy.setCopyright(itemToCopy.getCopyright()); + copy.setLicense(original.getLicense()); //technical - copy.setEditor(itemToCopy.getEditor()); - copy.setEditorVersion(itemToCopy.getEditorVersion()); + copy.setEditor(original.getEditor()); + copy.setEditorVersion(original.getEditorVersion()); persist(owner, copy); return copy; @@ -196,21 +198,16 @@ public class QuestionItemDAO { .getSingleResult().intValue(); } - public List<QuestionItemShort> getItems(Identity me, List<Long> inKeys, int firstResult, int maxResults, SortKey... orderBy) { + public List<QuestionItemView> getItems(Identity me, List<Long> inKeys, int firstResult, int maxResults, SortKey... orderBy) { StringBuilder sb = new StringBuilder(); - sb.append("select item from questionitem item") - .append(" inner join item.ownerGroup ownerGroup ") - .append(" left join fetch item.taxonomyLevel taxonomyLevel ") - .append(" where ownerGroup in (") - .append(" select vmember.securityGroup from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as vmember ") - .append(" where vmember.identity.key=:identityKey and vmember.securityGroup=ownerGroup") - .append(" )"); + sb.append("select item from qauthoritem item where item.authorKey=:identityKey"); if(inKeys != null && !inKeys.isEmpty()) { sb.append(" and item.key in (:itemKeys)"); } + PersistenceHelper.appendGroupBy(sb, "item", orderBy); - TypedQuery<QuestionItemShort> query = dbInstance.getCurrentEntityManager() - .createQuery(sb.toString(), QuestionItemShort.class) + TypedQuery<QuestionItemView> query = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), QuestionItemView.class) .setParameter("identityKey", me.getKey()); if(inKeys != null && !inKeys.isEmpty()) { query.setParameter("itemKeys", inKeys); @@ -226,7 +223,12 @@ public class QuestionItemDAO { public List<QuestionItem> getAllItems(int firstResult, int maxResults) { StringBuilder sb = new StringBuilder(); - sb.append("select item from questionitem item order by item.key"); + sb.append("select item from questionitem item") + .append(" left join fetch item.taxonomyLevel taxonomyLevel") + .append(" left join fetch item.license license") + .append(" left join fetch item.type itemType") + .append(" left join fetch item.educationalContext educationalContext") + .append(" order by item.key"); TypedQuery<QuestionItem> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), QuestionItem.class); @@ -249,7 +251,12 @@ public class QuestionItemDAO { public QuestionItemImpl loadById(Long key) { StringBuilder sb = new StringBuilder(); - sb.append("select item from questionitem item where item.key=:key"); + sb.append("select item from questionitem item") + .append(" left join fetch item.taxonomyLevel taxonomyLevel") + .append(" left join fetch item.license license") + .append(" left join fetch item.type itemType") + .append(" left join fetch item.educationalContext educationalContext") + .append(" where item.key=:key"); List<QuestionItemImpl> items = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), QuestionItemImpl.class) .setParameter("key", key) @@ -261,6 +268,21 @@ public class QuestionItemDAO { return items.get(0); } + public List<QuestionItemFull> loadByIds(Collection<Long> key) { + StringBuilder sb = new StringBuilder(); + sb.append("select item from questionitem item") + .append(" left join fetch item.taxonomyLevel taxonomyLevel") + .append(" left join fetch item.license license") + .append(" left join fetch item.type itemType") + .append(" left join fetch item.educationalContext educationalContext") + .append(" where item.key in (:keys)"); + List<QuestionItemFull> items = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), QuestionItemFull.class) + .setParameter("keys", key) + .getResultList(); + return items; + } + public QuestionItemImpl loadForUpdate(Long key) { StringBuilder sb = new StringBuilder(); sb.append("select item from questionitem item where item.key=:key"); @@ -303,19 +325,20 @@ public class QuestionItemDAO { return query.getResultList(); } - public List<QuestionItemShort> getFavoritItems(Identity identity, List<Long> inKeys, int firstResult, int maxResults) { + public List<QuestionItemView> getFavoritItems(Identity identity, List<Long> inKeys, + int firstResult, int maxResults, SortKey... orderBy) { StringBuilder sb = new StringBuilder(); - sb.append("select item from questionitem item") - .append(" left join fetch item.taxonomyLevel taxonomyLevel") + sb.append("select item from qitemview item") .append(" where item.key in (") .append(" select mark.resId from ").append(MarkImpl.class.getName()).append(" mark where mark.creator.key=:identityKey and mark.resName='QuestionItem'") .append(" )"); if(inKeys != null && !inKeys.isEmpty()) { sb.append(" and item.key in (:itemKeys)"); } + PersistenceHelper.appendGroupBy(sb, "item", orderBy); - TypedQuery<QuestionItemShort> query = dbInstance.getCurrentEntityManager() - .createQuery(sb.toString(), QuestionItemShort.class) + TypedQuery<QuestionItemView> query = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), QuestionItemView.class) .setParameter("identityKey", identity.getKey()); if(inKeys != null && !inKeys.isEmpty()) { query.setParameter("itemKeys", inKeys); @@ -342,7 +365,7 @@ public class QuestionItemDAO { dbInstance.commit();//release the lock asap } - public void share(Long itemKey, List<OLATResource> resources) { + public void share(Long itemKey, List<OLATResource> resources, boolean editable) { EntityManager em = dbInstance.getCurrentEntityManager(); QuestionItem lockedItem = loadForUpdate(itemKey); for(OLATResource resource:resources) { @@ -350,6 +373,7 @@ public class QuestionItemDAO { ResourceShareImpl share = new ResourceShareImpl(); share.setCreationDate(new Date()); share.setItem(lockedItem); + share.setEditable(editable); share.setResource(resource); em.persist(share); } @@ -382,19 +406,17 @@ public class QuestionItemDAO { return count.intValue(); } - public List<QuestionItemShort> getSharedItemByResource(OLATResource resource, List<Long> inKeys, + public List<QuestionItemView> getSharedItemByResource(OLATResource resource, List<Long> inKeys, int firstResult, int maxResults, SortKey... orderBy) { StringBuilder sb = new StringBuilder(); - sb.append("select item from qshareitem share") - .append(" inner join share.item item") - .append(" left join fetch item.taxonomyLevel taxonomyLevel") - .append(" where share.resource.key=:resourceKey"); + sb.append("select item from qshareditemview item where item.resourceKey=:resourceKey"); if(inKeys != null && !inKeys.isEmpty()) { sb.append(" and item.key in (:itemKeys)"); } + PersistenceHelper.appendGroupBy(sb, "item", orderBy); - TypedQuery<QuestionItemShort> query = dbInstance.getCurrentEntityManager() - .createQuery(sb.toString(), QuestionItemShort.class) + TypedQuery<QuestionItemView> query = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), QuestionItemView.class) .setParameter("resourceKey", resource.getKey()); if(inKeys != null && !inKeys.isEmpty()) { query.setParameter("itemKeys", inKeys); diff --git a/src/main/java/org/olat/modules/qpool/manager/QuestionItemDocumentFactory.java b/src/main/java/org/olat/modules/qpool/manager/QuestionItemDocumentFactory.java index d3de1f17ae4..1d70d2aa553 100644 --- a/src/main/java/org/olat/modules/qpool/manager/QuestionItemDocumentFactory.java +++ b/src/main/java/org/olat/modules/qpool/manager/QuestionItemDocumentFactory.java @@ -105,11 +105,15 @@ public class QuestionItemDocumentFactory { addStringField(document, QItemDocument.LANGUAGE_FIELD, item.getLanguage(), 1.0f); //educational - addStringField(document, QItemDocument.EDU_CONTEXT_FIELD, item.getEducationalContext(), 1.0f); + if(item.getEducationalContext() != null) { + String context = item.getEducationalContext().getLevel(); + addStringField(document, QItemDocument.EDU_CONTEXT_FIELD, context, 1.0f); + } //question - if(item.getQuestionType() != null) { - addStringField(document, QItemDocument.ITEM_TYPE_FIELD, item.getQuestionType().name(), 1.0f); + if(item.getType() != null) { + String itemType = item.getType().getType(); + addStringField(document, QItemDocument.ITEM_TYPE_FIELD, itemType, 1.0f); } addStringField(document, QItemDocument.ASSESSMENT_TYPE_FIELD, item.getAssessmentType(), 1.0f); @@ -120,7 +124,10 @@ public class QuestionItemDocumentFactory { } //rights - addTextField(document, QItemDocument.COPYRIGHT_FIELD, item.getCopyright(), 2.0f); + if(item.getLicense() != null) { + String licenseKey = item.getLicense().getLicenseKey(); + addTextField(document, QItemDocument.COPYRIGHT_FIELD, licenseKey, 2.0f); + } //technical addTextField(document, QItemDocument.EDITOR_FIELD, item.getEditor(), 2.0f); diff --git a/src/main/java/org/olat/modules/qpool/manager/QuestionPoolServiceImpl.java b/src/main/java/org/olat/modules/qpool/manager/QuestionPoolServiceImpl.java index 2536f2c603f..cf84ae8ca0b 100644 --- a/src/main/java/org/olat/modules/qpool/manager/QuestionPoolServiceImpl.java +++ b/src/main/java/org/olat/modules/qpool/manager/QuestionPoolServiceImpl.java @@ -25,11 +25,13 @@ import java.util.List; import java.util.zip.ZipOutputStream; import org.olat.basesecurity.BaseSecurity; +import org.olat.basesecurity.SecurityGroup; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.DefaultResultInfos; import org.olat.core.commons.persistence.ResultInfos; import org.olat.core.commons.persistence.SortKey; import org.olat.core.id.Identity; +import org.olat.core.id.Roles; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; @@ -43,10 +45,14 @@ import org.olat.modules.qpool.QPoolService; import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QuestionItemCollection; import org.olat.modules.qpool.QuestionItemShort; +import org.olat.modules.qpool.QuestionItemView; import org.olat.modules.qpool.QuestionPoolModule; -import org.olat.modules.qpool.QuestionType; import org.olat.modules.qpool.TaxonomyLevel; +import org.olat.modules.qpool.model.PoolImpl; +import org.olat.modules.qpool.model.QEducationalContext; import org.olat.modules.qpool.model.QItemDocument; +import org.olat.modules.qpool.model.QItemType; +import org.olat.modules.qpool.model.QLicense; import org.olat.modules.qpool.model.QuestionItemImpl; import org.olat.modules.qpool.model.SearchQuestionItemParams; import org.olat.resource.OLATResource; @@ -74,6 +80,12 @@ public class QuestionPoolServiceImpl implements QPoolService { @Autowired private CollectionDAO collectionDao; @Autowired + private QLicenseDAO qpoolLicenseDao; + @Autowired + private QItemTypeDAO qpoolItemTypeDao; + @Autowired + private QEducationalContextDAO qEduContextDao; + @Autowired private TaxonomyLevelDAO taxonomyLevelDao; @Autowired private QuestionItemDAO questionItemDao; @@ -87,15 +99,6 @@ public class QuestionPoolServiceImpl implements QPoolService { private LifeFullIndexer lifeIndexer; - @Override - public String getTaxonomicPath(QuestionItem item) { - QuestionItemImpl reloadedItem = questionItemDao.loadById(item.getKey()); - if(reloadedItem.getTaxonomyLevel() == null) { - return ""; - } - return reloadedItem.getTaxonomyLevel().getMaterializedPathNames(); - } - @Override public void deleteItems(List<QuestionItemShort> items) { if(items == null || items.isEmpty()) { @@ -109,6 +112,17 @@ public class QuestionPoolServiceImpl implements QPoolService { questionItemDao.delete(items); } + @Override + public boolean isAuthor(QuestionItem item, Identity identity) { + QuestionItemImpl itemImpl; + if(item instanceof QuestionItemImpl) { + itemImpl = (QuestionItemImpl)item; + } else { + itemImpl = questionItemDao.loadById(item.getKey()); + } + return securityManager.isIdentityInSecurityGroup(identity, itemImpl.getOwnerGroup()); + } + @Override public void addAuthors(List<Identity> authors, List<QuestionItemShort> items) { if(authors == null || authors.isEmpty() || items == null || items.isEmpty()) { @@ -156,11 +170,15 @@ public class QuestionPoolServiceImpl implements QPoolService { @Override - public List<QuestionItem> copyItems(Identity cloner, List<QuestionItemShort> itemsToCopy) { + public List<QuestionItem> copyItems(Identity owner, List<QuestionItemShort> itemsToCopy) { List<QuestionItem> copies = new ArrayList<QuestionItem>(); for(QuestionItemShort itemToCopy:itemsToCopy) { - QuestionItemImpl copy = questionItemDao.copy(cloner, itemToCopy); - + QuestionItemImpl original = questionItemDao.loadById(itemToCopy.getKey()); + QuestionItemImpl copy = questionItemDao.copy(owner, original); + QPoolSPI provider = qpoolModule.getQuestionPoolProvider(copy.getFormat()); + if(provider != null) { + provider.copyItem(original, copy); + } copies.add(copy); } return copies; @@ -217,65 +235,17 @@ public class QuestionPoolServiceImpl implements QPoolService { @Override public QuestionItem createAndPersistItem(Identity owner, String subject, String format, String language, - TaxonomyLevel taxonLevel, String dir, String rootFilename, QuestionType type) { + TaxonomyLevel taxonLevel, String dir, String rootFilename, QItemType type) { return questionItemDao.createAndPersist(owner, subject, format, language, taxonLevel, dir, rootFilename, type); } - /*private QuestionItem importItem(Identity owner, String filename, File file, QPoolSPI provider) { - String uuid = UUID.randomUUID().toString(); - VFSContainer root = qpoolModule.getRootContainer(); - VFSContainer itemDir = FileStorage.getDirectory(root, uuid); - - String rootFilename = filename; - if(filename.toLowerCase().endsWith(".zip")) { - ZipUtil.unzipStrict(file, itemDir); - rootFilename = searchRootFilename("", itemDir, provider); - } else { - //copy - VFSLeaf leaf = itemDir.createChildLeaf(filename); - OutputStream out = leaf.getOutputStream(false); - InputStream in = null; - try { - in = new FileInputStream(file); - IOUtils.copy(in, out); - } catch (FileNotFoundException e) { - log.error("", e); - } catch (IOException e) { - log.error("", e); - } finally { - IOUtils.closeQuietly(in); - IOUtils.closeQuietly(out); - } - } - - return questionItemDao.create(owner, filename, provider.getFormat(), "de", null, uuid, rootFilename, null); - } - - private String searchRootFilename(String path, VFSContainer dir, QPoolSPI provider) { - for(VFSItem item:dir.getItems()) { - if(item instanceof VFSContainer) { - String root = searchRootFilename(path + "/" + item.getName(), (VFSContainer)item, provider); - if(root != null) { - return root; - } - } else if(item instanceof VFSLeaf) { - if(provider.isCompatible(item.getName(), (VFSLeaf)item)) { - return path + item.getName(); - } - } - } - return null; - }*/ - - - @Override public int countItems(Identity author) { return questionItemDao.countItems(author); } @Override - public ResultInfos<QuestionItemShort> getItems(Identity author, SearchQuestionItemParams searchParams, int firstResult, int maxResults, SortKey... orderBy) { + public ResultInfos<QuestionItemView> getItems(Identity author, SearchQuestionItemParams searchParams, int firstResult, int maxResults, SortKey... orderBy) { if(searchParams != null && StringHelper.containsNonWhitespace(searchParams.getSearchString())) { try { String queryString = searchParams.getSearchString(); @@ -286,19 +256,19 @@ public class QuestionPoolServiceImpl implements QPoolService { int initialResultsSize = results.size(); if(results.isEmpty()) { - return new DefaultResultInfos<QuestionItemShort>(); + return new DefaultResultInfos<QuestionItemView>(); } else if(results.size() > maxResults) { results = results.subList(0, Math.min(results.size(), maxResults * 2)); } - List<QuestionItemShort> items = questionItemDao.getItems(author, results, firstResult, maxResults, orderBy); - return new DefaultResultInfos<QuestionItemShort>(firstResult + items.size(), firstResult + initialResultsSize, items); + List<QuestionItemView> items = questionItemDao.getItems(author, results, firstResult, maxResults, orderBy); + return new DefaultResultInfos<QuestionItemView>(firstResult + items.size(), firstResult + initialResultsSize, items); } catch (Exception e) { log.error("", e); } - return new DefaultResultInfos<QuestionItemShort>(); + return new DefaultResultInfos<QuestionItemView>(); } else { - List<QuestionItemShort> items = questionItemDao.getItems(author, null, firstResult, maxResults, orderBy); - return new DefaultResultInfos<QuestionItemShort>(firstResult + items.size(), -1, items); + List<QuestionItemView> items = questionItemDao.getItems(author, null, firstResult, maxResults, orderBy); + return new DefaultResultInfos<QuestionItemView>(firstResult + items.size(), -1, items); } } @@ -308,8 +278,41 @@ public class QuestionPoolServiceImpl implements QPoolService { } @Override - public List<Pool> getPools(Identity identity) { - return poolDao.getPools(0, -1); + public List<Pool> getPools(Identity identity, Roles roles) { + if(roles.isOLATAdmin()) { + return poolDao.getPools(0, -1); + } + return poolDao.getPools(identity, 0, -1); + } + + @Override + public void addOwners(List<Identity> owners, List<Pool> pools) { + if(owners == null || owners.isEmpty() || pools == null || pools.isEmpty()) { + return;//nothing to do + } + + for(Pool pool:pools) { + SecurityGroup secGroup = ((PoolImpl)pool).getOwnerGroup(); + for(Identity owner:owners) { + if(!securityManager.isIdentityInSecurityGroup(owner, secGroup)) { + securityManager.addIdentityToSecurityGroup(owner, secGroup); + } + } + } + } + + @Override + public void removeOwners(List<Identity> owners, List<Pool> pools) { + if(owners == null || owners.isEmpty() || pools == null || pools.isEmpty()) { + return;//nothing to do + } + + List<SecurityGroup> secGroups = new ArrayList<SecurityGroup>(pools.size()); + for(Pool pool:pools) { + SecurityGroup secGroup = ((PoolImpl)pool).getOwnerGroup(); + secGroups.add(secGroup); + } + securityManager.removeIdentityFromSecurityGroups(owners, secGroups); } @Override @@ -318,7 +321,7 @@ public class QuestionPoolServiceImpl implements QPoolService { } @Override - public ResultInfos<QuestionItemShort> getItemsOfPool(Pool pool, SearchQuestionItemParams searchParams, + public ResultInfos<QuestionItemView> getItemsOfPool(Pool pool, SearchQuestionItemParams searchParams, int firstResult, int maxResults, SortKey... orderBy) { if(searchParams != null && StringHelper.containsNonWhitespace(searchParams.getSearchString())) { @@ -331,25 +334,31 @@ public class QuestionPoolServiceImpl implements QPoolService { int initialResultsSize = results.size(); if(results.isEmpty()) { - return new DefaultResultInfos<QuestionItemShort>(); + return new DefaultResultInfos<QuestionItemView>(); } else if(results.size() > maxResults) { results = results.subList(0, Math.min(results.size(), maxResults * 2)); } - List<QuestionItemShort> items = poolDao.getItemsOfPool(pool, results, 0, maxResults, orderBy); - return new DefaultResultInfos<QuestionItemShort>(firstResult + items.size(), firstResult + initialResultsSize, items); + List<QuestionItemView> items = poolDao.getItemsOfPool(pool, results, 0, maxResults, orderBy); + return new DefaultResultInfos<QuestionItemView>(firstResult + items.size(), firstResult + initialResultsSize, items); } catch (Exception e) { log.error("", e); } - return new DefaultResultInfos<QuestionItemShort>(); + return new DefaultResultInfos<QuestionItemView>(); } else { - List<QuestionItemShort> items = poolDao.getItemsOfPool(pool, null, firstResult, maxResults, orderBy); - return new DefaultResultInfos<QuestionItemShort>(firstResult + items.size(), -1, items); + List<QuestionItemView> items = poolDao.getItemsOfPool(pool, null, firstResult, maxResults, orderBy); + return new DefaultResultInfos<QuestionItemView>(firstResult + items.size(), -1, items); } } @Override - public void addItemToPool(QuestionItemShort item, Pool pool) { - poolDao.addItemToPool(item, pool); + public void shareItemsInPools(List<QuestionItemShort> items, List<Pool> pools, boolean editable) { + if(items == null || items.isEmpty() || pools == null || pools.isEmpty()) { + return;//nothing to do + } + + for(QuestionItemShort item:items) { + poolDao.addItemToPool(item, pools, editable); + } } @Override @@ -358,7 +367,7 @@ public class QuestionPoolServiceImpl implements QPoolService { } @Override - public ResultInfos<QuestionItemShort> getFavoritItems(Identity identity, SearchQuestionItemParams searchParams, + public ResultInfos<QuestionItemView> getFavoritItems(Identity identity, SearchQuestionItemParams searchParams, int firstResult, int maxResults, SortKey... orderBy) { if(searchParams != null && StringHelper.containsNonWhitespace(searchParams.getSearchString())) { @@ -373,17 +382,17 @@ public class QuestionPoolServiceImpl implements QPoolService { searchParams.getIdentity(), searchParams.getRoles(), firstResult, maxResults * 5, orderBy); if(results.isEmpty()) { - return new DefaultResultInfos<QuestionItemShort>(); + return new DefaultResultInfos<QuestionItemView>(); } - List<QuestionItemShort> items = questionItemDao.getFavoritItems(identity, results, firstResult, maxResults); - return new DefaultResultInfos<QuestionItemShort>(firstResult + items.size(), firstResult + results.size(), items); + List<QuestionItemView> items = questionItemDao.getFavoritItems(identity, results, firstResult, maxResults, orderBy); + return new DefaultResultInfos<QuestionItemView>(firstResult + items.size(), firstResult + results.size(), items); } catch (Exception e) { log.error("", e); } - return new DefaultResultInfos<QuestionItemShort>(); + return new DefaultResultInfos<QuestionItemView>(); } else { - List<QuestionItemShort> items = questionItemDao.getFavoritItems(identity, null, firstResult, maxResults); - return new DefaultResultInfos<QuestionItemShort>(firstResult + items.size(), -1, items); + List<QuestionItemView> items = questionItemDao.getFavoritItems(identity, null, firstResult, maxResults, orderBy); + return new DefaultResultInfos<QuestionItemView>(firstResult + items.size(), -1, items); } } @@ -398,7 +407,7 @@ public class QuestionPoolServiceImpl implements QPoolService { } @Override - public void shareItems(List<QuestionItemShort> items, List<BusinessGroup> groups) { + public void shareItemsWithGroups(List<QuestionItemShort> items, List<BusinessGroup> groups, boolean editable) { if(items == null || items.isEmpty() || groups == null || groups.isEmpty()) { return;//nothing to do } @@ -409,7 +418,7 @@ public class QuestionPoolServiceImpl implements QPoolService { } for(QuestionItemShort item:items) { - questionItemDao.share(item.getKey(), resources); + questionItemDao.share(item.getKey(), resources, editable); } } @@ -424,7 +433,7 @@ public class QuestionPoolServiceImpl implements QPoolService { } @Override - public ResultInfos<QuestionItemShort> getSharedItemByResource(OLATResource resource, SearchQuestionItemParams searchParams, + public ResultInfos<QuestionItemView> getSharedItemByResource(OLATResource resource, SearchQuestionItemParams searchParams, int firstResult, int maxResults, SortKey... orderBy) { if(searchParams != null && StringHelper.containsNonWhitespace(searchParams.getSearchString())) { @@ -437,19 +446,19 @@ public class QuestionPoolServiceImpl implements QPoolService { int initialResultsSize = results.size(); if(results.isEmpty()) { - return new DefaultResultInfos<QuestionItemShort>(); + return new DefaultResultInfos<QuestionItemView>(); } else if(results.size() > maxResults) { results = results.subList(0, Math.min(results.size(), maxResults * 2)); } - List<QuestionItemShort> items = questionItemDao.getSharedItemByResource(resource, results, firstResult, maxResults); - return new DefaultResultInfos<QuestionItemShort>(firstResult + items.size(), firstResult + initialResultsSize, items); + List<QuestionItemView> items = questionItemDao.getSharedItemByResource(resource, results, firstResult, maxResults); + return new DefaultResultInfos<QuestionItemView>(firstResult + items.size(), firstResult + initialResultsSize, items); } catch (Exception e) { log.error("", e); } - return new DefaultResultInfos<QuestionItemShort>(); + return new DefaultResultInfos<QuestionItemView>(); } else { - List<QuestionItemShort> items = questionItemDao.getSharedItemByResource(resource, null, firstResult, maxResults, orderBy); - return new DefaultResultInfos<QuestionItemShort>(firstResult + items.size(), -1, items); + List<QuestionItemView> items = questionItemDao.getSharedItemByResource(resource, null, firstResult, maxResults, orderBy); + return new DefaultResultInfos<QuestionItemView>(firstResult + items.size(), -1, items); } } @@ -478,7 +487,7 @@ public class QuestionPoolServiceImpl implements QPoolService { } @Override - public ResultInfos<QuestionItemShort> getItemsOfCollection(QuestionItemCollection collection, SearchQuestionItemParams searchParams, + public ResultInfos<QuestionItemView> getItemsOfCollection(QuestionItemCollection collection, SearchQuestionItemParams searchParams, int firstResult, int maxResults, SortKey... orderBy) { if(searchParams != null && StringHelper.containsNonWhitespace(searchParams.getSearchString())) { @@ -492,23 +501,23 @@ public class QuestionPoolServiceImpl implements QPoolService { firstResult, maxResults * 5, orderBy); if(results.isEmpty()) { - return new DefaultResultInfos<QuestionItemShort>(); + return new DefaultResultInfos<QuestionItemView>(); } - List<QuestionItemShort> items = collectionDao.getItemsOfCollection(collection, results, firstResult, maxResults, orderBy); - return new DefaultResultInfos<QuestionItemShort>(firstResult + items.size(), firstResult + results.size(), items); + List<QuestionItemView> items = collectionDao.getItemsOfCollection(collection, results, firstResult, maxResults, orderBy); + return new DefaultResultInfos<QuestionItemView>(firstResult + items.size(), firstResult + results.size(), items); } catch (Exception e) { log.error("", e); } - return new DefaultResultInfos<QuestionItemShort>(); + return new DefaultResultInfos<QuestionItemView>(); } else { - List<QuestionItemShort> items = collectionDao.getItemsOfCollection(collection, null, firstResult, maxResults, orderBy); - return new DefaultResultInfos<QuestionItemShort>(firstResult + items.size(), -1, items); + List<QuestionItemView> items = collectionDao.getItemsOfCollection(collection, null, firstResult, maxResults, orderBy); + return new DefaultResultInfos<QuestionItemView>(firstResult + items.size(), -1, items); } } @Override - public void createPool(Identity identity, String name) { - poolDao.createPool(identity, name); + public void createPool(Identity identity, String name, boolean publicPool) { + poolDao.createPool(identity, name, publicPool); } @Override @@ -532,12 +541,53 @@ public class QuestionPoolServiceImpl implements QPoolService { return new DefaultResultInfos<Pool>(firstResult + pools.size(), -1, pools); } + @Override + public QItemType createItemType(String type, boolean deletable) { + return qpoolItemTypeDao.create(type, deletable); + } + + @Override + public List<QItemType> getAllItemTypes() { + return qpoolItemTypeDao.getItemTypes(); + } + + @Override + public QItemType getItemType(String type) { + return qpoolItemTypeDao.loadByType(type); + } + + @Override + public QEducationalContext createEducationalContext(String level) { + return qEduContextDao.create(level, true); + } + + @Override + public List<QEducationalContext> getAllEducationlContexts() { + return qEduContextDao.getEducationalContexts(); + } + + @Override + public QEducationalContext getEducationlContextByLevel(String level) { + return qEduContextDao.loadByLevel(level); + } + + @Override + public QLicense createLicense(String licenseKey) { + return qpoolLicenseDao.create(licenseKey, true); + } + + @Override + public List<QLicense> getAllLicenses() { + return qpoolLicenseDao.getLicenses(); + } + + @Override + public QLicense getLicense(String licenseKey) { + return qpoolLicenseDao.loadByLicenseKey(licenseKey); + } + @Override public List<TaxonomyLevel> getStudyFields() { return taxonomyLevelDao.loadAllLevels(); } - - - - -} +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/qpool/model/AuthorItemView.java b/src/main/java/org/olat/modules/qpool/model/AuthorItemView.java new file mode 100644 index 00000000000..1a7624c748f --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/model/AuthorItemView.java @@ -0,0 +1,346 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.model; + +import java.math.BigDecimal; +import java.util.Date; + +import javax.persistence.Cacheable; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; + +import org.hibernate.annotations.GenericGenerator; +import org.olat.core.id.CreateInfo; +import org.olat.core.id.ModifiedInfo; +import org.olat.core.id.Persistable; +import org.olat.core.util.StringHelper; +import org.olat.modules.qpool.QuestionItemView; +import org.olat.modules.qpool.QuestionStatus; + +/** + * + * Initial date: 21.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Cacheable(false) +@Entity(name="qauthoritem") +@Table(name="o_qp_item_author_v") +public class AuthorItemView implements QuestionItemView, CreateInfo, ModifiedInfo, Persistable { + + private static final long serialVersionUID = 503607331953283037L; + + @Id + @GeneratedValue(generator = "system-uuid") + @GenericGenerator(name = "system-uuid", strategy = "hilo") + @Column(name="item_id", nullable=false, unique=true, insertable=true, updatable=false) + private Long key; + + @Column(name="item_author", nullable=false, insertable=false, updatable=false) + private Long authorKey; + @Column(name="item_rating", nullable=true, insertable=false, updatable=false) + private Double rating; + + //general + @Column(name="item_identifier", nullable=false, insertable=true, updatable=false) + private String identifier; + @Column(name="item_master_identifier", nullable=false, insertable=true, updatable=false) + private String masterIdentifier; + @Column(name="item_title", nullable=false, insertable=true, updatable=true) + private String title; + @Column(name="item_language", nullable=false, insertable=true, updatable=true) + private String language; + + //classification + @Column(name="item_taxonomy_level", nullable=true, insertable=false, updatable=false) + private String taxonomyLevel; + + //educational + @Column(name="item_edu_context", nullable=false, insertable=true, updatable=true) + private String educationalContextLevel; + @Column(name="item_educational_learningtime", nullable=false, insertable=true, updatable=true) + private String educationalLearningTime; + + //question + @Column(name="item_type", nullable=false, insertable=true, updatable=true) + private String itemType; + @Column(name="item_difficulty", nullable=true, insertable=true, updatable=true) + private BigDecimal difficulty; + @Column(name="item_stdev_difficulty", nullable=true, insertable=true, updatable=true) + private BigDecimal stdevDifficulty; + @Column(name="item_differentiation", nullable=true, insertable=true, updatable=true) + private BigDecimal differentiation; + @Column(name="item_num_of_answers_alt", nullable=false, insertable=true, updatable=true) + private int numOfAnswerAlternatives; + @Column(name="item_usage", nullable=false, insertable=true, updatable=true) + private int usage; + + //life cycle + @Column(name="item_status", nullable=false, insertable=true, updatable=true) + private String status; + + //technics + @Column(name="item_format", nullable=false, insertable=true, updatable=true) + private String format; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="item_creationdate", nullable=false, insertable=true, updatable=false) + private Date creationDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="item_lastmodified", nullable=false, insertable=true, updatable=true) + private Date lastModified; + + @Override + public Long getKey() { + return key; + } + + public void setKey(Long key) { + this.key = key; + } + + @Override + public boolean isEditable() { + return true; + } + + public Long getAuthorKey() { + return authorKey; + } + + public void setAuthorKey(Long authorKey) { + this.authorKey = authorKey; + } + + @Override + public Double getRating() { + return rating; + } + + public void setRating(Double rating) { + this.rating = rating; + } + + + public String getResourceableTypeName() { + return "QuestionItem"; + } + + public Long getResourceableId() { + return getKey(); + } + + @Override + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + @Override + public String getMasterIdentifier() { + return masterIdentifier; + } + + public void setMasterIdentifier(String masterIdentifier) { + this.masterIdentifier = masterIdentifier; + } + + @Override + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + @Override + public String getEducationalContextLevel() { + return educationalContextLevel; + } + + public void setEducationalContextLevel(String educationalContextLevel) { + this.educationalContextLevel = educationalContextLevel; + } + + @Override + public String getTaxonomyLevelName() { + return taxonomyLevel; + } + + public String getTaxonomyLevel() { + return taxonomyLevel; + } + + public void setTaxonomyLevel(String taxonomyLevel) { + this.taxonomyLevel = taxonomyLevel; + } + + @Override + public String getEducationalLearningTime() { + return educationalLearningTime; + } + + public void setEducationalLearningTime(String educationalLearningTime) { + this.educationalLearningTime = educationalLearningTime; + } + + @Override + public BigDecimal getDifficulty() { + return difficulty; + } + + public void setDifficulty(BigDecimal difficulty) { + this.difficulty = difficulty; + } + + @Override + public BigDecimal getStdevDifficulty() { + return stdevDifficulty; + } + + public void setStdevDifficulty(BigDecimal stdevDifficulty) { + this.stdevDifficulty = stdevDifficulty; + } + + @Override + public BigDecimal getDifferentiation() { + return differentiation; + } + + public void setDifferentiation(BigDecimal differentiation) { + this.differentiation = differentiation; + } + + @Override + public int getNumOfAnswerAlternatives() { + return numOfAnswerAlternatives; + } + + public void setNumOfAnswerAlternatives(int numOfAnswerAlternatives) { + this.numOfAnswerAlternatives = numOfAnswerAlternatives; + } + + @Override + public int getUsage() { + return usage; + } + + public void setUsage(int usage) { + this.usage = usage; + } + + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + @Override + public Date getLastModified() { + return lastModified; + } + + @Override + public void setLastModified(Date date) { + lastModified = date; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public String getItemType() { + return itemType; + } + + public void setItemType(String itemType) { + this.itemType = itemType; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + @Transient + public QuestionStatus getQuestionStatus() { + if(StringHelper.containsNonWhitespace(status)) { + return QuestionStatus.valueOf(status); + } + return null; + } + + @Override + public int hashCode() { + return key == null ? 97489 : key.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof AuthorItemView) { + AuthorItemView q = (AuthorItemView)obj; + return key != null && key.equals(q.key); + } + return false; + } + + @Override + public boolean equalsByPersistableKey(Persistable persistable) { + return equals(persistable); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("poolItemView[key=").append(this.key) + .append("]").append(super.toString()); + return sb.toString(); + } +} diff --git a/src/main/java/org/olat/modules/qpool/model/ItemView.java b/src/main/java/org/olat/modules/qpool/model/ItemView.java new file mode 100644 index 00000000000..103818c2447 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/model/ItemView.java @@ -0,0 +1,337 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.model; + +import java.math.BigDecimal; +import java.util.Date; + +import javax.persistence.Cacheable; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; + +import org.hibernate.annotations.GenericGenerator; +import org.olat.core.id.CreateInfo; +import org.olat.core.id.ModifiedInfo; +import org.olat.core.id.Persistable; +import org.olat.core.util.StringHelper; +import org.olat.modules.qpool.QuestionItemView; +import org.olat.modules.qpool.QuestionStatus; + +/** + * + * Initial date: 21.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Cacheable(false) +@Entity(name="qitemview") +@Table(name="o_qp_item_v") +public class ItemView implements QuestionItemView, CreateInfo, ModifiedInfo, Persistable { + + private static final long serialVersionUID = 503607331953283037L; + + @Id + @GeneratedValue(generator = "system-uuid") + @GenericGenerator(name = "system-uuid", strategy = "hilo") + @Column(name="item_id", nullable=false, unique=true, insertable=true, updatable=false) + private Long key; + + @Column(name="item_rating", nullable=true, insertable=false, updatable=false) + private Double rating; + + //general + @Column(name="item_identifier", nullable=false, insertable=true, updatable=false) + private String identifier; + @Column(name="item_master_identifier", nullable=false, insertable=true, updatable=false) + private String masterIdentifier; + @Column(name="item_title", nullable=false, insertable=true, updatable=true) + private String title; + @Column(name="item_language", nullable=false, insertable=true, updatable=true) + private String language; + + //classification + @Column(name="item_taxonomy_level", nullable=true, insertable=false, updatable=false) + private String taxonomyLevel; + + //educational + @Column(name="item_edu_context", nullable=false, insertable=true, updatable=true) + private String educationalContextLevel; + @Column(name="item_educational_learningtime", nullable=false, insertable=true, updatable=true) + private String educationalLearningTime; + + //question + @Column(name="item_type", nullable=false, insertable=true, updatable=true) + private String itemType; + @Column(name="item_difficulty", nullable=true, insertable=true, updatable=true) + private BigDecimal difficulty; + @Column(name="item_stdev_difficulty", nullable=true, insertable=true, updatable=true) + private BigDecimal stdevDifficulty; + @Column(name="item_differentiation", nullable=true, insertable=true, updatable=true) + private BigDecimal differentiation; + @Column(name="item_num_of_answers_alt", nullable=false, insertable=true, updatable=true) + private int numOfAnswerAlternatives; + @Column(name="item_usage", nullable=false, insertable=true, updatable=true) + private int usage; + + //life cycle + @Column(name="item_status", nullable=false, insertable=true, updatable=true) + private String status; + + //technics + @Column(name="item_format", nullable=false, insertable=true, updatable=true) + private String format; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="item_creationdate", nullable=false, insertable=true, updatable=false) + private Date creationDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="item_lastmodified", nullable=false, insertable=true, updatable=true) + private Date lastModified; + + @Override + public Long getKey() { + return key; + } + + public void setKey(Long key) { + this.key = key; + } + + @Override + public boolean isEditable() { + return false; + } + + @Override + public Double getRating() { + return rating; + } + + public void setRating(Double rating) { + this.rating = rating; + } + + + public String getResourceableTypeName() { + return "QuestionItem"; + } + + public Long getResourceableId() { + return getKey(); + } + + @Override + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + @Override + public String getMasterIdentifier() { + return masterIdentifier; + } + + public void setMasterIdentifier(String masterIdentifier) { + this.masterIdentifier = masterIdentifier; + } + + @Override + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + @Override + public String getEducationalContextLevel() { + return educationalContextLevel; + } + + public void setEducationalContextLevel(String educationalContextLevel) { + this.educationalContextLevel = educationalContextLevel; + } + + @Override + public String getTaxonomyLevelName() { + return taxonomyLevel; + } + + public String getTaxonomyLevel() { + return taxonomyLevel; + } + + public void setTaxonomyLevel(String taxonomyLevel) { + this.taxonomyLevel = taxonomyLevel; + } + + + @Override + public String getEducationalLearningTime() { + return educationalLearningTime; + } + + public void setEducationalLearningTime(String educationalLearningTime) { + this.educationalLearningTime = educationalLearningTime; + } + + @Override + public BigDecimal getDifficulty() { + return difficulty; + } + + public void setDifficulty(BigDecimal difficulty) { + this.difficulty = difficulty; + } + + @Override + public BigDecimal getStdevDifficulty() { + return stdevDifficulty; + } + + public void setStdevDifficulty(BigDecimal stdevDifficulty) { + this.stdevDifficulty = stdevDifficulty; + } + + @Override + public BigDecimal getDifferentiation() { + return differentiation; + } + + public void setDifferentiation(BigDecimal differentiation) { + this.differentiation = differentiation; + } + + @Override + public int getNumOfAnswerAlternatives() { + return numOfAnswerAlternatives; + } + + public void setNumOfAnswerAlternatives(int numOfAnswerAlternatives) { + this.numOfAnswerAlternatives = numOfAnswerAlternatives; + } + + @Override + public int getUsage() { + return usage; + } + + public void setUsage(int usage) { + this.usage = usage; + } + + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + @Override + public Date getLastModified() { + return lastModified; + } + + @Override + public void setLastModified(Date date) { + lastModified = date; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public String getItemType() { + return itemType; + } + + public void setItemType(String itemType) { + this.itemType = itemType; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + @Transient + public QuestionStatus getQuestionStatus() { + if(StringHelper.containsNonWhitespace(status)) { + return QuestionStatus.valueOf(status); + } + return null; + } + + @Override + public int hashCode() { + return key == null ? 97489 : key.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof ItemView) { + ItemView q = (ItemView)obj; + return key != null && key.equals(q.key); + } + return false; + } + + @Override + public boolean equalsByPersistableKey(Persistable persistable) { + return equals(persistable); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("poolItemView[key=").append(this.key) + .append("]").append(super.toString()); + return sb.toString(); + } +} diff --git a/src/main/java/org/olat/modules/qpool/model/LOMDuration.java b/src/main/java/org/olat/modules/qpool/model/LOMDuration.java new file mode 100644 index 00000000000..947a754dbbd --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/model/LOMDuration.java @@ -0,0 +1,87 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.model; + +/** + * + * Initial date: 21.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LOMDuration { + private int year = 0; + private int month = 0; + private int day = 0; + private int hour = 0; + private int minute = 0; + private int seconds = 0; + + public LOMDuration() { + // + } + + public int getYear() { + return year; + } + + public void setYear(int year) { + this.year = year; + } + + public int getMonth() { + return month; + } + + public void setMonth(int month) { + this.month = month; + } + + public int getDay() { + return day; + } + + public void setDay(int day) { + this.day = day; + } + + public int getHour() { + return hour; + } + + public void setHour(int hour) { + this.hour = hour; + } + + public int getMinute() { + return minute; + } + + public void setMinute(int minute) { + this.minute = minute; + } + + public int getSeconds() { + return seconds; + } + + public void setSeconds(int seconds) { + this.seconds = seconds; + } +} diff --git a/src/main/java/org/olat/modules/qpool/model/PoolItemView.java b/src/main/java/org/olat/modules/qpool/model/PoolItemView.java new file mode 100644 index 00000000000..2ce7281e4eb --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/model/PoolItemView.java @@ -0,0 +1,351 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.model; + +import java.math.BigDecimal; +import java.util.Date; + +import javax.persistence.Cacheable; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; + +import org.hibernate.annotations.GenericGenerator; +import org.olat.core.id.CreateInfo; +import org.olat.core.id.ModifiedInfo; +import org.olat.core.id.Persistable; +import org.olat.core.util.StringHelper; +import org.olat.modules.qpool.QuestionItemView; +import org.olat.modules.qpool.QuestionStatus; + +/** + * + * Initial date: 21.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Cacheable(false) +@Entity(name="qpoolitem") +@Table(name="o_qp_item_pool_v") +public class PoolItemView implements QuestionItemView, CreateInfo, ModifiedInfo, Persistable { + + private static final long serialVersionUID = 503607331953283037L; + + @Id + @GeneratedValue(generator = "system-uuid") + @GenericGenerator(name = "system-uuid", strategy = "hilo") + @Column(name="item_id", nullable=false, unique=true, insertable=true, updatable=false) + private Long key; + + @Column(name="item_editable", nullable=false, insertable=false, updatable=false) + private boolean editable; + @Column(name="item_rating", nullable=true, insertable=false, updatable=false) + private Double rating; + @Column(name="item_pool", nullable=false, insertable=false, updatable=false) + private Long poolKey; + + //general + @Column(name="item_identifier", nullable=false, insertable=true, updatable=false) + private String identifier; + @Column(name="item_master_identifier", nullable=false, insertable=true, updatable=false) + private String masterIdentifier; + @Column(name="item_title", nullable=false, insertable=true, updatable=true) + private String title; + @Column(name="item_language", nullable=false, insertable=true, updatable=true) + private String language; + + //classification + @Column(name="item_taxonomy_level", nullable=true, insertable=false, updatable=false) + private String taxonomyLevel; + + //educational + @Column(name="item_edu_context", nullable=false, insertable=true, updatable=true) + private String educationalContextLevel; + @Column(name="item_educational_learningtime", nullable=false, insertable=true, updatable=true) + private String educationalLearningTime; + + //question + @Column(name="item_type", nullable=false, insertable=true, updatable=true) + private String itemType; + @Column(name="item_difficulty", nullable=true, insertable=true, updatable=true) + private BigDecimal difficulty; + @Column(name="item_stdev_difficulty", nullable=true, insertable=true, updatable=true) + private BigDecimal stdevDifficulty; + @Column(name="item_differentiation", nullable=true, insertable=true, updatable=true) + private BigDecimal differentiation; + @Column(name="item_num_of_answers_alt", nullable=false, insertable=true, updatable=true) + private int numOfAnswerAlternatives; + @Column(name="item_usage", nullable=false, insertable=true, updatable=true) + private int usage; + + //life cycle + @Column(name="item_status", nullable=false, insertable=true, updatable=true) + private String status; + + //technics + @Column(name="item_format", nullable=false, insertable=true, updatable=true) + private String format; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="item_creationdate", nullable=false, insertable=true, updatable=false) + private Date creationDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="item_lastmodified", nullable=false, insertable=true, updatable=true) + private Date lastModified; + + @Override + public Long getKey() { + return key; + } + + public void setKey(Long key) { + this.key = key; + } + + @Override + public boolean isEditable() { + return editable; + } + + public void setEditable(boolean editable) { + this.editable = editable; + } + + @Override + public Double getRating() { + return rating; + } + + public void setRating(Double rating) { + this.rating = rating; + } + + public Long getPoolKey() { + return poolKey; + } + + public void setPoolKey(Long poolKey) { + this.poolKey = poolKey; + } + + public String getResourceableTypeName() { + return "QuestionItem"; + } + + public Long getResourceableId() { + return getKey(); + } + + @Override + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + @Override + public String getMasterIdentifier() { + return masterIdentifier; + } + + public void setMasterIdentifier(String masterIdentifier) { + this.masterIdentifier = masterIdentifier; + } + + @Override + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + @Override + public String getEducationalContextLevel() { + return educationalContextLevel; + } + + public void setEducationalContextLevel(String educationalContextLevel) { + this.educationalContextLevel = educationalContextLevel; + } + + @Override + public String getTaxonomyLevelName() { + return taxonomyLevel; + } + + public String getTaxonomyLevel() { + return taxonomyLevel; + } + + public void setTaxonomyLevel(String taxonomyLevel) { + this.taxonomyLevel = taxonomyLevel; + } + + @Override + public String getEducationalLearningTime() { + return educationalLearningTime; + } + + public void setEducationalLearningTime(String educationalLearningTime) { + this.educationalLearningTime = educationalLearningTime; + } + + @Override + public BigDecimal getDifficulty() { + return difficulty; + } + + public void setDifficulty(BigDecimal difficulty) { + this.difficulty = difficulty; + } + + @Override + public BigDecimal getStdevDifficulty() { + return stdevDifficulty; + } + + public void setStdevDifficulty(BigDecimal stdevDifficulty) { + this.stdevDifficulty = stdevDifficulty; + } + + @Override + public BigDecimal getDifferentiation() { + return differentiation; + } + + public void setDifferentiation(BigDecimal differentiation) { + this.differentiation = differentiation; + } + + @Override + public int getNumOfAnswerAlternatives() { + return numOfAnswerAlternatives; + } + + public void setNumOfAnswerAlternatives(int numOfAnswerAlternatives) { + this.numOfAnswerAlternatives = numOfAnswerAlternatives; + } + + @Override + public int getUsage() { + return usage; + } + + public void setUsage(int usage) { + this.usage = usage; + } + + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + @Override + public Date getLastModified() { + return lastModified; + } + + @Override + public void setLastModified(Date date) { + lastModified = date; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public String getItemType() { + return itemType; + } + + public void setItemType(String itemType) { + this.itemType = itemType; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + @Transient + public QuestionStatus getQuestionStatus() { + if(StringHelper.containsNonWhitespace(status)) { + return QuestionStatus.valueOf(status); + } + return null; + } + + @Override + public int hashCode() { + return key == null ? 97489 : key.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof PoolItemView) { + PoolItemView q = (PoolItemView)obj; + return key != null && key.equals(q.key); + } + return false; + } + + @Override + public boolean equalsByPersistableKey(Persistable persistable) { + return equals(persistable); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("poolItemView[key=").append(this.key) + .append("]").append(super.toString()); + return sb.toString(); + } +} diff --git a/src/main/java/org/olat/modules/qpool/model/QEducationalContext.java b/src/main/java/org/olat/modules/qpool/model/QEducationalContext.java new file mode 100644 index 00000000000..47ccb8df4bc --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/model/QEducationalContext.java @@ -0,0 +1,126 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.model; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import org.hibernate.annotations.GenericGenerator; +import org.olat.core.id.CreateInfo; +import org.olat.core.id.Persistable; + +/** + * + * Initial date: 15.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Entity(name="qeducontext") +@Table(name="o_qp_edu_context") +@NamedQueries({ + @NamedQuery(name="loadQEduContexts", query="select educontext from qeducontext educontext"), + @NamedQuery(name="loadQEduContextById", query="select educontext from qeducontext educontext where educontext.key=:contextKey"), + @NamedQuery(name="loadQEduContextByLevel", query="select educontext from qeducontext educontext where educontext.level=:level") +}) +public class QEducationalContext implements CreateInfo, Persistable { + + private static final long serialVersionUID = 7688819263188243303L; + + @Id + @GeneratedValue(generator = "system-uuid") + @GenericGenerator(name = "system-uuid", strategy = "hilo") + @Column(name="id", nullable=false, unique=true, insertable=true, updatable=false) + private Long key; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="creationdate", nullable=false, insertable=true, updatable=false) + private Date creationDate; + + @Column(name="q_level", nullable=false, insertable=true, updatable=false) + private String level; + + @Column(name="q_deletable", nullable=false, insertable=true, updatable=false) + private boolean deletable; + + @Override + public Long getKey() { + return key; + } + + public void setKey(Long key) { + this.key = key; + } + + @Override + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + public String getLevel() { + return level; + } + + public void setLevel(String level) { + this.level = level; + } + + public boolean isDeletable() { + return deletable; + } + + public void setDeletable(boolean deletable) { + this.deletable = deletable; + } + + @Override + public int hashCode() { + return key == null ? 184325456 : key.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof QEducationalContext) { + QEducationalContext q = (QEducationalContext)obj; + return key != null && key.equals(q.key); + } + return false; + } + + @Override + public boolean equalsByPersistableKey(Persistable persistable) { + return equals(persistable); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/qpool/model/QItemType.java b/src/main/java/org/olat/modules/qpool/model/QItemType.java new file mode 100644 index 00000000000..bd2e91f0ac1 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/model/QItemType.java @@ -0,0 +1,126 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.model; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import org.hibernate.annotations.GenericGenerator; +import org.olat.core.id.CreateInfo; +import org.olat.core.id.Persistable; + +/** + * + * Initial date: 15.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Entity(name="qitemtype") +@Table(name="o_qp_item_type") +@NamedQueries({ + @NamedQuery(name="loadQItemTypes", query="select itemtype from qitemtype itemtype"), + @NamedQuery(name="loadQItemTypeById", query="select itemtype from qitemtype itemtype where itemtype.key=:itemTypeKey"), + @NamedQuery(name="loadQItemTypeByType", query="select itemtype from qitemtype itemtype where itemtype.type=:itemType") +}) +public class QItemType implements CreateInfo, Persistable { + + private static final long serialVersionUID = -3853789181651253873L; + + @Id + @GeneratedValue(generator = "system-uuid") + @GenericGenerator(name = "system-uuid", strategy = "hilo") + @Column(name="id", nullable=false, unique=true, insertable=true, updatable=false) + private Long key; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="creationdate", nullable=false, insertable=true, updatable=false) + private Date creationDate; + + @Column(name="q_type", nullable=false, insertable=true, updatable=false) + private String type; + + @Column(name="q_deletable", nullable=false, insertable=true, updatable=false) + private boolean deletable; + + @Override + public Long getKey() { + return key; + } + + public void setKey(Long key) { + this.key = key; + } + + @Override + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public boolean isDeletable() { + return deletable; + } + + public void setDeletable(boolean deletable) { + this.deletable = deletable; + } + + @Override + public int hashCode() { + return key == null ? 184325456 : key.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof QItemType) { + QItemType q = (QItemType)obj; + return key != null && key.equals(q.key); + } + return false; + } + + @Override + public boolean equalsByPersistableKey(Persistable persistable) { + return equals(persistable); + } +} diff --git a/src/main/java/org/olat/modules/qpool/model/QLicense.java b/src/main/java/org/olat/modules/qpool/model/QLicense.java new file mode 100644 index 00000000000..fd906227598 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/model/QLicense.java @@ -0,0 +1,138 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.model; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import org.hibernate.annotations.GenericGenerator; +import org.olat.core.id.CreateInfo; +import org.olat.core.id.Persistable; + +/** + * + * Initial date: 15.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Entity(name="qlicense") +@Table(name="o_qp_license") +@NamedQueries({ + @NamedQuery(name="loadQLicenses", query="select license from qlicense license"), + @NamedQuery(name="loadQLicenseById", query="select license from qlicense license where license.key=:licenseKey"), + @NamedQuery(name="loadQLicenseByLicenseKey", query="select license from qlicense license where license.licenseKey=:licenseKey") +}) +public class QLicense implements CreateInfo, Persistable { + + private static final long serialVersionUID = -5165837831689041061L; + + @Id + @GeneratedValue(generator = "system-uuid") + @GenericGenerator(name = "system-uuid", strategy = "hilo") + @Column(name="id", nullable=false, unique=true, insertable=true, updatable=false) + private Long key; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="creationdate", nullable=false, insertable=true, updatable=false) + private Date creationDate; + + @Column(name="q_license", nullable=false, insertable=true, updatable=true) + private String licenseKey; + + @Column(name="q_text", nullable=false, insertable=true, updatable=true) + private String licenseText; + + @Column(name="q_deletable", nullable=false, insertable=true, updatable=false) + private boolean deletable; + + @Override + public Long getKey() { + return key; + } + + public void setKey(Long key) { + this.key = key; + } + + @Override + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + public String getLicenseKey() { + return licenseKey; + } + + public void setLicenseKey(String licenseKey) { + this.licenseKey = licenseKey; + } + + public String getLicenseText() { + return licenseText; + } + + public void setLicenseText(String licenseText) { + this.licenseText = licenseText; + } + + public boolean isDeletable() { + return deletable; + } + + public void setDeletable(boolean deletable) { + this.deletable = deletable; + } + + @Override + public int hashCode() { + return key == null ? 184325456 : key.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof QLicense) { + QLicense q = (QLicense)obj; + return key != null && key.equals(q.key); + } + return false; + } + + @Override + public boolean equalsByPersistableKey(Persistable persistable) { + return equals(persistable); + } + +} diff --git a/src/main/java/org/olat/modules/qpool/model/QuestionItemImpl.java b/src/main/java/org/olat/modules/qpool/model/QuestionItemImpl.java index 07baaa1546f..0c5056e8dbb 100644 --- a/src/main/java/org/olat/modules/qpool/model/QuestionItemImpl.java +++ b/src/main/java/org/olat/modules/qpool/model/QuestionItemImpl.java @@ -45,7 +45,6 @@ import org.olat.core.id.Persistable; import org.olat.core.util.StringHelper; import org.olat.modules.qpool.QuestionItemFull; import org.olat.modules.qpool.QuestionStatus; -import org.olat.modules.qpool.QuestionType; import org.olat.modules.qpool.TaxonomyLevel; /** @@ -92,14 +91,16 @@ public class QuestionItemImpl implements QuestionItemFull, CreateInfo, ModifiedI private TaxonomyLevel taxonomyLevel; //educational - @Column(name="q_educational_context", nullable=true, insertable=true, updatable=true) - private String educationalContext; + @ManyToOne(targetEntity=QEducationalContext.class,fetch=FetchType.LAZY,optional=true) + @JoinColumn(name="fk_edu_context", nullable=false, insertable=true, updatable=true) + private QEducationalContext educationalContext; @Column(name="q_educational_learningtime", nullable=false, insertable=true, updatable=true) private String educationalLearningTime; //question - @Column(name="q_type", nullable=false, insertable=true, updatable=true) - private String type; + @ManyToOne(targetEntity=QItemType.class,fetch=FetchType.LAZY,optional=true) + @JoinColumn(name="fk_type", nullable=false, insertable=true, updatable=true) + private QItemType type; @Column(name="q_difficulty", nullable=true, insertable=true, updatable=true) private BigDecimal difficulty; @Column(name="q_stdev_difficulty", nullable=true, insertable=true, updatable=true) @@ -118,11 +119,11 @@ public class QuestionItemImpl implements QuestionItemFull, CreateInfo, ModifiedI private String itemVersion; @Column(name="q_status", nullable=false, insertable=true, updatable=true) private String status; - //TODO contribute //rights - @Column(name="q_copyright", nullable=true, insertable=true, updatable=true) - private String copyright; + @ManyToOne(targetEntity=QLicense.class,fetch=FetchType.LAZY,optional=true) + @JoinColumn(name="fk_license", nullable=true, insertable=true, updatable=true) + private QLicense license; //technics @Column(name="q_editor", nullable=true, insertable=true, updatable=true) @@ -247,16 +248,23 @@ public class QuestionItemImpl implements QuestionItemFull, CreateInfo, ModifiedI return null; } - @Override - public String getEducationalContext() { + public QEducationalContext getEducationalContext() { return educationalContext; } - public void setEducationalContext(String educationalContext) { + public void setEducationalContext(QEducationalContext educationalContext) { this.educationalContext = educationalContext; } + @Override + public String getEducationalContextLevel() { + if(educationalContext != null) { + return educationalContext.getLevel(); + } + return null; + } + @Override public String getEducationalLearningTime() { return educationalLearningTime; @@ -361,23 +369,22 @@ public class QuestionItemImpl implements QuestionItemFull, CreateInfo, ModifiedI this.language = language; } - - - public String getType() { + public QItemType getType() { return type; } - - public void setType(String type) { - this.type = type; - } - public QuestionType getQuestionType() { - if(StringHelper.containsNonWhitespace(type)) { - return QuestionType.valueOf(type); + @Override + public String getItemType() { + if(type != null) { + return type.getType(); } return null; } + public void setType(QItemType type) { + this.type = type; + } + public String getStatus() { return status; } @@ -405,13 +412,12 @@ public class QuestionItemImpl implements QuestionItemFull, CreateInfo, ModifiedI return null; } - - public String getCopyright() { - return copyright; + public QLicense getLicense() { + return license; } - public void setCopyright(String copyright) { - this.copyright = copyright; + public void setLicense(QLicense license) { + this.license = license; } public SecurityGroup getOwnerGroup() { diff --git a/src/main/java/org/olat/modules/qpool/model/SharedItemView.java b/src/main/java/org/olat/modules/qpool/model/SharedItemView.java new file mode 100644 index 00000000000..8d80e4a3e53 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/model/SharedItemView.java @@ -0,0 +1,351 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.model; + +import java.math.BigDecimal; +import java.util.Date; + +import javax.persistence.Cacheable; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; + +import org.hibernate.annotations.GenericGenerator; +import org.olat.core.id.CreateInfo; +import org.olat.core.id.ModifiedInfo; +import org.olat.core.id.Persistable; +import org.olat.core.util.StringHelper; +import org.olat.modules.qpool.QuestionItemView; +import org.olat.modules.qpool.QuestionStatus; + +/** + * + * Initial date: 21.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Cacheable(false) +@Entity(name="qshareditemview") +@Table(name="o_qp_item_shared_v") +public class SharedItemView implements QuestionItemView, CreateInfo, ModifiedInfo, Persistable { + + private static final long serialVersionUID = 503607331953283037L; + + @Id + @GeneratedValue(generator = "system-uuid") + @GenericGenerator(name = "system-uuid", strategy = "hilo") + @Column(name="item_id", nullable=false, unique=true, insertable=true, updatable=false) + private Long key; + + @Column(name="item_editable", nullable=false, insertable=false, updatable=false) + private boolean editable; + @Column(name="item_rating", nullable=true, insertable=false, updatable=false) + private Double rating; + @Column(name="item_resource_id", nullable=false, insertable=false, updatable=false) + private Long resourceKey; + + //general + @Column(name="item_identifier", nullable=false, insertable=true, updatable=false) + private String identifier; + @Column(name="item_master_identifier", nullable=false, insertable=true, updatable=false) + private String masterIdentifier; + @Column(name="item_title", nullable=false, insertable=true, updatable=true) + private String title; + @Column(name="item_language", nullable=false, insertable=true, updatable=true) + private String language; + + //classification + @Column(name="item_taxonomy_level", nullable=true, insertable=false, updatable=false) + private String taxonomyLevel; + + //educational + @Column(name="item_edu_context", nullable=false, insertable=true, updatable=true) + private String educationalContextLevel; + @Column(name="item_educational_learningtime", nullable=false, insertable=true, updatable=true) + private String educationalLearningTime; + + //question + @Column(name="item_type", nullable=false, insertable=true, updatable=true) + private String itemType; + @Column(name="item_difficulty", nullable=true, insertable=true, updatable=true) + private BigDecimal difficulty; + @Column(name="item_stdev_difficulty", nullable=true, insertable=true, updatable=true) + private BigDecimal stdevDifficulty; + @Column(name="item_differentiation", nullable=true, insertable=true, updatable=true) + private BigDecimal differentiation; + @Column(name="item_num_of_answers_alt", nullable=false, insertable=true, updatable=true) + private int numOfAnswerAlternatives; + @Column(name="item_usage", nullable=false, insertable=true, updatable=true) + private int usage; + + //life cycle + @Column(name="item_status", nullable=false, insertable=true, updatable=true) + private String status; + + //technics + @Column(name="item_format", nullable=false, insertable=true, updatable=true) + private String format; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="item_creationdate", nullable=false, insertable=true, updatable=false) + private Date creationDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="item_lastmodified", nullable=false, insertable=true, updatable=true) + private Date lastModified; + + @Override + public Long getKey() { + return key; + } + + public void setKey(Long key) { + this.key = key; + } + + @Override + public boolean isEditable() { + return editable; + } + + public void setEditable(boolean editable) { + this.editable = editable; + } + + @Override + public Double getRating() { + return rating; + } + + public void setRating(Double rating) { + this.rating = rating; + } + + public Long getResourceKey() { + return resourceKey; + } + + public void setResourceKey(Long resourceKey) { + this.resourceKey = resourceKey; + } + + public String getResourceableTypeName() { + return "QuestionItem"; + } + + public Long getResourceableId() { + return getKey(); + } + + @Override + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + @Override + public String getMasterIdentifier() { + return masterIdentifier; + } + + public void setMasterIdentifier(String masterIdentifier) { + this.masterIdentifier = masterIdentifier; + } + + @Override + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + @Override + public String getEducationalContextLevel() { + return educationalContextLevel; + } + + public void setEducationalContextLevel(String educationalContextLevel) { + this.educationalContextLevel = educationalContextLevel; + } + + @Override + public String getTaxonomyLevelName() { + return taxonomyLevel; + } + + public String getTaxonomyLevel() { + return taxonomyLevel; + } + + public void setTaxonomyLevel(String taxonomyLevel) { + this.taxonomyLevel = taxonomyLevel; + } + + @Override + public String getEducationalLearningTime() { + return educationalLearningTime; + } + + public void setEducationalLearningTime(String educationalLearningTime) { + this.educationalLearningTime = educationalLearningTime; + } + + @Override + public BigDecimal getDifficulty() { + return difficulty; + } + + public void setDifficulty(BigDecimal difficulty) { + this.difficulty = difficulty; + } + + @Override + public BigDecimal getStdevDifficulty() { + return stdevDifficulty; + } + + public void setStdevDifficulty(BigDecimal stdevDifficulty) { + this.stdevDifficulty = stdevDifficulty; + } + + @Override + public BigDecimal getDifferentiation() { + return differentiation; + } + + public void setDifferentiation(BigDecimal differentiation) { + this.differentiation = differentiation; + } + + @Override + public int getNumOfAnswerAlternatives() { + return numOfAnswerAlternatives; + } + + public void setNumOfAnswerAlternatives(int numOfAnswerAlternatives) { + this.numOfAnswerAlternatives = numOfAnswerAlternatives; + } + + @Override + public int getUsage() { + return usage; + } + + public void setUsage(int usage) { + this.usage = usage; + } + + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + @Override + public Date getLastModified() { + return lastModified; + } + + @Override + public void setLastModified(Date date) { + lastModified = date; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public String getItemType() { + return itemType; + } + + public void setItemType(String itemType) { + this.itemType = itemType; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + @Transient + public QuestionStatus getQuestionStatus() { + if(StringHelper.containsNonWhitespace(status)) { + return QuestionStatus.valueOf(status); + } + return null; + } + + @Override + public int hashCode() { + return key == null ? 97489 : key.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof SharedItemView) { + SharedItemView q = (SharedItemView)obj; + return key != null && key.equals(q.key); + } + return false; + } + + @Override + public boolean equalsByPersistableKey(Persistable persistable) { + return equals(persistable); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("poolItemView[key=").append(this.key) + .append("]").append(super.toString()); + return sb.toString(); + } +} diff --git a/src/main/java/org/olat/modules/qpool/ui/ItemRow.java b/src/main/java/org/olat/modules/qpool/ui/ItemRow.java index b03e43204ff..d54f12851c5 100644 --- a/src/main/java/org/olat/modules/qpool/ui/ItemRow.java +++ b/src/main/java/org/olat/modules/qpool/ui/ItemRow.java @@ -23,22 +23,21 @@ import java.math.BigDecimal; import java.util.Date; import org.olat.core.gui.components.form.flexible.elements.FormLink; -import org.olat.modules.qpool.QuestionItemShort; +import org.olat.modules.qpool.QuestionItemView; import org.olat.modules.qpool.QuestionStatus; -import org.olat.modules.qpool.QuestionType; /** * * Initial date: 23.01.2013<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ -public class ItemRow implements QuestionItemShort { - - private final QuestionItemShort delegate; +public class ItemRow implements QuestionItemView { + + private final QuestionItemView delegate; private FormLink markLink; - public ItemRow(QuestionItemShort item) { + public ItemRow(QuestionItemView item) { this.delegate = item; } @@ -47,6 +46,16 @@ public class ItemRow implements QuestionItemShort { return delegate.getKey(); } + @Override + public boolean isEditable() { + return delegate.isEditable(); + } + + @Override + public Double getRating() { + return delegate.getRating(); + } + @Override public String getResourceableTypeName() { return delegate.getResourceableTypeName(); @@ -82,8 +91,8 @@ public class ItemRow implements QuestionItemShort { } @Override - public String getEducationalContext() { - return delegate.getEducationalContext(); + public String getEducationalContextLevel() { + return delegate.getEducationalContextLevel(); } @Override @@ -92,8 +101,8 @@ public class ItemRow implements QuestionItemShort { } @Override - public String getType() { - return delegate.getType(); + public String getItemType() { + return delegate.getItemType(); } @Override @@ -141,16 +150,6 @@ public class ItemRow implements QuestionItemShort { return delegate.getQuestionStatus(); } - @Override - public QuestionType getQuestionType() { - return delegate.getQuestionType(); - } - - /* - public QuestionItem getItem() { - return delegate; - }*/ - public FormLink getMarkLink() { return markLink; } diff --git a/src/main/java/org/olat/modules/qpool/ui/MetadatasController.java b/src/main/java/org/olat/modules/qpool/ui/MetadatasController.java index 65a5d2f3adf..e4f7e135446 100644 --- a/src/main/java/org/olat/modules/qpool/ui/MetadatasController.java +++ b/src/main/java/org/olat/modules/qpool/ui/MetadatasController.java @@ -65,22 +65,24 @@ public class MetadatasController extends BasicController { private RightsMetadataEditController rightsEditCtrl; private QuestionItem item; + private final boolean canEdit; - public MetadatasController(UserRequest ureq, WindowControl wControl, QuestionItem item) { + public MetadatasController(UserRequest ureq, WindowControl wControl, QuestionItem item, boolean canEdit) { super(ureq, wControl); this.item = item; + this.canEdit = canEdit; - generalCtrl = new GeneralMetadataController(ureq, wControl, item); + generalCtrl = new GeneralMetadataController(ureq, wControl, item, canEdit); listenTo(generalCtrl); - educationalCtrl = new EducationalMetadataController(ureq, wControl, item); + educationalCtrl = new EducationalMetadataController(ureq, wControl, item, canEdit); listenTo(educationalCtrl); - questionCtrl = new QuestionMetadataController(ureq, wControl, item); + questionCtrl = new QuestionMetadataController(ureq, wControl, item, canEdit); listenTo(questionCtrl); - lifecycleCtrl = new LifecycleMetadataController(ureq, wControl, item); + lifecycleCtrl = new LifecycleMetadataController(ureq, wControl, item, canEdit); listenTo(lifecycleCtrl); - technicalCtrl = new TechnicalMetadataController(ureq, wControl, item); + technicalCtrl = new TechnicalMetadataController(ureq, wControl, item, canEdit); listenTo(technicalCtrl); - rightsCtrl = new RightsMetadataController(ureq, wControl, item); + rightsCtrl = new RightsMetadataController(ureq, wControl, item, canEdit); listenTo(rightsCtrl); mainVC = createVelocityContainer("item_metadatas"); @@ -102,7 +104,6 @@ public class MetadatasController extends BasicController { return item; } - @Override protected void event(UserRequest ureq, Component source, Event event) { // @@ -110,8 +111,8 @@ public class MetadatasController extends BasicController { @Override protected void event(UserRequest ureq, Controller source, Event event) { - if(QPoolEvent.EDIT.endsWith(event.getCommand())) { + if(!canEdit) return; if(source == generalCtrl) { doEditGeneralMetadata(ureq); } else if(source == educationalCtrl) { diff --git a/src/main/java/org/olat/modules/qpool/ui/PoolDataModel.java b/src/main/java/org/olat/modules/qpool/ui/PoolDataModel.java deleted file mode 100644 index d4ce4cb084e..00000000000 --- a/src/main/java/org/olat/modules/qpool/ui/PoolDataModel.java +++ /dev/null @@ -1,139 +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.modules.qpool.ui; - -import java.util.ArrayList; -import java.util.List; - -import org.olat.core.commons.persistence.DefaultResultInfos; -import org.olat.core.commons.persistence.ResultInfos; -import org.olat.core.commons.persistence.SortKey; -import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; -import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModel; -import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataSource; -import org.olat.core.gui.components.table.TableDataModel; -import org.olat.core.gui.translator.Translator; -import org.olat.modules.qpool.ui.PoolsAdminController.PoolSource; - -/** - * - * Initial date: 23.01.2013<br> - * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com - * - */ -public class PoolDataModel implements FlexiTableDataModel, FlexiTableDataSource<PoolRow>, TableDataModel<PoolRow> { - - private List<PoolRow> rows; - private PoolSource source; - private FlexiTableColumnModel columnModel; - private final Translator translator; - - public PoolDataModel(FlexiTableColumnModel columnModel, PoolSource source, Translator translator) { - this.columnModel = columnModel; - this.translator = translator; - this.source = source; - } - - @Override - public FlexiTableColumnModel getTableColumnModel() { - return columnModel; - } - - @Override - public void setTableColumnModel(FlexiTableColumnModel tableColumnModel) { - this.columnModel = tableColumnModel; - } - - @Override - public int getRowCount() { - return source.getNumOfItems(); - } - - @Override - public PoolRow getObject(int row) { - return rows.get(row); - } - - @Override - public void setObjects(List<PoolRow> objects) { - rows = new ArrayList<PoolRow>(objects); - } - - @Override - public ResultInfos<PoolRow> load(int firstResult, int maxResults, SortKey... orderBy) { - if(rows == null) { - rows = new ArrayList<PoolRow>(); - } - - for(int i=rows.size(); i<firstResult; i++) { - rows.add(null); - } - ResultInfos<PoolRow> newRows = source.getRows(firstResult, maxResults, orderBy); - for(int i=0; i<newRows.getObjects().size(); i++) { - int rowIndex = i + firstResult; - if(rowIndex < rows.size()) { - rows.set(rowIndex, newRows.getObjects().get(i)); - } else { - rows.add(newRows.getObjects().get(i)); - } - } - return new DefaultResultInfos<PoolRow>(newRows.getNextFirstResult(), newRows.getCorrectedRowCount(), rows); - } - - @Override - public ResultInfos<PoolRow> search(String query, List<String> addQueries, int firstResult, int maxResults, SortKey... orderBy) { - return load(firstResult, maxResults, orderBy); - } - - @Override - public int getColumnCount() { - return columnModel.getColumnCount(); - } - - @Override - public PoolDataModel createCopyWithEmptyList() { - return new PoolDataModel(columnModel, source, translator); - } - - @Override - public Object getValueAt(int row, int col) { - PoolRow item = getObject(row); - switch(Cols.values()[col]) { - case id: return item.getKey(); - case name: return item.getName(); - default: return ""; - } - } - - public enum Cols { - id("pool.key"), - name("pool.name"); - - private final String i18nKey; - - private Cols(String i18nKey) { - this.i18nKey = i18nKey; - } - - public String i18nKey() { - return i18nKey; - } - } -} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/qpool/ui/QItemEvent.java b/src/main/java/org/olat/modules/qpool/ui/QItemEvent.java index cff9f81c49c..f37c2594f77 100644 --- a/src/main/java/org/olat/modules/qpool/ui/QItemEvent.java +++ b/src/main/java/org/olat/modules/qpool/ui/QItemEvent.java @@ -20,7 +20,7 @@ package org.olat.modules.qpool.ui; import org.olat.core.gui.control.Event; -import org.olat.modules.qpool.QuestionItemShort; +import org.olat.modules.qpool.QuestionItemView; /** * @@ -31,14 +31,14 @@ import org.olat.modules.qpool.QuestionItemShort; public class QItemEvent extends Event { private static final long serialVersionUID = 1868410260121125418L; - private final QuestionItemShort item; + private final QuestionItemView item; - public QItemEvent(String cmd, QuestionItemShort item) { + public QItemEvent(String cmd, QuestionItemView item) { super(cmd); this.item = item; } - public QuestionItemShort getItem() { + public QuestionItemView getItem() { return item; } } diff --git a/src/main/java/org/olat/modules/qpool/ui/QuestionItemDataModel.java b/src/main/java/org/olat/modules/qpool/ui/QuestionItemDataModel.java index 186de0fad10..6a5a6f47120 100644 --- a/src/main/java/org/olat/modules/qpool/ui/QuestionItemDataModel.java +++ b/src/main/java/org/olat/modules/qpool/ui/QuestionItemDataModel.java @@ -31,7 +31,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable import org.olat.core.gui.components.table.TableDataModel; import org.olat.core.gui.translator.Translator; import org.olat.modules.qpool.QuestionStatus; -import org.olat.modules.qpool.QuestionType; /** * @@ -162,23 +161,23 @@ public class QuestionItemDataModel implements FlexiTableDataModel, FlexiTableDat case taxnonomyLevel: return item.getTaxonomyLevelName(); case difficulty: return item.getDifficulty(); case type: { - QuestionType type = item.getQuestionType(); + String type = item.getItemType(); if(type == null) { return ""; } - return type.name(); + return type; } + case rating: return item.getRating(); + case format: return item.getFormat(); case status: { QuestionStatus s = item.getQuestionStatus(); if(s == null) { return ""; } return translator.translate("lifecycle.status." + s.name()); - } - case mark: { + } case mark: { return item.getMarkLink(); - } - default: { + } default: { return "-"; } } @@ -193,6 +192,8 @@ public class QuestionItemDataModel implements FlexiTableDataModel, FlexiTableDat difficulty("question.difficulty"), type("question.assessmentType"), + format("technical.format"), + rating("rating"), status("lifecycle.status"), mark("mark"); diff --git a/src/main/java/org/olat/modules/qpool/ui/QuestionItemDetailsController.java b/src/main/java/org/olat/modules/qpool/ui/QuestionItemDetailsController.java index 84dedaacc2e..0358172e1e9 100644 --- a/src/main/java/org/olat/modules/qpool/ui/QuestionItemDetailsController.java +++ b/src/main/java/org/olat/modules/qpool/ui/QuestionItemDetailsController.java @@ -68,7 +68,7 @@ public class QuestionItemDetailsController extends BasicController { private final QuestionPoolModule poolModule; private final QPoolService qpoolService; - public QuestionItemDetailsController(UserRequest ureq, WindowControl wControl, QuestionItem item) { + public QuestionItemDetailsController(UserRequest ureq, WindowControl wControl, QuestionItem item, boolean editable) { super(ureq, wControl); poolModule = CoreSpringFactory.getImpl(QuestionPoolModule.class); @@ -84,8 +84,9 @@ public class QuestionItemDetailsController extends BasicController { } } listenTo(editCtrl); - - metadatasCtrl = new MetadatasController(ureq, wControl, item); + + boolean canEdit = editable || qpoolService.isAuthor(item, getIdentity()); + metadatasCtrl = new MetadatasController(ureq, wControl, item, canEdit); listenTo(metadatasCtrl); Roles roles = ureq.getUserSession().getRoles(); @@ -99,6 +100,7 @@ public class QuestionItemDetailsController extends BasicController { mainVC = createVelocityContainer("item_details"); shareItem = LinkFactory.createButton("share.item", mainVC, this); deleteItem = LinkFactory.createButton("delete.item", mainVC, this); + deleteItem.setVisible(canEdit); exportItem = LinkFactory.createButton("export.item", mainVC, this); mainVC.put("type_specifics", editCtrl.getInitialComponent()); @@ -169,7 +171,7 @@ public class QuestionItemDetailsController extends BasicController { } private void doShareItems(UserRequest ureq, QuestionItemShort item, List<BusinessGroup> groups) { - qpoolService.shareItems(Collections.singletonList(item), groups); + qpoolService.shareItemsWithGroups(Collections.singletonList(item), groups, false); fireEvent(ureq, new QPoolEvent(QPoolEvent.ITEM_SHARED)); } diff --git a/src/main/java/org/olat/modules/qpool/ui/QuestionItemSummaryController.java b/src/main/java/org/olat/modules/qpool/ui/QuestionItemSummaryController.java index 21fb9e86ac9..3777b7bf1d7 100644 --- a/src/main/java/org/olat/modules/qpool/ui/QuestionItemSummaryController.java +++ b/src/main/java/org/olat/modules/qpool/ui/QuestionItemSummaryController.java @@ -19,7 +19,6 @@ */ package org.olat.modules.qpool.ui; -import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.StaticTextElement; @@ -28,7 +27,6 @@ import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.util.StringHelper; import org.olat.modules.qpool.QuestionItem; -import org.olat.modules.qpool.QPoolService; /** * @@ -46,14 +44,11 @@ public class QuestionItemSummaryController extends FormBasicController { private StaticTextElement usageEl; private StaticTextElement descriptionEl; + private boolean canEdit; private QuestionItem item; - private final QPoolService qpoolService; public QuestionItemSummaryController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); - - qpoolService = CoreSpringFactory.getImpl(QPoolService.class); - initForm(ureq); } @@ -75,11 +70,15 @@ public class QuestionItemSummaryController extends FormBasicController { // } + public boolean isCanEdit() { + return canEdit; + } + public QuestionItem getItem() { return item; } - public void updateItem(QuestionItem item) { + public void updateItem(QuestionItem item, boolean canEdit) { this.item = item; keyEl.setValue(item.getKey().toString()); @@ -87,7 +86,7 @@ public class QuestionItemSummaryController extends FormBasicController { subjectEl.setValue(item.getTitle()); String keywords = item.getKeywords(); keywordsEl.setValue(keywords == null ? "" : keywords); - String taxonPath = qpoolService.getTaxonomicPath(item); + String taxonPath = item.getTaxonomicPath(); studyFieldEl.setValue(taxonPath == null ? "" : taxonPath); int usage = item.getUsage(); diff --git a/src/main/java/org/olat/modules/qpool/ui/QuestionItemsSource.java b/src/main/java/org/olat/modules/qpool/ui/QuestionItemsSource.java index 42ea18f393b..7079e2f1690 100644 --- a/src/main/java/org/olat/modules/qpool/ui/QuestionItemsSource.java +++ b/src/main/java/org/olat/modules/qpool/ui/QuestionItemsSource.java @@ -23,7 +23,7 @@ import java.util.List; import org.olat.core.commons.persistence.ResultInfos; import org.olat.core.commons.persistence.SortKey; -import org.olat.modules.qpool.QuestionItemShort; +import org.olat.modules.qpool.QuestionItemView; /** * @@ -35,6 +35,6 @@ public interface QuestionItemsSource { public int getNumOfItems(); - public ResultInfos<QuestionItemShort> getItems(String query, List<String> condQueries, int firstResult, int maxResults, SortKey... orderBy); + public ResultInfos<QuestionItemView> getItems(String query, List<String> condQueries, int firstResult, int maxResults, SortKey... orderBy); } diff --git a/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java b/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java index 9b48cc9edae..3eafefb2bda 100644 --- a/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java +++ b/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java @@ -61,10 +61,14 @@ import org.olat.core.id.OLATResourceable; import org.olat.group.BusinessGroup; import org.olat.group.model.BusinessGroupSelectionEvent; import org.olat.group.ui.main.SelectBusinessGroupController; +import org.olat.ims.qti.QTIConstants; +import org.olat.ims.qti.qpool.QTIQPoolServiceProvider; +import org.olat.modules.qpool.QPoolService; import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QuestionItemShort; -import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionItemView; import org.olat.modules.qpool.ui.QuestionItemDataModel.Cols; +import org.olat.modules.qpool.ui.wizard.Export_1_TypeStep; import org.olat.modules.qpool.ui.wizard.ImportAuthor_1_ChooseMemberStep; /** @@ -74,7 +78,7 @@ import org.olat.modules.qpool.ui.wizard.ImportAuthor_1_ChooseMemberStep; */ public class QuestionListController extends FormBasicController implements StackedControllerAware, ItemRowsSource { - private FormLink createList, shareItem, copyItem, deleteItem, authorItem, importItem; + private FormLink createList, exportItem, shareItem, copyItem, deleteItem, authorItem, importItem; private FlexiTableElement itemsTable; private QuestionItemDataModel model; @@ -83,8 +87,10 @@ public class QuestionListController extends FormBasicController implements Stack private CloseableModalController cmc; private DialogBoxController confirmCopyBox; private DialogBoxController confirmDeleteBox; + private ShareItemOptionController shareItemsCtrl; private SelectBusinessGroupController selectGroupCtrl; private CreateCollectionController createCollectionCtrl; + private StepsMainRunController exportWizard; private StepsMainRunController importAuthorsWizard; private ImportController importItemCtrl; @@ -112,22 +118,25 @@ public class QuestionListController extends FormBasicController implements Stack protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { //add the table FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.mark.i18nKey(), Cols.mark.ordinal())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.key.i18nKey(), Cols.key.ordinal(), true, "key")); //columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.identifier.i18nKey(), Cols.identifier.ordinal(), true, "identifier")); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.title.i18nKey(), Cols.title.ordinal(), true, "title")); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.taxnonomyLevel.i18nKey(), Cols.taxnonomyLevel.ordinal(), true, "taxonomyLevel.field")); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.difficulty.i18nKey(), Cols.difficulty.ordinal(), true, "point")); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.type.i18nKey(), Cols.type.ordinal(), true, "type")); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.format.i18nKey(), Cols.format.ordinal(), true, "format")); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.rating.i18nKey(), Cols.rating.ordinal(), true, "rating")); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.status.i18nKey(), Cols.status.ordinal(), true, "status")); columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("select", translate("select"), "select-item")); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.mark.i18nKey(), Cols.mark.ordinal())); - + model = new QuestionItemDataModel(columnsModel, this, getTranslator()); itemsTable = uifactory.addTableElement(ureq, "items", model, model, 20, true, getTranslator(), formLayout); itemsTable.setMultiSelect(true); itemsTable.setRendererType(FlexiTableRendererType.dataTables); createList = uifactory.addFormLink("create.list", formLayout, Link.BUTTON); + exportItem = uifactory.addFormLink("export.item", formLayout, Link.BUTTON); shareItem = uifactory.addFormLink("share.item", formLayout, Link.BUTTON); copyItem = uifactory.addFormLink("copy", formLayout, Link.BUTTON); importItem = uifactory.addFormLink("import.item", formLayout, Link.BUTTON); @@ -162,7 +171,11 @@ public class QuestionListController extends FormBasicController implements Stack Set<Integer> selections = itemsTable.getMultiSelectedIndex(); List<QuestionItemShort> items = getShortItems(selections); doAskCollectionName(ureq, items); - } else if(link == shareItem) { + } else if(link == exportItem) { + Set<Integer> selections = itemsTable.getMultiSelectedIndex(); + List<QuestionItemShort> items = getShortItems(selections); + doExport(ureq, items); + } else if(link == shareItem) { Set<Integer> selections = itemsTable.getMultiSelectedIndex(); if(selections.size() > 0) { List<QuestionItemShort> items = getShortItems(selections); @@ -194,9 +207,9 @@ public class QuestionListController extends FormBasicController implements Stack } else if("mark".equals(link.getCmd())) { ItemRow row = (ItemRow)link.getUserObject(); if(doMark(ureq, row)) { - link.setI18nKey("Mark_true"); + link.setCustomEnabledLinkCSS("b_mark_set"); } else { - link.setI18nKey("Mark_false"); + link.setCustomEnabledLinkCSS("b_mark_not_set"); } link.getComponent().setDirty(true); } @@ -218,6 +231,7 @@ public class QuestionListController extends FormBasicController implements Stack @Override protected void event(UserRequest ureq, Controller source, Event event) { if(source == selectGroupCtrl) { + cmc.deactivate(); if(event instanceof BusinessGroupSelectionEvent) { BusinessGroupSelectionEvent bge = (BusinessGroupSelectionEvent)event; List<BusinessGroup> groups = bge.getGroups(); @@ -227,6 +241,10 @@ public class QuestionListController extends FormBasicController implements Stack doShareItems(ureq, items, groups); } } + } else if(source == shareItemsCtrl) { + if(event instanceof QPoolEvent) { + fireEvent(ureq, event); + } cmc.deactivate(); cleanUp(); } else if(source == createCollectionCtrl) { @@ -238,6 +256,12 @@ public class QuestionListController extends FormBasicController implements Stack } cmc.deactivate(); cleanUp(); + } else if(source == exportWizard) { + if(event == Event.CANCELLED_EVENT || event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) { + getWindowControl().pop(); + removeAsListenerAndDispose(exportWizard); + exportWizard = null; + } } else if(source == importAuthorsWizard) { if(event == Event.CANCELLED_EVENT || event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) { getWindowControl().pop(); @@ -321,6 +345,43 @@ public class QuestionListController extends FormBasicController implements Stack listenTo(cmc); } + /** + * Test only QTI 1.2 + * @param ureq + * @param items + */ + private void doExport(UserRequest ureq, List<QuestionItemShort> items) { + removeAsListenerAndDispose(exportWizard); + + Step start = new Export_1_TypeStep(ureq, items); + StepRunnerCallback finish = new StepRunnerCallback() { + @Override + public Step execute(UserRequest ureq, WindowControl wControl, StepsRunContext runContext) { + @SuppressWarnings("unchecked") + List<QuestionItemShort> items = (List<QuestionItemShort>)runContext.get("items"); + List<QuestionItemShort> qti12Items = new ArrayList<QuestionItemShort>(); + for(QuestionItemShort item:items) { + if(QTIConstants.QTI_12_FORMAT.equals(item.getFormat())) { + qti12Items.add(item); + } + } + + QTIQPoolServiceProvider qtiProvider = CoreSpringFactory.getImpl(QTIQPoolServiceProvider.class); + qtiProvider.assembleTest(qti12Items); + /* + QPoolExportResource mr = new QPoolExportResource("UTF-8", item); + ureq.getDispatchResult().setResultingMediaResource(mr); + */ + return StepsMainRunController.DONE_MODIFIED; + } + }; + + exportWizard = new StepsMainRunController(ureq, getWindowControl(), start, finish, null, + translate("export.item"), "o_sel_qpool_export_1_wizard"); + listenTo(exportWizard); + getWindowControl().pushAsModalDialog(exportWizard.getInitialComponent()); + } + private void doCreateCollection(UserRequest ureq, String name, List<QuestionItemShort> items) { qpoolService.createCollection(getIdentity(), name, items); fireEvent(ureq, new QPoolEvent(QPoolEvent.COLL_CREATED)); @@ -383,18 +444,26 @@ public class QuestionListController extends FormBasicController implements Stack } protected void doCopy(UserRequest ureq, List<QuestionItemShort> items) { - qpoolService.copyItems(getIdentity(), items); + List<QuestionItem> copies = qpoolService.copyItems(getIdentity(), items); + itemsTable.reset(); + showInfo("item.copied", Integer.toString(copies.size())); fireEvent(ureq, new QPoolEvent(QPoolEvent.EDIT)); } private void doShareItems(UserRequest ureq, List<QuestionItemShort> items, List<BusinessGroup> groups) { - qpoolService.shareItems(items, groups); - fireEvent(ureq, new QPoolEvent(QPoolEvent.ITEM_SHARED)); + removeAsListenerAndDispose(shareItemsCtrl); + shareItemsCtrl = new ShareItemOptionController(ureq, getWindowControl(), items, groups, null); + listenTo(shareItemsCtrl); + + cmc = new CloseableModalController(getWindowControl(), translate("close"), + shareItemsCtrl.getInitialComponent(), true, translate("share.item")); + cmc.activate(); + listenTo(cmc); } protected void doSelect(UserRequest ureq, ItemRow row) { QuestionItem item = qpoolService.loadItemById(row.getKey()); - QuestionItemDetailsController detailsCtrl = new QuestionItemDetailsController(ureq, getWindowControl(), item); + QuestionItemDetailsController detailsCtrl = new QuestionItemDetailsController(ureq, getWindowControl(), item, row.isEditable()); LayoutMain3ColsController mainCtrl = new LayoutMain3ColsController(ureq, getWindowControl(), detailsCtrl); stackPanel.pushController(item.getTitle(), mainCtrl); } @@ -419,20 +488,20 @@ public class QuestionListController extends FormBasicController implements Stack public ResultInfos<ItemRow> getRows(String query, List<String> condQueries, int firstResult, int maxResults, SortKey... orderBy) { Set<Long> marks = markManager.getMarkResourceIds(getIdentity(), "QuestionItem", Collections.<String>emptyList()); - ResultInfos<QuestionItemShort> items = source.getItems(query, condQueries, firstResult, maxResults, orderBy); + ResultInfos<QuestionItemView> items = source.getItems(query, condQueries, firstResult, maxResults, orderBy); List<ItemRow> rows = new ArrayList<ItemRow>(items.getObjects().size()); - for(QuestionItemShort item:items.getObjects()) { + for(QuestionItemView item:items.getObjects()) { ItemRow row = forgeRow(item, marks); rows.add(row); } return new DefaultResultInfos<ItemRow>(items.getNextFirstResult(), items.getCorrectedRowCount(), rows); } - protected ItemRow forgeRow(QuestionItemShort item, Set<Long> markedQuestionKeys) { + protected ItemRow forgeRow(QuestionItemView item, Set<Long> markedQuestionKeys) { boolean marked = markedQuestionKeys.contains(item.getKey()); - ItemRow row = new ItemRow(item); - FormLink markLink = uifactory.addFormLink("mark_" + row.getKey(), "mark", "Mark_" + marked, null, null, Link.NONTRANSLATED); + FormLink markLink = uifactory.addFormLink("mark_" + row.getKey(), "mark", " ", null, null, Link.NONTRANSLATED); + markLink.setCustomEnabledLinkCSS(marked ? "b_mark_set" : "b_mark_not_set"); markLink.setUserObject(row); row.setMarkLink(markLink); return row; diff --git a/src/main/java/org/olat/modules/qpool/ui/QuestionPoolMainEditorController.java b/src/main/java/org/olat/modules/qpool/ui/QuestionPoolMainEditorController.java index f306229c587..dc438828d44 100644 --- a/src/main/java/org/olat/modules/qpool/ui/QuestionPoolMainEditorController.java +++ b/src/main/java/org/olat/modules/qpool/ui/QuestionPoolMainEditorController.java @@ -40,13 +40,18 @@ 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.Roles; import org.olat.core.id.context.ContextEntry; import org.olat.core.id.context.StateEntry; import org.olat.group.BusinessGroup; import org.olat.modules.qpool.Pool; +import org.olat.modules.qpool.QPoolService; import org.olat.modules.qpool.QuestionItemCollection; import org.olat.modules.qpool.QuestionItemShort; -import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.ui.admin.PoolsAdminController; +import org.olat.modules.qpool.ui.admin.QEducationalContextsAdminController; +import org.olat.modules.qpool.ui.admin.QItemTypesAdminController; +import org.olat.modules.qpool.ui.admin.QLicensesAdminController; import org.olat.modules.qpool.ui.datasource.CollectionOfItemsSource; import org.olat.modules.qpool.ui.datasource.MarkedItemsSource; import org.olat.modules.qpool.ui.datasource.MyQuestionItemsSource; @@ -75,16 +80,21 @@ public class QuestionPoolMainEditorController extends BasicController implements private QuestionsController markedQuestionsCtrl; private PoolsAdminController poolAdminCtrl; + private QItemTypesAdminController typesCtrl; + private QEducationalContextsAdminController levelsCtrl; + private QLicensesAdminController licensesCtrl; private TaxonomyAdminController studyFieldCtrl; private LayoutMain3ColsController columnLayoutCtr; private QuestionPoolAdminStatisticsController adminStatisticsCtrl; + private final Roles roles; private final MarkManager markManager; private final QPoolService qpoolService; public QuestionPoolMainEditorController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); + roles = ureq.getUserSession().getRoles(); markManager = CoreSpringFactory.getImpl(MarkManager.class); qpoolService = CoreSpringFactory.getImpl(QPoolService.class); @@ -134,6 +144,12 @@ public class QuestionPoolMainEditorController extends BasicController implements doSelectAdminStudyFields(ureq); } else if("menu.admin.pools".equals(uNode)) { doSelectAdminPools(ureq); + } else if("menu.admin.types".equals(uNode)) { + doSelectAdminTypes(ureq); + } else if("menu.admin.levels".equals(uNode)) { + doSelectAdminLevels(ureq); + } else if("menu.admin.licenses".equals(uNode)) { + doSelectAdminLicenses(ureq); } else if("menu.database.my".equals(uNode)) { doSelectMyQuestions(ureq); } else if("menu.database.favorit".equals(uNode)) { @@ -185,10 +201,10 @@ public class QuestionPoolMainEditorController extends BasicController implements if(node != null) { Object userObj = node.getUserObject(); if(userObj instanceof BusinessGroup) { - qpoolService.shareItems(Collections.singletonList(item), Collections.singletonList((BusinessGroup)userObj)); + qpoolService.shareItemsWithGroups(Collections.singletonList(item), Collections.singletonList((BusinessGroup)userObj), false); showInfo("item.shared", item.getTitle()); } else if(userObj instanceof Pool) { - qpoolService.addItemToPool(item, (Pool)userObj); + qpoolService.shareItemsInPools(Collections.singletonList(item), Collections.singletonList((Pool)userObj), false); showInfo("item.pooled", item.getTitle()); } else if(userObj instanceof QuestionItemCollection) { qpoolService.addItemToCollection(item, (QuestionItemCollection)userObj); @@ -228,6 +244,30 @@ public class QuestionPoolMainEditorController extends BasicController implements content.setContent(poolAdminCtrl.getInitialComponent()); } + private void doSelectAdminTypes(UserRequest ureq) { + if(typesCtrl == null) { + typesCtrl = new QItemTypesAdminController(ureq, getWindowControl()); + listenTo(typesCtrl); + } + content.setContent(typesCtrl.getInitialComponent()); + } + + private void doSelectAdminLevels(UserRequest ureq) { + if(levelsCtrl == null) { + levelsCtrl = new QEducationalContextsAdminController(ureq, getWindowControl()); + listenTo(levelsCtrl); + } + content.setContent(levelsCtrl.getInitialComponent()); + } + + private void doSelectAdminLicenses(UserRequest ureq) { + if(licensesCtrl == null) { + licensesCtrl = new QLicensesAdminController(ureq, getWindowControl()); + listenTo(licensesCtrl); + } + content.setContent(licensesCtrl.getInitialComponent()); + } + private void doSelectMyQuestions(UserRequest ureq) { if(myQuestionsCtrl == null) { myQuestionsCtrl = new QuestionsController(ureq, getWindowControl(), new MyQuestionItemsSource(getIdentity(), ureq.getUserSession().getRoles())); @@ -324,7 +364,7 @@ public class QuestionPoolMainEditorController extends BasicController implements private void buildPoolSubTreeModel(GenericTreeNode poolNode) { poolNode.removeAllChildren(); - List<Pool> pools = qpoolService.getPools(getIdentity()); + List<Pool> pools = qpoolService.getPools(getIdentity(), roles); for(Pool pool:pools) { GenericTreeNode node = new GenericTreeNode(pool.getName(), pool); node.setIconCssClass("o_sel_qpool_pool"); @@ -340,7 +380,19 @@ public class QuestionPoolMainEditorController extends BasicController implements adminNode.addChild(node); node = new GenericTreeNode(translate("menu.admin.pools"), "menu.admin.pools"); - node.setIconCssClass("o_sel_qpool_study_pools"); + node.setIconCssClass("o_sel_qpool_admin_pools"); + adminNode.addChild(node); + + node = new GenericTreeNode(translate("menu.admin.types"), "menu.admin.types"); + node.setIconCssClass("o_sel_qpool_admin_types"); + adminNode.addChild(node); + + node = new GenericTreeNode(translate("menu.admin.levels"), "menu.admin.levels"); + node.setIconCssClass("o_sel_qpool_admin_levels"); + adminNode.addChild(node); + + node = new GenericTreeNode(translate("menu.admin.licenses"), "menu.admin.licenses"); + node.setIconCssClass("o_sel_qpool_admin_licenses"); adminNode.addChild(node); } diff --git a/src/main/java/org/olat/modules/qpool/ui/QuestionsController.java b/src/main/java/org/olat/modules/qpool/ui/QuestionsController.java index 11d11db1e5a..66ec154230e 100644 --- a/src/main/java/org/olat/modules/qpool/ui/QuestionsController.java +++ b/src/main/java/org/olat/modules/qpool/ui/QuestionsController.java @@ -37,9 +37,10 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.modules.qpool.QPoolService; import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QuestionItemShort; -import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionItemView; /** * @@ -109,7 +110,7 @@ public class QuestionsController extends BasicController implements StackedContr @Override protected void event(UserRequest ureq, Component source, Event event) { if(selectItem == source) { - doSelect(ureq, detailsCtrl.getItem()); + doSelect(ureq, detailsCtrl.getItem(), detailsCtrl.isCanEdit()); } else if(deleteItem == source) { doConfirmDelete(ureq, detailsCtrl.getItem()); } @@ -120,7 +121,7 @@ public class QuestionsController extends BasicController implements StackedContr if(source == listCtrl) { if(event instanceof QItemEvent) { QItemEvent se = (QItemEvent)event; - QuestionItemShort item = se.getItem(); + QuestionItemView item = se.getItem(); doUpdateDetails(ureq, item); } else if(event instanceof QPoolEvent) { fireEvent(ureq, event); @@ -143,8 +144,8 @@ public class QuestionsController extends BasicController implements StackedContr super.event(ureq, source, event); } - protected void doSelect(UserRequest ureq, QuestionItem item) { - QuestionItemDetailsController detailsCtrl = new QuestionItemDetailsController(ureq, getWindowControl(), item); + protected void doSelect(UserRequest ureq, QuestionItem item, boolean editable) { + QuestionItemDetailsController detailsCtrl = new QuestionItemDetailsController(ureq, getWindowControl(), item, editable); listenTo(detailsCtrl); LayoutMain3ColsController mainCtrl = new LayoutMain3ColsController(ureq, getWindowControl(), detailsCtrl); listenTo(mainCtrl); @@ -156,9 +157,10 @@ public class QuestionsController extends BasicController implements StackedContr confirmDeleteBox.setUserObject(item); } - private void doUpdateDetails(UserRequest ureq, QuestionItemShort itemShort) { - QuestionItem item = qpoolService.loadItemById(itemShort.getKey()); - detailsCtrl.updateItem(item); + private void doUpdateDetails(UserRequest ureq, QuestionItemView itemView) { + deleteItem.setVisible(itemView.isEditable()); + QuestionItem item = qpoolService.loadItemById(itemView.getKey()); + detailsCtrl.updateItem(item, itemView.isEditable()); previewCtrl.updateItem(ureq, item); } diff --git a/src/main/java/org/olat/modules/qpool/ui/ShareItemOptionController.java b/src/main/java/org/olat/modules/qpool/ui/ShareItemOptionController.java new file mode 100644 index 00000000000..cfd562eefa0 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/ShareItemOptionController.java @@ -0,0 +1,124 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.ui; + +import java.util.List; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.SingleSelection; +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.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.group.BusinessGroup; +import org.olat.modules.qpool.Pool; +import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionItemShort; + +/** + * + * Initial date: 21.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class ShareItemOptionController extends FormBasicController { + + private final String[] keys = {"yes","no"}; + private SingleSelection editableEl; + + private final QPoolService qpoolService; + + private final List<Pool> pools; + private final List<BusinessGroup> groups; + private final List<QuestionItemShort> items; + + public ShareItemOptionController(UserRequest ureq, WindowControl wControl, + List<QuestionItemShort> items, List<BusinessGroup> groups, List<Pool> pools) { + super(ureq, wControl, "share_options"); + qpoolService = CoreSpringFactory.getImpl(QPoolService.class); + + this.pools = pools; + this.items = items; + this.groups = groups; + + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + StringBuilder names = new StringBuilder(); + if(groups != null && !groups.isEmpty()) { + for(BusinessGroup group:groups) { + if(names.length() > 0) names.append(", "); + names.append(group.getName()); + } + } + if(pools != null && !pools.isEmpty()) { + for(Pool pool:pools) { + if(names.length() > 0) names.append(", "); + names.append(pool.getName()); + } + } + + if(formLayout instanceof FormLayoutContainer) { + ((FormLayoutContainer)formLayout).contextPut("shares", names.toString()); + } + + FormLayoutContainer mailCont = FormLayoutContainer.createDefaultFormLayout("editable", getTranslator()); + formLayout.add(mailCont); + String[] values = new String[]{ + translate("yes"), + translate("no") + }; + editableEl = uifactory.addRadiosVertical("share.editable", "share.editable", mailCont, keys, values); + editableEl.select("no", true); + + FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + buttonsCont.setRootForm(mainForm); + formLayout.add(buttonsCont); + uifactory.addFormSubmitButton("ok", "ok", buttonsCont); + uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl()); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void formOK(UserRequest ureq) { + boolean editable = editableEl.isOneSelected() && editableEl.isSelected(0); + if(groups != null && !groups.isEmpty()) { + qpoolService.shareItemsWithGroups(items, groups, editable); + } + if(pools != null && !pools.isEmpty()) { + qpoolService.shareItemsInPools(items, pools, editable); + } + fireEvent(ureq, new QPoolEvent(QPoolEvent.ITEM_SHARED)); + } + + @Override + protected void formCancelled(UserRequest ureq) { + fireEvent(ureq, Event.CANCELLED_EVENT); + } +} diff --git a/src/main/java/org/olat/modules/qpool/ui/_content/item_list.html b/src/main/java/org/olat/modules/qpool/ui/_content/item_list.html index 0c5c9609a7e..e278ab433bc 100644 --- a/src/main/java/org/olat/modules/qpool/ui/_content/item_list.html +++ b/src/main/java/org/olat/modules/qpool/ui/_content/item_list.html @@ -2,6 +2,7 @@ $r.render("items") <div class="b_clearfix o_qpool_button_bar_box"> <div class="o_qpool_button_bar"> $r.render("create.list") + $r.render("export.item") $r.render("share.item") $r.render("copy") $r.render("import.item") diff --git a/src/main/java/org/olat/modules/qpool/ui/_content/share_options.html b/src/main/java/org/olat/modules/qpool/ui/_content/share_options.html new file mode 100644 index 00000000000..5b19468a914 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/_content/share_options.html @@ -0,0 +1,3 @@ +<p>$r.translate("share.options", $shares)</p> +$r.render("editable") +$r.render("buttons") diff --git a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties index 9c84806160a..8475f0f5ccc 100644 --- a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties @@ -1,5 +1,6 @@ #Mon Mar 02 09:54:04 CET 2009 create.list=Liste erstellen +create.test=Test erstellen topnav.qpool=Q-Pool topnav.qpool.alt=Question pools create.collection.description=Geben Sie eine Name zu Ihre Liste. @@ -12,6 +13,12 @@ menu.admin=Administration menu.admin.alt=Administration menu.admin.studyfields=Fachbereich menu.admin.studyfields.alt=Fachbereich +menu.admin.types=Typ +menu.admin.types.alt=Typ +menu.admin.levels=Level +menu.admin.levels.alt=Level +menu.admin.licenses=Lizenz +menu.admin.licenses.alt=Lizenz menu.database=Fragendatenbank menu.database.alt=Ihre Fragendatenbank menu.database.my=Meine Fragen @@ -77,15 +84,19 @@ rights.copyright=Copyright rights.description=Lizenz rights.owners=Urheber error.wrongFloat=Falsches Zahlenformat. Beispiele\: 1.0, 0.5, 0.2 - +export.item=Export +rating=Rating manage.owners=Authoren item.level=Level item.shared=Frage {0} wurde freigegeben. item.pooled=Frage {0} wurde im Pool hinzugefügt. item.deleted=Frage wurde gelöscht. item.collectioned=Frage {0} wurde in der Liste hinzugefügt. +item.copied={0} Frage wurde kopiert. pool.key=ID pool.name=Name +pool.public=Public +pool.owners=Owners create.pool=Pool erstellen delete.pool=Pool löschen delete.pool.confirm=Wollen Sie wirklich diesen Pool "{0}" löschen? @@ -112,3 +123,5 @@ select.item=Bearbeiten export.item=Export import.item=Import error.input.toolong=Leider ist Ihr gerade eingegebener Text mit {1} Zeichen zu lang. Bitte beschr\u00E4nken Sie sich auf maximal {0} Zeichen. +share.options=Wollen Sie andere Personen diese Frage erlauben zu editieren? +share.editable=Editieren \ No newline at end of file diff --git a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties index 2d0095f7c90..305dc004ab9 100644 --- a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties @@ -1,11 +1,11 @@ -#Sun Jan 31 17:38:12 CET 2010 -topnav.qpool=Q-Pool -topnav.qpool.alt=Question pools -menu.database.my=My questions -menu.database.my.alt=My questions +#Mon Mar 18 11:59:20 CET 2013 menu.database.favorit=My favorits menu.database.favorit.alt=My favorits +menu.database.my=My questions +menu.database.my.alt=My questions menu.pools=Pool menu.pools.alt=Pool menu.pools.main=Catalog menu.pools.main.alt=Catalog +topnav.qpool=Q-Pool +topnav.qpool.alt=Question pools diff --git a/src/main/java/org/olat/modules/qpool/ui/PoolEditController.java b/src/main/java/org/olat/modules/qpool/ui/admin/PoolEditController.java similarity index 72% rename from src/main/java/org/olat/modules/qpool/ui/PoolEditController.java rename to src/main/java/org/olat/modules/qpool/ui/admin/PoolEditController.java index 2f9573695b2..8bb6332552f 100644 --- a/src/main/java/org/olat/modules/qpool/ui/PoolEditController.java +++ b/src/main/java/org/olat/modules/qpool/ui/admin/PoolEditController.java @@ -17,10 +17,12 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.modules.qpool.ui; +package org.olat.modules.qpool.ui.admin; +import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; 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.FormLayoutContainer; @@ -28,7 +30,10 @@ 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.util.StringHelper; +import org.olat.core.util.Util; import org.olat.modules.qpool.Pool; +import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.ui.MetadatasController; /** * @@ -39,22 +44,21 @@ import org.olat.modules.qpool.Pool; public class PoolEditController extends FormBasicController { private TextElement nameEl; + private MultipleSelectionElement publicEl; + private final Pool pool; + private final QPoolService qpoolService; public PoolEditController(UserRequest ureq, WindowControl wControl, Pool pool) { super(ureq, wControl); + setTranslator(Util.createPackageTranslator(MetadatasController.class, ureq.getLocale(), getTranslator())); + this.pool = pool; + qpoolService = CoreSpringFactory.getImpl(QPoolService.class); + initForm(ureq); } - public Pool getPool() { - return pool; - } - - public String getName() { - return nameEl.getValue(); - } - @Override protected void doDispose() { // @@ -65,6 +69,12 @@ public class PoolEditController extends FormBasicController { String name = pool == null ? "" : pool.getName(); nameEl = uifactory.addTextElement("pool.name", "pool.name", 128, name, formLayout); + String[] keys = new String[]{"on"}; + String[] values = new String[]{""}; + publicEl = uifactory.addCheckboxesHorizontal("pool.public", formLayout, keys, values, null); + boolean publicPool = pool == null ? false : pool.isPublicPool(); + publicEl.select("on", publicPool); + FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); buttonsCont.setRootForm(mainForm); formLayout.add(buttonsCont); @@ -87,6 +97,13 @@ public class PoolEditController extends FormBasicController { @Override protected void formOK(UserRequest ureq) { + if(pool == null) { + qpoolService.createPool(getIdentity(), nameEl.getValue(), publicEl.isAtLeastSelected(1)); + } else { + pool.setPublicPool(publicEl.isAtLeastSelected(1)); + pool.setName(nameEl.getValue()); + qpoolService.updatePool(pool); + } fireEvent(ureq, Event.DONE_EVENT); } diff --git a/src/main/java/org/olat/modules/qpool/ui/PoolsAdminController.java b/src/main/java/org/olat/modules/qpool/ui/admin/PoolsAdminController.java similarity index 55% rename from src/main/java/org/olat/modules/qpool/ui/PoolsAdminController.java rename to src/main/java/org/olat/modules/qpool/ui/admin/PoolsAdminController.java index 2aa575cc4cb..b840f611f54 100644 --- a/src/main/java/org/olat/modules/qpool/ui/PoolsAdminController.java +++ b/src/main/java/org/olat/modules/qpool/ui/admin/PoolsAdminController.java @@ -17,15 +17,17 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.modules.qpool.ui; +package org.olat.modules.qpool.ui.admin; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import org.olat.admin.securitygroup.gui.GroupController; +import org.olat.admin.securitygroup.gui.IdentitiesAddEvent; +import org.olat.admin.securitygroup.gui.IdentitiesRemoveEvent; import org.olat.core.CoreSpringFactory; -import org.olat.core.commons.persistence.DefaultResultInfos; import org.olat.core.commons.persistence.ResultInfos; -import org.olat.core.commons.persistence.SortKey; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; @@ -35,22 +37,31 @@ 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.elements.table.DefaultFlexiColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType; import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent; import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel; import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.components.table.TableDataModel; 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.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.core.gui.translator.Translator; +import org.olat.core.id.Identity; +import org.olat.core.util.Util; import org.olat.modules.qpool.Pool; import org.olat.modules.qpool.QPoolService; -import org.olat.modules.qpool.ui.PoolDataModel.Cols; +import org.olat.modules.qpool.model.PoolImpl; +import org.olat.modules.qpool.ui.MetadatasController; +import org.olat.modules.qpool.ui.QPoolEvent; /** + * + * Manage the list of pools * * Initial date: 21.02.2013<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com @@ -62,6 +73,8 @@ public class PoolsAdminController extends FormBasicController { private PoolDataModel model; private FlexiTableElement poolTable; + + private GroupController groupCtrl; private CloseableModalController cmc; private PoolEditController poolEditCtrl; private DialogBoxController confirmDeleteCtrl; @@ -70,6 +83,8 @@ public class PoolsAdminController extends FormBasicController { public PoolsAdminController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl, "pools_admin"); + setTranslator(Util.createPackageTranslator(MetadatasController.class, ureq.getLocale(), getTranslator())); + qpoolService = CoreSpringFactory.getImpl(QPoolService.class); initForm(ureq); } @@ -84,16 +99,25 @@ public class PoolsAdminController extends FormBasicController { //add the table FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.id.i18nKey(), Cols.id.ordinal(), true, "key")); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.publicPool.i18nKey(), Cols.publicPool.ordinal(), true, "name")); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.name.i18nKey(), Cols.name.ordinal(), true, "name")); columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("edit", translate("edit"), "edit-pool")); + columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("pool.owners", translate("pool.owners"), "owners-pool")); columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("delete", translate("delete"), "delete-pool")); - model = new PoolDataModel(columnsModel, new PoolSource(), getTranslator()); - poolTable = uifactory.addTableElement(ureq, "pools", model, model, 20, false, getTranslator(), formLayout); + model = new PoolDataModel(columnsModel, getTranslator()); + poolTable = uifactory.addTableElement(ureq, "pools", model, null, 20, false, getTranslator(), formLayout); poolTable.setRendererType(FlexiTableRendererType.classic); + reloadModel(); createPool = uifactory.addFormLink("create.pool", formLayout, Link.BUTTON); } + + private void reloadModel() { + ResultInfos<Pool> pools = qpoolService.getPools(0, -1); + model.setObjects(pools.getObjects()); + poolTable.reset(); + } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { @@ -103,11 +127,14 @@ public class PoolsAdminController extends FormBasicController { if(event instanceof SelectionEvent) { SelectionEvent se = (SelectionEvent)event; if("edit-pool".equals(se.getCommand())) { - PoolRow row = model.getObject(se.getIndex()); - doEditPool(ureq, row.getPool()); + Pool row = model.getObject(se.getIndex()); + doEditPool(ureq, row); } else if("delete-pool".equals(se.getCommand())) { - PoolRow row = model.getObject(se.getIndex()); - doConfirmDelete(ureq, row.getPool()); + Pool row = model.getObject(se.getIndex()); + doConfirmDelete(ureq, row); + } else if("owners-pool".equals(se.getCommand())) { + Pool row = model.getObject(se.getIndex()); + doManageOwners(ureq, row); } } } @@ -118,16 +145,24 @@ public class PoolsAdminController extends FormBasicController { protected void event(UserRequest ureq, Controller source, Event event) { if(source == poolEditCtrl) { if(event == Event.DONE_EVENT) { - Pool pool = poolEditCtrl.getPool(); - if(pool == null) { - doCreate(ureq, poolEditCtrl.getName()); - } else { - doEdit(ureq, pool, poolEditCtrl.getName()); - } + reloadModel(); + fireEvent(ureq, new QPoolEvent(QPoolEvent.POOL_CREATED)); } cmc.deactivate(); cleanUp(); - } else if(source == confirmDeleteCtrl) { + } else if(source == groupCtrl) { + Pool selectedPool = (Pool)groupCtrl.getUserObject(); + if(event instanceof IdentitiesAddEvent ) { + IdentitiesAddEvent identitiesAddedEvent = (IdentitiesAddEvent) event; + List<Identity> list = identitiesAddedEvent.getAddIdentities(); + qpoolService.addOwners(list, Collections.singletonList(selectedPool)); + identitiesAddedEvent.getAddedIdentities().addAll(list); + } else if (event instanceof IdentitiesRemoveEvent) { + IdentitiesRemoveEvent identitiesRemoveEvent = (IdentitiesRemoveEvent) event; + List<Identity> list = identitiesRemoveEvent.getRemovedIdentities(); + qpoolService.removeOwners(list, Collections.singletonList(selectedPool)); + } + } else if(source == confirmDeleteCtrl) { if(DialogBoxUIFactory.isOkEvent(event) || DialogBoxUIFactory.isYesEvent(event)) { Pool pool = (Pool)confirmDeleteCtrl.getUserObject(); doDelete(ureq, pool); @@ -139,8 +174,10 @@ public class PoolsAdminController extends FormBasicController { private void cleanUp() { removeAsListenerAndDispose(poolEditCtrl); + removeAsListenerAndDispose(groupCtrl); removeAsListenerAndDispose(cmc); poolEditCtrl = null; + groupCtrl = null; cmc = null; } @@ -158,7 +195,7 @@ public class PoolsAdminController extends FormBasicController { private void doDelete(UserRequest ureq, Pool pool) { qpoolService.deletePool(pool); - poolTable.reset(); + reloadModel(); fireEvent(ureq, new QPoolEvent(QPoolEvent.POOL_DELETED)); } @@ -173,37 +210,92 @@ public class PoolsAdminController extends FormBasicController { listenTo(cmc); } - private void doCreate(UserRequest ureq, String name) { - qpoolService.createPool(getIdentity(), name); - poolTable.reset(); - fireEvent(ureq, new QPoolEvent(QPoolEvent.POOL_CREATED)); - } + private void doManageOwners(UserRequest ureq, Pool pool) { + if(pool instanceof PoolImpl) { + PoolImpl poolImpl = (PoolImpl)pool; + groupCtrl = new GroupController(ureq, getWindowControl(), true, true, false, true, + false, false, poolImpl.getOwnerGroup()); + groupCtrl.setUserObject(pool); + listenTo(groupCtrl); - private void doEdit(UserRequest ureq, Pool pool, String name) { - pool.setName(name); - qpoolService.updatePool(pool); - poolTable.reset(); - fireEvent(ureq, new QPoolEvent(QPoolEvent.POOL_CREATED)); + cmc = new CloseableModalController(getWindowControl(), translate("close"), + groupCtrl.getInitialComponent(), true, translate("manage.owners")); + cmc.activate(); + listenTo(cmc); + } } - private PoolRow forgeRow(Pool pool) { - PoolRow row = new PoolRow(pool); - return row; + private enum Cols { + id("pool.key"), + publicPool("pool.public"), + name("pool.name"); + + private final String i18nKey; + + private Cols(String i18nKey) { + this.i18nKey = i18nKey; + } + + public String i18nKey() { + return i18nKey; + } } - public class PoolSource { - - public int getNumOfItems() { - return qpoolService.countPools(); + private static class PoolDataModel implements FlexiTableDataModel, TableDataModel<Pool> { + + private List<Pool> rows; + private FlexiTableColumnModel columnModel; + private final Translator translator; + + public PoolDataModel(FlexiTableColumnModel columnModel, Translator translator) { + this.columnModel = columnModel; + this.translator = translator; } - - public ResultInfos<PoolRow> getRows(int firstResult, int maxResults, SortKey... orderBy) { - ResultInfos<Pool> pools = qpoolService.getPools(firstResult, maxResults, orderBy); - List<PoolRow> rows = new ArrayList<PoolRow>(pools.getObjects().size()); - for(Pool pool:pools.getObjects()) { - rows.add(forgeRow(pool)); + + @Override + public FlexiTableColumnModel getTableColumnModel() { + return columnModel; + } + + @Override + public void setTableColumnModel(FlexiTableColumnModel tableColumnModel) { + this.columnModel = tableColumnModel; + } + + @Override + public int getRowCount() { + return rows == null ? 0 : rows.size(); + } + + @Override + public Pool getObject(int row) { + return rows.get(row); + } + + @Override + public void setObjects(List<Pool> objects) { + rows = new ArrayList<Pool>(objects); + } + + @Override + public int getColumnCount() { + return columnModel.getColumnCount(); + } + + @Override + public PoolDataModel createCopyWithEmptyList() { + return new PoolDataModel(columnModel, translator); + } + + @Override + public Object getValueAt(int row, int col) { + Pool item = getObject(row); + switch(Cols.values()[col]) { + case id: return item.getKey(); + case publicPool: return new Boolean(item.isPublicPool()); + case name: return item.getName(); + default: return ""; } - return new DefaultResultInfos<PoolRow>(pools.getNextFirstResult(), pools.getCorrectedRowCount(), rows); } } } diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/QEducationalContextEditController.java b/src/main/java/org/olat/modules/qpool/ui/admin/QEducationalContextEditController.java new file mode 100644 index 00000000000..6aeb31d67cd --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/admin/QEducationalContextEditController.java @@ -0,0 +1,105 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.ui.admin; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +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.FormLayoutContainer; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.util.StringHelper; +import org.olat.core.util.Util; +import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.model.QEducationalContext; +import org.olat.modules.qpool.ui.MetadatasController; + +/** + * + * Initial date: 18.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QEducationalContextEditController extends FormBasicController { + + private TextElement nameEl; + + private final QEducationalContext itemLevel; + private final QPoolService qpoolService; + + public QEducationalContextEditController(UserRequest ureq, WindowControl wControl, QEducationalContext itemLevel) { + super(ureq, wControl); + setTranslator(Util.createPackageTranslator(MetadatasController.class, ureq.getLocale(), getTranslator())); + + this.itemLevel = itemLevel; + qpoolService = CoreSpringFactory.getImpl(QPoolService.class); + + initForm(ureq); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + String name = itemLevel == null ? "" : itemLevel.getLevel(); + nameEl = uifactory.addTextElement("level.level", "level.level", 128, name, formLayout); + + FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + buttonsCont.setRootForm(mainForm); + formLayout.add(buttonsCont); + uifactory.addFormSubmitButton("ok", "ok", buttonsCont); + uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl()); + } + + @Override + protected boolean validateFormLogic(UserRequest ureq) { + boolean allOk = true; + + nameEl.clearError(); + if(!StringHelper.containsNonWhitespace(nameEl.getValue())) { + nameEl.setErrorKey("form.mandatory.hover", null); + allOk = false; + } + + return allOk && super.validateFormLogic(ureq); + } + + @Override + protected void formOK(UserRequest ureq) { + if(itemLevel == null) { + qpoolService.createEducationalContext(nameEl.getValue()); + } else { + //itemType.setName(nameEl.getValue()); + //qpoolService.updatePool(itemType); + } + fireEvent(ureq, Event.DONE_EVENT); + } + + @Override + protected void formCancelled(UserRequest ureq) { + fireEvent(ureq, Event.CANCELLED_EVENT); + } +} diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/QEducationalContextsAdminController.java b/src/main/java/org/olat/modules/qpool/ui/admin/QEducationalContextsAdminController.java new file mode 100644 index 00000000000..e4a370a49b8 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/admin/QEducationalContextsAdminController.java @@ -0,0 +1,308 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.ui.admin; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import org.olat.core.CoreSpringFactory; +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.FlexiTableElement; +import org.olat.core.gui.components.form.flexible.elements.FormLink; +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.elements.table.BooleanCellRenderer; +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.FlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType; +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.form.flexible.impl.elements.table.StaticFlexiColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer; +import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.components.table.TableDataModel; +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.generic.closablewrapper.CloseableModalController; +import org.olat.core.gui.control.generic.modal.DialogBoxController; +import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.core.util.Util; +import org.olat.core.util.i18n.I18nItem; +import org.olat.core.util.i18n.I18nManager; +import org.olat.core.util.i18n.I18nModule; +import org.olat.core.util.i18n.ui.TranslationToolI18nItemEditCrumbController; +import org.olat.core.util.prefs.Preferences; +import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.model.QEducationalContext; +import org.olat.modules.qpool.ui.MetadatasController; + +/** + * + * Manage the list of levels + * + * Initial date: 18.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QEducationalContextsAdminController extends FormBasicController { + + private FormLink createType; + + private LevelDataModel model; + private FlexiTableElement tableEl; + + private CloseableModalController cmc; + private QEducationalContextEditController editCtrl; + private DialogBoxController confirmDeleteCtrl; + private TranslationToolI18nItemEditCrumbController i18nItemEditCtr; + + private final QPoolService qpoolService; + + public QEducationalContextsAdminController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl, "levels_admin"); + + setTranslator(Util.createPackageTranslator(MetadatasController.class, ureq.getLocale(), getTranslator())); + + qpoolService = CoreSpringFactory.getImpl(QPoolService.class); + initForm(ureq); + reloadModel(); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + //add the table + FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.id.i18nKey(), Cols.id.ordinal(), true, "key")); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.level.i18nKey(), Cols.level.ordinal(), true, "level")); + FlexiCellRenderer renderer = new StaticFlexiCellRenderer("translate", new TextFlexiCellRenderer()); + columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.levelI18n.i18nKey(), Cols.levelI18n.ordinal(), "translate", renderer)); + FlexiCellRenderer delRenderer = new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("delete"), "delete-level"), null); + columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("delete", Cols.deletable.ordinal(), "delete-level", delRenderer)); + + model = new LevelDataModel(columnsModel); + tableEl = uifactory.addTableElement(ureq, "levels", model, null, 20, false, getTranslator(), formLayout); + tableEl.setRendererType(FlexiTableRendererType.classic); + + createType = uifactory.addFormLink("create.level", formLayout, Link.BUTTON); + } + + private void reloadModel() { + List<QEducationalContext> rows = qpoolService.getAllEducationlContexts(); + model.setObjects(rows); + tableEl.reset(); + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(source == createType) { + doEdit(ureq, null); + } else if(source == tableEl) { + if(event instanceof SelectionEvent) { + SelectionEvent se = (SelectionEvent)event; + if("delete-level".equals(se.getCommand())) { + QEducationalContext row = model.getObject(se.getIndex()); + doConfirmDelete(ureq, row); + } else if("translate".equals(se.getCommand())) { + QEducationalContext row = model.getObject(se.getIndex()); + doOpenTranslationTool(ureq, row); + } + } + } + super.formInnerEvent(ureq, source, event); + } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if(source == editCtrl) { + if(event == Event.DONE_EVENT) { + reloadModel(); + } + cmc.deactivate(); + cleanUp(); + } else if(source == confirmDeleteCtrl) { + if(DialogBoxUIFactory.isOkEvent(event) || DialogBoxUIFactory.isYesEvent(event)) { + QEducationalContext level = (QEducationalContext)confirmDeleteCtrl.getUserObject(); + doDelete(ureq, level); + } + } else if(source == cmc) { + cleanUp(); + } + } + + private void cleanUp() { + removeAsListenerAndDispose(editCtrl); + removeAsListenerAndDispose(cmc); + editCtrl = null; + cmc = null; + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + private void doOpenTranslationTool(UserRequest ureq, QEducationalContext row) { + Locale orgininalLocale = getLocale(); + Locale varLocale = new Locale(orgininalLocale.getLanguage(), orgininalLocale.getCountry(), "__customizing"); + + I18nItem item = new I18nItem("org.olat.modules.qpool.ui", "item.level." + row.getLevel(), varLocale, 1, 1); + List<I18nItem> i18nItems = new ArrayList<I18nItem>(); + i18nItems.add(item); + + Preferences guiPrefs = ureq.getUserSession().getGuiPreferences(); + List<String> referenceLangs = I18nModule.getTransToolReferenceLanguages(); + String referencePrefs = (String)guiPrefs.get(I18nModule.class, I18nModule.GUI_PREFS_PREFERRED_REFERENCE_LANG, referenceLangs.get(0)); + I18nManager i18nMgr = I18nManager.getInstance(); + Locale referenceLocale = i18nMgr.getLocaleOrNull(referencePrefs); + + + i18nItemEditCtr = new TranslationToolI18nItemEditCrumbController(ureq, getWindowControl(), i18nItems, referenceLocale, true); + listenTo(i18nItemEditCtr); + + i18nItemEditCtr.initialzeI18nitemAsCurrentItem(ureq, item); + + // Open in modal window + if (cmc != null) removeAsListenerAndDispose(cmc); + cmc = new CloseableModalController(getWindowControl(), "close", i18nItemEditCtr.getInitialComponent()); + listenTo(cmc); + cmc.activate(); + } + + private void doConfirmDelete(UserRequest ureq, QEducationalContext level) { + String title = translate("delete.level"); + String text = translate("delete.level.confirm", new String[]{ level.getLevel() }); + confirmDeleteCtrl = activateOkCancelDialog(ureq, title, text, confirmDeleteCtrl); + confirmDeleteCtrl.setUserObject(level); + } + + private void doDelete(UserRequest ureq, QEducationalContext level) { + //qpoolService.deletePool(pool); + reloadModel(); + } + + private void doEdit(UserRequest ureq, QEducationalContext level) { + removeAsListenerAndDispose(editCtrl); + editCtrl = new QEducationalContextEditController(ureq, getWindowControl(), level); + listenTo(editCtrl); + + cmc = new CloseableModalController(getWindowControl(), translate("close"), + editCtrl.getInitialComponent(), true, translate("edit.pool")); + cmc.activate(); + listenTo(cmc); + } + + private enum Cols { + id("level.key"), + level("level.level"), + levelI18n("level.translation"), + deletable("level.deletable"); + + private final String i18nKey; + + private Cols(String i18nKey) { + this.i18nKey = i18nKey; + } + + public String i18nKey() { + return i18nKey; + } + } + + private class LevelDataModel implements FlexiTableDataModel, TableDataModel<QEducationalContext> { + + private FlexiTableColumnModel columnModel; + private List<QEducationalContext> levels; + + public LevelDataModel(FlexiTableColumnModel columnModel) { + this.columnModel = columnModel; + } + + @Override + public FlexiTableColumnModel getTableColumnModel() { + return columnModel; + } + + @Override + public void setTableColumnModel(FlexiTableColumnModel columnModel) { + this.columnModel = columnModel; + } + + @Override + public int getColumnCount() { + return columnModel.getColumnCount(); + } + + @Override + public QEducationalContext getObject(int row) { + if(levels != null && row >= 0 && row < levels.size()) { + return levels.get(row); + } + return null; + } + + @Override + public void setObjects(List<QEducationalContext> objects) { + levels = new ArrayList<QEducationalContext>(objects); + } + + @Override + public Object createCopyWithEmptyList() { + return new LevelDataModel(columnModel); + } + + + @Override + public int getRowCount() { + return levels == null ? 0 : levels.size(); + } + + @Override + public Object getValueAt(int row, int col) { + QEducationalContext level = getObject(row); + switch(Cols.values()[col]) { + case id: return level.getKey(); + case level: return level.getLevel(); + case levelI18n: { + String i18nKey = "item.level." + level.getLevel().toLowerCase(); + String translation = getTranslator().translate(i18nKey); + if(translation.length() > 256) { + return i18nKey; + } + return translation; + } + case deletable: return level.isDeletable(); + default: return ""; + } + } + } + +} diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/QItemTypeEditController.java b/src/main/java/org/olat/modules/qpool/ui/admin/QItemTypeEditController.java new file mode 100644 index 00000000000..81c60369ea1 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/admin/QItemTypeEditController.java @@ -0,0 +1,105 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.ui.admin; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +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.FormLayoutContainer; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.util.StringHelper; +import org.olat.core.util.Util; +import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.model.QItemType; +import org.olat.modules.qpool.ui.MetadatasController; + +/** + * + * Initial date: 21.02.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QItemTypeEditController extends FormBasicController { + + private TextElement nameEl; + + private final QItemType itemType; + private final QPoolService qpoolService; + + public QItemTypeEditController(UserRequest ureq, WindowControl wControl, QItemType itemType) { + super(ureq, wControl); + setTranslator(Util.createPackageTranslator(MetadatasController.class, ureq.getLocale(), getTranslator())); + + this.itemType = itemType; + qpoolService = CoreSpringFactory.getImpl(QPoolService.class); + + initForm(ureq); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + String name = itemType == null ? "" : itemType.getType(); + nameEl = uifactory.addTextElement("type.type", "type.type", 128, name, formLayout); + + FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + buttonsCont.setRootForm(mainForm); + formLayout.add(buttonsCont); + uifactory.addFormSubmitButton("ok", "ok", buttonsCont); + uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl()); + } + + @Override + protected boolean validateFormLogic(UserRequest ureq) { + boolean allOk = true; + + nameEl.clearError(); + if(!StringHelper.containsNonWhitespace(nameEl.getValue())) { + nameEl.setErrorKey("form.mandatory.hover", null); + allOk = false; + } + + return allOk && super.validateFormLogic(ureq); + } + + @Override + protected void formOK(UserRequest ureq) { + if(itemType == null) { + qpoolService.createItemType(nameEl.getValue(), true); + } else { + //itemType.setName(nameEl.getValue()); + //qpoolService.updatePool(itemType); + } + fireEvent(ureq, Event.DONE_EVENT); + } + + @Override + protected void formCancelled(UserRequest ureq) { + fireEvent(ureq, Event.CANCELLED_EVENT); + } +} diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/QItemTypesAdminController.java b/src/main/java/org/olat/modules/qpool/ui/admin/QItemTypesAdminController.java new file mode 100644 index 00000000000..ab4549eaf4e --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/admin/QItemTypesAdminController.java @@ -0,0 +1,308 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.ui.admin; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import org.olat.core.CoreSpringFactory; +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.FlexiTableElement; +import org.olat.core.gui.components.form.flexible.elements.FormLink; +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.elements.table.BooleanCellRenderer; +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.FlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType; +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.form.flexible.impl.elements.table.StaticFlexiColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer; +import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.components.table.TableDataModel; +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.generic.closablewrapper.CloseableModalController; +import org.olat.core.gui.control.generic.modal.DialogBoxController; +import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.core.util.Util; +import org.olat.core.util.i18n.I18nItem; +import org.olat.core.util.i18n.I18nManager; +import org.olat.core.util.i18n.I18nModule; +import org.olat.core.util.i18n.ui.TranslationToolI18nItemEditCrumbController; +import org.olat.core.util.prefs.Preferences; +import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.model.QItemType; +import org.olat.modules.qpool.ui.MetadatasController; + +/** + * + * Manage the list of types + * + * Initial date: 21.02.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QItemTypesAdminController extends FormBasicController { + + private FormLink createType; + + private QItemTypeDataModel model; + private FlexiTableElement tableEl; + + private CloseableModalController cmc; + private QItemTypeEditController editCtrl; + private DialogBoxController confirmDeleteCtrl; + private TranslationToolI18nItemEditCrumbController i18nItemEditCtr; + + private final QPoolService qpoolService; + + public QItemTypesAdminController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl, "types_admin"); + + setTranslator(Util.createPackageTranslator(MetadatasController.class, ureq.getLocale(), getTranslator())); + + qpoolService = CoreSpringFactory.getImpl(QPoolService.class); + initForm(ureq); + reloadModel(); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + //add the table + FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.id.i18nKey(), Cols.id.ordinal(), true, "key")); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.type.i18nKey(), Cols.type.ordinal(), true, "name")); + FlexiCellRenderer renderer = new StaticFlexiCellRenderer("translate", new TextFlexiCellRenderer()); + columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.typeI18n.i18nKey(), Cols.typeI18n.ordinal(), "translate", renderer)); + FlexiCellRenderer delRenderer = new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("delete"), "delete-type"), null); + columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("delete", Cols.deletable.ordinal(), "delete-type", delRenderer)); + + model = new QItemTypeDataModel(columnsModel); + tableEl = uifactory.addTableElement(ureq, "types", model, null, 20, false, getTranslator(), formLayout); + tableEl.setRendererType(FlexiTableRendererType.classic); + + createType = uifactory.addFormLink("create.type", formLayout, Link.BUTTON); + } + + private void reloadModel() { + List<QItemType> rows = qpoolService.getAllItemTypes(); + model.setObjects(rows); + tableEl.reset(); + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(source == createType) { + doEdit(ureq, null); + } else if(source == tableEl) { + if(event instanceof SelectionEvent) { + SelectionEvent se = (SelectionEvent)event; + if("delete-type".equals(se.getCommand())) { + QItemType row = model.getObject(se.getIndex()); + doConfirmDelete(ureq, row); + } else if("translate".equals(se.getCommand())) { + QItemType row = model.getObject(se.getIndex()); + doOpenTranslationTool(ureq, row); + } + } + } + super.formInnerEvent(ureq, source, event); + } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if(source == editCtrl) { + if(event == Event.DONE_EVENT) { + reloadModel(); + } + cmc.deactivate(); + cleanUp(); + } else if(source == confirmDeleteCtrl) { + if(DialogBoxUIFactory.isOkEvent(event) || DialogBoxUIFactory.isYesEvent(event)) { + QItemType type = (QItemType)confirmDeleteCtrl.getUserObject(); + doDelete(ureq, type); + } + } else if(source == cmc) { + cleanUp(); + } + } + + private void cleanUp() { + removeAsListenerAndDispose(editCtrl); + removeAsListenerAndDispose(cmc); + editCtrl = null; + cmc = null; + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + private void doOpenTranslationTool(UserRequest ureq, QItemType row) { + Locale orgininalLocale = getLocale(); + Locale varLocale = new Locale(orgininalLocale.getLanguage(), orgininalLocale.getCountry(), "__customizing"); + + I18nItem item = new I18nItem("org.olat.modules.qpool.ui", "item.type." + row.getType(), varLocale, 1, 1); + List<I18nItem> i18nItems = new ArrayList<I18nItem>(); + i18nItems.add(item); + + Preferences guiPrefs = ureq.getUserSession().getGuiPreferences(); + List<String> referenceLangs = I18nModule.getTransToolReferenceLanguages(); + String referencePrefs = (String)guiPrefs.get(I18nModule.class, I18nModule.GUI_PREFS_PREFERRED_REFERENCE_LANG, referenceLangs.get(0)); + I18nManager i18nMgr = I18nManager.getInstance(); + Locale referenceLocale = i18nMgr.getLocaleOrNull(referencePrefs); + + + i18nItemEditCtr = new TranslationToolI18nItemEditCrumbController(ureq, getWindowControl(), i18nItems, referenceLocale, true); + listenTo(i18nItemEditCtr); + + i18nItemEditCtr.initialzeI18nitemAsCurrentItem(ureq, item); + + // Open in modal window + if (cmc != null) removeAsListenerAndDispose(cmc); + cmc = new CloseableModalController(getWindowControl(), "close", i18nItemEditCtr.getInitialComponent()); + listenTo(cmc); + cmc.activate(); + } + + private void doConfirmDelete(UserRequest ureq, QItemType type) { + String title = translate("delete.type"); + String text = translate("delete.type.confirm", new String[]{ type.getType() }); + confirmDeleteCtrl = activateOkCancelDialog(ureq, title, text, confirmDeleteCtrl); + confirmDeleteCtrl.setUserObject(type); + } + + private void doDelete(UserRequest ureq, QItemType type) { + //qpoolService.deletePool(pool); + reloadModel(); + } + + private void doEdit(UserRequest ureq, QItemType type) { + removeAsListenerAndDispose(editCtrl); + editCtrl = new QItemTypeEditController(ureq, getWindowControl(), type); + listenTo(editCtrl); + + cmc = new CloseableModalController(getWindowControl(), translate("close"), + editCtrl.getInitialComponent(), true, translate("edit.pool")); + cmc.activate(); + listenTo(cmc); + } + + private enum Cols { + id("type.key"), + type("type.type"), + typeI18n("type.translation"), + deletable("type.deletable"); + + private final String i18nKey; + + private Cols(String i18nKey) { + this.i18nKey = i18nKey; + } + + public String i18nKey() { + return i18nKey; + } + } + + private class QItemTypeDataModel implements FlexiTableDataModel, TableDataModel<QItemType> { + + private FlexiTableColumnModel columnModel; + private List<QItemType> types; + + public QItemTypeDataModel(FlexiTableColumnModel columnModel) { + this.columnModel = columnModel; + } + + @Override + public FlexiTableColumnModel getTableColumnModel() { + return columnModel; + } + + @Override + public void setTableColumnModel(FlexiTableColumnModel columnModel) { + this.columnModel = columnModel; + } + + @Override + public int getColumnCount() { + return columnModel.getColumnCount(); + } + + @Override + public QItemType getObject(int row) { + if(types != null && row >= 0 && row < types.size()) { + return types.get(row); + } + return null; + } + + @Override + public void setObjects(List<QItemType> objects) { + types = new ArrayList<QItemType>(objects); + } + + @Override + public Object createCopyWithEmptyList() { + return new QItemTypeDataModel(columnModel); + } + + + @Override + public int getRowCount() { + return types == null ? 0 : types.size(); + } + + @Override + public Object getValueAt(int row, int col) { + QItemType type = getObject(row); + switch(Cols.values()[col]) { + case id: return type.getKey(); + case type: return type.getType(); + case typeI18n: { + String i18nKey = "item.type." + type.getType().toLowerCase(); + String translation = getTranslator().translate(i18nKey); + if(translation.length() > 256) { + return i18nKey; + } + return translation; + } + case deletable: return type.isDeletable(); + default: return ""; + } + } + } + +} diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/QLicenseEditController.java b/src/main/java/org/olat/modules/qpool/ui/admin/QLicenseEditController.java new file mode 100644 index 00000000000..208801f9ed3 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/admin/QLicenseEditController.java @@ -0,0 +1,105 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.ui.admin; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +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.FormLayoutContainer; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.util.StringHelper; +import org.olat.core.util.Util; +import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.model.QLicense; +import org.olat.modules.qpool.ui.MetadatasController; + +/** + * + * Initial date: 18.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QLicenseEditController extends FormBasicController { + + private TextElement nameEl; + + private final QLicense license; + private final QPoolService qpoolService; + + public QLicenseEditController(UserRequest ureq, WindowControl wControl, QLicense license) { + super(ureq, wControl); + setTranslator(Util.createPackageTranslator(MetadatasController.class, ureq.getLocale(), getTranslator())); + + this.license = license; + qpoolService = CoreSpringFactory.getImpl(QPoolService.class); + + initForm(ureq); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + String name = license == null ? "" : license.getLicenseKey(); + nameEl = uifactory.addTextElement("license.key", "license.key", 128, name, formLayout); + + FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + buttonsCont.setRootForm(mainForm); + formLayout.add(buttonsCont); + uifactory.addFormSubmitButton("ok", "ok", buttonsCont); + uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl()); + } + + @Override + protected boolean validateFormLogic(UserRequest ureq) { + boolean allOk = true; + + nameEl.clearError(); + if(!StringHelper.containsNonWhitespace(nameEl.getValue())) { + nameEl.setErrorKey("form.mandatory.hover", null); + allOk = false; + } + + return allOk && super.validateFormLogic(ureq); + } + + @Override + protected void formOK(UserRequest ureq) { + if(license == null) { + qpoolService.createLicense(nameEl.getValue()); + } else { + //itemType.setName(nameEl.getValue()); + //qpoolService.updatePool(itemType); + } + fireEvent(ureq, Event.DONE_EVENT); + } + + @Override + protected void formCancelled(UserRequest ureq) { + fireEvent(ureq, Event.CANCELLED_EVENT); + } +} diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/QLicensesAdminController.java b/src/main/java/org/olat/modules/qpool/ui/admin/QLicensesAdminController.java new file mode 100644 index 00000000000..ddac4da52bd --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/admin/QLicensesAdminController.java @@ -0,0 +1,258 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.ui.admin; + +import java.util.ArrayList; +import java.util.List; + +import org.olat.core.CoreSpringFactory; +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.FlexiTableElement; +import org.olat.core.gui.components.form.flexible.elements.FormLink; +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.elements.table.BooleanCellRenderer; +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.FlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType; +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.form.flexible.impl.elements.table.StaticFlexiColumnModel; +import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.components.table.TableDataModel; +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.generic.closablewrapper.CloseableModalController; +import org.olat.core.gui.control.generic.modal.DialogBoxController; +import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.core.util.Util; +import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.model.QLicense; +import org.olat.modules.qpool.ui.MetadatasController; + +/** + * + * Manage the licenses + * + * Initial date: 18.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QLicensesAdminController extends FormBasicController { + + private FormLink createType; + + private QItemTypeDataModel model; + private FlexiTableElement tableEl; + + private CloseableModalController cmc; + private QLicenseEditController editCtrl; + private DialogBoxController confirmDeleteCtrl; + + private final QPoolService qpoolService; + + public QLicensesAdminController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl, "licenses_admin"); + + setTranslator(Util.createPackageTranslator(MetadatasController.class, ureq.getLocale(), getTranslator())); + + qpoolService = CoreSpringFactory.getImpl(QPoolService.class); + initForm(ureq); + reloadModel(); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + //add the table + FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.id.i18nKey(), Cols.id.ordinal(), true, "key")); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.licenseKey.i18nKey(), Cols.licenseKey.ordinal(), true, "licenseKey")); + FlexiCellRenderer delRenderer = new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("delete"), "delete-license"), null); + columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("delete", Cols.deletable.ordinal(), "delete-license", delRenderer)); + + model = new QItemTypeDataModel(columnsModel); + tableEl = uifactory.addTableElement(ureq, "licenses", model, null, 20, false, getTranslator(), formLayout); + tableEl.setRendererType(FlexiTableRendererType.classic); + + createType = uifactory.addFormLink("create.license", formLayout, Link.BUTTON); + } + + private void reloadModel() { + List<QLicense> rows = qpoolService.getAllLicenses(); + model.setObjects(rows); + tableEl.reset(); + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(source == createType) { + doEdit(ureq, null); + } else if(source == tableEl) { + if(event instanceof SelectionEvent) { + SelectionEvent se = (SelectionEvent)event; + if("delete-license".equals(se.getCommand())) { + QLicense row = model.getObject(se.getIndex()); + doConfirmDelete(ureq, row); + } + } + } + super.formInnerEvent(ureq, source, event); + } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if(source == editCtrl) { + if(event == Event.DONE_EVENT) { + reloadModel(); + } + cmc.deactivate(); + cleanUp(); + } else if(source == confirmDeleteCtrl) { + if(DialogBoxUIFactory.isOkEvent(event) || DialogBoxUIFactory.isYesEvent(event)) { + QLicense type = (QLicense)confirmDeleteCtrl.getUserObject(); + doDelete(ureq, type); + } + } else if(source == cmc) { + cleanUp(); + } + } + + private void cleanUp() { + removeAsListenerAndDispose(editCtrl); + removeAsListenerAndDispose(cmc); + editCtrl = null; + cmc = null; + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + + private void doConfirmDelete(UserRequest ureq, QLicense type) { + String title = translate("delete.license"); + String text = translate("delete.license.confirm", new String[]{ type.getLicenseKey() }); + confirmDeleteCtrl = activateOkCancelDialog(ureq, title, text, confirmDeleteCtrl); + confirmDeleteCtrl.setUserObject(type); + } + + private void doDelete(UserRequest ureq, QLicense type) { + //qpoolService.deletePool(pool); + reloadModel(); + } + + private void doEdit(UserRequest ureq, QLicense license) { + removeAsListenerAndDispose(editCtrl); + editCtrl = new QLicenseEditController(ureq, getWindowControl(), license); + listenTo(editCtrl); + + cmc = new CloseableModalController(getWindowControl(), translate("close"), + editCtrl.getInitialComponent(), true, translate("edit.pool")); + cmc.activate(); + listenTo(cmc); + } + + private enum Cols { + id("license.id"), + licenseKey("license.key"), + deletable("license.deletable"); + + private final String i18nKey; + + private Cols(String i18nKey) { + this.i18nKey = i18nKey; + } + + public String i18nKey() { + return i18nKey; + } + } + + private class QItemTypeDataModel implements FlexiTableDataModel, TableDataModel<QLicense> { + + private FlexiTableColumnModel columnModel; + private List<QLicense> licenses; + + public QItemTypeDataModel(FlexiTableColumnModel columnModel) { + this.columnModel = columnModel; + } + + @Override + public FlexiTableColumnModel getTableColumnModel() { + return columnModel; + } + + @Override + public void setTableColumnModel(FlexiTableColumnModel columnModel) { + this.columnModel = columnModel; + } + + @Override + public int getColumnCount() { + return columnModel.getColumnCount(); + } + + @Override + public QLicense getObject(int row) { + if(licenses != null && row >= 0 && row < licenses.size()) { + return licenses.get(row); + } + return null; + } + + @Override + public void setObjects(List<QLicense> objects) { + licenses = new ArrayList<QLicense>(objects); + } + + @Override + public Object createCopyWithEmptyList() { + return new QItemTypeDataModel(columnModel); + } + + @Override + public int getRowCount() { + return licenses == null ? 0 : licenses.size(); + } + + @Override + public Object getValueAt(int row, int col) { + QLicense type = getObject(row); + switch(Cols.values()[col]) { + case id: return type.getKey(); + case licenseKey: return type.getLicenseKey(); + case deletable: return type.isDeletable(); + default: return ""; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/_content/levels_admin.html b/src/main/java/org/olat/modules/qpool/ui/admin/_content/levels_admin.html new file mode 100644 index 00000000000..0aef3e0e5d0 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/admin/_content/levels_admin.html @@ -0,0 +1,14 @@ +<fieldset> + <legend>$r.translate("menu.admin.levels")</legend> + $r.render("levels") + <div class="b_clearfix o_qpool_button_bar_box"> + <div class="o_qpool_button_bar"> + $r.render("create.level") + </div> + </div> +</fieldset> + + + + + diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/_content/licenses_admin.html b/src/main/java/org/olat/modules/qpool/ui/admin/_content/licenses_admin.html new file mode 100644 index 00000000000..1165b8a7139 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/admin/_content/licenses_admin.html @@ -0,0 +1,14 @@ +<fieldset> + <legend>$r.translate("menu.admin.licenses")</legend> + $r.render("licenses") + <div class="b_clearfix o_qpool_button_bar_box"> + <div class="o_qpool_button_bar"> + $r.render("create.license") + </div> + </div> +</fieldset> + + + + + diff --git a/src/main/java/org/olat/modules/qpool/ui/_content/pools_admin.html b/src/main/java/org/olat/modules/qpool/ui/admin/_content/pools_admin.html similarity index 100% rename from src/main/java/org/olat/modules/qpool/ui/_content/pools_admin.html rename to src/main/java/org/olat/modules/qpool/ui/admin/_content/pools_admin.html diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/_content/types_admin.html b/src/main/java/org/olat/modules/qpool/ui/admin/_content/types_admin.html new file mode 100644 index 00000000000..599449ee234 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/admin/_content/types_admin.html @@ -0,0 +1,14 @@ +<fieldset> + <legend>$r.translate("menu.admin.types")</legend> + $r.render("types") + <div class="b_clearfix o_qpool_button_bar_box"> + <div class="o_qpool_button_bar"> + $r.render("create.type") + </div> + </div> +</fieldset> + + + + + diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/qpool/ui/admin/_i18n/LocalStrings_de.properties new file mode 100644 index 00000000000..fc1034f6711 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/admin/_i18n/LocalStrings_de.properties @@ -0,0 +1,18 @@ +#Mon Mar 02 09:54:04 CET 2009 +level.key=ID +level.level=Level +level.translation=Ubersetzung +type.key=ID +type.type=Typ +type.translation=Ubersetzung +license.id=ID +license.key=Lizenz +delete.type=Löschen +delete.type.confirm=Wollen Sie wirklich dieser Typ löschen? +delete.level=Löschen +delete.level.confirm=Wollen Sie wirklich dieser Level löschen? +delete.license=Löschen +delete.license.confirm=Wollen Sie wirklich dieser Lizenz löschen? +create.level=Level erstellen +create.license=Lizenz erstellen +create.type=Typ erstellen \ No newline at end of file diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/qpool/ui/admin/_i18n/LocalStrings_en.properties new file mode 100644 index 00000000000..a008421f6a7 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/admin/_i18n/LocalStrings_en.properties @@ -0,0 +1,2 @@ +#Sun Jan 31 17:38:12 CET 2010 + diff --git a/src/main/java/org/olat/modules/qpool/ui/datasource/CollectionOfItemsSource.java b/src/main/java/org/olat/modules/qpool/ui/datasource/CollectionOfItemsSource.java index 1b058dfec81..904c9703a51 100644 --- a/src/main/java/org/olat/modules/qpool/ui/datasource/CollectionOfItemsSource.java +++ b/src/main/java/org/olat/modules/qpool/ui/datasource/CollectionOfItemsSource.java @@ -26,9 +26,9 @@ import org.olat.core.commons.persistence.ResultInfos; import org.olat.core.commons.persistence.SortKey; import org.olat.core.id.Identity; import org.olat.core.id.Roles; -import org.olat.modules.qpool.QuestionItemCollection; -import org.olat.modules.qpool.QuestionItemShort; import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionItemCollection; +import org.olat.modules.qpool.QuestionItemView; import org.olat.modules.qpool.model.SearchQuestionItemParams; import org.olat.modules.qpool.ui.QuestionItemsSource; @@ -58,7 +58,7 @@ public class CollectionOfItemsSource implements QuestionItemsSource { } @Override - public ResultInfos<QuestionItemShort> getItems(String query, List<String> condQueries, int firstResult, int maxResults, SortKey... orderBy) { + public ResultInfos<QuestionItemView> getItems(String query, List<String> condQueries, int firstResult, int maxResults, SortKey... orderBy) { SearchQuestionItemParams params = new SearchQuestionItemParams(identity, roles); params.setSearchString(query); return qpoolService.getItemsOfCollection(collection, params, firstResult, maxResults); diff --git a/src/main/java/org/olat/modules/qpool/ui/datasource/MarkedItemsSource.java b/src/main/java/org/olat/modules/qpool/ui/datasource/MarkedItemsSource.java index ed4a780014f..0f1ae06eafe 100644 --- a/src/main/java/org/olat/modules/qpool/ui/datasource/MarkedItemsSource.java +++ b/src/main/java/org/olat/modules/qpool/ui/datasource/MarkedItemsSource.java @@ -26,8 +26,8 @@ import org.olat.core.commons.persistence.ResultInfos; import org.olat.core.commons.persistence.SortKey; import org.olat.core.id.Identity; import org.olat.core.id.Roles; -import org.olat.modules.qpool.QuestionItemShort; import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionItemView; import org.olat.modules.qpool.model.SearchQuestionItemParams; import org.olat.modules.qpool.ui.QuestionItemsSource; @@ -55,9 +55,9 @@ public class MarkedItemsSource implements QuestionItemsSource { } @Override - public ResultInfos<QuestionItemShort> getItems(String query, List<String> condQueries, int firstResult, int maxResults, SortKey... orderBy) { + public ResultInfos<QuestionItemView> getItems(String query, List<String> condQueries, int firstResult, int maxResults, SortKey... orderBy) { SearchQuestionItemParams params = new SearchQuestionItemParams(me, roles); params.setSearchString(query); - return qpoolService.getFavoritItems(me, params, firstResult, maxResults); + return qpoolService.getFavoritItems(me, params, firstResult, maxResults, orderBy); } } diff --git a/src/main/java/org/olat/modules/qpool/ui/datasource/MyQuestionItemsSource.java b/src/main/java/org/olat/modules/qpool/ui/datasource/MyQuestionItemsSource.java index e8969d31280..5d0248f113b 100644 --- a/src/main/java/org/olat/modules/qpool/ui/datasource/MyQuestionItemsSource.java +++ b/src/main/java/org/olat/modules/qpool/ui/datasource/MyQuestionItemsSource.java @@ -26,8 +26,8 @@ import org.olat.core.commons.persistence.ResultInfos; import org.olat.core.commons.persistence.SortKey; import org.olat.core.id.Identity; import org.olat.core.id.Roles; -import org.olat.modules.qpool.QuestionItemShort; import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionItemView; import org.olat.modules.qpool.model.SearchQuestionItemParams; import org.olat.modules.qpool.ui.QuestionItemsSource; @@ -55,9 +55,9 @@ public class MyQuestionItemsSource implements QuestionItemsSource { } @Override - public ResultInfos<QuestionItemShort> getItems(String query, List<String> condQueries, int firstResult, int maxResults, SortKey... orderBy) { + public ResultInfos<QuestionItemView> getItems(String query, List<String> condQueries, int firstResult, int maxResults, SortKey... orderBy) { SearchQuestionItemParams params = new SearchQuestionItemParams(me, roles); params.setSearchString(query); - return qpoolService.getItems(me, params, firstResult, maxResults); + return qpoolService.getItems(me, params, firstResult, maxResults, orderBy); } } diff --git a/src/main/java/org/olat/modules/qpool/ui/datasource/PooledItemsSource.java b/src/main/java/org/olat/modules/qpool/ui/datasource/PooledItemsSource.java index 36cd6bb9fff..5b646e9935b 100644 --- a/src/main/java/org/olat/modules/qpool/ui/datasource/PooledItemsSource.java +++ b/src/main/java/org/olat/modules/qpool/ui/datasource/PooledItemsSource.java @@ -27,8 +27,8 @@ import org.olat.core.commons.persistence.SortKey; import org.olat.core.id.Identity; import org.olat.core.id.Roles; import org.olat.modules.qpool.Pool; -import org.olat.modules.qpool.QuestionItemShort; import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionItemView; import org.olat.modules.qpool.model.SearchQuestionItemParams; import org.olat.modules.qpool.ui.QuestionItemsSource; @@ -58,7 +58,7 @@ public class PooledItemsSource implements QuestionItemsSource { } @Override - public ResultInfos<QuestionItemShort> getItems(String query, List<String> condQueries, int firstResult, int maxResults, SortKey... orderBy) { + public ResultInfos<QuestionItemView> getItems(String query, List<String> condQueries, int firstResult, int maxResults, SortKey... orderBy) { SearchQuestionItemParams params = new SearchQuestionItemParams(identity, roles); params.setSearchString(query); return qpoolService.getItemsOfPool(pool, params, firstResult, maxResults, orderBy); diff --git a/src/main/java/org/olat/modules/qpool/ui/datasource/SharedItemsSource.java b/src/main/java/org/olat/modules/qpool/ui/datasource/SharedItemsSource.java index 883da2eebc8..2b5a14b12b1 100644 --- a/src/main/java/org/olat/modules/qpool/ui/datasource/SharedItemsSource.java +++ b/src/main/java/org/olat/modules/qpool/ui/datasource/SharedItemsSource.java @@ -27,8 +27,8 @@ import org.olat.core.commons.persistence.SortKey; import org.olat.core.id.Identity; import org.olat.core.id.Roles; import org.olat.group.BusinessGroup; -import org.olat.modules.qpool.QuestionItemShort; import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionItemView; import org.olat.modules.qpool.model.SearchQuestionItemParams; import org.olat.modules.qpool.ui.QuestionItemsSource; import org.olat.resource.OLATResource; @@ -59,7 +59,7 @@ public class SharedItemsSource implements QuestionItemsSource { } @Override - public ResultInfos<QuestionItemShort> getItems(String query, List<String> condQueries, int firstResult, int maxResults, SortKey... orderBy) { + public ResultInfos<QuestionItemView> getItems(String query, List<String> condQueries, int firstResult, int maxResults, SortKey... orderBy) { SearchQuestionItemParams params = new SearchQuestionItemParams(identity, roles); params.setSearchString(query); return qpoolService.getSharedItemByResource(resource, params, firstResult, maxResults, orderBy); diff --git a/src/main/java/org/olat/modules/qpool/ui/edit/EducationalMetadataController.java b/src/main/java/org/olat/modules/qpool/ui/edit/EducationalMetadataController.java index 861e718a512..aab7b492d0c 100644 --- a/src/main/java/org/olat/modules/qpool/ui/edit/EducationalMetadataController.java +++ b/src/main/java/org/olat/modules/qpool/ui/edit/EducationalMetadataController.java @@ -32,8 +32,9 @@ import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.util.Util; import org.olat.modules.qpool.QuestionItem; -import org.olat.modules.qpool.ui.QPoolEvent; +import org.olat.modules.qpool.model.QEducationalContext; import org.olat.modules.qpool.ui.MetadatasController; +import org.olat.modules.qpool.ui.QPoolEvent; /** * @@ -41,15 +42,17 @@ import org.olat.modules.qpool.ui.MetadatasController; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class EducationalMetadataController extends FormBasicController { +public class EducationalMetadataController extends FormBasicController { private FormLink editLink; private StaticTextElement contextEl, learningTimeEl; + + private final boolean edit; - public EducationalMetadataController(UserRequest ureq, WindowControl wControl, QuestionItem item) { + public EducationalMetadataController(UserRequest ureq, WindowControl wControl, QuestionItem item, boolean edit) { super(ureq, wControl, "view"); setTranslator(Util.createPackageTranslator(MetadatasController.class, ureq.getLocale(), getTranslator())); - + this.edit = edit; initForm(ureq); setItem(item); } @@ -57,9 +60,10 @@ public class EducationalMetadataController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormTitle("educational"); - - editLink = uifactory.addFormLink("edit", "edit", null, formLayout, Link.BUTTON_XSMALL); - editLink.setCustomEnabledLinkCSS("b_link_left_icon b_link_edit"); + if(edit) { + editLink = uifactory.addFormLink("edit", "edit", null, formLayout, Link.BUTTON_XSMALL); + editLink.setCustomEnabledLinkCSS("b_link_left_icon b_link_edit"); + } FormLayoutContainer metaCont = FormLayoutContainer.createDefaultFormLayout("metadatas", getTranslator()); formLayout.add("metadatas", metaCont); @@ -69,8 +73,13 @@ public class EducationalMetadataController extends FormBasicController { } public void setItem(QuestionItem item) { - String context = item.getEducationalContext() == null ? "" : item.getEducationalContext(); - contextEl.setValue(context); + QEducationalContext context = item.getEducationalContext(); + if(context == null || context.getLevel() == null) { + contextEl.setValue(""); + } else { + contextEl.setValue(context.getLevel()); + } + String learningTime = item.getEducationalLearningTime() == null ? "" : item.getEducationalLearningTime(); learningTimeEl.setValue(learningTime); } diff --git a/src/main/java/org/olat/modules/qpool/ui/edit/EducationalMetadataEditController.java b/src/main/java/org/olat/modules/qpool/ui/edit/EducationalMetadataEditController.java index 16668940e38..dd94dfbca55 100644 --- a/src/main/java/org/olat/modules/qpool/ui/edit/EducationalMetadataEditController.java +++ b/src/main/java/org/olat/modules/qpool/ui/edit/EducationalMetadataEditController.java @@ -19,19 +19,24 @@ */ package org.olat.modules.qpool.ui.edit; +import java.util.List; + import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.IntegerElement; import org.olat.core.gui.components.form.flexible.elements.SingleSelection; -import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.util.Util; -import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionItem; +import org.olat.modules.qpool.manager.LOMConverter; +import org.olat.modules.qpool.model.LOMDuration; +import org.olat.modules.qpool.model.QEducationalContext; import org.olat.modules.qpool.model.QuestionItemImpl; import org.olat.modules.qpool.ui.MetadatasController; @@ -44,7 +49,7 @@ import org.olat.modules.qpool.ui.MetadatasController; public class EducationalMetadataEditController extends FormBasicController { private SingleSelection contextEl; - private TextElement learningTimeDayElement, learningTimeHourElement, learningTimeMinuteElement, learningTimeSecondElement; + private IntegerElement learningTimeDayElement, learningTimeHourElement, learningTimeMinuteElement, learningTimeSecondElement; private FormLayoutContainer learningTimeContainer; private QuestionItem item; @@ -62,9 +67,16 @@ public class EducationalMetadataEditController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormTitle("educational"); - - String[] contextKeys = new String[]{ "" }; - contextEl = uifactory.addDropdownSingleselect("educational.context", "educational.context", formLayout, contextKeys, contextKeys, null); + + List<QEducationalContext> levels = qpoolService.getAllEducationlContexts(); + String[] contextKeys = new String[ levels.size() ]; + String[] contextValues = new String[ levels.size() ]; + int count = 0; + for(QEducationalContext level:levels) { + contextKeys[count] = level.getLevel(); + contextValues[count++] = "item.level." + level.getLevel().toLowerCase(); + } + contextEl = uifactory.addDropdownSingleselect("educational.context", "educational.context", formLayout, contextKeys, contextValues, null); //learningTimeEl = uifactory.addTextElement("educational.learningTime", "educational.learningTime", 1000, "", formLayout); @@ -74,24 +86,20 @@ public class EducationalMetadataEditController extends FormBasicController { learningTimeContainer.setLabel("educational.learningTime", null); formLayout.add(learningTimeContainer); - String day = "d"; - String hour = "h"; - String minute = "m"; - String second = "s"; - - learningTimeDayElement = uifactory.addTextElement("learningTime.day", "", 2, day, learningTimeContainer); + LOMDuration duration = LOMConverter.convertDuration(item.getEducationalLearningTime()); + learningTimeDayElement = uifactory.addIntegerElement("learningTime.day", "", duration.getDay(), learningTimeContainer); learningTimeDayElement.setDisplaySize(3); learningTimeDayElement.setMandatory(true); - learningTimeHourElement = uifactory.addTextElement("learningTime.hour", "", 2, hour, learningTimeContainer); + learningTimeHourElement = uifactory.addIntegerElement("learningTime.hour", "", duration.getHour(), learningTimeContainer); learningTimeHourElement.setDisplaySize(3); learningTimeHourElement.setMandatory(true); - learningTimeMinuteElement = uifactory.addTextElement("learningTime.minute", "", 2, minute, learningTimeContainer); + learningTimeMinuteElement = uifactory.addIntegerElement("learningTime.minute", "", duration.getMinute(), learningTimeContainer); learningTimeMinuteElement.setDisplaySize(3); learningTimeMinuteElement.setMandatory(true); - learningTimeSecondElement = uifactory.addTextElement("learningTime.second", "", 2, second, learningTimeContainer); + learningTimeSecondElement = uifactory.addIntegerElement("learningTime.second", "", duration.getSeconds(), learningTimeContainer); learningTimeSecondElement.setDisplaySize(3); learningTimeSecondElement.setMandatory(true); @@ -117,12 +125,18 @@ public class EducationalMetadataEditController extends FormBasicController { if(item instanceof QuestionItemImpl) { QuestionItemImpl itemImpl = (QuestionItemImpl)item; if(contextEl.isOneSelected()) { - itemImpl.setEducationalContext(contextEl.getSelectedKey()); + QEducationalContext context = qpoolService.getEducationlContextByLevel(contextEl.getSelectedKey()); + itemImpl.setEducationalContext(context); } else { itemImpl.setEducationalContext(null); } - //itemImpl.setEducationalLearningTime(learningTimeEl.getValue()); + int day = learningTimeDayElement.getIntValue(); + int hour = learningTimeHourElement.getIntValue(); + int minute = learningTimeMinuteElement.getIntValue(); + int seconds = learningTimeSecondElement.getIntValue(); + String timeStr = LOMConverter.convertDuration(day, hour, minute, seconds); + itemImpl.setEducationalLearningTime(timeStr); } item = qpoolService.updateItem(item); fireEvent(ureq, new QItemEdited(item)); diff --git a/src/main/java/org/olat/modules/qpool/ui/edit/GeneralMetadataController.java b/src/main/java/org/olat/modules/qpool/ui/edit/GeneralMetadataController.java index 333c6817606..7abc630771a 100644 --- a/src/main/java/org/olat/modules/qpool/ui/edit/GeneralMetadataController.java +++ b/src/main/java/org/olat/modules/qpool/ui/edit/GeneralMetadataController.java @@ -19,7 +19,6 @@ */ package org.olat.modules.qpool.ui.edit; -import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; @@ -33,9 +32,8 @@ import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.util.Util; import org.olat.modules.qpool.QuestionItem; -import org.olat.modules.qpool.QPoolService; -import org.olat.modules.qpool.ui.QPoolEvent; import org.olat.modules.qpool.ui.MetadatasController; +import org.olat.modules.qpool.ui.QPoolEvent; /** * @@ -48,14 +46,12 @@ public class GeneralMetadataController extends FormBasicController { private FormLink editLink; private StaticTextElement keyEl, identifierEl, masterIdentifierEl, titleEl, keywordsEl, coverageEl, addInfosEl, languageEl, studyFieldEl; - private final QPoolService qpoolService; + private final boolean edit; - public GeneralMetadataController(UserRequest ureq, WindowControl wControl, QuestionItem item) { + public GeneralMetadataController(UserRequest ureq, WindowControl wControl, QuestionItem item, boolean edit) { super(ureq, wControl, "view"); setTranslator(Util.createPackageTranslator(MetadatasController.class, ureq.getLocale(), getTranslator())); - - qpoolService = CoreSpringFactory.getImpl(QPoolService.class); - + this.edit = edit; initForm(ureq); setItem(item); } @@ -63,9 +59,10 @@ public class GeneralMetadataController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormTitle("general"); - - editLink = uifactory.addFormLink("edit", "edit", null, formLayout, Link.BUTTON_XSMALL); - editLink.setCustomEnabledLinkCSS("b_link_left_icon b_link_edit"); + if(edit) { + editLink = uifactory.addFormLink("edit", "edit", null, formLayout, Link.BUTTON_XSMALL); + editLink.setCustomEnabledLinkCSS("b_link_left_icon b_link_edit"); + } FormLayoutContainer metaCont = FormLayoutContainer.createDefaultFormLayout("metadatas", getTranslator()); formLayout.add("metadatas", metaCont); @@ -100,7 +97,7 @@ public class GeneralMetadataController extends FormBasicController { addInfosEl.setValue(addInfos); String language = item.getLanguage() == null ? "" : item.getLanguage(); languageEl.setValue(language); - String studyFields = qpoolService.getTaxonomicPath(item); + String studyFields = item.getTaxonomicPath(); studyFieldEl.setValue(studyFields == null ? "" : studyFields); } diff --git a/src/main/java/org/olat/modules/qpool/ui/edit/GeneralMetadataEditController.java b/src/main/java/org/olat/modules/qpool/ui/edit/GeneralMetadataEditController.java index 0e63cd77690..e43d6fa59a6 100644 --- a/src/main/java/org/olat/modules/qpool/ui/edit/GeneralMetadataEditController.java +++ b/src/main/java/org/olat/modules/qpool/ui/edit/GeneralMetadataEditController.java @@ -21,20 +21,34 @@ package org.olat.modules.qpool.ui.edit; import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +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.FormLink; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.Form; 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.FormSubmit; +import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.components.tree.GenericTreeNode; +import org.olat.core.gui.components.tree.SelectionTree; +import org.olat.core.gui.components.tree.TreeEvent; +import org.olat.core.gui.components.tree.TreeNode; 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.generic.closablewrapper.CloseableModalController; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; -import org.olat.modules.qpool.QuestionItem; +import org.olat.core.util.tree.TreeHelper; import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionItem; +import org.olat.modules.qpool.TaxonomyLevel; import org.olat.modules.qpool.model.QuestionItemImpl; import org.olat.modules.qpool.ui.MetadatasController; +import org.olat.modules.qpool.ui.TaxonomyTreeModel; /** * @@ -43,10 +57,17 @@ import org.olat.modules.qpool.ui.MetadatasController; * */ public class GeneralMetadataEditController extends FormBasicController { - + + private FormSubmit okButton; + private FormLink selectContext; + private FormLayoutContainer selectContextCont; private TextElement titleEl, keywordsEl, coverageEl, addInfosEl, languageEl; + private SelectionTree selectPathCmp; + private CloseableModalController cmc; + private String taxonomicPath; + private TaxonomyLevel selectedTaxonomicPath; private QuestionItem item; private final QPoolService qpoolService; @@ -56,7 +77,7 @@ public class GeneralMetadataEditController extends FormBasicController { this.item = item; qpoolService = CoreSpringFactory.getImpl(QPoolService.class); - taxonomicPath = qpoolService.getTaxonomicPath(item); + taxonomicPath = item.getTaxonomicPath(); initForm(ureq); } @@ -66,7 +87,7 @@ public class GeneralMetadataEditController extends FormBasicController { this.item = item; qpoolService = CoreSpringFactory.getImpl(QPoolService.class); - taxonomicPath = qpoolService.getTaxonomicPath(item); + taxonomicPath = item.getTaxonomicPath(); initForm(ureq); } @@ -92,12 +113,19 @@ public class GeneralMetadataEditController extends FormBasicController { languageEl = uifactory.addTextElement("general.language", "general.language", 10, language, formLayout); //classification - uifactory.addStaticTextElement("classification.taxonomic.path", taxonomicPath == null ? "" : taxonomicPath, formLayout); + String txPath = taxonomicPath == null ? "" : taxonomicPath; + String selectContextPage = velocity_root + "/edit_edu_context.html"; + selectContextCont = FormLayoutContainer.createCustomFormLayout("owners", getTranslator(), selectContextPage); + selectContextCont.setLabel("classification.taxonomic.path", null); + selectContextCont.contextPut("path", txPath); + formLayout.add(selectContextCont); + selectContextCont.setRootForm(mainForm); + selectContext = uifactory.addFormLink("select", selectContextCont, Link.BUTTON_SMALL); FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); buttonsCont.setRootForm(mainForm); formLayout.add(buttonsCont); - uifactory.addFormSubmitButton("ok", "ok", buttonsCont); + okButton =uifactory.addFormSubmitButton("ok", "ok", buttonsCont); uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl()); } @@ -105,6 +133,34 @@ public class GeneralMetadataEditController extends FormBasicController { protected void doDispose() { // } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if(source == cmc) { + cleanUp(); + } + super.event(ureq, source, event); + } + + @Override + public void event(UserRequest ureq, Component source, Event event) { + if(source == selectPathCmp) { + TreeEvent te = (TreeEvent) event; + if (te.getCommand().equals(TreeEvent.COMMAND_TREENODE_CLICKED)) { + GenericTreeNode node = (GenericTreeNode)selectPathCmp.getSelectedNode(); + selectedTaxonomicPath = (TaxonomyLevel)node.getUserObject(); + selectContextCont.contextPut("path", selectedTaxonomicPath.getMaterializedPathNames()); + } + cmc.deactivate(); + cleanUp(); + } + super.event(ureq, source, event); + } + + private void cleanUp() { + removeAsListenerAndDispose(cmc); + cmc = null; + } @Override protected boolean validateFormLogic(UserRequest ureq) { @@ -132,6 +188,40 @@ public class GeneralMetadataEditController extends FormBasicController { return allOk; } + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(source == selectContext) { + okButton.getComponent().setDirty(false); + doOpenSelection(ureq); + } + super.formInnerEvent(ureq, source, event); + } + + private void doOpenSelection(UserRequest ureq) { + if(item instanceof QuestionItemImpl) { + QuestionItemImpl itemImpl = (QuestionItemImpl)item; + + selectPathCmp = new SelectionTree("taxPathSelection", getTranslator()); + selectPathCmp.addListener(this); + selectPathCmp.setMultiselect(false); + selectPathCmp.setFormButtonKey("select"); + selectPathCmp.setShowCancelButton(true); + TaxonomyTreeModel treeModel = new TaxonomyTreeModel(); + selectPathCmp.setTreeModel(treeModel); + + if(itemImpl.getTaxonomyLevel() != null || selectedTaxonomicPath != null) { + TaxonomyLevel txPath = selectedTaxonomicPath == null ? itemImpl.getTaxonomyLevel() : selectedTaxonomicPath; + TreeNode selectedNode = TreeHelper.findNodeByUserObject(txPath, treeModel.getRootNode()); + selectPathCmp.setSelectedNodeId(selectedNode.getIdent()); + } + + cmc = new CloseableModalController(getWindowControl(), translate("close"), + selectPathCmp, true, translate("classification.taxonomic.path")); + cmc.activate(); + listenTo(cmc); + } + } + @Override protected void formCancelled(UserRequest ureq) { fireEvent(ureq, Event.CANCELLED_EVENT); @@ -146,6 +236,9 @@ public class GeneralMetadataEditController extends FormBasicController { itemImpl.setCoverage(coverageEl.getValue()); itemImpl.setAdditionalInformations(addInfosEl.getValue()); itemImpl.setLanguage(languageEl.getValue()); + if(selectedTaxonomicPath != null) { + itemImpl.setTaxonomyLevel(selectedTaxonomicPath); + } } item = qpoolService.updateItem(item); fireEvent(ureq, new QItemEdited(item)); diff --git a/src/main/java/org/olat/modules/qpool/ui/edit/LifecycleMetadataController.java b/src/main/java/org/olat/modules/qpool/ui/edit/LifecycleMetadataController.java index 5eba4fa926d..3b20d6d3a95 100644 --- a/src/main/java/org/olat/modules/qpool/ui/edit/LifecycleMetadataController.java +++ b/src/main/java/org/olat/modules/qpool/ui/edit/LifecycleMetadataController.java @@ -47,10 +47,13 @@ public class LifecycleMetadataController extends FormBasicController { private FormLink editLink; private StaticTextElement versionEl, statusEl; - public LifecycleMetadataController(UserRequest ureq, WindowControl wControl, QuestionItem item) { + private final boolean edit; + + public LifecycleMetadataController(UserRequest ureq, WindowControl wControl, QuestionItem item, boolean edit) { super(ureq, wControl, "view"); setTranslator(Util.createPackageTranslator(MetadatasController.class, ureq.getLocale(), getTranslator())); + this.edit = edit; initForm(ureq); setItem(item); } @@ -58,9 +61,10 @@ public class LifecycleMetadataController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormTitle("lifecycle"); - - editLink = uifactory.addFormLink("edit", "edit", null, formLayout, Link.BUTTON_XSMALL); - editLink.setCustomEnabledLinkCSS("b_link_left_icon b_link_edit"); + if(edit) { + editLink = uifactory.addFormLink("edit", "edit", null, formLayout, Link.BUTTON_XSMALL); + editLink.setCustomEnabledLinkCSS("b_link_left_icon b_link_edit"); + } FormLayoutContainer metaCont = FormLayoutContainer.createDefaultFormLayout("metadatas", getTranslator()); formLayout.add("metadatas", metaCont); diff --git a/src/main/java/org/olat/modules/qpool/ui/edit/QuestionMetadataController.java b/src/main/java/org/olat/modules/qpool/ui/edit/QuestionMetadataController.java index 7134ee03716..48e68761693 100644 --- a/src/main/java/org/olat/modules/qpool/ui/edit/QuestionMetadataController.java +++ b/src/main/java/org/olat/modules/qpool/ui/edit/QuestionMetadataController.java @@ -34,6 +34,7 @@ import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.util.Util; import org.olat.modules.qpool.QuestionItem; +import org.olat.modules.qpool.model.QItemType; import org.olat.modules.qpool.ui.QPoolEvent; import org.olat.modules.qpool.ui.MetadatasController; @@ -48,10 +49,13 @@ public class QuestionMetadataController extends FormBasicController { private FormLink editLink; private StaticTextElement typeEl, difficultyEl, stdevDifficultyEl, differentiationEl, numAnswerAltEl, usageEl, assessmentTypeEl; - public QuestionMetadataController(UserRequest ureq, WindowControl wControl, QuestionItem item) { + private final boolean edit; + + public QuestionMetadataController(UserRequest ureq, WindowControl wControl, QuestionItem item, boolean edit) { super(ureq, wControl, "view"); setTranslator(Util.createPackageTranslator(MetadatasController.class, ureq.getLocale(), getTranslator())); + this.edit = edit; initForm(ureq); setItem(item); } @@ -59,8 +63,10 @@ public class QuestionMetadataController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormTitle("question"); - editLink = uifactory.addFormLink("edit", "edit", null, formLayout, Link.BUTTON_XSMALL); - editLink.setCustomEnabledLinkCSS("b_link_left_icon b_link_edit"); + if(edit) { + editLink = uifactory.addFormLink("edit", "edit", null, formLayout, Link.BUTTON_XSMALL); + editLink.setCustomEnabledLinkCSS("b_link_left_icon b_link_edit"); + } FormLayoutContainer metaCont = FormLayoutContainer.createDefaultFormLayout("metadatas", getTranslator()); formLayout.add("metadatas", metaCont); @@ -75,8 +81,13 @@ public class QuestionMetadataController extends FormBasicController { } public void setItem(QuestionItem item) { - String type = item.getType() == null ? "" : item.getType(); - typeEl.setValue(type); + QItemType type = item.getType(); + if(type == null || type.getType() == null) { + typeEl.setValue(""); + } else { + typeEl.setValue(type.getType()); + } + difficultyEl.setValue(toString(item.getDifficulty())); stdevDifficultyEl.setValue(toString(item.getStdevDifficulty())); differentiationEl.setValue(toString(item.getDifferentiation())); diff --git a/src/main/java/org/olat/modules/qpool/ui/edit/QuestionMetadataEditController.java b/src/main/java/org/olat/modules/qpool/ui/edit/QuestionMetadataEditController.java index 8b8f3abdd27..8964b9c1f59 100644 --- a/src/main/java/org/olat/modules/qpool/ui/edit/QuestionMetadataEditController.java +++ b/src/main/java/org/olat/modules/qpool/ui/edit/QuestionMetadataEditController.java @@ -20,6 +20,7 @@ package org.olat.modules.qpool.ui.edit; import java.math.BigDecimal; +import java.util.List; import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; @@ -33,8 +34,9 @@ import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; -import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionItem; +import org.olat.modules.qpool.model.QItemType; import org.olat.modules.qpool.model.QuestionItemImpl; import org.olat.modules.qpool.ui.MetadatasController; @@ -64,9 +66,16 @@ public class QuestionMetadataEditController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormTitle("question"); - - String[] typeKeys = new String[]{ "" }; - typeEl = uifactory.addDropdownSingleselect("question.type", "question.type", formLayout, typeKeys, typeKeys, null); + + List<QItemType> types = qpoolService.getAllItemTypes(); + String[] typeKeys = new String[types.size()]; + String[] typeValues = new String[types.size()]; + int count = 0; + for(QItemType type:types) { + typeKeys[count] = type.getType(); + typeValues[count++] = translate("item.type." + type.getType().toLowerCase()); + } + typeEl = uifactory.addDropdownSingleselect("question.type", "question.type", formLayout, typeKeys, typeValues, null); difficultyEl = uifactory.addTextElement("question.difficulty", "question.difficulty", 10, "", formLayout); difficultyEl.setExampleKey("question.difficulty.example", null); @@ -163,8 +172,10 @@ public class QuestionMetadataEditController extends FormBasicController { protected void formOK(UserRequest ureq) { if(item instanceof QuestionItemImpl) { QuestionItemImpl itemImpl = (QuestionItemImpl)item; - String type = typeEl.isOneSelected() ? typeEl.getSelectedKey() : null; - itemImpl.setType(type); + if(typeEl.isOneSelected()) { + String typeKey = typeEl.getSelectedKey(); + itemImpl.setType(qpoolService.getItemType(typeKey)); + } BigDecimal difficulty = toBigDecimal(difficultyEl.getValue()); itemImpl.setDifficulty(difficulty); diff --git a/src/main/java/org/olat/modules/qpool/ui/edit/RightsMetadataController.java b/src/main/java/org/olat/modules/qpool/ui/edit/RightsMetadataController.java index a33b0c553ca..e6b38aa28e5 100644 --- a/src/main/java/org/olat/modules/qpool/ui/edit/RightsMetadataController.java +++ b/src/main/java/org/olat/modules/qpool/ui/edit/RightsMetadataController.java @@ -37,10 +37,10 @@ import org.olat.core.gui.components.link.Link; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.id.Identity; -import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.modules.qpool.QPoolService; import org.olat.modules.qpool.QuestionItem; +import org.olat.modules.qpool.model.QLicense; import org.olat.modules.qpool.ui.MetadatasController; import org.olat.modules.qpool.ui.QPoolEvent; import org.olat.user.UserManager; @@ -61,12 +61,14 @@ public class RightsMetadataController extends FormBasicController { private final QPoolService qpoolService; private final UserManager userManager; - public RightsMetadataController(UserRequest ureq, WindowControl wControl, QuestionItem item) { + private final boolean edit; + + public RightsMetadataController(UserRequest ureq, WindowControl wControl, QuestionItem item, boolean edit) { super(ureq, wControl, "view"); setTranslator(Util.createPackageTranslator(MetadatasController.class, ureq.getLocale(), getTranslator())); qpoolService = CoreSpringFactory.getImpl(QPoolService.class); userManager = CoreSpringFactory.getImpl(UserManager.class); - + this.edit = edit; initForm(ureq); setItem(item); } @@ -74,9 +76,10 @@ public class RightsMetadataController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormTitle("rights"); - - editLink = uifactory.addFormLink("edit", "edit", null, formLayout, Link.BUTTON_XSMALL); - editLink.setCustomEnabledLinkCSS("b_link_left_icon b_link_edit"); + if(edit) { + editLink = uifactory.addFormLink("edit", "edit", null, formLayout, Link.BUTTON_XSMALL); + editLink.setCustomEnabledLinkCSS("b_link_left_icon b_link_edit"); + } FormLayoutContainer metaCont = FormLayoutContainer.createDefaultFormLayout("metadatas", getTranslator()); formLayout.add("metadatas", metaCont); @@ -96,11 +99,11 @@ public class RightsMetadataController extends FormBasicController { } public void setItem(QuestionItem item) { - String copyright = item.getCopyright(); - if(StringHelper.containsNonWhitespace(copyright)) { + QLicense copyright = item.getLicense(); + if(copyright != null) { copyrightEl.select("on", true); descriptionEl.setVisible(true); - descriptionEl.setValue(copyright); + descriptionEl.setValue(copyright.getLicenseKey()); } else { copyrightEl.select("on", false); descriptionEl.setVisible(false); diff --git a/src/main/java/org/olat/modules/qpool/ui/edit/RightsMetadataEditController.java b/src/main/java/org/olat/modules/qpool/ui/edit/RightsMetadataEditController.java index 27367c1433d..5ace2f438da 100644 --- a/src/main/java/org/olat/modules/qpool/ui/edit/RightsMetadataEditController.java +++ b/src/main/java/org/olat/modules/qpool/ui/edit/RightsMetadataEditController.java @@ -20,10 +20,10 @@ package org.olat.modules.qpool.ui.edit; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; +import org.jgroups.util.UUID; import org.olat.admin.securitygroup.gui.GroupController; import org.olat.admin.securitygroup.gui.IdentitiesAddEvent; import org.olat.admin.securitygroup.gui.IdentitiesRemoveEvent; @@ -49,6 +49,7 @@ import org.olat.core.util.Util; import org.olat.modules.qpool.QPoolService; import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QuestionItemShort; +import org.olat.modules.qpool.model.QLicense; import org.olat.modules.qpool.model.QuestionItemImpl; import org.olat.modules.qpool.ui.MetadatasController; import org.olat.user.UserManager; @@ -69,21 +70,11 @@ public class RightsMetadataEditController extends FormBasicController { private CloseableModalController cmc; private GroupController groupController; - + + private String[] keys; private QuestionItem item; private final UserManager userManager; private final QPoolService qpoolService; - private static final String[] keys = { - "-", - "all rights reserved", - "CC by", - "CC by-sa", - "CC by-nd", - "CC by-nc", - "CC by-nc-sa", - "CC by-nc-nd", - "freetext" - }; public RightsMetadataEditController(UserRequest ureq, WindowControl wControl, QuestionItem item) { super(ureq, wControl); @@ -108,21 +99,39 @@ public class RightsMetadataEditController extends FormBasicController { managerOwners = uifactory.addFormLink("manage.owners", formLayout, Link.BUTTON_SMALL); - String[] values = Arrays.copyOf(keys, keys.length); + + List<QLicense> licenses = qpoolService.getAllLicenses(); + keys = new String[licenses.size() + 2]; + String[] values = new String[licenses.size() + 2]; + keys[0] = "none"; values[0] = "None"; + int count = 1; + for(QLicense license:licenses) { + keys[count] = license.getLicenseKey(); + values[count++] = license.getLicenseKey(); + } + keys[keys.length - 1] = "free"; values[values.length - 1] = "Freetext"; + copyrightEl = uifactory.addDropdownSingleselect("rights.copyright", "rights.copyright", formLayout, keys, values, null); copyrightEl.addActionListener(this, FormEvent.ONCHANGE); - String copyright = item.getCopyright(); - if(!StringHelper.containsNonWhitespace(copyright)) { + String description; + QLicense copyright = item.getLicense(); + if(copyright == null) { + description = ""; copyrightEl.select(keys[0], true); } else if(isKey(copyright)) { - copyrightEl.select(copyright, true); + description = copyright.getLicenseText(); + copyrightEl.select(copyright.getLicenseKey(), true); } else { + description = copyright.getLicenseText(); copyrightEl.select(keys[keys.length - 1], true); } - String description = copyright == null ? "" : copyright; + if(description == null) { + description = ""; + } + descriptionEl = uifactory.addTextAreaElement("rights.description", "rights.description", 1000, 6, 40, true, description, formLayout); descriptionEl.setVisible(copyrightEl.getSelectedKey().equals(keys[keys.length - 1])); @@ -146,7 +155,7 @@ public class RightsMetadataEditController extends FormBasicController { authorCont.contextPut("authors", authorLinks); } - private boolean isKey(String value) { + private boolean isKey(QLicense value) { for(String key:keys) { if(key.equals(value)) { return true; @@ -232,11 +241,18 @@ public class RightsMetadataEditController extends FormBasicController { QuestionItemImpl itemImpl = (QuestionItemImpl)item; String selectedKey = copyrightEl.getSelectedKey(); if(selectedKey.equals(keys[0])) { - itemImpl.setCopyright(null); + itemImpl.setLicense(null); } else if(selectedKey.equals(keys[keys.length - 1])) { - itemImpl.setCopyright(descriptionEl.getValue()); + QLicense license = qpoolService.getLicense(selectedKey); + itemImpl.setLicense(license); + } else if (itemImpl.getLicense() != null && itemImpl.getLicense().isDeletable()) { + String licenseText = descriptionEl.getValue(); + itemImpl.getLicense().setLicenseText(licenseText); } else { - itemImpl.setCopyright(selectedKey); + String licenseText = descriptionEl.getValue(); + QLicense license = qpoolService.createLicense("perso-" + UUID.randomUUID().toString()); + license.setLicenseText(licenseText); + itemImpl.setLicense(license); } } item = qpoolService.updateItem(item); diff --git a/src/main/java/org/olat/modules/qpool/ui/edit/TechnicalMetadataController.java b/src/main/java/org/olat/modules/qpool/ui/edit/TechnicalMetadataController.java index dee4cce6234..7d18a89982e 100644 --- a/src/main/java/org/olat/modules/qpool/ui/edit/TechnicalMetadataController.java +++ b/src/main/java/org/olat/modules/qpool/ui/edit/TechnicalMetadataController.java @@ -46,11 +46,14 @@ public class TechnicalMetadataController extends FormBasicController { private FormLink editLink; private StaticTextElement editorEl, editorVersionEl, formatEl, creationDateEl, lastModifiedEl; + + private final boolean edit; - public TechnicalMetadataController(UserRequest ureq, WindowControl wControl, QuestionItem item) { + public TechnicalMetadataController(UserRequest ureq, WindowControl wControl, QuestionItem item, boolean edit) { super(ureq, wControl, "view"); setTranslator(Util.createPackageTranslator(MetadatasController.class, ureq.getLocale(), getTranslator())); + this.edit = edit; initForm(ureq); setItem(item); } @@ -58,9 +61,10 @@ public class TechnicalMetadataController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormTitle("technical"); - - editLink = uifactory.addFormLink("edit", "edit", null, formLayout, Link.BUTTON_XSMALL); - editLink.setCustomEnabledLinkCSS("b_link_left_icon b_link_edit"); + if(edit) { + editLink = uifactory.addFormLink("edit", "edit", null, formLayout, Link.BUTTON_XSMALL); + editLink.setCustomEnabledLinkCSS("b_link_left_icon b_link_edit"); + } FormLayoutContainer metaCont = FormLayoutContainer.createDefaultFormLayout("metadatas", getTranslator()); formLayout.add("metadatas", metaCont); diff --git a/src/main/java/org/olat/modules/qpool/ui/edit/_content/edit_edu_context.html b/src/main/java/org/olat/modules/qpool/ui/edit/_content/edit_edu_context.html new file mode 100644 index 00000000000..ee65e37a3a3 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/edit/_content/edit_edu_context.html @@ -0,0 +1 @@ +$path $r.render("select") \ No newline at end of file diff --git a/src/main/java/org/olat/modules/qpool/ui/edit/_content/view.html b/src/main/java/org/olat/modules/qpool/ui/edit/_content/view.html index ea005323eea..b38e689b815 100644 --- a/src/main/java/org/olat/modules/qpool/ui/edit/_content/view.html +++ b/src/main/java/org/olat/modules/qpool/ui/edit/_content/view.html @@ -1,9 +1,11 @@ <div class="b_clearfix"> <fieldset> <legend>$off_title</legend> - <div class="o_buttons_box_right"> - $r.render("edit") - </div> + #if($r.available("edit")) + <div class="o_buttons_box_right"> + $r.render("edit") + </div> + #end $r.render("metadatas") </fieldset> </div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/qpool/ui/wizard/ExportOverviewController.java b/src/main/java/org/olat/modules/qpool/ui/wizard/ExportOverviewController.java new file mode 100644 index 00000000000..c89303de609 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/wizard/ExportOverviewController.java @@ -0,0 +1,58 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.ui.wizard; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.impl.Form; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.generic.wizard.StepFormBasicController; +import org.olat.core.gui.control.generic.wizard.StepsEvent; +import org.olat.core.gui.control.generic.wizard.StepsRunContext; + +/** + * + * Initial date: 20.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class ExportOverviewController extends StepFormBasicController { + + public ExportOverviewController(UserRequest ureq, WindowControl wControl, Form rootForm, StepsRunContext runContext) { + super(ureq, wControl, rootForm, runContext, LAYOUT_DEFAULT, null); + + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + // + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void formOK(UserRequest ureq) { + fireEvent(ureq, StepsEvent.ACTIVATE_NEXT); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/qpool/ui/wizard/ExportTypeController.java b/src/main/java/org/olat/modules/qpool/ui/wizard/ExportTypeController.java new file mode 100644 index 00000000000..d278e8b59bd --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/wizard/ExportTypeController.java @@ -0,0 +1,58 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.ui.wizard; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.impl.Form; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.generic.wizard.StepFormBasicController; +import org.olat.core.gui.control.generic.wizard.StepsEvent; +import org.olat.core.gui.control.generic.wizard.StepsRunContext; + +/** + * + * Initial date: 20.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class ExportTypeController extends StepFormBasicController { + + public ExportTypeController(UserRequest ureq, WindowControl wControl, Form rootForm, StepsRunContext runContext) { + super(ureq, wControl, rootForm, runContext, LAYOUT_DEFAULT, null); + + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + // + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void formOK(UserRequest ureq) { + fireEvent(ureq, StepsEvent.ACTIVATE_NEXT); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/qpool/ui/wizard/Export_1_TypeStep.java b/src/main/java/org/olat/modules/qpool/ui/wizard/Export_1_TypeStep.java new file mode 100644 index 00000000000..38f9847e976 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/wizard/Export_1_TypeStep.java @@ -0,0 +1,61 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.ui.wizard; + +import java.util.List; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.impl.Form; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.generic.wizard.BasicStep; +import org.olat.core.gui.control.generic.wizard.PrevNextFinishConfig; +import org.olat.core.gui.control.generic.wizard.StepFormController; +import org.olat.core.gui.control.generic.wizard.StepsRunContext; +import org.olat.modules.qpool.QuestionItemShort; + +/** + * + * Initial date: 20.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class Export_1_TypeStep extends BasicStep { + + private final List<QuestionItemShort> items; + + public Export_1_TypeStep(UserRequest ureq, List<QuestionItemShort> items) { + super(ureq); + this.items = items; + setNextStep(new Export_2_OverviewStep(ureq)); + setI18nTitleAndDescr("export.type", "export.type"); + } + + @Override + public PrevNextFinishConfig getInitialPrevNextFinishConfig() { + return new PrevNextFinishConfig(false, true, false); + } + + @Override + public StepFormController getStepController(UserRequest ureq, WindowControl wControl, StepsRunContext runContext, Form form) { + runContext.put("items", items); + ExportTypeController controller = new ExportTypeController(ureq, wControl, form, runContext); + return controller; + } +} diff --git a/src/main/java/org/olat/modules/qpool/ui/wizard/Export_2_OverviewStep.java b/src/main/java/org/olat/modules/qpool/ui/wizard/Export_2_OverviewStep.java new file mode 100644 index 00000000000..ee2d247fc92 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/ui/wizard/Export_2_OverviewStep.java @@ -0,0 +1,56 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.ui.wizard; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.impl.Form; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.generic.wizard.BasicStep; +import org.olat.core.gui.control.generic.wizard.PrevNextFinishConfig; +import org.olat.core.gui.control.generic.wizard.Step; +import org.olat.core.gui.control.generic.wizard.StepFormController; +import org.olat.core.gui.control.generic.wizard.StepsRunContext; + +/** + * + * Initial date: 20.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class Export_2_OverviewStep extends BasicStep { + + + public Export_2_OverviewStep(UserRequest ureq) { + super(ureq); + setNextStep(Step.NOSTEP); + setI18nTitleAndDescr("export.overview", "export.overview"); + } + + @Override + public PrevNextFinishConfig getInitialPrevNextFinishConfig() { + return new PrevNextFinishConfig(true, false, true); + } + + @Override + public StepFormController getStepController(UserRequest ureq, WindowControl wControl, StepsRunContext runContext, Form form) { + ExportOverviewController controller = new ExportOverviewController(ureq, wControl, form, runContext); + return controller; + } +} diff --git a/src/main/java/org/olat/modules/qpool/ui/wizard/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/qpool/ui/wizard/_i18n/LocalStrings_de.properties index 07b63e8ca57..4ca1c047eab 100644 --- a/src/main/java/org/olat/modules/qpool/ui/wizard/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/qpool/ui/wizard/_i18n/LocalStrings_de.properties @@ -2,4 +2,6 @@ author.item=Authoren author.choose.title=Authoren auswählen author.confirm.title=Bestätigen -table.user.login=$org.olat.admin.user\:table.user.login \ No newline at end of file +table.user.login=$org.olat.admin.user\:table.user.login +export.type=Typ +export.overview=Overview \ No newline at end of file diff --git a/src/main/resources/database/mysql/alter_8_4_0_to_9_0_0.sql b/src/main/resources/database/mysql/alter_8_4_0_to_9_0_0.sql index 555e7e3ceb3..795b7da2157 100644 --- a/src/main/resources/database/mysql/alter_8_4_0_to_9_0_0.sql +++ b/src/main/resources/database/mysql/alter_8_4_0_to_9_0_0.sql @@ -5,6 +5,9 @@ drop table o_qp_item_collection; drop table o_qp_pool; drop table o_qp_item; drop table o_qp_taxonomy_level; +drop table o_qp_edu_context; +drop table o_qp_item_type; +drop table o_qp_license; -- question item create table if not exists o_qp_pool ( @@ -38,9 +41,9 @@ create table if not exists o_qp_item ( q_coverage varchar(1024), q_additional_informations varchar(256), q_language varchar(16), - q_educational_context varchar(128), + fk_edu_context bigint, q_educational_learningtime varchar(32), - q_type varchar(64), + fk_type bigint, q_difficulty decimal(10,9), q_stdev_difficulty decimal(10,9), q_differentiation decimal(10,9), @@ -49,7 +52,7 @@ create table if not exists o_qp_item ( q_assessment_type varchar(64), q_status varchar(32) not null, q_version varchar(50), - q_copyright varchar(2048), + fk_license bigint, q_editor varchar(256), q_editor_version varchar(256), q_format varchar(32) not null, @@ -97,6 +100,160 @@ create table if not exists o_qp_collection_2_item ( primary key (id) ); +create table if not exists o_qp_edu_context ( + id bigint not null, + creationdate datetime not null, + q_level varchar(256) not null, + q_deletable bit default 0, + primary key (id) +); + +create table if not exists o_qp_item_type ( + id bigint not null, + creationdate datetime not null, + q_type varchar(256) not null, + q_deletable bit default 0, + primary key (id) +); + +create table if not exists o_qp_license ( + id bigint not null, + creationdate datetime not null, + q_license varchar(256) not null, + q_text varchar(2048), + q_deletable bit default 0, + primary key (id) +); + + +-- views with rating +create or replace view o_qp_item_v as ( + select + item.id as item_id, + item.q_identifier as item_identifier, + item.q_master_identifier as item_master_identifier, + item.q_title as item_title, + item.q_language as item_language, + taxlevel.q_field as item_taxonomy_level, + educontext.q_level as item_edu_context, + item.q_educational_learningtime as item_educational_learningtime, + itemtype.q_type as item_type, + item.q_difficulty as item_difficulty, + item.q_stdev_difficulty as item_stdev_difficulty, + item.q_differentiation as item_differentiation, + item.q_num_of_answers_alt as item_num_of_answers_alt, + item.q_usage as item_usage, + item.q_status as item_status, + item.q_format as item_format, + item.creationdate as item_creationdate, + item.lastmodified as item_lastmodified, + (select avg(rating.rating) from o_userrating as rating + where rating.resid=item.id and rating.resname='QuestionItem' and rating.ressubpath is null + ) as item_rating + from o_qp_item as item + left join o_qp_taxonomy_level as taxlevel on (item.fk_taxonomy_level = taxlevel.id) + left join o_qp_item_type as itemtype on (item.fk_type = itemtype.id) + left join o_qp_edu_context as educontext on (item.fk_edu_context = educontext.id) +); + +create or replace view o_qp_item_my_v as ( + select + item.id as item_id, + ownership.identity_id as item_author, + item.q_identifier as item_identifier, + item.q_master_identifier as item_master_identifier, + item.q_title as item_title, + item.q_language as item_language, + taxlevel.q_field as item_taxonomy_level, + educontext.q_level as item_edu_context, + item.q_educational_learningtime as item_educational_learningtime, + itemtype.q_type as item_type, + item.q_difficulty as item_difficulty, + item.q_stdev_difficulty as item_stdev_difficulty, + item.q_differentiation as item_differentiation, + item.q_num_of_answers_alt as item_num_of_answers_alt, + item.q_usage as item_usage, + item.q_status as item_status, + item.q_format as item_format, + item.creationdate as item_creationdate, + item.lastmodified as item_lastmodified, + (select avg(rating.rating) from o_userrating as rating + where rating.resid=item.id and rating.resname='QuestionItem' and rating.ressubpath is null + ) as item_rating + from o_qp_item as item + inner join o_bs_secgroup as ownergroup on (ownergroup.id = item.fk_ownergroup) + inner join o_bs_membership as ownership on (ownergroup.id = ownership.secgroup_id) + left join o_qp_taxonomy_level as taxlevel on (item.fk_taxonomy_level = taxlevel.id) + left join o_qp_item_type as itemtype on (item.fk_type = itemtype.id) + left join o_qp_edu_context as educontext on (item.fk_edu_context = educontext.id) +); + +create or replace view o_qp_item_pool_v as ( + select + item.id as item_id, + pool2item.q_editable as item_editable, + pool2item.fk_pool_id as item_pool, + item.q_identifier as item_identifier, + item.q_master_identifier as item_master_identifier, + item.q_title as item_title, + item.q_language as item_language, + taxlevel.q_field as item_taxonomy_level, + educontext.q_level as item_edu_context, + item.q_educational_learningtime as item_educational_learningtime, + itemtype.q_type as item_type, + item.q_difficulty as item_difficulty, + item.q_stdev_difficulty as item_stdev_difficulty, + item.q_differentiation as item_differentiation, + item.q_num_of_answers_alt as item_num_of_answers_alt, + item.q_usage as item_usage, + item.q_status as item_status, + item.q_format as item_format, + item.creationdate as item_creationdate, + item.lastmodified as item_lastmodified, + (select avg(rating.rating) from o_userrating as rating + where rating.resid=item.id and rating.resname='QuestionItem' and rating.ressubpath is null + ) as item_rating + from o_qp_item as item + inner join o_qp_pool_2_item as pool2item on (pool2item.fk_item_id = item.id) + left join o_qp_taxonomy_level as taxlevel on (item.fk_taxonomy_level = taxlevel.id) + left join o_qp_item_type as itemtype on (item.fk_type = itemtype.id) + left join o_qp_edu_context as educontext on (item.fk_edu_context = educontext.id) +); + +create or replace view o_qp_item_shared_v as ( + select + item.id as item_id, + shareditem.q_editable as item_editable, + shareditem.fk_resource_id as item_resource_id, + item.q_identifier as item_identifier, + item.q_master_identifier as item_master_identifier, + item.q_title as item_title, + item.q_language as item_language, + taxlevel.q_field as item_taxonomy_level, + educontext.q_level as item_edu_context, + item.q_educational_learningtime as item_educational_learningtime, + itemtype.q_type as item_type, + item.q_difficulty as item_difficulty, + item.q_stdev_difficulty as item_stdev_difficulty, + item.q_differentiation as item_differentiation, + item.q_num_of_answers_alt as item_num_of_answers_alt, + item.q_usage as item_usage, + item.q_status as item_status, + item.q_format as item_format, + item.creationdate as item_creationdate, + item.lastmodified as item_lastmodified, + (select avg(rating.rating) from o_userrating as rating + where rating.resid=item.id and rating.resname='QuestionItem' and rating.ressubpath is null + ) as item_rating + from o_qp_item as item + inner join o_qp_share_item as shareditem on (shareditem.fk_item_id = item.id) + left join o_qp_taxonomy_level as taxlevel on (item.fk_taxonomy_level = taxlevel.id) + left join o_qp_item_type as itemtype on (item.fk_type = itemtype.id) + left join o_qp_edu_context as educontext on (item.fk_edu_context = educontext.id) +); + + + alter table o_qp_pool add constraint idx_qp_pool_owner_grp_id foreign key (fk_ownergroup) references o_bs_secgroup(id); @@ -116,6 +273,10 @@ alter table o_qp_collection_2_item add unique (fk_collection_id, fk_item_id); alter table o_qp_item add constraint idx_qp_pool_2_field_id foreign key (fk_taxonomy_level) references o_qp_taxonomy_level(id); alter table o_qp_item add constraint idx_qp_item_owner_id foreign key (fk_ownergroup) references o_bs_secgroup(id); -alter table o_qp_taxonomy_level add constraint idx_qp_field_2_parent_id foreign key (fk_parent_field) references o_qp_taxonomy_level(id); +alter table o_qp_item add constraint idx_qp_item_edu_ctxt_id foreign key (fk_edu_context) references o_qp_edu_context(id); +alter table o_qp_item add constraint idx_qp_item_type_id foreign key (fk_type) references o_qp_item_type(id); +alter table o_qp_item add constraint idx_qp_item_license_id foreign key (fk_license) references o_qp_license(id); +alter table o_qp_taxonomy_level add constraint idx_qp_field_2_parent_id foreign key (fk_parent_field) references o_qp_taxonomy_level(id); +alter table o_qp_item_type add unique (q_type(200)); diff --git a/src/main/resources/ehcache.xml b/src/main/resources/ehcache.xml deleted file mode 100644 index 7f7cf307dce..00000000000 --- a/src/main/resources/ehcache.xml +++ /dev/null @@ -1,129 +0,0 @@ -<ehcache updateCheck="false"> - - <!-- OLAT uses ehcache as following: - - hibernate second level cache - - hibernate query cache - - hibernate timestamp cache - - OLAT assessment property cache (PersistingAssessmentManager) - --> - - <!-- Sets the path to the directory where cache .data files are created. - - If the path is a Java System Property it is replaced by - its value in the running VM. - - The following properties are translated: - user.home - User's home directory - user.dir - User's current working directory - java.io.tmpdir - Default temp file path --> - <diskStore path="java.io.tmpdir"/> - - <!--Default Cache configuration. These will applied to caches programmatically created through - the CacheManager. - - The following attributes are required: - - maxElementsInMemory - Sets the maximum number of objects that will be created in memory - eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the - element is never expired. - overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache - has reached the maxInMemory limit. - - The following attributes are optional: - timeToIdleSeconds - Sets the time to idle for an element before it expires. - i.e. The maximum amount of time between accesses before an element expires - Is only used if the element is not eternal. - Optional attribute. A value of 0 means that an Element can idle for infinity. - The default value is 0. - timeToLiveSeconds - Sets the time to live for an element before it expires. - i.e. The maximum time between creation time and when an element expires. - Is only used if the element is not eternal. - Optional attribute. A value of 0 means that and Element can live for infinity. - The default value is 0. - diskPersistent - Whether the disk store persists between restarts of the Virtual Machine. - The default value is false. - diskExpiryThreadIntervalSeconds- The number of seconds between runs of the disk expiry thread. The default value - is 120 seconds. - --> - - <defaultCache - maxElementsInMemory="10000" - eternal="false" - timeToIdleSeconds="1800" - timeToLiveSeconds="3600" - overflowToDisk="false" - /> - - <cache name="net.sf.hibernate.cache.UpdateTimestampsCache" - maxElementsInMemory="10000" - eternal="true" - overflowToDisk="false" - /> - - <cache name="net.sf.hibernate.cache.StandardQueryCache" - maxElementsInMemory="1000" - eternal="false" - timeToIdleSeconds="1800" - timeToLiveSeconds="3600" - overflowToDisk="false" - /> - - <cache name="org.olat.core.util.cache.n.impl.svm.SingleVMCacher@org.olat.core.dispatcher.mapper.MapperService_mapper__0" - maxElementsInMemory="10000" - eternal="false" - timeToIdleSeconds="300" - timeToLiveSeconds="300" - overflowToDisk="false" - /> - - <cache name="org.olat.core.util.cache.n.impl.svm.SingleVMCacher@org.olat.modules.openmeetings.manager.OpenMeetingsManager_session__0" - maxElementsInMemory="10000" - eternal="false" - timeToIdleSeconds="900" - timeToLiveSeconds="900" - overflowToDisk="false" - /> - - <!-- - specific OLAT caches - --> - - <!-- cache RSS documents for three minutes (there is at most one per user) --> - <cache name="org.olat.commons.servlets.RSSServlet_rssdocs" - maxElementsInMemory="200" - eternal="false" - timeToIdleSeconds="0" - timeToLiveSeconds="180" - overflowToDisk="false" - /> - - - - - <!-- Sample cache named sampleCache1 - This cache contains a maximum in memory of 10000 elements, and will expire - an element if it is idle for more than 5 minutes and lives for more than - 10 minutes. - - If there are more than 10000 elements it will overflow to the - disk cache, which in this configuration will go to wherever java.io.tmp is - defined on your system. On a standard Linux system this will be /tmp" - --> - <!--cache name="my.package.Class" - maxElementsInMemory="10000" - eternal="false" - timeToIdleSeconds="300" - timeToLiveSeconds="600" - overflowToDisk="true" - /--> - - <!-- Sample cache named sampleCache2 - This cache contains 1000 elements. Elements will always be held in memory. - They are not expired. --> - <!--cache name="my.package.Class.collection" - maxElementsInMemory="1000" - eternal="true" - overflowToDisk="false" - /--> - -</ehcache> diff --git a/src/main/webapp/static/js/functions.js b/src/main/webapp/static/js/functions.js index 9e795e2d228..bd7c6eed3fc 100644 --- a/src/main/webapp/static/js/functions.js +++ b/src/main/webapp/static/js/functions.js @@ -74,7 +74,7 @@ var BLoader = { if (window.execScript) window.execScript(jsString); // IE style else window.eval(jsString); } catch(e){ - console.log(contextDesc, 'cannot execute js', jsString); + if(console) console.log(contextDesc, 'cannot execute js', jsString); if (o_info.debug) { // add webbrowser console log o_logerr('BLoader::executeGlobalJS: Error when executing JS code in contextDesc::' + contextDesc + ' error::"'+showerror(e)+' for: '+escape(jsString)); } @@ -138,7 +138,7 @@ var BLoader = { } } } catch(e){ - console.log(e); + if(console) console.log(e); if (o_info.debug) { // add webbrowser console log o_logerr('BLoader::loadCSS: Error when loading CSS from URL::' + cssURL); } @@ -441,8 +441,8 @@ function o_ainvoke(r) { try{ newc.html(hdrco);//Ext.DomHelper.overwrite(newc, hdrco, false); } catch(e) { - console.log(e); - console.log('Fragment',hdrco); + if(console) console.log(e); + if(console) console.log('Fragment',hdrco); } b_changedDomEl.push('o_c'+ciid); } @@ -535,7 +535,8 @@ function o_ainvoke(r) { jQuery(document).ooLog('debug',"stack content"+b_onDomReplacementFinished_callbacks.toSource(), "functions.js"); } - for (mycounter = 0; stacklength > mycounter; mycounter++) { + for (mycounter = 0; stacklength > mycounter; mycounter++) { + if (mycounter > 50) { if(jQuery(document).ooLog().isDebugEnabled()) { jQuery(document).ooLog('debug',"Stopped executing DOM replacement callback functions - to many functions::" + b_onDomReplacementFinished_callbacks.length, "functions.js"); @@ -557,7 +558,10 @@ function o_ainvoke(r) { if(jQuery(document).ooLog().isDebugEnabled()) jQuery(document).ooLog('debug',"Executing DOM replacement callback function #" + mycounter + " with timeout funct::" + func, "functions.js"); // don't use execScript here - must be executed outside this function scope so that dom replacement elements are available - //TODO jquery func.delay(0.01); + + //func.delay(0.01); + func();//TODO jquery + if(jQuery(document).ooLog().isDebugEnabled()) jQuery(document).ooLog('debug',"Stacksize after timeout: " + b_onDomReplacementFinished_callbacks.length, "functions.js"); } @@ -1087,19 +1091,19 @@ function b_doPrint() { * Attach event listeners to enable inline translation tool hover links */ function b_attach_i18n_inline_editing() { - return; // Add hover handler to display inline edit links - Ext.select('span.b_translation_i18nitem').hover(function(){ - Ext.get(this.firstChild).show(); + jQuery('span.b_translation_i18nitem').hover(function() { + jQuery(this.firstChild).show(); if(jQuery(document).ooLog().isDebugEnabled()) jQuery(document).ooLog('debug',"Entered i18nitem::" + this.firstChild, "functions.js:b_attach_i18n_inline_editing()"); },function(){ - Ext.select('a.b_translation_i18nitem_launcher').hide(); + jQuery('a.b_translation_i18nitem_launcher').hide(); if(jQuery(document).ooLog().isDebugEnabled()) jQuery(document).ooLog('debug',"Leaving i18nitem::" + this, "functions.js:b_attach_i18n_inline_editing()"); }); // Add highlight effect on link to show which element is affected by this link - Ext.select('a.b_translation_i18nitem_launcher').hover(function(){ - Ext.get(this).findParent('span.b_translation_i18nitem').highlight(); - },function(){}); + jQuery('a.b_translation_i18nitem_launcher').hover(function() { + var parent = jQuery(this).parent('span.b_translation_i18nitem') + parent.effect("highlight"); + }); // Add to on ajax ready callback for next execution b_AddOnDomReplacementFinishedCallback(b_attach_i18n_inline_editing); } diff --git a/src/test/java/org/olat/ims/qti/qpool/QTIExportProcessorTest.java b/src/test/java/org/olat/ims/qti/qpool/QTIExportProcessorTest.java new file mode 100644 index 00000000000..3b2f6bce075 --- /dev/null +++ b/src/test/java/org/olat/ims/qti/qpool/QTIExportProcessorTest.java @@ -0,0 +1,91 @@ +/** + * <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.qti.qpool; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Collections; +import java.util.List; + +import junit.framework.Assert; + +import org.jgroups.util.UUID; +import org.junit.Before; +import org.junit.Test; +import org.olat.core.commons.persistence.DB; +import org.olat.core.id.Identity; +import org.olat.modules.qpool.QuestionItem; +import org.olat.modules.qpool.QuestionItemFull; +import org.olat.modules.qpool.manager.FileStorage; +import org.olat.modules.qpool.manager.QEducationalContextDAO; +import org.olat.modules.qpool.manager.QItemTypeDAO; +import org.olat.modules.qpool.manager.QuestionItemDAO; +import org.olat.test.JunitTestHelper; +import org.olat.test.OlatTestCase; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 08.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QTIExportProcessorTest extends OlatTestCase { + + private static Identity owner; + + @Autowired + private DB dbInstance; + @Autowired + private FileStorage qpoolFileStorage; + @Autowired + private QItemTypeDAO qItemTypeDao; + @Autowired + private QuestionItemDAO questionItemDao; + @Autowired + private QEducationalContextDAO qEduContextDao; + + @Before + public void setup() { + if(owner == null) { + owner = JunitTestHelper.createAndPersistIdentityAsUser("QTI-imp-owner-" + UUID.randomUUID().toString()); + } + } + + + @Test + public void testImport_QTI12_metadata() throws IOException, URISyntaxException { + //first import + URL itemUrl = QTIExportProcessorTest.class.getResource("mchc_asmimr_106.zip"); + Assert.assertNotNull(itemUrl); + File itemFile = new File(itemUrl.toURI()); + QTIImportProcessor proc = new QTIImportProcessor(owner, itemFile.getName(), itemFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage); + List<QuestionItem> items = proc.process(); + Assert.assertNotNull(items); + dbInstance.commitAndCloseSession(); + + //after export + QTIExportProcessor exportProc = new QTIExportProcessor(qpoolFileStorage); + List<QuestionItemFull> fullItems = questionItemDao.loadByIds(Collections.singletonList(items.get(0).getKey())); + exportProc.assembleTest(fullItems); + } +} \ No newline at end of file diff --git a/src/test/java/org/olat/ims/qti/qpool/QTIImportProcessorTest.java b/src/test/java/org/olat/ims/qti/qpool/QTIImportProcessorTest.java index 499515dfeb5..2bb368d2179 100644 --- a/src/test/java/org/olat/ims/qti/qpool/QTIImportProcessorTest.java +++ b/src/test/java/org/olat/ims/qti/qpool/QTIImportProcessorTest.java @@ -48,7 +48,11 @@ import org.olat.modules.qpool.QuestionItemFull; import org.olat.modules.qpool.QuestionStatus; import org.olat.modules.qpool.QuestionType; import org.olat.modules.qpool.manager.FileStorage; +import org.olat.modules.qpool.manager.QEducationalContextDAO; +import org.olat.modules.qpool.manager.QItemTypeDAO; import org.olat.modules.qpool.manager.QuestionItemDAO; +import org.olat.modules.qpool.model.QEducationalContext; +import org.olat.modules.qpool.model.QItemType; import org.olat.modules.qpool.model.QuestionItemImpl; import org.olat.test.JunitTestHelper; import org.olat.test.OlatTestCase; @@ -69,7 +73,11 @@ public class QTIImportProcessorTest extends OlatTestCase { @Autowired private FileStorage qpoolFileStorage; @Autowired + private QItemTypeDAO qItemTypeDao; + @Autowired private QuestionItemDAO questionItemDao; + @Autowired + private QEducationalContextDAO qEduContextDao; @Before public void setup() { @@ -90,7 +98,7 @@ public class QTIImportProcessorTest extends OlatTestCase { File itemFile = new File(itemUrl.toURI()); //get the document informations - QTIImportProcessor proc = new QTIImportProcessor(owner, itemFile.getName(), itemFile, questionItemDao, qpoolFileStorage); + QTIImportProcessor proc = new QTIImportProcessor(owner, itemFile.getName(), itemFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage); DocInfos docInfos = proc.getDocInfos(); Assert.assertNotNull(docInfos); Assert.assertNotNull(docInfos.getFilename()); @@ -120,7 +128,8 @@ public class QTIImportProcessorTest extends OlatTestCase { //description -> qticomment Assert.assertEquals("This is a multiple-choice example with image content. The rendering is a standard radio button style. No response processing is incorporated.", reloadItem.getDescription()); //question type - Assert.assertEquals(QuestionType.SC, reloadItem.getQuestionType()); + Assert.assertNotNull(reloadItem.getType()); + Assert.assertEquals(QuestionType.SC.name(), reloadItem.getType().getType()); //check that the file is storead VFSContainer itemDir = qpoolFileStorage.getContainer(reloadItem.getDirectory()); @@ -139,7 +148,7 @@ public class QTIImportProcessorTest extends OlatTestCase { File itemFile = new File(itemUrl.toURI()); //get the document informations - QTIImportProcessor proc = new QTIImportProcessor(owner, itemFile.getName(), itemFile, questionItemDao, qpoolFileStorage); + QTIImportProcessor proc = new QTIImportProcessor(owner, itemFile.getName(), itemFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage); List<QuestionItem> items = proc.process(); Assert.assertNotNull(items); Assert.assertEquals(1, items.size()); @@ -157,7 +166,7 @@ public class QTIImportProcessorTest extends OlatTestCase { //description -> qticomment Assert.assertEquals("This is a standard numerical fill-in-blank (integer) example. No response processing is incorporated.", reloadItem.getDescription()); //question type - Assert.assertEquals(QuestionType.FIB, reloadItem.getQuestionType()); + Assert.assertEquals(QuestionType.FIB.name(), reloadItem.getType().getType()); } /** @@ -172,7 +181,7 @@ public class QTIImportProcessorTest extends OlatTestCase { File testFile = new File(testUrl.toURI()); //get the document informations - QTIImportProcessor proc = new QTIImportProcessor(owner, testFile.getName(), testFile, questionItemDao, qpoolFileStorage); + QTIImportProcessor proc = new QTIImportProcessor(owner, testFile.getName(), testFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage); DocInfos docInfos = proc.getDocInfos(); Assert.assertNotNull(docInfos); Assert.assertNotNull(docInfos.getFilename()); @@ -192,7 +201,7 @@ public class QTIImportProcessorTest extends OlatTestCase { File itemFile = new File(itemUrl.toURI()); //get the document informations - QTIImportProcessor proc = new QTIImportProcessor(owner, itemFile.getName(), itemFile, questionItemDao, qpoolFileStorage); + QTIImportProcessor proc = new QTIImportProcessor(owner, itemFile.getName(), itemFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage); List<QuestionItem> items = proc.process(); Assert.assertNotNull(items); Assert.assertEquals(4, items.size()); @@ -206,7 +215,9 @@ public class QTIImportProcessorTest extends OlatTestCase { for(QuestionItem item:items) { Assert.assertEquals(QTIConstants.QTI_12_FORMAT, item.getFormat()); - QuestionType type = item.getQuestionType(); + QItemType itemType = item.getType(); + Assert.assertNotNull(itemType); + QuestionType type = QuestionType.valueOf(itemType.getType()); if(type != null) { switch(type) { case SC: sc++; break; @@ -252,7 +263,7 @@ public class QTIImportProcessorTest extends OlatTestCase { File itemFile = new File(itemUrl.toURI()); //get the document informations - QTIImportProcessor proc = new QTIImportProcessor(owner, itemFile.getName(), itemFile, questionItemDao, qpoolFileStorage); + QTIImportProcessor proc = new QTIImportProcessor(owner, itemFile.getName(), itemFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage); List<QuestionItem> items = proc.process(); Assert.assertNotNull(items); Assert.assertEquals(2, items.size()); @@ -277,11 +288,11 @@ public class QTIImportProcessorTest extends OlatTestCase { Assert.assertNotNull(itemNode); //check the attachments - if(itemFull.getQuestionType() == QuestionType.SC) { + if(itemFull.getType().getType().equals(QuestionType.SC.name())) { Assert.assertTrue(exists(itemFull, "media/image1.gif")); Assert.assertTrue(exists(itemFull, "media/image2.gif")); Assert.assertFalse(exists(itemFull, "media/image3.gif")); - } else if(itemFull.getQuestionType() == QuestionType.MC) { + } else if(itemFull.getType().getType().equals(QuestionType.MC.name())) { Assert.assertFalse(exists(itemFull, "media/image1.gif")); Assert.assertTrue(exists(itemFull, "media/image2.gif")); Assert.assertTrue(exists(itemFull, "media/image3.gif")); @@ -298,7 +309,7 @@ public class QTIImportProcessorTest extends OlatTestCase { File itemFile = new File(itemUrl.toURI()); //get the document informations - QTIImportProcessor proc = new QTIImportProcessor(owner, itemFile.getName(), itemFile, questionItemDao, qpoolFileStorage); + QTIImportProcessor proc = new QTIImportProcessor(owner, itemFile.getName(), itemFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage); List<QuestionItem> items = proc.process(); Assert.assertNotNull(items); Assert.assertEquals(3, items.size()); @@ -344,6 +355,30 @@ public class QTIImportProcessorTest extends OlatTestCase { } } + @Test + public void testImport_QTI12_metadata() throws IOException, URISyntaxException { + URL itemUrl = QTIImportProcessorTest.class.getResource("mchc_i_001.xml"); + Assert.assertNotNull(itemUrl); + File itemFile = new File(itemUrl.toURI()); + + //get the document informations + QTIImportProcessor proc = new QTIImportProcessor(owner, itemFile.getName(), itemFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage); + List<QuestionItem> items = proc.process(); + Assert.assertNotNull(items); + Assert.assertEquals(1, items.size()); + dbInstance.commitAndCloseSession(); + + //check metadata + QuestionItem item = items.get(0); + Assert.assertEquals("Standard Multiple Choice Item", item.getTitle()); + //qmd_levelofdifficulty + QEducationalContext level = item.getEducationalContext(); + Assert.assertNotNull(level); + Assert.assertEquals("basic", level.getLevel()); + //qmd_toolvendor + Assert.assertEquals("QTITools", item.getEditor()); + } + private boolean exists(QuestionItemFull itemFull, String path) { String dir = itemFull.getDirectory(); VFSContainer itemContainer = qpoolFileStorage.getContainer(dir); diff --git a/src/test/java/org/olat/ims/qti/qpool/mchc_i_001.xml b/src/test/java/org/olat/ims/qti/qpool/mchc_i_001.xml new file mode 100644 index 00000000000..5f03748b40a --- /dev/null +++ b/src/test/java/org/olat/ims/qti/qpool/mchc_i_001.xml @@ -0,0 +1 @@ +<?xml version = "1.0" encoding = "UTF-8" standalone = "no"?> <!DOCTYPE questestinterop SYSTEM "ims_qtiasiv1p2.dtd"> <!-- Author: Colin Smythe --> <!-- Date: 22nd January --> <!-- srosse added metadata --> <!-- Version 1.2 Compliant Example: BasicExample002a --> <questestinterop> <qticomment>This is a simple multiple choice example. The rendering is a standard radio button style. No response processing is incorporated.</qticomment> <item title = "Standard Multiple Choice Item" ident = "IMS_V01_I_mchc_i_001"> <itemmetadata> <qtimetadata> <qtimetadatafield> <fieldlabel>qmd_levelofdifficulty</fieldlabel> <fieldentry>basic</fieldentry> </qtimetadatafield> <qtimetadatafield> <fieldlabel>qmd_topic</fieldlabel> <fieldentry>qtiv1p2test</fieldentry> </qtimetadatafield> <qtimetadatafield> <fieldlabel>qmd_toolvendor</fieldlabel> <fieldentry>QTITools</fieldentry> </qtimetadatafield> </qtimetadata> </itemmetadata> <presentation label = "BasicExample002a"> <flow> <material> <mattext>Which one of the listed standards committees is responsible for developing the token ring specification ?</mattext> </material> <response_lid ident = "MCa_01" rcardinality = "Single" rtiming = "No"> <render_choice shuffle = "Yes"> <flow_label> <response_label ident = "A"> <material> <mattext>IEEE 802.3</mattext> </material> </response_label> </flow_label> <flow_label> <response_label ident = "B"> <material> <mattext>IEEE 802.5</mattext> </material> </response_label> </flow_label> <flow_label> <response_label ident = "C"> <material> <mattext>IEEE 802.6</mattext> </material> </response_label> </flow_label> <flow_label> <response_label ident = "D"> <material> <mattext>IEEE 802.11</mattext> </material> </response_label> </flow_label> <flow_label> <response_label ident = "E" rshuffle = "No"> <material> <mattext>None of the above.</mattext> </material> </response_label> </flow_label> </render_choice> </response_lid> </flow> </presentation> </item> </questestinterop> \ No newline at end of file diff --git a/src/test/java/org/olat/modules/qpool/manager/CollectionDAOTest.java b/src/test/java/org/olat/modules/qpool/manager/CollectionDAOTest.java index ed045790712..d3c9a7b2f2f 100644 --- a/src/test/java/org/olat/modules/qpool/manager/CollectionDAOTest.java +++ b/src/test/java/org/olat/modules/qpool/manager/CollectionDAOTest.java @@ -19,6 +19,7 @@ */ package org.olat.modules.qpool.manager; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -31,8 +32,9 @@ import org.olat.core.id.Identity; import org.olat.ims.qti.QTIConstants; import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QuestionItemCollection; -import org.olat.modules.qpool.QuestionItemShort; +import org.olat.modules.qpool.QuestionItemView; import org.olat.modules.qpool.QuestionType; +import org.olat.modules.qpool.model.QItemType; import org.olat.test.JunitTestHelper; import org.olat.test.OlatTestCase; import org.springframework.beans.factory.annotation.Autowired; @@ -51,6 +53,8 @@ public class CollectionDAOTest extends OlatTestCase { @Autowired private CollectionDAO collectionDao; @Autowired + private QItemTypeDAO qItemTypeDao; + @Autowired private QuestionItemDAO questionDao; @Test @@ -80,9 +84,10 @@ public class CollectionDAOTest extends OlatTestCase { @Test public void addItemToCollectionById() { + QItemType fibType = qItemTypeDao.loadByType(QuestionType.FIB.name()); Identity id = JunitTestHelper.createAndPersistIdentityAsUser("Coll-Onwer-2-" + UUID.randomUUID().toString()); QuestionItemCollection coll = collectionDao.createCollection("NGC collection 2", id); - QuestionItem item = questionDao.createAndPersist(null, "NGC 89", QTIConstants.QTI_12_FORMAT, Locale.GERMAN.getLanguage(), null, null, null, QuestionType.FIB); + QuestionItem item = questionDao.createAndPersist(null, "NGC 89", QTIConstants.QTI_12_FORMAT, Locale.GERMAN.getLanguage(), null, null, null, fibType); dbInstance.commitAndCloseSession(); //add the item to the collection @@ -93,38 +98,44 @@ public class CollectionDAOTest extends OlatTestCase { @Test public void getItemsOfCollection() { //create a collection with 2 items + QItemType fibType = qItemTypeDao.loadByType(QuestionType.FIB.name()); Identity id = JunitTestHelper.createAndPersistIdentityAsUser("Coll-Onwer-3-" + UUID.randomUUID().toString()); QuestionItemCollection coll = collectionDao.createCollection("NGC collection 3", id); - QuestionItem item1 = questionDao.createAndPersist(null, "NGC 92", QTIConstants.QTI_12_FORMAT, Locale.GERMAN.getLanguage(), null, null, null, QuestionType.FIB); - QuestionItem item2 = questionDao.createAndPersist(null, "NGC 97", QTIConstants.QTI_12_FORMAT, Locale.GERMAN.getLanguage(), null, null, null, QuestionType.FIB); + QuestionItem item1 = questionDao.createAndPersist(null, "NGC 92", QTIConstants.QTI_12_FORMAT, Locale.GERMAN.getLanguage(), null, null, null, fibType); + QuestionItem item2 = questionDao.createAndPersist(null, "NGC 97", QTIConstants.QTI_12_FORMAT, Locale.GERMAN.getLanguage(), null, null, null, fibType); collectionDao.addItemToCollection(item1.getKey(), coll); collectionDao.addItemToCollection(item2.getKey(), coll); dbInstance.commit();//check if it's alright //load the items of the collection - List<QuestionItemShort> items = collectionDao.getItemsOfCollection(coll, null, 0, -1); + List<QuestionItemView> items = collectionDao.getItemsOfCollection(coll, null, 0, -1); + List<Long> itemKeys = new ArrayList<Long>(); + for(QuestionItemView item:items) { + itemKeys.add(item.getKey()); + } Assert.assertNotNull(items); Assert.assertEquals(2, items.size()); - Assert.assertTrue(items.contains(item1)); - Assert.assertTrue(items.contains(item2)); + Assert.assertTrue(itemKeys.contains(item1.getKey())); + Assert.assertTrue(itemKeys.contains(item2.getKey())); //count them int numOfItems = collectionDao.countItemsOfCollection(coll); Assert.assertEquals(2, numOfItems); //load limit sub set - List<QuestionItemShort> limitedItems = collectionDao.getItemsOfCollection(coll, Collections.singletonList(item1.getKey()), 0, -1); + List<QuestionItemView> limitedItems = collectionDao.getItemsOfCollection(coll, Collections.singletonList(item1.getKey()), 0, -1); Assert.assertNotNull(limitedItems); Assert.assertEquals(1, limitedItems.size()); - Assert.assertTrue(limitedItems.contains(item1)); + Assert.assertEquals(item1.getKey(), limitedItems.get(0).getKey()); } @Test public void getItemKeysOfCollection() { //create a collection with 2 items + QItemType fibType = qItemTypeDao.loadByType(QuestionType.FIB.name()); Identity id = JunitTestHelper.createAndPersistIdentityAsUser("Coll-Onwer-4-" + UUID.randomUUID().toString()); QuestionItemCollection coll = collectionDao.createCollection("NGC collection 4", id); - QuestionItem item1 = questionDao.createAndPersist(null, "NGC 99", QTIConstants.QTI_12_FORMAT, Locale.GERMAN.getLanguage(), null, null, null, QuestionType.FIB); - QuestionItem item2 = questionDao.createAndPersist(null, "NGC 101", QTIConstants.QTI_12_FORMAT, Locale.GERMAN.getLanguage(), null, null, null, QuestionType.FIB); + QuestionItem item1 = questionDao.createAndPersist(null, "NGC 99", QTIConstants.QTI_12_FORMAT, Locale.GERMAN.getLanguage(), null, null, null, fibType); + QuestionItem item2 = questionDao.createAndPersist(null, "NGC 101", QTIConstants.QTI_12_FORMAT, Locale.GERMAN.getLanguage(), null, null, null, fibType); collectionDao.addItemToCollection(item1.getKey(), coll); collectionDao.addItemToCollection(item2.getKey(), coll); dbInstance.commit();//check if it's alright diff --git a/src/test/java/org/olat/modules/qpool/manager/LOMConverterTest.java b/src/test/java/org/olat/modules/qpool/manager/LOMConverterTest.java index 77b78c8a66d..767bee52b65 100644 --- a/src/test/java/org/olat/modules/qpool/manager/LOMConverterTest.java +++ b/src/test/java/org/olat/modules/qpool/manager/LOMConverterTest.java @@ -25,7 +25,10 @@ import java.net.URISyntaxException; import javax.xml.bind.JAXBException; +import junit.framework.Assert; + import org.junit.Test; +import org.olat.modules.qpool.model.LOMDuration; import org.olat.modules.qpool.model.QuestionItemImpl; /** @@ -49,4 +52,47 @@ public class LOMConverterTest { out.close(); System.out.println("LOM: " + new String(out.toByteArray())); } -} + + + @Test + public void convertDuration_toString() + throws IOException, URISyntaxException, JAXBException { + //1h 30m + String duration1 = LOMConverter.convertDuration(0, 1, 30, 0); + Assert.assertEquals("PT1H30M", duration1); + //1m 45s + String duration2 = LOMConverter.convertDuration(0, 0, 1, 45); + Assert.assertEquals("PT1M45S", duration2); + } + + @Test + public void convertDuration_toDuration() + throws IOException, URISyntaxException, JAXBException { + //1h 30m + LOMDuration duration1 = LOMConverter.convertDuration("PT1H30M"); + Assert.assertEquals(0, duration1.getYear()); + Assert.assertEquals(0, duration1.getMonth()); + Assert.assertEquals(0, duration1.getDay()); + Assert.assertEquals(1, duration1.getHour()); + Assert.assertEquals(30, duration1.getMinute()); + Assert.assertEquals(0, duration1.getSeconds()); + + //1m 45s + LOMDuration duration2 = LOMConverter.convertDuration("PT1M45S"); + Assert.assertEquals(0, duration2.getYear()); + Assert.assertEquals(0, duration2.getMonth()); + Assert.assertEquals(0, duration2.getDay()); + Assert.assertEquals(0, duration2.getHour()); + Assert.assertEquals(1, duration2.getMinute()); + Assert.assertEquals(45, duration2.getSeconds()); + + //2y 3 month and 4h 1minute 35s + LOMDuration duration3 = LOMConverter.convertDuration("P2Y3MT4H1M35S"); + Assert.assertEquals(2, duration3.getYear()); + Assert.assertEquals(3, duration3.getMonth()); + Assert.assertEquals(0, duration3.getDay()); + Assert.assertEquals(4, duration3.getHour()); + Assert.assertEquals(1, duration3.getMinute()); + Assert.assertEquals(35, duration3.getSeconds()); + } +} \ No newline at end of file diff --git a/src/test/java/org/olat/modules/qpool/manager/PoolDAOTest.java b/src/test/java/org/olat/modules/qpool/manager/PoolDAOTest.java index 1d58d111bbb..b759541b738 100644 --- a/src/test/java/org/olat/modules/qpool/manager/PoolDAOTest.java +++ b/src/test/java/org/olat/modules/qpool/manager/PoolDAOTest.java @@ -33,7 +33,9 @@ import org.olat.ims.qti.QTIConstants; import org.olat.modules.qpool.Pool; import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QuestionItemShort; +import org.olat.modules.qpool.QuestionItemView; import org.olat.modules.qpool.QuestionType; +import org.olat.modules.qpool.model.QItemType; import org.olat.test.JunitTestHelper; import org.olat.test.OlatTestCase; import org.springframework.beans.factory.annotation.Autowired; @@ -52,22 +54,25 @@ public class PoolDAOTest extends OlatTestCase { @Autowired private PoolDAO poolDao; @Autowired + private QItemTypeDAO qItemTypeDao; + @Autowired private QuestionItemDAO questionItemDao; @Test public void createPool() { - Pool pool = poolDao.createPool(null, "NGC"); + Pool pool = poolDao.createPool(null, "NGC", false); Assert.assertNotNull(pool); Assert.assertNotNull(pool.getKey()); Assert.assertNotNull(pool.getCreationDate()); Assert.assertEquals("NGC", pool.getName()); + Assert.assertFalse(pool.isPublicPool()); dbInstance.commitAndCloseSession(); } @Test public void createPool_withOwner() { Identity id = JunitTestHelper.createAndPersistIdentityAsUser("Pool-owner-" + UUID.randomUUID().toString()); - Pool pool = poolDao.createPool(id, "NGC owned"); + Pool pool = poolDao.createPool(id, "NGC owned", true); Assert.assertNotNull(pool); dbInstance.commitAndCloseSession(); } @@ -76,10 +81,11 @@ public class PoolDAOTest extends OlatTestCase { public void getPoolsAndGetNumOfPools() { //create a pool String name = "NGC-" + UUID.randomUUID().toString(); - Pool pool = poolDao.createPool(null, name); + Pool pool = poolDao.createPool(null, name, true); Assert.assertNotNull(pool); Assert.assertNotNull(pool.getKey()); Assert.assertEquals(name, pool.getName()); + Assert.assertTrue(pool.isPublicPool()); dbInstance.commitAndCloseSession(); //get pools @@ -100,18 +106,35 @@ public class PoolDAOTest extends OlatTestCase { dbInstance.commitAndCloseSession(); } + @Test + public void getPrivatePool() { + Identity owner = JunitTestHelper.createAndPersistIdentityAsUser("Pool-owner-" + UUID.randomUUID().toString()); + Identity quidam = JunitTestHelper.createAndPersistIdentityAsUser("Pool-quidam-" + UUID.randomUUID().toString()); + Pool pool = poolDao.createPool(owner, "Private pool", false); + dbInstance.commitAndCloseSession(); + + //owner has a private pool and public pools + List<Pool> ownerPoolList = poolDao.getPools(owner, 0, -1); + Assert.assertTrue(ownerPoolList.contains(pool)); + + //quidam has only public pools + List<Pool> quidamPoolList = poolDao.getPools(quidam, 0, -1); + Assert.assertFalse(quidamPoolList.contains(pool)); + } + @Test public void addItemToPool() { //create a pool String name = "NGC-" + UUID.randomUUID().toString(); - Pool pool = poolDao.createPool(null, name); + Pool pool = poolDao.createPool(null, name, true); Assert.assertNotNull(pool); - QuestionItem item = questionItemDao.createAndPersist(null, "Galaxy", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); + QuestionItem item = questionItemDao.createAndPersist(null, "Galaxy", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); Assert.assertNotNull(item); dbInstance.commitAndCloseSession(); //get pools - poolDao.addItemToPool(item, pool); + poolDao.addItemToPool(item, Collections.singletonList(pool), false); dbInstance.commit(); } @@ -119,16 +142,17 @@ public class PoolDAOTest extends OlatTestCase { public void getItemsOfPool() { //create a pool String name = "NGC-" + UUID.randomUUID().toString(); - Pool pool = poolDao.createPool(null, name); - QuestionItem item = questionItemDao.createAndPersist(null, "Galaxy", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); - poolDao.addItemToPool(item, pool); + Pool pool = poolDao.createPool(null, name, true); + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); + QuestionItem item = questionItemDao.createAndPersist(null, "Galaxy", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + poolDao.addItemToPool(item, Collections.singletonList(pool), false); dbInstance.commitAndCloseSession(); //retrieve - List<QuestionItemShort> items = poolDao.getItemsOfPool(pool, null, 0 , -1); + List<QuestionItemView> items = poolDao.getItemsOfPool(pool, null, 0 , -1); Assert.assertNotNull(items); Assert.assertEquals(1, items.size()); - Assert.assertTrue(items.contains(item)); + Assert.assertTrue(items.get(0).getKey().equals(item.getKey())); //count int numOfItems = poolDao.getNumOfItemsInPool(pool); Assert.assertEquals(1, numOfItems); @@ -138,11 +162,12 @@ public class PoolDAOTest extends OlatTestCase { public void getPools_ofItem() { //create a pool String name = "NGC-" + UUID.randomUUID().toString(); - Pool pool1 = poolDao.createPool(null, name); - Pool pool2 = poolDao.createPool(null, name + "-b"); - QuestionItem item = questionItemDao.createAndPersist(null, "Galaxy", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); - poolDao.addItemToPool(item, pool1); - poolDao.addItemToPool(item, pool2); + Pool pool1 = poolDao.createPool(null, name, true); + Pool pool2 = poolDao.createPool(null, name + "-b", true); + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); + QuestionItem item = questionItemDao.createAndPersist(null, "Galaxy", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + poolDao.addItemToPool(item, Collections.singletonList(pool1), false); + poolDao.addItemToPool(item, Collections.singletonList(pool2), true); dbInstance.commitAndCloseSession(); //retrieve the pools @@ -157,24 +182,22 @@ public class PoolDAOTest extends OlatTestCase { public void removeItemFromPool() { //create a pool with an item String name = "NGC-" + UUID.randomUUID().toString(); - Pool pool = poolDao.createPool(null, name); - QuestionItem item = questionItemDao.createAndPersist(null, "Galaxy", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); - poolDao.addItemToPool(item, pool); + Pool pool = poolDao.createPool(null, name, true); + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); + QuestionItem item = questionItemDao.createAndPersist(null, "Galaxy", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + poolDao.addItemToPool(item, Collections.singletonList(pool), false); dbInstance.commitAndCloseSession(); //check the pool and remove the items - List<QuestionItemShort> items = poolDao.getItemsOfPool(pool, null, 0 , -1); + List<QuestionItemView> items = poolDao.getItemsOfPool(pool, null, 0 , -1); Assert.assertEquals(1, items.size()); - List<QuestionItemShort> toDelete = Collections.singletonList(items.get(0)); + List<QuestionItemShort> toDelete = Collections.<QuestionItemShort>singletonList(items.get(0)); int count = poolDao.deleteFromPools(toDelete); Assert.assertEquals(1, count); dbInstance.commitAndCloseSession(); //check if the pool is empty - List<QuestionItemShort> emptyItems = poolDao.getItemsOfPool(pool, null, 0 , -1); + List<QuestionItemView> emptyItems = poolDao.getItemsOfPool(pool, null, 0 , -1); Assert.assertTrue(emptyItems.isEmpty()); } - - - -} +} \ No newline at end of file diff --git a/src/test/java/org/olat/modules/qpool/manager/QEducationalContextDAOTest.java b/src/test/java/org/olat/modules/qpool/manager/QEducationalContextDAOTest.java new file mode 100644 index 00000000000..434401bfa4d --- /dev/null +++ b/src/test/java/org/olat/modules/qpool/manager/QEducationalContextDAOTest.java @@ -0,0 +1,136 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.manager; + +import java.util.List; +import java.util.UUID; + +import junit.framework.Assert; + +import org.junit.Test; +import org.olat.core.commons.persistence.DB; +import org.olat.modules.qpool.model.QEducationalContext; +import org.olat.test.OlatTestCase; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 18.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QEducationalContextDAOTest extends OlatTestCase { + + @Autowired + private DB dbInstance; + @Autowired + private QEducationalContextDAO qEduContextDao; + + @Test + public void testCreate() { + String levelStr = "lowLevel-" + UUID.randomUUID().toString(); + QEducationalContext level = qEduContextDao.create(levelStr, true); + dbInstance.commit(); + //check + Assert.assertNotNull(level); + Assert.assertNotNull(level.getKey()); + Assert.assertNotNull(level.getCreationDate()); + Assert.assertEquals(levelStr, level.getLevel()); + Assert.assertTrue(level.isDeletable()); + } + + @Test + public void testCreateAndGet() { + String levelStr = "highLevel-" + UUID.randomUUID().toString(); + QEducationalContext level = qEduContextDao.create(levelStr, true); + dbInstance.commit(); + //load it + QEducationalContext reloadedLevel = qEduContextDao.loadById(level.getKey()); + //check the values + Assert.assertNotNull(reloadedLevel); + Assert.assertEquals(level.getKey(), reloadedLevel.getKey()); + Assert.assertNotNull(reloadedLevel.getCreationDate()); + Assert.assertEquals(levelStr, reloadedLevel.getLevel()); + Assert.assertTrue(reloadedLevel.isDeletable()); + } + + @Test + public void testCreateAndGet_byLevel() { + String levelStr = "onlyLevel-" + UUID.randomUUID().toString(); + QEducationalContext level = qEduContextDao.create(levelStr, true); + dbInstance.commit(); + //load it + QEducationalContext reloadedLevel = qEduContextDao.loadByLevel(levelStr); + //check the values + Assert.assertNotNull(reloadedLevel); + Assert.assertEquals(level.getKey(), reloadedLevel.getKey()); + Assert.assertNotNull(reloadedLevel.getCreationDate()); + Assert.assertEquals(levelStr, reloadedLevel.getLevel()); + Assert.assertTrue(reloadedLevel.isDeletable()); + } + + @Test + public void testGetItemLevels() { + String levelStr = "primary-school-" + UUID.randomUUID().toString(); + QEducationalContext level = qEduContextDao.create(levelStr, true); + dbInstance.commit(); + //load it + List<QEducationalContext> allLevels = qEduContextDao.getEducationalContexts(); + //check the values + Assert.assertNotNull(allLevels); + Assert.assertTrue(allLevels.contains(level)); + } + + @Test + public void testDelete_deletable() { + String levelStr = "secondary-school-" + UUID.randomUUID().toString(); + QEducationalContext level = qEduContextDao.create(levelStr, true); + dbInstance.commitAndCloseSession(); + + //delete it + boolean deleted = qEduContextDao.delete(level); + dbInstance.commitAndCloseSession(); + Assert.assertTrue(deleted); + + //check that the type is really, really deleted + QEducationalContext reloadedLevel = qEduContextDao.loadById(level.getKey()); + Assert.assertNull(reloadedLevel); + List<QEducationalContext> allLevels = qEduContextDao.getEducationalContexts(); + Assert.assertFalse(allLevels.contains(level)); + } + + @Test + public void testDelete_notDeletable() { + String levelStr = "uni-" + UUID.randomUUID().toString(); + QEducationalContext level = qEduContextDao.create(levelStr, false); + dbInstance.commitAndCloseSession(); + + //delete it + boolean deleted = qEduContextDao.delete(level); + dbInstance.commitAndCloseSession(); + Assert.assertFalse(deleted); + + //check that the type is really, really deleted + QEducationalContext reloadedLevel = qEduContextDao.loadById(level.getKey()); + Assert.assertNotNull(reloadedLevel); + List<QEducationalContext> allLevels = qEduContextDao.getEducationalContexts(); + Assert.assertTrue(allLevels.contains(level)); + } +} \ No newline at end of file diff --git a/src/test/java/org/olat/modules/qpool/manager/QItemTypeDAOTest.java b/src/test/java/org/olat/modules/qpool/manager/QItemTypeDAOTest.java new file mode 100644 index 00000000000..e6a3f25a12c --- /dev/null +++ b/src/test/java/org/olat/modules/qpool/manager/QItemTypeDAOTest.java @@ -0,0 +1,138 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.manager; + +import java.util.List; +import java.util.UUID; + +import junit.framework.Assert; + +import org.junit.Test; +import org.olat.core.commons.persistence.DB; +import org.olat.modules.qpool.model.QItemType; +import org.olat.test.OlatTestCase; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 15.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QItemTypeDAOTest extends OlatTestCase { + + @Autowired + private DB dbInstance; + @Autowired + private QItemTypeDAO qpoolItemTypeDao; + + @Test + public void testCreate() { + String typeStr = "interessantType-" + UUID.randomUUID().toString(); + QItemType type = qpoolItemTypeDao.create(typeStr, true); + dbInstance.commit(); + //check + Assert.assertNotNull(type); + Assert.assertNotNull(type.getKey()); + Assert.assertNotNull(type.getCreationDate()); + Assert.assertNotNull(type.getType()); + //lower case always + Assert.assertEquals(typeStr.toLowerCase(), type.getType()); + Assert.assertTrue(type.isDeletable()); + } + + @Test + public void testCreateAndGet() { + String typeStr = "veryInteressantType-" + UUID.randomUUID().toString(); + QItemType type = qpoolItemTypeDao.create(typeStr, true); + dbInstance.commit(); + //load it + QItemType reloadedType = qpoolItemTypeDao.loadById(type.getKey()); + //check the values + Assert.assertNotNull(reloadedType); + Assert.assertEquals(type.getKey(), reloadedType.getKey()); + Assert.assertNotNull(reloadedType.getCreationDate()); + Assert.assertEquals(typeStr.toLowerCase(), reloadedType.getType()); + Assert.assertTrue(reloadedType.isDeletable()); + } + + @Test + public void testGetItemTypes() { + String typeStr = "cute-" + UUID.randomUUID().toString(); + QItemType type = qpoolItemTypeDao.create(typeStr, true); + dbInstance.commit(); + //load it + List<QItemType> allTypes = qpoolItemTypeDao.getItemTypes(); + //check the values + Assert.assertNotNull(allTypes); + Assert.assertTrue(allTypes.contains(type)); + } + + @Test + public void testDelete_deletable() { + String typeStr = "cute-" + UUID.randomUUID().toString(); + QItemType type = qpoolItemTypeDao.create(typeStr, true); + dbInstance.commitAndCloseSession(); + + //delete it + boolean deleted = qpoolItemTypeDao.delete(type); + dbInstance.commitAndCloseSession(); + Assert.assertTrue(deleted); + + //check that the type is really, really deleted + QItemType reloadedType = qpoolItemTypeDao.loadById(type.getKey()); + Assert.assertNull(reloadedType); + List<QItemType> allTypes = qpoolItemTypeDao.getItemTypes(); + Assert.assertFalse(allTypes.contains(type)); + } + + @Test + public void testDelete_notDeletable() { + String typeStr = "titanium-" + UUID.randomUUID().toString(); + QItemType type = qpoolItemTypeDao.create(typeStr, false); + dbInstance.commitAndCloseSession(); + + //delete it + boolean deleted = qpoolItemTypeDao.delete(type); + dbInstance.commitAndCloseSession(); + Assert.assertFalse(deleted); + + //check that the type is really, really deleted + QItemType reloadedType = qpoolItemTypeDao.loadById(type.getKey()); + Assert.assertNotNull(reloadedType); + List<QItemType> allTypes = qpoolItemTypeDao.getItemTypes(); + Assert.assertTrue(allTypes.contains(type)); + } + + /*@Test + public void testUnique() { + String typeStr = "unique-" + UUID.randomUUID().toString(); + QItemType type = qpoolItemTypeDao.create(typeStr, false); + dbInstance.commitAndCloseSession(); + Assert.assertNotNull(type); + + + //create the same as above + QItemType duplicateType = qpoolItemTypeDao.create(typeStr, true); + dbInstance.commitAndCloseSession(); + Assert.assertNull(duplicateType); + }*/ + +} \ No newline at end of file diff --git a/src/test/java/org/olat/modules/qpool/manager/QLicenseDAOTest.java b/src/test/java/org/olat/modules/qpool/manager/QLicenseDAOTest.java new file mode 100644 index 00000000000..58330c3c98b --- /dev/null +++ b/src/test/java/org/olat/modules/qpool/manager/QLicenseDAOTest.java @@ -0,0 +1,136 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.manager; + +import java.util.List; +import java.util.UUID; + +import junit.framework.Assert; + +import org.junit.Test; +import org.olat.core.commons.persistence.DB; +import org.olat.modules.qpool.model.QLicense; +import org.olat.test.OlatTestCase; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 18.03.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QLicenseDAOTest extends OlatTestCase { + + @Autowired + private DB dbInstance; + @Autowired + private QLicenseDAO qpoolLicenseDao; + + @Test + public void testCreate() { + String licenseKey = "mit-license-" + UUID.randomUUID().toString(); + QLicense license = qpoolLicenseDao.create(licenseKey, true); + dbInstance.commit(); + //check + Assert.assertNotNull(license); + Assert.assertNotNull(license.getKey()); + Assert.assertNotNull(license.getCreationDate()); + Assert.assertEquals(licenseKey, license.getLicenseKey()); + Assert.assertTrue(license.isDeletable()); + } + + @Test + public void testCreateAndGet() { + String licenseKey = "apache-license-" + UUID.randomUUID().toString(); + QLicense license = qpoolLicenseDao.create(licenseKey, true); + dbInstance.commit(); + //load it + QLicense reloadedLicense = qpoolLicenseDao.loadById(license.getKey()); + //check the values + Assert.assertNotNull(reloadedLicense); + Assert.assertEquals(license.getKey(), reloadedLicense.getKey()); + Assert.assertNotNull(reloadedLicense.getCreationDate()); + Assert.assertEquals(licenseKey, reloadedLicense.getLicenseKey()); + Assert.assertTrue(reloadedLicense.isDeletable()); + } + + @Test + public void testCreateAndGet_byLicenseKey() { + String licenseKey = "apache-license-" + UUID.randomUUID().toString(); + QLicense license = qpoolLicenseDao.create(licenseKey, true); + dbInstance.commit(); + //load it + QLicense reloadedLicense = qpoolLicenseDao.loadByLicenseKey(licenseKey); + //check the values + Assert.assertNotNull(reloadedLicense); + Assert.assertEquals(license.getKey(), reloadedLicense.getKey()); + Assert.assertNotNull(reloadedLicense.getCreationDate()); + Assert.assertEquals(licenseKey, reloadedLicense.getLicenseKey()); + Assert.assertTrue(reloadedLicense.isDeletable()); + } + + @Test + public void testGetItemLevels() { + String licenseKey = "gnu-" + UUID.randomUUID().toString(); + QLicense license = qpoolLicenseDao.create(licenseKey, true); + dbInstance.commit(); + //load it + List<QLicense> allLicenses = qpoolLicenseDao.getLicenses(); + //check the values + Assert.assertNotNull(allLicenses); + Assert.assertTrue(allLicenses.contains(license)); + } + + @Test + public void testDelete_deletable() { + String licenseKey = "gpl-" + UUID.randomUUID().toString(); + QLicense license = qpoolLicenseDao.create(licenseKey, true); + dbInstance.commitAndCloseSession(); + + //delete it + boolean deleted = qpoolLicenseDao.delete(license); + dbInstance.commitAndCloseSession(); + Assert.assertTrue(deleted); + + //check that the type is really, really deleted + QLicense reloadedLicense = qpoolLicenseDao.loadById(license.getKey()); + Assert.assertNull(reloadedLicense); + List<QLicense> licenses = qpoolLicenseDao.getLicenses(); + Assert.assertFalse(licenses.contains(license)); + } + + @Test + public void testDelete_notDeletable() { + String licenseKey = "lgpl-" + UUID.randomUUID().toString(); + QLicense license = qpoolLicenseDao.create(licenseKey, false); + dbInstance.commitAndCloseSession(); + + //delete it + boolean deleted = qpoolLicenseDao.delete(license); + dbInstance.commitAndCloseSession(); + Assert.assertFalse(deleted); + + //check that the type is really, really deleted + QLicense reloadedLicense = qpoolLicenseDao.loadById(license.getKey()); + Assert.assertNotNull(reloadedLicense); + List<QLicense> allLicenses = qpoolLicenseDao.getLicenses(); + Assert.assertTrue(allLicenses.contains(license)); + } +} \ No newline at end of file diff --git a/src/test/java/org/olat/modules/qpool/manager/QuestionDAOTest.java b/src/test/java/org/olat/modules/qpool/manager/QuestionDAOTest.java index 85b87fab0e7..1b5814633e6 100644 --- a/src/test/java/org/olat/modules/qpool/manager/QuestionDAOTest.java +++ b/src/test/java/org/olat/modules/qpool/manager/QuestionDAOTest.java @@ -37,9 +37,13 @@ import org.olat.group.manager.BusinessGroupDAO; import org.olat.ims.qti.QTIConstants; import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QuestionItemShort; +import org.olat.modules.qpool.QuestionItemView; import org.olat.modules.qpool.QuestionStatus; import org.olat.modules.qpool.QuestionType; import org.olat.modules.qpool.TaxonomyLevel; +import org.olat.modules.qpool.model.QEducationalContext; +import org.olat.modules.qpool.model.QItemType; +import org.olat.modules.qpool.model.QLicense; import org.olat.modules.qpool.model.QuestionItemImpl; import org.olat.resource.OLATResource; import org.olat.test.JunitTestHelper; @@ -61,19 +65,26 @@ public class QuestionDAOTest extends OlatTestCase { @Autowired private QuestionItemDAO questionDao; @Autowired - private MarkManager markManager; + private MarkManager markManager; + @Autowired + private QItemTypeDAO qItemTypeDao; + @Autowired + private QLicenseDAO qLicenseDao; + @Autowired + private QEducationalContextDAO qEduContextDao; @Autowired private TaxonomyLevelDAO taxonomyLevelDao; @Test public void createQuestion() { - QuestionItem item = questionDao.createAndPersist(null, "Stars", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.FIB); + QItemType fibType = qItemTypeDao.loadByType(QuestionType.FIB.name()); + QuestionItem item = questionDao.createAndPersist(null, "Stars", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, fibType); Assert.assertNotNull(item); Assert.assertNotNull(item.getKey()); Assert.assertNotNull(item.getIdentifier()); Assert.assertNotNull(item.getCreationDate()); Assert.assertNotNull(item.getLastModified()); - Assert.assertNotNull(item.getQuestionType()); + Assert.assertNotNull(item.getType()); Assert.assertNotNull(item.getQuestionStatus()); Assert.assertEquals("Stars", item.getTitle()); dbInstance.commitAndCloseSession(); @@ -81,13 +92,14 @@ public class QuestionDAOTest extends OlatTestCase { @Test public void createQuestion_withOwner() { + QItemType fibType = qItemTypeDao.loadByType(QuestionType.FIB.name()); Identity id = JunitTestHelper.createAndPersistIdentityAsUser("QOwn-1-" + UUID.randomUUID().toString()); - QuestionItem item = questionDao.createAndPersist(id, "My fav. stars", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.FIB); + QuestionItem item = questionDao.createAndPersist(id, "My fav. stars", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, fibType); Assert.assertNotNull(item); Assert.assertNotNull(item.getKey()); Assert.assertNotNull(item.getCreationDate()); Assert.assertNotNull(item.getLastModified()); - Assert.assertNotNull(item.getQuestionType()); + Assert.assertNotNull(item.getType()); Assert.assertNotNull(item.getQuestionStatus()); Assert.assertEquals("My fav. stars", item.getTitle()); dbInstance.commitAndCloseSession(); @@ -97,9 +109,14 @@ public class QuestionDAOTest extends OlatTestCase { public void copyQuestion() { // create an item and fill it TaxonomyLevel taxonomyLevel = taxonomyLevelDao.createAndPersist(null, "Tax. to copy"); + QEducationalContext eduContext = qEduContextDao.create("primary.school", true); + QLicense mitLicense = qLicenseDao.create("mit-" + UUID.randomUUID().toString(), true); + QItemType fibType = qItemTypeDao.loadByType(QuestionType.FIB.name()); + QItemType essayType = qItemTypeDao.loadByType(QuestionType.ESSAY.name()); + Identity author = JunitTestHelper.createAndPersistIdentityAsUser("QClone-1-" + UUID.randomUUID().toString()); Identity cloner = JunitTestHelper.createAndPersistIdentityAsUser("QClone-2-" + UUID.randomUUID().toString()); - QuestionItemImpl original = questionDao.createAndPersist(author, "To copy", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), taxonomyLevel, null, "root.xml", QuestionType.FIB); + QuestionItemImpl original = questionDao.createAndPersist(author, "To copy", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), taxonomyLevel, null, "root.xml", fibType); dbInstance.commit(); Assert.assertNotNull(original); Assert.assertNotNull(original.getIdentifier()); @@ -113,10 +130,10 @@ public class QuestionDAOTest extends OlatTestCase { original.setAdditionalInformations("Additional informations before copy"); original.setLanguage("en"); //educational - original.setEducationalContext("Secondary school"); + original.setEducationalContext(eduContext); original.setEducationalLearningTime("PT1H30M"); //question - original.setType(QuestionType.ESSAY.name()); + original.setType(essayType); original.setDifficulty(new BigDecimal("0.1")); original.setStdevDifficulty(new BigDecimal("0.2")); original.setDifferentiation(new BigDecimal("-0.5")); @@ -127,7 +144,7 @@ public class QuestionDAOTest extends OlatTestCase { original.setItemVersion("1.0"); original.setStatus(QuestionStatus.review.name()); //rights - original.setCopyright("MIT License"); + original.setLicense(mitLicense); //technical original.setEditor("OpenOLAT"); original.setEditorVersion("9.0a"); @@ -170,7 +187,7 @@ public class QuestionDAOTest extends OlatTestCase { Assert.assertEquals(QuestionStatus.draft.name(), clone.getStatus()); Assert.assertEquals(original.getItemVersion(), clone.getItemVersion()); //rights - Assert.assertEquals(original.getCopyright(), clone.getCopyright()); + Assert.assertEquals(original.getLicense(), clone.getLicense()); //technical Assert.assertEquals(original.getEditor(), clone.getEditor()); Assert.assertEquals(original.getEditorVersion(), clone.getEditorVersion()); @@ -179,34 +196,55 @@ public class QuestionDAOTest extends OlatTestCase { Assert.assertNotNull(clone.getLastModified()); } + @Test + public void getItems_all() { + //create an author with 2 items + QItemType fibType = qItemTypeDao.loadByType(QuestionType.FIB.name()); + Identity id = JunitTestHelper.createAndPersistIdentityAsUser("QOwn-all-" + UUID.randomUUID().toString()); + QuestionItem item = questionDao.createAndPersist(id, "NGC all", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, fibType); + dbInstance.commitAndCloseSession(); + + //retrieve all items + List<QuestionItem> items = questionDao.getAllItems(0, -1); + Assert.assertNotNull(items); + Assert.assertTrue(items.size() >= 1); + Assert.assertTrue(items.contains(item)); + } + @Test public void getItems_byAuthor() { //create an author with 2 items + QItemType fibType = qItemTypeDao.loadByType(QuestionType.FIB.name()); Identity id = JunitTestHelper.createAndPersistIdentityAsUser("QOwn-2-" + UUID.randomUUID().toString()); - QuestionItem item1 = questionDao.createAndPersist(id, "NGC 2171", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.FIB); - QuestionItem item2 = questionDao.createAndPersist(id, "NGC 2172", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.FIB); + QuestionItem item1 = questionDao.createAndPersist(id, "NGC 2171", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, fibType); + QuestionItem item2 = questionDao.createAndPersist(id, "NGC 2172", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, fibType); dbInstance.commitAndCloseSession(); //count the items of the author int numOfItems = questionDao.countItems(id); Assert.assertEquals(2, numOfItems); //retrieve the items of the author - List<QuestionItemShort> items = questionDao.getItems(id, null, 0, -1); + List<QuestionItemView> items = questionDao.getItems(id, null, 0, -1); + List<Long> itemKeys = new ArrayList<Long>(); + for(QuestionItemView item:items) { + itemKeys.add(item.getKey()); + } Assert.assertNotNull(items); Assert.assertEquals(2, items.size()); - Assert.assertTrue(items.contains(item1)); - Assert.assertTrue(items.contains(item2)); + Assert.assertTrue(itemKeys.contains(item1.getKey())); + Assert.assertTrue(itemKeys.contains(item2.getKey())); //limit the list - List<QuestionItemShort> limitedItems = questionDao.getItems(id, Collections.singletonList(item1.getKey()), 0, -1); + List<QuestionItemView> limitedItems = questionDao.getItems(id, Collections.singletonList(item1.getKey()), 0, -1); Assert.assertNotNull(limitedItems); Assert.assertEquals(1, limitedItems.size()); - Assert.assertTrue(limitedItems.contains(item1)); + Assert.assertEquals(item1.getKey(), limitedItems.get(0).getKey()); } @Test public void getNumOfQuestions() { - QuestionItem item = questionDao.createAndPersist(null, "NGC 1277", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); + QuestionItem item = questionDao.createAndPersist(null, "NGC 1277", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); Assert.assertNotNull(item); dbInstance.commitAndCloseSession(); @@ -217,36 +255,42 @@ public class QuestionDAOTest extends OlatTestCase { @Test public void getFavoritItems() { + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); Identity id = JunitTestHelper.createAndPersistIdentityAsUser("fav-item-" + UUID.randomUUID().toString()); - QuestionItem item1 = questionDao.createAndPersist(id, "NGC 55", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); - QuestionItem item2 = questionDao.createAndPersist(id, "NGC 253", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); - QuestionItem item3 = questionDao.createAndPersist(id, "NGC 292", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); + QuestionItem item1 = questionDao.createAndPersist(id, "NGC 55", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + QuestionItem item2 = questionDao.createAndPersist(id, "NGC 253", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + QuestionItem item3 = questionDao.createAndPersist(id, "NGC 292", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); markManager.setMark(item1, id, null, "[QuestionItem:" + item1 + "]"); markManager.setMark(item2, id, null, "[QuestionItem:" + item2 + "]"); dbInstance.commitAndCloseSession(); - List<QuestionItemShort> favorits = questionDao.getFavoritItems(id, null, 0, -1); + List<QuestionItemView> favorits = questionDao.getFavoritItems(id, null, 0, -1); + List<Long> favoritKeys = new ArrayList<Long>(); + for(QuestionItemView favorit:favorits) { + favoritKeys.add(favorit.getKey()); + } Assert.assertNotNull(favorits); Assert.assertEquals(2, favorits.size()); - Assert.assertTrue(favorits.contains(item1)); - Assert.assertTrue(favorits.contains(item2)); - Assert.assertFalse(favorits.contains(item3)); + Assert.assertTrue(favoritKeys.contains(item1.getKey())); + Assert.assertTrue(favoritKeys.contains(item2.getKey())); + Assert.assertFalse(favoritKeys.contains(item3.getKey())); //limit to the first favorit - List<QuestionItemShort> limitedFavorits = questionDao.getFavoritItems(id, Collections.singletonList(item1.getKey()), 0, -1); + List<QuestionItemView> limitedFavorits = questionDao.getFavoritItems(id, Collections.singletonList(item1.getKey()), 0, -1); Assert.assertNotNull(limitedFavorits); Assert.assertEquals(1, limitedFavorits.size()); - Assert.assertTrue(limitedFavorits.contains(item1)); + Assert.assertEquals(item1.getKey(), limitedFavorits.get(0).getKey()); } @Test public void getFavoritItemKeys() { + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); Identity id = JunitTestHelper.createAndPersistIdentityAsUser("fav-item-" + UUID.randomUUID().toString()); - QuestionItem item1 = questionDao.createAndPersist(id, "NGC 331", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); - QuestionItem item2 = questionDao.createAndPersist(id, "NGC 332", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); - QuestionItem item3 = questionDao.createAndPersist(id, "NGC 333", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); - markManager.setMark(item1, id, null, "[QuestionItem:" + item1 + "]"); - markManager.setMark(item2, id, null, "[QuestionItem:" + item2 + "]"); + QuestionItem item1 = questionDao.createAndPersist(id, "NGC 331", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + QuestionItem item2 = questionDao.createAndPersist(id, "NGC 332", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + QuestionItem item3 = questionDao.createAndPersist(id, "NGC 333", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + markManager.setMark(item1, id, null, "[QuestionItem:" + item1.getKey() + "]"); + markManager.setMark(item2, id, null, "[QuestionItem:" + item2.getKey() + "]"); dbInstance.commitAndCloseSession(); List<Long> favoritKeys = questionDao.getFavoritKeys(id); @@ -260,9 +304,10 @@ public class QuestionDAOTest extends OlatTestCase { @Test public void shareItems() { //create a group to share 2 items + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); BusinessGroup group = businessGroupDao.createAndPersist(null, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); - QuestionItem item1 = questionDao.createAndPersist(null, "Share-Item-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); - QuestionItem item2 = questionDao.createAndPersist(null, "Share-Item-2", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); + QuestionItem item1 = questionDao.createAndPersist(null, "Share-Item-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + QuestionItem item2 = questionDao.createAndPersist(null, "Share-Item-2", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); dbInstance.commit(); //share them @@ -270,26 +315,32 @@ public class QuestionDAOTest extends OlatTestCase { questionDao.share(item2, group.getResource()); //retrieve them - List<QuestionItemShort> sharedItems = questionDao.getSharedItemByResource(group.getResource(), null, 0, -1); + List<QuestionItemView> sharedItems = questionDao.getSharedItemByResource(group.getResource(), null, 0, -1); + List<Long> sharedItemKeys = new ArrayList<Long>(); + for(QuestionItemView sharedItem:sharedItems) { + sharedItemKeys.add(sharedItem.getKey()); + } Assert.assertNotNull(sharedItems); Assert.assertEquals(2, sharedItems.size()); - Assert.assertTrue(sharedItems.contains(item1)); - Assert.assertTrue(sharedItems.contains(item2)); + Assert.assertTrue(sharedItemKeys.contains(item1.getKey())); + Assert.assertTrue(sharedItemKeys.contains(item2.getKey())); //retrieve limited sub set - List<QuestionItemShort> limitedSharedItems = questionDao.getSharedItemByResource(group.getResource(), Collections.singletonList(item1.getKey()), 0, -1); + List<QuestionItemView> limitedSharedItems = questionDao.getSharedItemByResource(group.getResource(), Collections.singletonList(item1.getKey()), 0, -1); Assert.assertNotNull(limitedSharedItems); Assert.assertEquals(1, limitedSharedItems.size()); - Assert.assertTrue(limitedSharedItems.contains(item1)); + Assert.assertEquals(item1.getKey(), limitedSharedItems.get(0).getKey()); } @Test public void shareItems_countSharedItemByResource() { //create a group to share 2 items + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); + QItemType fibType = qItemTypeDao.loadByType(QuestionType.FIB.name()); BusinessGroup group = businessGroupDao.createAndPersist(null, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); - QuestionItem item1 = questionDao.createAndPersist(null, "Count-shared-Item-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); - QuestionItem item2 = questionDao.createAndPersist(null, "Count-shared-Item-2", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); - QuestionItem item3 = questionDao.createAndPersist(null, "Count-shared-Item-3", QTIConstants.QTI_12_FORMAT, Locale.FRENCH.getLanguage(), null, null, null, QuestionType.FIB); + QuestionItem item1 = questionDao.createAndPersist(null, "Count-shared-Item-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + QuestionItem item2 = questionDao.createAndPersist(null, "Count-shared-Item-2", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + QuestionItem item3 = questionDao.createAndPersist(null, "Count-shared-Item-3", QTIConstants.QTI_12_FORMAT, Locale.FRENCH.getLanguage(), null, null, null, fibType); dbInstance.commit(); //share them @@ -306,33 +357,35 @@ public class QuestionDAOTest extends OlatTestCase { @Test public void shareItem_resources() { //create a group to share 2 items + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); BusinessGroup group1 = businessGroupDao.createAndPersist(null, "gdao-1", "gdao-desc", -1, -1, false, false, false, false, false); BusinessGroup group2 = businessGroupDao.createAndPersist(null, "gdao-2", "gdao-desc", -1, -1, false, false, false, false, false); - QuestionItem item = questionDao.createAndPersist(null, "Share-Item-3", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); + QuestionItem item = questionDao.createAndPersist(null, "Share-Item-3", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); dbInstance.commit(); //share them List<OLATResource> resources = new ArrayList<OLATResource>(); resources.add(group1.getResource()); resources.add(group2.getResource()); - questionDao.share(item.getKey(), resources); + questionDao.share(item.getKey(), resources, false); //retrieve them - List<QuestionItemShort> sharedItems1 = questionDao.getSharedItemByResource(group1.getResource(), null, 0, -1); + List<QuestionItemView> sharedItems1 = questionDao.getSharedItemByResource(group1.getResource(), null, 0, -1); Assert.assertNotNull(sharedItems1); Assert.assertEquals(1, sharedItems1.size()); - Assert.assertTrue(sharedItems1.contains(item)); - List<QuestionItemShort> sharedItems2 = questionDao.getSharedItemByResource(group2.getResource(), null, 0, -1); + Assert.assertEquals(item.getKey(), sharedItems1.get(0).getKey()); + List<QuestionItemView> sharedItems2 = questionDao.getSharedItemByResource(group2.getResource(), null, 0, -1); Assert.assertNotNull(sharedItems2); Assert.assertEquals(1, sharedItems2.size()); - Assert.assertTrue(sharedItems2.contains(item)); + Assert.assertEquals(item.getKey(), sharedItems2.get(0).getKey()); } @Test public void shareItems_avoidDuplicates() { //create a group to share 2 items + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); BusinessGroup group = businessGroupDao.createAndPersist(null, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); - QuestionItem item = questionDao.createAndPersist(null, "Share-Item-Dup-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); + QuestionItem item = questionDao.createAndPersist(null, "Share-Item-Dup-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); dbInstance.commit(); //share them @@ -341,18 +394,19 @@ public class QuestionDAOTest extends OlatTestCase { questionDao.share(item, group.getResource()); //retrieve them - List<QuestionItemShort> sharedItems = questionDao.getSharedItemByResource(group.getResource(), null, 0, -1); + List<QuestionItemView> sharedItems = questionDao.getSharedItemByResource(group.getResource(), null, 0, -1); Assert.assertNotNull(sharedItems); Assert.assertEquals(1, sharedItems.size()); - Assert.assertTrue(sharedItems.contains(item)); + Assert.assertEquals(item.getKey(), sharedItems.get(0).getKey()); } @Test public void shareItems_businessGroups() { //create a group to share 2 items + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); Identity id = JunitTestHelper.createAndPersistIdentityAsUser("Share-item-" + UUID.randomUUID().toString()); BusinessGroup group = businessGroupDao.createAndPersist(id, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); - QuestionItem item = questionDao.createAndPersist(id, "Share-Item-Dup-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); + QuestionItem item = questionDao.createAndPersist(id, "Share-Item-Dup-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); dbInstance.commit(); //share them @@ -370,10 +424,11 @@ public class QuestionDAOTest extends OlatTestCase { @Test public void getSharedResources() { //create a group to share 2 items + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); Identity id = JunitTestHelper.createAndPersistIdentityAsUser("Share-item-" + UUID.randomUUID().toString()); BusinessGroup group1 = businessGroupDao.createAndPersist(id, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); BusinessGroup group2 = businessGroupDao.createAndPersist(id, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); - QuestionItem item = questionDao.createAndPersist(id, "Share-Item-Dup-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); + QuestionItem item = questionDao.createAndPersist(id, "Share-Item-Dup-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); dbInstance.commit(); //share them @@ -392,18 +447,19 @@ public class QuestionDAOTest extends OlatTestCase { @Test public void removeFromShare() { //create a group to share 2 items + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); Identity id = JunitTestHelper.createAndPersistIdentityAsUser("Share-rm-" + UUID.randomUUID().toString()); BusinessGroup group = businessGroupDao.createAndPersist(id, "gdrm", "gdrm-desc", -1, -1, false, false, false, false, false); - QuestionItem item = questionDao.createAndPersist(id, "Share-item-rm-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); + QuestionItem item = questionDao.createAndPersist(id, "Share-item-rm-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); dbInstance.commit(); //share them questionDao.share(item, group.getResource()); //retrieve them as a check - List<QuestionItemShort> shared = questionDao.getSharedItemByResource(group.getResource(), null, 0, -1); + List<QuestionItemView> shared = questionDao.getSharedItemByResource(group.getResource(), null, 0, -1); Assert.assertEquals(1, shared.size()); //and remove the items - List<QuestionItemShort> toDelete = Collections.singletonList((QuestionItemShort)shared.get(0)); + List<QuestionItemShort> toDelete = Collections.<QuestionItemShort>singletonList(shared.get(0)); int count = questionDao.deleteFromShares(toDelete); Assert.assertEquals(1, count); dbInstance.commit();//make sure that changes are committed diff --git a/src/test/java/org/olat/modules/qpool/manager/QuestionPoolServiceTest.java b/src/test/java/org/olat/modules/qpool/manager/QuestionPoolServiceTest.java index d57e58db357..ccc5b7a7418 100644 --- a/src/test/java/org/olat/modules/qpool/manager/QuestionPoolServiceTest.java +++ b/src/test/java/org/olat/modules/qpool/manager/QuestionPoolServiceTest.java @@ -39,11 +39,13 @@ import org.olat.core.id.Identity; import org.olat.group.BusinessGroup; import org.olat.group.manager.BusinessGroupDAO; import org.olat.ims.qti.QTIConstants; +import org.olat.modules.qpool.QPoolService; import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QuestionItemCollection; import org.olat.modules.qpool.QuestionItemShort; -import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionItemView; import org.olat.modules.qpool.QuestionType; +import org.olat.modules.qpool.model.QItemType; import org.olat.test.JunitTestHelper; import org.olat.test.OlatTestCase; import org.springframework.beans.factory.annotation.Autowired; @@ -61,6 +63,8 @@ public class QuestionPoolServiceTest extends OlatTestCase { @Autowired private BusinessGroupDAO businessGroupDao; @Autowired + private QItemTypeDAO qItemTypeDao; + @Autowired private QuestionItemDAO questionDao; @Autowired private QPoolService qpoolService; @@ -68,10 +72,11 @@ public class QuestionPoolServiceTest extends OlatTestCase { @Test public void deleteItems() { //create a group to share 2 items + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); Identity id = JunitTestHelper.createAndPersistIdentityAsUser("Share-rm-" + UUID.randomUUID().toString()); BusinessGroup group = businessGroupDao.createAndPersist(id, "gdrm", "gdrm-desc", -1, -1, false, false, false, false, false); - QuestionItem item1 = questionDao.createAndPersist(id, "Share-item-rm-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); - QuestionItem item2 = questionDao.createAndPersist(id, "Share-item-rm-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, QuestionType.MC); + QuestionItem item1 = questionDao.createAndPersist(id, "Share-item-rm-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + QuestionItem item2 = questionDao.createAndPersist(id, "Share-item-rm-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); dbInstance.commit(); //share them questionDao.share(item1, group.getResource()); @@ -94,9 +99,10 @@ public class QuestionPoolServiceTest extends OlatTestCase { @Test public void createCollection() { //create an user with 2 items + QItemType fibType = qItemTypeDao.loadByType(QuestionType.FIB.name()); Identity id = JunitTestHelper.createAndPersistIdentityAsUser("Coll-Owner-3-" + UUID.randomUUID().toString()); - QuestionItem item1 = questionDao.createAndPersist(id, "NGC 92", QTIConstants.QTI_12_FORMAT, Locale.GERMAN.getLanguage(), null, null, null, QuestionType.FIB); - QuestionItem item2 = questionDao.createAndPersist(id, "NGC 97", QTIConstants.QTI_12_FORMAT, Locale.GERMAN.getLanguage(), null, null, null, QuestionType.FIB); + QuestionItem item1 = questionDao.createAndPersist(id, "NGC 92", QTIConstants.QTI_12_FORMAT, Locale.GERMAN.getLanguage(), null, null, null, fibType); + QuestionItem item2 = questionDao.createAndPersist(id, "NGC 97", QTIConstants.QTI_12_FORMAT, Locale.GERMAN.getLanguage(), null, null, null, fibType); dbInstance.commit(); //load the items of the collection @@ -111,11 +117,15 @@ public class QuestionPoolServiceTest extends OlatTestCase { //retrieve the list of items in the collection int numOfItemsInCollection = qpoolService.countItemsOfCollection(newColl); Assert.assertEquals(2, numOfItemsInCollection); - ResultInfos<QuestionItemShort> itemsOfCollection = qpoolService.getItemsOfCollection(newColl, null, 0, -1); + ResultInfos<QuestionItemView> itemsOfCollection = qpoolService.getItemsOfCollection(newColl, null, 0, -1); Assert.assertNotNull(itemsOfCollection); Assert.assertEquals(2, itemsOfCollection.getObjects().size()); - Assert.assertTrue(itemsOfCollection.getObjects().contains(item1)); - Assert.assertTrue(itemsOfCollection.getObjects().contains(item2)); + List<Long> itemKeys = new ArrayList<Long>(); + for(QuestionItemView item:itemsOfCollection.getObjects()) { + itemKeys.add(item.getKey()); + } + Assert.assertTrue(itemKeys.contains(item1.getKey())); + Assert.assertTrue(itemKeys.contains(item2.getKey())); } @Test diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java index c77f9c52fb0..81748e3d3de 100644 --- a/src/test/java/org/olat/test/AllTestsJunit4.java +++ b/src/test/java/org/olat/test/AllTestsJunit4.java @@ -118,10 +118,16 @@ import org.junit.runners.Suite; org.olat.core.commons.persistence.DBTest.class, org.olat.modules.ims.cp.CPManagerTest.class, org.olat.modules.ims.qti.fileresource.FileResourceValidatorTest.class, + org.olat.ims.qti.qpool.QTIImportProcessorTest.class, + org.olat.ims.qti.qpool.QTIExportProcessorTest.class, org.olat.modules.webFeed.FeedManagerImplTest.class, + org.olat.modules.qpool.manager.LOMConverterTest.class, org.olat.modules.qpool.manager.QuestionDAOTest.class, org.olat.modules.qpool.manager.FileStorageTest.class, org.olat.modules.qpool.manager.CollectionDAOTest.class, + org.olat.modules.qpool.manager.QLicenseDAOTest.class, + org.olat.modules.qpool.manager.QItemTypeDAOTest.class, + org.olat.modules.qpool.manager.QEducationalContextDAOTest.class, org.olat.modules.qpool.manager.PoolDAOTest.class, org.olat.modules.qpool.manager.TaxonomyLevelDAOTest.class, org.olat.modules.qpool.manager.QuestionPoolServiceTest.class, -- GitLab