/**
* 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.
* <p>
*/
package org.olat.modules.wiki;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.olat.core.commons.modules.bc.FileUploadController;
import org.olat.core.commons.modules.bc.FolderConfig;
import org.olat.core.commons.modules.bc.FolderEvent;
import org.olat.core.commons.services.search.ui.SearchServiceUIFactory;
import org.olat.core.commons.services.search.ui.SearchServiceUIFactory.DisplayOption;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.form.Form;
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.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.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.CloseableModalController;
import org.olat.core.gui.control.generic.modal.DialogBoxController;
import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
import org.olat.core.gui.control.state.ControllerState;
import org.olat.core.id.Identity;
import org.olat.core.id.OLATResourceable;
import org.olat.core.id.context.BusinessControlFactory;
import org.olat.core.id.context.ContextEntry;
import org.olat.core.logging.AssertException;
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.service.ServiceFactory;
import org.olat.core.util.coordinate.CoordinatorManager;
import org.olat.core.util.coordinate.LockResult;
import org.olat.core.util.notifications.ContextualSubscriptionController;
import org.olat.core.util.notifications.NotificationsManager;
import org.olat.core.util.notifications.PublisherData;
import org.olat.core.util.notifications.SubscriptionContext;
import org.olat.core.util.resource.OresHelper;
import org.olat.core.util.vfs.Quota;
import org.olat.core.util.vfs.VFSContainer;
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.ForumManager;
import org.olat.modules.fo.ForumUIFactory;
import org.olat.modules.wiki.gui.components.wikiToHtml.ErrorEvent;
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.versioning.HistoryTableDateModel;
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 {
OLog log = Tracing.createLoggerFor(this.getClass());
private TabbedPane tabs;
private WikiPage selectedPage;
private String pageId;
private VFSContainer wikiContainer;
private OLATResourceable ores;
private VelocityContainer articleContent, navigationContent, discussionContent, editContent, content, versioningContent, mediaMgntContent, imageDisplay;
private WikiEditArticleForm wikiEditForm;
private WikiMarkupComponent wikiMenuComp, wikiArticleComp, wikiVersionDisplayComp;
private ContextualSubscriptionController cSubscriptionCtrl;
private TableController versioningTableCtr;
private HistoryTableDateModel versioningTableModel;
private FileUploadController fileUplCtr;
private BreadCrumbController breadCrumpCtr;
private DialogBoxController removePageDialogCtr, archiveWikiDialogCtr;
private List diffs = new ArrayList(2);
private Identity ident;
private SubscriptionContext subsContext;
private LockResult lockEntry;
private Link archiveLink, closePreviewButton, deletePageButton, manageMediaButton, toMainPageLink, a2zLink, changesLink, editMenuButton, revertVersionButton;
private TableController mediaTableCtr;
private MediaFilesTableModel mediaFilesTableModel;
private TableGuiConfiguration tableConfig;
private WikiSecurityCallback securityCallback;
private WikiArticleSearchForm searchArticleForm;
private Controller searchCtrl;
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_PAGE = "delete.page";
private static final String ACTION_MANAGE_MEDIA = "manage.media";
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";
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();
if (securityCallback == null) throw new AssertException("WikiSecurityCallback is null! You must provide an security callback!", null);
this.ident = ureq.getIdentity();
WikiPage page = null;
Wiki wiki = getWiki();
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);
this.pageId = page.getPageId();
WikiPage menuPage = getWiki().getPage(WikiPage.WIKI_MENU_PAGE);
tabs = new TabbedPane("userTabP", ureq.getLocale());
tabs.addListener(this);
// init the tabbed pane container
content = createVelocityContainer("index");
// add a histroy ctr that displays visited pages
breadCrumpCtr = new BreadCrumbController(ureq, getWindowControl());
breadCrumpCtr.addControllerListener(this);
breadCrumpCtr.addLink(WikiPage.WIKI_INDEX_PAGE, WikiPage.WIKI_INDEX_PAGE);
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);
content.put("subscription", cSubscriptionCtrl.getInitialComponent());
}
//TODO:gs:a allow to jump into certain wiki page from email link
/***************************************************************************
* navigation container
**************************************************************************/
navigationContent = createVelocityContainer("navigation");
toMainPageLink = LinkFactory.createLink("navigation.mainpage", navigationContent, this);
a2zLink = LinkFactory.createLink("navigation.a-z", navigationContent, this);
changesLink = LinkFactory.createLink("navigation.changes", navigationContent, this);
archiveLink = LinkFactory.createLink("archive.wiki", navigationContent, this);
archiveLink.setTitle("archive.wiki.title");
if (this.securityCallback.mayEditWikiMenu()) editMenuButton = LinkFactory.createButtonSmall("edit.menu", navigationContent, this);
navigationContent.put("breadcrumb", breadCrumpCtr.getInitialComponent());
content.put("navigation", navigationContent);
searchArticleForm = new WikiArticleSearchForm(ureq, getWindowControl());
searchArticleForm.addControllerListener(this);
navigationContent.put("searchArticleForm", searchArticleForm.getInitialComponent());
//search
SearchServiceUIFactory searchServiceUIFactory = (SearchServiceUIFactory)ServiceFactory.getService(SearchServiceUIFactory.class);
searchCtrl = searchServiceUIFactory.createInputController(ureq, wControl, DisplayOption.STANDARD_TEXT, null);
listenTo(searchCtrl);
navigationContent.put("search_article", searchCtrl.getInitialComponent());
// attach menu
//FIXME:gs:a pass only ores to component to make shure they have the same wiki instance
wikiMenuComp = new WikiMarkupComponent("wikiArticle", ores, 0);
wikiMenuComp.addListener(this);
// load the menu page and set the image mapper
wikiMenuComp.setWikiContent(menuPage.getContent());
wikiMenuComp.setImageMapperUri(ureq, wikiContainer);
navigationContent.put("wikiMenu", wikiMenuComp);
// 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");
wikiArticleComp = new WikiMarkupComponent("wikiArticle", ores, 300);
wikiArticleComp.addListener(this);
wikiArticleComp.setImageMapperUri(ureq, wikiContainer);
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);
deletePageButton = LinkFactory.createButtonSmall(ACTION_DELETE_PAGE, editContent, this);
manageMediaButton = LinkFactory.createButtonSmall(ACTION_MANAGE_MEDIA, editContent, this);
editContent.contextPut("isGuest", Boolean.valueOf(ureq.getUserSession().getRoles().isGuestOnly()));
wikiEditForm = new WikiEditArticleForm("wikieditform", getTranslator(), page);
wikiEditForm.addListener(this);
editContent.contextPut("editformid", "ofo_"+wikiEditForm.hashCode());
editContent.put("editForm", wikiEditForm);
JSAndCSSComponent js = new JSAndCSSComponent("js", this.getClass(), new String[] { "wiki-script.js" }, null, false);
content.put("js", js);
// FIXME:gs:a FileUploadCtr should accept vfsContainers instead of
// OLATrootfolderimpl. Refactor it!!!!!!!
fileUplCtr = new FileUploadController(getWindowControl(), WikiManager.getInstance().getMediaFolder(ores), ureq, (int)FolderConfig.getLimitULKB(), Quota.UNLIMITED, null, false);
fileUplCtr.addControllerListener(this);
editContent.put("fileUplCtr", fileUplCtr.getInitialComponent());
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);
}
doReleaseEditLock();
updatePageContext(page);
setTabsEnabled(true); //apply security settings to tabs by may disabling edit tab
putInitialPanel(content);
//set pageId to the latest used
this.pageId = page.getPageId();
}
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();
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) this.pageId = page.getPageId();
}
if (source == content) {
// noting yet
} else if (source == tabs) {
/*************************************************************************
* tabbed pane events
************************************************************************/
// 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();
TabbedPaneChangedEvent tabEvent = (TabbedPaneChangedEvent) event;
Component comp = tabEvent.getNewComponent();
String compName = comp.getComponentName();
if (command.equals(TabbedPaneChangedEvent.TAB_CHANGED)) {
updatePageContext(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("mayDeleteArticle", Boolean.valueOf(ident.getKey().equals(Long.valueOf(page.getInitalAuthor() )) || securityCallback.mayEditWikiMenu() ));
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());
versioningTableCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator(), this);
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().addAForum();
page.setForumKey(forum.getKey().longValue());
WikiManager.getInstance().updateWikiPageProperties(ores, page);
}
forum = ForumManager.getInstance().loadForum(Long.valueOf(page.getForumKey()));
// TODO enhance forum callback with subscription stuff
boolean isModerator = securityCallback.mayModerateForum();
ForumCallback forumCallback = new WikiForumCallback(ureq.getUserSession().getRoles().isGuestOnly(), isModerator);
// calculate the new businesscontext for the coursenode being called.
//FIXME:pb:mannheim discussion should not be "this.ores" -> may be the "forum" should go in here.
//
ContextEntry ce = BusinessControlFactory.getInstance().createContextEntry(forum);
WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ce, getWindowControl());
discussionContent.put("articleforum", ForumUIFactory.getStandardForumController(ureq, bwControl, forum, forumCallback).getInitialComponent());
}
} else if (source == wikiEditForm) {
/*************************************************************************
* edit form events
************************************************************************/
if (event == Form.EVNT_VALIDATION_OK) {
boolean dirty = !wikiEditForm.getWikiContent().equals(page.getContent());
// fosm_2 is preview button
if (ureq.getParameter("olat_fosm_2") != null) {
WikiPage preview = new WikiPage("temp");
preview.setContent(wikiEditForm.getWikiContent());
wikiVersionDisplayComp.setWikiContent(preview.getContent());
editContent.put("versionDisplay", wikiVersionDisplayComp);
editContent.contextPut("isDirty", Boolean.valueOf(dirty));
} else { //pressed save button
// only save new version if content changed
if (dirty) {
editContent.contextPut("isDirty", Boolean.valueOf(false));
page.setContent(wikiEditForm.getWikiContent());
page.setModifyAuthor(ident.getKey().longValue());
page.setUpdateComment(wikiEditForm.getUpdateComment());
if(page.getInitalAuthor() == 0) page.setInitalAuthor(ident.getKey().longValue());
//menu page only editable by admin and owner set new content if changed
if (page.getPageName().equals(WikiPage.WIKI_MENU_PAGE)) wikiMenuComp.setWikiContent(page.getContent());
WikiManager.getInstance().saveWikiPage(ores, page, true, wiki);
// inform subscription context about changes
NotificationsManager.getInstance().markPublisherNews(subsContext, ureq.getIdentity());
//dirt and save and close clicked
}
if (ureq.getParameter("olat_fosm_1") != null) {
tabs.setSelectedPane(0);
doReleaseEditLock();
updatePageContext(page);
}
// remove the preview if save button pressed
editContent.remove(wikiVersionDisplayComp);
}
} else if (event == Form.EVNT_FORM_CANCELLED) {
tabs.setSelectedPane(0);
doReleaseEditLock();
}
} else if (source == wikiArticleComp || source == wikiMenuComp) {
/*************************************************************************
* wiki component events
************************************************************************/
if (event instanceof RequestPageEvent) {
RequestPageEvent pageEvent = (RequestPageEvent) event;
page = wiki.getPage(pageEvent.getCommand(), true);
page.incrementViewCount();
updatePageContext(page);
breadCrumpCtr.addLink(page.getPageName(), page.getPageName());
tabs.setSelectedPane(0);
} else if (event instanceof RequestNewPageEvent) {
page = handleRequestNewPageEvent(ureq, (RequestNewPageEvent) event);
} else if (event instanceof ErrorEvent) {
showWarning(event.getCommand());
} else if (event instanceof RequestMediaEvent) {
deliverMediaFile(ureq, event.getCommand());
} else if (event instanceof RequestImageEvent) {
WikiPage imagePage = new WikiPage(event.getCommand());
imagePage.setContent("[[Image:"+event.getCommand()+"]]");
articleContent.contextPut("page", imagePage);
wikiArticleComp.setWikiContent(imagePage.getContent());
setTabsEnabled(false);
}
} 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(page);
tabs.setSelectedPane(2);
}
} else if (source == toMainPageLink){ // home link
page = wiki.getPage(WikiPage.WIKI_INDEX_PAGE, true);
page.incrementViewCount();
breadCrumpCtr.addLink(page.getPageName(), page.getPageName());
updatePageContext(page);
tabs.setSelectedPane(0);
} else if (source == a2zLink){
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());
setTabsEnabled(false);
setState(WikiPage.WIKI_A2Z_PAGE);
tabs.setSelectedPane(0);
} else if (source == changesLink){
WikiPage recentChanges = wiki.getPage(WikiPage.WIKI_RECENT_CHANGES_PAGE);
recentChanges.setContent(translate("nav.changes.desc")+wiki.getRecentChanges(ureq.getLocale()));
articleContent.contextPut("page", recentChanges);
wikiArticleComp.setWikiContent(recentChanges.getContent());
setTabsEnabled(false);
tabs.setSelectedPane(0);
} else if (source == editMenuButton){
page = wiki.getPage(WikiPage.WIKI_MENU_PAGE);
editContent.contextPut("linkList", wiki.getListOfAllPageNames());
tryToSetEditLock(page, ureq, ores);
updatePageContext(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 == versioningContent) {
/*************************************************************************
* versioning container events
************************************************************************/
} else if (source == editContent) {
/*************************************************************************
* edit container events
************************************************************************/
} else if (source == closePreviewButton){
editContent.remove(wikiVersionDisplayComp);
} else if (source == deletePageButton){
removePageDialogCtr = activateOkCancelDialog(ureq, null, translate("question", page.getPageName()), removePageDialogCtr);
return;
} else if (source == manageMediaButton){
if(wiki.getMediaFileListWithMetadata().size() > 0){
mediaMgntContent = createVelocityContainer("media");
refreshTableDataModel(ureq);
mediaMgntContent.put("mediaMgmtTable", mediaTableCtr.getInitialComponent());
CloseableModalController cmc = new CloseableModalController(getWindowControl(), translate("close"), mediaMgntContent, true, translate("manage.media"));
cmc.activate();
}
} else if (source == revertVersionButton) {
wikiEditForm.setPage(selectedPage);
tabs.setSelectedPane(2);
tryToSetEditLock(page, ureq, ores);
}
//set recent page id to the page currently used
if(page != null)this.pageId = page.getPageId();
}
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) {
mediaTableCtr = new TableController(new TableGuiConfiguration(), ureq, getWindowControl(), getTranslator(), null);
mediaTableCtr.setMultiSelect(true);
mediaTableCtr.addMultiSelectAction(ACTION_DELETE_MEDIAS, ACTION_DELETE_MEDIAS);
listenTo(mediaTableCtr);
List filelist = getWiki().getMediaFileListWithMetadata();
Map files = new HashMap();
for (Iterator 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 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 = (MediaFileElement)files.get(elem.getName());
element.setFileName(elem.getName());
}
}
}
mediaFilesTableModel = new MediaFilesTableModel(new ArrayList(files.values()), getTranslator());
mediaFilesTableModel.addColumnDescriptors(mediaTableCtr);
mediaTableCtr.setTableDataModel(mediaFilesTableModel);
mediaTableCtr.setSortColumn(3, false);
mediaTableCtr.modelChanged();
}
private WikiPage handleRequestNewPageEvent(UserRequest ureq, RequestNewPageEvent requestPage) {
if(!securityCallback.mayEditAndCreateArticle()){
if (ureq.getUserSession().getRoles().isGuestOnly()) showInfo("guest.no.edit");
showInfo("no.edit");
return null;
}
// create new page
WikiPage page = new WikiPage(requestPage.getCommand());
page.setCreationTime(System.currentTimeMillis());
page.setInitalAuthor(ureq.getIdentity().getKey().longValue());
getWiki().addPage(page);
WikiManager.getInstance().saveWikiPage(ores, page, false, getWiki());
updatePageContext(page);
doReleaseEditLock();
tryToSetEditLock(page, ureq, ores);
tabs.setSelectedPane(2);
return page;
}
public void event(UserRequest ureq, Controller source, Event event) {
Wiki wiki = getWiki();
//reload page from cache
WikiPage page = wiki.getPage(pageId, true);
//set recent page id to the page currently used
this.pageId = page.getPageId();
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 = (WikiPage) 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 = (WikiPage) 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 == fileUplCtr) {
/*************************************************************************
* file upload controller events
************************************************************************/
if (event == Event.DONE_EVENT) {
fileUplCtr.reset();
} else if (event.getCommand().equals(FolderEvent.UPLOAD_EVENT)) {
FolderEvent fEvent = (FolderEvent)event;
createMediaMetadataFile(fEvent.getFilename(), ureq.getIdentity().getKey());
editContent.contextPut("fileList", wiki.getMediaFileList());
}
} else if (source == breadCrumpCtr) {
/*************************************************************************
* BreadCrump controller events
************************************************************************/
page = wiki.getPage(event.getCommand(), true);
updatePageContext(page);
setTabsEnabled(true);
breadCrumpCtr.addLink(page.getPageName(), page.getPageName());
tabs.setSelectedPane(0);
} else if (source == removePageDialogCtr) {
if (DialogBoxUIFactory.isOkEvent(event)) {
wiki.removePage(page);
breadCrumpCtr.removeLink(page.getPageName());
WikiManager.getInstance().deleteWikiPage(ores, page);
page = wiki.getPage(WikiPage.WIKI_INDEX_PAGE);
updatePageContext(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 list = new ArrayList(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 = (MediaFileElement)mediaFilesTableModel.getObject(te.getRowId());
if (isImage(element.getFilename()) ) { // show images inline as modal overlay
imageDisplay.contextPut("mediaElement", element);
imageDisplay.contextPut("imageUri", wikiArticleComp.getImageBaseUri());
CloseableModalController cmc = new CloseableModalController(getWindowControl(), translate("close"), imageDisplay);
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)) {
//convert wiki into IMS content package and copy to users home folder
WikiToCPExport utils = new WikiToCPExport(ores, ident, getTranslator());
utils.archiveWikiToCP();
}
}
else if (source == searchArticleForm) {
String query = searchArticleForm.getQuery();
if (query == null) query = WikiPage.WIKI_INDEX_PAGE;
page = wiki.findPage(query);
if (page.getPageName().equals(Wiki.NEW_PAGE)) setTabsEnabled(false);
page.incrementViewCount();
updatePageContext(page);
if(!page.getPageName().startsWith("O_")) breadCrumpCtr.addLink(page.getPageName(), page.getPageName());
tabs.setSelectedPane(0);
}
//set recent page id to the page currently used
this.pageId = page.getPageId();
}
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 toDelete, UserRequest ureq) {
for (Iterator iter = toDelete.iterator(); iter.hasNext();) {
VFSContainer mediaFolder = WikiManager.getInstance().getMediaFolder(ores);
MediaFileElement element = (MediaFileElement) 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);
}
protected void doDispose() {
ThreadLocalUserActivityLogger.log(LearningResourceLoggingAction.LEARNING_RESOURCE_CLOSE, getClass());
if (versioningTableCtr != null) {
versioningTableCtr.dispose();
versioningTableCtr = null;
}
if (fileUplCtr != null) {
fileUplCtr.dispose();
fileUplCtr = null;
}
if (breadCrumpCtr != null) {
breadCrumpCtr.dispose();
breadCrumpCtr = null;
}
if (cSubscriptionCtrl != null) {
cSubscriptionCtrl.dispose();
cSubscriptionCtrl = null;
}
doReleaseEditLock();
}
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.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.getCoordinator().getLocker().acquireLock(ores, ureq.getIdentity(), page.getPageName());
editContent.contextPut("lockEntry", lockEntry);
}
/**
* called by the gui framework upon browser back/forward.
*/
protected void adjustState(ControllerState cstate, UserRequest ureq) {
// the pagename is unique within a wiki.
String pageName = cstate.getSerializedState();
Wiki wiki = getWiki();
if (pageName.equals(WikiPage.WIKI_A2Z_PAGE)) {
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());
setTabsEnabled(false);
setState(WikiPage.WIKI_A2Z_PAGE);
} else {
WikiPage page = wiki.getPage(pageName, true);
if (page != null) this.pageId = page.getPageId();
page.incrementViewCount();
updatePageContext(page);
//breadCrumpCtr.addLink(page.getPageName(), page.getPageName());
}
}
/**
* update depended velocity contexts and componetens with latest globally used page
*
*/
private void updatePageContext(WikiPage page) {
setState(page.getPageName());
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);
}
private Wiki getWiki(){
return WikiManager.getInstance().getOrLoadWiki(ores);
}
}