diff options
author | Joonas Lehtinen <joonas.lehtinen@itmill.com> | 2006-12-29 17:01:42 +0000 |
---|---|---|
committer | Joonas Lehtinen <joonas.lehtinen@itmill.com> | 2006-12-29 17:01:42 +0000 |
commit | 333a6a59b6f4038d2da0198118bf79b78fdc8e57 (patch) | |
tree | 9d05bc6b51345fcd0b2c19bb50a50c7586fafb87 | |
parent | 7824bde45fead3ec6fe062cf1da5731c366e5ded (diff) | |
download | vaadin-framework-333a6a59b6f4038d2da0198118bf79b78fdc8e57.tar.gz vaadin-framework-333a6a59b6f4038d2da0198118bf79b78fdc8e57.zip |
- Renamed default theme to base
- Merged XSLT and AJAX -based themes
- Added automatic browser detection and mode selection
- Added automatic ajax-html page generation
- Added automatic XSLT theme header generation (no more window template modifications needed!)
svn changeset:187/svn branch:toolkit
5 files changed, 240 insertions, 146 deletions
diff --git a/src/com/itmill/toolkit/terminal/web/AjaxApplicationManager.java b/src/com/itmill/toolkit/terminal/web/AjaxApplicationManager.java index 4b21f699be..861ececa1d 100644 --- a/src/com/itmill/toolkit/terminal/web/AjaxApplicationManager.java +++ b/src/com/itmill/toolkit/terminal/web/AjaxApplicationManager.java @@ -114,7 +114,7 @@ public class AjaxApplicationManager implements Paintable.RepaintRequestListener, application.removeListener((Application.WindowDetachListener) this); } - public void handleXmlHttpRequest(HttpServletRequest request, + public void handleUidlRequest(HttpServletRequest request, HttpServletResponse response) throws IOException { boolean repaintAll = request.getParameter(GET_PARAM_REPAINT_ALL) != null; diff --git a/src/com/itmill/toolkit/terminal/web/ApplicationServlet.java b/src/com/itmill/toolkit/terminal/web/ApplicationServlet.java index 24f943ef7a..24f9390aff 100644 --- a/src/com/itmill/toolkit/terminal/web/ApplicationServlet.java +++ b/src/com/itmill/toolkit/terminal/web/ApplicationServlet.java @@ -52,7 +52,9 @@ import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; +import java.util.Stack; import java.util.StringTokenizer; +import java.util.Vector; import java.util.WeakHashMap; import javax.servlet.ServletContext; @@ -136,49 +138,49 @@ public class ApplicationServlet extends HttpServlet implements private static final String PARAMETER_TRANSFORMER_CACHETIME = "TransformerCacheTime"; - private static int DEFAULT_THEME_CACHETIME = 1000 * 60 * 60 * 24; + private static final int DEFAULT_THEME_CACHETIME = 1000 * 60 * 60 * 24; - private static int DEFAULT_BUFFER_SIZE = 32 * 1024; + private static final int DEFAULT_BUFFER_SIZE = 32 * 1024; - private static int DEFAULT_MAX_TRANSFORMERS = 1; + private static final int DEFAULT_MAX_TRANSFORMERS = 1; - private static int MAX_BUFFER_SIZE = 64 * 1024; + private static final int MAX_BUFFER_SIZE = 64 * 1024; - private static String SESSION_ATTR_VARMAP = "itmill-toolkit-varmap"; + private static final String SESSION_ATTR_VARMAP = "itmill-toolkit-varmap"; - static String SESSION_ATTR_CONTEXT = "itmill-toolkit-context"; + private static final String SESSION_ATTR_CONTEXT = "itmill-toolkit-context"; - static String SESSION_ATTR_APPS = "itmill-toolkit-apps"; + protected static final String SESSION_ATTR_APPS = "itmill-toolkit-apps"; - private static String SESSION_BINDING_LISTENER = "itmill-toolkit-bindinglistener"; + private static final String SESSION_BINDING_LISTENER = "itmill-toolkit-bindinglistener"; // TODO Should default or base theme be the default? - private static String DEFAULT_THEME = "default"; + protected static final String DEFAULT_THEME = "base"; - private static String RESOURCE_URI = "/RES/"; + private static final String RESOURCE_URI = "/RES/"; - private static String AJAX_UIDL_URI = "/UIDL/"; + private static final String AJAX_UIDL_URI = "/UIDL/"; - private static String THEME_DIRECTORY_PATH = "WEB-INF/lib/themes/"; + private static final String THEME_DIRECTORY_PATH = "WEB-INF/lib/themes/"; - private static String THEME_LISTING_FILE = THEME_DIRECTORY_PATH + private static final String THEME_LISTING_FILE = THEME_DIRECTORY_PATH + "themes.txt"; - private static String DEFAULT_THEME_JAR_PREFIX = "itmill-toolkit-themes"; + private static final String DEFAULT_THEME_JAR_PREFIX = "itmill-toolkit-themes"; - private static String DEFAULT_THEME_JAR = "WEB-INF/lib/" + private static final String DEFAULT_THEME_JAR = "WEB-INF/lib/" + DEFAULT_THEME_JAR_PREFIX + "-" + VERSION + ".jar"; - private static String DEFAULT_THEME_TEMP_FILE_PREFIX = "ITMILL_TMP_"; + private static final String DEFAULT_THEME_TEMP_FILE_PREFIX = "ITMILL_TMP_"; - private static String SERVER_COMMAND_PARAM = "SERVER_COMMANDS"; + private static final String SERVER_COMMAND_PARAM = "SERVER_COMMANDS"; - private static int SERVER_COMMAND_STREAM_MAINTAIN_PERIOD = 15000; + private static final int SERVER_COMMAND_STREAM_MAINTAIN_PERIOD = 15000; - private static int SERVER_COMMAND_HEADER_PADDING = 2000; + private static final int SERVER_COMMAND_HEADER_PADDING = 2000; // Maximum delay between request for an user to be considered active (in ms) - private static long ACTIVE_USER_REQUEST_INTERVAL = 1000 * 45; + private static final long ACTIVE_USER_REQUEST_INTERVAL = 1000 * 45; // Private fields private Class applicationClass; @@ -499,15 +501,9 @@ public class ApplicationServlet extends HttpServlet implements HttpVariableMap variableMap = null; OutputStream out = response.getOutputStream(); HashSet currentlyDirtyWindowsForThisApplication = new HashSet(); - WebApplicationContext appContext = null; Application application = null; try { - // If the resource path is unassigned, initialize it - if (resourcePath == null) - resourcePath = request.getContextPath() - + request.getServletPath() + RESOURCE_URI; - // Handle resource requests if (handleResourceRequest(request, response)) return; @@ -523,19 +519,15 @@ public class ApplicationServlet extends HttpServlet implements if (application == null) application = createApplication(request); - // Is this a download request from application - DownloadStream download = null; + // Set the last application request date + applicationToLastRequestDate.put(application, new Date()); // Invoke context transaction listeners - if (application != null) { - appContext = (WebApplicationContext) application.getContext(); - } - if (appContext != null) { - appContext.startTransaction(application, request); - } + ((WebApplicationContext) application.getContext()) + .startTransaction(application, request); - // Set the last application request date - applicationToLastRequestDate.put(application, new Date()); + // Is this a download request from application + DownloadStream download = null; // The rest of the process is synchronized with the application // in order to guarantee that no parallel variable handling is @@ -546,7 +538,7 @@ public class ApplicationServlet extends HttpServlet implements String resourceId = request.getPathInfo(); if (resourceId != null && resourceId.startsWith(AJAX_UIDL_URI)) { - getApplicationManager(application).handleXmlHttpRequest( + getApplicationManager(application).handleUidlRequest( request, response); return; @@ -594,6 +586,7 @@ public class ApplicationServlet extends HttpServlet implements window, t)); } } + // Remove application if it has stopped if (!application.isRunning()) { endApplication(request, response, application); @@ -634,34 +627,128 @@ public class ApplicationServlet extends HttpServlet implements window.setTerminal(terminalType); } - // Find theme and initialize TransformerType - UIDLTransformerType transformerType = null; - if (window.getTheme() != null) { - Theme activeTheme; - if ((activeTheme = this.themeSource - .getThemeByName(window.getTheme())) != null) { - transformerType = new UIDLTransformerType( - terminalType, activeTheme); - } else { - Log - .info("Theme named '" - + window.getTheme() - + "' not found. Using system default theme."); + // Find theme + Theme theme = themeSource + .getThemeByName(window.getTheme() != null ? window + .getTheme() : DEFAULT_THEME); + if (theme == null) + throw new ServletException("Default theme (named '" + + DEFAULT_THEME + "') can not be found"); + + // If UIDL rendering mode is preferred, a page for it is + // rendered + String renderingMode = theme.getPreferredMode(terminalType, + themeSource); + if (Theme.MODE_UIDL.equals(renderingMode)) { + response.setContentType("text/html"); + BufferedWriter page = new BufferedWriter( + new OutputStreamWriter(out)); + + page + .write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" " + + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"); + + page.write("<html><head>\n<title>" + + window.getCaption() + "</title>\n"); + + Theme t = theme; + Vector themes = new Vector(); + themes.add(t); + while (t.getParent() != null) { + String parentName = t.getParent(); + t = themeSource.getThemeByName(parentName); + themes.add(t); } - } + for (int k=themes.size()-1; k>=0; k--) { + t = (Theme) themes.get(k); + Collection files = t.getFileNames(terminalType, + Theme.MODE_UIDL); + for (Iterator i = files.iterator(); i.hasNext();) { + String file = (String) i.next(); + if (file.endsWith(".css")) + page + .write("<link rel=\"stylesheet\" href=\"" + + getResourceLocation(t + .getName(), + new ThemeResource( + file)) + + "\" type=\"text/css\" />\n"); + else if (file.endsWith(".js")) + page + .write("<script src=\"" + + getResourceLocation(t + .getName(), + new ThemeResource( + file)) + + "\" type=\"text/javascript\"></script>\n"); + } + + } + + page.write("</head><body>\n"); - // Use default theme if selected theme was not found. - if (transformerType == null) { - Theme defaultTheme = this.themeSource - .getThemeByName(ApplicationServlet.DEFAULT_THEME); - if (defaultTheme == null) { - throw new ServletException( - "Default theme not found in the specified theme source(s)."); + page + .write("<div id=\"ajax-wait\"><div>Loading...</div></div>\n"); + + page.write("<div id=\"ajax-window\"></div>\n"); + + page.write("<script language=\"JavaScript\">\n"); + page + .write("var client = new ITMillToolkitClient(" + + "document.getElementById('ajax-window')," + + "\"" + + getApplicationUrl(request) + + "/UIDL/" + + "\",\"" + + resourcePath + ((Theme)themes.get(themes.size()-1)).getName() + "/" + + + "client/\",document.getElementById('ajax-wait'));\n"); + + // TODO Should we also show debug information? + /* + * var debug = + * document.location.href.split("debug=")[1]; if (debug && + * debug.split("&")[0] == "1") client.debugEnabled = + * true; + */ + + for (int k=themes.size()-1; k>=0; k--) { + t = (Theme) themes.get(k); + String themeObjName = t.getName() + "Theme"; + themeObjName = themeObjName.substring(0,1).toUpperCase() + themeObjName.substring(1); + page + .write(" (new "+themeObjName+"(\"" + resourcePath + ((Theme)themes.get(k)).getName() + "/\")).registerTo(client);\n"); } - transformerType = new UIDLTransformerType(terminalType, - defaultTheme); + + page.write("client.start();\n"); + + page.write("</script>\n"); + + page.write("</body></html>\n"); + page.close(); + + return; + } + + // If other than XSLT or UIDL mode is requested + if (!Theme.MODE_XSLT.equals(renderingMode)) { + // TODO More informal message should be given is browser + // is not supported + response.setContentType("text/html"); + BufferedWriter page = new BufferedWriter( + new OutputStreamWriter(out)); + page.write("<html><head></head><body>"); + page.write("Unsupported browser."); + page.write("</body></html>"); + page.close(); + + return; } + // Initialize Transformer + UIDLTransformerType transformerType = new UIDLTransformerType( + terminalType, theme); + transformer = this.transformerFactory .getTransformer(transformerType); @@ -769,9 +856,9 @@ public class ApplicationServlet extends HttpServlet implements transformerFactory.releaseTransformer(transformer); // Notify transaction end - if (appContext != null && application != null) { - appContext.endTransaction(application, request); - } + if (application != null) + ((WebApplicationContext) application.getContext()) + .endTransaction(application, request); // Clean the function library state for this thread // for security reasons @@ -988,6 +1075,11 @@ public class ApplicationServlet extends HttpServlet implements private boolean handleResourceRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException { + // If the resource path is unassigned, initialize it + if (resourcePath == null) + resourcePath = request.getContextPath() + request.getServletPath() + + RESOURCE_URI; + String resourceId = request.getPathInfo(); // Check if this really is a resource request diff --git a/src/com/itmill/toolkit/terminal/web/CollectionThemeSource.java b/src/com/itmill/toolkit/terminal/web/CollectionThemeSource.java index 5f0de2e54d..728c9f403d 100644 --- a/src/com/itmill/toolkit/terminal/web/CollectionThemeSource.java +++ b/src/com/itmill/toolkit/terminal/web/CollectionThemeSource.java @@ -1,30 +1,30 @@ /* ************************************************************************* - IT Mill Toolkit + IT Mill Toolkit - Development of Browser User Intarfaces Made Easy + Development of Browser User Intarfaces Made Easy - Copyright (C) 2000-2006 IT Mill Ltd - - ************************************************************************* + Copyright (C) 2000-2006 IT Mill Ltd + + ************************************************************************* - This product is distributed under commercial license that can be found - from the product package on license/license.txt. Use of this product might - require purchasing a commercial license from IT Mill Ltd. For guidelines - on usage, see license/licensing-guidelines.html + This product is distributed under commercial license that can be found + from the product package on license/license.txt. Use of this product might + require purchasing a commercial license from IT Mill Ltd. For guidelines + on usage, see license/licensing-guidelines.html - ************************************************************************* - - For more information, contact: - - IT Mill Ltd phone: +358 2 4802 7180 - Ruukinkatu 2-4 fax: +358 2 4802 7181 - 20540, Turku email: info@itmill.com - Finland company www: www.itmill.com - - Primary source for information and releases: www.itmill.com + ************************************************************************* + + For more information, contact: + + IT Mill Ltd phone: +358 2 4802 7180 + Ruukinkatu 2-4 fax: +358 2 4802 7181 + 20540, Turku email: info@itmill.com + Finland company www: www.itmill.com + + Primary source for information and releases: www.itmill.com - ********************************************************************** */ + ********************************************************************** */ package com.itmill.toolkit.terminal.web; @@ -34,12 +34,15 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; -/** Theme source for consisting of collection of other theme sources. - * This class is used to implement the retrieval of themes - * from multiple sources. Also this class implements the inheritance - * of themes by first retrieving the relevant parent theme information. +/** + * Theme source for consisting of collection of other theme sources. This class + * is used to implement the retrieval of themes from multiple sources. Also this + * class implements the inheritance of themes by first retrieving the relevant + * parent theme information. + * * @author IT Mill Ltd. - * @version @VERSION@ + * @version + * @VERSION@ * @since 3.0 */ public class CollectionThemeSource implements ThemeSource { @@ -54,10 +57,11 @@ public class CollectionThemeSource implements ThemeSource { } /** - * @see com.itmill.toolkit.terminal.web.ThemeSource#getXSLStreams(Theme, WebBrowser) + * @see com.itmill.toolkit.terminal.web.ThemeSource#getXSLStreams(Theme, + * WebBrowser) */ public Collection getXSLStreams(Theme theme, WebBrowser type) - throws ThemeException { + throws ThemeException { Collection xslFiles = new LinkedList(); // Add parent theme XSL @@ -74,17 +78,16 @@ public class CollectionThemeSource implements ThemeSource { } private Collection getParentXSLStreams(Theme theme, WebBrowser type) - throws ThemeException { + throws ThemeException { Collection xslFiles = new LinkedList(); - Collection parents = theme.getParentThemes(); - for (Iterator i = parents.iterator(); i.hasNext();) { - String name = (String) i.next(); - Theme parent = this.getThemeByName(name); + String parentName = theme.getParent(); + if (parentName != null) { + Theme parent = this.getThemeByName(parentName); if (parent != null) { xslFiles.addAll(this.getXSLStreams(parent, type)); } else { throw new ThemeSource.ThemeException( - "Parent theme not found for name: " + name); + "Parent theme not found for name: " + parentName); } } return xslFiles; @@ -112,7 +115,7 @@ public class CollectionThemeSource implements ThemeSource { int delim = resourceId.indexOf("/"); String subResourceId = ""; String themeName = ""; - if (delim >=0 && delim < resourceId.length() - 1) { + if (delim >= 0 && delim < resourceId.length() - 1) { subResourceId = resourceId.substring(delim + 1); themeName = resourceId.substring(0, delim); } @@ -122,8 +125,9 @@ public class CollectionThemeSource implements ThemeSource { if (themeName.length() > 0) { Theme t = this.getThemeByName(themeName); if (t != null) { - themes.add(t.getName()); - addAllParents(themes, t); + themes.add(themeName); + if (t.getParent() != null) + themes.add(t.getParent()); } } @@ -134,8 +138,8 @@ public class CollectionThemeSource implements ThemeSource { // Search all sources for (Iterator i = this.sources.iterator(); i.hasNext();) { try { - InputStream in = - ((ThemeSource) i.next()).getResource(resource); + InputStream in = ((ThemeSource) i.next()) + .getResource(resource); if (in != null) return in; } catch (ThemeException e) { @@ -144,26 +148,8 @@ public class CollectionThemeSource implements ThemeSource { } } - throw new ThemeException( - "Theme resource not found:" - + subResourceId - + " in themes " - + themes); - } - /** Recusrivelu get list of parent themes in inheritace order. - * - * @param t Theme which parents should be listed - * @return Collection of themes in inheritance order. - */ - private void addAllParents(List list, Theme t) { - if (t == null) - return; - - List parents = t.getParentThemes(); - list.addAll(parents); - for (Iterator i = parents.iterator(); i.hasNext();) { - addAllParents(list, this.getThemeByName((String) i.next())); - } + throw new ThemeException("Theme resource not found:" + subResourceId + + " in themes " + themes); } /** @@ -190,8 +176,11 @@ public class CollectionThemeSource implements ThemeSource { return null; } - /**Add new theme source to this collection. - * @param source Theme source to be added. + /** + * Add new theme source to this collection. + * + * @param source + * Theme source to be added. */ public void add(ThemeSource source) { this.sources.add(source); diff --git a/src/com/itmill/toolkit/terminal/web/Theme.java b/src/com/itmill/toolkit/terminal/web/Theme.java index 91daab4bf9..e8ae703f3f 100644 --- a/src/com/itmill/toolkit/terminal/web/Theme.java +++ b/src/com/itmill/toolkit/terminal/web/Theme.java @@ -172,8 +172,8 @@ public class Theme extends DefaultHandler { /** Author of the theme. */ private Author author; - /** List of parent themes */ - private List parentThemes = new LinkedList(); + /** Name of the theme, which this theme extends */ + private String parentTheme = null; /** Fileset of included XSL files. */ private Fileset files = null; @@ -234,26 +234,30 @@ public class Theme extends DefaultHandler { * Get the preferred operating mode supported by this theme for given * terminal. */ - public String getPreferredMode(WebBrowser terminal) { + public String getPreferredMode(WebBrowser terminal, ThemeSource themeSource) { // If no supported modes are declared, then we use parents preferred // mode - if (parentThemes != null && parentThemes.size() > 0 - && supportedModes.keySet().isEmpty()) - return ((Theme) parentThemes.get(0)).getPreferredMode(terminal); - + if (parentTheme != null + && supportedModes.keySet().isEmpty()) { + Theme parent = themeSource.getThemeByName(parentTheme); + if (parent == null) + throw new IllegalStateException("Parent theme '"+parentTheme+"' is not found for theme '"+getName()+"'."); + return parent.getPreferredMode(terminal, themeSource); + } + // Iterate and test the modes in order for (Iterator i = supportedModes.keySet().iterator(); i.hasNext();) { String mode = (String) i.next(); - if (supportsMode(mode, terminal)) + if (supportsMode(mode, terminal,themeSource)) return mode; } - return MODE_FALLBACK; + return null; } /** Tests if this theme suppors given mode */ - public boolean supportsMode(String mode, WebBrowser terminal) { + public boolean supportsMode(String mode, WebBrowser terminal, ThemeSource themeSource) { // Theme must explicitly support the given mode RequirementCollection rc = (RequirementCollection) supportedModes @@ -262,9 +266,13 @@ public class Theme extends DefaultHandler { return false; // All parents must also support the mode - for (Iterator i = parentThemes.iterator(); i.hasNext();) - if (!((Theme) i.next()).supportsMode(mode, terminal)) - return false; + if (parentTheme != null) { + Theme parent = themeSource.getThemeByName(parentTheme); + if (parent == null) + throw new IllegalStateException("Parent theme '"+parentTheme+"' is not found for theme '"+getName()+"'."); + if(!parent.supportsMode(mode, terminal, themeSource)) + return false; + } return true; } @@ -324,7 +332,9 @@ public class Theme extends DefaultHandler { if (this.name.equals(themeName)) throw new IllegalArgumentException("Theme " + this.name + " extends itself."); - this.parentThemes.add(themeName); + if (parentTheme != null) + throw new IllegalArgumentException("Only one extends statement is allowed"); + this.parentTheme = themeName; } else if (TAG_FILE.equals(qName)) { File f = new File(atts.getValue(ATTR_NAME)); if (this.openFilesets.isEmpty()) { @@ -437,6 +447,11 @@ public class Theme extends DefaultHandler { this.modesListCurrentlyOpen = false; } else if (TAG_MODE.equals(qName)) { this.currentlyOpenMode = null; + } else if (TAG_OR.equals(qName) || TAG_AND.equals(qName)) { + RequirementCollection r = (RequirementCollection) openRequirements.pop(); + if (openRequirements.size() < 1) + throw new IllegalStateException(); + ((RequirementCollection)openRequirements.peek()).addRequirement(r); } } @@ -532,8 +547,8 @@ public class Theme extends DefaultHandler { * @see java.lang.Object#toString() */ public String toString() { - return this.name + " author=[" + this.author + "]" + " inherits=" - + parentThemes + "]" + " files={" + return this.name + " author='" + this.author + "'" + (parentTheme != null ? " inherits='" + + parentTheme + "'" : "" )+ " files={" + (files != null ? files.toString() : "null") + "}"; } @@ -1082,13 +1097,11 @@ public class Theme extends DefaultHandler { } /** - * Returns the list of parent themes of this theme. Returns list of all - * inherited themes in the inheritance order. + * Returns the name of the parent theme. * - * @return List of parent theme instances. */ - public List getParentThemes() { - return parentThemes; + public String getParent() { + return parentTheme; } /** Get theme description */ diff --git a/src/com/itmill/toolkit/terminal/web/WebBrowser.java b/src/com/itmill/toolkit/terminal/web/WebBrowser.java index f6091d4a14..2dd270c249 100644 --- a/src/com/itmill/toolkit/terminal/web/WebBrowser.java +++ b/src/com/itmill/toolkit/terminal/web/WebBrowser.java @@ -100,7 +100,7 @@ public class WebBrowser implements Terminal { * @return Name of the terminal window */ public String getDefaultTheme() { - return "default"; + return ApplicationServlet.DEFAULT_THEME; } /** Get the name and version of the web browser application. |