Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
WikiMainController.java 48.58 KiB
/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <hr>
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* This file has been modified by the OpenOLAT community. Changes are licensed
* under the Apache 2.0 license as the original file.
*/

package org.olat.modules.wiki;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.olat.core.CoreSpringFactory;
import org.olat.core.commons.modules.bc.FolderEvent;
import org.olat.core.commons.services.notifications.NotificationsManager;
import org.olat.core.commons.services.notifications.PublisherData;
import org.olat.core.commons.services.notifications.SubscriptionContext;
import org.olat.core.commons.services.notifications.ui.ContextualSubscriptionController;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.dropdown.Dropdown;
import org.olat.core.gui.components.dropdown.Dropdown.Spacer;
import org.olat.core.gui.components.htmlheader.jscss.JSAndCSSComponent;
import org.olat.core.gui.components.link.Link;
import org.olat.core.gui.components.link.LinkFactory;
import org.olat.core.gui.components.panel.Panel;
import org.olat.core.gui.components.panel.StackedPanel;
import org.olat.core.gui.components.tabbedpane.TabbedPane;
import org.olat.core.gui.components.tabbedpane.TabbedPaneChangedEvent;
import org.olat.core.gui.components.table.Table;
import org.olat.core.gui.components.table.TableController;
import org.olat.core.gui.components.table.TableEvent;
import org.olat.core.gui.components.table.TableGuiConfiguration;
import org.olat.core.gui.components.table.TableMultiSelectEvent;
import org.olat.core.gui.components.tree.GenericTreeModel;
import org.olat.core.gui.components.tree.GenericTreeNode;
import org.olat.core.gui.components.tree.TreeEvent;
import org.olat.core.gui.components.tree.TreeNode;
import org.olat.core.gui.components.velocity.VelocityContainer;
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.clone.CloneableController;
import org.olat.core.gui.control.generic.closablewrapper.CloseableCalloutWindowController;
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.OLATResourceable;
import org.olat.core.id.context.BusinessControlFactory;
import org.olat.core.id.context.ContextEntry;
import org.olat.core.id.context.StateEntry;
import org.olat.core.logging.OLATRuntimeException;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.logging.activity.LearningResourceLoggingAction;
import org.olat.core.logging.activity.OlatResourceableType;
import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
import org.olat.core.util.Encoder;
import org.olat.core.util.StringHelper;
import org.olat.core.util.coordinate.CoordinatorManager;
import org.olat.core.util.coordinate.LockResult;
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;
import org.olat.core.util.vfs.VFSMediaResource;
import org.olat.modules.fo.Forum;
import org.olat.modules.fo.ForumCallback;
import org.olat.modules.fo.manager.ForumManager;
import org.olat.modules.fo.ui.ForumController;
import org.olat.modules.wiki.gui.components.wikiToHtml.ErrorEvent;
import org.olat.modules.wiki.gui.components.wikiToHtml.FilterUtil;
import org.olat.modules.wiki.gui.components.wikiToHtml.RequestImageEvent;
import org.olat.modules.wiki.gui.components.wikiToHtml.RequestMediaEvent;
import org.olat.modules.wiki.gui.components.wikiToHtml.RequestNewPageEvent;
import org.olat.modules.wiki.gui.components.wikiToHtml.RequestPageEvent;
import org.olat.modules.wiki.gui.components.wikiToHtml.WikiMarkupComponent;
import org.olat.modules.wiki.portfolio.WikiArtefact;
import org.olat.modules.wiki.versioning.ChangeInfo;
import org.olat.modules.wiki.versioning.HistoryTableDateModel;
import org.olat.portfolio.EPUIFactory;
import org.olat.search.SearchServiceUIFactory;
import org.olat.search.SearchServiceUIFactory.DisplayOption;
import org.olat.util.logging.activity.LoggingResourceable;



/**
 * Description:<br>
 * This controller creates the whole GUI for a wiki with a tabbed pane contaning an article
 * view, per page forum view, edit pane and versioning pane. The rendering of the wiki syntax to html
 * is done by @see org.olat.core.gui.components.wikiToHtml.WikiMarkupComponent.
 * <P>
 * Initial Date: May 4, 2006 <br>
 * 
 * @author guido
 */
public class WikiMainController extends BasicController implements CloneableController, Activateable2 {
	
	private static final OLog log = Tracing.createLoggerFor(WikiMainController.class);

	private TabbedPane tabs;
	private WikiPage selectedPage;
	private GenericTreeModel wikiMenuModel;
	private String pageId;
	private VFSContainer wikiContainer;
	private OLATResourceable ores;
	private VelocityContainer articleContent, navigationContent, discussionContent, editContent, content, versioningContent, mediaMgntContent, imageDisplay;
	private ForumController forumController;
	private WikiEditArticleForm wikiEditForm;
	private WikiMarkupComponent wikiArticleComp, wikiVersionDisplayComp;
	private ContextualSubscriptionController cSubscriptionCtrl;
	private TableController versioningTableCtr;
	private WikiFileUploadController wikiUploadFileCtr;
	private HistoryTableDateModel versioningTableModel;
	private DialogBoxController removePageDialogCtr, archiveWikiDialogCtr;
	private List<ChangeInfo> diffs = new ArrayList<ChangeInfo>(2);
	private SubscriptionContext subsContext;
	private LockResult lockEntry;
	private Link archiveLink, closePreviewButton, createLink, toMainPageLink,
		a2zLink, changesLink, editMenuButton, revertVersionButton;
	private TableController mediaTableCtr;
	private MediaFilesTableModel mediaFilesTableModel;
	private TableGuiConfiguration tableConfig;
	private WikiSecurityCallback securityCallback;
	private Controller searchCtrl;
	private WikiArticleSearchForm createArticleForm;
	private CloseableCalloutWindowController calloutCtrl;
	private StackedPanel mainPanel;

	private Dropdown wikiMenuDropdown, navigationDropdown, breadcrumpDropdown;
	private GenericTreeNode navMainPageNode, navAZNode, navChangesNode, wikiMenuNode;
	
