]> source.dussan.org Git - vaadin-framework.git/commitdiff
Notifications API.
authorMarc Englund <marc.englund@itmill.com>
Mon, 5 Nov 2007 15:25:43 +0000 (15:25 +0000)
committerMarc Englund <marc.englund@itmill.com>
Mon, 5 Nov 2007 15:25:43 +0000 (15:25 +0000)
+ small fix for richtextarea

svn changeset:2712/svn branch:trunk

WebContent/WEB-INF/web.xml
src/com/itmill/toolkit/demo/NotificationDemo.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/client/ui/Notification.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/client/ui/richtextarea/IRichTextArea.java
src/com/itmill/toolkit/terminal/gwt/public/default/styles.css
src/com/itmill/toolkit/terminal/gwt/public/default/window/notification.css [new file with mode: 0644]
src/com/itmill/toolkit/ui/Window.java

index 1a962304385fdaf542d2f86e2ada32e8a9fe2775..ede3cfa876256f38250a1499439f540b03df1382 100644 (file)
     </init-param>\r
   </servlet>\r
   \r
+  <servlet>\r
+    <servlet-name>NotificationDemo</servlet-name>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
+    <init-param>\r
+      <param-name>application</param-name>\r
+      <param-value>com.itmill.toolkit.demo.NotificationDemo</param-value>\r
+    </init-param>\r
+  </servlet>\r
+  \r
   \r
         <servlet-mapping>\r
     <servlet-name>TestForNativeWindowing</servlet-name>\r
     <servlet-name>CachingDemo</servlet-name>\r
     <url-pattern>/CachingDemo/*</url-pattern>\r
   </servlet-mapping>\r
+\r
+  <servlet-mapping>\r
+    <servlet-name>NotificationDemo</servlet-name>\r
+    <url-pattern>/NotificationDemo/*</url-pattern>\r
+  </servlet-mapping>\r
 
   <welcome-file-list>\r
     <welcome-file>index.jsp</welcome-file>\r
diff --git a/src/com/itmill/toolkit/demo/NotificationDemo.java b/src/com/itmill/toolkit/demo/NotificationDemo.java
new file mode 100644 (file)
index 0000000..00cfd18
--- /dev/null
@@ -0,0 +1,82 @@
+package com.itmill.toolkit.demo;
+
+import com.itmill.toolkit.data.Item;
+import com.itmill.toolkit.ui.Button;
+import com.itmill.toolkit.ui.NativeSelect;
+import com.itmill.toolkit.ui.RichTextArea;
+import com.itmill.toolkit.ui.Select;
+import com.itmill.toolkit.ui.TextField;
+import com.itmill.toolkit.ui.Window;
+import com.itmill.toolkit.ui.Button.ClickEvent;
+import com.itmill.toolkit.ui.Button.ClickListener;
+
+/**
+ * Demonstrates the use of Notifications.
+ * 
+ * @author IT Mill Ltd.
+ * @see com.itmill.toolkit.ui.Window
+ */
+public class NotificationDemo extends com.itmill.toolkit.Application {
+
+       NativeSelect type;
+       TextField caption;
+       TextField message;
+
+       /**
+        * The initialization method that is the only requirement for inheriting the
+        * com.itmill.toolkit.service.Application class. It will be automatically
+        * called by the framework when a user accesses the application.
+        */
+       public void init() {
+
+               /*
+                * - Create new window for the application - Give the window a visible
+                * title - Set the window to be the main window of the application
+                */
+               Window main = new Window("Notification demo");
+               setMainWindow(main);
+
+               Window conf = new Window("Show Notification");
+               conf.setWidth(450);
+               conf.setHeight(340);
+               main.addWindow(conf);
+
+               type = new NativeSelect("Notification type");
+               type.addContainerProperty("caption", String.class, null);
+               type.setNullSelectionAllowed(false);
+               type.setItemCaptionMode(Select.ITEM_CAPTION_MODE_PROPERTY);
+               type.setItemCaptionPropertyId("caption");
+               Item i = type.addItem(new Integer(
+                               Window.Notification.TYPE_HUMANIZED_MESSAGE));
+               i.getItemProperty("caption").setValue("Humanized message");
+               i = type.addItem(new Integer(Window.Notification.TYPE_WARNING_MESSAGE));
+               i.getItemProperty("caption").setValue("Warning message");
+               i = type.addItem(new Integer(Window.Notification.TYPE_ERROR_MESSAGE));
+               i.getItemProperty("caption").setValue("Error message");
+               i = type
+                               .addItem(new Integer(Window.Notification.TYPE_TRAY_NOTIFICATION));
+               i.getItemProperty("caption").setValue("Tray notification");
+               type.setValue(new Integer(Window.Notification.TYPE_HUMANIZED_MESSAGE));
+               conf.addComponent(type);
+
+               caption = new TextField("Caption");
+               caption.setValue("Saved!");
+               caption.setColumns(20);
+               conf.addComponent(caption);
+
+               message = new RichTextArea();
+               message.setCaption("Message");
+               message.setValue("Your stuff has been saved in <b>MyDocuments</b>.");
+               conf.addComponent(message);
+
+               Button b = new Button("Show notification", new ClickListener() {
+                       public void buttonClick(ClickEvent event) {
+                               getMainWindow().showNotification((String) caption.getValue(),
+                                               (String) message.getValue(),
+                                               ((Integer) type.getValue()).intValue());
+                       }
+
+               });
+               conf.addComponent(b);
+       }
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/Notification.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/Notification.java
new file mode 100644 (file)
index 0000000..cd47400
--- /dev/null
@@ -0,0 +1,229 @@
+package com.itmill.toolkit.terminal.gwt.client.ui;\r
+\r
+import com.google.gwt.user.client.DOM;\r
+import com.google.gwt.user.client.Element;\r
+import com.google.gwt.user.client.Event;\r
+import com.google.gwt.user.client.EventPreview;\r
+import com.google.gwt.user.client.Timer;\r
+import com.google.gwt.user.client.ui.HTML;\r
+import com.google.gwt.user.client.ui.PopupPanel;\r
+import com.google.gwt.user.client.ui.Widget;\r
+\r
+public class Notification extends PopupPanel {\r
+\r
+       public static final int CENTERED = 1;\r
+       public static final int CENTERED_TOP = 2;\r
+       public static final int CENTERED_BOTTOM = 3;\r
+       public static final int TOP_LEFT = 4;\r
+       public static final int TOP_RIGHT = 5;\r
+       public static final int BOTTOM_LEFT = 6;\r
+       public static final int BOTTOM_RIGHT = 7;\r
+\r
+       public static final int DELAY_FOREVER = -1;\r
+       public static final int DELAY_NONE = 0;\r
+\r
+       private static final String STYLENAME = "i-Notification";\r
+       private static final int mouseMoveThreshold = 7;\r
+       private static final int Z_INDEX_BASE = 20000;\r
+\r
+       private int startOpacity = 90;\r
+       private int fadeMsec = 400;\r
+       private int delayMsec = 1000;\r
+\r
+       private Timer fader;\r
+       private Timer delay;\r
+       private EventPreview eventPreview;\r
+\r
+       private String temporaryStyle;\r
+\r
+       public Notification() {\r
+               setStylePrimaryName(STYLENAME);\r
+               sinkEvents(Event.ONCLICK);\r
+               DOM.setStyleAttribute(getElement(), "zIndex", "" + Z_INDEX_BASE);\r
+       }\r
+\r
+       public Notification(int delayMsec) {\r
+               this();\r
+               this.delayMsec = delayMsec;\r
+       }\r
+\r
+       public Notification(int delayMsec, int fadeMsec, int startOpacity) {\r
+               this(delayMsec);\r
+               this.fadeMsec = fadeMsec;\r
+               this.startOpacity = startOpacity;\r
+       }\r
+\r
+       public void startDelay() {\r
+               DOM.removeEventPreview(eventPreview);\r
+               if (delayMsec > 0) {\r
+                       delay = new Timer() {\r
+                               public void run() {\r
+                                       fade();\r
+                               }\r
+                       };\r
+                       delay.scheduleRepeating(delayMsec);\r
+               } else if (delayMsec == 0) {\r
+                       fade();\r
+               }\r
+       }\r
+\r
+       public void show() {\r
+               show(CENTERED);\r
+       }\r
+\r
+       public void show(String style) {\r
+               show(CENTERED, style);\r
+       }\r
+\r
+       public void show(int position) {\r
+               show(position, null);\r
+       }\r
+\r
+       public void show(Widget widget, int position, String style) {\r
+               setWidget(widget);\r
+               show(position, style);\r
+       }\r
+\r
+       public void show(String html, int position, String style) {\r
+               setWidget(new HTML(html));\r
+               show(position, style);\r
+       }\r
+\r
+       public void show(int position, String style) {\r
+               hide();\r
+               setOpacity(getElement(), startOpacity);\r
+               if (style != null) {\r
+                       this.temporaryStyle = style;\r
+                       addStyleName(style);\r
+               }\r
+               super.show();\r
+               setPosition(position);\r
+\r
+               if (eventPreview == null) {\r
+                       eventPreview = new EventPreview() {\r
+                               int x = -1;\r
+                               int y = -1;\r
+\r
+                               public boolean onEventPreview(Event event) {\r
+                                       switch (DOM.eventGetType(event)) {\r
+                                       case Event.ONMOUSEMOVE:\r
+                                               if (x < 0) {\r
+                                                       x = DOM.eventGetClientX(event);\r
+                                                       y = DOM.eventGetClientY(event);\r
+                                               } else if (Math.abs(DOM.eventGetClientX(event) - x) > mouseMoveThreshold\r
+                                                               || Math.abs(DOM.eventGetClientY(event) - y) > mouseMoveThreshold) {\r
+                                                       startDelay();\r
+                                               }\r
+                                               break;\r
+                                       case Event.KEYEVENTS:\r
+                                       case Event.ONCLICK:\r
+                                       case Event.ONDBLCLICK:\r
+                                       case Event.ONSCROLL:\r
+                                       default:\r
+                                               startDelay();\r
+                                       }\r
+                                       return true;\r
+                               }\r
+                       };\r
+               }\r
+\r
+               DOM.addEventPreview(eventPreview);\r
+       }\r
+\r
+       public void hide() {\r
+               DOM.removeEventPreview(eventPreview);\r
+               cancelDelay();\r
+               cancelFade();\r
+               if (this.temporaryStyle != null) {\r
+                       removeStyleName(this.temporaryStyle);\r
+                       this.temporaryStyle = null;\r
+               }\r
+               super.hide();\r
+       }\r
+\r
+       public void fade() {\r
+               cancelDelay();\r
+               fader = new Timer() {\r
+                       int opacity = startOpacity;\r
+\r
+                       public void run() {\r
+                               opacity -= 5;\r
+                               setOpacity(getElement(), opacity);\r
+                               if (opacity <= 0) {\r
+                                       cancel();\r
+                                       hide();\r
+                               }\r
+                       }\r
+               };\r
+               int msec = fadeMsec / (startOpacity / 5);\r
+               fader.scheduleRepeating(msec);\r
+       }\r
+\r
+       public void setPosition(int position) {\r
+               Element el = getElement();\r
+               DOM.setStyleAttribute(el, "top", null);\r
+               DOM.setStyleAttribute(el, "left", null);\r
+               DOM.setStyleAttribute(el, "bottom", null);\r
+               DOM.setStyleAttribute(el, "right", null);\r
+               switch (position) {\r
+               case TOP_LEFT:\r
+                       DOM.setStyleAttribute(el, "top", "0px");\r
+                       DOM.setStyleAttribute(el, "left", "0px");\r
+                       break;\r
+               case TOP_RIGHT:\r
+                       DOM.setStyleAttribute(el, "top", "0px");\r
+                       DOM.setStyleAttribute(el, "right", "0px");\r
+                       break;\r
+               case BOTTOM_RIGHT:\r
+                       DOM.setStyleAttribute(el, "position", "absolute");\r
+                       DOM.setStyleAttribute(el, "bottom", "0px");\r
+                       DOM.setStyleAttribute(el, "right", "0px");\r
+                       break;\r
+               case BOTTOM_LEFT:\r
+                       DOM.setStyleAttribute(el, "bottom", "0px");\r
+                       DOM.setStyleAttribute(el, "left", "0px");\r
+                       break;\r
+               case CENTERED_TOP:\r
+                       center();\r
+                       DOM.setStyleAttribute(el, "top", "0px");\r
+                       break;\r
+               case CENTERED_BOTTOM:\r
+                       center();\r
+                       DOM.setStyleAttribute(el, "top", null);\r
+                       DOM.setStyleAttribute(el, "bottom", "0px");\r
+                       break;\r
+               default:\r
+               case CENTERED:\r
+                       center();\r
+                       break;\r
+               }\r
+       }\r
+\r
+       private void cancelFade() {\r
+               if (fader != null) {\r
+                       fader.cancel();\r
+                       fader = null;\r
+               }\r
+       }\r
+\r
+       private void cancelDelay() {\r
+               if (delay != null) {\r
+                       delay.cancel();\r
+                       delay = null;\r
+               }\r
+       }\r
+\r
+       private void setOpacity(Element el, int opacity) {\r
+               DOM.setStyleAttribute(el, "opacity", "" + (opacity / 100.0));\r
+               DOM.setStyleAttribute(el, "filter", "Alpha(opacity=" + opacity + ")");\r
+\r
+       }\r
+\r
+       public void onBrowserEvent(Event event) {\r
+               DOM.removeEventPreview(eventPreview);\r
+               if (fader == null) {\r
+                       fade();\r
+               }\r
+       }\r
+\r
+}\r
index e2af2fd2b898b8cfba4ce63b9feaf9f3d4b75af9..03c73e9e9d09293f4e8da302832055c555148198 100644 (file)
@@ -29,18 +29,18 @@ public class IRichTextArea extends Composite implements Paintable,
        protected ApplicationConnection client;
 
        private boolean immediate = false;
-       
+
        RichTextArea rta = new RichTextArea();
-       
+
        RichTextToolbar formatter = new RichTextToolbar(rta);
 
        public IRichTextArea() {
                FlowPanel fp = new FlowPanel();
                fp.add(formatter);
-               
+
                rta.setWidth("100%");
                rta.addFocusListener(this);
-               
+
                fp.add(rta);
 
                initWidget(fp);
@@ -51,28 +51,30 @@ public class IRichTextArea extends Composite implements Paintable,
                this.client = client;
                id = uidl.getId();
 
-               if (client.updateComponent(this, uidl, true))
+               if (client.updateComponent(this, uidl, true)) {
                        return;
+               }
 
                immediate = uidl.getBooleanAttribute("immediate");
-               
-               rta.setText(uidl.getStringAttribute("text"));
+
+               rta.setHTML(uidl.getStringVariable("text"));
 
        }
 
        public void onChange(Widget sender) {
-               if (client != null && id != null)
+               if (client != null && id != null) {
                        client.updateVariable(id, "text", rta.getText(), immediate);
+               }
        }
 
        public void onFocus(Widget sender) {
-               
+
        }
 
        public void onLostFocus(Widget sender) {
                String html = rta.getHTML();
                client.updateVariable(id, "text", html, immediate);
-               
+
        }
 
 }
