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(&quot;Not a supported image file format.&quot;);
- * 	return;
- * }
- * System.out.println(ii.getFormatName() + &quot;, &quot; + ii.getMimeType() + &quot;, &quot; + ii.getWidth() + &quot; x &quot; + ii.getHeight() + &quot; pixels, &quot;
- * 		+ ii.getBitsPerPixel() + &quot; bits per pixel, &quot; + ii.getNumberOfImages() + &quot; image(s), &quot; + ii.getNumberOfComments() + &quot; comment(s).&quot;);
- * </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 &gt;= 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", "&nbsp;&nbsp;&nbsp;&nbsp;", 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