	public static final String ACTION_COMPARE = "compare";
	public static final String ACTION_SHOW = "view.version";
	private static final String ACTION_EDIT_MENU = "editMenu";
	private static final String ACTION_CLOSE_PREVIEW = "preview.close";
	private static final String ACTION_DELETE_MEDIAS = "delete.medias";
	private static final String ACTION_DELETE_MEDIA = "delete.media";
	protected static final String ACTION_SHOW_MEDIA = "show.media";
	protected static final String METADATA_SUFFIX = ".metadata";
	private static final String MEDIA_FILE_FILENAME = "filename";
	private static final String MEDIA_FILE_CREATIONDATE = "creation.date";
	private static final String MEDIA_FILE_CREATED_BY = "created.by";
	private static final String MEDIA_FILE_DELETIONDATE = "deleted.at";
	private static final String MEDIA_FILE_DELETED_BY = "deleted.by";
	
//	indicates if user is already on image-detail-view-page (OLAT-6233)
	private boolean isImageDetailView = false;
	
	private CloseableModalController cmc;
	
	WikiMainController(UserRequest ureq, WindowControl wControl, OLATResourceable ores,
			WikiSecurityCallback securityCallback, String initialPageName) {
		super(ureq, wControl);
		
		this.wikiContainer = WikiManager.getInstance().getWikiRootContainer(ores);
		this.ores = ores;
		this.securityCallback = securityCallback;
		this.subsContext = securityCallback.getSubscriptionContext();
		boolean guestOnly = ureq.getUserSession().getRoles().isGuestOnly();
		
		WikiPage page = null;
		Wiki wiki = getWiki();
		if(wiki == null) {
			VelocityContainer vc = createVelocityContainer("deleted");
			mainPanel = putInitialPanel(vc);
			return;
		}
		
		if (!ores.getResourceableTypeName().equals("BusinessGroup")) {
			addLoggingResourceable(LoggingResourceable.wrap(ores, OlatResourceableType.genRepoEntry));
		}
		ThreadLocalUserActivityLogger.log(LearningResourceLoggingAction.LEARNING_RESOURCE_OPEN, getClass());
		// init the first page either startpage or an other page identified by initial page name
		if (initialPageName != null && wiki.pageExists(WikiManager.generatePageId(initialPageName))) {
			page = wiki.getPage(initialPageName, true);
		} else {
			page = wiki.getPage(WikiPage.WIKI_INDEX_PAGE);
			if (initialPageName != null) showError("wiki.error.page.not.found");
		}
		this.pageId = page.getPageId();
		
		tabs = new TabbedPane("userTabP", ureq.getLocale());
		tabs.addListener(this);
		// init the tabbed pane container
		content = createVelocityContainer("index");

		
		// navigation container
		navigationContent = createVelocityContainer("navigation");
		navigationContent.contextPut("navigationEnabled", Boolean.TRUE);
		
		// add a history that displays visited pages
		breadcrumpDropdown = new Dropdown("breadcrump", "navigation.history", false, getTranslator());
		Link indexLink = LinkFactory.createToolLink(WikiPage.WIKI_INDEX_PAGE, "select-page", WikiPage.WIKI_INDEX_PAGE, this);
		breadcrumpDropdown.addComponent(indexLink);
		navigationContent.put("breadcrumb", breadcrumpDropdown);

		if(subsContext != null) {
			String businnessPath = wControl.getBusinessControl().getAsString();
			PublisherData data = new PublisherData(OresHelper.calculateTypeName(WikiPage.class), null, businnessPath);
			cSubscriptionCtrl = new ContextualSubscriptionController(ureq, getWindowControl(), subsContext, data);
			listenTo(cSubscriptionCtrl);
			navigationContent.put("subscription", cSubscriptionCtrl.getInitialComponent());
		}
		
		navigationDropdown = new Dropdown("navi", "navigation.navigation", false, getTranslator());
		navigationContent.put("navi", navigationDropdown);
		
		toMainPageLink = LinkFactory.createLink("navigation.mainpage", navigationContent, this);
		toMainPageLink.setDomReplaceable(false);
		toMainPageLink.setIconLeftCSS("o_icon o_icon_home");
		navigationDropdown.addComponent(toMainPageLink);
		
		a2zLink = LinkFactory.createLink("navigation.a-z", navigationContent, this);
		a2zLink.setDomReplacementWrapperRequired(false);
		navigationDropdown.addComponent(a2zLink);
		
		changesLink = LinkFactory.createLink("navigation.changes", navigationContent, this);
		changesLink.setDomReplacementWrapperRequired(false);
		navigationDropdown.addComponent(changesLink);

		archiveLink = LinkFactory.createLink("archive.wiki", navigationContent, this);
		archiveLink.setIconLeftCSS("o_icon o_icon_archive_tool");
		archiveLink.setDomReplacementWrapperRequired(false);
		archiveLink.setTitle("archive.wiki.title");
		
		if(!guestOnly) {
			createLink = LinkFactory.createLink("navigation.create.article", navigationContent, this);
			createLink.setIconLeftCSS("o_icon o_icon_create");
			createLink.setElementCssClass("o_sel_wiki_create_page");
			createLink.setDomReplacementWrapperRequired(false);
		}

		content.put("navigation", navigationContent);
		
		//search
		if(!guestOnly) {
		  SearchServiceUIFactory searchServiceUIFactory = (SearchServiceUIFactory)CoreSpringFactory.getBean(SearchServiceUIFactory.class);
		  searchCtrl = searchServiceUIFactory.createInputController(ureq, wControl, DisplayOption.STANDARD, null);
		  listenTo(searchCtrl);
		  navigationContent.put("search_article", searchCtrl.getInitialComponent());
		}

		// attach menu
		wikiMenuDropdown = new Dropdown("wikiMenu", "navigation.menu", false, getTranslator());
		if (securityCallback.mayEditWikiMenu()) {
			editMenuButton = LinkFactory.createLink("edit.menu", navigationContent, this);
			editMenuButton.setIconLeftCSS("o_icon o_icon_edit");
		}
		navigationContent.put("wikiMenuDropdown", wikiMenuDropdown);
		updateWikiMenu(wiki);

		// attach index article
		wikiArticleComp = new WikiMarkupComponent("wikiArticle", ores, 300);
		wikiArticleComp.addListener(this);
		wikiArticleComp.setImageMapperUri(ureq, wikiContainer);
		navigationContent.put("wikiArticle", wikiArticleComp);

		/***************************************************************************
		 * wiki component
		 **************************************************************************/
		articleContent = createVelocityContainer("article");
		articleContent.put("wikiArticle", wikiArticleComp);
		tabs.addTab(translate("tab.article"), articleContent);

		/***************************************************************************
		 * discussion container
		 **************************************************************************/
		discussionContent = createVelocityContainer("discuss");
		tabs.addTab(translate("tab.discuss"), discussionContent);

		/***************************************************************************
		 * edit container
		 **************************************************************************/
		editContent = createVelocityContainer("edit");
		imageDisplay = createVelocityContainer("imagedisplay");
		closePreviewButton = LinkFactory.createButtonSmall(ACTION_CLOSE_PREVIEW, editContent, this);
		
		editContent.contextPut("isGuest", Boolean.valueOf(ureq.getUserSession().getRoles().isGuestOnly()));
		wikiEditForm = new WikiEditArticleForm(ureq, wControl, page, securityCallback);
		listenTo(wikiEditForm);
		editContent.contextPut("editformid", "ofo_"+wikiEditForm.hashCode());

		editContent.put("editForm", wikiEditForm.getInitialComponent());
		
		JSAndCSSComponent js = new JSAndCSSComponent("js", new String[] { "js/openolat/wiki.js" }, null);
		content.put("js", js);
		editContent.contextPut("fileList", wiki.getMediaFileList());
		editContent.contextPut("linkList", wiki.getListOfAllPageNames());
		
		tabs.addTab(translate("tab.edit"), editContent);

		/***************************************************************************
		 * version container
		 **************************************************************************/
		versioningContent = createVelocityContainer("versions");
		wikiVersionDisplayComp = new WikiMarkupComponent("versionDisplay", ores, 300);
		wikiVersionDisplayComp.addListener(this);
		wikiVersionDisplayComp.setImageMapperUri(ureq, wikiContainer);
		tabs.addTab(translate("tab.versions"), versioningContent);
		if (this.securityCallback.mayEditAndCreateArticle()) revertVersionButton = LinkFactory.createButton("revert.old.version", versioningContent, this);
		
		tableConfig = new TableGuiConfiguration();
		tableConfig.setPageingEnabled(true);
		tableConfig.setResultsPerPage(10);
		tableConfig.setSelectedRowUnselectable(true);

		content.put("wikiTabs", tabs);
		// if not content yet switch to the edit tab
		if (page.getContent().equals("")) {
			tabs.setSelectedPane(2);
			tryToSetEditLock(page, ureq, ores);
		}
		updatePageContext(ureq, page);
		setTabsEnabled(true); //apply security settings to tabs by may disabling edit tab
		mainPanel = putInitialPanel(content);
		
		//set pageId to the latest used
		this.pageId = page.getPageId();
	}
	
