diff --git a/src/main/java/org/olat/core/commons/controllers/linkchooser/CustomLinkChooserController.java b/src/main/java/org/olat/core/commons/controllers/linkchooser/CustomLinkChooserController.java
index df7070fa1642d753f408eacb371cae41ac325bdd..3ce1b1805a2aa23e0dcf3830e6bc57f183760cdd 100644
--- a/src/main/java/org/olat/core/commons/controllers/linkchooser/CustomLinkChooserController.java
+++ b/src/main/java/org/olat/core/commons/controllers/linkchooser/CustomLinkChooserController.java
@@ -31,6 +31,7 @@ import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
 import org.olat.core.gui.components.tree.MenuTree;
+import org.olat.core.gui.components.tree.TreeEvent;
 import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
@@ -68,7 +69,7 @@ public class CustomLinkChooserController extends BasicController {
 		mainVC.put("internalLinkTree", jumpInSelectionTree);
 
 		selectButton = LinkFactory.createButton("selectfile", mainVC, this);
-		selectButton.setElementCssClass("btn btn-primary");
+		selectButton.setCustomEnabledLinkCSS("btn btn-default");
 		cancelButton = LinkFactory.createButton("cancel", mainVC, this);
 		
 		putInitialPanel(mainVC);
@@ -84,8 +85,19 @@ public class CustomLinkChooserController extends BasicController {
 		if(source == cancelButton) {
 			fireEvent(ureq, Event.CANCELLED_EVENT);
 		} else if(selectButton == source) {
-			String url = customLinkTreeModel.getInternalLinkUrlFor(jumpInSelectionTree.getSelectedNode().getIdent());
-			fireEvent(ureq, new URLChoosenEvent(url));
+			if(jumpInSelectionTree.getSelectedNode() != null) {
+				String url = customLinkTreeModel.getInternalLinkUrlFor(jumpInSelectionTree.getSelectedNode().getIdent());
+				fireEvent(ureq, new URLChoosenEvent(url));
+			}
+		} else if (source == jumpInSelectionTree) {
+			TreeEvent te = (TreeEvent) event;
+			if (te.getCommand().equals(MenuTree.COMMAND_TREENODE_CLICKED)) {
+				if(jumpInSelectionTree.getSelectedNode() != null) {
+					selectButton.setCustomEnabledLinkCSS("btn btn-default o_button_dirty");
+				} else {
+					selectButton.setCustomEnabledLinkCSS("btn btn-default");
+				}
+			}
 		}
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java b/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java
index 0422a92067085903be62790591e8635b02882087..6c7dac156eb3ab0168722a51b6cd19f471a54bba 100644
--- a/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java
@@ -72,9 +72,11 @@ import org.olat.ims.qti.export.QTIExportFormatterCSVType1;
 import org.olat.ims.qti.export.QTIExportManager;
 import org.olat.ims.qti.fileresource.TestFileResource;
 import org.olat.ims.qti.process.AssessmentInstance;
+import org.olat.ims.qti.process.FilePersister;
 import org.olat.ims.qti.statistics.QTIStatisticResourceResult;
 import org.olat.ims.qti.statistics.QTIStatisticSearchParams;
 import org.olat.ims.qti.statistics.QTIType;
+import org.olat.ims.qti.statistics.ui.QTI12PullTestsToolController;
 import org.olat.ims.qti.statistics.ui.QTI12StatisticsToolController;
 import org.olat.modules.ModuleConfiguration;
 import org.olat.repository.RepositoryEntry;
@@ -147,8 +149,22 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements As
 			CourseEnvironment courseEnv, AssessmentToolOptions options) {
 		List<Controller> tools = new ArrayList<>();
 		tools.add(new QTI12StatisticsToolController(ureq, wControl, stackPanel, courseEnv, options, this));
+		if(options.getGroup() == null && options.getIdentities() != null && options.getIdentities().size() > 0) {
+			for(Identity assessedIdentity:options.getIdentities()) {
+				if(isTestRunning(assessedIdentity, courseEnv)) {
+					tools.add(new QTI12PullTestsToolController(ureq, wControl, courseEnv, options, this));
+					break;
+				}
+			}
+		}
 		return tools;
 	}
+	
+	public boolean isTestRunning(Identity assessedIdentity, CourseEnvironment courseEnv) {
+		String resourcePath = courseEnv.getCourseResourceableId() + File.separator + getIdent();
+		FilePersister qtiPersister = new FilePersister(assessedIdentity, resourcePath);
+		return qtiPersister.exists();
+	}
 
 	@Override
 	public StatisticResourceResult createStatisticNodeResult(UserRequest ureq, WindowControl wControl,
diff --git a/src/main/java/org/olat/ims/qti/statistics/ui/QTI12PullTestsToolController.java b/src/main/java/org/olat/ims/qti/statistics/ui/QTI12PullTestsToolController.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3053c1a10775615ce2a572e37be8cf5849d4985
--- /dev/null
+++ b/src/main/java/org/olat/ims/qti/statistics/ui/QTI12PullTestsToolController.java
@@ -0,0 +1,170 @@
+package org.olat.ims.qti.statistics.ui;
+
+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.link.Link;
+import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.controller.BasicController;
+import org.olat.core.gui.control.generic.dtabs.Activateable2;
+import org.olat.core.gui.control.generic.modal.DialogBoxController;
+import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
+import org.olat.core.id.Identity;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.StateEntry;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.Util;
+import org.olat.core.util.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.AssessmentToolOptions;
+import org.olat.course.nodes.IQTESTCourseNode;
+import org.olat.course.run.environment.CourseEnvironment;
+import org.olat.course.run.scoring.ScoreEvaluation;
+import org.olat.course.run.userview.UserCourseEnvironment;
+import org.olat.ims.qti.QTIResultManager;
+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.modules.ModuleConfiguration;
+import org.olat.modules.iq.IQManager;
+import org.olat.modules.iq.IQRetrievedEvent;
+import org.olat.user.UserManager;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 07.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class QTI12PullTestsToolController extends BasicController implements Activateable2 {
+	
+	private final Link pullButton;
+	private DialogBoxController retrieveConfirmationCtr;
+	
+	private final IQTESTCourseNode courseNode;
+	private final CourseEnvironment courseEnv;
+	private final List<Identity> assessedIdentities;
+	
+	@Autowired
+	private IQManager iqm;
+	@Autowired
+	private UserManager userManager;
+	
+	public QTI12PullTestsToolController(UserRequest ureq, WindowControl wControl, CourseEnvironment courseEnv,
+			AssessmentToolOptions asOptions, IQTESTCourseNode courseNode) {
+		super(ureq, wControl);
+		setTranslator(Util.createPackageTranslator(QTIResultManager.class, getLocale(), getTranslator()));
+		
+		this.courseEnv = courseEnv;
+		this.courseNode = courseNode;
+		this.assessedIdentities = asOptions.getIdentities();
+		
+		pullButton = LinkFactory.createButton("menu.pull.tests.title", null, this);
+		pullButton.setTranslator(getTranslator());
+		putInitialPanel(pullButton);
+		getInitialComponent().setSpanAsDomReplaceable(true); // override to wrap panel as span to not break link layout 
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
+		//
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		if(pullButton == source) {
+			confirmPull(ureq);
+		}
+	}
+	
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if(retrieveConfirmationCtr == source) {
+			if(DialogBoxUIFactory.isYesEvent(event)) {
+				doRetrieveTests();
+			}
+			removeAsListenerAndDispose(retrieveConfirmationCtr);
+			retrieveConfirmationCtr = null;
+		}
+	}
+	
+	private void confirmPull(UserRequest ureq) {
+		int count = 0;
+		StringBuilder fullnames = new StringBuilder(256);
+		for(Identity assessedIdentity:assessedIdentities) {
+			if(courseNode.isTestRunning(assessedIdentity, courseEnv)) {
+				if(fullnames.length() > 0) fullnames.append(", ");
+				String name = userManager.getUserDisplayName(assessedIdentity);
+				if(StringHelper.containsNonWhitespace(name)) {
+					fullnames.append(name);
+					count++;
+				}
+			}
+		}
+		
+		if(count == 0) {
+			showInfo("retrievetest.nothing.todo");
+		} else if(count == 1) {
+			String title = translate("retrievetest.confirm.title");
+			String text = translate("retrievetest.confirm.text", new String[]{ fullnames.toString() });
+			retrieveConfirmationCtr = activateYesNoDialog(ureq, title, text, retrieveConfirmationCtr);
+		} else  {
+			String title = translate("retrievetest.confirm.title");
+			String text = translate("retrievetest.confirm.text.plural", new String[]{ fullnames.toString() });
+			retrieveConfirmationCtr = activateYesNoDialog(ureq, title, text, retrieveConfirmationCtr);
+		}
+	}
+	
+	private void doRetrieveTests() {
+		ICourse course = CourseFactory.loadCourse(courseEnv.getCourseResourceableId());
+		for(Identity assessedIdentity:assessedIdentities) {
+			if(courseNode.isTestRunning(assessedIdentity, courseEnv)) {
+				IQRetrievedEvent retrieveEvent = new IQRetrievedEvent(assessedIdentity, courseEnv.getCourseResourceableId(), courseNode.getIdent());
+				CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(retrieveEvent, retrieveEvent);
+				retrieveTest(assessedIdentity, course);
+			}
+		}
+	}
+
+	private void retrieveTest(Identity assessedIdentity, ICourse course) {
+		ModuleConfiguration modConfig = courseNode.getModuleConfiguration();
+
+		String resourcePathInfo = courseEnv.getCourseResourceableId() + File.separator + courseNode.getIdent();
+		AssessmentInstance ai = AssessmentFactory.createAssessmentInstance(assessedIdentity, "", modConfig, false, courseEnv.getCourseResourceableId(), courseNode.getIdent(), resourcePathInfo, null);
+		//close the test
+		ai.stop();
+		//persist the results
+		iqm.persistResults(ai);
+
+		//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, Boolean.FALSE, new Long(ai.getAssessID()));
+		UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course);
+		courseNode.updateUserScoreEvaluation(sceval, userCourseEnv, assessedIdentity, true);
+		
+		//cleanup
+		ai.cleanUp();
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/ims/qti/statistics/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/ims/qti/statistics/ui/_i18n/LocalStrings_de.properties
index 055cf0e2844017890df06aa4d5c918d77eec877d..ffb723fc72d9a4f236033a762e4ce8ff8a03139c 100644
--- a/src/main/java/org/olat/ims/qti/statistics/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/ims/qti/statistics/ui/_i18n/LocalStrings_de.properties
@@ -1,5 +1,6 @@
 
 menu.title=Test Statistiken
+menu.pull.tests.title=Tests einziehen
 splash.choosetest=Wählen Sie einen Test aus
 splash.notenoughresults=Für diesen Test/Umfrage gibt es noch zu wenig Resultate ({0} Teilnehmer)
 
@@ -80,4 +81,6 @@ fig.avg=Mittelwert
 fig.span=Spannweite
 fig.median=Median
 print=Drucken
-section=Sektion
\ No newline at end of file
+section=Sektion
+retrievetest.confirm.text.plural=Wollen Sie wirklich die Tests von "{0}" einziehen?
+retrievetest.nothing.todo=Es gibt zurzeit kein Test dass Sie einziehen k\u00F6nnen.
\ No newline at end of file
diff --git a/src/main/java/org/olat/ims/qti/statistics/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/ims/qti/statistics/ui/_i18n/LocalStrings_en.properties
index 011c14f00fe90574a52b1509c0a02baa565c1141..fa59a3d47a2f9bb3c6bf5f62e9d3699cfc8a831a 100644
--- a/src/main/java/org/olat/ims/qti/statistics/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/ims/qti/statistics/ui/_i18n/LocalStrings_en.properties
@@ -63,7 +63,10 @@ fig.testId=Test-ID
 fig.title=Key figures
 fig.wronganswers=Number of wrong answers
 menu.title=Test Statistics
+menu.pull.tests.title=Pull tests
 print=Print
+retrievetest.confirm.text.plural=Do you really want to pull the tests of "{0}"?
+retrievetest.nothing.todo=There isn't tests you can pull at the moment.
 solution=Solution
 splash.choosetest=Please choose a Test
 splash.notenoughresults=We don't have enough data for the selected test/survey. ({0} Participant(s) so far...)