index e5e037f9880267a4cc00d14bf757387560f62fa1..3935cf07aa10f21f97438903ca24a12d6a55c803 100644 (file)
@@ -8,6 +8,7 @@
 @import "table/table.css";\r
 @import "slider/slider.css";\r
 @import "window/window.css";\r
+@import "window/notification.css";\r
 @import "caption/caption.css";\r
 @import "tree/tree.css";\r
 @import "splitpanel/splitpanel.css";\r
diff --git a/src/com/itmill/toolkit/terminal/gwt/public/default/window/notification.css b/src/com/itmill/toolkit/terminal/gwt/public/default/window/notification.css
new file mode 100644 (file)
index 0000000..3156f38
--- /dev/null
@@ -0,0 +1,38 @@
+\r
+.i-Notification {\r
+       font-family: "Trebuchet MS", geneva, helvetica, arial, tahoma, verdana, sans-serif;\r
+       background-color: #ffffff;\r
+       color: #cccccc;\r
+       border: 10px solid #cccccc;\r
+       padding: 0.2em;\r
+       cursor: pointer;\r
+}\r
+.i-Notification H1,\r
+.i-Notification p,\r
+.i-Notification.error H1,\r
+.i-Notification.error p,\r
+.i-Notification.warning H1,\r
+.i-Notification.warning p {\r
+       display: inline;\r
+       padding: 0.1em;\r
+}\r
+.i-Notification.tray H1,\r
+.i-Notification.tray p {\r
+       display: block;\r
+       font-size: 1em;\r
+       line-height: 0.5em;\r
+}\r
+\r
+.i-Notification.warning {\r
+       border-color: #f14c1a;\r
+       color: #f14c1a;\r
+}\r
+\r
+.i-Notification.error {\r
+       color: #ff0a0a;\r
+       border-color: #ff0a0a;\r
+}\r
+.i-Notification.tray {\r
+       color: #000000;\r
+       border-bottom: none;\r
+}\r
index 411f977f8181c064b8de230dc2083c21442b989a..376e056756c5dfa216a9d1dda69fe99b52aa28dc 100644 (file)
 
 package com.itmill.toolkit.ui;
 
