/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <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 the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <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>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.core.commons.fullWebApp;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.WindowSettings;
import org.olat.core.gui.Windows;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.htmlheader.jscss.JSAndCSSComponent;
import org.olat.core.gui.components.panel.Panel;
import org.olat.core.gui.components.velocity.VelocityContainer;
import org.olat.core.gui.control.ChiefController;
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.ScreenMode.Mode;
import org.olat.core.gui.control.controller.MainLayoutBasicController;
import org.olat.core.gui.control.generic.dtabs.Activateable2;
import org.olat.core.gui.control.generic.layout.MainLayout3ColumnsController;
import org.olat.core.id.context.ContextEntry;
import org.olat.core.id.context.StateEntry;
/**
* <h3>Description:</h3> This main layout controller provides a three column
* layout based on the YAML framework. You must use the the
* BaseFullWebappController as parent controller or implement the necessary YAML
* HTML wrapper markup code yourself.
* <p>
* The meaning of the col1, col2 and col3 are strictly following the YAML
* concept. This means, that in a brasato web application in most cases the
* following mapping is applied:
* <ul>
* <li>col1: menu</li>
* <li>col2: toolboxes</li>
* <li>col3: content area</li>
* </ul>
* Read the YAML specification if you don't understand why this is. Rendering is
* all done using CSS.
* <p>
* For information about YAML please see @see http://www.yaml.de
* <p>
* <h3>Events thrown by this controller:</h3>
* <ul>
* <li>none</li>
* </ul>
* <p>
* Initial Date: 11.10.2007 <br>
*
* @author Florian Gnaegi, frentix GmbH, http://www.frentix.com
*/
public class LayoutMain3ColsController extends MainLayoutBasicController implements MainLayout3ColumnsController, Activateable2 {
private VelocityContainer layoutMainVC;
// current columns components
private Component[] columns = new Component[3];
// current css classes for the main div
private Set<String> mainCssClasses = new HashSet<String>();
private LayoutMain3ColsConfig localLayoutConfig;
private String layoutConfigKey = null;
private Panel panel1, panel2, panel3;
private Activateable2 activateableDelegate2; //fxdiff BAKS-7 Resume function
private boolean fullScreen = false;
private ChiefController thebaseChief;
/**
*
* @param ureq
* @param wControl
* @param colCtrl3
*/
public LayoutMain3ColsController(UserRequest ureq, WindowControl wControl, Controller colCtrl3) {
this(ureq,wControl, null, null, colCtrl3.getInitialComponent(), null, null);
listenTo(colCtrl3);
if(colCtrl3 instanceof Activateable2) {
activateableDelegate2 = (Activateable2)colCtrl3;
}
}
/**
* Constructor for creating a 3 col based menu on the main area. This
* constructor uses the default column width configuration
*
* @param ureq
* @param wControl
* @param col1 usually the left column
* @param col2 usually the right column
* @param col3 usually the content column
* @param layoutConfigKey identificator for this layout to persist the users
* column width settings
*/
public LayoutMain3ColsController(UserRequest ureq, WindowControl wControl, Component col1, Component col3,
String layoutConfigKey) {
this(ureq,wControl, col1, null, col3, layoutConfigKey, null);
}
/**
* Constructor for creating a 3 col based menu on the main area. This
* constructor uses the default column width configuration
*
* @param ureq
* @param wControl
* @param col1 usually the left column
* @param col2 usually the right column
* @param col3 usually the content column
* @param layoutConfigKey identificator for this layout to persist the users
* column width settings
*/
public LayoutMain3ColsController(UserRequest ureq, WindowControl wControl, Component col1, Component col2, Component col3,
String layoutConfigKey) {
this(ureq,wControl, col1, col2, col3, layoutConfigKey, null);
}
/**
* Constructor for creating a 3 col based menu on the main area
*
* @param ureq
* @param wControl
* @param col1 usually the left column
* @param col2 usually the right column
* @param col3 usually the content column
* @param layoutConfigKey identificator for this layout to persist the users
* column width settings
* @param defaultConfiguration The layout width configuration to be used
*/
public LayoutMain3ColsController(UserRequest ureq, WindowControl wControl, Component col1, Component col2, Component col3,
String layoutConfigKey, LayoutMain3ColsConfig defaultConfiguration) {
super(ureq, wControl);
layoutMainVC = createVelocityContainer("main_3cols");
this.layoutConfigKey = layoutConfigKey;
localLayoutConfig = getGuiPrefs(ureq, defaultConfiguration);
WindowSettings wSettings = wControl.getWindowBackOffice().getWindowSettings();
// Push columns to velocity
panel1 = new Panel("panel1");
panel1.setVisible(!wSettings.isHideColumn1());
if(col1 != null) {
col1.setVisible(!wSettings.isHideColumn1());
}
layoutMainVC.put("col1", panel1);
setCol1(col1);
panel2 = new Panel("panel2");
panel2.setVisible(!wSettings.isHideColumn2());
if(col2 != null) {
col2.setVisible(!wSettings.isHideColumn2());
}
layoutMainVC.put("col2", panel2);
setCol2(col2);
panel3 = new Panel("panel3");
layoutMainVC.put("col3", panel3);
setCol3(col3);
if(col1 != null || col2 != null) {
JSAndCSSComponent js = new JSAndCSSComponent("js", new String[] { "js/jquery/ui/jquery-ui-1.11.4.custom.resize.min.js" }, null);
layoutMainVC.put("js", js);
}
putInitialPanel(layoutMainVC);
}
public boolean isFullScreen() {
return fullScreen;
}
public void setAsFullscreen(UserRequest ureq) {
ChiefController cc = getWindowControl().getWindowBackOffice().getChiefController();
if (cc != null) {
thebaseChief = cc;
thebaseChief.getScreenMode().setMode(Mode.full);
} else {
Windows.getWindows(ureq).setFullScreen(Boolean.TRUE);
}
fullScreen = true;
}
public void activate() {
getWindowControl().pushToMainArea(layoutMainVC);
}
public void deactivate(UserRequest ureq) {
getWindowControl().pop();
if (fullScreen) {
if(thebaseChief != null) {
thebaseChief.getScreenMode().setMode(Mode.standard);
} else if (ureq != null){
ChiefController cc = getWindowControl().getWindowBackOffice().getChiefController();
if (cc != null) {
thebaseChief = cc;
thebaseChief.getScreenMode().setMode(Mode.standard);
}
}
}
}
/**
* Add a controller to this layout controller that should be cleaned up when
* this layout controller is diposed. In most scenarios you should hold a
* reference to the content controllers that controll the col1, col2 or col3,
* but in rare cases this is not the case and you have no local reference to
* your controller. You can then use this method to add your controller. At
* the dispose time of the layout controller your controller will be disposed
* as well.
*
* @param toBedisposedControllerOnDispose
*/
public void addDisposableChildController(Controller toBedisposedControllerOnDispose) {
listenTo(toBedisposedControllerOnDispose);
}
//fxdiff BAKS-7 Resume function
public void addActivateableDelegate(Activateable2 delegate) {
this.activateableDelegate2 = delegate;
}
//fxdiff BAKS-7 Resume function
@Override
public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
if(activateableDelegate2 != null) {
activateableDelegate2.activate(ureq, entries, state);
}
}
/**
* The Controller to be set on the mainPanel in case of disposing this layout
* controller.
*
* @param disposedMessageControllerOnDipsose
*/
public void setDisposedMessageController(Controller disposedMessageControllerOnDipsose) {
this.setDisposedMsgController(disposedMessageControllerOnDipsose);
}
/**
* Add a css class to the #o_main wrapper div, e.g. for special background
* formatting
*
* @param cssClass
*/
public void addCssClassToMain(String cssClass) {
if (mainCssClasses.contains(cssClass)) {
// do nothing and report as error to console, but no GUI error for user
getLogger().error("Tried to add CSS class::" + cssClass + " to #o_main but CSS class was already added");
} else {
mainCssClasses.add(cssClass);
// add new CSS classes for main container
String mainCss = calculateMainCssClasses(mainCssClasses);
layoutMainVC.contextPut("mainCssClasses", mainCss);
}
}
/**
* Remove a CSS class from the #o_main wrapper div
*
* @param cssClass
*/
public void removeCssClassFromMain(String cssClass) {
if (mainCssClasses.contains(cssClass)) {
mainCssClasses.remove(cssClass);
// add new CSS classes for main container
String mainCss = calculateMainCssClasses(mainCssClasses);
layoutMainVC.contextPut("mainCssClasses", mainCss);
} else {
// do nothing and report as error to console, but no GUI error for user
getLogger().error("Tried to remove CSS class::" + cssClass + " from #o_main but CSS class was not there");
}
}
@Override
protected void doDispose() {
columns = null;
mainCssClasses = null;
layoutMainVC = null;
thebaseChief = null;
}
@Override
protected void event(UserRequest ureq, Component source, Event event) {
if (source == layoutMainVC) {
String command = event.getCommand();
String width = ureq.getModuleURI();
int parsedWidth;
try {
parsedWidth = Integer.parseInt(width);
if (parsedWidth < 1) {
// do not allow width smaller than 1em - resizer will be lost
// otherwhise
parsedWidth = 1;
}
} catch (NumberFormatException e) {
logWarn("Could not parse column width::" + width + " for command::" + command, e);
parsedWidth = 14; // default value
}
if (command.equals("saveCol1Width")) {
localLayoutConfig.setCol1WidthEM(parsedWidth);
saveGuiPrefs(ureq, localLayoutConfig);
layoutMainVC.contextPut("col1CustomCSSStyles", "width: " + localLayoutConfig.getCol1WidthEM() + "em;");
// don't refresh view in ajax mode!
layoutMainVC.setDirty(false);
} else if (command.equals("saveCol2Width")) {
localLayoutConfig.setCol2WidthEM(parsedWidth);
saveGuiPrefs(ureq, localLayoutConfig);
layoutMainVC.contextPut("col2CustomCSSStyles", "width: " + localLayoutConfig.getCol2WidthEM() + "em;");
// don't refresh view in ajax mode!
layoutMainVC.setDirty(false);
}
}
}
private void saveGuiPrefs(UserRequest ureq, LayoutMain3ColsConfig layoutConfig ) {
// save config if not local setting
if (layoutConfigKey != null && ureq.getUserSession().isAuthenticated() && !ureq.getUserSession().getRoles().isGuestOnly()) {
ureq.getUserSession().getGuiPreferences().putAndSave(this.getClass(), layoutConfigKey, layoutConfig);
}
}
/**
* Internal helper to load the layout config either from the GUI preferences
* or to generate a volatile one
*
* @param ureq
* @return the layout column config
*/
private LayoutMain3ColsConfig getGuiPrefs(UserRequest ureq, LayoutMain3ColsConfig defaultConfiguration) {
if (localLayoutConfig != null) { return localLayoutConfig; }
LayoutMain3ColsConfig layoutConfig = null;
if (layoutConfigKey != null && ureq.getUserSession().isAuthenticated() && !ureq.getUserSession().getRoles().isGuestOnly()) {
// try to get persisted layout config
layoutConfig = (LayoutMain3ColsConfig) ureq.getUserSession().getGuiPreferences().get(this.getClass(), layoutConfigKey);
}
if (layoutConfig == null) {
// user has no config so far, use default configuration if available or create a new one
layoutConfig = (defaultConfiguration == null ? new LayoutMain3ColsConfig() : defaultConfiguration);
}
return layoutConfig;
}
/**
* @see org.olat.core.gui.control.generic.layout.MainLayout3ColumnsController#hideCol1(boolean)
*/
public void hideCol1(boolean hide) {
hideCol(hide, 1);
}
/**
* @see org.olat.core.gui.control.generic.layout.MainLayout3ColumnsController#hideCol2(boolean)
*/
public void hideCol2(boolean hide) {
hideCol(hide, 2);
}
/**
* @see org.olat.core.gui.control.generic.layout.MainLayout3ColumnsController#hideCol3(boolean)
*/
public void hideCol3(boolean hide) {
hideCol(hide, 3);
}
/**
* Internal method to hide a column without removing the component
*
* @param hide
* @param column
*/
private void hideCol(boolean hide, int column) {
if (hide) {
if (columns[column - 1] == null) {
return;
} else {
mainCssClasses.add("o_hidecol" + column);
}
} else {
if (columns[column - 1] == null) {
return;
} else {
mainCssClasses.remove("o_hidecol" + column);
}
}
// add new CSS classes for main container
String mainCss = calculateMainCssClasses(mainCssClasses);
layoutMainVC.contextPut("mainCssClasses", mainCss);
}
/**
* @see org.olat.core.gui.control.generic.layout.MainLayout3ColumnsController#setCol1(org.olat.core.gui.components.Component)
*/
public void setCol1(Component col1Component) {
setCol(col1Component, 1);
panel1.setContent(col1Component);
// init col width
if(col1Component != null && col1Component.isVisible()) {
layoutMainVC.contextPut("col1CustomCSSStyles", "width: " + localLayoutConfig.getCol1WidthEM() + "em;");
layoutMainVC.contextPut("col3CustomCSSStyles1", "margin-left: " + localLayoutConfig.getCol1WidthEM() + "em;");
} else {
layoutMainVC.contextPut("col3CustomCSSStyles1", "margin-left:0;");
}
}
/**
* @see org.olat.core.gui.control.generic.layout.MainLayout3ColumnsController#setCol2(org.olat.core.gui.components.Component)
*/
public void setCol2(Component col2Component) {
setCol(col2Component, 2);
panel2.setContent(col2Component);
if(col2Component != null && col2Component.isVisible()) {
layoutMainVC.contextPut("col2CustomCSSStyles", "width: " + localLayoutConfig.getCol2WidthEM() + "em;");
layoutMainVC.contextPut("col3CustomCSSStyles2", "margin-right: " + localLayoutConfig.getCol2WidthEM() + "em;");
} else {
layoutMainVC.contextPut("col3CustomCSSStyles2", "margin-right: 0;");
}
}
/**
* @see org.olat.core.gui.control.generic.layout.MainLayout3ColumnsController#setCol3(org.olat.core.gui.components.Component)
*/
public void setCol3(Component col3Component) {
setCol(col3Component, 3);
panel3.setContent(col3Component);
}
/**
* Internal method to set a new column
*
* @param newComponent
* @param column
*/
private void setCol(Component newComponent, int column) {
Component oldComp = columns[column - 1];
// remove old component from velocity first
if (oldComp == null) {
// css class to indicate if a column is hidden or shown
mainCssClasses.remove("o_hidecol" + column);
} else {
layoutMainVC.remove(oldComp);
}
// add new component to velocity
if (newComponent == null) {
// tell YAML layout via css class on main container to not display this
// column: this will adjust margin of col3 in normal setups
mainCssClasses.add("o_hidecol" + column);
layoutMainVC.contextPut("existsCol" + column, Boolean.FALSE);
} else {
layoutMainVC.contextPut("existsCol" + column, Boolean.TRUE);
}
// add new CSS classes for main container
String mainCss = calculateMainCssClasses(mainCssClasses);
layoutMainVC.contextPut("mainCssClasses", mainCss);
// remember new component
columns[column - 1] = newComponent;
}
/**
* Helper to generate the CSS classes that are set on the #o_main container to
* correctly render the column width and margins according to the YAML spec
*
* @param classes
* @return
*/
private String calculateMainCssClasses(Set<String> classes) {
String mainCss = "";
for (Iterator<String> iter = classes.iterator(); iter.hasNext();) {
String cssClass = iter.next();
mainCss += cssClass;
if (iter.hasNext()) {
mainCss += " ";
}
}
return mainCss;
}
}