From bf63e8eeffabc17901f0b673cb85ae55cf62e429 Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Wed, 22 May 2019 08:59:16 +0200
Subject: [PATCH] OO-3938: enhance behavior of back button, but not fix
 completely

---
 .../modules/bc/FolderRunController.java       | 21 +++++---
 .../modules/bc/commands/CmdCreateFile.java    | 18 ++++---
 .../modules/bc/commands/CmdOpenContent.java   | 11 ++--
 .../ui/DocEditorFullscreenController.java     |  3 +-
 .../org/olat/core/gui/components/Window.java  | 51 +++++++++++--------
 .../control/winmgr/WindowBackOfficeImpl.java  |  7 +--
 .../activity/UserActivityLoggerImpl.java      |  4 +-
 .../ui/AbstractAssignmentEditController.java  | 21 ++++++--
 .../gta/ui/GTACoachManagementController.java  | 18 ++++++-
 .../gta/ui/GTAParticipantController.java      | 44 ++++++++--------
 .../course/nodes/gta/ui/GTARunController.java | 26 +++++++---
 .../ui/GTASampleSolutionsEditController.java  | 20 ++++++--
 .../gta/ui/SubmitDocumentsController.java     | 23 +++++++--
 .../SharedFolderEditorController.java         | 12 +++--
 14 files changed, 183 insertions(+), 96 deletions(-)

diff --git a/src/main/java/org/olat/core/commons/modules/bc/FolderRunController.java b/src/main/java/org/olat/core/commons/modules/bc/FolderRunController.java
index d869bbed6d3..ae680598142 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/FolderRunController.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/FolderRunController.java
@@ -551,17 +551,26 @@ public class FolderRunController extends BasicController implements Activateable
 	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
 		if(entries == null || entries.isEmpty()) return;
 		
