From 94acf6c2801711a015d4fc0b72b301d9abcd1448 Mon Sep 17 00:00:00 2001 From: Joonas Lehtinen Date: Fri, 2 Feb 2007 19:24:24 +0000 Subject: [PATCH] Fixed bug: uriHandlers, parameterHandlers and opened resources should only be added to lists once. svn changeset:429/svn branch:toolkit --- src/com/itmill/toolkit/ui/Window.java | 1323 +++++++++++++------------ 1 file changed, 664 insertions(+), 659 deletions(-) diff --git a/src/com/itmill/toolkit/ui/Window.java b/src/com/itmill/toolkit/ui/Window.java index ccc7ae6b2b..974990f48c 100644 --- a/src/com/itmill/toolkit/ui/Window.java +++ b/src/com/itmill/toolkit/ui/Window.java @@ -1,30 +1,30 @@ /* ************************************************************************* - IT Mill Toolkit + IT Mill Toolkit - Development of Browser User Interfaces Made Easy + Development of Browser User Interfaces 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.pdf. Use of this product might - require purchasing a commercial license from IT Mill Ltd. For guidelines - on usage, see licensing-guidelines.html + This product is distributed under commercial license that can be found + from the product package on license.pdf. Use of this product might + require purchasing a commercial license from IT Mill Ltd. For guidelines + on usage, see 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.ui; @@ -56,643 +56,648 @@ import java.util.Iterator; */ public class Window extends Panel implements URIHandler, ParameterHandler { - /** Window with no border */ - public static final int BORDER_NONE = 0; - - /** Window with only minimal border */ - public static final int BORDER_MINIMAL = 1; - - /** Window with default borders */ - public static final int BORDER_DEFAULT = 2; - - /** The terminal this window is attached to */ - private Terminal terminal = null; - - /** The applicaiton this window is attached to */ - private Application application = null; - - /** List of URI handlers for this window */ - private LinkedList uriHandlerList = null; - - /** List of parameter handlers for this window */ - private LinkedList parameterHandlerList = null; - - /** - * Explicitly specified theme of this window. If null, application theme is - * used - */ - private String theme = null; - - /** Resources to be opened automatically on next repaint */ - private LinkedList openList = new LinkedList(); - - /** The name of the window */ - private String name = null; - - /** Window border mode */ - private int border = BORDER_DEFAULT; - - /** Focused component */ - private Focusable focusedComponent; - - /* ********************************************************************* */ - - /** - * Create new empty unnamed window with default layout. - * - *

- * To show the window in application, it must be added to application with - * Application.addWindow() method. - *

- * - *

- * The windows are scrollable by default. - *

- * - * @param caption - * Title of the window - */ - public Window() { - this("", null); - } - - /** - * Create new empty window with default layout. - * - *

- * To show the window in application, it must be added to application with - * Application.addWindow() method. - *

- * - *

- * The windows are scrollable by default. - *

- * - * @param caption - * Title of the window - */ - public Window(String caption) { - this(caption, null); - } - - /** - * Create new window. - * - *

- * To show the window in application, it must be added to application with - * Application.addWindow() method. - *

- * - *

- * The windows are scrollable by default. - *

- * - * @param caption - * Title of the window - * @param layout - * Layout of the window - */ - public Window(String caption, Layout layout) { - super(caption, layout); - setScrollable(true); - } - - /** - * Get terminal type. - * - * @return Value of property terminal. - */ - public Terminal getTerminal() { - return this.terminal; - } - - /* ********************************************************************* */ - - /** - * Get window of the component. Returns the window where this component - * belongs to. If the component does not yet belong to a window the returns - * null. - * - * @return parent window of the component. - */ - public final Window getWindow() { - return this; - } - - /** - * Get application instance of the component. Returns the application where - * this component belongs to. If the component does not yet belong to a - * application the returns null. - * - * @return parent application of the component. - */ - public final Application getApplication() { - return this.application; - } - - /** - * Getter for property parent. Parent is the visual parent of a component. - * Each component can belong to only one ComponentContainer at time. - * - * @return Value of property parent. - */ - public final Component getParent() { - return null; - } - - /** - * Setter for property parent. Parent is the visual parent of a component. - * This is mostly called by containers add method. Setting parent is not - * allowed for the window, and thus this call should newer be called. - * - * @param parent - * New value of property parent. - */ - public void setParent(Component parent) { - throw new RuntimeException("Setting parent for Window is not allowed"); - } - - /** - * Get component UIDL tag. - * - * @return Component UIDL tag as string. - */ - public String getTag() { - return "window"; - } - - /* ********************************************************************* */ - - /** Add new URI handler to this window */ - public void addURIHandler(URIHandler handler) { - if (uriHandlerList == null) - uriHandlerList = new LinkedList(); - synchronized (uriHandlerList) { - uriHandlerList.addLast(handler); - } - } - - /** Remove given URI handler from this window */ - public void removeURIHandler(URIHandler handler) { - if (handler == null || uriHandlerList == null) - return; - synchronized (uriHandlerList) { - uriHandlerList.remove(handler); - if (uriHandlerList.isEmpty()) - uriHandlerList = null; - } - } - - /** - * Handle uri recursively. - */ - public DownloadStream handleURI(URL context, String relativeUri) { - DownloadStream result = null; - if (uriHandlerList != null) { - Object[] handlers; - synchronized (uriHandlerList) { - handlers = uriHandlerList.toArray(); - } - for (int i = 0; i < handlers.length; i++) { - DownloadStream ds = ((URIHandler) handlers[i]).handleURI( - context, relativeUri); - if (ds != null) { - if (result != null) - throw new RuntimeException("handleURI for " + context - + " uri: '" + relativeUri - + "' returns ambigious result."); - result = ds; - } - } - } - return result; - } - - /* ********************************************************************* */ - - /** Add new parameter handler to this window. */ - public void addParameterHandler(ParameterHandler handler) { - if (parameterHandlerList == null) - parameterHandlerList = new LinkedList(); - synchronized (parameterHandlerList) { - parameterHandlerList.addLast(handler); - } - } - - /** Remove given URI handler from this window. */ - public void removeParameterHandler(ParameterHandler handler) { - if (handler == null || parameterHandlerList == null) - return; - synchronized (parameterHandlerList) { - parameterHandlerList.remove(handler); - if (parameterHandlerList.isEmpty()) - parameterHandlerList = null; - } - } - - /* Documented by the interface */ - public void handleParameters(Map parameters) { - if (parameterHandlerList != null) { - Object[] handlers; - synchronized (parameterHandlerList) { - handlers = parameterHandlerList.toArray(); - } - for (int i = 0; i < handlers.length; i++) - ((ParameterHandler) handlers[i]).handleParameters(parameters); - } - } - - /* ********************************************************************* */ - - /** - * Get theme for this window. - * - * @return Name of the theme used in window. If the theme for this - * individual window is not explicitly set, the application theme is - * used instead. If application is not assigned the - * terminal.getDefaultTheme is used. If terminal is not set, null is - * returned - */ - public String getTheme() { - if (theme != null) - return theme; - if ((application != null) && (application.getTheme() != null)) - return application.getTheme(); - if (terminal != null) - return terminal.getDefaultTheme(); - return null; - } - - /** - * Set theme for this window. - * - * @param theme - * New theme for this window. Null implies the default theme. - */ - public void setTheme(String theme) { - this.theme = theme; - requestRepaint(); - } - - /** - * Paint the content of this component. - * - * @param event - * PaintEvent. - * @throws PaintException - * The paint operation failed. - */ - public synchronized void paintContent(PaintTarget target) - throws PaintException { - - // Set the window name - target.addAttribute("name", getName()); - - // Set the window theme - target.addAttribute("theme", getTheme()); - - // Mark main window - if (getApplication() != null - && this == getApplication().getMainWindow()) - target.addAttribute("main", true); - - // Open requested resource - synchronized (openList) { - if (!openList.isEmpty()) { - for (Iterator i = openList.iterator(); i.hasNext();) - ((OpenResource) i.next()).paintContent(target); - openList.clear(); - } - } - - // Contents of the window panel is painted - super.paintContent(target); - - // Set focused component - if (this.focusedComponent != null) - target.addVariable(this, "focused", "" - + this.focusedComponent.getFocusableId()); - else - target.addVariable(this, "focused", ""); - - } - - /* ********************************************************************* */ - - /** - * Open the given resource in this window. - */ - public void open(Resource resource) { - synchronized (openList) { - openList.add(new OpenResource(resource, null, -1, -1, - BORDER_DEFAULT)); - } - requestRepaint(); - } - - /* ********************************************************************* */ - - /** - * Open the given resource in named terminal window. Empty or - * null window name results the resource to be opened in this - * window. - */ - public void open(Resource resource, String windowName) { - synchronized (openList) { - openList.add(new OpenResource(resource, windowName, -1, -1, - BORDER_DEFAULT)); - } - requestRepaint(); - } - - /* ********************************************************************* */ - - /** - * Open the given resource in named terminal window with given size and - * border properties. Empty or null window name results the - * resource to be opened in this window. - */ - public void open(Resource resource, String windowName, int width, - int height, int border) { - synchronized (openList) { - openList.add(new OpenResource(resource, windowName, width, height, - border)); - } - requestRepaint(); - } - - /* ********************************************************************* */ - - /** - * Returns the full url of the window, this returns window specific url even - * for the main window. - * - * @return String - */ - public URL getURL() { - - if (application == null) - return null; - - try { - return new URL(application.getURL(), getName() + "/"); - } catch (MalformedURLException e) { - throw new RuntimeException("Internal problem, please report"); - } - } - - /** - * Get the unique name of the window that indentifies it on the terminal. - * - * @return String - */ - public String getName() { - return name; - } - - /** - * Returns the border. - * - * @return int - */ - public int getBorder() { - return border; - } - - /** - * Sets the border. - * - * @param border - * The border to set - */ - public void setBorder(int border) { - this.border = border; - } - - /** - * Sets the application this window is connected to. - * - *

- * This method should not be invoked directly. Instead the - * {@link com.itmill.toolkit.Application#addWindow(Window)} method should be - * used to add the window to an application and - * {@link com.itmill.toolkit.Application#removeWindow(Window)} method for - * removing the window from the applicion. These methods call this method - * implicitly. - *

- * - *

- * The method invokes {@link Component#attach()} and - * {@link Component#detach()} methods when necessary. - *

- * - * @param application - * The application to set - */ - public void setApplication(Application application) { - - // If the application is not changed, dont do nothing - if (application == this.application) - return; - - // Send detach event if the window is connected to application - if (this.application != null) { - detach(); - } - - // Connect to new parent - this.application = application; - - // Send attach event if connected to a window - if (application != null) - attach(); - } - - /** - * Sets the name. - *

- * The name of the window must be unique inside the application. Also the - * name may only contain the following characters: a-z, A-Z and 0-9. - *

- * - *

- * If the name is null, the the window is given name automatically when it - * is added to an application. - *

- * - * @param name - * The name to set - */ - public void setName(String name) { - - // The name can not be changed in application - if (getApplication() != null) - throw new IllegalStateException( - "Window name can not be changed while " - + "the window is in application"); - - // Check the name format - if (name != null) - for (int i = 0; i < name.length(); i++) { - char c = name.charAt(i); - if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9'))) - throw new IllegalArgumentException( - "Window name can contain " - + "only a-z, A-Z and 0-9 characters: '" - + name + "' given."); - } - - this.name = name; - } - - /** - * Set terminal type. The terminal type is set by the the terminal adapter - * and may change from time to time. - * - * @param type - * terminal type to set - */ - public void setTerminal(Terminal type) { - this.terminal = type; - } - - /** - * Window only supports pixels as unit. - * - * @see com.itmill.toolkit.terminal.Sizeable#getHeightUnits() - */ - public void setHeightUnits(int units) { - if (units != Sizeable.UNITS_PIXELS) - throw new IllegalArgumentException("Only pixels are supported"); - } - - /** - * Window only supports pixels as unit. - * - * @see com.itmill.toolkit.terminal.Sizeable#getWidthUnits() - */ - public void setWidthUnits(int units) { - if (units != Sizeable.UNITS_PIXELS) - throw new IllegalArgumentException("Only pixels are supported"); - } - - /** Private data structure for storing opening window properties */ - private class OpenResource { - - private Resource resource; - - private String name; - - private int width; - - private int height; - - private int border; - - /** Create new open resource */ - private OpenResource(Resource resource, String name, int width, - int height, int border) { - this.resource = resource; - this.name = name; - this.width = width; - this.height = height; - this.border = border; - } - - /** Paint the open-tag inside the window. */ - private void paintContent(PaintTarget target) throws PaintException { - target.startTag("open"); - target.addAttribute("src", resource); - if (name != null && name.length() > 0) - target.addAttribute("name", name); - if (width >= 0) - target.addAttribute("width", width); - if (height >= 0) - target.addAttribute("height", height); - switch (border) { - case Window.BORDER_MINIMAL: - target.addAttribute("border", "minimal"); - break; - case Window.BORDER_NONE: - target.addAttribute("border", "none"); - break; - } - - target.endTag("open"); - } - } - - /** - * @see com.itmill.toolkit.terminal.VariableOwner#changeVariables(java.lang.Object, - * java.util.Map) - */ - public void changeVariables(Object source, Map variables) { - super.changeVariables(source, variables); - - // Get focused component - String focusedId = (String) variables.get("focused"); - if (focusedId != null) { - try { - long id = Long.parseLong(focusedId); - this.focusedComponent = Window.getFocusableById(id); - } catch (NumberFormatException ignored) { - // We ignore invalid focusable ids - } - } - - } - - /** - * Get currently focused component in this window. - * - * @return Focused component or null if none is focused. - */ - public Component.Focusable getFocusedComponent() { - return this.focusedComponent; - } - - /** - * Set currently focused component in this window. - * - * @param focusable - * Focused component or null if none is focused. - */ - public void setFocusedComponent(Component.Focusable focusable) { - this.focusedComponent = focusable; - } - - /* Focusable id generator ****************************************** */ - - private static long lastUsedFocusableId = 0; - - private static Map focusableComponents = new HashMap(); - - /** Get an id for focusable component. */ - public static long getNewFocusableId(Component.Focusable focusable) { - long newId = ++lastUsedFocusableId; - WeakReference ref = new WeakReference(focusable); - focusableComponents.put(new Long(newId), ref); - return newId; - } - - /** Map focusable id back to focusable component. */ - public static Component.Focusable getFocusableById(long focusableId) { - WeakReference ref = (WeakReference) focusableComponents.get(new Long( - focusableId)); - if (ref != null) { - Object o = ref.get(); - if (o != null) { - return (Component.Focusable) o; - } - } - return null; - } - - /** Release focusable component id when not used anymore. */ - public static void removeFocusableId(long focusableId) { - Long id = new Long(focusableId); - WeakReference ref = (WeakReference) focusableComponents.get(id); - ref.clear(); - focusableComponents.remove(id); - } + /** Window with no border */ + public static final int BORDER_NONE = 0; + + /** Window with only minimal border */ + public static final int BORDER_MINIMAL = 1; + + /** Window with default borders */ + public static final int BORDER_DEFAULT = 2; + + /** The terminal this window is attached to */ + private Terminal terminal = null; + + /** The applicaiton this window is attached to */ + private Application application = null; + + /** List of URI handlers for this window */ + private LinkedList uriHandlerList = null; + + /** List of parameter handlers for this window */ + private LinkedList parameterHandlerList = null; + + /** + * Explicitly specified theme of this window. If null, application theme is + * used + */ + private String theme = null; + + /** Resources to be opened automatically on next repaint */ + private LinkedList openList = new LinkedList(); + + /** The name of the window */ + private String name = null; + + /** Window border mode */ + private int border = BORDER_DEFAULT; + + /** Focused component */ + private Focusable focusedComponent; + + /* ********************************************************************* */ + + /** + * Create new empty unnamed window with default layout. + * + *

+ * To show the window in application, it must be added to application with + * Application.addWindow() method. + *

+ * + *

+ * The windows are scrollable by default. + *

+ * + * @param caption + * Title of the window + */ + public Window() { + this("", null); + } + + /** + * Create new empty window with default layout. + * + *

+ * To show the window in application, it must be added to application with + * Application.addWindow() method. + *

+ * + *

+ * The windows are scrollable by default. + *

+ * + * @param caption + * Title of the window + */ + public Window(String caption) { + this(caption, null); + } + + /** + * Create new window. + * + *

+ * To show the window in application, it must be added to application with + * Application.addWindow() method. + *

+ * + *

+ * The windows are scrollable by default. + *

+ * + * @param caption + * Title of the window + * @param layout + * Layout of the window + */ + public Window(String caption, Layout layout) { + super(caption, layout); + setScrollable(true); + } + + /** + * Get terminal type. + * + * @return Value of property terminal. + */ + public Terminal getTerminal() { + return this.terminal; + } + + /* ********************************************************************* */ + + /** + * Get window of the component. Returns the window where this component + * belongs to. If the component does not yet belong to a window the returns + * null. + * + * @return parent window of the component. + */ + public final Window getWindow() { + return this; + } + + /** + * Get application instance of the component. Returns the application where + * this component belongs to. If the component does not yet belong to a + * application the returns null. + * + * @return parent application of the component. + */ + public final Application getApplication() { + return this.application; + } + + /** + * Getter for property parent. Parent is the visual parent of a component. + * Each component can belong to only one ComponentContainer at time. + * + * @return Value of property parent. + */ + public final Component getParent() { + return null; + } + + /** + * Setter for property parent. Parent is the visual parent of a component. + * This is mostly called by containers add method. Setting parent is not + * allowed for the window, and thus this call should newer be called. + * + * @param parent + * New value of property parent. + */ + public void setParent(Component parent) { + throw new RuntimeException("Setting parent for Window is not allowed"); + } + + /** + * Get component UIDL tag. + * + * @return Component UIDL tag as string. + */ + public String getTag() { + return "window"; + } + + /* ********************************************************************* */ + + /** Add new URI handler to this window */ + public void addURIHandler(URIHandler handler) { + if (uriHandlerList == null) + uriHandlerList = new LinkedList(); + synchronized (uriHandlerList) { + if (!uriHandlerList.contains(handler)) + uriHandlerList.addLast(handler); + } + } + + /** Remove given URI handler from this window */ + public void removeURIHandler(URIHandler handler) { + if (handler == null || uriHandlerList == null) + return; + synchronized (uriHandlerList) { + uriHandlerList.remove(handler); + if (uriHandlerList.isEmpty()) + uriHandlerList = null; + } + } + + /** + * Handle uri recursively. + */ + public DownloadStream handleURI(URL context, String relativeUri) { + DownloadStream result = null; + if (uriHandlerList != null) { + Object[] handlers; + synchronized (uriHandlerList) { + handlers = uriHandlerList.toArray(); + } + for (int i = 0; i < handlers.length; i++) { + DownloadStream ds = ((URIHandler) handlers[i]).handleURI( + context, relativeUri); + if (ds != null) { + if (result != null) + throw new RuntimeException("handleURI for " + context + + " uri: '" + relativeUri + + "' returns ambigious result."); + result = ds; + } + } + } + return result; + } + + /* ********************************************************************* */ + + /** Add new parameter handler to this window. */ + public void addParameterHandler(ParameterHandler handler) { + if (parameterHandlerList == null) + parameterHandlerList = new LinkedList(); + synchronized (parameterHandlerList) { + if (!parameterHandlerList.contains(handler)) + parameterHandlerList.addLast(handler); + } + } + + /** Remove given URI handler from this window. */ + public void removeParameterHandler(ParameterHandler handler) { + if (handler == null || parameterHandlerList == null) + return; + synchronized (parameterHandlerList) { + parameterHandlerList.remove(handler); + if (parameterHandlerList.isEmpty()) + parameterHandlerList = null; + } + } + + /* Documented by the interface */ + public void handleParameters(Map parameters) { + if (parameterHandlerList != null) { + Object[] handlers; + synchronized (parameterHandlerList) { + handlers = parameterHandlerList.toArray(); + } + for (int i = 0; i < handlers.length; i++) + ((ParameterHandler) handlers[i]).handleParameters(parameters); + } + } + + /* ********************************************************************* */ + + /** + * Get theme for this window. + * + * @return Name of the theme used in window. If the theme for this + * individual window is not explicitly set, the application theme is + * used instead. If application is not assigned the + * terminal.getDefaultTheme is used. If terminal is not set, null is + * returned + */ + public String getTheme() { + if (theme != null) + return theme; + if ((application != null) && (application.getTheme() != null)) + return application.getTheme(); + if (terminal != null) + return terminal.getDefaultTheme(); + return null; + } + + /** + * Set theme for this window. + * + * @param theme + * New theme for this window. Null implies the default theme. + */ + public void setTheme(String theme) { + this.theme = theme; + requestRepaint(); + } + + /** + * Paint the content of this component. + * + * @param event + * PaintEvent. + * @throws PaintException + * The paint operation failed. + */ + public synchronized void paintContent(PaintTarget target) + throws PaintException { + + // Set the window name + target.addAttribute("name", getName()); + + // Set the window theme + target.addAttribute("theme", getTheme()); + + // Mark main window + if (getApplication() != null + && this == getApplication().getMainWindow()) + target.addAttribute("main", true); + + // Open requested resource + synchronized (openList) { + if (!openList.isEmpty()) { + for (Iterator i = openList.iterator(); i.hasNext();) + ((OpenResource) i.next()).paintContent(target); + openList.clear(); + } + } + + // Contents of the window panel is painted + super.paintContent(target); + + // Set focused component + if (this.focusedComponent != null) + target.addVariable(this, "focused", "" + + this.focusedComponent.getFocusableId()); + else + target.addVariable(this, "focused", ""); + + } + + /* ********************************************************************* */ + + /** + * Open the given resource in this window. + */ + public void open(Resource resource) { + synchronized (openList) { + if (!openList.contains(resource)) + openList.add(new OpenResource(resource, null, -1, -1, + BORDER_DEFAULT)); + } + requestRepaint(); + } + + /* ********************************************************************* */ + + /** + * Open the given resource in named terminal window. Empty or + * null window name results the resource to be opened in this + * window. + */ + public void open(Resource resource, String windowName) { + synchronized (openList) { + if (!openList.contains(resource)) + openList.add(new OpenResource(resource, windowName, -1, -1, + BORDER_DEFAULT)); + } + requestRepaint(); + } + + /* ********************************************************************* */ + + /** + * Open the given resource in named terminal window with given size and + * border properties. Empty or null window name results the + * resource to be opened in this window. + */ + public void open(Resource resource, String windowName, int width, + int height, int border) { + synchronized (openList) { + if (!openList.contains(resource)) + openList.add(new OpenResource(resource, windowName, width, + height, border)); + } + requestRepaint(); + } + + /* ********************************************************************* */ + + /** + * Returns the full url of the window, this returns window specific url even + * for the main window. + * + * @return String + */ + public URL getURL() { + + if (application == null) + return null; + + try { + return new URL(application.getURL(), getName() + "/"); + } catch (MalformedURLException e) { + throw new RuntimeException("Internal problem, please report"); + } + } + + /** + * Get the unique name of the window that indentifies it on the terminal. + * + * @return String + */ + public String getName() { + return name; + } + + /** + * Returns the border. + * + * @return int + */ + public int getBorder() { + return border; + } + + /** + * Sets the border. + * + * @param border + * The border to set + */ + public void setBorder(int border) { + this.border = border; + } + + /** + * Sets the application this window is connected to. + * + *

+ * This method should not be invoked directly. Instead the + * {@link com.itmill.toolkit.Application#addWindow(Window)} method should be + * used to add the window to an application and + * {@link com.itmill.toolkit.Application#removeWindow(Window)} method for + * removing the window from the applicion. These methods call this method + * implicitly. + *

+ * + *

+ * The method invokes {@link Component#attach()} and + * {@link Component#detach()} methods when necessary. + *

+ * + * @param application + * The application to set + */ + public void setApplication(Application application) { + + // If the application is not changed, dont do nothing + if (application == this.application) + return; + + // Send detach event if the window is connected to application + if (this.application != null) { + detach(); + } + + // Connect to new parent + this.application = application; + + // Send attach event if connected to a window + if (application != null) + attach(); + } + + /** + * Sets the name. + *

+ * The name of the window must be unique inside the application. Also the + * name may only contain the following characters: a-z, A-Z and 0-9. + *

+ * + *

+ * If the name is null, the the window is given name automatically when it + * is added to an application. + *

+ * + * @param name + * The name to set + */ + public void setName(String name) { + + // The name can not be changed in application + if (getApplication() != null) + throw new IllegalStateException( + "Window name can not be changed while " + + "the window is in application"); + + // Check the name format + if (name != null) + for (int i = 0; i < name.length(); i++) { + char c = name.charAt(i); + if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9'))) + throw new IllegalArgumentException( + "Window name can contain " + + "only a-z, A-Z and 0-9 characters: '" + + name + "' given."); + } + + this.name = name; + } + + /** + * Set terminal type. The terminal type is set by the the terminal adapter + * and may change from time to time. + * + * @param type + * terminal type to set + */ + public void setTerminal(Terminal type) { + this.terminal = type; + } + + /** + * Window only supports pixels as unit. + * + * @see com.itmill.toolkit.terminal.Sizeable#getHeightUnits() + */ + public void setHeightUnits(int units) { + if (units != Sizeable.UNITS_PIXELS) + throw new IllegalArgumentException("Only pixels are supported"); + } + + /** + * Window only supports pixels as unit. + * + * @see com.itmill.toolkit.terminal.Sizeable#getWidthUnits() + */ + public void setWidthUnits(int units) { + if (units != Sizeable.UNITS_PIXELS) + throw new IllegalArgumentException("Only pixels are supported"); + } + + /** Private data structure for storing opening window properties */ + private class OpenResource { + + private Resource resource; + + private String name; + + private int width; + + private int height; + + private int border; + + /** Create new open resource */ + private OpenResource(Resource resource, String name, int width, + int height, int border) { + this.resource = resource; + this.name = name; + this.width = width; + this.height = height; + this.border = border; + } + + /** Paint the open-tag inside the window. */ + private void paintContent(PaintTarget target) throws PaintException { + target.startTag("open"); + target.addAttribute("src", resource); + if (name != null && name.length() > 0) + target.addAttribute("name", name); + if (width >= 0) + target.addAttribute("width", width); + if (height >= 0) + target.addAttribute("height", height); + switch (border) { + case Window.BORDER_MINIMAL: + target.addAttribute("border", "minimal"); + break; + case Window.BORDER_NONE: + target.addAttribute("border", "none"); + break; + } + + target.endTag("open"); + } + } + + /** + * @see com.itmill.toolkit.terminal.VariableOwner#changeVariables(java.lang.Object, + * java.util.Map) + */ + public void changeVariables(Object source, Map variables) { + super.changeVariables(source, variables); + + // Get focused component + String focusedId = (String) variables.get("focused"); + if (focusedId != null) { + try { + long id = Long.parseLong(focusedId); + this.focusedComponent = Window.getFocusableById(id); + } catch (NumberFormatException ignored) { + // We ignore invalid focusable ids + } + } + + } + + /** + * Get currently focused component in this window. + * + * @return Focused component or null if none is focused. + */ + public Component.Focusable getFocusedComponent() { + return this.focusedComponent; + } + + /** + * Set currently focused component in this window. + * + * @param focusable + * Focused component or null if none is focused. + */ + public void setFocusedComponent(Component.Focusable focusable) { + this.focusedComponent = focusable; + } + + /* Focusable id generator ****************************************** */ + + private static long lastUsedFocusableId = 0; + + private static Map focusableComponents = new HashMap(); + + /** Get an id for focusable component. */ + public static long getNewFocusableId(Component.Focusable focusable) { + long newId = ++lastUsedFocusableId; + WeakReference ref = new WeakReference(focusable); + focusableComponents.put(new Long(newId), ref); + return newId; + } + + /** Map focusable id back to focusable component. */ + public static Component.Focusable getFocusableById(long focusableId) { + WeakReference ref = (WeakReference) focusableComponents.get(new Long( + focusableId)); + if (ref != null) { + Object o = ref.get(); + if (o != null) { + return (Component.Focusable) o; + } + } + return null; + } + + /** Release focusable component id when not used anymore. */ + public static void removeFocusableId(long focusableId) { + Long id = new Long(focusableId); + WeakReference ref = (WeakReference) focusableComponents.get(id); + ref.clear(); + focusableComponents.remove(id); + } } -- 2.39.5