-import com.itmill.toolkit.Application;
-import com.itmill.toolkit.Application.WindowAttachEvent;
-import com.itmill.toolkit.Application.WindowAttachListener;
-import com.itmill.toolkit.terminal.DownloadStream;
-import com.itmill.toolkit.terminal.PaintException;
-import com.itmill.toolkit.terminal.PaintTarget;
-import com.itmill.toolkit.terminal.ParameterHandler;
-import com.itmill.toolkit.terminal.Resource;
-import com.itmill.toolkit.terminal.Sizeable;
-import com.itmill.toolkit.terminal.Terminal;
-import com.itmill.toolkit.terminal.URIHandler;
-
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Method;
 import java.net.MalformedURLException;
@@ -47,11 +35,21 @@ import java.net.URL;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.Map;
-import java.util.Iterator;
 import java.util.Set;
 
+import com.itmill.toolkit.Application;
+import com.itmill.toolkit.terminal.DownloadStream;
+import com.itmill.toolkit.terminal.PaintException;
+import com.itmill.toolkit.terminal.PaintTarget;
+import com.itmill.toolkit.terminal.ParameterHandler;
+import com.itmill.toolkit.terminal.Resource;
+import com.itmill.toolkit.terminal.Sizeable;
+import com.itmill.toolkit.terminal.Terminal;
+import com.itmill.toolkit.terminal.URIHandler;
+
 /**
  * Application window component.
  * 
@@ -98,7 +96,7 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
        private LinkedList parameterHandlerList = null;
 
        /** Set of subwindows */
