From 4cddbcb4dff812097afb0210047594dbfb472e3a Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Tue, 16 Sep 2014 09:11:45 +0200
Subject: [PATCH] OO-1200: check if the current controller of a course element
 is wrapped in a titled wrapper controller in the navigation handler of the
 course, add a unique prefix per course to the tree node identifier of the CP
 items

---
 .../olat/course/nodes/cp/CPRunController.java |  6 +-
 .../run/navigation/NavigationHandler.java     |  5 ++
 .../olat/modules/cp/CPDisplayController.java  |  6 +-
 .../olat/modules/cp/CPManifestTreeModel.java  |  9 +-
 .../modules/cp/CPOfflineReadableManager.java  |  4 +-
 .../java/org/olat/modules/cp/CPUIFactory.java | 86 ++-----------------
 .../repository/handlers/ImsCPHandler.java     | 31 +------
 7 files changed, 30 insertions(+), 117 deletions(-)

diff --git a/src/main/java/org/olat/course/nodes/cp/CPRunController.java b/src/main/java/org/olat/course/nodes/cp/CPRunController.java
index 8c9f573daac..2fc80ad44e2 100644
--- a/src/main/java/org/olat/course/nodes/cp/CPRunController.java
+++ b/src/main/java/org/olat/course/nodes/cp/CPRunController.java
@@ -137,6 +137,7 @@ public class CPRunController extends BasicController implements ControllerEventL
 	 * @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 == showCPButton) { // those must be links
 			fireEvent(ureq, Event.CHANGED_EVENT);
@@ -148,6 +149,7 @@ public class CPRunController extends BasicController implements ControllerEventL
 	 * @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 == null) { // external source (from the course at this time being)
 			if (event instanceof TreeEvent) {
@@ -161,7 +163,6 @@ public class CPRunController extends BasicController implements ControllerEventL
 	}
 	
 	@Override
-	// Resume function
 	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
 		if(entries == null || entries.isEmpty()) return;
 		
@@ -202,7 +203,7 @@ public class CPRunController extends BasicController implements ControllerEventL
  		  activateFirstPage = false; 
 		}
 		cpDispC = CPUIFactory.getInstance().createContentOnlyCPDisplayController(ureq, getWindowControl(), new LocalFolderImpl(cpRoot),
-				activateFirstPage, false, deliveryOptions, nodecmd, courseResource);
+				activateFirstPage, false, deliveryOptions, nodecmd, courseResource, cpNode.getIdent());
 		cpDispC.setContentEncoding(deliveryOptions.getContentEncoding());
 		cpDispC.setJSEncoding(deliveryOptions.getJavascriptEncoding());
 		cpDispC.addControllerListener(this);
@@ -234,6 +235,7 @@ public class CPRunController extends BasicController implements ControllerEventL
 	/**
 	 * @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
 	 */