-		String path = BusinessControlFactory.getInstance().getPath(entries.get(0));
-		VFSItem vfsItem = folderComponent.getRootContainer().resolve(path);
-		if (vfsItem instanceof VFSContainer) {
-			folderComponent.setCurrentContainerPath(path);
-			updatePathResource(ureq);
+		if("DocEditor".equals(entries.get(entries.size() - 1).getOLATResourceable().getResourceableTypeName())
+				&& folderCommandController != null) {
+			// do nothing
 		} else {
-			activatePath(ureq, path);
+			String path = BusinessControlFactory.getInstance().getPath(entries.get(0));
+			VFSItem vfsItem = folderComponent.getRootContainer().resolve(path);
+			if (vfsItem instanceof VFSContainer) {
+				folderComponent.setCurrentContainerPath(path);
+				updatePathResource(ureq);
+			} else {
+				activatePath(ureq, path);
+			}
 		}
 	}
 
 	public void activatePath(UserRequest ureq, String path) {
+		if(folderCommandController != null) {
+			removeAsListenerAndDispose(folderCommandController);
+			folderCommandController = null;
+		}
 		if (path != null && path.length() > 0) {
 			VFSItem vfsItem = folderComponent.getRootContainer().resolve(path.endsWith("/") ? path.substring(0, path.length()-1) : path);
 			if (vfsItem instanceof VFSLeaf) {
diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdCreateFile.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdCreateFile.java
index 1fb3f85cf19..d466cdee5e2 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdCreateFile.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdCreateFile.java
@@ -52,6 +52,7 @@ import org.olat.core.id.Identity;
 import org.olat.core.logging.AssertException;
 import org.olat.core.util.FileUtils;
 import org.olat.core.util.WebappHelper;
+import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.vfs.VFSConstants;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSLeaf;
@@ -86,15 +87,15 @@ public class CmdCreateFile extends BasicController implements FolderCommand {
 	}
 
 	@Override
-	public Controller execute(FolderComponent folderComponent, UserRequest ureq, WindowControl wControl, Translator translator) {
-		if (folderComponent.getCurrentContainer().canWrite() != VFSConstants.YES) {
-			throw new AssertException("Illegal attempt to create file in: " + folderComponent.getCurrentContainerPath());
+	public Controller execute(FolderComponent folderCmp, UserRequest ureq, WindowControl wControl, Translator translator) {
+		if (folderCmp.getCurrentContainer().canWrite() != VFSConstants.YES) {
+			throw new AssertException("Illegal attempt to create file in: " + folderCmp.getCurrentContainerPath());
 		}		
 		setTranslator(translator);
-		this.folderComponent = folderComponent;
+		this.folderComponent = folderCmp;
 
 		//check for quota
-		long quotaLeft = VFSManager.getQuotaLeftKB(folderComponent.getCurrentContainer());
+		long quotaLeft = VFSManager.getQuotaLeftKB(folderCmp.getCurrentContainer());
 		if (quotaLeft <= 0 && quotaLeft != -1 ) {
 			String supportAddr = WebappHelper.getMailConfig("mailQuota");
 			String msg = translate("QuotaExceededSupport", new String[] { supportAddr });
@@ -102,10 +103,10 @@ public class CmdCreateFile extends BasicController implements FolderCommand {
 			return null;
 		}
 		
-		boolean hasMeta = folderComponent.getCurrentContainer().canMeta() == VFSConstants.YES;
+		boolean hasMeta = folderCmp.getCurrentContainer().canMeta() == VFSConstants.YES;
 		Identity identity = getIdentity();
 		DocTemplates docTemplates = DocTemplates.editables(identity, ureq.getUserSession().getRoles(), getLocale(), hasMeta).build();
-		createCtrl = new CreateDocumentController(ureq, wControl, folderComponent.getCurrentContainer(), docTemplates);
+		createCtrl = new CreateDocumentController(ureq, wControl, folderCmp.getCurrentContainer(), docTemplates);
 		listenTo(createCtrl);
 		
 		cmc = new CloseableModalController(getWindowControl(), translate("close"), createCtrl.getInitialComponent(),
@@ -177,7 +178,8 @@ public class CmdCreateFile extends BasicController implements FolderCommand {
 		DocEditorConfigs configs = DocEditorConfigs.builder()
 				.addConfig(htmlEditorConfig)
 				.build();
-		editorCtr = new DocEditorFullscreenController(ureq, getWindowControl(), vfsLeaf, secCallback, configs);
+		WindowControl swb = addToHistory(ureq, OresHelper.createOLATResourceableType("DocEditor"), null);
+		editorCtr = new DocEditorFullscreenController(ureq, swb, vfsLeaf, secCallback, configs);
 		listenTo(editorCtr);
 	}
 
diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdOpenContent.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdOpenContent.java
index 0cb04de0d3a..8cb10ba2164 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdOpenContent.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdOpenContent.java
@@ -40,6 +40,7 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.util.StringHelper;
+import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.vfs.VFSConstants;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
@@ -71,9 +72,9 @@ public class CmdOpenContent extends BasicController implements FolderCommand {
 	}
 
 	@Override
-	public Controller execute(FolderComponent folderComponent, UserRequest ureq, WindowControl wControl,
+	public Controller execute(FolderComponent folderCmp, UserRequest ureq, WindowControl wControl,
 			Translator translator) {
-		this.folderComponent = folderComponent;
+		this.folderComponent = folderCmp;
 		String pos = ureq.getParameter(ListRenderer.PARAM_CONTENT_EDIT_ID);
 		if (!StringHelper.containsNonWhitespace(pos)) {
 			// somehow parameter did not make it to us
@@ -112,14 +113,16 @@ public class CmdOpenContent extends BasicController implements FolderCommand {
 		DocEditorConfigs configs = DocEditorConfigs.builder()
 				.addConfig(htmlEditorConfig)
 				.build();
-		editCtrl = new DocEditorFullscreenController(ureq, getWindowControl(), vfsLeaf, secCallback, configs);
+		
+		WindowControl swb = addToHistory(ureq, OresHelper.createOLATResourceableType("DocEditor"), null);
+		editCtrl = new DocEditorFullscreenController(ureq, swb, vfsLeaf, secCallback, configs);
 		listenTo(editCtrl);
 		
 		if (vfsLeaf.canMeta() == VFSConstants.YES) {
 			CoreSpringFactory.getImpl(VFSRepositoryService.class).increaseDownloadCount(vfsLeaf);
 		}
 		
-		return this;
+		return editCtrl;
 	}
 	
 	private DocEditorSecurityCallback getDocEditorSecCallback(UserRequest ureq, VFSLeaf vfsLeaf) {
diff --git a/src/main/java/org/olat/core/commons/services/doceditor/ui/DocEditorFullscreenController.java b/src/main/java/org/olat/core/commons/services/doceditor/ui/DocEditorFullscreenController.java
index d719e8977dc..8bde1e47188 100644
--- a/src/main/java/org/olat/core/commons/services/doceditor/ui/DocEditorFullscreenController.java
+++ b/src/main/java/org/olat/core/commons/services/doceditor/ui/DocEditorFullscreenController.java
@@ -82,8 +82,7 @@ public class DocEditorFullscreenController extends BasicController {
 	@Override
 	protected void doDispose() {
 		if(editorCtrl != null) {
-			removeAsListenerAndDispose(editorCtrl);
-			editorCtrl = null;
+			doCloseEditor();
 		}
 	}
 }
diff --git a/src/main/java/org/olat/core/gui/components/Window.java b/src/main/java/org/olat/core/gui/components/Window.java
index d17028cbf17..7235ac181a8 100644
--- a/src/main/java/org/olat/core/gui/components/Window.java
+++ b/src/main/java/org/olat/core/gui/components/Window.java
@@ -407,7 +407,6 @@ public class Window extends AbstractComponent implements CustomCSSDelegate {
 							
 						MediaResource mmr = null;
 						//REVIEW:PB: this will be the code allowing back forward navigation
-						//-----> if (didDispatch || inlineAfterBackForward) {
 						if (forceReload) {
 							//force RELOAD with a redirect to itself
 							String reRenderUri = buildURIFor(this, timestampID, null);
@@ -421,7 +420,6 @@ public class Window extends AbstractComponent implements CustomCSSDelegate {
 									// a) have the normal mode set (not the ajax mode)
 									// b) have the target="_blank" attribute
 									// reason: in non-ajax-mode, a link has to know beforehand whether it opens in a new window or not.
-									// FIXME:fj:c think about bodyOnLoad -> win.open(new window url)
 									throw new AssertException("a link in ajax mode should never result in a new window");
 								}
 								mmr = ureq.getDispatchResult().getResultingMediaResource();
@@ -433,7 +431,6 @@ public class Window extends AbstractComponent implements CustomCSSDelegate {
 							} 
 							
 							//REVIEW:PB: this will be the code allowing back forward navigation
-							//-----> if (inline) {
 							if (inline || !validForDispatching) {
 								if(!validForDispatching){
 									// not valid: fire oldtimestamp event and later rerender
@@ -720,16 +717,19 @@ public class Window extends AbstractComponent implements CustomCSSDelegate {
 					
 					// todo maybe better delegate window registry to the windowbackoffice?
 					URLBuilder ubu = new URLBuilder(uriPrefix, resWindow.getInstanceId(), String.valueOf(resWindow.timestamp));
-					StringOutput sout = new StringOutput(30);
-					ubu.buildURI(sout, null, null);
-					mr = new RedirectMediaResource(sout.toString());
-					ServletUtil.serveResource(request, response, mr);
-					if (isDebugLog) {
-						long diff = System.currentTimeMillis() - debug_start;
-						debugMsg.append("rdirnw:").append(diff).append(LOG_SEPARATOR);
-						log.debug(debugMsg.toString());
-						long durationDispatchRequest = System.currentTimeMillis() - debug_start;
-						log.debug("Perf-Test: Window return from 2 durationDispatchRequest=" + durationDispatchRequest);
+					try(StringOutput sout = new StringOutput(30)) {
+						ubu.buildURI(sout, null, null);
+						mr = new RedirectMediaResource(sout.toString());
+						ServletUtil.serveResource(request, response, mr);
+						if (isDebugLog) {
+							long diff = System.currentTimeMillis() - debug_start;
+							debugMsg.append("rdirnw:").append(diff).append(LOG_SEPARATOR);
+							log.debug(debugMsg.toString());
+							long durationDispatchRequest = System.currentTimeMillis() - debug_start;
+							log.debug("Perf-Test: Window return from 2 durationDispatchRequest=" + durationDispatchRequest);
+						}
+					} catch(IOException e) {
+						log.error("", e);
 					}
 					return;
 				}
@@ -920,9 +920,13 @@ public class Window extends AbstractComponent implements CustomCSSDelegate {
 		URLBuilder ubu = new URLBuilder(getUriPrefix(), getInstanceId(), getTimestamp());
 		Renderer fr = Renderer.getInstance(cmp.getParent(), cmp.getTranslator(), ubu, renderResult, wbackofficeImpl.getGlobalSettings());
 		
-		StringOutput sb = StringOutputPool.allocStringBuilder(2048);
-		fr.render(cmp, sb, null);
-		return StringOutputPool.freePop(sb);
+		try(StringOutput sb = StringOutputPool.allocStringBuilder(2048)) {
+			fr.render(cmp, sb, null);
+			return StringOutputPool.freePop(sb);
+		} catch(IOException e) {
+			log.error("", e);
+			return null;
+		}
 	}
 
 	/**
@@ -945,8 +949,9 @@ public class Window extends AbstractComponent implements CustomCSSDelegate {
 				start = System.currentTimeMillis();
 			}
 			
-			final List<Component> dirties = new ArrayList<Component>();
+			final List<Component> dirties = new ArrayList<>();
 			ComponentVisitor dirtyV = new ComponentVisitor() {
+				@Override
 				public boolean visit(Component comp, UserRequest ureq) {
 					boolean visitChildren = false;
 					if(comp == null) {
@@ -1128,9 +1133,13 @@ public class Window extends AbstractComponent implements CustomCSSDelegate {
 	 */
 	public String buildURIFor(Window win, String timestampId, String moduleUri) {
 		URLBuilder ubu = new URLBuilder(uriPrefix, win.getInstanceId(), timestampId);
-		StringOutput so = new StringOutput();
-		ubu.buildURI(so, null, null, moduleUri, 0);
-		return so.toString();
+		try(StringOutput so = new StringOutput()) {
+			ubu.buildURI(so, null, null, moduleUri, 0);
+			return so.toString();
+		} catch(IOException e) {
+			log.error("", e);
+			return null;
+		}
 	}	
 
 	private String buildURIForRedirect(String moduleUri) {
@@ -1157,7 +1166,7 @@ public class Window extends AbstractComponent implements CustomCSSDelegate {
 			return NO_DISPATCHRESULT;
 		}
 
-		List<Component> foundPath = new ArrayList<Component>(10);
+		List<Component> foundPath = new ArrayList<>(10);
 		// OLAT-1973
 		Component target = ComponentHelper.findDescendantOrSelfByID(getContentPane(), s_compID, foundPath);
 		if (target == null) {
diff --git a/src/main/java/org/olat/core/gui/control/winmgr/WindowBackOfficeImpl.java b/src/main/java/org/olat/core/gui/control/winmgr/WindowBackOfficeImpl.java
index ec45c3596bb..82e05bafb95 100644
--- a/src/main/java/org/olat/core/gui/control/winmgr/WindowBackOfficeImpl.java
+++ b/src/main/java/org/olat/core/gui/control/winmgr/WindowBackOfficeImpl.java
@@ -170,20 +170,15 @@ public class WindowBackOfficeImpl implements WindowBackOffice {
 	 * @return
 	 */
 	public JSAndCSSAdderImpl createJSAndCSSAdder() {
-		JSAndCSSAdderImpl jcImpl = new JSAndCSSAdderImpl(this);
-		return jcImpl;
+		return new JSAndCSSAdderImpl(this);
 	}
 
-	/**
-	 * @see org.olat.core.gui.control.WindowBackOffice#sendCommandTo(org.olat.core.gui.control.winmgr.Command)
-	 */
 	@Override
 	public void sendCommandTo(Command wco) {
 		if (ajaxC != null) ajaxC.sendCommandTo(new WindowCommand(this,wco));
 	}
 	
 	public void pushCommands(UserRequest ureq, HttpServletRequest request, HttpServletResponse response) {
-
 		try {
 			boolean acceptJson = ServletUtil.acceptJson(request);
 			//first set the headers with the content-type
diff --git a/src/main/java/org/olat/core/logging/activity/UserActivityLoggerImpl.java b/src/main/java/org/olat/core/logging/activity/UserActivityLoggerImpl.java
index f31e4be6bce..efccd013b30 100644
--- a/src/main/java/org/olat/core/logging/activity/UserActivityLoggerImpl.java
+++ b/src/main/java/org/olat/core/logging/activity/UserActivityLoggerImpl.java
@@ -669,7 +669,7 @@ public class UserActivityLoggerImpl implements IUserActivityLogger {
 		if (loggingAction.getTypeListDefinition()==null) {
 			// this is a foul!
 			log_.warn("LoggingAction has no ResourceableTypeList defined: action="+loggingAction+", fieldId="+loggingAction.getJavaFieldIdForDebug());
-		} else {
+		} else if(log_.isDebugEnabled()) {
 			// good boy
 			String errorMsg = loggingAction.getTypeListDefinition().executeCheckAndGetErrorMessage(resourceInfos);
 			if (errorMsg!=null) {
@@ -684,7 +684,7 @@ public class UserActivityLoggerImpl implements IUserActivityLogger {
 		// start creating the LoggingObject 
 		final LoggingObject logObj = new LoggingObject(sessionId, identityKey, crudAction.name().substring(0,1), actionVerb.name(), actionObject);
 
-		if (resourceInfos!=null && resourceInfos.size()!=0) {
+		if (resourceInfos != null && !resourceInfos.isEmpty()) {
 			// this should be the normal case - we do have LoggingResourceables which we can log
 			// alongside the log message
 
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/AbstractAssignmentEditController.java b/src/main/java/org/olat/course/nodes/gta/ui/AbstractAssignmentEditController.java
index 69f4f4f8654..14b42d165b9 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/AbstractAssignmentEditController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/AbstractAssignmentEditController.java
@@ -53,13 +53,17 @@ 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.dtabs.Activateable2;
 import org.olat.core.gui.control.generic.modal.DialogBoxController;
 import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
 import org.olat.core.gui.render.Renderer;
 import org.olat.core.gui.render.StringOutput;
 import org.olat.core.gui.render.URLBuilder;
 import org.olat.core.gui.translator.Translator;
+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.resource.OresHelper;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
@@ -79,7 +83,7 @@ import org.springframework.beans.factory.annotation.Autowired;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-abstract class AbstractAssignmentEditController extends FormBasicController {
+abstract class AbstractAssignmentEditController extends FormBasicController implements Activateable2 {
 
 	private FormLink addTaskLink, createTaskLink;
 	private FlexiTableElement taskDefTableEl;
@@ -182,6 +186,13 @@ abstract class AbstractAssignmentEditController extends FormBasicController {
 		//
 	}
 
+	@Override
+	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
+		if((entries == null || entries.isEmpty()) && docEditorCtrl != null) {
+			cleanUp();
+		}
+	}
+
 	@Override
 	protected void event(UserRequest ureq, Controller source, Event event) {
 		if(addTaskCtrl == source) {
@@ -194,12 +205,10 @@ abstract class AbstractAssignmentEditController extends FormBasicController {
 			}
 			cmc.deactivate();
 			cleanUp();
-			//fireEvent(ureq, Event.DONE_EVENT);
 		} else if(editTaskCtrl == source) {
 			if(event == Event.DONE_EVENT) {
 				doFinishReplacementOfTask(editTaskCtrl.getFilenameToReplace(), editTaskCtrl.getTask());
 				updateModel(ureq);
-				//fireEvent(ureq, Event.DONE_EVENT);
 				gtaManager.markNews(courseEnv, gtaNode);
 			}
 			cmc.deactivate();
@@ -219,6 +228,7 @@ abstract class AbstractAssignmentEditController extends FormBasicController {
 				gtaManager.markNews(courseEnv, gtaNode);
 				updateModel(ureq);
 				cleanUp();
+				addToHistory(ureq, this);
 			}
 		} else if(confirmDeleteCtrl == source) {
 			if(DialogBoxUIFactory.isOkEvent(event) || DialogBoxUIFactory.isYesEvent(event)) {
@@ -314,14 +324,15 @@ abstract class AbstractAssignmentEditController extends FormBasicController {
 
 	private void doOpen(UserRequest ureq, TaskDefinition taskDef, Mode mode) {
 		VFSItem vfsItem = tasksContainer.resolve(taskDef.getFilename());
-		if(vfsItem == null || !(vfsItem instanceof VFSLeaf)) {
+		if(!(vfsItem instanceof VFSLeaf)) {
 			showError("error.missing.file");
 		} else {
 			DocEditorSecurityCallback secCallback = DocEditorSecurityCallbackBuilder.builder()
 					.withMode(mode)
 					.build();
 			DocEditorConfigs configs = GTAUIFactory.getEditorConfig(tasksContainer, taskDef.getFilename(), courseRepoKey);
-			docEditorCtrl = new DocEditorFullscreenController(ureq, getWindowControl(), (VFSLeaf)vfsItem, secCallback, configs);
+			WindowControl swb = addToHistory(ureq, OresHelper.createOLATResourceableType("DocEditor"), null);
+			docEditorCtrl = new DocEditorFullscreenController(ureq, swb, (VFSLeaf)vfsItem, secCallback, configs);
 			listenTo(docEditorCtrl);
 		}
 	}
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachManagementController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachManagementController.java
index ea81239505c..6c92b5e7b99 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachManagementController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachManagementController.java
@@ -19,12 +19,17 @@
  */
 package org.olat.course.nodes.gta.ui;
 
+import java.util.List;
+
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 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;
+import org.olat.core.gui.control.generic.dtabs.Activateable2;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.StateEntry;
 import org.olat.course.nodes.GTACourseNode;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.modules.ModuleConfiguration;
@@ -35,7 +40,7 @@ import org.olat.modules.ModuleConfiguration;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class GTACoachManagementController extends BasicController {
+public class GTACoachManagementController extends BasicController implements Activateable2 {
 	
 	private GTACoachAssignementEditController assignmentEditCtrl;
 	private GTASampleSolutionsEditController solutionEditCtrl;
@@ -67,6 +72,17 @@ public class GTACoachManagementController extends BasicController {
 		//
 	}
 
+
+	@Override
+	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
+		if(assignmentEditCtrl != null) {
+			assignmentEditCtrl.activate(ureq, entries, state);
+		}
+		if(solutionEditCtrl != null) {
+			solutionEditCtrl.activate(ureq, entries, state);
+		}
+	}
+
 	@Override
 	protected void event(UserRequest ureq, Component source, Event event) {
 		//
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java
index 42c2b4ead8f..455ddba3a85 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java
@@ -744,28 +744,32 @@ public class GTAParticipantController extends GTAAbstractController implements A
 
 	@Override
 	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
-		if(entries == null || entries.isEmpty()) return;
-		
-		String type = entries.get(0).getOLATResourceable().getResourceableTypeName();
-		if("Correction".equalsIgnoreCase(type)) {
-			int revisionLoop = entries.get(0).getOLATResourceable().getResourceableId().intValue();
-			if(revisionLoop == 0) {
-				if(correctionsCtrl != null) {
+		if(entries == null || entries.isEmpty()) {
+			if(submitDocCtrl != null) {
+				submitDocCtrl.activate(ureq, entries, state);
+			}
+		} else {
+			String type = entries.get(0).getOLATResourceable().getResourceableTypeName();
+			if("Correction".equalsIgnoreCase(type)) {
+				int revisionLoop = entries.get(0).getOLATResourceable().getResourceableId().intValue();
+				if(revisionLoop == 0) {
+					if(correctionsCtrl != null) {
+						List<ContextEntry> subEntries = entries.subList(1, entries.size());
+						correctionsCtrl.activate(ureq, subEntries, null);
+					}
+				} else if(revisionDocumentsCtrl != null) {
+					revisionDocumentsCtrl.activate(ureq, entries, null);
+				}
+			} else if("Solution".equalsIgnoreCase(type)) {
+				if(solutionsCtrl != null) {
 					List<ContextEntry> subEntries = entries.subList(1, entries.size());
-					correctionsCtrl.activate(ureq, subEntries, null);
+					solutionsCtrl.activate(ureq, subEntries, null);
+				}
+			} else if("Assessment".equalsIgnoreCase(type)) {
+				if(gradingCtrl != null) {
+					List<ContextEntry> subEntries = entries.subList(1, entries.size());
+					gradingCtrl.activate(ureq, subEntries, null);
 				}
-			} else if(revisionDocumentsCtrl != null) {
-				revisionDocumentsCtrl.activate(ureq, entries, null);
-			}
-		} else if("Solution".equalsIgnoreCase(type)) {
-			if(solutionsCtrl != null) {
-				List<ContextEntry> subEntries = entries.subList(1, entries.size());
-				solutionsCtrl.activate(ureq, subEntries, null);
-			}
-		} else if("Assessment".equalsIgnoreCase(type)) {
-			if(gradingCtrl != null) {
-				List<ContextEntry> subEntries = entries.subList(1, entries.size());
-				gradingCtrl.activate(ureq, subEntries, null);
 			}
 		}
 	}
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTARunController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTARunController.java
index 23ebc84ed01..63918ccde6f 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTARunController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTARunController.java
@@ -161,7 +161,8 @@ public class GTARunController extends BasicController implements Activateable2 {
 			}
 		} else if("management".equalsIgnoreCase(type)) {
 			if(manageLink != null) {
-				doManage(ureq);
+				List<ContextEntry> subEntries = entries.subList(1, entries.size());
+				doManage(ureq).activate(ureq, subEntries, entries.get(0).getTransientState());
 				if(segmentView != null) {
 					segmentView.select(manageLink);
 				}
@@ -174,6 +175,16 @@ public class GTARunController extends BasicController implements Activateable2 {
 					segmentView.select(runLink);
 				}
 			}
+		} else {
+			if("CourseNode".equalsIgnoreCase(entries.get(0).getOLATResourceable().getResourceableTypeName())) {
+				state = entries.get(0).getTransientState();
+				entries = entries.subList(1, entries.size());
+			}
+			
+			if(runCtrl != null && segmentView == null) {
+				runCtrl.activate(ureq, entries, state);
+			}
+			
 		}
 	}
 
@@ -221,9 +232,8 @@ public class GTARunController extends BasicController implements Activateable2 {
 	private Activateable2 doOpenRun(UserRequest ureq) {
 		if(runCtrl == null) {
 			createRun(ureq);
-		} else {
-			addToHistory(ureq, runCtrl);
 		}
+		addToHistory(ureq, runCtrl);
 		if(mainVC != null) {
 			mainVC.put("segmentCmp", runCtrl.getInitialComponent());
 		}
@@ -235,8 +245,8 @@ public class GTARunController extends BasicController implements Activateable2 {
 			createMarked(ureq);
 		} else {
 			markedCtrl.reload(ureq);
-			addToHistory(ureq, markedCtrl);
 		}
+		addToHistory(ureq, markedCtrl);
 		if(mainVC != null) {
 			mainVC.put("segmentCmp", markedCtrl.getInitialComponent());
 		}
@@ -248,23 +258,23 @@ public class GTARunController extends BasicController implements Activateable2 {
 			createCoach(ureq);
 		} else {
 			coachCtrl.reload(ureq);
-			addToHistory(ureq, coachCtrl);
 		}
+		addToHistory(ureq, coachCtrl);
 		if(mainVC != null) {
 			mainVC.put("segmentCmp", coachCtrl.getInitialComponent());
 		}
 		return coachCtrl;
 	}
 	
-	private void doManage(UserRequest ureq) {
+	private GTACoachManagementController doManage(UserRequest ureq) {
 		if(manageCtrl == null) {
 			createManage(ureq);
-		} else {
-			addToHistory(ureq, manageCtrl);
 		}
+		addToHistory(ureq, manageCtrl);
 		if(mainVC != null) {
 			mainVC.put("segmentCmp", manageCtrl.getInitialComponent());
 		}
+		return manageCtrl;
 	}
 	
 	private GTAParticipantController createRun(UserRequest ureq) {
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTASampleSolutionsEditController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTASampleSolutionsEditController.java
index 33d99ce850e..cc53748488c 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTASampleSolutionsEditController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTASampleSolutionsEditController.java
@@ -49,6 +49,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.gui.control.generic.closablewrapper.CloseableModalController;
+import org.olat.core.gui.control.generic.dtabs.Activateable2;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.StateEntry;
+import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.vfs.VFSConstants;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
@@ -68,7 +72,7 @@ import org.springframework.beans.factory.annotation.Autowired;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class GTASampleSolutionsEditController extends FormBasicController {
+public class GTASampleSolutionsEditController extends FormBasicController implements Activateable2 {
 	
 	private FormLink addSolutionLink;
 	private FormLink createSolutionLink;
@@ -226,7 +230,14 @@ public class GTASampleSolutionsEditController extends FormBasicController {
 		addSolutionCtrl = null;
 		cmc = null;
 	}
-	
+
+	@Override
+	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
+		if(entries == null || entries.isEmpty()) {
+			cleanUp();
+		}
+	}
+
 	@Override
 	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
 		if(addSolutionLink == source) {
@@ -256,14 +267,15 @@ public class GTASampleSolutionsEditController extends FormBasicController {
 	
 	private void doOpen(UserRequest ureq, Solution solution, Mode mode) {
 		VFSItem vfsItem = solutionContainer.resolve(solution.getFilename());
-		if(vfsItem == null || !(vfsItem instanceof VFSLeaf)) {
+		if(!(vfsItem instanceof VFSLeaf)) {
 			showError("error.missing.file");
 		} else {
 			DocEditorSecurityCallback secCallback = DocEditorSecurityCallbackBuilder.builder()
 					.withMode(mode)
 					.build();
 			DocEditorConfigs configs = GTAUIFactory.getEditorConfig(solutionContainer, solution.getFilename(), courseRepoKey);
-			docEditorCtrl = new DocEditorFullscreenController(ureq, getWindowControl(), (VFSLeaf)vfsItem, secCallback, configs);
+			WindowControl swb = addToHistory(ureq, OresHelper.createOLATResourceableType("DocEditor"), null);
+			docEditorCtrl = new DocEditorFullscreenController(ureq, swb, (VFSLeaf)vfsItem, secCallback, configs);
 			listenTo(docEditorCtrl);
 		}
 	}
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/SubmitDocumentsController.java b/src/main/java/org/olat/course/nodes/gta/ui/SubmitDocumentsController.java
index ce130ea6691..a098585916e 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/SubmitDocumentsController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/SubmitDocumentsController.java
@@ -58,10 +58,14 @@ 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.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.context.ContextEntry;
+import org.olat.core.id.context.StateEntry;
 import org.olat.core.util.CodeHelper;
 import org.olat.core.util.io.SystemFileFilter;
+import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.vfs.VFSConstants;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
@@ -82,15 +86,17 @@ import org.springframework.beans.factory.annotation.Autowired;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-class SubmitDocumentsController extends FormBasicController {
+class SubmitDocumentsController extends FormBasicController implements Activateable2 {
 	
 	private DocumentTableModel model;
 	private FlexiTableElement tableEl;
-	private FormLink uploadDocButton, createDocButton;
+	private FormLink uploadDocButton;
+	private FormLink createDocButton;
 
 	private CloseableModalController cmc;
 	private NewDocumentController newDocCtrl;
-	private DocumentUploadController uploadCtrl, replaceCtrl;
+	private DocumentUploadController uploadCtrl;
+	private DocumentUploadController replaceCtrl;
 	private DialogBoxController confirmDeleteCtrl;
 	private SinglePageController viewDocCtrl;
 	private DocEditorFullscreenController docEditorCtrl;
@@ -245,6 +251,13 @@ class SubmitDocumentsController extends FormBasicController {
 		//
 	}
 
+	@Override
+	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
+		if((entries == null ||entries.isEmpty()) && docEditorCtrl != null) {
+			cleanUp();
+		}
+	}
+
 	@Override
 	public void event(UserRequest ureq, Controller source, Event event) {
 		if(confirmDeleteCtrl == source) {
@@ -298,6 +311,7 @@ class SubmitDocumentsController extends FormBasicController {
 			updateModel(ureq);
 			cleanUp();
 			checkDeadline(ureq);
+			addToHistory(ureq, this);
 		} else if(cmc == source) {
 			cleanUp();
 		}
@@ -406,7 +420,8 @@ class SubmitDocumentsController extends FormBasicController {
 					.withMode(mode)
 					.build();
 			DocEditorConfigs configs = GTAUIFactory.getEditorConfig(documentsContainer, filename, null);
-			docEditorCtrl = new DocEditorFullscreenController(ureq, getWindowControl(), (VFSLeaf)vfsItem, secCallback, configs);
+			WindowControl swb = addToHistory(ureq, OresHelper.createOLATResourceableType("DocEditor"), null);
+			docEditorCtrl = new DocEditorFullscreenController(ureq, swb, (VFSLeaf)vfsItem, secCallback, configs);
 			listenTo(docEditorCtrl);
 		}
 	}
diff --git a/src/main/java/org/olat/modules/sharedfolder/SharedFolderEditorController.java b/src/main/java/org/olat/modules/sharedfolder/SharedFolderEditorController.java
index eeef627c8bc..019633fce22 100644
--- a/src/main/java/org/olat/modules/sharedfolder/SharedFolderEditorController.java
+++ b/src/main/java/org/olat/modules/sharedfolder/SharedFolderEditorController.java
@@ -91,11 +91,13 @@ public class SharedFolderEditorController extends DefaultController implements A
 
 	@Override
 	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
-		if(entries == null || entries.isEmpty()) return;
-		
-		String path = BusinessControlFactory.getInstance().getPath(entries.get(0));
-		if(StringHelper.containsNonWhitespace(path)) {
-			folderRunController.activatePath(ureq, path);
+		if(entries == null || entries.isEmpty()) {
+			folderRunController.activate(ureq, entries, state);
+		} else {
+			String path = BusinessControlFactory.getInstance().getPath(entries.get(0));
+			if(StringHelper.containsNonWhitespace(path)) {
+				folderRunController.activatePath(ureq, path);
+			}
 		}
 	}
 
-- 
GitLab