-       private HashSet subwindows = new HashSet();
+       private final HashSet subwindows = new HashSet();
 
        /**
         * Explicitly specified theme of this window. If null, application theme is
@@ -109,7 +107,7 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
        /**
         * Resources to be opened automatically on next repaint.
         */
-       private LinkedList openList = new LinkedList();
+       private final LinkedList openList = new LinkedList();
 
        /**
         * The name of the window.
@@ -148,6 +146,8 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
         */
        private int scrollLeft = 0;
 
+       private LinkedList notifications;
+
        /* ********************************************************************* */
 
        /**
@@ -240,8 +240,9 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
         * @return the parent application of the component.
         */
        public final Application getApplication() {
-               if (getParent() == null)
+               if (getParent() == null) {
                        return this.application;
+               }
                return ((Window) getParent()).getApplication();
        }
 
@@ -300,11 +301,13 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
        public void addURIHandler(URIHandler handler) {
                // TODO Subwindow support
 
-               if (uriHandlerList == null)
+               if (uriHandlerList == null) {
                        uriHandlerList = new LinkedList();
+               }
                synchronized (uriHandlerList) {
-                       if (!uriHandlerList.contains(handler))
+                       if (!uriHandlerList.contains(handler)) {
                                uriHandlerList.addLast(handler);
+                       }
                }
        }
 
