/**
* <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.course.config.ui.courselayout;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.olat.core.CoreSpringFactory;
import org.olat.core.commons.services.image.ImageService;
import org.olat.core.gui.components.htmlheader.jscss.CustomCSS;
import org.olat.core.helpers.GUISettings;
import org.olat.core.helpers.Settings;
import org.olat.core.util.FileUtils;
import org.olat.core.util.StringHelper;
import org.olat.core.util.UserSession;
import org.olat.core.util.WebappHelper;
import org.olat.core.util.vfs.LocalFolderImpl;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.vfs.filters.VFSItemFilter;
import org.olat.course.config.CourseConfig;
import org.olat.course.run.environment.CourseEnvironment;
/**
* Description:<br>
* some static helpers for the course-layout-generator
*
* <P>
* Initial Date: 01.02.2011 <br>
*
* @author Roman Haag, roman.haag@frentix.com, http://www.frentix.com
*/
public class CourseLayoutHelper {
public static final String COURSEFOLDER_CSS_BASE = "/courseCSS";
private static int logoMaxHeight;
private static int logoMaxWidth;
private static ImageService imageHelperToUse;
public static final String CONFIG_KEY_LEGACY = "legacy";
public static final String CONFIG_KEY_DEFAULT = CourseConfig.VALUE_EMPTY_CSS_FILEREF;
public static final String CONFIG_KEY_TEMPLATE = "template::";
public static final String CONFIG_KEY_PREDEFINED = "predefined";
public static final String CONFIG_KEY_CUSTOM = "custom";
public static final String LAYOUT_COURSE_SUBFOLDER = "/layout";
private static final String IFRAME_CSS = "/iframe.css";
private static final String MAIN_CSS = "/main.css";
private static final VFSItemFilter themeNamesFilter = new VFSItemFilter() {
@Override
public boolean accept(VFSItem it) {
if (!(it instanceof VFSContainer)) return false;
// remove unwanted meta-dirs
else if (FileUtils.isMetaFilename(it.getName())) return false;
// last check is blacklist
return !(layoutBlacklist.contains(it.getName()));
}
};
/**
* Array holding the folder-names of the blacklisted course-layouts
* (set by spring)
*
*/
private static List<String> layoutBlacklist;
CourseLayoutHelper(){
//
}
/**
* get configured path for this courseEnvironment
* @param courseEnvironment
* @return
*/
public static VFSContainer getCSSBaseFolder(CourseEnvironment courseEnvironment) {
CourseConfig courseConfig = courseEnvironment.getCourseConfig();
String cssSet = courseConfig.getCssLayoutRef();
return getThemeBaseFolder(courseEnvironment, cssSet);
}
/**
* get path according to type of theme
* @param courseEnvironment
* @param cssSet
* @return
*/
public static VFSContainer getThemeBaseFolder(CourseEnvironment courseEnvironment, String cssSet) {
VFSContainer courseBase = courseEnvironment.getCourseBaseContainer();
// the hidden-dir CSS in "/coursecss/xy.css"
if (StringHelper.containsNonWhitespace(cssSet) && cssSet.contains(COURSEFOLDER_CSS_BASE) && cssSet.startsWith("/") && cssSet.lastIndexOf("/") > 0){
if (courseEnvironment.getCourseFolderContainer().resolve(COURSEFOLDER_CSS_BASE) != null) {
return courseEnvironment.getCourseFolderContainer();
} else return null;
} else if (!StringHelper.containsNonWhitespace(cssSet) || cssSet.startsWith("/")) {
// the old legacy format "/blibla.css"
return (VFSContainer) courseBase.resolve("coursefolder");
} else if (cssSet.equals(CONFIG_KEY_CUSTOM)) {
return (VFSContainer) courseBase.resolve(LAYOUT_COURSE_SUBFOLDER + "/custom");
} else if (CONFIG_KEY_PREDEFINED.equals(cssSet)) {
return (VFSContainer) courseBase.resolve(LAYOUT_COURSE_SUBFOLDER + "/predefined");
} else if (cssSet.startsWith(CONFIG_KEY_TEMPLATE)) {
String selTheme = cssSet.substring(CONFIG_KEY_TEMPLATE.length());
// 1. check if it's a layout from the OLAT-theme
VFSContainer themeContainer = getOLATThemeCourseLayoutFolder();
if(themeContainer!=null){
themeContainer = (VFSContainer) themeContainer.resolve("/"+selTheme);
return themeContainer;
}
// 2. check if it's system-default
String staticAbsPath = WebappHelper.getContextRealPath("/static/coursethemes/");
File themesFile = new File(staticAbsPath + selTheme);
if(themesFile.exists() && themesFile.isDirectory())
return new LocalFolderImpl(themesFile);
}
return null; // default was set
}
/**
* get CustomCSS preconfigured according to choosen course theme
* @param usess
* @param courseEnvironment
* @return
*/
public static CustomCSS getCustomCSS(UserSession usess, CourseEnvironment courseEnvironment) {
VFSContainer courseContainer = getCSSBaseFolder(courseEnvironment);
CustomCSS customCSS = null;
// check for existing main.css and iframe.css
if (isCourseThemeFolderValid(courseContainer)) {
customCSS = new CustomCSS(courseContainer, MAIN_CSS, IFRAME_CSS, usess);
} else if (courseContainer!=null && courseContainer.resolve(courseEnvironment.getCourseConfig().getCssLayoutRef()) != null){ // legacy fallback
customCSS = new CustomCSS(courseContainer, courseEnvironment.getCourseConfig().getCssLayoutRef(), usess);
}
return customCSS;
}
/**
* get a list of system wide course theme templates
* they need to be in webapp/static/coursethemes/XY
* @return
*/
public static List<VFSItem> getCourseThemeTemplates(){
List<VFSItem> courseThemes = new ArrayList<VFSItem>();
// 1. add the system-defaults
String staticAbsPath = WebappHelper.getContextRealPath("/static");
File themesFile = new File(staticAbsPath);
VFSContainer cThemeCont = new LocalFolderImpl(themesFile);
cThemeCont = (VFSContainer) cThemeCont.resolve("/coursethemes");
if (cThemeCont != null) {
courseThemes = cThemeCont.getItems(themeNamesFilter);
}
// 2. now add the additional Templates from the current Theme
VFSContainer addThCont = CourseLayoutHelper.getOLATThemeCourseLayoutFolder();
if (addThCont != null) {
List<VFSItem> additionalThemes = addThCont.getItems(themeNamesFilter);
courseThemes.addAll(additionalThemes);
}
return courseThemes;
}
/**
* returns the Folder with the additional courselayouts from the current
* OLAT-Theme this is e.g. : /static/themes/frentix/courselayouts/<br />
* If no courselayouts exist in the current OLAT-Theme, null is returned!
*
* @return the courselayouts-folder or null
*/
public static VFSContainer getOLATThemeCourseLayoutFolder() {
VFSContainer courseLayoutFolder = null;
File themeDir = null;
// first attempt is to use custom theme path
if (Settings.getGuiCustomThemePath() != null) {
themeDir = new File(Settings.getGuiCustomThemePath(), CoreSpringFactory.getImpl(GUISettings.class).getGuiThemeIdentifyer());
if (themeDir.exists() && themeDir.isDirectory()) {
VFSContainer themeContainer = new LocalFolderImpl(themeDir);
courseLayoutFolder = (VFSContainer) themeContainer.resolve("/courselayouts");
}
}
// fallback is to use the standards themes directory in the web app
if (themeDir == null || !themeDir.exists() || !themeDir.isDirectory()) {
File themesDir = new File(WebappHelper.getContextRealPath("/static/themes/"));
themeDir = new File(themesDir, CoreSpringFactory.getImpl(GUISettings.class).getGuiThemeIdentifyer());
}
// resolve now
if (themeDir != null && themeDir.exists() && themeDir.isDirectory()) {
VFSContainer themeContainer = new LocalFolderImpl(themeDir);
courseLayoutFolder = (VFSContainer) themeContainer.resolve("/courselayouts");
}
return courseLayoutFolder;
}
/**
* checks if the given theme base contains the needed css-files
* - main.css
* - iframe.css
* @param courseThemeBase
* @return
*/
public static boolean isCourseThemeFolderValid(VFSContainer courseThemeBase){
if (courseThemeBase==null) return false;
return courseThemeBase.resolve(MAIN_CSS) != null && courseThemeBase.resolve(IFRAME_CSS) != null;
}
/**
* [spring]
* @param logoMaxHeight The logoMaxHeight to set.
*/
public void setLogoMaxHeight(int logoMaxHeight) {
CourseLayoutHelper.logoMaxHeight = logoMaxHeight;
}
/**
* [spring]
*
* @param layouts comma-separated list of folder-names (e.g.
* purple,green,blue)
*/
public void setLayoutBlacklist(String layouts){
layoutBlacklist = Arrays.asList(layouts.split(","));
}
/**
* @return Returns the logoMaxHeight.
*/
public static int getLogoMaxHeight() {
return logoMaxHeight;
}
/**
* [spring]
* @param logoMaxWidth The logoMaxWidth to set.
*/
public void setLogoMaxWidth(int logoMaxWidth) {
CourseLayoutHelper.logoMaxWidth = logoMaxWidth;
}
/**
* @return Returns the logoMaxWidth.
*/
public static int getLogoMaxWidth() {
return logoMaxWidth;
}
/**
* @return Returns the imageHelperToUse.
*/
public static ImageService getImageHelperToUse() {
return imageHelperToUse;
}
/**
* allows to exchange the java implementation of Imagehelper.
* to use i.e. an imageMagick-instance to get better image-scaling (transparency, etc.)
* [spring]
* @param imageHelperToUse The imageHelperToUse to set.
*/
public void setImageHelperToUse(ImageService imageHelperToUse) {
CourseLayoutHelper.imageHelperToUse = imageHelperToUse;
}
}