diff --git a/src/main/java/de/bps/ims/qti/QTIResultDetailsController.java b/src/main/java/de/bps/ims/qti/QTIResultDetailsController.java
index 6e3e2c3f8336c683b5a35437e4d06042df516fe3..462c8ef8ed0623ad725ccc94f7ecfb7903942945 100644
--- a/src/main/java/de/bps/ims/qti/QTIResultDetailsController.java
+++ b/src/main/java/de/bps/ims/qti/QTIResultDetailsController.java
@@ -126,7 +126,7 @@ public class QTIResultDetailsController extends BasicController {
 
 		QTIResultManager qrm = QTIResultManager.getInstance();
 		tableModel = new QTIResultTableModel(
-				qrm.getResultSets(courseResourceableId, nodeIdent, repositoryEntry.getKey(), identity));
+				qrm.getResultSets(courseResourceableId, nodeIdent, repositoryEntry.getKey(), identity), getTranslator());
 		tableCtr.setTableDataModel(tableModel);
 		listenTo(tableCtr);
 		
diff --git a/src/main/java/org/olat/core/gui/components/table/TableDataModel.java b/src/main/java/org/olat/core/gui/components/table/TableDataModel.java
index ad4b6f53d16a5224356a4d8c1d7d0d1ce8b8e570..e6012259287a50d4f6f6321f2870a548876fae34 100644
--- a/src/main/java/org/olat/core/gui/components/table/TableDataModel.java
+++ b/src/main/java/org/olat/core/gui/components/table/TableDataModel.java
@@ -33,29 +33,29 @@ import java.util.List;
  * 
  * @author Felix Jost
  */