@@ -317,12 +320,14 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
        public void removeURIHandler(URIHandler handler) {
                // TODO Subwindow support
 
-               if (handler == null || uriHandlerList == null)
+               if (handler == null || uriHandlerList == null) {
                        return;
+               }
                synchronized (uriHandlerList) {
                        uriHandlerList.remove(handler);
-                       if (uriHandlerList.isEmpty())
+                       if (uriHandlerList.isEmpty()) {
                                uriHandlerList = null;
+                       }
                }
        }
 
@@ -345,10 +350,11 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
                                DownloadStream ds = ((URIHandler) handlers[i]).handleURI(
                                                context, relativeUri);
                                if (ds != null) {
-                                       if (result != null)
+                                       if (result != null) {
                                                throw new RuntimeException("handleURI for " + context
                                                                + " uri: '" + relativeUri
                                                                + "' returns ambigious result.");
+                                       }
                                        result = ds;
                                }
                        }
@@ -366,11 +372,13 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
         */
        public void addParameterHandler(ParameterHandler handler) {
                // TODO Subwindow support
-               if (parameterHandlerList == null)
+               if (parameterHandlerList == null) {
                        parameterHandlerList = new LinkedList();
+               }
                synchronized (parameterHandlerList) {
-                       if (!parameterHandlerList.contains(handler))
+                       if (!parameterHandlerList.contains(handler)) {
                                parameterHandlerList.addLast(handler);
+                       }
                }
        }
 