	private void updateWikiMenu(Wiki wiki) {
		Collection<String> links = wiki.getListOfAllPageNames();
		if(wikiMenuNode != null) {
			wikiMenuNode.removeAllChildren();
			for(String link:links) {
				String ident = "w" + Encoder.md5hash(link);
				GenericTreeNode menuItemNode = new GenericTreeNode(ident, link, link);
				wikiMenuNode.addChild(menuItemNode);
			}
		}
		
		wikiMenuDropdown.removeAllComponents();
		for(String link:links) {
			Link menuLink = LinkFactory.createToolLink(link, "select-page", link, this);
			wikiMenuDropdown.addComponent(menuLink);
		}
		if(editMenuButton != null) {
			wikiMenuDropdown.addComponent(new Spacer("wiki-spacer"));
			wikiMenuDropdown.addComponent(editMenuButton);
		}
	}
	
	public GenericTreeModel getAndUseExternalTree() {
		final String resId = ores.getResourceableId().toString();
		Wiki wiki = getWiki();
		wikiMenuModel = new GenericTreeModel();

		String root = "wiki-" + resId;
		GenericTreeNode rootNode = new GenericTreeNode(root);
		wikiMenuModel.setRootNode(rootNode);

		//Index
		String navMainItem = "nav-main-item-" + resId;
		navMainPageNode = new GenericTreeNode(navMainItem, translate("navigation.mainpage"), navMainItem);
		rootNode.addChild(navMainPageNode);
		
		//Wiki-Menu
		String wikiMenuTitle = translate("navigation.menu");
		String wikiMenuItem = "menu-item-" + resId;
		wikiMenuNode = new GenericTreeNode(wikiMenuItem, wikiMenuTitle, wikiMenuItem);
		rootNode.addChild(wikiMenuNode);
		
		String navAZItem = "nav-az-item-" + resId;
		navAZNode = new GenericTreeNode(navAZItem, translate("navigation.a-z"), navAZItem);
		rootNode.addChild(navAZNode);
		
		String navChangesItem = "nav-changes-item-" + resId;
		navChangesNode = new GenericTreeNode(navChangesItem, translate("navigation.changes"), navChangesItem);
		rootNode.addChild(navChangesNode);

		updateWikiMenu(wiki);
		
		navigationDropdown.setVisible(false);
		wikiMenuDropdown.setVisible(false);

		navigationContent.contextPut("navigationEnabled", Boolean.FALSE);
		return wikiMenuModel;
	}

	@Override
	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
		if(entries == null || entries.isEmpty()) return;

		Wiki wiki = getWiki();
		if(wiki == null) {
			return;
		}
		