-public interface TableDataModel {
+public interface TableDataModel<T> {
 
 	/**
 	 * @return
 	 */
-	int getColumnCount();
+	public int getColumnCount();
 
 	/**
 	 * @return
 	 */
-	int getRowCount();
+	public int getRowCount();
 
 	/**
 	 * @param row
 	 * @param col
 	 * @return
 	 */
-	Object getValueAt(int row, int col);
+	public Object getValueAt(int row, int col);
 
-	Object getObject(int row);
+	public T getObject(int row);
 
-	void setObjects(List objects);
+	public void setObjects(List<T> objects);
 
-	Object createCopyWithEmptyList();
+	public Object createCopyWithEmptyList();
 	
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/nodes/iq/IQControllerCreatorOlat.java b/src/main/java/org/olat/course/nodes/iq/IQControllerCreatorOlat.java
index 1ae8e535a77629e4549a9dbcda65f418832264f4..6e8e6ed0d044e643ba3bb343680d8a3540447a03 100644
--- a/src/main/java/org/olat/course/nodes/iq/IQControllerCreatorOlat.java
+++ b/src/main/java/org/olat/course/nodes/iq/IQControllerCreatorOlat.java
@@ -195,7 +195,7 @@ public class IQControllerCreatorOlat implements IQControllerCreator {
 
 	public Controller createIQTestDetailsEditController(Long courseResourceableId, String ident, Identity identity,
 			RepositoryEntry referencedRepositoryEntry, String qmdEntryTypeAssess, UserRequest ureq, WindowControl wControl) {
-		return new QTIResultDetailsController(courseResourceableId, ident, identity, referencedRepositoryEntry, qmdEntryTypeAssess, ureq, wControl);
+		return new QTIResultDetailsController(ureq, wControl, courseResourceableId, ident, identity, referencedRepositoryEntry, qmdEntryTypeAssess);
 	}
 
 
diff --git a/src/main/java/org/olat/course/nodes/iq/IQRunController.java b/src/main/java/org/olat/course/nodes/iq/IQRunController.java
index b64208fd9a92f33a8ba5764e5132da9e86c07ac9..81f6d84dbef320e44d3cf3ea14fd6582eda55a57 100644
--- a/src/main/java/org/olat/course/nodes/iq/IQRunController.java
+++ b/src/main/java/org/olat/course/nodes/iq/IQRunController.java
@@ -348,10 +348,10 @@ public class IQRunController extends BasicController implements GenericEventList
 		}
 	}
 	
-	private List allChats;
 	private void checkChats (UserRequest ureq) {
+		List<?> allChats = null;
 		if (ureq != null) {
-			allChats = (List) ureq.getUserSession().getEntry("chats");
+			allChats = (List<?>)ureq.getUserSession().getEntry("chats");
 		}
 		if (allChats == null || allChats.size() == 0) {
 			startButton.setEnabled (true);
@@ -395,7 +395,6 @@ public class IQRunController extends BasicController implements GenericEventList
 				listenTo(displayController);
 				if(displayController.isClosed()) {
 					//do nothing
-					System.out.println();
 				} else  if (displayController.isReady()) {
 					// in case displayController was unable to initialize, a message was set by displayController
 					// this is the case if no more attempts or security check was unsuccessfull
@@ -508,27 +507,32 @@ public class IQRunController extends BasicController implements GenericEventList
 				else if(type.equals(AssessmentInstance.QMD_ENTRY_TYPE_SELF)){
 					am.incrementNodeAttempts(courseNode, urequest.getIdentity(), userCourseEnv);
 				}
+			} else if (event.equals(Event.DONE_EVENT)) {
+				stopAssessment(urequest, event);
+			} else if ("test_stopped".equals(event.getCommand())) {
+				stopAssessment(urequest, event);
+				showWarning("error.assessment.stopped");
 			}
-			else if (event.equals(Event.DONE_EVENT)) {
-				if(displayContainerController != null) {
-					displayContainerController.deactivate(urequest);
-				} else {
-					getWindowControl().pop();
-				}	
-				removeHistory(urequest);
-				OLATResourceable ores = OresHelper.createOLATResourceableInstance("test", -1l);
-				addToHistory(urequest, ores, null);
-				if (type.equals(AssessmentInstance.QMD_ENTRY_TYPE_ASSESS) && !assessmentStopped ) {
-					assessmentStopped = true;					
-					AssessmentEvent assessmentStoppedEvent = new AssessmentEvent(AssessmentEvent.TYPE.STOPPED, userSession);
-					singleUserEventCenter.deregisterFor(this, assessmentInstanceOres);
-					singleUserEventCenter.fireEventToListenersOf(assessmentStoppedEvent, assessmentEventOres);
-				}
-				fireEvent(urequest, Event.DONE_EVENT);
-				
-			}
 		}
 	}
+	
+	private void stopAssessment(UserRequest ureq, Event event) {
+		if(displayContainerController != null) {
+			displayContainerController.deactivate(ureq);
+		} else {
+			getWindowControl().pop();
+		}	
+		removeHistory(ureq);
+		OLATResourceable ores = OresHelper.createOLATResourceableInstance("test", -1l);
+		addToHistory(ureq, ores, null);
+		if (type.equals(AssessmentInstance.QMD_ENTRY_TYPE_ASSESS) && !assessmentStopped ) {
+			assessmentStopped = true;					
+			AssessmentEvent assessmentStoppedEvent = new AssessmentEvent(AssessmentEvent.TYPE.STOPPED, userSession);
+			singleUserEventCenter.deregisterFor(this, assessmentInstanceOres);
+			singleUserEventCenter.fireEventToListenersOf(assessmentStoppedEvent, assessmentEventOres);
+		}
+		fireEvent(ureq, event);
+	}
 
 	private void exposeUserTestDataToVC(UserRequest ureq) {
     // config : show score info
diff --git a/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_de.properties
index 4a89b2fd5e3dde002aaa4c45b20b22c59461a456..47158dee29439e21c73d05d0d4df5136eaeb2b4d 100644
--- a/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_de.properties
@@ -136,6 +136,7 @@ error.surv.undefined.long=Es ist kein Fragebogen f\u00FCr "{0}" definiert. W\u00
 error.surv.undefined.short=Es ist kein Fragebogen f\u00FCr "{0}" definiert.
 error.test.undefined.long=Es ist kein Test f\u00FCr "{0}" definiert. W\u00E4hlen Sie einen unter "Test-Konfiguration" aus.
 error.test.undefined.short=Es ist kein Test f\u00FCr "{0}" definiert.
+error.assessment.stopped=Das Test wurde von Ihrem Tutor eingezogen.
 fieldset.chosecreateeditfile=Informationstext (HTML-Seite)
 file.name=Gew\u00E4hlte Datei
 help.iq.layout=Hilfe zu den Darstellungsoptionen
diff --git a/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_en.properties
index 8e37b0a3768ae178de7917b5fac5644f7fa271bc..546eeaf454abdb1f9ccf898523724d5b57ee355d 100644
--- a/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_en.properties
@@ -102,6 +102,7 @@ error.surv.undefined.long=No questionnaire for "{0}" defined. Choose one in the
 error.surv.undefined.short=No questionnaire for "{0}" defined.
 error.test.undefined.long=No test for "{0}" defined. Choose one in the section "Test configuration".
 error.test.undefined.short=No test for "{0}" defined.
+error.assessment.stopped=Your tutor pull your test.
 fieldset.chosecreateeditfile=Information (HTML page)
 file.name=Selected file
 help.iq.file.name-self.hover=Help to select a self-test
diff --git a/src/main/java/org/olat/ims/qti/QTIResultDetailsController.java b/src/main/java/org/olat/ims/qti/QTIResultDetailsController.java
index 276169d8f64eab6e785805dd3189d39db393f79f..233b2318358568d88047ec97f8acc7bcae603cfb 100644
--- a/src/main/java/org/olat/ims/qti/QTIResultDetailsController.java
+++ b/src/main/java/org/olat/ims/qti/QTIResultDetailsController.java
@@ -25,11 +25,13 @@
 
 package org.olat.ims.qti;
 
+import java.io.File;
+import java.util.List;
+
 import org.dom4j.Document;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.table.DefaultColumnDescriptor;
-import org.olat.core.gui.components.table.StaticColumnDescriptor;
 import org.olat.core.gui.components.table.TableController;
 import org.olat.core.gui.components.table.TableEvent;
 import org.olat.core.gui.components.table.TableGuiConfiguration;
@@ -39,10 +41,28 @@ 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.closablewrapper.CloseableModalController;
+import org.olat.core.gui.control.generic.modal.DialogBoxController;
+import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
 import org.olat.core.id.Identity;
+import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.i18n.I18nModule;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
+import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.nodes.AssessableCourseNode;
+import org.olat.course.run.scoring.ScoreEvaluation;
+import org.olat.course.run.userview.UserCourseEnvironment;
+import org.olat.ims.qti.container.AssessmentContext;
+import org.olat.ims.qti.process.AssessmentFactory;
+import org.olat.ims.qti.process.AssessmentInstance;
 import org.olat.ims.qti.process.FilePersister;
+import org.olat.ims.qti.process.Persister;
 import org.olat.ims.qti.render.LocalizedXSLTransformer;
+import org.olat.modules.ModuleConfiguration;
+import org.olat.modules.iq.IQManager;
+import org.olat.modules.iq.IQRetrievedEvent;
 import org.olat.repository.RepositoryEntry;
+import org.olat.user.UserManager;
 
 /**
  * Initial Date:  12.01.2005
@@ -53,13 +73,18 @@ public class QTIResultDetailsController extends BasicController {
 
 	private Long courseResourceableId;
 	private String nodeIdent;
-	private Identity identity;
+	private Identity assessedIdentity;
 	private RepositoryEntry repositoryEntry;
+	private Persister qtiPersister;
 	private String type;
+
+	private final IQManager iqm;
+	private final QTIResultManager qrm;
 	
 	private VelocityContainer main, details;
 	private QTIResultTableModel tableModel;
 	private TableController tableCtr;
+	private DialogBoxController retrieveConfirmationCtr;
 	
 	private CloseableModalController cmc;
 	
@@ -72,13 +97,20 @@ public class QTIResultDetailsController extends BasicController {
 	 * @param ureq
 	 * @param wControl
 	 */
-	public QTIResultDetailsController(Long courseResourceableId, String nodeIdent, Identity identity, RepositoryEntry re, String type, UserRequest ureq, WindowControl wControl) {
+	public QTIResultDetailsController(UserRequest ureq, WindowControl wControl, Long courseResourceableId, String nodeIdent, Identity assessedIdentity,
+			RepositoryEntry re, String type) {
 		super(ureq, wControl);
 		this.courseResourceableId = courseResourceableId;
 		this.nodeIdent = nodeIdent;
-		this.identity = identity;
+		this.assessedIdentity = assessedIdentity;
 		this.repositoryEntry = re;
 		this.type = type;
+		this.iqm = IQManager.getInstance();
+		this.qrm = QTIResultManager.getInstance();
+		
+		String resourcePath = courseResourceableId + File.separator + nodeIdent;
+		qtiPersister = new FilePersister(assessedIdentity, resourcePath);
+		System.out.println("qti.ser: " + qtiPersister.exists());
 		
 		init(ureq);
 	}
@@ -92,11 +124,10 @@ public class QTIResultDetailsController extends BasicController {
 		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("column.header.date", 0, null, ureq.getLocale()));
 		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("column.header.duration", 1, null, ureq.getLocale()));
 		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("column.header.assesspoints", 2, null, ureq.getLocale()));
-		tableCtr.addColumnDescriptor(new StaticColumnDescriptor("sel", "column.header.details", getTranslator().translate("select")));
+		tableCtr.addColumnDescriptor(new QTISelectColumnDescriptor("column.header.action", 3, ureq.getLocale(), getTranslator()));
 
-		QTIResultManager qrm = QTIResultManager.getInstance();
-		tableModel = new QTIResultTableModel(
-				qrm.getResultSets(courseResourceableId, nodeIdent, repositoryEntry.getKey(), identity));
+		List<QTIResultSet> resultSets = qrm.getResultSets(courseResourceableId, nodeIdent, repositoryEntry.getKey(), assessedIdentity);
+		tableModel = new QTIResultTableModel(resultSets, qtiPersister, getTranslator());
 		tableCtr.setTableDataModel(tableModel);
 		listenTo(tableCtr);
 		
@@ -107,6 +138,7 @@ public class QTIResultDetailsController extends BasicController {
 	/**
 	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event)
 	 */
+	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
 		if (source == main) {
 			if (event.getCommand().equals("close")) {
@@ -118,13 +150,14 @@ public class QTIResultDetailsController extends BasicController {
 	/**
 	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event)
 	 */
+	@Override
 	public void event(UserRequest ureq, Controller source, Event event) {
 		if (source == tableCtr) {
 			TableEvent tEvent = (TableEvent)event;
 			if (tEvent.getActionId().equals("sel")) {
-				QTIResultSet resultSet = tableModel.getResultSet(tEvent.getRowId());
+				QTIResultSet resultSet = tableModel.getObject(tEvent.getRowId());
 				
-				Document doc = FilePersister.retreiveResultsReporting(identity, type, resultSet.getAssessmentID());
+				Document doc = FilePersister.retreiveResultsReporting(assessedIdentity, type, resultSet.getAssessmentID());
 				if (doc == null) {
 					showInfo("error.resreporting.na");
 					return;
@@ -137,7 +170,20 @@ public class QTIResultDetailsController extends BasicController {
 				listenTo(cmc);
 				
 				cmc.activate();
+			} else if(tEvent.getActionId().equals("ret")) {
+				String fullname = UserManager.getInstance().getUserDisplayName(assessedIdentity.getUser());
+				String title = translate("retrievetest.confirm.title");
+				String text = translate("retrievetest.confirm.text", new String[]{fullname});
+				retrieveConfirmationCtr = activateYesNoDialog(ureq, title, text, retrieveConfirmationCtr);
 			}
+		} else if (source == retrieveConfirmationCtr) {
+			if(DialogBoxUIFactory.isYesEvent(event)) {
+				IQRetrievedEvent retrieveEvent = new IQRetrievedEvent(assessedIdentity, courseResourceableId, nodeIdent);
+				CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(retrieveEvent, retrieveEvent);
+				doRetrieveTest(ureq);
+			}
+			removeAsListenerAndDispose(retrieveConfirmationCtr);
+			retrieveConfirmationCtr = null;
 		}
 	}
 
@@ -147,5 +193,38 @@ public class QTIResultDetailsController extends BasicController {
 	protected void doDispose() {
 		//
 	}
+	
+	/**
+	 * Retrieve the test: load the course, close the assessment instamce, persist the QTI
+	 * result set, pass the score to the course node.
+	 * @param ureq
+	 */
+	protected void doRetrieveTest(UserRequest ureq2) {
+		ICourse course = CourseFactory.loadCourse(courseResourceableId);
+		AssessableCourseNode testNode = (AssessableCourseNode)course.getRunStructure().getNode(nodeIdent);
+		ModuleConfiguration modConfig = testNode.getModuleConfiguration();
+
+		String resourcePathInfo = courseResourceableId + File.separator + nodeIdent; 
+		AssessmentInstance ai = AssessmentFactory.createAssessmentInstance(assessedIdentity, modConfig, false ,resourcePathInfo);
+		//close the test
+		ai.close();
+		//persist the results
+		iqm.persistResults(ai, courseResourceableId.longValue(), nodeIdent, assessedIdentity, "");
 
+		//reporting
+		Document docResReporting = iqm.getResultsReporting(ai, assessedIdentity, I18nModule.getDefaultLocale());
+		FilePersister.createResultsReporting(docResReporting, assessedIdentity, ai.getFormattedType(), ai.getAssessID());
+		
+		//olat results
+		AssessmentContext ac = ai.getAssessmentContext();
+		Float score = new Float(ac.getScore());
+		Boolean passed = new Boolean(ac.isPassed());
+		ScoreEvaluation sceval = new ScoreEvaluation(score, passed, new Long(ai.getAssessID()));
+		UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course);
+		testNode.updateUserScoreEvaluation(sceval, userCourseEnv, assessedIdentity, true);
+		
+		List<QTIResultSet> resultSets = qrm.getResultSets(courseResourceableId, nodeIdent, repositoryEntry.getKey(), assessedIdentity);
+		tableModel.setObjects(resultSets);
+		tableCtr.modelChanged();
+	}
 }
diff --git a/src/main/java/org/olat/ims/qti/QTIResultManager.java b/src/main/java/org/olat/ims/qti/QTIResultManager.java
index afe6bd804c9499029f9896e327ec3f8effad916d..8d6eee9fb19b1142ba1d40217706b40bfdf49499 100644
--- a/src/main/java/org/olat/ims/qti/QTIResultManager.java
+++ b/src/main/java/org/olat/ims/qti/QTIResultManager.java
@@ -84,7 +84,7 @@ public class QTIResultManager extends BasicManager implements UserDataDeletable
 	 * @param identity May be null
 	 * @return List of resultsets
 	 */
-	public List getResultSets(Long olatResource, String olatResourceDetail, Long repositoryRef, Identity identity) {
+	public List<QTIResultSet> getResultSets(Long olatResource, String olatResourceDetail, Long repositoryRef, Identity identity) {
 		Long olatRes = olatResource;
 		String olatResDet = olatResourceDetail;
 		Long repRef = repositoryRef;
diff --git a/src/main/java/org/olat/ims/qti/QTIResultTableModel.java b/src/main/java/org/olat/ims/qti/QTIResultTableModel.java
index 66cfcfc2a77e6550295eac9a6c8a8d56a7d6cee2..3eefec578e59a38d1d43c132768ac23ea4cf5ab0 100644
--- a/src/main/java/org/olat/ims/qti/QTIResultTableModel.java
+++ b/src/main/java/org/olat/ims/qti/QTIResultTableModel.java
@@ -26,28 +26,45 @@
 package org.olat.ims.qti;
 
 
+import java.util.ArrayList;
 import java.util.List;
 
-import org.olat.core.gui.components.table.BaseTableDataModelWithoutFilter;
 import org.olat.core.gui.components.table.TableDataModel;
+import org.olat.core.gui.translator.Translator;
 import org.olat.core.util.Formatter;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.ims.qti.process.Persister;
 
 /**
  * Initial Date:  12.01.2005
  *
  * @author Mike Stock
  */
-public class QTIResultTableModel extends BaseTableDataModelWithoutFilter implements TableDataModel {
+public class QTIResultTableModel implements TableDataModel<QTIResultSet> {
 
 	private static final int COLUMN_COUNT = 3;
-	private List resultSets;
+	private List<QTIResultSet> resultSets;
+	private Persister persister;
+	private final Translator translator;
 	
 	/**
 	 * @param resultSets
 	 */
-	public QTIResultTableModel(List resultSets) {
+	public QTIResultTableModel(List<QTIResultSet> resultSets, Translator translator) {
+		this(resultSets, null, translator);
+	}
+	
+	/**
+	 * @param resultSets
+	 */
+	public QTIResultTableModel(List<QTIResultSet> resultSets, Persister persister, Translator translator) {
 		this.resultSets = resultSets;
+		this.persister = persister;
+		this.translator = translator;
+	}
+	
+	private boolean isTestReleased() {
+		return persister == null || !persister.exists();
 	}
 	
 	/**
@@ -61,14 +78,38 @@ public class QTIResultTableModel extends BaseTableDataModelWithoutFilter impleme
 	 * @see org.olat.core.gui.components.table.TableDataModel#getRowCount()
 	 */
 	public int getRowCount() {
-		return resultSets.size();
+		return resultSets.size() + (isTestReleased() ? 0 : 1);
+	}
+	
+	@Override
+	public QTIResultSet getObject(int row) {
+		return resultSets.get(row);
+	}
+
+	@Override
+	public void setObjects(List<QTIResultSet> objects) {
+		this.resultSets = objects;
+	}
+
+	@Override
+	public QTIResultTableModel createCopyWithEmptyList() {
+		return new QTIResultTableModel(new ArrayList<QTIResultSet>(), persister, translator);
 	}
 
 	/**
 	 * @see org.olat.core.gui.components.table.TableDataModel#getValueAt(int, int)
 	 */
 	public Object getValueAt(int row, int col) {
-		QTIResultSet resultSet = (QTIResultSet)resultSets.get(row);
+		if(!isTestReleased() && (row+1 == getRowCount())) {
+			switch (col) {
+				case 0: return persister.getLastModified();
+				case 1: return translator.translate("notReleased");
+				case 2: return translator.translate("open");
+				case 3: return Boolean.FALSE;
+				default: return "error";
+			}	
+		}
+		QTIResultSet resultSet = getObject(row);
 		switch (col) {
 			case 0: return resultSet.getLastModified();
 			case 1: {
@@ -80,6 +121,7 @@ public class QTIResultTableModel extends BaseTableDataModelWithoutFilter impleme
 				}
 			}
 			case 2: return "" + AssessmentHelper.getRoundedScore(resultSet.getScore());
+			case 3: return Boolean.TRUE;
 			default: return "error";
 		}	
 	}
@@ -91,5 +133,17 @@ public class QTIResultTableModel extends BaseTableDataModelWithoutFilter impleme
 	public QTIResultSet getResultSet(int rowId) {
 		return (QTIResultSet)resultSets.get(rowId);
 	}
+	
+	public static class Wrapper {
+		
+		private QTIResultSet resultSet;
+		
+		public Wrapper(QTIResultSet resultSet) {
+			this.resultSet = resultSet;
+		}
 
+		public QTIResultSet getResultSet() {
+			return resultSet;
+		}
+	}
 }
diff --git a/src/main/java/org/olat/ims/qti/QTISelectColumnDescriptor.java b/src/main/java/org/olat/ims/qti/QTISelectColumnDescriptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..bb22c129bacd06c109297d1735aa67e0df32149d
--- /dev/null
+++ b/src/main/java/org/olat/ims/qti/QTISelectColumnDescriptor.java
@@ -0,0 +1,67 @@
+/**
+ * <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;
+
+import java.util.Locale;
+
+import org.olat.core.gui.components.table.DefaultColumnDescriptor;
+import org.olat.core.gui.render.Renderer;
+import org.olat.core.gui.render.StringOutput;
+import org.olat.core.gui.translator.Translator;
+
+/**
+ * 
+ * Description:<br>
+ * 
+ * <P>
+ * Initial Date:  11 oct. 2011 <br>
+ *
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class QTISelectColumnDescriptor extends DefaultColumnDescriptor {
+	
+	private final Translator translator;
+	
+	public QTISelectColumnDescriptor(final String headerKey, final int dataColumn, final Locale locale, final Translator translator) {
+		super(headerKey, dataColumn, null, locale);
+		this.translator = translator;
+	}
+
+	@Override
+	public String getAction(int row) {
+		int sortedRow = table.getSortedRow(row);
+		Object state = getTable().getTableDataModel().getValueAt(sortedRow, getDataColumn());
+		if(state instanceof Boolean && !((Boolean)state).booleanValue()) {
+			return "ret";
+		}
+		return "sel";
+	}
+
+	@Override
+	public void renderValue(StringOutput sb, int row, Renderer renderer) {
+		int sortedRow = table.getSortedRow(row);
+		Object state = getTable().getTableDataModel().getValueAt(sortedRow, getDataColumn());
+		if(state instanceof Boolean && ((Boolean)state).booleanValue()) {
+			sb.append(translator.translate("select"));
+		} else {
+			sb.append(translator.translate("retrievetest"));
+		}
+	}
+}
diff --git a/src/main/java/org/olat/ims/qti/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/ims/qti/_i18n/LocalStrings_de.properties
index f14411d71dd3217913bb843d6b7e820ac0abe184..cf176e01dbb88ca0ff0f2ca6dc01e964a707a762 100644
--- a/src/main/java/org/olat/ims/qti/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/ims/qti/_i18n/LocalStrings_de.properties
@@ -22,10 +22,16 @@ ass.identifier=Identifikator (Matrikelnummer)
 ass.inst=Institution
 ass.title=Assessment
 ass.user=Testperson
+column.header.action=Aktion
 column.header.assesspoints=Punkte
 column.header.date=Datum
 column.header.details=Details
 column.header.duration=Dauer
+retrievetest=Einziehen
+retrievetest.confirm.title=Test einziehen
+retrievetest.confirm.text=Wollen Sie wirklich den Test von {0} einziehen?
+notReleased=Nicht abgegeben
+open=Offen
 date=Datum
 dur=Dauer
 editor.newquestion=Neue Frage
diff --git a/src/main/java/org/olat/ims/qti/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/ims/qti/_i18n/LocalStrings_en.properties
index 620bd3fd22886475df49ccdca7e114fb8647d004..f1ee9af447f5117de26a81587dd29c4f07b9e79c 100644
--- a/src/main/java/org/olat/ims/qti/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/ims/qti/_i18n/LocalStrings_en.properties
@@ -22,10 +22,16 @@ ass.identifier=Identification number (registration number)
 ass.inst=Institution
 ass.title=Assessment
 ass.user=Candidate
+column.header.action=Action
 column.header.assesspoints=Score
 column.header.date=Date
 column.header.details=Details
 column.header.duration=Duration
+retrievetest=Pull
+retrievetest.confirm.title=Pull test
+retrievetest.confirm.text=Do you really want to pull the test of {0}?
+notReleased=Not released
+open=Open
 date=Date
 days=Days
 dur=Duration
diff --git a/src/main/java/org/olat/ims/qti/process/FilePersister.java b/src/main/java/org/olat/ims/qti/process/FilePersister.java
index da5bb76da76336815a6a723af0a39ea9f47dbfba..38d50860c0a889df826ba269f28f0922d49ef812 100644
--- a/src/main/java/org/olat/ims/qti/process/FilePersister.java
+++ b/src/main/java/org/olat/ims/qti/process/FilePersister.java
@@ -36,6 +36,7 @@ import java.io.InputStream;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.OutputStream;
+import java.util.Date;
 
 import org.dom4j.Document;
 import org.dom4j.Element;
@@ -43,6 +44,7 @@ import org.dom4j.io.OutputFormat;
 import org.dom4j.io.XMLWriter;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.OLATRuntimeException;
+import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.FileUtils;
 import org.olat.core.util.WebappHelper;
@@ -52,6 +54,8 @@ import org.olat.ims.resources.IMSEntityResolver;
 /**
  */
 public class FilePersister implements Persister {
+	private static OLog log = Tracing.createLoggerFor(FilePersister.class);
+	
 	private static final String QTI_SER = "qtiser";
 	private static final String RES_REPORTING = "resreporting";
 	private static final String QTI_FILE = "qti.ser";
@@ -72,6 +76,21 @@ public class FilePersister implements Persister {
 		this.resourcePathInfo = resourcePathInfo;
 		this.subjectName = subj.getName();
 	}
+	
+	@Override
+	public boolean exists() {
+		File fSerial = new File(getFullQtiPath(), QTI_FILE);
+		return fSerial.exists();
+	}
+
+	@Override
+	public Date getLastModified() {
+		File fSerial = new File(getFullQtiPath(), QTI_FILE);
+		if(fSerial.exists()) {
+			return new Date(fSerial.lastModified());
+		}
+		return null;
+	}
 
 	/**
 	 * serialize the current test in case of a stop and later resume (e.g. the
@@ -80,12 +99,13 @@ public class FilePersister implements Persister {
 	 * 
 	 * @see org.olat.ims.qti.process.Persister#persist(Object, String)
 	 */
+	@Override
 	public void persist(Object o, String info) {
 		File fSerialDir = new File(getFullQtiPath());
 		OutputStream os = null;
 		try {
 			long start = -1;
-			boolean debugOn = Tracing.isDebugEnabled(FilePersister.class);
+			boolean debugOn = log.isDebug();
 			if (debugOn) {
 				start = System.currentTimeMillis();
 			}
@@ -102,7 +122,7 @@ public class FilePersister implements Persister {
 			os.close();
 			if (debugOn) {
 				long stop = System.currentTimeMillis();
-				Tracing.logDebug("time in ms to save ims qti ser file:"+(stop-start),FilePersister.class);
+				log.debug("time in ms to save ims qti ser file:"+(stop-start));
 			}
 		} catch (Exception e) {
 			try {
@@ -117,9 +137,10 @@ public class FilePersister implements Persister {
 	/**
 	 * returns (at the moment) only AssessmentInstances, see persist()
 	 */
+	@Override
 	public Object toRAM() {
 		// File path e.g. qtiser/<Unique_Course_ID>/<Node_ID>/test/qti.ser
-		File fSerialDir = new File( getFullQtiPath());		
+		File fSerialDir = new File( getFullQtiPath());
 		if ( !fSerialDir.exists() ) {
 			// file not found => try older path version ( < V5.1) e.g. qtiser/test/360459/qti.ser
 			String path = QTI_SER + File.separator + subjectName + File.separator + resourcePathInfo;
@@ -129,7 +150,7 @@ public class FilePersister implements Persister {
 		InputStream is = null;
 		try {
 			long start = -1;
-			boolean debugOn = Tracing.isDebugEnabled(FilePersister.class);
+			boolean debugOn = log.isDebug();
 			if (debugOn) {
 				start = System.currentTimeMillis();
 			}
@@ -141,7 +162,7 @@ public class FilePersister implements Persister {
 			is.close();
 			if (debugOn) {
 				long stop = System.currentTimeMillis();
-				Tracing.logDebug("time in ms to load ims qti ser file:"+(stop-start),FilePersister.class);
+				log.debug("time in ms to load ims qti ser file:"+(stop-start));
 			}
 
 		} catch (Exception e) {
@@ -248,7 +269,7 @@ public class FilePersister implements Persister {
 						File userDir = new File(subDirs[j],identity.getName());
 						if (userDir.exists()) {
 							FileUtils.deleteDirsAndFiles(userDir, true, true);
-							Tracing.logDebug("Delete qti.ser Userdata dir=" + userDir.getAbsolutePath(), FilePersister.class);
+							log.debug("Delete qti.ser Userdata dir=" + userDir.getAbsolutePath());
 						}
 					}
 				}
@@ -258,13 +279,13 @@ public class FilePersister implements Persister {
 			File qtiserDir = new File(WebappHelper.getUserDataRoot() + File.separator + QTI_SER + File.separator + identity.getName());
 			if (qtiserDir != null) {
 				FileUtils.deleteDirsAndFiles(qtiserDir, true, true);
-				Tracing.logDebug("Delete qti.ser Userdata dir=" + qtiserDir.getAbsolutePath(), FilePersister.class);
+				log.debug("Delete qti.ser Userdata dir=" + qtiserDir.getAbsolutePath());
 			}
 			// 3. Delete resreporting @ /resreporting/<USER_NAME>
 			File resReportingDir = new File(WebappHelper.getUserDataRoot() + File.separator + RES_REPORTING + File.separator + identity.getName());
 			if (resReportingDir != null) {
 				FileUtils.deleteDirsAndFiles(resReportingDir, true, true);
-				Tracing.logDebug("Delete qti resreporting Userdata dir=" + qtiserDir.getAbsolutePath(), FilePersister.class);
+				log.debug("Delete qti resreporting Userdata dir=" + qtiserDir.getAbsolutePath());
 			}
 		} catch (Exception e) {
 			throw new OLATRuntimeException(FilePersister.class, "could not delete QTI resreporting dir for identity=" + identity, e);
diff --git a/src/main/java/org/olat/ims/qti/process/Persister.java b/src/main/java/org/olat/ims/qti/process/Persister.java
index b650e580341d91d65dad290b7d844d4dda40f9e4..b76ab1048bbe93a89590d4de41588a21e76bfa51 100644
--- a/src/main/java/org/olat/ims/qti/process/Persister.java
+++ b/src/main/java/org/olat/ims/qti/process/Persister.java
@@ -25,10 +25,19 @@
 
 package org.olat.ims.qti.process;
 
+import java.util.Date;
+
 /**
  */
 public interface Persister {
+	
+	public boolean exists();
+	
+	public Date getLastModified();
+	
 	public void persist(Object o, String info);
+	
 	public Object toRAM();
+	
 	public void cleanUp();
 }
diff --git a/src/main/java/org/olat/modules/iq/IQDisplayController.java b/src/main/java/org/olat/modules/iq/IQDisplayController.java
index 3892d6b98d60772e9e991c741780681d866a269d..9d8403cc5c3b4a9440043ca1b77b24be60951bfc 100644
--- a/src/main/java/org/olat/modules/iq/IQDisplayController.java
+++ b/src/main/java/org/olat/modules/iq/IQDisplayController.java
@@ -39,12 +39,14 @@ import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
 import org.olat.core.gui.components.progressbar.ProgressBar;
 import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.DefaultController;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.dtabs.Activateable2;
 import org.olat.core.gui.translator.PackageTranslator;
 import org.olat.core.gui.translator.Translator;
+import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.context.ContextEntry;
 import org.olat.core.id.context.StateEntry;
@@ -54,6 +56,8 @@ import org.olat.core.logging.activity.StringResourceableType;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
+import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.event.GenericEventListener;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.course.nodes.iq.IQEditController;
 import org.olat.ims.qti.QTIConstants;
@@ -75,7 +79,7 @@ import org.olat.util.logging.activity.LoggingResourceable;
 /**
  * @author Felix Jost
  */
-public class IQDisplayController extends DefaultController implements Activateable2 {
+public class IQDisplayController extends DefaultController implements GenericEventListener, Activateable2 {
 
 	private static final String PACKAGE = Util.getPackageName(IQDisplayController.class);
 	private static final String VELOCITY_ROOT = Util.getPackageVelocityRoot(IQDisplayController.class);
@@ -88,6 +92,8 @@ public class IQDisplayController extends DefaultController implements Activateab
 	private String repositorySoftkey = null;
 	private Resolver resolver = null;
 	private Persister persister = null;
+	private final Identity assessedIdentity;
+	private volatile boolean retrievedFlag = false;
 
 	private ProgressBar qtiscoreprogress, qtiquestionprogress;
 	private IQComponent qticomp;
@@ -100,6 +106,7 @@ public class IQDisplayController extends DefaultController implements Activateab
 	private String callingResDetail = "";
 	private boolean ready;
 	private Link closeButton;
+	private OLATResourceable retrieveListenerOres; 
 
 	/**
 	 * IMS QTI Display Controller used by the course nodes
@@ -118,6 +125,8 @@ public class IQDisplayController extends DefaultController implements Activateab
 	IQDisplayController(ModuleConfiguration moduleConfiguration, IQSecurityCallback secCallback, UserRequest ureq,
 			WindowControl wControl, long callingResId, String callingResDetail) {
 		super(wControl);
+		
+		this.assessedIdentity = ureq.getIdentity();
 
 		ThreadLocalUserActivityLogger.log(LearningResourceLoggingAction.LEARNING_RESOURCE_OPEN, getClass());
 
@@ -147,6 +156,7 @@ public class IQDisplayController extends DefaultController implements Activateab
 
 		ThreadLocalUserActivityLogger.log(LearningResourceLoggingAction.LEARNING_RESOURCE_OPEN, getClass());
 
+		this.assessedIdentity = ureq.getIdentity();
 		this.modConfig = new ModuleConfiguration();
 		modConfig.set(IQEditController.CONFIG_KEY_ENABLEMENU, Boolean.TRUE);
 		modConfig.set(IQEditController.CONFIG_KEY_TYPE, type);
@@ -167,6 +177,9 @@ public class IQDisplayController extends DefaultController implements Activateab
 		this.translator = new PackageTranslator(PACKAGE, ureq.getLocale());
 		this.ready = false;
 
+		retrieveListenerOres =  new IQRetrievedEvent(ureq.getIdentity(), callingResId, callingResDetail);
+		CoordinatorManager.getInstance().getCoordinator().getEventBus().registerFor(this, ureq.getIdentity(), retrieveListenerOres);
+
 		iqm = IQManager.getInstance();
 
 		myContent = new VelocityContainer("olatmodiqrun", VELOCITY_ROOT + "/qti.html", translator, this);
@@ -371,12 +384,36 @@ public class IQDisplayController extends DefaultController implements Activateab
 
 	}
 
+	@Override
+	public void event(Event event) {
+		if(event instanceof IQRetrievedEvent) {
+			IQRetrievedEvent e = (IQRetrievedEvent)event;
+			if(e.isConcerned(assessedIdentity, callingResId, callingResDetail)) {
+				//it's me -> it's finished
+				retrievedFlag = true;
+			}
+		}
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if(retrievedFlag) {
+			fireEvent(ureq, new Event("test_stopped"));
+		} else {
+			super.event(ureq, source, event);
+		}
+	}
+
 	/**
 	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest,
 	 *      org.olat.core.gui.components.Component, org.olat.core.gui.control.Event)
 	 */
 	public void event(UserRequest ureq, Component source, Event event) {
-		
+		if(retrievedFlag) {
+			fireEvent(ureq, new Event("test_stopped"));
+			return;
+		}
+
 		if (source == myContent || source == qticomp) { // those must be links
 			String wfCommand = event.getCommand();
 			// process workflow
@@ -491,7 +528,7 @@ public class IQDisplayController extends DefaultController implements Activateab
 	 */
 	protected void postSubmitAssessment(UserRequest ureq, AssessmentInstance ai) {
 		if (!qtistatus.isPreview()) {
-			iqm.persistResults(ai, callingResId, callingResDetail, ureq);
+			iqm.persistResults(ai, callingResId, callingResDetail, ureq.getIdentity(), ureq.getHttpReq().getRemoteAddr());
 			getWindowControl().setInfo(translator.translate("status.results.saved"));
 		} else {
 			getWindowControl().setInfo(translator.translate("status.results.notsaved"));
@@ -507,7 +544,7 @@ public class IQDisplayController extends DefaultController implements Activateab
 	}
 	
 	protected void generateDetailsResults(UserRequest ureq, AssessmentInstance ai) {
-		Document docResReporting = iqm.getResultsReporting(ai, ureq);
+		Document docResReporting = iqm.getResultsReporting(ai, ureq.getIdentity(), ureq.getLocale());
 		if (!iqsec.isPreview()) {
 			FilePersister.createResultsReporting(docResReporting, ureq.getIdentity(), ai.getFormattedType(), ai.getAssessID());
 			// Send score and passed to parent controller. Maybe it is necessary
@@ -537,10 +574,10 @@ public class IQDisplayController extends DefaultController implements Activateab
 	 * @param ureq
 	 */
 	private void logAudit(UserRequest ureq) {
-		Set params = ureq.getParameterSet();
+		Set<String> params = ureq.getParameterSet();
 		StringBuilder sb = new StringBuilder();
-		for (Iterator iter = params.iterator(); iter.hasNext();) {
-			String paramName = (String) iter.next();
+		for (Iterator<String> iter = params.iterator(); iter.hasNext();) {
+			String paramName = iter.next();
 			sb.append("|");
 			sb.append(paramName);
 			sb.append("=");
@@ -560,6 +597,6 @@ public class IQDisplayController extends DefaultController implements Activateab
 	 * @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
 	 */
 	protected void doDispose() {
-		//
+		CoordinatorManager.getInstance().getCoordinator().getEventBus().deregisterFor(this, retrieveListenerOres);
 	}
 }
diff --git a/src/main/java/org/olat/modules/iq/IQManager.java b/src/main/java/org/olat/modules/iq/IQManager.java
index 3b2e3697f465eb9aef2fb52128ed863441f9e489..e21fb5b107b6b9f69ea2f3bf8532a215a85e55d7 100644
--- a/src/main/java/org/olat/modules/iq/IQManager.java
+++ b/src/main/java/org/olat/modules/iq/IQManager.java
@@ -41,7 +41,6 @@ import org.hibernate.Hibernate;
 import org.hibernate.type.Type;
 import org.olat.admin.user.delete.service.UserDeletionManager;
 import org.olat.basesecurity.BaseSecurityManager;
-import org.olat.basesecurity.IdentityManagerImpl;
 import org.olat.core.commons.fullWebApp.LayoutMain3ColsController;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.persistence.DBFactory;
@@ -88,7 +87,6 @@ import org.olat.modules.ModuleConfiguration;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
 import org.olat.user.UserDataDeletable;
-import org.olat.user.UserManager;
 import org.olat.util.logging.activity.LoggingResourceable;
 
 /**
@@ -229,9 +227,9 @@ public class IQManager extends BasicManager implements UserDataDeletable {
 	 * @param ureq
 	 * @return
 	 */
-	public Document getResultsReporting(AssessmentInstance ai, UserRequest ureq) {
+	public Document getResultsReporting(AssessmentInstance ai, Identity assessedIdentity, Locale locale) {
 		ResultsBuilder resB = new ResultsBuilder();
-		return resB.getResDoc(ai, ureq.getLocale(), ureq.getIdentity());
+		return resB.getResDoc(ai, locale, assessedIdentity);
 	}
 
 	/**
@@ -319,7 +317,7 @@ public class IQManager extends BasicManager implements UserDataDeletable {
 	 * @param ureq
 	 */
 
-	public void persistResults(AssessmentInstance ai, long resId, String resDetail, UserRequest ureq) {
+	public void persistResults(AssessmentInstance ai, long resId, String resDetail, Identity assessedIdentity, String remoteAddr) {
 		AssessmentContext ac = ai.getAssessmentContext();
 		
 		QTIResultSet qtiResultSet = new QTIResultSet();
@@ -327,7 +325,7 @@ public class IQManager extends BasicManager implements UserDataDeletable {
 		qtiResultSet.setOlatResource(resId);
 		qtiResultSet.setOlatResourceDetail(resDetail);
 		qtiResultSet.setRepositoryRef(ai.getRepositoryEntryKey());
-		qtiResultSet.setIdentity(ureq.getIdentity());
+		qtiResultSet.setIdentity(assessedIdentity);
 		qtiResultSet.setQtiType(ai.getType());
 		qtiResultSet.setAssessmentID(ai.getAssessID());
 		
@@ -361,7 +359,7 @@ public class IQManager extends BasicManager implements UserDataDeletable {
 				else qtiResult.setScore(ic.getScore());
 				qtiResult.setTstamp(new Date(ic.getLatestAnswerTime()));
 				qtiResult.setLastModified(new Date(System.currentTimeMillis()));
-				qtiResult.setIp(ureq.getHttpReq().getRemoteAddr());
+				qtiResult.setIp(remoteAddr);
 				
 				// Get user answers for this item
 				StringBuilder sb = new StringBuilder();
diff --git a/src/main/java/org/olat/modules/iq/IQRetrievedEvent.java b/src/main/java/org/olat/modules/iq/IQRetrievedEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..5010732cb96ed2874b794ac37b463ea2d0aeef9e
--- /dev/null
+++ b/src/main/java/org/olat/modules/iq/IQRetrievedEvent.java
@@ -0,0 +1,79 @@
+/**
+ * <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.iq;
+
+import org.olat.core.id.Identity;
+import org.olat.core.id.OLATResourceable;
+import org.olat.core.util.event.MultiUserEvent;
+
+/**
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class IQRetrievedEvent extends MultiUserEvent implements OLATResourceable {
+
+	private static final long serialVersionUID = -4054560436205827712L;
+	
+	private Long assessedIdentityKey;
+	private Long courseResourceableId;
+	private String nodeIdent;
+
+	/**
+	 * constructor for a retrieved survey event
+	 */
+	public IQRetrievedEvent(Identity assessedIdentity, Long courseResourceableId, String nodeIdent) {
+		super("iqretrieved");
+		this.assessedIdentityKey = assessedIdentity.getKey();
+		this.courseResourceableId = courseResourceableId;
+		this.nodeIdent = nodeIdent;
+	}
+
+	public Long getAssessedIdentityKey() {
+		return assessedIdentityKey;
+	}
+
+	@Override
+	public String getResourceableTypeName() {
+		return "iqretrieved";
+	}
+
+	@Override
+	public Long getResourceableId() {
+		return assessedIdentityKey;
+	}
+
+	public Long getCourseResourceableId() {
+		return courseResourceableId;
+	}
+
+	public String getNodeIdent() {
+		return nodeIdent;
+	}
+	
+	public boolean isConcerned(Identity identity, Long courseResourceableId, String nodeIdent) {
+		if(identity != null && identity.getKey().equals(getAssessedIdentityKey())
+				&& getCourseResourceableId() != null && getCourseResourceableId().equals(courseResourceableId)
+				&& getNodeIdent() != null && getNodeIdent().equals(nodeIdent)) {
+			//it's me -> it's finished
+			return true;
+		}
+		return false;
+	}
+}