@@ -382,12 +390,14 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
         */
        public void removeParameterHandler(ParameterHandler handler) {
                // TODO Subwindow support
-               if (handler == null || parameterHandlerList == null)
+               if (handler == null || parameterHandlerList == null) {
                        return;
+               }
                synchronized (parameterHandlerList) {
                        parameterHandlerList.remove(handler);
-                       if (parameterHandlerList.isEmpty())
+                       if (parameterHandlerList.isEmpty()) {
                                parameterHandlerList = null;
+                       }
                }
        }
 
@@ -398,8 +408,9 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
                        synchronized (parameterHandlerList) {
                                handlers = parameterHandlerList.toArray();
                        }
-                       for (int i = 0; i < handlers.length; i++)
+                       for (int i = 0; i < handlers.length; i++) {
                                ((ParameterHandler) handlers[i]).handleParameters(parameters);
+                       }
                }
        }
 
@@ -419,14 +430,18 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
         *         returned
         */
        public String getTheme() {
-               if (getParent() != null)
+               if (getParent() != null) {
                        return ((Window) getParent()).getTheme();
-               if (theme != null)
+               }
+               if (theme != null) {
                        return theme;
-               if ((application != null) && (application.getTheme() != null))
+               }
+               if ((application != null) && (application.getTheme() != null)) {
                        return application.getTheme();
-               if (terminal != null)
+               }
+               if (terminal != null) {
                        return terminal.getDefaultTheme();
+               }
                return null;
        }
 
@@ -439,9 +454,10 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
         *            the New theme for this window. Null implies the default theme.
         */
        public void setTheme(String theme) {
-               if (getParent() != null)
+               if (getParent() != null) {
                        throw new UnsupportedOperationException(
                                        "Setting theme for sub-windws is not supported.");
+               }
                this.theme = theme;
                requestRepaint();
        }
@@ -467,14 +483,16 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
 
                // Marks the main window
                if (getApplication() != null
-                               && this == getApplication().getMainWindow())
+                               && this == getApplication().getMainWindow()) {
                        target.addAttribute("main", true);
+               }
 
                // Open requested resource
                synchronized (openList) {
                        if (!openList.isEmpty()) {
-                               for (Iterator i = openList.iterator(); i.hasNext();)
+                               for (Iterator i = openList.iterator(); i.hasNext();) {
                                        ((OpenResource) i.next()).paintContent(target);
+                               }
                                openList.clear();
                        }
                }
@@ -494,11 +512,12 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
                target.addVariable(this, "close", false);
 
                // Sets the focused component
-               if (this.focusedComponent != null)
+               if (this.focusedComponent != null) {
                        target.addVariable(this, "focused", ""
                                        + this.focusedComponent.getFocusableId());
-               else
+               } else {
                        target.addVariable(this, "focused", "");
+               }
 
                // Paint subwindows
                for (Iterator i = subwindows.iterator(); i.hasNext();) {
@@ -506,6 +525,29 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
                        w.paint(target);
                }
 