+	@Override
 	protected void doDispose() {
 		if (cpDispC != null) {
 			cpDispC.dispose();
diff --git a/src/main/java/org/olat/course/run/navigation/NavigationHandler.java b/src/main/java/org/olat/course/run/navigation/NavigationHandler.java
index 2f7f69cabc0..4dece99bce1 100644
--- a/src/main/java/org/olat/course/run/navigation/NavigationHandler.java
+++ b/src/main/java/org/olat/course/run/navigation/NavigationHandler.java
@@ -44,6 +44,7 @@ import org.olat.core.gui.control.ControllerEventListener;
 import org.olat.core.gui.control.Disposable;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.messages.MessageUIFactory;
+import org.olat.core.gui.control.generic.title.TitledWrapperController;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.context.BusinessControlFactory;
@@ -186,6 +187,10 @@ public class NavigationHandler implements Disposable {
 				internCourseNode = prevEval.getCourseNode();
 				SubTree subTree = externalTreeModels.get(internCourseNode.getIdent());
 				subtreemodelListener = subTree.getTreeModelListener();
+				
+				if (currentNodeController instanceof TitledWrapperController) {
+					currentNodeController = ((TitledWrapperController)currentNodeController).getContentController();
+				}
 				if(subtreemodelListener != currentNodeController) {
 					if(subtreemodelListener instanceof CPRunController) {
 						nrcr =  ((CPRunController)subtreemodelListener).createNodeRunConstructionResult(ureq);
diff --git a/src/main/java/org/olat/modules/cp/CPDisplayController.java b/src/main/java/org/olat/modules/cp/CPDisplayController.java
index 3da58b86b54..ed84d80fa94 100644
--- a/src/main/java/org/olat/modules/cp/CPDisplayController.java
+++ b/src/main/java/org/olat/modules/cp/CPDisplayController.java
@@ -106,9 +106,11 @@ public class CPDisplayController extends BasicController implements Activateable
 	 * @param showMenu
 	 * @param showNavigation Show the next/previous link
 	 * @param activateFirstPage
+	 * @param identPrefix In a course, set a unique prefix per node, if someone set 2x the same CPs in the course, the node identifiers
+	 * of the CP elements must be different but predictable
 	 */
 	public CPDisplayController(UserRequest ureq, WindowControl wControl, VFSContainer rootContainer, boolean showMenu, boolean showNavigation,
-			boolean activateFirstPage, boolean showPrint, DeliveryOptions deliveryOptions, String initialUri, OLATResourceable ores) {
+			boolean activateFirstPage, boolean showPrint, DeliveryOptions deliveryOptions, String initialUri, OLATResourceable ores, String identPrefix) {
 		super(ureq, wControl);
 		this.rootContainer = rootContainer;
 
@@ -141,7 +143,7 @@ public class CPDisplayController extends BasicController implements Activateable
 		}
 		// initialize tree model in any case
 		try {
-			ctm = new CPManifestTreeModel((VFSLeaf) mani);
+			ctm = new CPManifestTreeModel((VFSLeaf) mani, identPrefix);
 		} catch (IOException e) {
 			showError("error.manifest.corrupted");
 			return;
diff --git a/src/main/java/org/olat/modules/cp/CPManifestTreeModel.java b/src/main/java/org/olat/modules/cp/CPManifestTreeModel.java
index ae6a4dcb76e..e004b2d6b83 100644
--- a/src/main/java/org/olat/modules/cp/CPManifestTreeModel.java
+++ b/src/main/java/org/olat/modules/cp/CPManifestTreeModel.java
@@ -61,17 +61,20 @@ public class CPManifestTreeModel extends GenericTreeModel {
 	private final Map<String,TreeNode> hrefToTreeNode = new HashMap<String,TreeNode>();
 	private Map<String,String> resources; // keys: resource att 'identifier'; values: resource att 'href'
 	private final List<TreeNode> treeNodes = new ArrayList<TreeNode>();
+	private final String identPrefix;
 
 	/**
 	 * Constructor of the content packaging tree model
 	 * @param manifest the imsmanifest.xml file
 	 */
-	CPManifestTreeModel(VFSLeaf manifest) throws IOException {
+	CPManifestTreeModel(VFSLeaf manifest, String identPrefix) throws IOException {
+		this.identPrefix = identPrefix;
 		Document doc = loadDocument(manifest);
 		initDocument(doc);
 	}
 	
-	CPManifestTreeModel(String manifest) throws IOException {
+	CPManifestTreeModel(String manifest,  String identPrefix) throws IOException {
+		this.identPrefix = identPrefix;
 		Document doc = loadDocument(manifest);
 		initDocument(doc);
 	}
@@ -199,7 +202,7 @@ public class CPManifestTreeModel extends GenericTreeModel {
 			//set resolved file path directly
 			String identifierref = item.attributeValue("identifierref");
 			if(identifierref != null) {
-				gtn.setIdent("cp" + Encoder.md5hash(identifierref));
+				gtn.setIdent("cp" + Encoder.md5hash(identPrefix + identifierref));
 			}
 			XPath meta = rootElement.createXPath("//ns:resource[@identifier='" + identifierref + "']");
 			meta.setNamespaceURIs(nsuris);
diff --git a/src/main/java/org/olat/modules/cp/CPOfflineReadableManager.java b/src/main/java/org/olat/modules/cp/CPOfflineReadableManager.java
index 8c5b6fe32ad..3104aafa4a5 100644
--- a/src/main/java/org/olat/modules/cp/CPOfflineReadableManager.java
+++ b/src/main/java/org/olat/modules/cp/CPOfflineReadableManager.java
@@ -193,7 +193,7 @@ public class CPOfflineReadableManager {
 		/* first, we do the menu-tree */
 		File mani = new File(unzippedDir, FILENAME_IMSMANIFEST);
 		LocalFileImpl vfsMani = new LocalFileImpl(mani);
-		CPManifestTreeModel ctm = new CPManifestTreeModel(vfsMani);
+		CPManifestTreeModel ctm = new CPManifestTreeModel(vfsMani, "");
 		TreeNode root = ctm.getRootNode();
 		// let's take the rootnode title as  page title
 		this.rootTitle = root.getTitle(); 
@@ -227,7 +227,7 @@ public class CPOfflineReadableManager {
 	public String getOfflineCPStartHTMLFile(String manifest, String indexSrc)
 	throws IOException {
 
-		CPManifestTreeModel ctm = new CPManifestTreeModel(manifest);
+		CPManifestTreeModel ctm = new CPManifestTreeModel(manifest, "");
 		TreeNode root = ctm.getRootNode();
 		// let's take the rootnode title as  page title
 
diff --git a/src/main/java/org/olat/modules/cp/CPUIFactory.java b/src/main/java/org/olat/modules/cp/CPUIFactory.java
index 60846dc2efb..2eb2096721b 100644
--- a/src/main/java/org/olat/modules/cp/CPUIFactory.java
+++ b/src/main/java/org/olat/modules/cp/CPUIFactory.java
@@ -31,7 +31,6 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.iframe.DeliveryOptions;
 import org.olat.core.gui.control.generic.layout.MainLayout3ColumnsController;
 import org.olat.core.id.OLATResourceable;
-import org.olat.core.util.controller.OLATResourceableListeningWrapperController;
 import org.olat.core.util.vfs.VFSContainer;
 
 /**
@@ -73,32 +72,8 @@ public class CPUIFactory {
 	 * @return a CPDisplayController
 	 */
 	public CPDisplayController createContentOnlyCPDisplayController(UserRequest ureq, WindowControl wControl, VFSContainer rootContainer,
-			boolean activateFirstPage, boolean showNavigation, DeliveryOptions deliveryOptions, String initialUri, OLATResourceable ores) {
-		return new CPDisplayController(ureq, wControl, rootContainer, false, showNavigation, activateFirstPage, true, deliveryOptions, initialUri, ores);		
-	}
-
-	/**
-	 * Creates a main layout controller. The layout uses one or two columns
-	 * depending the the showMenu flag.
-	 * <p>
-	 * Use this where you have no main layout present, e.g. in a pop up in a
-	 * stand-alone view
-	 * 
-	 * @param ureq
-	 * @param wControl
-	 * @param rootContainer The VFS root container where the CP is found on disk
-	 * @param showMenu true to display the menu, false to hide the menu
-	 * @param activateFirstPage true to automatically activate the first node with
-	 *          content
-	 * @param initialUri can be NULL, will use first page then
-	 * @return A main layout controller
-	 */
-	public MainLayout3ColumnsController createMainLayoutController(UserRequest ureq, WindowControl wControl, VFSContainer rootContainer,
-			boolean showMenu, boolean activateFirstPage, DeliveryOptions deliveryOptions, String initialUri, OLATResourceable ores) {
-		CPDisplayController cpCtr = new CPDisplayController(ureq, wControl, rootContainer, showMenu, true, activateFirstPage, true, deliveryOptions, initialUri, ores);
-		MainLayout3ColumnsController layoutCtr = new LayoutMain3ColsController(ureq, wControl, cpCtr.getMenuComponent(), cpCtr.getInitialComponent(), rootContainer.getName());
-		layoutCtr.addDisposableChildController(cpCtr); // cascade disposing requests
-		return layoutCtr;
+			boolean activateFirstPage, boolean showNavigation, DeliveryOptions deliveryOptions, String initialUri, OLATResourceable ores, String identPrefix) {
+		return new CPDisplayController(ureq, wControl, rootContainer, false, showNavigation, activateFirstPage, true, deliveryOptions, initialUri, ores, identPrefix);		
 	}
 	
 	/**
@@ -116,57 +91,10 @@ public class CPUIFactory {
 	 */
 	public MainLayout3ColumnsController createMainLayoutController(UserRequest ureq, WindowControl wControl, VFSContainer rootContainer,
 			boolean showMenu, DeliveryOptions deliveryOptions) {
-		return createMainLayoutController(ureq, wControl, rootContainer, showMenu, true, deliveryOptions, null, null);
-	}
-
-	/**
-	 * Creates a main layout controller that is wrapped with a resource listener
-	 * that automatically disposes the controller whenever something changes on
-	 * the resource. The layout uses one or two columns depending the the showMenu
-	 * flag.
-	 * <p>
-	 * Use this where you have no main layout present, e.g. in a pop up in a
-	 * stand-alone view
-	 * 
-	 * @param res The OLAT resource to listen to
-	 * @param ureq
-	 * @param rootContainer The VFS root container where the CP is found on disk
-	 * @param showMenu true to display the menu, false to hide the menu
-	 * @param activateFirstPage true to automatically activate the first node with
-	 *          content
-	 * @param initialUri can be NULL, will use first page then
-	 * @return A main layout controller
-	 * @return the resource listening wrapper
-	 */
-	public OLATResourceableListeningWrapperController createMainLayoutResourceableListeningWrapperController(OLATResourceable res, UserRequest ureq, WindowControl wControl,
-			VFSContainer rootContainer, boolean showMenu, boolean activateFirstPage, DeliveryOptions deliveryOptions, String initialUri) {
-
-		CPDisplayController cpCtr = new CPDisplayController(ureq, wControl, rootContainer, showMenu, true, activateFirstPage, true, deliveryOptions, initialUri, res);
+		CPDisplayController cpCtr = new CPDisplayController(ureq, wControl, rootContainer, showMenu, true, true, true, deliveryOptions, null, null, "");
 		MainLayout3ColumnsController layoutCtr = new LayoutMain3ColsController(ureq, wControl, cpCtr.getMenuComponent(), cpCtr.getInitialComponent(), rootContainer.getName());
-		layoutCtr.addDisposableChildController(cpCtr);
-		return new OLATResourceableListeningWrapperController(ureq, wControl, res, layoutCtr, cpCtr, ureq.getIdentity());
-	}
-
-
-	/**
-	 * Creates a main layout controller that is wrapped with a resource listener
-	 * that automatically disposes the controller whenever something changes on
-	 * the resource. The layout uses one or two columns depending the the showMenu
-	 * flag.
-	 * <p>
-	 * Use this where you have no main layout present, e.g. in a pop up in a
-	 * stand-alone view
-	 * 
-	 * @param res The OLAT resource to listen to
-	 * @param ureq
-	 * @param rootContainer The VFS root container where the CP is found on disk
-	 * @param showMenu true to display the menu, false to hide the menu
-	 * @return A main layout controller
-	 * @return the resource listening wrapper
-	 */
-	public OLATResourceableListeningWrapperController createMainLayoutResourceableListeningWrapperController(OLATResourceable res, UserRequest ureq, WindowControl wControl,
-			VFSContainer rootContainer, DeliveryOptions deliveryOptions) {
-		return createMainLayoutResourceableListeningWrapperController(res, ureq, wControl, rootContainer, true, true, deliveryOptions, null);
+		layoutCtr.addDisposableChildController(cpCtr); // cascade disposing requests
+		return layoutCtr;
 	}
 
 	/**
@@ -184,7 +112,7 @@ public class CPUIFactory {
 	 */
 	public LayoutMain3ColsPreviewController createMainLayoutPreviewController(UserRequest ureq, WindowControl wControl, VFSContainer rootContainer,
 			boolean showMenu, DeliveryOptions deliveryOptions) {
-		CPDisplayController cpCtr = new CPDisplayController(ureq, wControl, rootContainer, showMenu, true, true, true, deliveryOptions, null, null);		
+		CPDisplayController cpCtr = new CPDisplayController(ureq, wControl, rootContainer, showMenu, true, true, true, deliveryOptions, null, null, "");		
 		LayoutMain3ColsPreviewController layoutCtr = new LayoutMain3ColsPreviewController(ureq, wControl, cpCtr.getMenuComponent(), cpCtr.getInitialComponent(), rootContainer.getName());
 		layoutCtr.addDisposableChildController(cpCtr); // cascade disposing requests
 		return layoutCtr;
@@ -205,7 +133,7 @@ public class CPUIFactory {
 	 */
 	public LayoutMain3ColsController createMainLayoutPreviewController_v2(UserRequest ureq, WindowControl wControl, VFSContainer rootContainer,
 			boolean showMenu, DeliveryOptions deliveryOptions) {
-		CPDisplayController cpCtr = new CPDisplayController(ureq, wControl, rootContainer, showMenu, true, true, true, deliveryOptions, null, null);		
+		CPDisplayController cpCtr = new CPDisplayController(ureq, wControl, rootContainer, showMenu, true, true, true, deliveryOptions, null, null, "");		
 		LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(ureq, wControl, cpCtr.getMenuComponent(), cpCtr.getInitialComponent(), rootContainer.getName());
 		layoutCtr.addDisposableChildController(cpCtr); // cascade disposing requests
 		layoutCtr.addCssClassToMain("o_preview");
diff --git a/src/main/java/org/olat/repository/handlers/ImsCPHandler.java b/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
index 492700383a5..16fce20e36c 100644
--- a/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
+++ b/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
@@ -187,46 +187,19 @@ public class ImsCPHandler extends FileHandler {
 		final LocalFolderImpl vfsWrapper = new LocalFolderImpl(cpRoot);
 		CPPackageConfig packageConfig = CPManager.getInstance().getCPPackageConfig(res);
 		final DeliveryOptions deliveryOptions = (packageConfig == null ? null : packageConfig.getDeliveryOptions());
-		
-		// jump to either the forum or the folder if the business-launch-path says so.
-		/*
-		BusinessControl bc = wControl.getBusinessControl();
-		ContextEntry ce = bc.popLauncherContextEntry();
-		MainLayoutController layoutCtr;
-		if ( ce != null ) { // a context path is left for me
-			log.debug("businesscontrol (for further jumps) would be:"+bc);
-			OLATResourceable ores = ce.getOLATResourceable();
-			log.debug("OLATResourceable=" + ores);
-			String typeName = ores.getResourceableTypeName();
-			// typeName format: 'path=/test1/test2/readme.txt'
-			// First remove prefix 'path='
-			String path = typeName.substring("path=".length());
-			if  (path.length() > 0) {
-			  log.debug("direct navigation to container-path=" + path);
-			  layoutCtr = CPUIFactory.getInstance().createMainLayoutResourceableListeningWrapperController(res, ureq, wControl, vfsWrapper, true, false, deliveryOptions, path);
-			} else {
-				layoutCtr = CPUIFactory.getInstance().createMainLayoutResourceableListeningWrapperController(res, ureq, wControl, vfsWrapper, deliveryOptions);
-			}
-		} else {
-			layoutCtr = CPUIFactory.getInstance().createMainLayoutResourceableListeningWrapperController(res, ureq, wControl, vfsWrapper, deliveryOptions);
-		}
-		*/
-		
-		CPRuntimeController runtime = new CPRuntimeController(ureq, wControl, re, reSecurity,
+		return new CPRuntimeController(ureq, wControl, re, reSecurity,
 				new RuntimeControllerCreator() {
 					@Override
 					public Controller create(UserRequest uureq, WindowControl wwControl, TooledStackedPanel toolbarPanel, RepositoryEntry entry, RepositoryEntrySecurity security) {
 						boolean activateFirstPage = true;
 						String initialUri = null;
 						
-						CPDisplayController cpCtr = new CPDisplayController(uureq, wwControl, vfsWrapper, true, true, activateFirstPage, true, deliveryOptions, initialUri, entry.getOlatResource());
+						CPDisplayController cpCtr = new CPDisplayController(uureq, wwControl, vfsWrapper, true, true, activateFirstPage, true, deliveryOptions, initialUri, entry.getOlatResource(), "");
 						MainLayout3ColumnsController ctr = new LayoutMain3ColsController(uureq, wwControl, cpCtr.getMenuComponent(), cpCtr.getInitialComponent(), vfsWrapper.getName());
 						ctr.addDisposableChildController(cpCtr);
 						return ctr;
 					}
 			});
-
-		return runtime;
 	}
 
 	@Override
-- 
GitLab