		ContextEntry ce = entries.get(0);
		String typ = ce.getOLATResourceable().getResourceableTypeName();
		if("az".equalsIgnoreCase(typ)) {
			openAtoZPage(ureq, wiki);
		} else if ("lastChanges".equalsIgnoreCase(typ)) {
			openLastChangesPage(ureq, wiki);
		} else if ("index".equalsIgnoreCase(typ)) {
			WikiPage page = openIndexPage(ureq, wiki);
			pageId = page.getPageId();
		} else if ("Forum".equalsIgnoreCase(typ)) {
			Long forumKey = ce.getOLATResourceable().getResourceableId();
			for(WikiPage page:wiki.getAllPagesWithContent()) {
				if(forumKey.longValue() == page.getForumKey()) {
					if(page != null) {
						this.pageId = page.getPageId();
					}
					updatePageContext(ureq, page);
					
					OLATResourceable tabOres = OresHelper.createOLATResourceableInstance("tab", 1l);
					ContextEntry tabCe = BusinessControlFactory.getInstance().createContextEntry(tabOres);
					tabs.activate(ureq, Collections.singletonList(tabCe), null);
					if(forumController != null && entries.size() > 1) {
						List<ContextEntry> subEntries = entries.subList(1, entries.size());
						forumController.activate(ureq, subEntries, null);
					}
					break;
				}
			}
		} else {
			String path = BusinessControlFactory.getInstance().getPath(ce);
			if(path.startsWith("page=")) {
				path = path.substring(5, path.length());
			}
			String activatePageId = WikiManager.generatePageId(FilterUtil.normalizeWikiLink(path));
			if(wiki.pageExists(activatePageId)) {
				WikiPage page = wiki.getPage(activatePageId, true);
				if(page != null) {
					this.pageId = page.getPageId();
				}
				updatePageContext(ureq, page);
				
				if(entries.size() > 1) {
					List<ContextEntry> subEntries = entries.subList(1, entries.size());
					String subTyp = subEntries.get(0).getOLATResourceable().getResourceableTypeName();
					if("tab".equalsIgnoreCase(subTyp)) {
						tabs.activate(ureq, subEntries, ce.getTransientState());
					} else if("message".equalsIgnoreCase(subTyp)) {
						OLATResourceable tabOres = OresHelper.createOLATResourceableInstance("tab", 1l);
						ContextEntry tabCe = BusinessControlFactory.getInstance().createContextEntry(tabOres);
						tabs.activate(ureq, Collections.singletonList(tabCe), null);
					
						forumController.activate(ureq, subEntries, null);		
					}
				}
			}
		}
	}

	@Override
	public void event(UserRequest ureq, Component source, Event event) {
	
		String command = event.getCommand();
		setTabsEnabled(true);
		//to make shure we use the lateste page, reload from cache
		Wiki wiki = getWiki();
		if(wiki == null) {
			mainPanel.setContent(createVelocityContainer("deleted"));
			return;
		}
		WikiPage page = null;
		
		//FIXME:gs images and media should also be wiki pages -> see jamwiki
		if (!(event instanceof RequestNewPageEvent) && !(event instanceof RequestMediaEvent) && !(event instanceof RequestImageEvent)) {
			page = wiki.getPage(pageId, true);
			//set recent page id to the page currently used
			if (page != null) pageId = page.getPageId();
		}
		
		if (source == content) {
			// noting yet
		} else if (source == tabs) {
			/*************************************************************************
			 * tabbed pane events
			 ************************************************************************/
			
			TabbedPaneChangedEvent tabEvent = (TabbedPaneChangedEvent) event;
			Component comp = tabEvent.getNewComponent();
			String compName = comp.getComponentName();
			selectTab(ureq, command, compName, page, wiki);
		} else if (source == wikiArticleComp) {
			/*************************************************************************
			 * wiki component events
			 ************************************************************************/
			if (event instanceof RequestPageEvent) {
				RequestPageEvent pageEvent = (RequestPageEvent) event;
				page = openPage(ureq, pageEvent.getCommand(), wiki);
			} else if (event instanceof RequestNewPageEvent) {
				page = handleRequestNewPageEvent(ureq, (RequestNewPageEvent)event, wiki);
			} else  if (event instanceof ErrorEvent) {
				showWarning(event.getCommand());
			} else if (event instanceof RequestMediaEvent) {
				deliverMediaFile(ureq, event.getCommand());
			} else if (event instanceof RequestImageEvent) {
				// OLAT-6233 if image-view page is shown 2nd time (click on image ), return to content-wiki-page 
				// instead of linking to the image-view-page itself
				if(isImageDetailView){
					page = wiki.getPage(pageId,true);
					updatePageContext(ureq, page);
					isImageDetailView = false;
				} else {
					final WikiPage imagePage = new WikiPage(event.getCommand());
					imagePage.setContent("[[Image:" + event.getCommand() + "]]");
					articleContent.contextPut("page", imagePage);
					wikiArticleComp.setWikiContent(imagePage.getContent());
					setTabsEnabled(false);
					isImageDetailView = true;
				}
			}
		} else if (source == navigationContent ) {
			/*************************************************************************
			 * article container events
			 ************************************************************************/
			if (command.equals(ACTION_EDIT_MENU)) {
				page = wiki.getPage(WikiPage.WIKI_MENU_PAGE);
				editContent.contextPut("linkList", wiki.getListOfAllPageNames());
				tryToSetEditLock(page, ureq, ores);
				updatePageContext(ureq, page);
				tabs.setSelectedPane(2);
			}
		} else if (source == toMainPageLink){ // home link
			page = openIndexPage(ureq, wiki);
		} else if (source == a2zLink){
			openAtoZPage(ureq, wiki);
		} else if (source == changesLink){
			openLastChangesPage(ureq, wiki);
		} else if (source == editMenuButton){
			page = wiki.getPage(WikiPage.WIKI_MENU_PAGE);
			editContent.contextPut("linkList", wiki.getListOfAllPageNames());
			tryToSetEditLock(page, ureq, ores);
			updatePageContext(ureq, page);
			//wikiEditForm.setPage(page);
			tabs.setSelectedPane(2);
		} else if (source == archiveLink){
			//archive a snapshot of the wiki in the users personal folder
			archiveWikiDialogCtr = activateOkCancelDialog(ureq, null, translate("archive.question"), archiveWikiDialogCtr);
			return;
		} else if (source == createLink) {
			removeAsListenerAndDispose(calloutCtrl);
			removeAsListenerAndDispose(createArticleForm);
			
			createArticleForm = new WikiArticleSearchForm(ureq, getWindowControl());
			listenTo(createArticleForm);
			calloutCtrl = new CloseableCalloutWindowController(ureq, getWindowControl(),
					createArticleForm.getInitialComponent(), createLink, "", true, null);
			listenTo(calloutCtrl);
			calloutCtrl.activate();	
		} else if (source == versioningContent) {
			//nothing to do
		} else if (source == editContent) {
			//nothing to do
		} else if (source == closePreviewButton){
			editContent.remove(wikiVersionDisplayComp);
		} else if (source == revertVersionButton) {
			wikiEditForm.setPage(selectedPage);
			tabs.setSelectedPane(2);
			tryToSetEditLock(page, ureq, ores);
		} else if(source instanceof Link && "select-page".equals(command)) {
			String name = source.getComponentName();
			page = openPage(ureq, name, wiki);
		}
		
		//set recent page id to the page currently used
		if(page != null) {
			this.pageId = page.getPageId();
		}
	}
	
	private void selectTab(UserRequest ureq, String command, String compName, WikiPage page, Wiki wiki) {
		// first release a potential lock on this page. only when the edit tab is acitve
		// a lock will be created. in all other cases it is save to release an existing lock
		doReleaseEditLock();
		if (command.equals(TabbedPaneChangedEvent.TAB_CHANGED)) {
			updatePageContext(ureq, page);
		}
		
		if (command.equals(TabbedPaneChangedEvent.TAB_CHANGED) && compName.equals("vc_article")) {
			/***********************************************************************
			 * tabbed pane change to article
			 **********************************************************************/
			// if(page.getContent().equals("")) wikiArticleComp.setVisible(false);
			// FIXME:guido: ... && comp == articleContent)) etc.
		} else if (command.equals(TabbedPaneChangedEvent.TAB_CHANGED) && compName.equals("vc_edit")) {
			/***********************************************************************
			 * tabbed pane change to edit tab
			 **********************************************************************/
			wikiEditForm.resetUpdateComment();
			editContent.contextPut("linkList", wiki.getListOfAllPageNames());
			editContent.contextPut("fileList", wiki.getMediaFileList());
			// try to edit acquire lock for this page
			tryToSetEditLock(page, ureq, ores);
		} else if (command.equals(TabbedPaneChangedEvent.TAB_CHANGED) && compName.equals("vc_versions")) {
			/***********************************************************************
			 * tabbed pane change to versioning tab
			 **********************************************************************/
			versioningTableModel = new HistoryTableDateModel(wiki.getHistory(page), getTranslator());
			removeAsListenerAndDispose(versioningTableCtr);
			versioningTableCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator());
			listenTo(versioningTableCtr);
			versioningTableModel.addColumnDescriptors(versioningTableCtr);
			versioningTableCtr.setTableDataModel(versioningTableModel);
			versioningTableCtr.modelChanged();
			versioningTableCtr.setSortColumn(1, false);
			versioningContent.put("versions", versioningTableCtr.getInitialComponent());
			versioningContent.contextPut("diffs", diffs);
		} else if (command.equals(TabbedPaneChangedEvent.TAB_CHANGED) && compName.equals("vc_discuss")) {
			/***********************************************************************
			 * tabbed pane change to discussion tab
			 **********************************************************************/
			Forum forum = null;
			if (page.getForumKey() > 0) {
				forum = ForumManager.getInstance().loadForum(Long.valueOf(page.getForumKey()));
			}
			if(forum == null) {
				forum = ForumManager.getInstance().addAForum();
				page.setForumKey(forum.getKey().longValue());
				WikiManager.getInstance().updateWikiPageProperties(ores, page);
			}
			
			boolean isModerator = securityCallback.mayModerateForum();				
			ForumCallback forumCallback = new WikiForumCallback(ureq.getUserSession().getRoles().isGuestOnly(), isModerator, subsContext);
			
			ContextEntry ce = BusinessControlFactory.getInstance().createContextEntry(forum);
			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ce, getWindowControl());
			
			removeAsListenerAndDispose(forumController);
			forumController = new ForumController(ureq, bwControl, forum, forumCallback, false);
			listenTo(forumController);
			discussionContent.put("articleforum", forumController.getInitialComponent());
		}

		OLATResourceable pageRes = OresHelper.createOLATResourceableTypeWithoutCheck("path=" + page.getPageName());
		WindowControl wc = addToHistory(ureq, pageRes, null);
		OLATResourceable tabOres = tabs.getTabResource();
		addToHistory(ureq, tabOres, null, wc, true);
	}
	
	private WikiPage openPage(UserRequest ureq, String name, Wiki wiki) {
		WikiPage page = wiki.getPage(name, true);
		page.incrementViewCount();
		updatePageContext(ureq, page);
		Link pageLink = LinkFactory.createToolLink(page.getPageName(), "select-page", page.getPageName(), this);
		breadcrumpDropdown.addComponent(pageLink);
		setTabsEnabled(true);
		tabs.setSelectedPane(0);
		return page;
	}
	
	private WikiPage openIndexPage(UserRequest ureq, Wiki wiki) {
		WikiPage page = wiki.getPage(WikiPage.WIKI_INDEX_PAGE, true);
		page.incrementViewCount();
		Link pageLink = LinkFactory.createToolLink(page.getPageName(), "select-page", page.getPageName(), this);
		breadcrumpDropdown.addComponent(pageLink);
		updatePageContext(ureq, page);
		setTabsEnabled(true);
		tabs.setSelectedPane(0);
		addToHistory(ureq, OresHelper.createOLATResourceableTypeWithoutCheck("index"), null);
		return page;
	}
	
	private void openLastChangesPage(UserRequest ureq, Wiki wiki) {
		WikiPage recentChanges = wiki.getPage(WikiPage.WIKI_RECENT_CHANGES_PAGE);
		recentChanges.setContent(translate("nav.changes.desc")+wiki.getRecentChanges(ureq.getLocale()));
		clearPortfolioLink();
		articleContent.contextPut("page", recentChanges);
		wikiArticleComp.setWikiContent(recentChanges.getContent());
		setTabsEnabled(false);
		tabs.setSelectedPane(0);
		addToHistory(ureq, OresHelper.createOLATResourceableTypeWithoutCheck("lastChanges"), null);
	}
	
	private void openAtoZPage(UserRequest ureq, Wiki wiki) {
		WikiPage a2zPage = wiki.getPage(WikiPage.WIKI_A2Z_PAGE);
		articleContent.contextPut("page", a2zPage);
		a2zPage.setContent(translate("nav.a-z.desc")+wiki.getAllPageNamesSorted());
		wikiArticleComp.setWikiContent(a2zPage.getContent());
		clearPortfolioLink();
		setTabsEnabled(false);
		tabs.setSelectedPane(0);
		addToHistory(ureq, OresHelper.createOLATResourceableTypeWithoutCheck("az"), null);
	}


	private void deliverMediaFile(UserRequest ureq, String command) {
		VFSLeaf leaf = (VFSLeaf)WikiManager.getInstance().getMediaFolder(ores).resolve(command);
		if(leaf == null) showError("wiki.error.file.not.found");
		else ureq.getDispatchResult().setResultingMediaResource(new VFSMediaResource(leaf));
	}


	private void refreshTableDataModel(UserRequest ureq, Wiki wiki) {
		
		removeAsListenerAndDispose(mediaTableCtr);
		mediaTableCtr = new TableController(new TableGuiConfiguration(), ureq, getWindowControl(), getTranslator());
		listenTo(mediaTableCtr);

		mediaTableCtr.setMultiSelect(true);
		mediaTableCtr.addMultiSelectAction(ACTION_DELETE_MEDIAS, ACTION_DELETE_MEDIAS);
		
		List<VFSItem> filelist = wiki.getMediaFileListWithMetadata();
		Map<String,MediaFileElement> files = new HashMap<String,MediaFileElement>();
		for (Iterator<VFSItem> iter = filelist.iterator(); iter.hasNext();) {
			VFSLeaf elem = (VFSLeaf) iter.next();
			if(elem.getName().endsWith(METADATA_SUFFIX)) {  //*.metadata files go here
				Properties p = new Properties();
				try {
					p.load(elem.getInputStream());
					MediaFileElement mediaFileElement = new MediaFileElement(elem.getName(), p.getProperty(MEDIA_FILE_CREATED_BY), p.getProperty(MEDIA_FILE_CREATIONDATE));
					mediaFileElement.setDeletedBy(p.getProperty(MEDIA_FILE_DELETED_BY));
					mediaFileElement.setDeletionDate(p.getProperty(MEDIA_FILE_DELETIONDATE));
					files.put(p.getProperty(MEDIA_FILE_FILENAME), mediaFileElement);
				} catch (IOException e) {
					throw new OLATRuntimeException("Could'n read properties from media file: "+elem.getName(), e);
				}
			}
		}
		for (Iterator<VFSItem> iter = filelist.iterator(); iter.hasNext();) {
			VFSLeaf elem = (VFSLeaf) iter.next();
			if(!elem.getName().endsWith(METADATA_SUFFIX)){
				if(!files.containsKey(elem.getName())) {
					//legacy file without metadata
					files.put(elem.getName(), new MediaFileElement(elem.getName(), 0, elem.getLastModified()));
				} else {
					//file with metadata, update name
					MediaFileElement element = files.get(elem.getName());
					element.setFileName(elem.getName());
				}
			}
		}
		
		mediaFilesTableModel = new MediaFilesTableModel(new ArrayList<MediaFileElement>(files.values()), getTranslator());
		mediaFilesTableModel.addColumnDescriptors(mediaTableCtr);
		mediaTableCtr.setTableDataModel(mediaFilesTableModel);
		mediaTableCtr.setSortColumn(3, false);
		mediaTableCtr.modelChanged();
	}

	private WikiPage handleRequestNewPageEvent(UserRequest ureq, RequestNewPageEvent requestPage, Wiki wiki) {
		if(!securityCallback.mayEditAndCreateArticle()){
			if (ureq.getUserSession().getRoles().isGuestOnly()) showInfo("guest.no.edit");
			showInfo("no.edit");
			return null;
		}
		// first check if no page exist 
		WikiPage page = wiki.findPage(requestPage.getCommand());
		if (page.getPageName().equals(Wiki.NEW_PAGE)) {
			// create new page
			log.debug("Page does not exist, create a new one...");
			page = new WikiPage(requestPage.getCommand());
			page.setCreationTime(System.currentTimeMillis());
			page.setInitalAuthor(ureq.getIdentity().getKey().longValue());
			wiki.addPage(page);
			WikiManager.getInstance().saveWikiPage(ores, page, false, wiki);
			log.debug("Safe new page=" + page);
			log.debug("Safe new pageId=" + page.getPageId());
		} 
		updatePageContext(ureq, page);
		doReleaseEditLock();
		tryToSetEditLock(page, ureq, ores);
		tabs.setSelectedPane(2);
		return page;
	}
	
	@Override
	public void event(UserRequest ureq, Controller source, Event event) {
		Wiki wiki = getWiki();
		if(wiki == null) {
			mainPanel.setContent(createVelocityContainer("deleted"));
			return;
		}
		//reload page from cache
		WikiPage page = wiki.getPage(pageId, true);
		//set recent page id to the page currently used
		this.pageId = page.getPageId();
		
		if(event instanceof TreeEvent) {
			TreeEvent te = (TreeEvent)event;
			String nodeId = te.getNodeId();
			if(navAZNode.getIdent().equals(nodeId)) {
				openAtoZPage(ureq, wiki);
			} else if(navChangesNode.getIdent().equals(nodeId)) {
				openLastChangesPage(ureq, wiki);
			} else if(navMainPageNode.getIdent().equals(nodeId)) {
				page = openIndexPage(ureq, wiki);
			} else if(wikiMenuNode.getIdent().equals(nodeId)) {
				page = openPage(ureq, WikiPage.WIKI_MENU_PAGE, wiki);
			} else {
				TreeNode node = wikiMenuModel.getNodeById(nodeId);
				if(node != null && node.getUserObject() instanceof String) {
					String link = (String)node.getUserObject();
					page = openPage(ureq, link, wiki);
				}
			}
			
			if(page != null) {
				this.pageId = page.getPageId();
			}
		} else if (source == versioningTableCtr) {
			/*************************************************************************
			 * history table events
			 ************************************************************************/
			if (event.getCommand().equals(Table.COMMANDLINK_ROWACTION_CLICKED)) {
				TableEvent te = (TableEvent) event;
				if (te.getActionId().equals(ACTION_COMPARE)) {
					selectedPage = versioningTableModel.getObject(te.getRowId());
					diffs = wiki.getDiff(page, selectedPage.getVersion() - 1, selectedPage.getVersion());
					versioningContent.contextPut("diffs", diffs);
					versioningContent.remove(wikiVersionDisplayComp);
					versioningContent.contextPut("page", selectedPage);
				} else if (te.getActionId().equals(ACTION_SHOW)) {
					versioningContent.contextRemove("diffs");
					selectedPage = versioningTableModel.getObject(te.getRowId());
					selectedPage = wiki.loadVersion(selectedPage, selectedPage.getVersion());
					wikiVersionDisplayComp.setWikiContent(selectedPage.getContent());
					wikiVersionDisplayComp.setImageMapperUri(ureq, wikiContainer);
					versioningContent.put("versionDisplay", wikiVersionDisplayComp);
					versioningContent.contextPut("page", selectedPage);
				}
			}
		} else if (source == wikiUploadFileCtr) {
			if(event.getCommand().equals(FolderEvent.UPLOAD_EVENT)) {
				FolderEvent fEvent = (FolderEvent)event;
				createMediaMetadataFile(fEvent.getFilename(), ureq.getIdentity().getKey());
				editContent.contextPut("fileList", wiki.getMediaFileList());
			}
			cmc.deactivate();
			cleanUp();
		} else if (source == removePageDialogCtr) {
			if (DialogBoxUIFactory.isOkEvent(event)) {
				wiki.removePage(page);
				breadcrumpDropdown.removeComponent(page.getPageName());
				WikiManager.getInstance().deleteWikiPage(ores, page);
				page = wiki.getPage(WikiPage.WIKI_INDEX_PAGE);
				updatePageContext(ureq, page);
				tabs.setSelectedPane(0);
			}
		} else if (source == mediaTableCtr) {
			if (event.getCommand().equals(Table.COMMANDLINK_ROWACTION_CLICKED)) {
				TableEvent te = (TableEvent) event;
				if (te.getActionId().equals(ACTION_DELETE_MEDIA)) {
					List<MediaFileElement> list = new ArrayList<MediaFileElement>(1);
					list.add(mediaFilesTableModel.getObject(te.getRowId()));
					deleteMediaFile(list, ureq);
				} else if (te.getActionId().equals(ACTION_SHOW_MEDIA)) {
					// show a selected file from the media folder
					MediaFileElement element = mediaFilesTableModel.getObject(te.getRowId());
					if (isImage(element.getFilename()) ) { // show images inline as modal overlay
						imageDisplay.contextPut("mediaElement", element);
						imageDisplay.contextPut("imageUri", wikiArticleComp.getImageBaseUri());
						
						removeAsListenerAndDispose(cmc);
						cmc = new CloseableModalController(getWindowControl(), translate("close"), imageDisplay);
						listenTo(cmc);
						
						cmc.activate();
					} else {
						deliverMediaFile(ureq, element.getFilename());
					}
				}
			} else if (event.getCommand().equals(Table.COMMAND_MULTISELECT)) {
				TableMultiSelectEvent tmse = (TableMultiSelectEvent) event;
				if (tmse.getAction().equals(ACTION_DELETE_MEDIAS)) {
						deleteMediaFile(mediaFilesTableModel.getObjects(tmse.getSelection()), ureq);
						editContent.contextPut("fileList", wiki.getMediaFileList());
				}
			}
		} else if (source == archiveWikiDialogCtr) {
			if (DialogBoxUIFactory.isOkEvent(event)) {
				WikiToCPResource rsrc = new WikiToCPResource(ores, getIdentity(), getTranslator());
				ureq.getDispatchResult().setResultingMediaResource(rsrc);
			}
		} else if (source == createArticleForm) {
			calloutCtrl.deactivate();
			
			String query = createArticleForm.getQuery();
			if (!StringHelper.containsNonWhitespace(query)) {
				query = WikiPage.WIKI_INDEX_PAGE;
			}
			page = wiki.findPage(query);
			pageId = page.getPageId();
			if (page.getPageName().equals(Wiki.NEW_PAGE)) {
				setTabsEnabled(false);
			}
			page.incrementViewCount();
			updatePageContext(ureq, page);
			if(!page.getPageName().startsWith("O_")) {
				Link pageLink = LinkFactory.createToolLink(page.getPageName(), "select-page", page.getPageName(), this);
				breadcrumpDropdown.addComponent(pageLink);
			}
			tabs.setSelectedPane(0);
		} else if (source == wikiEditForm) {
			//set recent page id to the page currently used
			this.pageId = page.getPageId();
			
			boolean wantPreview = false;
			boolean wantSave    = false;
			boolean wantClose   = false;
			if (event == Event.CANCELLED_EVENT) {
				wantClose = true;
			} else if (event == Event.DONE_EVENT) {
				wantSave = true;
			} else if (event.getCommand().equals("save.and.close")) {
				wantClose = true;
				wantSave = true;
				event = Event.DONE_EVENT;
			} else if (event.getCommand().equals("preview")) {
				wantPreview = true;
				event = Event.DONE_EVENT;
			} else if(event.getCommand().equals("delete.page")) {
				String msg = translate("question", page.getPageName());
				removePageDialogCtr = activateOkCancelDialog(ureq, null, msg, removePageDialogCtr);
				return;
			} else if(event.getCommand().equals("media.upload")) {
				doUploadFiles(ureq);
				return;
			} else if(event.getCommand().equals("manage.media")) {
				doManageMedias(ureq, wiki);
				return;
			}

			boolean dirty = !wikiEditForm.getWikiContent().equals(page.getContent());	
			if (wantPreview) {
				WikiPage preview = new WikiPage("temp");
				preview.setContent(wikiEditForm.getWikiContent());
				wikiVersionDisplayComp.setWikiContent(preview.getContent());
				editContent.put("versionDisplay", wikiVersionDisplayComp);
			}

			if (wantSave && dirty) {
				editContent.contextPut("isDirty", Boolean.valueOf(false));
				page.setContent(wikiEditForm.getWikiContent());
				page.setModifyAuthor(getIdentity().getKey().longValue());
				page.setUpdateComment(wikiEditForm.getUpdateComment());
				if(page.getInitalAuthor() == 0) page.setInitalAuthor(getIdentity().getKey().longValue());
				//menu page only editable by admin and owner set new content if changed
				if (page.getPageName().equals(WikiPage.WIKI_MENU_PAGE)) {
					updateWikiMenu(wiki);
				}
				WikiManager.getInstance().saveWikiPage(ores, page, true, wiki);
				// inform subscription context about changes
				NotificationsManager.getInstance().markPublisherNews(subsContext, ureq.getIdentity(), true);

				updatePageContext(ureq, page);
			}
			
			if (dirty && wantPreview && !wantSave) {
				//wikiEditForm.setDirty(true);
				editContent.contextPut("isDirty", Boolean.valueOf(dirty));
			}

			if (wantClose) {
				tabs.setSelectedPane(0);
				doReleaseEditLock();
				return;
			}
		}
	}
	
	private void cleanUp() {
		removeAsListenerAndDispose(cmc);
		removeAsListenerAndDispose(wikiUploadFileCtr);

		cmc = null;
		wikiUploadFileCtr = null;
	}
	
	private boolean isImage(String filename) {
		String fileSuffix = filename.substring(filename.lastIndexOf(".")+1, filename.length()).toLowerCase();
		if (fileSuffix.equals("jpg")) return true;
		if (fileSuffix.equals("jpeg")) return true;
		if (fileSuffix.equals("gif")) return true;
		if (fileSuffix.equals("png")) return true;
		return false;
	}


	private void createMediaMetadataFile(String filename, Long author) {
		VFSContainer mediaFolder = WikiManager.getInstance().getMediaFolder(ores);
		//only create metadatafile if base file exists
		if ((VFSLeaf)mediaFolder.resolve(filename) != null) {
			//metafile may exists when files get overwritten
			VFSLeaf metaFile = (VFSLeaf)mediaFolder.resolve(filename+METADATA_SUFFIX);
	    if (metaFile == null) {
	        // metafile does not exist => create one
	      metaFile = mediaFolder.createChildLeaf(filename+METADATA_SUFFIX);
	    } 
			Properties p = new Properties();
			p.setProperty(MEDIA_FILE_FILENAME, filename);
			p.setProperty(MEDIA_FILE_CREATIONDATE, String.valueOf(System.currentTimeMillis()));
			p.setProperty(MEDIA_FILE_CREATED_BY, String.valueOf(author));
			try {
				p.store(metaFile.getOutputStream(false), "wiki media files meta properties");
			} catch (IOException e) {
				throw new OLATRuntimeException(WikiManager.class, "failed to save media files properties for file: " + filename +" and olatresource: " + ores.getResourceableId(), e);
			}
		}
	}


	private void deleteMediaFile(List<MediaFileElement> toDelete, UserRequest ureq) {
		for (Iterator<MediaFileElement> iter = toDelete.iterator(); iter.hasNext();) {
			VFSContainer mediaFolder = WikiManager.getInstance().getMediaFolder(ores);
			MediaFileElement element = iter.next();
			if(log.isDebug()) log.debug("deleting media file: "+element.getFilename());
			if(!element.getFilename().endsWith(METADATA_SUFFIX)) {
				VFSLeaf file = (VFSLeaf)mediaFolder.resolve(element.getFilename());
				if (file != null) {
					file.delete();
					VFSLeaf metadata = (VFSLeaf)mediaFolder.resolve(element.getFilename()+METADATA_SUFFIX);
					if(metadata != null) {
						Properties p = new Properties();
						try {
							p.load(metadata.getInputStream());
							p.setProperty(MEDIA_FILE_DELETIONDATE, String.valueOf(System.currentTimeMillis()));
							p.setProperty(MEDIA_FILE_DELETED_BY, String.valueOf(ureq.getIdentity().getKey()));
							OutputStream os = metadata.getOutputStream(false);
							p.store(os, "wiki media file meta properties");
							os.close();
						} catch (IOException e) {
							throw new OLATRuntimeException("Could'n read properties from media file: "+metadata.getName(), e);
						}
					}
				}
			}
		}
		getWindowControl().pop();
	}

	private void setTabsEnabled(boolean enable) {
		tabs.setEnabled(1,enable);
		if(enable && securityCallback.mayEditAndCreateArticle()) {
			tabs.setEnabled(2, enable);
		} else {
			tabs.setEnabled(2, false);
		}
		tabs.setEnabled(3,enable);
	}
	
	private void doUploadFiles(UserRequest ureq) {
		removeAsListenerAndDispose(cmc);
		removeAsListenerAndDispose(wikiUploadFileCtr);
		
		wikiUploadFileCtr = new WikiFileUploadController(ureq, getWindowControl(), WikiManager.getInstance().getMediaFolder(ores));
		listenTo(wikiUploadFileCtr);
		
		String title = translate("media.upload");
		cmc = new CloseableModalController(getWindowControl(), translate("close"), wikiUploadFileCtr.getInitialComponent(),
				true, title, true);
		listenTo(cmc);
		cmc.activate();
	}
	
	private void doManageMedias(UserRequest ureq, Wiki wiki) {
		if(wiki.getMediaFileListWithMetadata().size() > 0){
			mediaMgntContent = createVelocityContainer("media");
			refreshTableDataModel(ureq, wiki);
			mediaMgntContent.put("mediaMgmtTable", mediaTableCtr.getInitialComponent());
			
			removeAsListenerAndDispose(cmc);
			cmc = new CloseableModalController(getWindowControl(), translate("close"), mediaMgntContent, true, translate("manage.media"));
			listenTo(cmc);
			
			cmc.activate();
		}
	}

	@Override
	protected void doDispose() {
		if(wikiArticleComp != null) {
			wikiArticleComp.dispose();
		}
		if(wikiVersionDisplayComp != null) {
			wikiVersionDisplayComp.dispose();
		}
		
		ThreadLocalUserActivityLogger.log(LearningResourceLoggingAction.LEARNING_RESOURCE_CLOSE, getClass());
		doReleaseEditLock();
	}

	@Override
	public Controller cloneController(UserRequest ureq, WindowControl wControl) {
		return WikiManager.getInstance().createWikiMainController(ureq, wControl, ores, securityCallback, null);
	}
	
	private void doReleaseEditLock() {
		if (lockEntry != null && lockEntry.isSuccess()) {
			CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(lockEntry);
			lockEntry = null;
		}
	}
	
	/**
	 * Try to aquire a lock on the page
	 * @param ureq
	 * @param ores
	 */
	private void tryToSetEditLock(WikiPage page, UserRequest ureq, OLATResourceable ores) {
		lockEntry = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(ores, ureq.getIdentity(), page.getPageName());
		editContent.contextPut("lockEntry", lockEntry);
	}
	
	/**
	 * update depended velocity contexts and componetens with latest globally used page
	 *
	 */
	private void updatePageContext(UserRequest ureq, WikiPage page) {

		if (page.getPageName().equals(WikiPage.WIKI_ERROR)) {
			wikiArticleComp.setWikiContent(translate(page.getContent()));
		} else {
			wikiArticleComp.setWikiContent(page.getContent());
		}
		
		wikiEditForm.setPage(page);
		diffs.clear();
		content.contextPut("page", page);
		
		articleContent.contextPut("page", page);
		discussionContent.contextPut("page", page);
		
		editContent.remove(wikiVersionDisplayComp);
		editContent.contextPut("page", page);
		
		versioningContent.remove(wikiVersionDisplayComp);
		versioningContent.contextPut("page", page);
		
		boolean userIsPageCreator = getIdentity().getKey().equals(page.getInitalAuthor());
		if(userIsPageCreator) {
			String subPath = page.getPageName();
			String businessPath = getWindowControl().getBusinessControl().getAsString();
			businessPath += "[page=" + subPath + ":0]";
			
			OLATResourceable wikiRes = OresHelper.createOLATResourceableInstance(WikiArtefact.ARTEFACT_TYPE, ores.getResourceableId());
			Controller ePFCollCtrl = EPUIFactory.createArtefactCollectWizzardController(ureq, getWindowControl(), wikiRes, businessPath);
			if (ePFCollCtrl != null) {
				navigationContent.put("portfolio-link", ePFCollCtrl.getInitialComponent());
			}			
		} else {
			clearPortfolioLink();
		}
		
		OLATResourceable pageRes = OresHelper.createOLATResourceableInstanceWithoutCheck("path=" + page.getPageName(), 0l);
		addToHistory(ureq, pageRes, null);
	}
	
	private void clearPortfolioLink(){
		content.put("portfolio-link", new Panel("empty"));
	}
	
	private Wiki getWiki(){
		return WikiManager.getInstance().getOrLoadWiki(ores);
	}
}