+               // Paint notifications
+               if (this.notifications != null) {
+                       target.startTag("notifications");
+                       for (Iterator it = this.notifications.iterator(); it.hasNext();) {
+                               Notification n = (Notification) it.next();
+                               target.startTag("notification");
+                               if (n.getCaption() != null) {
+                                       target.addAttribute("caption", n.getCaption());
+                               }
+                               if (n.getMessage() != null) {
+                                       target.addAttribute("message", n.getMessage());
+                               }
+                               target.addAttribute("position", n.getPosition());
+                               target.addAttribute("delay", n.getDelayMsec());
+                               if (n.getStyleName() != null) {
+                                       target.addAttribute("style", n.getStyleName());
+                               }
+                               target.endTag("notification");
+                       }
+                       target.endTag("notifications");
+                       this.notifications = null;
+               }
+
        }
 
        /* ********************************************************************* */
@@ -517,9 +559,10 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
         */
        public void open(Resource resource) {
                synchronized (openList) {
-                       if (!openList.contains(resource))
+                       if (!openList.contains(resource)) {
                                openList.add(new OpenResource(resource, null, -1, -1,
                                                BORDER_DEFAULT));
+                       }
                }
                requestRepaint();
        }
@@ -538,9 +581,10 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
         */
        public void open(Resource resource, String windowName) {
                synchronized (openList) {
-                       if (!openList.contains(resource))
+                       if (!openList.contains(resource)) {
                                openList.add(new OpenResource(resource, windowName, -1, -1,
                                                BORDER_DEFAULT));
+                       }
                }
                requestRepaint();
        }
@@ -561,9 +605,10 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
        public void open(Resource resource, String windowName, int width,
                        int height, int border) {
                synchronized (openList) {
-                       if (!openList.contains(resource))
+                       if (!openList.contains(resource)) {
                                openList.add(new OpenResource(resource, windowName, width,
                                                height, border));
+                       }
                }
                requestRepaint();
        }
