/**
* 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.group.ui.edit;
import java.util.List;
import org.apache.commons.lang.StringEscapeUtils;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.panel.Panel;
import org.olat.core.gui.components.stack.TooledStackedPanel;
import org.olat.core.gui.components.tabbedpane.TabbedPane;
import org.olat.core.gui.components.tabbedpane.TabbedPaneChangedEvent;
import org.olat.core.gui.components.velocity.VelocityContainer;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.ControllerEventListener;
import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.controller.BasicController;
import org.olat.core.gui.control.generic.dtabs.Activateable2;
import org.olat.core.gui.control.generic.modal.DialogBoxController;
import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
import org.olat.core.id.Roles;
import org.olat.core.id.context.ContextEntry;
import org.olat.core.id.context.StateEntry;
import org.olat.core.logging.AssertException;
import org.olat.core.logging.activity.ActionType;
import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
import org.olat.core.util.Util;
import org.olat.core.util.coordinate.CoordinatorManager;
import org.olat.core.util.coordinate.LockResult;
import org.olat.core.util.event.GenericEventListener;
import org.olat.core.util.resource.OLATResourceableJustBeforeDeletedEvent;
import org.olat.group.BusinessGroup;
import org.olat.group.BusinessGroupManagedFlag;
import org.olat.group.BusinessGroupService;
import org.olat.group.GroupLoggingAction;
import org.olat.group.ui.BGControllerFactory;
import org.olat.resource.accesscontrol.AccessControlModule;
import org.olat.util.logging.activity.LoggingResourceable;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Description: <BR>
* This controller displays a tabbed pane that lets the user configure and
* modify a business group.
* <P>
* Fires BusinessGroupModifiedEvent via the OLATResourceableEventCenter
* <P>
* Initial Date: Aug 17, 2004
*
* @author patrick, srosse
*/
public class BusinessGroupEditController extends BasicController implements ControllerEventListener, GenericEventListener, Activateable2 {
private boolean hasResources;
private BusinessGroup currBusinessGroup;
@Autowired
private BusinessGroupService businessGroupService;
@Autowired
private AccessControlModule acModule;
private TabbedPane tabbedPane;
private VelocityContainer mainVC;
private LockResult lockEntry;
private DialogBoxController alreadyLockedDialogController;
//controllers in tabs
private BusinessGroupEditDetailsController editDetailsController;
private BusinessGroupToolsController collaborationToolsController;
private BusinessGroupMembersController membersController;
private BusinessGroupEditResourceController resourceController;
private BusinessGroupEditAccessController tabAccessCtrl;
private int membersTab;
/**
* Never call this constructor directly, use the BGControllerFactory instead!!
*
* @param ureq
* @param wControl
* @param currBusinessGroup
* @param configurationFlags Flags to configure the controllers features. The
* controller does no type specific stuff implicit just by looking at
* the group type. Type specifig features must be flagged.
*/
public BusinessGroupEditController(UserRequest ureq, WindowControl wControl, TooledStackedPanel toolbarPanel, BusinessGroup businessGroup) {
super(ureq, wControl);
// OLAT-4955: setting the stickyActionType here passes it on to any controller defined in the scope of the editor,
// basically forcing any logging action called within the bg editor to be of type 'admin'
getUserActivityLogger().setStickyActionType(ActionType.admin);
addLoggingResourceable(LoggingResourceable.wrap(businessGroup));
// Initialize translator:
setTranslator(Util.createPackageTranslator(BGControllerFactory.class, getLocale(), getTranslator()));
// try to acquire edit lock on business group
String locksubkey = "groupEdit";
lockEntry = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(businessGroup, ureq.getIdentity(), locksubkey);
if (lockEntry.isSuccess()) {
// reload group to minimize stale object exception and update last usage timestamp
currBusinessGroup = businessGroupService.setLastUsageFor(getIdentity(), businessGroup);
if(currBusinessGroup == null) {
VelocityContainer vc = createVelocityContainer("deleted");
vc.contextPut("name", businessGroup.getName());
putInitialPanel(vc);
} else {
// add as listener to BusinessGroup so we are being notified about changes.
CoordinatorManager.getInstance().getCoordinator().getEventBus().registerFor(this, getIdentity(), currBusinessGroup);
//create some controllers
editDetailsController = new BusinessGroupEditDetailsController(ureq, getWindowControl(), businessGroup);
listenTo(editDetailsController);
collaborationToolsController = new BusinessGroupToolsController(ureq, getWindowControl(), businessGroup);
listenTo(collaborationToolsController);
membersController = new BusinessGroupMembersController(ureq, getWindowControl(), toolbarPanel, businessGroup);
listenTo(membersController);
tabbedPane = new TabbedPane("bgTabbs", ureq.getLocale());
tabbedPane.addListener(this);
setAllTabs(ureq);
mainVC = createVelocityContainer("edit");
mainVC.put("tabbedpane", tabbedPane);
String[] title = new String[] { StringEscapeUtils.escapeHtml(currBusinessGroup.getName()) };
mainVC.contextPut("title", getTranslator().translate("group.edit.title", title));
putInitialPanel(mainVC);
}
} else {
//lock was not successful !
alreadyLockedDialogController = DialogBoxUIFactory.createResourceLockedMessage(ureq, wControl, lockEntry, "error.message.locked", getTranslator());
listenTo(alreadyLockedDialogController);
alreadyLockedDialogController.activate();
putInitialPanel(new Panel("empty"));
}
}
public BusinessGroup getBusinessGroup() {
return currBusinessGroup;
}
/**
* Learning areas and and course rights should only appear when at least one course is associated.</br>
* <ul><li>
* a) No courses associated and user is not author</br>
* Description, Tools, Members, Publishing and booking
* </li><li>
* b) No course associated and user is author:</br>
* Description, Tools, Members, Courses, Publishing and booking
* </li><li>
* c) With courses associated:</br>
* Description, Tools, Members, Courses, Learning areas, Course rights, Publishing and booking
*
* @param ureq
*/
private void setAllTabs(UserRequest ureq) {
hasResources = businessGroupService.hasResources(currBusinessGroup);
tabAccessCtrl = getAccessController(ureq);
int currentSelectedPane = tabbedPane.getSelectedPane();
tabbedPane.removeAll();
editDetailsController.setAllowWaitingList(tabAccessCtrl == null || !tabAccessCtrl.isPaymentMethodInUse());
tabbedPane.addTab(translate("group.edit.tab.details"), editDetailsController.getInitialComponent());
tabbedPane.addTab(translate("group.edit.tab.collabtools"), collaborationToolsController.getInitialComponent());
membersController.updateBusinessGroup(currBusinessGroup);
membersTab = tabbedPane.addTab(translate("group.edit.tab.members"), membersController.getInitialComponent());
//resources (optional)
resourceController = getResourceController(ureq);
if(resourceController != null) {
tabbedPane.addTab(translate("group.edit.tab.resources"), resourceController.getInitialComponent());
}
if(tabAccessCtrl != null) {
tabbedPane.addTab(translate("group.edit.tab.accesscontrol"), tabAccessCtrl.getInitialComponent());
}
if(currentSelectedPane > 0) {
tabbedPane.setSelectedPane(currentSelectedPane);
}
}
/**
* The resources / courses tab is enabled if the user is
* an administrator, a group manager or an author. Or if the group has
* already some resources.
*
* @param ureq
* @return
*/
private BusinessGroupEditResourceController getResourceController(UserRequest ureq) {
Roles roles = ureq.getUserSession().getRoles();
boolean enabled = roles.isOLATAdmin() || roles.isGroupManager() || roles.isAuthor() || hasResources;
if(enabled) {
if(resourceController == null) {
resourceController = new BusinessGroupEditResourceController(ureq, getWindowControl(), currBusinessGroup);
listenTo(resourceController);
}
return resourceController;
}
removeAsListenerAndDispose(resourceController);
resourceController = null;
return null;
}
private BusinessGroupEditAccessController getAccessController(UserRequest ureq) {
if(tabAccessCtrl == null && acModule.isEnabled()) {
tabAccessCtrl = new BusinessGroupEditAccessController(ureq, getWindowControl(), currBusinessGroup);
if(BusinessGroupManagedFlag.isManaged(currBusinessGroup, BusinessGroupManagedFlag.bookings)
&& tabAccessCtrl.getNumOfBookingConfigurations() == 0) {
//booking is managed, no booking, don't show it
tabAccessCtrl = null;
} else {
listenTo(tabAccessCtrl);
}
}
if(tabAccessCtrl != null) {
tabAccessCtrl.updateBusinessGroup(currBusinessGroup);
}
return tabAccessCtrl;
}
/**
* @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 == tabbedPane && event instanceof TabbedPaneChangedEvent) {
tabbedPane.addToHistory(ureq, getWindowControl());
if(tabbedPane.getSelectedPane() == membersTab) {
membersController.updateBusinessGroup(currBusinessGroup);
}
}
}
/**
* @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 == collaborationToolsController) {
if (event == Event.CHANGED_EVENT) {
fireEvent(ureq, event);
// notify current active users of this business group
BusinessGroupModifiedEvent
.fireModifiedGroupEvents(BusinessGroupModifiedEvent.CONFIGURATION_MODIFIED_EVENT, currBusinessGroup, null);
}
} else if (source == alreadyLockedDialogController) {
//closed dialog box either by clicking ok, or closing the box
if (event == Event.CANCELLED_EVENT || DialogBoxUIFactory.isOkEvent(event)) {
fireEvent(ureq, Event.CANCELLED_EVENT);
}
} else if (source == editDetailsController) {
if (event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) {
//reload the business group
currBusinessGroup = editDetailsController.getGroup();
fireEvent(ureq, event);
// inform index about change
setAllTabs(ureq);
// notify current active users of this business group
BusinessGroupModifiedEvent
.fireModifiedGroupEvents(BusinessGroupModifiedEvent.CONFIGURATION_MODIFIED_EVENT, currBusinessGroup, null);
// do logging
ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_CONFIGURATION_CHANGED, getClass());
}
} else if (source == membersController) {
if (event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) {
//reload the business group
currBusinessGroup = membersController.getGroup();
fireEvent(ureq, event);
}
} else if (source == tabAccessCtrl) {
setAllTabs(ureq);
fireEvent(ureq, event);
} else if (source == resourceController) {
setAllTabs(ureq);
fireEvent(ureq, event);
}
}
/**
* @see org.olat.core.util.event.GenericEventListener#event(org.olat.core.gui.control.Event)
*/
@Override
public void event(Event event) {
if (event instanceof OLATResourceableJustBeforeDeletedEvent) {
OLATResourceableJustBeforeDeletedEvent delEvent = (OLATResourceableJustBeforeDeletedEvent) event;
if (!delEvent.targetEquals(currBusinessGroup)) throw new AssertException(
"receiving a delete event for a olatres we never registered for!!!:" + delEvent.getDerivedOres());
dispose();
}
}
@Override
public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
if(entries == null || entries.isEmpty() || tabbedPane == null) return;
tabbedPane.activate(ureq, entries, state);
}
/**
* @return true if lock on group has been acquired, flase otherwhise
*/
public boolean isLockAcquired() {
return lockEntry.isSuccess();
}
/**
* @see org.olat.core.gui.control.DefaultController#doDispose(boolean asynchronous)
*/
@Override
protected void doDispose() {
if(currBusinessGroup != null) {
CoordinatorManager.getInstance().getCoordinator().getEventBus().deregisterFor(this, currBusinessGroup);
//release lock on dispose
releaseBusinessGroupEditLock();
}
}
private void releaseBusinessGroupEditLock() {
if(lockEntry.isSuccess()){
// release lock
CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(lockEntry);
}else if(alreadyLockedDialogController != null){
//dispose if dialog still visible
alreadyLockedDialogController.dispose();
}
}
}