@@ -578,8 +623,9 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
         */
        public URL getURL() {
 
-               if (application == null)
+               if (application == null) {
                        return null;
+               }
 
                try {
                        return new URL(application.getURL(), getName() + "/");
@@ -651,8 +697,9 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
        public void setApplication(Application application) {
 
                // If the application is not changed, dont do nothing
-               if (application == this.application)
+               if (application == this.application) {
                        return;
+               }
 
                // Sends detach event if the window is connected to application
                if (this.application != null) {
@@ -663,8 +710,9 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
                this.application = application;
 
                // Sends the attach event if connected to a window
-               if (application != null)
+               if (application != null) {
                        attach();
+               }
        }
 
        /**
@@ -684,10 +732,11 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
        public void setName(String name) {
 
                // The name can not be changed in application
-               if (getApplication() != null)
+               if (getApplication() != null) {
                        throw new IllegalStateException(
                                        "Window name can not be changed while "
                                                        + "the window is in application");
+               }
 
                this.name = name;
        }
@@ -709,8 +758,9 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
         * @see com.itmill.toolkit.terminal.Sizeable#getHeightUnits()
         */
        public void setHeightUnits(int units) {
-               if (units != Sizeable.UNITS_PIXELS)
+               if (units != Sizeable.UNITS_PIXELS) {
                        throw new IllegalArgumentException("Only pixels are supported");
+               }
        }
 
        /**
@@ -719,8 +769,9 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
         * @see com.itmill.toolkit.terminal.Sizeable#getWidthUnits()
         */
        public void setWidthUnits(int units) {
-               if (units != Sizeable.UNITS_PIXELS)
+               if (units != Sizeable.UNITS_PIXELS) {
                        throw new IllegalArgumentException("Only pixels are supported");
+               }
        }
 
        /**
@@ -728,15 +779,15 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
         */
        private class OpenResource {
 
-               private Resource resource;
+               private final Resource resource;
 
-               private String name;
+               private final String name;
 
-               private int width;
+               private final int width;
 
-               private int height;
+               private final int height;
 
-               private int border;
+               private final int border;
 
                /**
                 * Creates a new open resource.
@@ -767,12 +818,15 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
                private void paintContent(PaintTarget target) throws PaintException {
                        target.startTag("open");
                        target.addAttribute("src", resource);
-                       if (name != null && name.length() > 0)
+                       if (name != null && name.length() > 0) {
                                target.addAttribute("name", name);
-                       if (width >= 0)
+                       }
+                       if (width >= 0) {
                                target.addAttribute("width", width);
-                       if (height >= 0)
+                       }
+                       if (height >= 0) {
                                target.addAttribute("height", height);
+                       }
                        switch (border) {
                        case Window.BORDER_MINIMAL:
                                target.addAttribute("border", "minimal");
@@ -1052,12 +1106,14 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
        public void addWindow(Window window) throws IllegalArgumentException,
                        NullPointerException {
 
-               if (getParent() != null)
+               if (getParent() != null) {
                        throw new IllegalArgumentException(
                                        "You can only add windows inside application-level windows");
+               }
 
-               if (window == null)
+               if (window == null) {
                        throw new NullPointerException("Argument must not be null");
+               }
 
                subwindows.add(window);
                window.setParent(this);
@@ -1124,4 +1180,136 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
                this.scrollLeft = scrollLeft;
        }
 
+       public void showNotification(String message) {
+               addNotification(new Notification(message));
+       }
+
+       public void showNotification(String message, int type) {
+               addNotification(new Notification(message, type));
+       }
+
+       public void showNotification(String caption, String message, int type) {
+               addNotification(new Notification(caption, message, type));
+       }
+
+       public void showNotification(Notification notification) {
+               addNotification(notification);
+       }
+
+       private void addNotification(Notification notification) {
+               if (this.notifications == null) {
+                       this.notifications = new LinkedList();
+               }
+               this.notifications.add(notification);
+               requestRepaint();
+       }
+
+       public class Notification {
+               public static final int TYPE_HUMANIZED_MESSAGE = 1;
+               public static final int TYPE_WARNING_MESSAGE = 2;
+               public static final int TYPE_ERROR_MESSAGE = 3;
+               public static final int TYPE_TRAY_NOTIFICATION = 4;
+
+               public static final int POSITION_CENTERED = 1;
+               public static final int POSITION_CENTERED_TOP = 2;
+               public static final int POSITION_CENTERED_BOTTOM = 3;
+               public static final int POSITION_TOP_LEFT = 4;
+               public static final int POSITION_TOP_RIGHT = 5;
+               public static final int POSITION_BOTTOM_LEFT = 6;
+               public static final int POSITION_BOTTOM_RIGHT = 7;
+
+               public static final int DELAY_FOREVER = -1;
+               public static final int DELAY_NONE = 0;
+
+               private String caption;
+               private String message;
+               private Resource icon;
+               private int position = POSITION_CENTERED;
+               private int delayMsec = 0;
+               private String styleName;
+
+               public Notification(String message) {
+                       this(null, message, TYPE_HUMANIZED_MESSAGE);
+               }
+
+               public Notification(String message, int type) {
+                       this(null, message, type);
+               }
+
+               public Notification(String caption, String message, int type) {
+                       this.caption = caption;
+                       this.message = message;
+                       setType(type);
+               }
+
+               private void setType(int type) {
+                       switch (type) {
+                       case TYPE_WARNING_MESSAGE:
+                               delayMsec = 1500;
+                               styleName = "warning";
+                               break;
+                       case TYPE_ERROR_MESSAGE:
+                               delayMsec = -1;
+                               styleName = "error";
+                               break;
+                       case TYPE_TRAY_NOTIFICATION:
+                               delayMsec = 3000;
+                               position = POSITION_BOTTOM_RIGHT;
+                               styleName = "tray";
+
+                       case TYPE_HUMANIZED_MESSAGE:
+                       default:
+                               break;
+                       }
+
+               }
+
+               public String getCaption() {
+                       return caption;
+               }
+
+               public void setCaption(String caption) {
+                       this.caption = caption;
+               }
+
+               public String getMessage() {
+                       return message;
+               }
+
+               public void setMessage(String message) {
+                       this.message = message;
+               }
+
+               public int getPosition() {
+                       return position;
+               }
+
+               public void setPosition(int position) {
+                       this.position = position;
+               }
+
+               public Resource getIcon() {
+                       return icon;
+               }
+
+               public void setIcon(Resource icon) {
+                       this.icon = icon;
+               }
+
+               public int getDelayMsec() {
+                       return delayMsec;
+               }
+
+               public void setDelayMsec(int delayMsec) {
+                       this.delayMsec = delayMsec;
+               }
+
+               public void setStyleName(String styleName) {
+                       this.styleName = styleName;
+               }
+
+               public String getStyleName() {
+                       return this.styleName;
+               }
+       }
 }