From b833befdfdee560f9302a532b36c31f2193ca3e8 Mon Sep 17 00:00:00 2001
From: Matti Tahvonen
Date: Tue, 5 Aug 2008 07:57:55 +0000
Subject: [PATCH] svn changeset:5134/svn branch:trunk
---
.../client/ApplicationConfiguration.java | 78 +
.../client/client/ApplicationConnection.java | 984 ++++++++
.../gwt/client/client/BrowserInfo.java | 141 ++
.../terminal/gwt/client/client/CSSRule.java | 84 +
.../terminal/gwt/client/client/Caption.java | 179 ++
.../gwt/client/client/CaptionWrapper.java | 32 +
.../terminal/gwt/client/client/Console.java | 17 +
.../terminal/gwt/client/client/Container.java | 52 +
.../client/ContainerResizedListener.java | 20 +
.../gwt/client/client/DateTimeService.java | 245 ++
.../gwt/client/client/DebugConsole.java | 112 +
.../gwt/client/client/DefaultWidgetSet.java | 323 +++
.../gwt/client/client/ErrorMessage.java | 73 +
.../terminal/gwt/client/client/Focusable.java | 16 +
.../client/LocaleNotLoadedException.java | 17 +
.../gwt/client/client/LocaleService.java | 197 ++
.../gwt/client/client/NullConsole.java | 26 +
.../terminal/gwt/client/client/Paintable.java | 10 +
.../gwt/client/client/StyleConstants.java | 17 +
.../terminal/gwt/client/client/Tooltip.java | 186 ++
.../gwt/client/client/TooltipInfo.java | 28 +
.../terminal/gwt/client/client/UIDL.java | 470 ++++
.../terminal/gwt/client/client/Util.java | 164 ++
.../terminal/gwt/client/client/WidgetSet.java | 33 +
.../terminal/gwt/client/client/ui/Action.java | 55 +
.../gwt/client/client/ui/ActionOwner.java | 16 +
.../gwt/client/client/ui/AlignmentInfo.java | 76 +
.../gwt/client/client/ui/CalendarEntry.java | 126 +
.../gwt/client/client/ui/CalendarPanel.java | 491 ++++
.../gwt/client/client/ui/ContextMenu.java | 117 +
.../terminal/gwt/client/client/ui/Field.java | 13 +
.../gwt/client/client/ui/IAccordion.java | 267 ++
.../gwt/client/client/ui/IButton.java | 117 +
.../gwt/client/client/ui/ICheckBox.java | 118 +
.../client/client/ui/ICustomComponent.java | 64 +
.../gwt/client/client/ui/ICustomLayout.java | 463 ++++
.../gwt/client/client/ui/IDateField.java | 231 ++
.../client/client/ui/IDateFieldCalendar.java | 25 +
.../gwt/client/client/ui/IEmbedded.java | 127 +
.../gwt/client/client/ui/IExpandLayout.java | 726 ++++++
.../gwt/client/client/ui/IFilterSelect.java | 788 ++++++
.../terminal/gwt/client/client/ui/IForm.java | 142 ++
.../gwt/client/client/ui/IFormLayout.java | 299 +++
.../gwt/client/client/ui/IGridLayout.java | 296 +++
.../client/ui/IHorizontalExpandLayout.java | 13 +
.../terminal/gwt/client/client/ui/ILabel.java | 49 +
.../terminal/gwt/client/client/ui/ILink.java | 193 ++
.../gwt/client/client/ui/IListSelect.java | 126 +
.../gwt/client/client/ui/IMenuBar.java | 234 ++
.../gwt/client/client/ui/INativeSelect.java | 77 +
.../gwt/client/client/ui/IOptionGroup.java | 78 +
.../client/client/ui/IOptionGroupBase.java | 223 ++
.../gwt/client/client/ui/IOrderedLayout.java | 1150 +++++++++
.../terminal/gwt/client/client/ui/IPanel.java | 388 +++
.../gwt/client/client/ui/IPasswordField.java | 21 +
.../gwt/client/client/ui/IPopupCalendar.java | 126 +
.../client/client/ui/IProgressIndicator.java | 96 +
.../gwt/client/client/ui/IScrollTable.java | 2246 +++++++++++++++++
.../gwt/client/client/ui/ISlider.java | 415 +++
.../gwt/client/client/ui/ISplitPanel.java | 410 +++
.../client/ui/ISplitPanelHorizontal.java | 12 +
.../client/client/ui/ISplitPanelVertical.java | 12 +
.../gwt/client/client/ui/ITablePaging.java | 438 ++++
.../gwt/client/client/ui/ITabsheet.java | 383 +++
.../gwt/client/client/ui/ITabsheetBase.java | 157 ++
.../gwt/client/client/ui/ITabsheetPanel.java | 112 +
.../gwt/client/client/ui/ITextArea.java | 50 +
.../gwt/client/client/ui/ITextField.java | 204 ++
.../gwt/client/client/ui/ITextualDate.java | 279 ++
.../terminal/gwt/client/client/ui/ITree.java | 409 +++
.../gwt/client/client/ui/ITwinColSelect.java | 220 ++
.../client/client/ui/IUnknownComponent.java | 40 +
.../gwt/client/client/ui/IUpload.java | 151 ++
.../terminal/gwt/client/client/ui/IView.java | 295 +++
.../gwt/client/client/ui/IWindow.java | 678 +++++
.../terminal/gwt/client/client/ui/Icon.java | 36 +
.../gwt/client/client/ui/MarginInfo.java | 68 +
.../gwt/client/client/ui/MenuBar.java | 513 ++++
.../gwt/client/client/ui/MenuItem.java | 188 ++
.../gwt/client/client/ui/Notification.java | 289 +++
.../client/ui/ShortcutActionHandler.java | 177 ++
.../terminal/gwt/client/client/ui/Table.java | 15 +
.../terminal/gwt/client/client/ui/Time.java | 317 +++
.../gwt/client/client/ui/ToolkitOverlay.java | 147 ++
.../gwt/client/client/ui/TreeAction.java | 55 +
.../gwt/client/client/ui/TreeImages.java | 27 +
.../client/ui/absolutegrid/AbsoluteGrid.java | 305 +++
.../ui/absolutegrid/ISizeableGridLayout.java | 166 ++
.../client/ui/richtextarea/IRichTextArea.java | 111 +
.../RichTextToolbar$Strings.properties | 35 +
.../ui/richtextarea/RichTextToolbar.java | 509 ++++
.../client/ui/richtextarea/backColors.gif | Bin 0 -> 104 bytes
.../client/client/ui/richtextarea/bold.gif | Bin 0 -> 864 bytes
.../client/ui/richtextarea/createLink.gif | Bin 0 -> 118 bytes
.../client/ui/richtextarea/fontSizes.gif | Bin 0 -> 96 bytes
.../client/client/ui/richtextarea/fonts.gif | Bin 0 -> 147 bytes
.../client/ui/richtextarea/foreColors.gif | Bin 0 -> 173 bytes
.../client/client/ui/richtextarea/gwtLogo.png | Bin 0 -> 11454 bytes
.../gwt/client/client/ui/richtextarea/hr.gif | Bin 0 -> 67 bytes
.../client/client/ui/richtextarea/indent.gif | Bin 0 -> 82 bytes
.../client/ui/richtextarea/insertImage.gif | Bin 0 -> 290 bytes
.../client/client/ui/richtextarea/italic.gif | Bin 0 -> 79 bytes
.../client/ui/richtextarea/justifyCenter.gif | Bin 0 -> 70 bytes
.../client/ui/richtextarea/justifyLeft.gif | Bin 0 -> 71 bytes
.../client/ui/richtextarea/justifyRight.gif | Bin 0 -> 855 bytes
.../gwt/client/client/ui/richtextarea/ol.gif | Bin 0 -> 76 bytes
.../client/client/ui/richtextarea/outdent.gif | Bin 0 -> 82 bytes
.../client/ui/richtextarea/removeFormat.gif | Bin 0 -> 360 bytes
.../client/ui/richtextarea/removeLink.gif | Bin 0 -> 895 bytes
.../client/ui/richtextarea/strikeThrough.gif | Bin 0 -> 80 bytes
.../client/ui/richtextarea/subscript.gif | Bin 0 -> 80 bytes
.../client/ui/richtextarea/superscript.gif | Bin 0 -> 80 bytes
.../gwt/client/client/ui/richtextarea/ul.gif | Bin 0 -> 863 bytes
.../client/ui/richtextarea/underline.gif | Bin 0 -> 88 bytes
114 files changed, 20304 insertions(+)
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ApplicationConfiguration.java
create mode 100755 src/com/itmill/toolkit/terminal/gwt/client/client/ApplicationConnection.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/BrowserInfo.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/CSSRule.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/Caption.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/CaptionWrapper.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/Console.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/Container.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ContainerResizedListener.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/DateTimeService.java
create mode 100755 src/com/itmill/toolkit/terminal/gwt/client/client/DebugConsole.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/DefaultWidgetSet.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ErrorMessage.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/Focusable.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/LocaleNotLoadedException.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/LocaleService.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/NullConsole.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/Paintable.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/StyleConstants.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/Tooltip.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/TooltipInfo.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/UIDL.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/Util.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/WidgetSet.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/Action.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ActionOwner.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/AlignmentInfo.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/CalendarEntry.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/CalendarPanel.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ContextMenu.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/Field.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IAccordion.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IButton.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ICheckBox.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ICustomComponent.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ICustomLayout.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IDateField.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IDateFieldCalendar.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IEmbedded.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IExpandLayout.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IFilterSelect.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IForm.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IFormLayout.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IGridLayout.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IHorizontalExpandLayout.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ILabel.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ILink.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IListSelect.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IMenuBar.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/INativeSelect.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IOptionGroup.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IOptionGroupBase.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IOrderedLayout.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IPanel.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IPasswordField.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IPopupCalendar.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IProgressIndicator.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IScrollTable.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ISlider.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ISplitPanel.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ISplitPanelHorizontal.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ISplitPanelVertical.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ITablePaging.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ITabsheet.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ITabsheetBase.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ITabsheetPanel.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ITextArea.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ITextField.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ITextualDate.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ITree.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ITwinColSelect.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IUnknownComponent.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IUpload.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IView.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/IWindow.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/Icon.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/MarginInfo.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/MenuBar.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/MenuItem.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/Notification.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ShortcutActionHandler.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/Table.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/Time.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/ToolkitOverlay.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/TreeAction.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/TreeImages.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/absolutegrid/AbsoluteGrid.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/absolutegrid/ISizeableGridLayout.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/IRichTextArea.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/RichTextToolbar$Strings.properties
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/RichTextToolbar.java
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/backColors.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/bold.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/createLink.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/fontSizes.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/fonts.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/foreColors.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/gwtLogo.png
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/hr.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/indent.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/insertImage.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/italic.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/justifyCenter.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/justifyLeft.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/justifyRight.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/ol.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/outdent.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/removeFormat.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/removeLink.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/strikeThrough.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/subscript.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/superscript.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/ul.gif
create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/client/ui/richtextarea/underline.gif
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/ApplicationConfiguration.java b/src/com/itmill/toolkit/terminal/gwt/client/client/ApplicationConfiguration.java
new file mode 100644
index 0000000000..aefc931c4c
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/ApplicationConfiguration.java
@@ -0,0 +1,78 @@
+package com.itmill.toolkit.terminal.gwt.client;
+
+import java.util.ArrayList;
+
+import com.google.gwt.core.client.JavaScriptObject;
+
+public class ApplicationConfiguration {
+
+ private String id;
+ private String themeUri;
+ private String pathInfo;
+ private String appUri;
+ private JavaScriptObject versionInfo;
+
+ public String getRootPanelId() {
+ return id;
+ }
+
+ public String getApplicationUri() {
+ return appUri;
+ }
+
+ public String getPathInfo() {
+ return pathInfo;
+ }
+
+ public String getThemeUri() {
+ return themeUri;
+ }
+
+ public void setAppId(String appId) {
+ id = appId;
+ }
+
+ public JavaScriptObject getVersionInfoJSObject() {
+ return versionInfo;
+ }
+
+ private native void loadFromDOM()
+ /*-{
+
+ var id = this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConfiguration::id;
+ if($wnd.itmill.toolkitConfigurations && $wnd.itmill.toolkitConfigurations[id]) {
+ var jsobj = $wnd.itmill.toolkitConfigurations[id];
+ var uri = jsobj.appUri;
+ if(uri[uri.length -1] != "/") {
+ uri = uri + "/";
+ }
+ this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConfiguration::appUri = uri;
+ this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConfiguration::pathInfo = jsobj.pathInfo;
+ this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConfiguration::themeUri = jsobj.themeUri;
+ if(jsobj.versionInfo) {
+ this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConfiguration::versionInfo = jsobj.versionInfo;
+ }
+
+ } else {
+ $wnd.alert("Toolkit app failed to initialize: " + this.id);
+ }
+
+ }-*/;
+
+ public native static void loadAppIdListFromDOM(ArrayList list)
+ /*-{
+
+ var j;
+ for(j in $wnd.itmill.toolkitConfigurations) {
+ list.@java.util.Collection::add(Ljava/lang/Object;)(j);
+ }
+ }-*/;
+
+ public static ApplicationConfiguration getConfigFromDOM(String appId) {
+ ApplicationConfiguration conf = new ApplicationConfiguration();
+ conf.setAppId(appId);
+ conf.loadFromDOM();
+ return conf;
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/ApplicationConnection.java b/src/com/itmill/toolkit/terminal/gwt/client/client/ApplicationConnection.java
new file mode 100755
index 0000000000..10313d289c
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/ApplicationConnection.java
@@ -0,0 +1,984 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Vector;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.RequestBuilder;
+import com.google.gwt.http.client.RequestCallback;
+import com.google.gwt.http.client.RequestException;
+import com.google.gwt.http.client.Response;
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONParser;
+import com.google.gwt.json.client.JSONString;
+import com.google.gwt.json.client.JSONValue;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.WindowCloseListener;
+import com.google.gwt.user.client.ui.FocusWidget;
+import com.google.gwt.user.client.ui.HasFocus;
+import com.google.gwt.user.client.ui.HasWidgets;
+import com.google.gwt.user.client.ui.Widget;
+import com.itmill.toolkit.terminal.gwt.client.ui.ContextMenu;
+import com.itmill.toolkit.terminal.gwt.client.ui.Field;
+import com.itmill.toolkit.terminal.gwt.client.ui.IView;
+import com.itmill.toolkit.terminal.gwt.client.ui.Notification;
+import com.itmill.toolkit.terminal.gwt.client.ui.Notification.HideEvent;
+
+/**
+ * Entry point classes define onModuleLoad()
.
+ */
+public class ApplicationConnection {
+ private static final String MODIFIED_CLASSNAME = "i-modified";
+
+ private static final String REQUIRED_CLASSNAME_EXT = "-required";
+
+ private static final String ERROR_CLASSNAME_EXT = "-error";
+
+ public static final String VAR_RECORD_SEPARATOR = "\u001e";
+
+ public static final String VAR_FIELD_SEPARATOR = "\u001f";
+
+ private final HashMap resourcesMap = new HashMap();
+
+ private static Console console;
+
+ private static boolean testingMode;
+
+ private final Vector pendingVariables = new Vector();
+
+ private final HashMap idToPaintable = new HashMap();
+
+ private final HashMap paintableToId = new HashMap();
+
+ /** Contains ExtendedTitleInfo by paintable id */
+ private final HashMap paintableToTitle = new HashMap();
+
+ private final WidgetSet widgetSet;
+
+ private ContextMenu contextMenu = null;
+
+ private Timer loadTimer;
+ private Timer loadTimer2;
+ private Timer loadTimer3;
+ private Element loadElement;
+
+ private final IView view;
+
+ private boolean applicationRunning = false;
+
+ /**
+ * True if each Paintable objects id is injected to DOM. Used for Testing
+ * Tools.
+ */
+ private boolean usePaintableIdsInDOM = false;
+
+ /**
+ * Contains reference for client wrapper given to Testing Tools.
+ *
+ * Used in JSNI functions
+ *
+ * @SuppressWarnings
+ */
+ private final JavaScriptObject ttClientWrapper = null;
+
+ private int activeRequests = 0;
+
+ private final ApplicationConfiguration configuration;
+
+ private final Vector pendingVariableBursts = new Vector();
+
+ public ApplicationConnection(WidgetSet widgetSet,
+ ApplicationConfiguration cnf) {
+ this.widgetSet = widgetSet;
+ configuration = cnf;
+
+ if (isDebugMode()) {
+ console = new DebugConsole(this);
+ } else {
+ console = new NullConsole();
+ }
+
+ if (checkTestingMode()) {
+ usePaintableIdsInDOM = true;
+ initializeTestingTools();
+ Window.addWindowCloseListener(new WindowCloseListener() {
+ public void onWindowClosed() {
+ uninitializeTestingTools();
+ }
+
+ public String onWindowClosing() {
+ return null;
+ }
+ });
+ }
+
+ initializeClientHooks();
+
+ // TODO remove hard coded id name
+ view = new IView(cnf.getRootPanelId());
+
+ makeUidlRequest("", true);
+ applicationRunning = true;
+ }
+
+ /**
+ * Method to check if application is in testing mode. Can be used after
+ * application init.
+ *
+ * @return true if in testing mode
+ */
+ public static boolean isTestingMode() {
+ return testingMode;
+ }
+
+ /**
+ * Check is application is run in testing mode.
+ *
+ * @return true if in testing mode
+ */
+ private native static boolean checkTestingMode()
+ /*-{
+ @com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::testingMode = $wnd.top.itmill && $wnd.top.itmill.registerToTT ? true : false;
+ return @com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::testingMode;
+ }-*/;
+
+ private native void initializeTestingTools()
+ /*-{
+ var ap = this;
+ var client = {};
+ client.isActive = function() {
+ return ap.@com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::hasActiveRequest()();
+ }
+ var vi = ap.@com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::getVersionInfo()();
+ if (vi) {
+ client.getVersionInfo = function() {
+ return vi;
+ }
+ }
+ $wnd.top.itmill.registerToTT(client);
+ this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::ttClientWrapper = client;
+ }-*/;
+
+ /**
+ * Helper for tt initialization
+ */
+ private JavaScriptObject getVersionInfo() {
+ return configuration.getVersionInfoJSObject();
+ }
+
+ private native void uninitializeTestingTools()
+ /*-{
+ $wnd.top.itmill.unregisterFromTT(this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::ttClientWrapper);
+ }-*/;
+
+ /**
+ * Publishes a JavaScript API for mash-up applications.
+ *
+ * itmill.forceSync()
sends pending variable changes, in
+ * effect synchronizing the server and client state. This is done for all
+ * applications on host page.
+ *
+ *
+ * TODO make this multi-app aware
+ */
+ private native void initializeClientHooks()
+ /*-{
+ var app = this;
+ var oldSync;
+ if($wnd.itmill.forceSync) {
+ oldSync = $wnd.itmill.forceSync;
+ }
+ $wnd.itmill.forceSync = function() {
+ if(oldSync) {
+ oldSync();
+ }
+ app.@com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::sendPendingVariableChanges()();
+ }
+ }-*/;
+
+ public static Console getConsole() {
+ return console;
+ }
+
+ private native static boolean isDebugMode()
+ /*-{
+ var uri = $wnd.location;
+ var re = /debug[^\/]*$/;
+ return re.test(uri);
+ }-*/;
+
+ public String getAppUri() {
+ return configuration.getApplicationUri();
+ };
+
+ public boolean hasActiveRequest() {
+ return (activeRequests > 0);
+ }
+
+ private void makeUidlRequest(String requestData, boolean repaintAll) {
+ startRequest();
+
+ console.log("Making UIDL Request with params: " + requestData);
+ String uri = getAppUri() + "UIDL" + configuration.getPathInfo();
+ if (repaintAll) {
+ uri += "?repaintAll=1";
+ }
+ final RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, uri);
+ // rb.setHeader("Content-Type",
+ // "application/x-www-form-urlencoded; charset=utf-8");
+ rb.setHeader("Content-Type", "text/plain;charset=utf-8");
+ try {
+ rb.sendRequest(requestData, new RequestCallback() {
+ public void onError(Request request, Throwable exception) {
+ // TODO Better reporting to user
+ console.error("Got error");
+ endRequest();
+ }
+
+ public void onResponseReceived(Request request,
+ Response response) {
+ handleReceivedJSONMessage(response);
+ }
+
+ });
+
+ } catch (final RequestException e) {
+ // TODO Better reporting to user
+ console.error(e.getMessage());
+ endRequest();
+ }
+ }
+
+ private void startRequest() {
+ activeRequests++;
+ showLoadingIndicator();
+ }
+
+ private void endRequest() {
+
+ checkForPendingVariableBursts();
+
+ activeRequests--;
+ // deferring to avoid flickering
+ DeferredCommand.addCommand(new Command() {
+ public void execute() {
+ if (activeRequests == 0) {
+ hideLoadingIndicator();
+ }
+ }
+ });
+ }
+
+ /**
+ * This method is called after applying uidl change set to application.
+ *
+ * It will clean current and queued variable change sets. And send next
+ * change set if it exists.
+ */
+ private void checkForPendingVariableBursts() {
+ cleanVariableBurst(pendingVariables);
+ if (pendingVariableBursts.size() > 0) {
+ for (Iterator iterator = pendingVariableBursts.iterator(); iterator
+ .hasNext();) {
+ cleanVariableBurst((Vector) iterator.next());
+ }
+ Vector nextBurst = (Vector) pendingVariableBursts.firstElement();
+ pendingVariableBursts.remove(0);
+ buildAndSendVariableBurst(nextBurst);
+ }
+ }
+
+ /**
+ * Cleans given queue of variable changes of such changes that came from
+ * components that do not exist anymore.
+ *
+ * @param variableBurst
+ */
+ private void cleanVariableBurst(Vector variableBurst) {
+ for (int i = 1; i < variableBurst.size(); i += 2) {
+ String id = (String) variableBurst.get(i);
+ id = id.substring(0, id.indexOf(VAR_FIELD_SEPARATOR));
+ if (!idToPaintable.containsKey(id)) {
+ // variable owner does not exist anymore
+ variableBurst.remove(i - 1);
+ variableBurst.remove(i - 1);
+ i -= 2;
+ ApplicationConnection.getConsole().log(
+ "Removed variable from removed component: " + id);
+ }
+ }
+ }
+
+ private void showLoadingIndicator() {
+ // show initial throbber
+ if (loadTimer == null) {
+ loadTimer = new Timer() {
+ public void run() {
+ // show initial throbber
+ if (loadElement == null) {
+ loadElement = DOM.createDiv();
+ DOM.setStyleAttribute(loadElement, "position",
+ "absolute");
+ DOM.appendChild(view.getElement(), loadElement);
+ ApplicationConnection.getConsole().log(
+ "inserting load indicator");
+ // Position
+ DOM.setStyleAttribute(loadElement, "top", (view
+ .getAbsoluteTop() + 6)
+ + "px");
+ }
+ DOM.setElementProperty(loadElement, "className",
+ "i-loading-indicator");
+ DOM.setStyleAttribute(loadElement, "display", "block");
+ DOM.setStyleAttribute(loadElement, "left", (view
+ .getAbsoluteLeft()
+ + view.getOffsetWidth()
+ - DOM.getElementPropertyInt(loadElement,
+ "offsetWidth") - 5)
+ + "px");
+
+ // Initialize other timers
+ loadTimer2 = new Timer() {
+ public void run() {
+ DOM.setElementProperty(loadElement, "className",
+ "i-loading-indicator-delay");
+ }
+ };
+ // Second one kicks in at 1500ms
+ loadTimer2.schedule(1200);
+
+ loadTimer3 = new Timer() {
+ public void run() {
+ DOM.setElementProperty(loadElement, "className",
+ "i-loading-indicator-wait");
+ }
+ };
+ // Third one kicks in at 5000ms
+ loadTimer3.schedule(4700);
+ }
+ };
+ // First one kicks in at 300ms
+ loadTimer.schedule(300);
+ }
+ }
+
+ private void hideLoadingIndicator() {
+ if (loadTimer != null) {
+ loadTimer.cancel();
+ if (loadTimer2 != null) {
+ loadTimer2.cancel();
+ loadTimer3.cancel();
+ }
+ loadTimer = null;
+ }
+ if (loadElement != null) {
+ DOM.removeChild(view.getElement(), loadElement);
+ loadElement = null;
+ }
+ }
+
+ private void handleReceivedJSONMessage(Response response) {
+ final Date start = new Date();
+ String jsonText = response.getText();
+ // for(;;);[realjson]
+ jsonText = jsonText.substring(9, jsonText.length() - 1);
+ JSONValue json;
+ try {
+ json = JSONParser.parse(jsonText);
+ } catch (final com.google.gwt.json.client.JSONException e) {
+ endRequest();
+ console.log(e.getMessage() + " - Original JSON-text:");
+ console.log(jsonText);
+ return;
+ }
+ // Handle redirect
+ final JSONObject redirect = (JSONObject) ((JSONObject) json)
+ .get("redirect");
+ if (redirect != null) {
+ final JSONString url = (JSONString) redirect.get("url");
+ if (url != null) {
+ console.log("redirecting to " + url.stringValue());
+ redirect(url.stringValue());
+ return;
+ }
+ }
+
+ // Store resources
+ final JSONObject resources = (JSONObject) ((JSONObject) json)
+ .get("resources");
+ for (final Iterator i = resources.keySet().iterator(); i.hasNext();) {
+ final String key = (String) i.next();
+ resourcesMap.put(key, ((JSONString) resources.get(key))
+ .stringValue());
+ }
+
+ // Store locale data
+ if (((JSONObject) json).containsKey("locales")) {
+ final JSONArray l = (JSONArray) ((JSONObject) json).get("locales");
+ for (int i = 0; i < l.size(); i++) {
+ LocaleService.addLocale((JSONObject) l.get(i));
+ }
+ }
+
+ JSONObject meta = null;
+ if (((JSONObject) json).containsKey("meta")) {
+ meta = ((JSONObject) json).get("meta").isObject();
+ if (meta.containsKey("repaintAll")) {
+ view.clear();
+ idToPaintable.clear();
+ paintableToId.clear();
+ }
+ }
+
+ // Process changes
+ final JSONArray changes = (JSONArray) ((JSONObject) json)
+ .get("changes");
+ for (int i = 0; i < changes.size(); i++) {
+ try {
+ final UIDL change = new UIDL((JSONArray) changes.get(i));
+ try {
+ console.dirUIDL(change);
+ } catch (final Exception e) {
+ console.log(e.getMessage());
+ // TODO: dir doesn't work in any browser although it should
+ // work (works in hosted mode)
+ // it partially did at some part but now broken.
+ }
+ final UIDL uidl = change.getChildUIDL(0);
+ final Paintable paintable = getPaintable(uidl.getId());
+ if (paintable != null) {
+ paintable.updateFromUIDL(uidl, this);
+ } else {
+ if (!uidl.getTag().equals("window")) {
+ System.out.println("Received update for "
+ + uidl.getTag()
+ + ", but there is no such paintable ("
+ + uidl.getId() + ") rendered.");
+ } else {
+ view.updateFromUIDL(uidl, this);
+ }
+ }
+ } catch (final Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (meta != null) {
+ if (meta.containsKey("focus")) {
+ final String focusPid = meta.get("focus").isString()
+ .stringValue();
+ final Paintable toBeFocused = getPaintable(focusPid);
+ if (toBeFocused instanceof HasFocus) {
+ final HasFocus toBeFocusedWidget = (HasFocus) toBeFocused;
+ toBeFocusedWidget.setFocus(true);
+ } else if (toBeFocused instanceof Focusable) {
+ ((Focusable) toBeFocused).focus();
+ } else {
+ getConsole().log("Could not focus component");
+ }
+
+ }
+ if (meta.containsKey("appError")) {
+ JSONObject error = meta.get("appError").isObject();
+ JSONValue val = error.get("caption");
+ String html = "";
+ if (val.isString() != null) {
+ html += "" + val.isString().stringValue() + "
";
+ }
+ val = error.get("message");
+ if (val.isString() != null) {
+ html += "" + val.isString().stringValue() + "
";
+ }
+ val = error.get("url");
+ String url = null;
+ if (val.isString() != null) {
+ url = val.isString().stringValue();
+ }
+
+ if (html.length() != 0) {
+ Notification n = new Notification(1000 * 60 * 45); // 45min
+ n.addEventListener(new NotificationRedirect(url));
+ n.show(html, Notification.CENTERED_TOP, "system");
+ } else {
+ redirect(url);
+ }
+ applicationRunning = false;
+ }
+ }
+
+ final long prosessingTime = (new Date().getTime()) - start.getTime();
+ console.log(" Processing time was " + String.valueOf(prosessingTime)
+ + "ms for " + jsonText.length() + " characters of JSON");
+ console.log("Referenced paintables: " + idToPaintable.size());
+
+ endRequest();
+ }
+
+ // Redirect browser, null reloads current page
+ private static native void redirect(String url)
+ /*-{
+ if (url) {
+ $wnd.location = url;
+ } else {
+ $wnd.location = $wnd.location;
+ }
+ }-*/;
+
+ public void registerPaintable(String id, Paintable paintable) {
+ idToPaintable.put(id, paintable);
+ paintableToId.put(paintable, id);
+ }
+
+ public void unregisterPaintable(Paintable p) {
+ Object id = paintableToId.get(p);
+ idToPaintable.remove(id);
+ paintableToTitle.remove(id);
+ paintableToId.remove(p);
+
+ if (p instanceof HasWidgets) {
+ unregisterChildPaintables((HasWidgets) p);
+ }
+ }
+
+ public void unregisterChildPaintables(HasWidgets container) {
+ final Iterator it = container.iterator();
+ while (it.hasNext()) {
+ final Widget w = (Widget) it.next();
+ if (w instanceof Paintable) {
+ unregisterPaintable((Paintable) w);
+ } else if (w instanceof HasWidgets) {
+ unregisterChildPaintables((HasWidgets) w);
+ }
+ }
+ }
+
+ /**
+ * Returns Paintable element by its id
+ *
+ * @param id
+ * Paintable ID
+ */
+ public Paintable getPaintable(String id) {
+ return (Paintable) idToPaintable.get(id);
+ }
+
+ private void addVariableToQueue(String paintableId, String variableName,
+ String encodedValue, boolean immediate, char type) {
+ final String id = paintableId + VAR_FIELD_SEPARATOR + variableName
+ + VAR_FIELD_SEPARATOR + type;
+ for (int i = 1; i < pendingVariables.size(); i += 2) {
+ if ((pendingVariables.get(i)).equals(id)) {
+ pendingVariables.remove(i - 1);
+ pendingVariables.remove(i - 1);
+ break;
+ }
+ }
+ pendingVariables.add(encodedValue);
+ pendingVariables.add(id);
+ if (immediate) {
+ sendPendingVariableChanges();
+ }
+ }
+
+ /**
+ * This method sends currently queued variable changes to server. It is
+ * called when immediate variable update must happen.
+ *
+ * To ensure correct order for variable changes (due servers multithreading
+ * or network), we always wait for active request to be handler before
+ * sending a new one. If there is an active request, we will put varible
+ * "burst" to queue that will be purged after current request is handled.
+ *
+ */
+ public void sendPendingVariableChanges() {
+ if (applicationRunning) {
+ if (hasActiveRequest()) {
+ // skip empty queues if there are pending bursts to be sent
+ if (pendingVariables.size() > 0
+ || pendingVariableBursts.size() == 0) {
+ Vector burst = (Vector) pendingVariables.clone();
+ pendingVariableBursts.add(burst);
+ }
+ } else {
+ buildAndSendVariableBurst(pendingVariables);
+ }
+ }
+ }
+
+ private void buildAndSendVariableBurst(Vector pendingVariables) {
+ final StringBuffer req = new StringBuffer();
+
+ for (int i = 0; i < pendingVariables.size(); i++) {
+ if (i > 0) {
+ if (i % 2 == 0) {
+ req.append(VAR_RECORD_SEPARATOR);
+ } else {
+ req.append(VAR_FIELD_SEPARATOR);
+ }
+ }
+ req.append(pendingVariables.get(i));
+ }
+
+ pendingVariables.clear();
+ makeUidlRequest(req.toString(), false);
+ }
+
+ public void updateVariable(String paintableId, String variableName,
+ String newValue, boolean immediate) {
+ addVariableToQueue(paintableId, variableName, newValue, immediate, 's');
+ }
+
+ public void updateVariable(String paintableId, String variableName,
+ int newValue, boolean immediate) {
+ addVariableToQueue(paintableId, variableName, "" + newValue, immediate,
+ 'i');
+ }
+
+ public void updateVariable(String paintableId, String variableName,
+ long newValue, boolean immediate) {
+ addVariableToQueue(paintableId, variableName, "" + newValue, immediate,
+ 'l');
+ }
+
+ public void updateVariable(String paintableId, String variableName,
+ float newValue, boolean immediate) {
+ addVariableToQueue(paintableId, variableName, "" + newValue, immediate,
+ 'f');
+ }
+
+ public void updateVariable(String paintableId, String variableName,
+ double newValue, boolean immediate) {
+ addVariableToQueue(paintableId, variableName, "" + newValue, immediate,
+ 'd');
+ }
+
+ public void updateVariable(String paintableId, String variableName,
+ boolean newValue, boolean immediate) {
+ addVariableToQueue(paintableId, variableName, newValue ? "true"
+ : "false", immediate, 'b');
+ }
+
+ public void updateVariable(String paintableId, String variableName,
+ Object[] values, boolean immediate) {
+ final StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < values.length; i++) {
+ if (i > 0) {
+ buf.append(",");
+ }
+ buf.append(values[i].toString());
+ }
+ addVariableToQueue(paintableId, variableName, buf.toString(),
+ immediate, 'a');
+ }
+
+ /**
+ * Update generic component features.
+ *
+ * Selecting correct implementation
+ *
+ *
+ * The implementation of a component depends on many properties, including
+ * styles, component features, etc. Sometimes the user changes those
+ * properties after the component has been created. Calling this method in
+ * the beginning of your updateFromUIDL -method automatically replaces your
+ * component with more appropriate if the requested implementation changes.
+ *
+ *
+ * Caption, icon, error messages and description
+ *
+ *
+ * Component can delegate management of caption, icon, error messages and
+ * description to parent layout. This is optional an should be decided by
+ * component author
+ *
+ *
+ * Component visibility and disabling
+ *
+ * This method will manage component visibility automatically and if
+ * component is an instanceof FocusWidget, also handle component disabling
+ * when needed.
+ *
+ * @param component
+ * Widget to be updated, expected to implement an instance of
+ * Paintable
+ * @param uidl
+ * UIDL to be painted
+ * @param manageCaption
+ * True if you want to delegate caption, icon, description
+ * and error message management to parent.
+ *
+ * @return Returns true iff no further painting is needed by caller
+ */
+ public boolean updateComponent(Widget component, UIDL uidl,
+ boolean manageCaption) {
+
+ // If the server request that a cached instance should be used, do
+ // nothing
+ if (uidl.getBooleanAttribute("cached")) {
+ return true;
+ }
+
+ // Visibility
+ boolean visible = !uidl.getBooleanAttribute("invisible");
+ component.setVisible(visible);
+ if (!visible) {
+ return true;
+ }
+
+ // Switch to correct implementation if needed
+ if (!widgetSet.isCorrectImplementation(component, uidl)) {
+ final Container parent = Util.getParentLayout(component);
+ if (parent != null) {
+ final Widget w = widgetSet.createWidget(uidl);
+ parent.replaceChildComponent(component, w);
+ registerPaintable(uidl.getId(), (Paintable) w);
+ ((Paintable) w).updateFromUIDL(uidl, this);
+ return true;
+ }
+ }
+
+ updateComponentSize(component, uidl);
+
+ boolean enabled = !uidl.getBooleanAttribute("disabled");
+ if (component instanceof FocusWidget) {
+ ((FocusWidget) component).setEnabled(enabled);
+ }
+
+ StringBuffer styleBuf = new StringBuffer();
+ final String primaryName = component.getStylePrimaryName();
+ styleBuf.append(primaryName);
+
+ // first disabling and read-only status
+ if (!enabled) {
+ styleBuf.append(" ");
+ styleBuf.append("i-disabled");
+ }
+ if (uidl.getBooleanAttribute("readonly")) {
+ styleBuf.append(" ");
+ styleBuf.append("i-readonly");
+ }
+
+ // add additional styles as css classes, prefixed with component default
+ // stylename
+ if (uidl.hasAttribute("style")) {
+ final String[] styles = uidl.getStringAttribute("style").split(" ");
+ for (int i = 0; i < styles.length; i++) {
+ styleBuf.append(" ");
+ styleBuf.append(primaryName);
+ styleBuf.append("-");
+ styleBuf.append(styles[i]);
+ }
+ }
+
+ // add modified classname to Fields
+ if (uidl.hasAttribute("modified") && component instanceof Field) {
+ styleBuf.append(" ");
+ styleBuf.append(MODIFIED_CLASSNAME);
+ }
+
+ TooltipInfo tooltipInfo = getTitleInfo((Paintable) component);
+ if (uidl.hasAttribute("description")) {
+ tooltipInfo.setTitle(uidl.getStringAttribute("description"));
+ } else {
+ tooltipInfo.setTitle(null);
+ }
+
+ // add error classname to components w/ error
+ if (uidl.hasAttribute("error")) {
+ styleBuf.append(" ");
+ styleBuf.append(primaryName);
+ styleBuf.append(ERROR_CLASSNAME_EXT);
+
+ tooltipInfo.setErrorUidl(uidl.getErrors());
+ } else {
+ tooltipInfo.setErrorUidl(null);
+ }
+
+ // add required style to required components
+ if (uidl.hasAttribute("required")) {
+ styleBuf.append(" ");
+ styleBuf.append(primaryName);
+ styleBuf.append(REQUIRED_CLASSNAME_EXT);
+ }
+
+ // Styles + disabled & readonly
+ component.setStyleName(styleBuf.toString());
+
+ // Set captions
+ if (manageCaption) {
+ final Container parent = Util.getParentLayout(component);
+ if (parent != null) {
+ parent.updateCaption((Paintable) component, uidl);
+ }
+ }
+
+ if (usePaintableIdsInDOM) {
+ DOM.setElementProperty(component.getElement(), "id", uidl.getId());
+ }
+
+ return false;
+ }
+
+ private void updateComponentSize(Widget component, UIDL uidl) {
+ String w = uidl.hasAttribute("width") ? uidl
+ .getStringAttribute("width") : "";
+ component.setWidth(w);
+ String h = uidl.hasAttribute("height") ? uidl
+ .getStringAttribute("height") : "";
+ component.setHeight(h);
+ }
+
+ /**
+ * Get either existing or new Paintable for given UIDL.
+ *
+ * If corresponding Paintable has been previously painted, return it.
+ * Otherwise create and register a new Paintable from UIDL. Caller must
+ * update the returned Paintable from UIDL after it has been connected to
+ * parent.
+ *
+ * @param uidl
+ * UIDL to create Paintable from.
+ * @return Either existing or new Paintable corresponding to UIDL.
+ */
+ public Paintable getPaintable(UIDL uidl) {
+ final String id = uidl.getId();
+ Paintable w = getPaintable(id);
+ if (w != null) {
+ return w;
+ }
+ w = (Paintable) widgetSet.createWidget(uidl);
+ registerPaintable(id, w);
+ return w;
+ }
+
+ public String getResource(String name) {
+ return (String) resourcesMap.get(name);
+ }
+
+ /**
+ * Singleton method to get instance of app's context menu.
+ *
+ * @return IContextMenu object
+ */
+ public ContextMenu getContextMenu() {
+ if (contextMenu == null) {
+ contextMenu = new ContextMenu();
+ if (usePaintableIdsInDOM) {
+ DOM.setElementProperty(contextMenu.getElement(), "id",
+ "PID_TOOLKIT_CM");
+ }
+ }
+ return contextMenu;
+ }
+
+ /**
+ * Translates custom protocols in UIRL URI's to be recognizable by browser.
+ * All uri's from UIDL should be routed via this method before giving them
+ * to browser due URI's in UIDL may contain custom protocols like theme://.
+ *
+ * @param toolkitUri
+ * toolkit URI from uidl
+ * @return translated URI ready for browser
+ */
+ public String translateToolkitUri(String toolkitUri) {
+ if (toolkitUri == null) {
+ return null;
+ }
+ if (toolkitUri.startsWith("theme://")) {
+ final String themeUri = configuration.getThemeUri();
+ if (themeUri == null) {
+ console
+ .error("Theme not set: ThemeResource will not be found. ("
+ + toolkitUri + ")");
+ }
+ toolkitUri = themeUri + toolkitUri.substring(7);
+ }
+ return toolkitUri;
+ }
+
+ public String getThemeUri() {
+ return configuration.getThemeUri();
+ }
+
+ /**
+ * Listens for Notification hide event, and redirects. Used for system
+ * messages, such as session expired.
+ *
+ */
+ private class NotificationRedirect implements Notification.EventListener {
+ String url;
+
+ NotificationRedirect(String url) {
+ this.url = url;
+ }
+
+ public void notificationHidden(HideEvent event) {
+ redirect(url);
+ }
+
+ }
+
+ /* Extended title handling */
+
+ /**
+ * Data showed in tooltips are stored centrilized as it may be needed in
+ * varios place: caption, layouts, and in owner components themselves.
+ *
+ * Updating TooltipInfo is done in updateComponent method.
+ *
+ */
+ public TooltipInfo getTitleInfo(Paintable titleOwner) {
+ TooltipInfo info = (TooltipInfo) paintableToTitle.get(titleOwner);
+ if (info == null) {
+ info = new TooltipInfo();
+ paintableToTitle.put(titleOwner, info);
+ }
+ return info;
+ }
+
+ private final Tooltip tooltip = new Tooltip(this);
+
+ /**
+ * Component may want to delegate Tooltip handling to client. Layouts add
+ * Tooltip (description, errors) to caption, but some components may want
+ * them to appear one other elements too.
+ *
+ * Events wanted by this handler are same as in Tooltip.TOOLTIP_EVENTS
+ *
+ * @param event
+ * @param owner
+ */
+ public void handleTooltipEvent(Event event, Paintable owner) {
+ tooltip.handleTooltipEvent(event, owner);
+
+ }
+
+ /**
+ * Adds PNG-fix conditionally (only for IE6) to the specified IMG -element.
+ *
+ * @param el
+ * the IMG element to fix
+ */
+ public void addPngFix(Element el) {
+ BrowserInfo b = BrowserInfo.get();
+ if (b.isIE6()) {
+ Util.addPngFix(el, getThemeUri()
+ + "/../default/common/img/blank.gif");
+ }
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/BrowserInfo.java b/src/com/itmill/toolkit/terminal/gwt/client/client/BrowserInfo.java
new file mode 100644
index 0000000000..63805fd623
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/BrowserInfo.java
@@ -0,0 +1,141 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client;
+
+/**
+ * Class used to query information about web browser.
+ *
+ * Browser details are detected only once and those are stored in this singleton
+ * class.
+ *
+ */
+public class BrowserInfo {
+
+ private static BrowserInfo instance;
+
+ /**
+ * Singleton method to get BrowserInfo object.
+ *
+ * @return instance of BrowserInfo object
+ */
+ public static BrowserInfo get() {
+ if (instance == null) {
+ instance = new BrowserInfo();
+ }
+ return instance;
+ }
+
+ private boolean isGecko;
+ private boolean isAppleWebKit;
+ private boolean isSafari;
+ private boolean isOpera;
+ private boolean isIE;
+ private float ieVersion = -1;
+ private float geckoVersion = -1;
+ private float appleWebKitVersion = -1;
+
+ private BrowserInfo() {
+ try {
+ String ua = getBrowserString().toLowerCase();
+ // browser engine name
+ isGecko = ua.indexOf("gecko") != -1 && ua.indexOf("safari") == -1;
+ isAppleWebKit = ua.indexOf("applewebkit") != -1;
+
+ // browser name
+ isSafari = ua.indexOf("safari") != -1;
+ isOpera = ua.indexOf("opera") != -1;
+ isIE = ua.indexOf("msie") != -1 && !isOpera
+ && (ua.indexOf("webtv") == -1);
+
+ if (isGecko) {
+ String tmp = ua.substring(ua.indexOf("rv:") + 3);
+ tmp = tmp.replaceFirst("(\\.[0-9]+).+", "$1");
+ geckoVersion = Float.parseFloat(tmp);
+ }
+ if (isAppleWebKit) {
+ String tmp = ua.substring(ua.indexOf("webkit/") + 7);
+ tmp = tmp.replaceFirst("([0-9]+)[^0-9].+", "$1");
+ appleWebKitVersion = Float.parseFloat(tmp);
+
+ }
+
+ if (isIE) {
+ String ieVersionString = ua.substring(ua.indexOf("msie ") + 5);
+ ieVersionString = ieVersionString.substring(0, ieVersionString
+ .indexOf(";"));
+ ieVersion = Float.parseFloat(ieVersionString);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ ApplicationConnection.getConsole().error(e.getMessage());
+ }
+ }
+
+ public boolean isIE() {
+ return isIE;
+ }
+
+ public boolean isSafari() {
+ return isSafari;
+ }
+
+ public boolean isIE6() {
+ return isIE && ieVersion == 6;
+ }
+
+ public boolean isIE7() {
+ return isIE && ieVersion == 7;
+ }
+
+ public boolean isGecko() {
+ return isGecko;
+ }
+
+ public boolean isFF2() {
+ return isGecko && geckoVersion == 1.8;
+ }
+
+ public boolean isFF3() {
+ return isGecko && geckoVersion == 1.9;
+ }
+
+ public float getGeckoVersion() {
+ return geckoVersion;
+ }
+
+ public float getWebkitVersion() {
+ return appleWebKitVersion;
+ }
+
+ public float getIEVersion() {
+ return ieVersion;
+ }
+
+ public boolean isOpera() {
+ return isOpera;
+ }
+
+ public native static String getBrowserString()
+ /*-{
+ return $wnd.navigator.userAgent;
+ }-*/;
+
+ public static void test() {
+ Console c = ApplicationConnection.getConsole();
+
+ c.log("getBrowserString() " + getBrowserString());
+ c.log("isIE() " + get().isIE());
+ c.log("isIE6() " + get().isIE6());
+ c.log("isIE7() " + get().isIE7());
+ c.log("isFF2() " + get().isFF2());
+ c.log("isSafari() " + get().isSafari());
+ c.log("getGeckoVersion() " + get().getGeckoVersion());
+ c.log("getWebkitVersion() " + get().getWebkitVersion());
+ c.log("getIEVersion() " + get().getIEVersion());
+ c.log("isIE() " + get().isIE());
+ c.log("isIE() " + get().isIE());
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/CSSRule.java b/src/com/itmill/toolkit/terminal/gwt/client/client/CSSRule.java
new file mode 100644
index 0000000000..d7cca245dc
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/CSSRule.java
@@ -0,0 +1,84 @@
+package com.itmill.toolkit.terminal.gwt.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+
+/**
+ * Utility class for fetching CSS properties from DOM StyleSheets JS object.
+ */
+public class CSSRule {
+
+ private final String selector;
+ private JavaScriptObject rules = null;
+
+ public CSSRule(String selector) {
+ this.selector = selector;
+ fetchRule(selector);
+ }
+
+ // TODO how to find the right LINK-element? We should probably give the
+ // stylesheet a name.
+ private native void fetchRule(final String selector)
+ /*-{
+ this.@com.itmill.toolkit.terminal.gwt.client.CSSRule::rules = @com.itmill.toolkit.terminal.gwt.client.CSSRule::searchForRule(Lcom/google/gwt/core/client/JavaScriptObject;Ljava/lang/String;)($doc.styleSheets[1], selector);
+ }-*/;
+
+ /*
+ * Loops through all current style rules and collects all matching to
+ * 'rules' array. The array is reverse ordered (last one found is first).
+ */
+ private static native JavaScriptObject searchForRule(
+ JavaScriptObject sheet, final String selector)
+ /*-{
+ if(!$doc.styleSheets)
+ return null;
+
+ selector = selector.toLowerCase();
+
+ var allMatches = [];
+
+ var theRules = new Array();
+ if (sheet.cssRules)
+ theRules = sheet.cssRules
+ else if (sheet.rules)
+ theRules = sheet.rules
+
+ var j = theRules.length;
+ for(var i=0; i
+ * Each component is responsible for maintaining its caption, description
+ * and error message. In most cases components doesn't want to do that and
+ * those elements reside outside of the component. Because of this layouts
+ * must provide service for it's childen to show those elements for them.
+ *
+ *
+ * @param component
+ * Child component for which service is requested.
+ * @param uidl
+ * UIDL of the child component.
+ */
+ void updateCaption(Paintable component, UIDL uidl);
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/ContainerResizedListener.java b/src/com/itmill/toolkit/terminal/gwt/client/client/ContainerResizedListener.java
new file mode 100644
index 0000000000..f299c985dd
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/ContainerResizedListener.java
@@ -0,0 +1,20 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client;
+
+/**
+ * ContainerResizedListener interface is useful for Widgets that support
+ * relative sizes and who need some additional sizing logic.
+ */
+public interface ContainerResizedListener {
+ /**
+ * This function is run when container box has been resized. Object
+ * implementing ContainerResizedListener is responsible to call the same
+ * function on its ancestors that implement NeedsLayout in case their
+ * container has resized. runAnchestorsLayout(HasWidgets parent) function
+ * from Util class may be a good helper for this.
+ */
+ public void iLayout();
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/DateTimeService.java b/src/com/itmill/toolkit/terminal/gwt/client/client/DateTimeService.java
new file mode 100644
index 0000000000..aaa3ebc9b6
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/DateTimeService.java
@@ -0,0 +1,245 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client;
+
+import java.util.Date;
+
+/**
+ * This class provides date/time parsing services to all components on the
+ * client side.
+ *
+ * @author IT Mill Ltd.
+ *
+ */
+public class DateTimeService {
+ public static int RESOLUTION_YEAR = 0;
+ public static int RESOLUTION_MONTH = 1;
+ public static int RESOLUTION_DAY = 2;
+ public static int RESOLUTION_HOUR = 3;
+ public static int RESOLUTION_MIN = 4;
+ public static int RESOLUTION_SEC = 5;
+ public static int RESOLUTION_MSEC = 6;
+
+ private String currentLocale;
+
+ private static int[] maxDaysInMonth = { 31, 28, 31, 30, 31, 30, 31, 31, 30,
+ 31, 30, 31 };
+
+ /**
+ * Creates a new date time service with the application default locale.
+ */
+ public DateTimeService() {
+ currentLocale = LocaleService.getDefaultLocale();
+ }
+
+ /**
+ * Creates a new date time service with a given locale.
+ *
+ * @param locale
+ * e.g. fi, en etc.
+ * @throws LocaleNotLoadedException
+ */
+ public DateTimeService(String locale) throws LocaleNotLoadedException {
+ setLocale(locale);
+ }
+
+ public void setLocale(String locale) throws LocaleNotLoadedException {
+ if (LocaleService.getAvailableLocales().contains(locale)) {
+ currentLocale = locale;
+ } else {
+ throw new LocaleNotLoadedException(locale);
+ }
+ }
+
+ public String getLocale() {
+ return currentLocale;
+ }
+
+ public String getMonth(int month) {
+ try {
+ return LocaleService.getMonthNames(currentLocale)[month];
+ } catch (final LocaleNotLoadedException e) {
+ // TODO redirect to console
+ System.out.println(e + ":" + e.getMessage());
+ }
+ return null;
+ }
+
+ public String getShortMonth(int month) {
+ try {
+ return LocaleService.getShortMonthNames(currentLocale)[month];
+ } catch (final LocaleNotLoadedException e) {
+ // TODO redirect to console
+ System.out.println(e + ":" + e.getMessage());
+ }
+ return null;
+ }
+
+ public String getDay(int day) {
+ try {
+ return LocaleService.getDayNames(currentLocale)[day];
+ } catch (final LocaleNotLoadedException e) {
+ // TODO redirect to console
+ System.out.println(e + ":" + e.getMessage());
+ }
+ return null;
+ }
+
+ public String getShortDay(int day) {
+ try {
+ return LocaleService.getShortDayNames(currentLocale)[day];
+ } catch (final LocaleNotLoadedException e) {
+ // TODO redirect to console
+ System.out.println(e + ":" + e.getMessage());
+ }
+ return null;
+ }
+
+ public int getFirstDayOfWeek() {
+ try {
+ return LocaleService.getFirstDayOfWeek(currentLocale);
+ } catch (final LocaleNotLoadedException e) {
+ // TODO redirect to console
+ System.out.println(e + ":" + e.getMessage());
+ }
+ return 0;
+ }
+
+ public boolean isTwelveHourClock() {
+ try {
+ return LocaleService.isTwelveHourClock(currentLocale);
+ } catch (final LocaleNotLoadedException e) {
+ // TODO redirect to console
+ System.out.println(e + ":" + e.getMessage());
+ }
+ return false;
+ }
+
+ public String getClockDelimeter() {
+ try {
+ return LocaleService.getClockDelimiter(currentLocale);
+ } catch (final LocaleNotLoadedException e) {
+ // TODO redirect to console
+ System.out.println(e + ":" + e.getMessage());
+ }
+ return ":";
+ }
+
+ public String[] getAmPmStrings() {
+ try {
+ return LocaleService.getAmPmStrings(currentLocale);
+ } catch (final LocaleNotLoadedException e) {
+ // TODO redirect to console
+ System.out.println(e + ":" + e.getMessage());
+ }
+ final String[] temp = new String[2];
+ temp[0] = "AM";
+ temp[1] = "PM";
+ return temp;
+ }
+
+ public int getStartWeekDay(Date date) {
+ final Date dateForFirstOfThisMonth = new Date(date.getYear(), date
+ .getMonth(), 1);
+ int firstDay;
+ try {
+ firstDay = LocaleService.getFirstDayOfWeek(currentLocale);
+ } catch (final LocaleNotLoadedException e) {
+ firstDay = 0;
+ // TODO redirect to console
+ System.out.println(e + ":" + e.getMessage());
+ }
+ int start = dateForFirstOfThisMonth.getDay() - firstDay;
+ if (start < 0) {
+ start = 6;
+ }
+ return start;
+ }
+
+ public static int getNumberOfDaysInMonth(Date date) {
+ final int month = date.getMonth();
+ if (month == 1 && true == isLeapYear(date)) {
+ return 29;
+ }
+ return maxDaysInMonth[month];
+ }
+
+ public static boolean isLeapYear(Date date) {
+ // Instantiate the date for 1st March of that year
+ final Date firstMarch = new Date(date.getYear(), 2, 1);
+
+ // Go back 1 day
+ final long firstMarchTime = firstMarch.getTime();
+ final long lastDayTimeFeb = firstMarchTime - (24 * 60 * 60 * 1000); // NUM_MILLISECS_A_DAY
+
+ // Instantiate new Date with this time
+ final Date febLastDay = new Date(lastDayTimeFeb);
+
+ // Check for date in this new instance
+ return (29 == febLastDay.getDate()) ? true : false;
+ }
+
+ public static boolean isSameDay(Date d1, Date d2) {
+ return (getDayInt(d1) == getDayInt(d2));
+ }
+
+ public static boolean isInRange(Date date, Date rangeStart, Date rangeEnd,
+ int resolution) {
+ Date s;
+ Date e;
+ if (rangeStart.after(rangeEnd)) {
+ s = rangeEnd;
+ e = rangeStart;
+ } else {
+ e = rangeEnd;
+ s = rangeStart;
+ }
+ long start = s.getYear() * 10000000000l;
+ long end = e.getYear() * 10000000000l;
+ long target = date.getYear() * 10000000000l;
+
+ if (resolution == RESOLUTION_YEAR) {
+ return (start <= target && end >= target);
+ }
+ start += s.getMonth() * 100000000;
+ end += e.getMonth() * 100000000;
+ target += date.getMonth() * 100000000;
+ if (resolution == RESOLUTION_MONTH) {
+ return (start <= target && end >= target);
+ }
+ start += s.getDate() * 1000000;
+ end += e.getDate() * 1000000;
+ target += date.getDate() * 1000000;
+ if (resolution == RESOLUTION_DAY) {
+ return (start <= target && end >= target);
+ }
+ start += s.getHours() * 10000;
+ end += e.getHours() * 10000;
+ target += date.getHours() * 10000;
+ if (resolution == RESOLUTION_HOUR) {
+ return (start <= target && end >= target);
+ }
+ start += s.getMinutes() * 100;
+ end += e.getMinutes() * 100;
+ target += date.getMinutes() * 100;
+ if (resolution == RESOLUTION_MIN) {
+ return (start <= target && end >= target);
+ }
+ start += s.getSeconds();
+ end += e.getSeconds();
+ target += date.getSeconds();
+ return (start <= target && end >= target);
+
+ }
+
+ private static int getDayInt(Date date) {
+ final int y = date.getYear();
+ final int m = date.getMonth();
+ final int d = date.getDate();
+
+ return ((y + 1900) * 10000 + m * 100 + d) * 1000000000;
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/DebugConsole.java b/src/com/itmill/toolkit/terminal/gwt/client/client/DebugConsole.java
new file mode 100755
index 0000000000..6bd0f247b3
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/DebugConsole.java
@@ -0,0 +1,112 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Panel;
+import com.google.gwt.user.client.ui.ScrollPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.itmill.toolkit.terminal.gwt.client.ui.IWindow;
+
+public final class DebugConsole extends IWindow implements Console {
+
+ private final Panel panel;
+
+ public DebugConsole(ApplicationConnection client) {
+ super();
+ this.client = client;
+ panel = new FlowPanel();
+ final ScrollPanel p = new ScrollPanel();
+ p.add(panel);
+ setWidget(p);
+ setCaption("Debug window");
+ minimize();
+ show();
+ }
+
+ private void minimize() {
+ // TODO stack to bottom (create window manager of some sort)
+ setPixelSize(60, 60);
+ setPopupPosition(Window.getClientWidth()
+ - (100 + IWindow.BORDER_WIDTH_HORIZONTAL), 0);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.itmill.toolkit.terminal.gwt.client.Console#log(java.lang.String)
+ */
+ public void log(String msg) {
+ panel.add(new HTML(msg));
+ System.out.println(msg);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.itmill.toolkit.terminal.gwt.client.Console#error(java.lang.String)
+ */
+ public void error(String msg) {
+ panel.add((new HTML(msg)));
+ System.out.println(msg);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.itmill.toolkit.terminal.gwt.client.Console#printObject(java.lang.Object)
+ */
+ public void printObject(Object msg) {
+ panel.add((new Label(msg.toString())));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.itmill.toolkit.terminal.gwt.client.Console#dirUIDL(com.itmill.toolkit.terminal.gwt.client.UIDL)
+ */
+ public void dirUIDL(UIDL u) {
+ panel.add(u.print_r());
+ }
+
+ public void setSize(Event event, boolean updateVariables) {
+ super.setSize(event, false);
+ }
+
+ public void onScroll(Widget widget, int scrollLeft, int scrollTop) {
+
+ }
+
+ public void setPopupPosition(int left, int top) {
+ // Keep the popup within the browser's client area, so that they can't
+ // get
+ // 'lost' and become impossible to interact with. Note that we don't
+ // attempt
+ // to keep popups pegged to the bottom and right edges, as they will
+ // then
+ // cause scrollbars to appear, so the user can't lose them.
+ if (left < 0) {
+ left = 0;
+ }
+ if (top < 0) {
+ top = 0;
+ }
+
+ // Set the popup's position manually, allowing setPopupPosition() to be
+ // called before show() is called (so a popup can be positioned without
+ // it
+ // 'jumping' on the screen).
+ Element elem = getElement();
+ DOM.setStyleAttribute(elem, "left", left + "px");
+ DOM.setStyleAttribute(elem, "top", top + "px");
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/DefaultWidgetSet.java b/src/com/itmill/toolkit/terminal/gwt/client/client/DefaultWidgetSet.java
new file mode 100644
index 0000000000..b98cdec668
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/DefaultWidgetSet.java
@@ -0,0 +1,323 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.itmill.toolkit.terminal.gwt.client.ui.IAccordion;
+import com.itmill.toolkit.terminal.gwt.client.ui.IButton;
+import com.itmill.toolkit.terminal.gwt.client.ui.ICheckBox;
+import com.itmill.toolkit.terminal.gwt.client.ui.ICustomComponent;
+import com.itmill.toolkit.terminal.gwt.client.ui.ICustomLayout;
+import com.itmill.toolkit.terminal.gwt.client.ui.IDateFieldCalendar;
+import com.itmill.toolkit.terminal.gwt.client.ui.IEmbedded;
+import com.itmill.toolkit.terminal.gwt.client.ui.IExpandLayout;
+import com.itmill.toolkit.terminal.gwt.client.ui.IFilterSelect;
+import com.itmill.toolkit.terminal.gwt.client.ui.IForm;
+import com.itmill.toolkit.terminal.gwt.client.ui.IFormLayout;
+import com.itmill.toolkit.terminal.gwt.client.ui.IGridLayout;
+import com.itmill.toolkit.terminal.gwt.client.ui.IHorizontalExpandLayout;
+import com.itmill.toolkit.terminal.gwt.client.ui.ILabel;
+import com.itmill.toolkit.terminal.gwt.client.ui.ILink;
+import com.itmill.toolkit.terminal.gwt.client.ui.IListSelect;
+import com.itmill.toolkit.terminal.gwt.client.ui.IMenuBar;
+import com.itmill.toolkit.terminal.gwt.client.ui.INativeSelect;
+import com.itmill.toolkit.terminal.gwt.client.ui.IOptionGroup;
+import com.itmill.toolkit.terminal.gwt.client.ui.IOrderedLayout;
+import com.itmill.toolkit.terminal.gwt.client.ui.IPanel;
+import com.itmill.toolkit.terminal.gwt.client.ui.IPasswordField;
+import com.itmill.toolkit.terminal.gwt.client.ui.IPopupCalendar;
+import com.itmill.toolkit.terminal.gwt.client.ui.IProgressIndicator;
+import com.itmill.toolkit.terminal.gwt.client.ui.IScrollTable;
+import com.itmill.toolkit.terminal.gwt.client.ui.ISlider;
+import com.itmill.toolkit.terminal.gwt.client.ui.ISplitPanelHorizontal;
+import com.itmill.toolkit.terminal.gwt.client.ui.ISplitPanelVertical;
+import com.itmill.toolkit.terminal.gwt.client.ui.ITablePaging;
+import com.itmill.toolkit.terminal.gwt.client.ui.ITabsheet;
+import com.itmill.toolkit.terminal.gwt.client.ui.ITextArea;
+import com.itmill.toolkit.terminal.gwt.client.ui.ITextField;
+import com.itmill.toolkit.terminal.gwt.client.ui.ITextualDate;
+import com.itmill.toolkit.terminal.gwt.client.ui.ITree;
+import com.itmill.toolkit.terminal.gwt.client.ui.ITwinColSelect;
+import com.itmill.toolkit.terminal.gwt.client.ui.IUnknownComponent;
+import com.itmill.toolkit.terminal.gwt.client.ui.IUpload;
+import com.itmill.toolkit.terminal.gwt.client.ui.IWindow;
+import com.itmill.toolkit.terminal.gwt.client.ui.absolutegrid.ISizeableGridLayout;
+import com.itmill.toolkit.terminal.gwt.client.ui.richtextarea.IRichTextArea;
+
+public class DefaultWidgetSet implements WidgetSet {
+
+ /**
+ * This is the entry point method.
+ */
+ public void onModuleLoad() {
+ ArrayList appIds = new ArrayList();
+ ApplicationConfiguration.loadAppIdListFromDOM(appIds);
+ for (Iterator iterator = appIds.iterator(); iterator.hasNext();) {
+ String appId = (String) iterator.next();
+ ApplicationConfiguration appConf = ApplicationConfiguration
+ .getConfigFromDOM(appId);
+ new ApplicationConnection(this, appConf);
+ }
+ }
+
+ public Widget createWidget(UIDL uidl) {
+
+ final String className = resolveWidgetTypeName(uidl);
+ if ("com.itmill.toolkit.terminal.gwt.client.ui.ICheckBox"
+ .equals(className)) {
+ return new ICheckBox();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IButton"
+ .equals(className)) {
+ return new IButton();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IWindow"
+ .equals(className)) {
+ return new IWindow();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IOrderedLayout"
+ .equals(className)) {
+ return new IOrderedLayout();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.ILabel"
+ .equals(className)) {
+ return new ILabel();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.ILink"
+ .equals(className)) {
+ return new ILink();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.absolutegrid.ISizeableGridLayout"
+ .equals(className)) {
+ return new ISizeableGridLayout();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IGridLayout"
+ .equals(className)) {
+ return new IGridLayout();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.ITree"
+ .equals(className)) {
+ return new ITree();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IOptionGroup"
+ .equals(className)) {
+ return new IOptionGroup();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.ITwinColSelect"
+ .equals(className)) {
+ return new ITwinColSelect();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.INativeSelect"
+ .equals(className)) {
+ return new INativeSelect();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IListSelect"
+ .equals(className)) {
+ return new IListSelect();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IPanel"
+ .equals(className)) {
+ return new IPanel();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.ITabsheet"
+ .equals(className)) {
+ return new ITabsheet();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IEmbedded"
+ .equals(className)) {
+ return new IEmbedded();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.ICustomLayout"
+ .equals(className)) {
+ return new ICustomLayout();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.ICustomComponent"
+ .equals(className)) {
+ return new ICustomComponent();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.ITextArea"
+ .equals(className)) {
+ return new ITextArea();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IPasswordField"
+ .equals(className)) {
+ return new IPasswordField();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.ITextField"
+ .equals(className)) {
+ return new ITextField();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.ITablePaging"
+ .equals(className)) {
+ return new ITablePaging();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IScrollTable"
+ .equals(className)) {
+ return new IScrollTable();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IDateFieldCalendar"
+ .equals(className)) {
+ return new IDateFieldCalendar();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.ITextualDate"
+ .equals(className)) {
+ return new ITextualDate();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IPopupCalendar"
+ .equals(className)) {
+ return new IPopupCalendar();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.ISlider"
+ .equals(className)) {
+ return new ISlider();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IForm"
+ .equals(className)) {
+ return new IForm();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IFormLayout"
+ .equals(className)) {
+ return new IFormLayout();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IUpload"
+ .equals(className)) {
+ return new IUpload();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.ISplitPanelHorizontal"
+ .equals(className)) {
+ return new ISplitPanelHorizontal();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.ISplitPanelVertical"
+ .equals(className)) {
+ return new ISplitPanelVertical();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IFilterSelect"
+ .equals(className)) {
+ return new IFilterSelect();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IProgressIndicator"
+ .equals(className)) {
+ return new IProgressIndicator();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IExpandLayout"
+ .equals(className)) {
+ return new IExpandLayout();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IHorizontalExpandLayout"
+ .equals(className)) {
+ return new IHorizontalExpandLayout();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.richtextarea.IRichTextArea"
+ .equals(className)) {
+ return new IRichTextArea();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IAccordion"
+ .equals(className)) {
+ return new IAccordion();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IMenuBar"
+ .equals(className)) {
+ return new IMenuBar();
+ }
+
+ return new IUnknownComponent();
+
+ /*
+ * TODO: Class based impl, use when GWT supports return
+ * (Widget)GWT.create(resolveWidgetClass(uidl));
+ */
+ }
+
+ protected String resolveWidgetTypeName(UIDL uidl) {
+
+ final String tag = uidl.getTag();
+ if ("button".equals(tag)) {
+ if ("switch".equals(uidl.getStringAttribute("type"))) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.ICheckBox";
+ } else {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IButton";
+ }
+ } else if ("window".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IWindow";
+ } else if ("orderedlayout".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IOrderedLayout";
+ } else if ("label".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.ILabel";
+ } else if ("link".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.ILink";
+ } else if ("gridlayout".equals(tag)) {
+ if (uidl.hasAttribute("height")) {
+ // height needs to be set to use sizeable grid layout, with
+ // width only or no size at all it fails to render properly.
+ return "com.itmill.toolkit.terminal.gwt.client.ui.absolutegrid.ISizeableGridLayout";
+ } else {
+ // Fall back to GWT FlexTable based implementation.
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IGridLayout";
+ }
+ } else if ("tree".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.ITree";
+ } else if ("select".equals(tag)) {
+ if (uidl.hasAttribute("type")) {
+ final String type = uidl.getStringAttribute("type");
+ if (type.equals("twincol")) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.ITwinColSelect";
+ }
+ if (type.equals("optiongroup")) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IOptionGroup";
+ }
+ if (type.equals("native")) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.INativeSelect";
+ }
+ if (type.equals("list")) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IListSelect";
+ }
+ } else {
+ if (uidl.hasAttribute("selectmode")
+ && uidl.getStringAttribute("selectmode")
+ .equals("multi")) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IListSelect";
+ } else {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IFilterSelect";
+ }
+ }
+ } else if ("panel".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IPanel";
+ } else if ("tabsheet".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.ITabsheet";
+ } else if ("accordion".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IAccordion";
+ } else if ("embedded".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IEmbedded";
+ } else if ("customlayout".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.ICustomLayout";
+ } else if ("customcomponent".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.ICustomComponent";
+ } else if ("textfield".equals(tag)) {
+ if (uidl.getBooleanAttribute("richtext")) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.richtextarea.IRichTextArea";
+ } else if (uidl.hasAttribute("multiline")) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.ITextArea";
+ } else if (uidl.getBooleanAttribute("secret")) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IPasswordField";
+ } else {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.ITextField";
+ }
+ } else if ("table".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IScrollTable";
+ } else if ("pagingtable".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.ITablePaging";
+ } else if ("datefield".equals(tag)) {
+ if (uidl.hasAttribute("type")) {
+ if ("inline".equals(uidl.getStringAttribute("type"))) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IDateFieldCalendar";
+ } else if ("popup".equals(uidl.getStringAttribute("type"))) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IPopupCalendar";
+ }
+ }
+ // popup calendar is the default
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IPopupCalendar";
+ } else if ("slider".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.ISlider";
+ } else if ("form".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IForm";
+ } else if ("formlayout".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IFormLayout";
+ } else if ("upload".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IUpload";
+ } else if ("hsplitpanel".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.ISplitPanelHorizontal";
+ } else if ("vsplitpanel".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.ISplitPanelVertical";
+ } else if ("progressindicator".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IProgressIndicator";
+ } else if ("expandlayout".equals(tag)) {
+ if ("horizontal".equals(uidl.getStringAttribute("orientation"))) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IHorizontalExpandLayout";
+ } else {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IExpandLayout";
+ }
+ } else if ("menubar".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IMenuBar";
+ }
+
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IUnknownComponent";
+
+ /*
+ * TODO: use class based impl when GWT supports it
+ */
+ }
+
+ public boolean isCorrectImplementation(Widget currentWidget, UIDL uidl) {
+ return GWT.getTypeName(currentWidget).equals(
+ resolveWidgetTypeName(uidl));
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/ErrorMessage.java b/src/com/itmill/toolkit/terminal/gwt/client/client/ErrorMessage.java
new file mode 100644
index 0000000000..e4ca0f1422
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/ErrorMessage.java
@@ -0,0 +1,73 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client;
+
+import java.util.Iterator;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.itmill.toolkit.terminal.gwt.client.ui.ToolkitOverlay;
+
+public class ErrorMessage extends FlowPanel {
+ public static final String CLASSNAME = "i-errormessage";
+
+ public ErrorMessage() {
+ super();
+ setStyleName(CLASSNAME);
+ }
+
+ public void updateFromUIDL(UIDL uidl) {
+ clear();
+ if (uidl.getChildCount() == 0) {
+ add(new HTML(" "));
+ } else {
+ for (final Iterator it = uidl.getChildIterator(); it.hasNext();) {
+ final Object child = it.next();
+ if (child instanceof String) {
+ final String errorMessage = (String) child;
+ add(new HTML(errorMessage));
+ } else if (child instanceof UIDL.XML) {
+ final UIDL.XML xml = (UIDL.XML) child;
+ add(new HTML(xml.getXMLAsString()));
+ } else {
+ final ErrorMessage childError = new ErrorMessage();
+ add(childError);
+ childError.updateFromUIDL((UIDL) child);
+ }
+ }
+ }
+ }
+
+ /**
+ * Shows this error message next to given element.
+ *
+ * @param indicatorElement
+ */
+ public void showAt(Element indicatorElement) {
+ ToolkitOverlay errorContainer = (ToolkitOverlay) getParent();
+ if (errorContainer == null) {
+ errorContainer = new ToolkitOverlay();
+ errorContainer.setWidget(this);
+ }
+ errorContainer.setPopupPosition(DOM.getAbsoluteLeft(indicatorElement)
+ + 2
+ * DOM.getElementPropertyInt(indicatorElement, "offsetHeight"),
+ DOM.getAbsoluteTop(indicatorElement)
+ + 2
+ * DOM.getElementPropertyInt(indicatorElement,
+ "offsetHeight"));
+ errorContainer.show();
+
+ }
+
+ public void hide() {
+ final ToolkitOverlay errorContainer = (ToolkitOverlay) getParent();
+ if (errorContainer != null) {
+ errorContainer.hide();
+ }
+ }
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/Focusable.java b/src/com/itmill/toolkit/terminal/gwt/client/client/Focusable.java
new file mode 100644
index 0000000000..43d07a3ea3
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/Focusable.java
@@ -0,0 +1,16 @@
+package com.itmill.toolkit.terminal.gwt.client;
+
+/**
+ * GWT's HasFocus is way too overkill for just receiving focus in simple
+ * components. Toolkit uses this interface in addition to GWT's HasFocus to pass
+ * focus requests from server to actual ui widgets in browsers.
+ *
+ * So in to make your server side focusable component receive focus on client
+ * side it must either implement this or HasFocus interface.
+ */
+public interface Focusable {
+ /**
+ * Sets focus to this widget.
+ */
+ public void focus();
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/LocaleNotLoadedException.java b/src/com/itmill/toolkit/terminal/gwt/client/client/LocaleNotLoadedException.java
new file mode 100644
index 0000000000..39c38bdd49
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/LocaleNotLoadedException.java
@@ -0,0 +1,17 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client;
+
+public class LocaleNotLoadedException extends Exception {
+
+ /**
+ * Serial generated by Eclipse.
+ */
+ private static final long serialVersionUID = 2005227056545210838L;
+
+ public LocaleNotLoadedException(String locale) {
+ super(locale);
+ }
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/LocaleService.java b/src/com/itmill/toolkit/terminal/gwt/client/client/LocaleService.java
new file mode 100644
index 0000000000..ed5a8432c6
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/LocaleService.java
@@ -0,0 +1,197 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONBoolean;
+import com.google.gwt.json.client.JSONNumber;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONString;
+
+/**
+ * Date / time etc. localisation service for all widgets. Caches all loaded
+ * locales as JSONObjects.
+ *
+ * @author IT Mill Ltd.
+ *
+ */
+public class LocaleService {
+
+ private static Map cache = new HashMap();
+ private static String defaultLocale;
+
+ public static void addLocale(JSONObject json) {
+ final String key = ((JSONString) json.get("name")).stringValue();
+ if (cache.containsKey(key)) {
+ cache.remove(key);
+ }
+ cache.put(key, json);
+ if (cache.size() == 1) {
+ setDefaultLocale(key);
+ }
+ }
+
+ public static void setDefaultLocale(String locale) {
+ defaultLocale = locale;
+ }
+
+ public static String getDefaultLocale() {
+ return defaultLocale;
+ }
+
+ public static Set getAvailableLocales() {
+ return cache.keySet();
+ }
+
+ public static String[] getMonthNames(String locale)
+ throws LocaleNotLoadedException {
+ if (cache.containsKey(locale)) {
+ final JSONObject l = (JSONObject) cache.get(locale);
+ final JSONArray mn = (JSONArray) l.get("mn");
+ final String[] temp = new String[12];
+ temp[0] = ((JSONString) mn.get(0)).stringValue();
+ temp[1] = ((JSONString) mn.get(1)).stringValue();
+ temp[2] = ((JSONString) mn.get(2)).stringValue();
+ temp[3] = ((JSONString) mn.get(3)).stringValue();
+ temp[4] = ((JSONString) mn.get(4)).stringValue();
+ temp[5] = ((JSONString) mn.get(5)).stringValue();
+ temp[6] = ((JSONString) mn.get(6)).stringValue();
+ temp[7] = ((JSONString) mn.get(7)).stringValue();
+ temp[8] = ((JSONString) mn.get(8)).stringValue();
+ temp[9] = ((JSONString) mn.get(9)).stringValue();
+ temp[10] = ((JSONString) mn.get(10)).stringValue();
+ temp[11] = ((JSONString) mn.get(11)).stringValue();
+ return temp;
+ } else {
+ throw new LocaleNotLoadedException(locale);
+ }
+ }
+
+ public static String[] getShortMonthNames(String locale)
+ throws LocaleNotLoadedException {
+ if (cache.containsKey(locale)) {
+ final JSONObject l = (JSONObject) cache.get(locale);
+ final JSONArray smn = (JSONArray) l.get("smn");
+ final String[] temp = new String[12];
+ temp[0] = ((JSONString) smn.get(0)).stringValue();
+ temp[1] = ((JSONString) smn.get(1)).stringValue();
+ temp[2] = ((JSONString) smn.get(2)).stringValue();
+ temp[3] = ((JSONString) smn.get(3)).stringValue();
+ temp[4] = ((JSONString) smn.get(4)).stringValue();
+ temp[5] = ((JSONString) smn.get(5)).stringValue();
+ temp[6] = ((JSONString) smn.get(6)).stringValue();
+ temp[7] = ((JSONString) smn.get(7)).stringValue();
+ temp[8] = ((JSONString) smn.get(8)).stringValue();
+ temp[9] = ((JSONString) smn.get(9)).stringValue();
+ temp[10] = ((JSONString) smn.get(10)).stringValue();
+ temp[11] = ((JSONString) smn.get(11)).stringValue();
+ return temp;
+ } else {
+ throw new LocaleNotLoadedException(locale);
+ }
+ }
+
+ public static String[] getDayNames(String locale)
+ throws LocaleNotLoadedException {
+ if (cache.containsKey(locale)) {
+ final JSONObject l = (JSONObject) cache.get(locale);
+ final JSONArray dn = (JSONArray) l.get("dn");
+ final String[] temp = new String[7];
+ temp[0] = ((JSONString) dn.get(0)).stringValue();
+ temp[1] = ((JSONString) dn.get(1)).stringValue();
+ temp[2] = ((JSONString) dn.get(2)).stringValue();
+ temp[3] = ((JSONString) dn.get(3)).stringValue();
+ temp[4] = ((JSONString) dn.get(4)).stringValue();
+ temp[5] = ((JSONString) dn.get(5)).stringValue();
+ temp[6] = ((JSONString) dn.get(6)).stringValue();
+ return temp;
+ } else {
+ throw new LocaleNotLoadedException(locale);
+ }
+ }
+
+ public static String[] getShortDayNames(String locale)
+ throws LocaleNotLoadedException {
+ if (cache.containsKey(locale)) {
+ final JSONObject l = (JSONObject) cache.get(locale);
+ final JSONArray sdn = (JSONArray) l.get("sdn");
+ final String[] temp = new String[7];
+ temp[0] = ((JSONString) sdn.get(0)).stringValue();
+ temp[1] = ((JSONString) sdn.get(1)).stringValue();
+ temp[2] = ((JSONString) sdn.get(2)).stringValue();
+ temp[3] = ((JSONString) sdn.get(3)).stringValue();
+ temp[4] = ((JSONString) sdn.get(4)).stringValue();
+ temp[5] = ((JSONString) sdn.get(5)).stringValue();
+ temp[6] = ((JSONString) sdn.get(6)).stringValue();
+ return temp;
+ } else {
+ throw new LocaleNotLoadedException(locale);
+ }
+ }
+
+ public static int getFirstDayOfWeek(String locale)
+ throws LocaleNotLoadedException {
+ if (cache.containsKey(locale)) {
+ final JSONObject l = (JSONObject) cache.get(locale);
+ final JSONNumber fdow = (JSONNumber) l.get("fdow");
+ return (int) fdow.getValue();
+ } else {
+ throw new LocaleNotLoadedException(locale);
+ }
+ }
+
+ public static String getDateFormat(String locale)
+ throws LocaleNotLoadedException {
+ if (cache.containsKey(locale)) {
+ final JSONObject l = (JSONObject) cache.get(locale);
+ final JSONString df = (JSONString) l.get("df");
+ return df.stringValue();
+ } else {
+ throw new LocaleNotLoadedException(locale);
+ }
+ }
+
+ public static boolean isTwelveHourClock(String locale)
+ throws LocaleNotLoadedException {
+ if (cache.containsKey(locale)) {
+ final JSONObject l = (JSONObject) cache.get(locale);
+ final JSONBoolean thc = (JSONBoolean) l.get("thc");
+ return thc.booleanValue();
+ } else {
+ throw new LocaleNotLoadedException(locale);
+ }
+ }
+
+ public static String getClockDelimiter(String locale)
+ throws LocaleNotLoadedException {
+ if (cache.containsKey(locale)) {
+ final JSONObject l = (JSONObject) cache.get(locale);
+ final JSONString hmd = (JSONString) l.get("hmd");
+ return hmd.stringValue();
+ } else {
+ throw new LocaleNotLoadedException(locale);
+ }
+ }
+
+ public static String[] getAmPmStrings(String locale)
+ throws LocaleNotLoadedException {
+ if (cache.containsKey(locale)) {
+ final JSONObject l = (JSONObject) cache.get(locale);
+ final JSONArray ampm = (JSONArray) l.get("ampm");
+ final String[] temp = new String[2];
+ temp[0] = ((JSONString) ampm.get(0)).stringValue();
+ temp[1] = ((JSONString) ampm.get(1)).stringValue();
+ return temp;
+ } else {
+ throw new LocaleNotLoadedException(locale);
+ }
+
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/NullConsole.java b/src/com/itmill/toolkit/terminal/gwt/client/client/NullConsole.java
new file mode 100644
index 0000000000..2c158b6ab7
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/NullConsole.java
@@ -0,0 +1,26 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client;
+
+/**
+ * Client side console implementation for non-debug mode that discards all
+ * messages.
+ *
+ */
+public class NullConsole implements Console {
+
+ public void dirUIDL(UIDL u) {
+ }
+
+ public void error(String msg) {
+ }
+
+ public void log(String msg) {
+ }
+
+ public void printObject(Object msg) {
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/Paintable.java b/src/com/itmill/toolkit/terminal/gwt/client/client/Paintable.java
new file mode 100644
index 0000000000..81c024be4c
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/Paintable.java
@@ -0,0 +1,10 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client;
+
+public interface Paintable {
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client);
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/StyleConstants.java b/src/com/itmill/toolkit/terminal/gwt/client/client/StyleConstants.java
new file mode 100644
index 0000000000..b4d5499172
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/StyleConstants.java
@@ -0,0 +1,17 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client;
+
+public class StyleConstants {
+
+ public static final String MARGIN_TOP = "margin-top";
+ public static final String MARGIN_RIGHT = "margin-right";
+ public static final String MARGIN_BOTTOM = "margin-bottom";
+ public static final String MARGIN_LEFT = "margin-left";
+
+ public static final String VERTICAL_SPACING = "vspacing";
+ public static final String HORIZONTAL_SPACING = "hspacing";
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/Tooltip.java b/src/com/itmill/toolkit/terminal/gwt/client/client/Tooltip.java
new file mode 100644
index 0000000000..b10a7ff23b
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/Tooltip.java
@@ -0,0 +1,186 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+package com.itmill.toolkit.terminal.gwt.client;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.itmill.toolkit.terminal.gwt.client.ui.ToolkitOverlay;
+
+/**
+ * TODO open for extension
+ */
+public class Tooltip extends ToolkitOverlay {
+ private static final String CLASSNAME = "i-tooltip";
+ private static final int MARGIN = 4;
+ public static final int TOOLTIP_EVENTS = Event.ONKEYDOWN
+ | Event.ONMOUSEOVER | Event.ONMOUSEOUT | Event.ONMOUSEMOVE
+ | Event.ONCLICK;
+ protected static final int MAX_WIDTH = 500;
+ ErrorMessage em = new ErrorMessage();
+ Element description = DOM.createDiv();
+ private Paintable tooltipOwner;
+ private boolean closing = false;
+ private boolean opening = false;
+ private ApplicationConnection ac;
+
+ public Tooltip(ApplicationConnection client) {
+ super(false, false, true);
+ ac = client;
+ setStyleName(CLASSNAME);
+ FlowPanel layout = new FlowPanel();
+ setWidget(layout);
+ layout.add(em);
+ DOM.setElementProperty(description, "className", CLASSNAME + "-text");
+ DOM.appendChild(layout.getElement(), description);
+ }
+
+ private void show(TooltipInfo info) {
+ boolean hasContent = false;
+ if (info.getErrorUidl() != null) {
+ em.setVisible(true);
+ em.updateFromUIDL(info.getErrorUidl());
+ hasContent = true;
+ } else {
+ em.setVisible(false);
+ }
+ if (info.getTitle() != null && !"".equals(info.getTitle())) {
+ DOM.setInnerHTML(description, info.getTitle());
+ DOM.setStyleAttribute(description, "display", "");
+ hasContent = true;
+ } else {
+ DOM.setInnerHTML(description, "");
+ DOM.setStyleAttribute(description, "display", "none");
+ }
+ if (hasContent) {
+ setPopupPositionAndShow(new PositionCallback() {
+ public void setPosition(int offsetWidth, int offsetHeight) {
+
+ if (offsetWidth > MAX_WIDTH) {
+ setWidth(MAX_WIDTH + "px");
+ }
+
+ offsetWidth = getOffsetWidth();
+
+ int x = tooltipEventMouseX + 10 + Window.getScrollLeft();
+ int y = tooltipEventMouseY + 10 + Window.getScrollTop();
+
+ if (x + offsetWidth + MARGIN - Window.getScrollLeft() > Window
+ .getClientWidth()) {
+ x = Window.getClientWidth() - offsetWidth - MARGIN;
+ }
+
+ if (y + offsetHeight + MARGIN - Window.getScrollTop() > Window
+ .getClientHeight()) {
+ y = tooltipEventMouseY - 5 - offsetHeight;
+ }
+
+ setPopupPosition(x, y);
+ sinkEvents(Event.ONMOUSEOVER | Event.ONMOUSEOUT);
+ }
+ });
+ } else {
+ hide();
+ }
+ }
+
+ public void showTooltip(Paintable owner, Event event) {
+ if (closing && tooltipOwner == owner) {
+ closeTimer.cancel();
+ closing = false;
+ return;
+ }
+ updatePosition(event);
+
+ if (opening) {
+ showTimer.cancel();
+ }
+ tooltipOwner = owner;
+ showTimer.schedule(1000);
+ opening = true;
+
+ }
+
+ private Timer showTimer = new Timer() {
+ public void run() {
+ TooltipInfo info = ac.getTitleInfo(tooltipOwner);
+ show(info);
+ opening = false;
+
+ }
+ };
+
+ private Timer closeTimer = new Timer() {
+ public void run() {
+ hide();
+ closing = false;
+ tooltipOwner = null;
+ setWidth("");
+ }
+ };
+
+ public void hideTooltip() {
+ if (opening) {
+ showTimer.cancel();
+ opening = false;
+ tooltipOwner = null;
+ }
+ if (!isAttached()) {
+ return;
+ }
+ if (closing) {
+ // already about to close
+ return;
+ }
+ closeTimer.schedule(300);
+ closing = true;
+ }
+
+ private int tooltipEventMouseX;
+ private int tooltipEventMouseY;
+
+ public void updatePosition(Event event) {
+ tooltipEventMouseX = DOM.eventGetClientX(event);
+ tooltipEventMouseY = DOM.eventGetClientY(event);
+
+ }
+
+ public void handleTooltipEvent(Event event, Paintable owner) {
+ final int type = DOM.eventGetType(event);
+ if ((Tooltip.TOOLTIP_EVENTS & type) == type) {
+ if (type == Event.ONMOUSEOVER) {
+ showTooltip(owner, event);
+ } else if (type == Event.ONMOUSEMOVE) {
+ updatePosition(event);
+ } else {
+ hideTooltip();
+ }
+ } else {
+ // non-tooltip event, hide tooltip
+ hideTooltip();
+ }
+ }
+
+ public void onBrowserEvent(Event event) {
+ final int type = DOM.eventGetType(event);
+ // cancel closing event if tooltip is mouseovered; the user might want
+ // to scroll of cut&paste
+
+ switch (type) {
+ case Event.ONMOUSEOVER:
+ closeTimer.cancel();
+ closing = false;
+ break;
+ case Event.ONMOUSEOUT:
+ hideTooltip();
+ break;
+ default:
+ // NOP
+ }
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/TooltipInfo.java b/src/com/itmill/toolkit/terminal/gwt/client/client/TooltipInfo.java
new file mode 100644
index 0000000000..0ac23f3fda
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/TooltipInfo.java
@@ -0,0 +1,28 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+package com.itmill.toolkit.terminal.gwt.client;
+
+public class TooltipInfo {
+
+ private String title;
+
+ private UIDL errorUidl;
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public UIDL getErrorUidl() {
+ return errorUidl;
+ }
+
+ public void setErrorUidl(UIDL errorUidl) {
+ this.errorUidl = errorUidl;
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/UIDL.java b/src/com/itmill/toolkit/terminal/gwt/client/client/UIDL.java
new file mode 100644
index 0000000000..0b8d319e72
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/UIDL.java
@@ -0,0 +1,470 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONBoolean;
+import com.google.gwt.json.client.JSONNumber;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONString;
+import com.google.gwt.json.client.JSONValue;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.Tree;
+import com.google.gwt.user.client.ui.TreeItem;
+import com.google.gwt.user.client.ui.TreeListener;
+
+public class UIDL {
+
+ JSONArray json;
+
+ public UIDL(JSONArray json) {
+ this.json = json;
+ }
+
+ public String getId() {
+ final JSONValue val = ((JSONObject) json.get(1)).get("id");
+ if (val == null) {
+ return null;
+ }
+ return ((JSONString) val).stringValue();
+ }
+
+ public String getTag() {
+ return ((JSONString) json.get(0)).stringValue();
+ }
+
+ public String getStringAttribute(String name) {
+ final JSONValue val = ((JSONObject) json.get(1)).get(name);
+ if (val == null) {
+ return null;
+ }
+ return ((JSONString) val).stringValue();
+ }
+
+ public Set getAttributeNames() {
+ final HashSet attrs = new HashSet(((JSONObject) json.get(1)).keySet());
+ attrs.remove("v");
+ return attrs;
+ }
+
+ public int getIntAttribute(String name) {
+ final JSONValue val = ((JSONObject) json.get(1)).get(name);
+ if (val == null) {
+ return 0;
+ }
+ final double num = ((JSONNumber) val).getValue();
+ return (int) num;
+ }
+
+ public long getLongAttribute(String name) {
+ final JSONValue val = ((JSONObject) json.get(1)).get(name);
+ if (val == null) {
+ return 0;
+ }
+ final double num = ((JSONNumber) val).getValue();
+ return (long) num;
+ }
+
+ public float getFloatAttribute(String name) {
+ final JSONValue val = ((JSONObject) json.get(1)).get(name);
+ if (val == null) {
+ return 0;
+ }
+ final double num = ((JSONNumber) val).getValue();
+ return (float) num;
+ }
+
+ public double getDoubleAttribute(String name) {
+ final JSONValue val = ((JSONObject) json.get(1)).get(name);
+ if (val == null) {
+ return 0;
+ }
+ final double num = ((JSONNumber) val).getValue();
+ return num;
+ }
+
+ public boolean getBooleanAttribute(String name) {
+ final JSONValue val = ((JSONObject) json.get(1)).get(name);
+ if (val == null) {
+ return false;
+ }
+ return ((JSONBoolean) val).booleanValue();
+ }
+
+ public String[] getStringArrayAttribute(String name) {
+ final JSONArray a = (JSONArray) ((JSONObject) json.get(1)).get(name);
+ final String[] s = new String[a.size()];
+ for (int i = 0; i < a.size(); i++) {
+ s[i] = ((JSONString) a.get(i)).stringValue();
+ }
+ return s;
+ }
+
+ public int[] getIntArrayAttribute(String name) {
+ final JSONArray a = (JSONArray) ((JSONObject) json.get(1)).get(name);
+ final int[] s = new int[a.size()];
+ for (int i = 0; i < a.size(); i++) {
+ s[i] = Integer.parseInt(((JSONString) a.get(i)).stringValue());
+ }
+ return s;
+ }
+
+ public HashSet getStringArrayAttributeAsSet(String string) {
+ final JSONArray a = getArrayVariable(string);
+ final HashSet s = new HashSet();
+ for (int i = 0; i < a.size(); i++) {
+ s.add(((JSONString) a.get(i)).stringValue());
+ }
+ return s;
+ }
+
+ /**
+ * Get attributes value as string whateever the type is
+ *
+ * @param name
+ * @return string presentation of attribute
+ */
+ private String getAttribute(String name) {
+ return json.get(1).isObject().get(name).toString();
+ }
+
+ public boolean hasAttribute(String name) {
+ return ((JSONObject) json.get(1)).get(name) != null;
+ }
+
+ public UIDL getChildUIDL(int i) {
+
+ final JSONValue c = json.get(i + 2);
+ if (c == null) {
+ return null;
+ }
+ if (c.isArray() != null) {
+ return new UIDL(c.isArray());
+ }
+ throw new IllegalStateException("Child node " + i
+ + " is not of type UIDL");
+ }
+
+ public String getChildString(int i) {
+
+ final JSONValue c = json.get(i + 2);
+ if (c.isString() != null) {
+ return ((JSONString) c).stringValue();
+ }
+ throw new IllegalStateException("Child node " + i
+ + " is not of type String");
+ }
+
+ public Iterator getChildIterator() {
+
+ return new Iterator() {
+
+ int index = 2;
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object next() {
+
+ if (json.size() > index) {
+ final JSONValue c = json.get(index++);
+ if (c.isString() != null) {
+ return c.isString().stringValue();
+ } else if (c.isArray() != null) {
+ return new UIDL(c.isArray());
+ } else if (c.isObject() != null) {
+ return new XML(c.isObject());
+ } else {
+ throw new IllegalStateException("Illegal child " + c
+ + " in tag " + getTag() + " at index " + index);
+ }
+ }
+ return null;
+ }
+
+ public boolean hasNext() {
+ return json.size() > index;
+ }
+
+ };
+ }
+
+ public int getNumberOfChildren() {
+ return json.size() - 2;
+ }
+
+ public String toString() {
+ String s = "<" + getTag();
+
+ for (final Iterator i = getAttributeNames().iterator(); i.hasNext();) {
+ final String name = i.next().toString();
+ s += " " + name + "=";
+ final JSONValue v = ((JSONObject) json.get(1)).get(name);
+ if (v.isString() != null) {
+ s += v;
+ } else {
+ s += "\"" + v + "\"";
+ }
+ }
+
+ s += ">\n";
+
+ final Iterator i = getChildIterator();
+ while (i.hasNext()) {
+ final Object c = i.next();
+ s += c.toString();
+ }
+
+ s += "" + getTag() + ">\n";
+
+ return s;
+ }
+
+ public String getChildrenAsXML() {
+ String s = "";
+ final Iterator i = getChildIterator();
+ while (i.hasNext()) {
+ final Object c = i.next();
+ s += c.toString();
+ }
+ return s;
+ }
+
+ public UIDLBrowser print_r() {
+ return new UIDLBrowser();
+ }
+
+ private class UIDLBrowser extends Tree {
+ public UIDLBrowser() {
+
+ DOM.setStyleAttribute(getElement(), "position", "");
+
+ final TreeItem root = new TreeItem(getTag());
+ addItem(root);
+ root.addItem("");
+ addTreeListener(new TreeListener() {
+
+ public void onTreeItemStateChanged(TreeItem item) {
+ if (item == root) {
+ removeItem(root);
+ UIDLBrowser.this.removeTreeListener(this);
+ addItem(dir());
+ final Iterator it = treeItemIterator();
+ while (it.hasNext()) {
+ ((TreeItem) it.next()).setState(true);
+ }
+ }
+ }
+
+ public void onTreeItemSelected(TreeItem item) {
+ }
+
+ });
+
+ }
+
+ protected boolean isKeyboardNavigationEnabled(TreeItem currentItem) {
+ return false;
+ }
+
+ }
+
+ public TreeItem dir() {
+
+ String nodeName = getTag();
+ for (final Iterator i = getAttributeNames().iterator(); i.hasNext();) {
+ final String name = i.next().toString();
+ final String value = getAttribute(name);
+ nodeName += " " + name + "=" + value;
+ }
+ final TreeItem item = new TreeItem(nodeName);
+
+ try {
+ TreeItem tmp = null;
+ for (final Iterator i = getVariableHash().keySet().iterator(); i
+ .hasNext();) {
+ final String name = i.next().toString();
+ String value = "";
+ try {
+ value = getStringVariable(name);
+ } catch (final Exception e) {
+ try {
+ final JSONArray a = getArrayVariable(name);
+ value = a.toString();
+ } catch (final Exception e2) {
+ try {
+ final int intVal = getIntVariable(name);
+ value = String.valueOf(intVal);
+ } catch (final Exception e3) {
+ value = "unknown";
+ }
+ }
+ }
+ if (tmp == null) {
+ tmp = new TreeItem("variables");
+ }
+ tmp.addItem(name + "=" + value);
+ }
+ if (tmp != null) {
+ item.addItem(tmp);
+ }
+ } catch (final Exception e) {
+ // Ingonered, no variables
+ }
+
+ final Iterator i = getChildIterator();
+ while (i.hasNext()) {
+ final Object child = i.next();
+ try {
+ final UIDL c = (UIDL) child;
+ item.addItem(c.dir());
+
+ } catch (final Exception e) {
+ item.addItem(child.toString());
+ }
+ }
+ return item;
+ }
+
+ private JSONObject getVariableHash() {
+ final JSONObject v = (JSONObject) ((JSONObject) json.get(1)).get("v");
+ if (v == null) {
+ throw new IllegalArgumentException("No variables defined in tag.");
+ }
+ return v;
+ }
+
+ public boolean hasVariable(String name) {
+ Object v = null;
+ try {
+ v = getVariableHash().get(name);
+ } catch (final IllegalArgumentException e) {
+ }
+ return v != null;
+ }
+
+ public String getStringVariable(String name) {
+ final JSONString t = (JSONString) getVariableHash().get(name);
+ if (t == null) {
+ throw new IllegalArgumentException("No such variable: " + name);
+ }
+ return t.stringValue();
+ }
+
+ public int getIntVariable(String name) {
+ final JSONNumber t = (JSONNumber) getVariableHash().get(name);
+ if (t == null) {
+ throw new IllegalArgumentException("No such variable: " + name);
+ }
+ return (int) t.getValue();
+ }
+
+ public long getLongVariable(String name) {
+ final JSONNumber t = (JSONNumber) getVariableHash().get(name);
+ if (t == null) {
+ throw new IllegalArgumentException("No such variable: " + name);
+ }
+ return (long) t.getValue();
+ }
+
+ public float getFloatVariable(String name) {
+ final JSONNumber t = (JSONNumber) getVariableHash().get(name);
+ if (t == null) {
+ throw new IllegalArgumentException("No such variable: " + name);
+ }
+ return (float) t.getValue();
+ }
+
+ public double getDoubleVariable(String name) {
+ final JSONNumber t = (JSONNumber) getVariableHash().get(name);
+ if (t == null) {
+ throw new IllegalArgumentException("No such variable: " + name);
+ }
+ return t.getValue();
+ }
+
+ public boolean getBooleanVariable(String name) {
+ final JSONBoolean t = (JSONBoolean) getVariableHash().get(name);
+ if (t == null) {
+ throw new IllegalArgumentException("No such variable: " + name);
+ }
+ return t.booleanValue();
+ }
+
+ private JSONArray getArrayVariable(String name) {
+ final JSONArray t = (JSONArray) getVariableHash().get(name);
+ if (t == null) {
+ throw new IllegalArgumentException("No such variable: " + name);
+ }
+ return t;
+ }
+
+ public String[] getStringArrayVariable(String name) {
+ final JSONArray a = getArrayVariable(name);
+ final String[] s = new String[a.size()];
+ for (int i = 0; i < a.size(); i++) {
+ s[i] = ((JSONString) a.get(i)).stringValue();
+ }
+ return s;
+ }
+
+ public Set getStringArrayVariableAsSet(String name) {
+ final JSONArray a = getArrayVariable(name);
+ final HashSet s = new HashSet();
+ for (int i = 0; i < a.size(); i++) {
+ s.add(((JSONString) a.get(i)).stringValue());
+ }
+ return s;
+ }
+
+ public int[] getIntArrayVariable(String name) {
+ final JSONArray a = getArrayVariable(name);
+ final int[] s = new int[a.size()];
+ for (int i = 0; i < a.size(); i++) {
+ final JSONValue v = a.get(i);
+ s[i] = v.isNumber() != null ? (int) ((JSONNumber) v).getValue()
+ : Integer.parseInt(v.toString());
+ }
+ return s;
+ }
+
+ public class XML {
+ JSONObject x;
+
+ private XML(JSONObject x) {
+ this.x = x;
+ }
+
+ public String getXMLAsString() {
+ final StringBuffer sb = new StringBuffer();
+ for (final Iterator it = x.keySet().iterator(); it.hasNext();) {
+ final String tag = (String) it.next();
+ sb.append("<");
+ sb.append(tag);
+ sb.append(">");
+ sb.append(x.get(tag).isString().stringValue());
+ sb.append("");
+ sb.append(tag);
+ sb.append(">");
+ }
+ return sb.toString();
+ }
+ }
+
+ public int getChildCount() {
+ return json.size() - 2;
+ }
+
+ public UIDL getErrors() {
+ final JSONArray a = (JSONArray) ((JSONObject) json.get(1)).get("error");
+ return new UIDL(a);
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/Util.java b/src/com/itmill/toolkit/terminal/gwt/client/client/Util.java
new file mode 100644
index 0000000000..5ecc407e66
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/Util.java
@@ -0,0 +1,164 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client;
+
+import java.util.Iterator;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.HasWidgets;
+import com.google.gwt.user.client.ui.Widget;
+
+public class Util {
+
+ /**
+ * Helper method for debugging purposes.
+ *
+ * Stops execution on firefox browsers on a breakpoint.
+ *
+ */
+ public static native void browserDebugger()
+ /*-{
+ if(window.console)
+ debugger;
+ }-*/;
+
+ /**
+ * Nulls oncontextmenu function on given element. We need to manually clear
+ * context menu events due bad browsers memory leaks, since GWT don't
+ * support them.
+ *
+ * @param el
+ */
+ public native static void removeContextMenuEvent(Element el)
+ /*-{
+ el.oncontextmenu = null;
+ }-*/;
+
+ /**
+ * Traverses recursively ancestors until ContainerResizedListener child
+ * widget is found. They will delegate it futher if needed.
+ *
+ * @param container
+ */
+ public static void runDescendentsLayout(HasWidgets container) {
+ final Iterator childWidgets = container.iterator();
+ while (childWidgets.hasNext()) {
+ final Widget child = (Widget) childWidgets.next();
+ if (child instanceof ContainerResizedListener) {
+ ((ContainerResizedListener) child).iLayout();
+ } else if (child instanceof HasWidgets) {
+ final HasWidgets childContainer = (HasWidgets) child;
+ runDescendentsLayout(childContainer);
+ }
+ }
+ }
+
+ /**
+ * Returns closest parent Widget in hierarchy that implements Container
+ * interface
+ *
+ * @param component
+ * @return closest parent Container
+ */
+ public static Container getParentLayout(Widget component) {
+ Widget parent = component.getParent();
+ while (parent != null && !(parent instanceof Container)) {
+ parent = parent.getParent();
+ }
+ if (parent != null && ((Container) parent).hasChildComponent(component)) {
+ return (Container) parent;
+ }
+ return null;
+ }
+
+ /**
+ * Detects if current browser is IE.
+ *
+ * @deprecated use BrowserInfo class instead
+ *
+ * @return true if IE
+ */
+ public static boolean isIE() {
+ return BrowserInfo.get().isIE();
+ }
+
+ /**
+ * Detects if current browser is IE6.
+ *
+ * @deprecated use BrowserInfo class instead
+ *
+ * @return true if IE6
+ */
+ public static boolean isIE6() {
+ return BrowserInfo.get().isIE6();
+ }
+
+ /**
+ * @deprecated use BrowserInfo class instead
+ * @return
+ */
+ public static boolean isIE7() {
+ return BrowserInfo.get().isIE7();
+ }
+
+ /**
+ * @deprecated use BrowserInfo class instead
+ * @return
+ */
+ public static boolean isFF2() {
+ return BrowserInfo.get().isFF2();
+ }
+
+ private static final Element escapeHtmlHelper = DOM.createDiv();
+
+ /**
+ * Converts html entities to text.
+ *
+ * @param html
+ * @return escaped string presentation of given html
+ */
+ public static String escapeHTML(String html) {
+ DOM.setInnerText(escapeHtmlHelper, html);
+ return DOM.getInnerHTML(escapeHtmlHelper);
+ }
+
+ /**
+ * Adds transparent PNG fix to image element; only use for IE6.
+ *
+ * @param el
+ * IMG element
+ * @param blankImageUrl
+ * URL to transparent one-pixel gif
+ */
+ public native static void addPngFix(Element el, String blankImageUrl)
+ /*-{
+ el.attachEvent("onload", function() {
+ var src = el.src;
+ if (src.indexOf(".png")<1) return;
+ var w = el.width||16;
+ var h = el.height||16;
+ el.src =blankImageUrl;
+ el.style.height = h+"px";
+ el.style.width = w+"px";
+ el.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+src+"', sizingMethod='crop');";
+ },false);
+ }-*/;
+
+ /**
+ * Clones given element as in JavaScript.
+ *
+ * Deprecate this if there appears similar method into GWT someday.
+ *
+ * @param element
+ * @param deep
+ * clone child tree also
+ * @return
+ */
+ public static native Element cloneNode(Element element, boolean deep)
+ /*-{
+ return element.cloneNode(deep);
+ }-*/;
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/WidgetSet.java b/src/com/itmill/toolkit/terminal/gwt/client/client/WidgetSet.java
new file mode 100644
index 0000000000..e55da2c33d
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/WidgetSet.java
@@ -0,0 +1,33 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client;
+
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.user.client.ui.Widget;
+
+public interface WidgetSet extends EntryPoint {
+
+ /**
+ * Create an uninitialized component that best matches given UIDL.
+ *
+ * @param uidl
+ * UIDL to be painted with returned component.
+ * @return New uninitialized and unregistered component that can paint given
+ * UIDL.
+ */
+ public Widget createWidget(UIDL uidl);
+
+ /**
+ * Test if the given component implementation conforms to UIDL.
+ *
+ * @param currentWidget
+ * Current implementation of the component
+ * @param uidl
+ * UIDL to test against
+ * @return true iff createWidget would return a new component of the same
+ * class than currentWidget
+ */
+ public boolean isCorrectImplementation(Widget currentWidget, UIDL uidl);
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/ui/Action.java b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/Action.java
new file mode 100644
index 0000000000..0f059870e3
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/Action.java
@@ -0,0 +1,55 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+import com.google.gwt.user.client.Command;
+
+/**
+ *
+ */
+public abstract class Action implements Command {
+
+ protected ActionOwner owner;
+
+ protected String iconUrl = null;
+
+ protected String caption = "";
+
+ public Action(ActionOwner owner) {
+ this.owner = owner;
+ }
+
+ /**
+ * Executed when action fired
+ */
+ public abstract void execute();
+
+ public String getHTML() {
+ final StringBuffer sb = new StringBuffer();
+ sb.append("");
+ if (getIconUrl() != null) {
+ sb.append("
");
+ }
+ sb.append(getCaption());
+ sb.append("
");
+ return sb.toString();
+ }
+
+ public String getCaption() {
+ return caption;
+ }
+
+ public void setCaption(String caption) {
+ this.caption = caption;
+ }
+
+ public String getIconUrl() {
+ return iconUrl;
+ }
+
+ public void setIconUrl(String url) {
+ iconUrl = url;
+ }
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/ui/ActionOwner.java b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/ActionOwner.java
new file mode 100644
index 0000000000..647a1cfe89
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/ActionOwner.java
@@ -0,0 +1,16 @@
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
+
+public interface ActionOwner {
+
+ /**
+ * @return Array of IActions
+ */
+ public Action[] getActions();
+
+ public ApplicationConnection getClient();
+
+ public String getPaintableId();
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/ui/AlignmentInfo.java b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/AlignmentInfo.java
new file mode 100644
index 0000000000..68024d849a
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/AlignmentInfo.java
@@ -0,0 +1,76 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+public class AlignmentInfo {
+
+ public static final int ALIGNMENT_LEFT = 1;
+ public static final int ALIGNMENT_RIGHT = 2;
+ public static final int ALIGNMENT_TOP = 4;
+ public static final int ALIGNMENT_BOTTOM = 8;
+ public static final int ALIGNMENT_HORIZONTAL_CENTER = 16;
+ public static final int ALIGNMENT_VERTICAL_CENTER = 32;
+
+ private int bitMask;
+
+ public AlignmentInfo(int bitMask) {
+ this.bitMask = bitMask;
+ }
+
+ public AlignmentInfo(int horizontal, int vertical) {
+ setAlignment(horizontal, vertical);
+ }
+
+ public void setAlignment(int horiz, int vert) {
+ bitMask = horiz + vert;
+ }
+
+ public int getBitMask() {
+ return bitMask;
+ }
+
+ public boolean isTop() {
+ return (bitMask & ALIGNMENT_TOP) == ALIGNMENT_TOP;
+ }
+
+ public boolean isBottom() {
+ return (bitMask & ALIGNMENT_BOTTOM) == ALIGNMENT_BOTTOM;
+ }
+
+ public boolean isLeft() {
+ return (bitMask & ALIGNMENT_LEFT) == ALIGNMENT_LEFT;
+ }
+
+ public boolean isRight() {
+ return (bitMask & ALIGNMENT_RIGHT) == ALIGNMENT_RIGHT;
+ }
+
+ public boolean isVerticalCenter() {
+ return (bitMask & ALIGNMENT_VERTICAL_CENTER) == ALIGNMENT_VERTICAL_CENTER;
+ }
+
+ public boolean isHorizontalCenter() {
+ return (bitMask & ALIGNMENT_HORIZONTAL_CENTER) == ALIGNMENT_HORIZONTAL_CENTER;
+ }
+
+ public String getVerticalAlignment() {
+ if (isBottom()) {
+ return "bottom";
+ } else if (isVerticalCenter()) {
+ return "middle";
+ }
+ return "top";
+ }
+
+ public String getHorizontalAlignment() {
+ if (isRight()) {
+ return "right";
+ } else if (isHorizontalCenter()) {
+ return "center";
+ }
+ return "left";
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/ui/CalendarEntry.java b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/CalendarEntry.java
new file mode 100644
index 0000000000..551c458ed6
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/CalendarEntry.java
@@ -0,0 +1,126 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+import java.util.Date;
+
+import com.itmill.toolkit.terminal.gwt.client.DateTimeService;
+
+public class CalendarEntry {
+ private final String styleName;
+ private Date start;
+ private Date end;
+ private String title;
+ private String description;
+ private boolean notime;
+
+ public CalendarEntry(String styleName, Date start, Date end, String title,
+ String description, boolean notime) {
+ this.styleName = styleName;
+ if (notime) {
+ Date d = new Date(start.getTime());
+ d.setSeconds(0);
+ d.setMinutes(0);
+ this.start = d;
+ if (end != null) {
+ d = new Date(end.getTime());
+ d.setSeconds(0);
+ d.setMinutes(0);
+ this.end = d;
+ } else {
+ end = start;
+ }
+ } else {
+ this.start = start;
+ this.end = end;
+ }
+ this.title = title;
+ this.description = description;
+ this.notime = notime;
+ }
+
+ public CalendarEntry(String styleName, Date start, Date end, String title,
+ String description) {
+ this(styleName, start, end, title, description, false);
+ }
+
+ public String getStyleName() {
+ return styleName;
+ }
+
+ public Date getStart() {
+ return start;
+ }
+
+ public void setStart(Date start) {
+ this.start = start;
+ }
+
+ public Date getEnd() {
+ return end;
+ }
+
+ public void setEnd(Date end) {
+ this.end = end;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public boolean isNotime() {
+ return notime;
+ }
+
+ public void setNotime(boolean notime) {
+ this.notime = notime;
+ }
+
+ public String getStringForDate(Date d) {
+ // TODO format from DateTimeService
+ String s = "";
+ if (!notime) {
+ if (!DateTimeService.isSameDay(d, start)) {
+ s += (start.getYear() + 1900) + "." + (start.getMonth() + 1)
+ + "." + start.getDate() + " ";
+ }
+ int i = start.getHours();
+ s += (i < 10 ? "0" : "") + i;
+ s += ":";
+ i = start.getMinutes();
+ s += (i < 10 ? "0" : "") + i;
+ if (!start.equals(end)) {
+ s += " - ";
+ if (!DateTimeService.isSameDay(start, end)) {
+ s += (end.getYear() + 1900) + "." + (end.getMonth() + 1)
+ + "." + end.getDate() + " ";
+ }
+ i = end.getHours();
+ s += (i < 10 ? "0" : "") + i;
+ s += ":";
+ i = end.getMinutes();
+ s += (i < 10 ? "0" : "") + i;
+ }
+ s += " ";
+ }
+ if (title != null) {
+ s += title;
+ }
+ return s;
+ }
+
+}
\ No newline at end of file
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/ui/CalendarPanel.java b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/CalendarPanel.java
new file mode 100644
index 0000000000..f5ecf338d0
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/CalendarPanel.java
@@ -0,0 +1,491 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.MouseListener;
+import com.google.gwt.user.client.ui.MouseListenerCollection;
+import com.google.gwt.user.client.ui.SourcesMouseEvents;
+import com.google.gwt.user.client.ui.SourcesTableEvents;
+import com.google.gwt.user.client.ui.TableListener;
+import com.google.gwt.user.client.ui.Widget;
+import com.itmill.toolkit.terminal.gwt.client.DateTimeService;
+import com.itmill.toolkit.terminal.gwt.client.LocaleService;
+
+public class CalendarPanel extends FlexTable implements MouseListener,
+ ClickListener {
+
+ private final IDateField datefield;
+
+ private IEventButton prevYear;
+
+ private IEventButton nextYear;
+
+ private IEventButton prevMonth;
+
+ private IEventButton nextMonth;
+
+ private Time time;
+
+ private Date minDate = null;
+
+ private Date maxDate = null;
+
+ private CalendarEntrySource entrySource;
+
+ /* Needed to identify resolution changes */
+ private int resolution = IDateField.RESOLUTION_YEAR;
+
+ /* Needed to identify locale changes */
+ private String locale = LocaleService.getDefaultLocale();
+
+ public CalendarPanel(IDateField parent) {
+ datefield = parent;
+ setStyleName(IDateField.CLASSNAME + "-calendarpanel");
+ // buildCalendar(true);
+ addTableListener(new DateClickListener(this));
+ }
+
+ public CalendarPanel(IDateField parent, Date min, Date max) {
+ datefield = parent;
+ setStyleName(IDateField.CLASSNAME + "-calendarpanel");
+ // buildCalendar(true);
+ addTableListener(new DateClickListener(this));
+
+ }
+
+ private void buildCalendar(boolean forceRedraw) {
+ final boolean needsMonth = datefield.getCurrentResolution() > IDateField.RESOLUTION_YEAR;
+ boolean needsBody = datefield.getCurrentResolution() >= IDateField.RESOLUTION_DAY;
+ final boolean needsTime = datefield.getCurrentResolution() >= IDateField.RESOLUTION_HOUR;
+ buildCalendarHeader(forceRedraw, needsMonth);
+ clearCalendarBody(!needsBody);
+ if (needsBody) {
+ buildCalendarBody();
+ }
+ if (needsTime) {
+ buildTime(forceRedraw);
+ } else if (time != null) {
+ remove(time);
+ time = null;
+ }
+ }
+
+ private void clearCalendarBody(boolean remove) {
+ if (!remove) {
+ for (int row = 2; row < 8; row++) {
+ for (int col = 0; col < 7; col++) {
+ setHTML(row, col, " ");
+ }
+ }
+ } else if (getRowCount() > 2) {
+ while (getRowCount() > 2) {
+ removeRow(2);
+ }
+ }
+ }
+
+ private void buildCalendarHeader(boolean forceRedraw, boolean needsMonth) {
+ if (forceRedraw) {
+ if (prevMonth == null) { // Only do once
+ prevYear = new IEventButton();
+ prevYear.setHTML("«");
+ prevYear.setStyleName("i-button-prevyear");
+ nextYear = new IEventButton();
+ nextYear.setHTML("»");
+ nextYear.setStyleName("i-button-nextyear");
+ prevYear.addMouseListener(this);
+ nextYear.addMouseListener(this);
+ prevYear.addClickListener(this);
+ nextYear.addClickListener(this);
+ setWidget(0, 0, prevYear);
+ setWidget(0, 4, nextYear);
+
+ if (needsMonth) {
+ prevMonth = new IEventButton();
+ prevMonth.setHTML("‹");
+ prevMonth.setStyleName("i-button-prevmonth");
+ nextMonth = new IEventButton();
+ nextMonth.setHTML("›");
+ nextMonth.setStyleName("i-button-nextmonth");
+ prevMonth.addMouseListener(this);
+ nextMonth.addMouseListener(this);
+ prevMonth.addClickListener(this);
+ nextMonth.addClickListener(this);
+ setWidget(0, 3, nextMonth);
+ setWidget(0, 1, prevMonth);
+ }
+
+ getFlexCellFormatter().setColSpan(0, 2, 3);
+ getRowFormatter().addStyleName(0,
+ IDateField.CLASSNAME + "-calendarpanel-header");
+ } else if (!needsMonth) {
+ // Remove month traverse buttons
+ prevMonth.removeClickListener(this);
+ prevMonth.removeMouseListener(this);
+ nextMonth.removeClickListener(this);
+ nextMonth.removeMouseListener(this);
+ remove(prevMonth);
+ remove(nextMonth);
+ prevMonth = null;
+ nextMonth = null;
+ }
+
+ // Print weekday names
+ final int firstDay = datefield.getDateTimeService()
+ .getFirstDayOfWeek();
+ for (int i = 0; i < 7; i++) {
+ int day = i + firstDay;
+ if (day > 6) {
+ day = 0;
+ }
+ if (datefield.getCurrentResolution() > IDateField.RESOLUTION_MONTH) {
+ setHTML(1, i, ""
+ + datefield.getDateTimeService().getShortDay(day)
+ + "");
+ } else {
+ setHTML(1, i, "");
+ }
+ }
+ }
+
+ final String monthName = needsMonth ? datefield.getDateTimeService()
+ .getMonth(datefield.getShowingDate().getMonth()) : "";
+ final int year = datefield.getShowingDate().getYear() + 1900;
+ setHTML(0, 2, "" + monthName + " " + year
+ + "");
+ }
+
+ private void buildCalendarBody() {
+ // date actually selected?
+ Date currentDate = datefield.getCurrentDate();
+ Date showing = datefield.getShowingDate();
+ boolean selected = (currentDate != null
+ && currentDate.getMonth() == showing.getMonth() && currentDate
+ .getYear() == showing.getYear());
+
+ final int startWeekDay = datefield.getDateTimeService()
+ .getStartWeekDay(datefield.getShowingDate());
+ final int numDays = DateTimeService.getNumberOfDaysInMonth(datefield
+ .getShowingDate());
+ int dayCount = 0;
+ final Date today = new Date();
+ final Date curr = new Date(datefield.getShowingDate().getTime());
+ for (int row = 2; row < 8; row++) {
+ for (int col = 0; col < 7; col++) {
+ if (!(row == 2 && col < startWeekDay)) {
+ if (dayCount < numDays) {
+ final int selectedDate = ++dayCount;
+ String title = "";
+ if (entrySource != null) {
+ curr.setDate(dayCount);
+ final List entries = entrySource.getEntries(curr,
+ IDateField.RESOLUTION_DAY);
+ if (entries != null) {
+ for (final Iterator it = entries.iterator(); it
+ .hasNext();) {
+ final CalendarEntry entry = (CalendarEntry) it
+ .next();
+ title += (title.length() > 0 ? ", " : "")
+ + entry.getStringForDate(curr);
+ }
+ }
+ }
+ final String baseclass = IDateField.CLASSNAME
+ + "-calendarpanel-day";
+ String cssClass = baseclass;
+ if (!isEnabledDate(curr)) {
+ cssClass += " " + baseclass + "-disabled";
+ }
+ if (selected
+ && datefield.getShowingDate().getDate() == dayCount) {
+ cssClass += " " + baseclass + "-selected";
+ }
+ if (today.getDate() == dayCount
+ && today.getMonth() == datefield
+ .getShowingDate().getMonth()
+ && today.getYear() == datefield
+ .getShowingDate().getYear()) {
+ cssClass += " " + baseclass + "-today";
+ }
+ if (title.length() > 0) {
+ cssClass += " " + baseclass + "-entry";
+ }
+ setHTML(row, col, ""
+ + selectedDate + "");
+ } else {
+ break;
+ }
+
+ }
+ }
+ }
+ }
+
+ private void buildTime(boolean forceRedraw) {
+ if (time == null) {
+ time = new Time(datefield);
+ setText(8, 0, ""); // Add new row
+ getFlexCellFormatter().setColSpan(8, 0, 7);
+ setWidget(8, 0, time);
+ }
+ time.updateTime(forceRedraw);
+ }
+
+ /**
+ *
+ * @param forceRedraw
+ * Build all from scratch, in case of e.g. locale changes
+ */
+ public void updateCalendar() {
+ // Locale and resolution changes force a complete redraw
+ buildCalendar(locale != datefield.getCurrentLocale()
+ || resolution != datefield.getCurrentResolution());
+ if (datefield instanceof ITextualDate) {
+ ((ITextualDate) datefield).buildDate();
+ }
+ locale = datefield.getCurrentLocale();
+ resolution = datefield.getCurrentResolution();
+ }
+
+ public void onClick(Widget sender) {
+ // processClickEvent(sender, true);
+ }
+
+ private boolean isEnabledDate(Date date) {
+ if ((minDate != null && date.before(minDate))
+ || (maxDate != null && date.after(maxDate))) {
+ return false;
+ }
+ return true;
+ }
+
+ private void processClickEvent(Widget sender, boolean updateVariable) {
+ if (!datefield.isEnabled() || datefield.isReadonly()) {
+ return;
+ }
+ Date showingDate = datefield.getShowingDate();
+ if (!updateVariable) {
+ if (sender == prevYear) {
+ showingDate.setYear(showingDate.getYear() - 1);
+ updateCalendar();
+ } else if (sender == nextYear) {
+ showingDate.setYear(showingDate.getYear() + 1);
+ updateCalendar();
+ } else if (sender == prevMonth) {
+ showingDate.setMonth(showingDate.getMonth() - 1);
+ updateCalendar();
+ } else if (sender == nextMonth) {
+ showingDate.setMonth(showingDate.getMonth() + 1);
+ updateCalendar();
+ }
+ } else {
+ if (datefield.getCurrentResolution() == IDateField.RESOLUTION_YEAR
+ || datefield.getCurrentResolution() == IDateField.RESOLUTION_MONTH) {
+ // Due to current UI, update variable if res=year/month
+ datefield.setCurrentDate(new Date(showingDate.getTime()));
+ if (datefield.getCurrentResolution() == IDateField.RESOLUTION_MONTH) {
+ datefield.getClient().updateVariable(datefield.getId(),
+ "month", datefield.getCurrentDate().getMonth() + 1,
+ false);
+ }
+ datefield.getClient().updateVariable(datefield.getId(), "year",
+ datefield.getCurrentDate().getYear() + 1900,
+ datefield.isImmediate());
+ }
+ }
+ }
+
+ private Timer timer;
+
+ public void onMouseDown(final Widget sender, int x, int y) {
+ if (sender instanceof IEventButton) {
+ processClickEvent(sender, false);
+ timer = new Timer() {
+ public void run() {
+ processClickEvent(sender, false);
+ }
+ };
+ timer.scheduleRepeating(100);
+ }
+ }
+
+ public void onMouseEnter(Widget sender) {
+ }
+
+ public void onMouseLeave(Widget sender) {
+ if (timer != null) {
+ timer.cancel();
+ }
+ }
+
+ public void onMouseMove(Widget sender, int x, int y) {
+ }
+
+ public void onMouseUp(Widget sender, int x, int y) {
+ if (timer != null) {
+ timer.cancel();
+ }
+ processClickEvent(sender, true);
+ }
+
+ private class IEventButton extends IButton implements SourcesMouseEvents {
+
+ private MouseListenerCollection mouseListeners;
+
+ public IEventButton() {
+ super();
+ sinkEvents(Event.FOCUSEVENTS | Event.KEYEVENTS | Event.ONCLICK
+ | Event.MOUSEEVENTS);
+ }
+
+ public void addMouseListener(MouseListener listener) {
+ if (mouseListeners == null) {
+ mouseListeners = new MouseListenerCollection();
+ }
+ mouseListeners.add(listener);
+ }
+
+ public void removeMouseListener(MouseListener listener) {
+ if (mouseListeners != null) {
+ mouseListeners.remove(listener);
+ }
+ }
+
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+ switch (DOM.eventGetType(event)) {
+ case Event.ONMOUSEDOWN:
+ case Event.ONMOUSEUP:
+ case Event.ONMOUSEMOVE:
+ case Event.ONMOUSEOVER:
+ case Event.ONMOUSEOUT:
+ if (mouseListeners != null) {
+ mouseListeners.fireMouseEvent(this, event);
+ }
+ break;
+ }
+ }
+ }
+
+ private class DateClickListener implements TableListener {
+
+ private final CalendarPanel cal;
+
+ public DateClickListener(CalendarPanel panel) {
+ cal = panel;
+ }
+
+ public void onCellClicked(SourcesTableEvents sender, int row, int col) {
+ if (sender != cal || row < 2 || row > 7
+ || !cal.datefield.isEnabled() || cal.datefield.isReadonly()) {
+ return;
+ }
+
+ final String text = cal.getText(row, col);
+ if (text.equals(" ")) {
+ return;
+ }
+
+ try {
+ final Integer day = new Integer(text);
+ final Date newDate = cal.datefield.getShowingDate();
+ newDate.setDate(day.intValue());
+ if (!isEnabledDate(newDate)) {
+ return;
+ }
+ if (cal.datefield.getCurrentDate() == null) {
+ cal.datefield.setCurrentDate(new Date(newDate.getTime()));
+
+ // Init variables with current time
+ datefield.getClient().updateVariable(cal.datefield.getId(),
+ "hour", newDate.getHours(), false);
+ datefield.getClient().updateVariable(cal.datefield.getId(),
+ "min", newDate.getMinutes(), false);
+ datefield.getClient().updateVariable(cal.datefield.getId(),
+ "sec", newDate.getSeconds(), false);
+ datefield.getClient().updateVariable(cal.datefield.getId(),
+ "msec", datefield.getMilliseconds(), false);
+ }
+
+ cal.datefield.getCurrentDate().setTime(newDate.getTime());
+ cal.datefield.getClient().updateVariable(cal.datefield.getId(),
+ "day", cal.datefield.getCurrentDate().getDate(), false);
+ cal.datefield.getClient().updateVariable(cal.datefield.getId(),
+ "month", cal.datefield.getCurrentDate().getMonth() + 1,
+ false);
+ cal.datefield.getClient().updateVariable(cal.datefield.getId(),
+ "year",
+ cal.datefield.getCurrentDate().getYear() + 1900,
+ cal.datefield.isImmediate());
+
+ if (datefield instanceof ITextualDate
+ && resolution < IDateField.RESOLUTION_HOUR) {
+ ((ToolkitOverlay) getParent()).hide();
+ } else {
+ updateCalendar();
+ }
+
+ } catch (final NumberFormatException e) {
+ // Not a number, ignore and stop here
+ return;
+ }
+ }
+
+ }
+
+ public void setLimits(Date min, Date max) {
+ if (min != null) {
+ final Date d = new Date(min.getTime());
+ d.setHours(0);
+ d.setMinutes(0);
+ d.setSeconds(1);
+ minDate = d;
+ } else {
+ minDate = null;
+ }
+ if (max != null) {
+ final Date d = new Date(max.getTime());
+ d.setHours(24);
+ d.setMinutes(59);
+ d.setSeconds(59);
+ maxDate = d;
+ } else {
+ maxDate = null;
+ }
+ }
+
+ public void setCalendarEntrySource(CalendarEntrySource entrySource) {
+ this.entrySource = entrySource;
+ }
+
+ public CalendarEntrySource getCalendarEntrySource() {
+ return entrySource;
+ }
+
+ public interface CalendarEntrySource {
+ public List getEntries(Date date, int resolution);
+ }
+
+ /**
+ * Sets focus to Calendar panel.
+ *
+ * @param focus
+ */
+ public void setFocus(boolean focus) {
+ nextYear.setFocus(focus);
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/ui/ContextMenu.java b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/ContextMenu.java
new file mode 100644
index 0000000000..b97dafee5b
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/ContextMenu.java
@@ -0,0 +1,117 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.MenuBar;
+import com.google.gwt.user.client.ui.MenuItem;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+public class ContextMenu extends ToolkitOverlay {
+
+ private ActionOwner actionOwner;
+
+ private final CMenuBar menu = new CMenuBar();
+
+ private int left;
+
+ private int top;
+
+ /**
+ * This method should be used only by Client object as only one per client
+ * should exists. Request an instance via client.getContextMenu();
+ *
+ * @param cli
+ * to be set as an owner of menu
+ */
+ public ContextMenu() {
+ super(true, false, true);
+ setWidget(menu);
+ setStyleName("i-contextmenu");
+ }
+
+ /**
+ * Sets the element from which to build menu
+ *
+ * @param ao
+ */
+ public void setActionOwner(ActionOwner ao) {
+ actionOwner = ao;
+ }
+
+ /**
+ * Shows context menu at given location.
+ *
+ * @param left
+ * @param top
+ */
+ public void showAt(int left, int top) {
+ this.left = left;
+ this.top = top;
+ menu.clearItems();
+ final Action[] actions = actionOwner.getActions();
+ for (int i = 0; i < actions.length; i++) {
+ final Action a = actions[i];
+ menu.addItem(new MenuItem(a.getHTML(), true, a));
+ }
+
+ setPopupPositionAndShow(new PositionCallback() {
+ public void setPosition(int offsetWidth, int offsetHeight) {
+ // mac FF gets bad width due GWT popups overflow hacks,
+ // re-determine width
+ offsetWidth = menu.getOffsetWidth();
+ int left = ContextMenu.this.left;
+ int top = ContextMenu.this.top;
+ if (offsetWidth + left > Window.getClientWidth()) {
+ left = left - offsetWidth;
+ if (left < 0) {
+ left = 0;
+ }
+ }
+ if (offsetHeight + top > Window.getClientHeight()) {
+ top = top - offsetHeight;
+ if (top < 0) {
+ top = 0;
+ }
+ }
+ setPopupPosition(left, top);
+ }
+ });
+ }
+
+ public void showAt(ActionOwner ao, int left, int top) {
+ setActionOwner(ao);
+ showAt(left, top);
+ }
+
+ /**
+ * Extend standard Gwt MenuBar to set proper settings and to override
+ * onPopupClosed method so that PopupPanel gets closed.
+ */
+ class CMenuBar extends MenuBar {
+ public CMenuBar() {
+ super(true);
+ }
+
+ public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
+ super.onPopupClosed(sender, autoClosed);
+ ContextMenu.this.hide();
+ }
+
+ /*public void onBrowserEvent(Event event) {
+ // Remove current selection when mouse leaves
+ if (DOM.eventGetType(event) == Event.ONMOUSEOUT) {
+ Element to = DOM.eventGetToElement(event);
+ if (!DOM.isOrHasChild(getElement(), to)) {
+ DOM.setElementProperty(
+ super.getSelectedItem().getElement(), "className",
+ super.getSelectedItem().getStylePrimaryName());
+ }
+ }
+
+ super.onBrowserEvent(event);
+ }*/
+ }
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/ui/Field.java b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/Field.java
new file mode 100644
index 0000000000..d0e1d0b666
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/Field.java
@@ -0,0 +1,13 @@
+/**
+ *
+ */
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+/**
+ * This interface indicates that the component is a Field (serverside), and
+ * wants (for instance) to automatically get the i-modified classname.
+ *
+ */
+public interface Field {
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/ui/IAccordion.java b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/IAccordion.java
new file mode 100644
index 0000000000..bd591bd229
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/IAccordion.java
@@ -0,0 +1,267 @@
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.ComplexPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
+import com.itmill.toolkit.terminal.gwt.client.Caption;
+import com.itmill.toolkit.terminal.gwt.client.ContainerResizedListener;
+import com.itmill.toolkit.terminal.gwt.client.Paintable;
+import com.itmill.toolkit.terminal.gwt.client.UIDL;
+import com.itmill.toolkit.terminal.gwt.client.Util;
+
+public class IAccordion extends ITabsheetBase implements
+ ContainerResizedListener {
+
+ public static final String CLASSNAME = "i-accordion";
+
+ private ArrayList stack = new ArrayList();
+
+ private Set paintables = new HashSet();
+
+ private String height;
+
+ public IAccordion() {
+ super(CLASSNAME);
+ // IE6 needs this to calculate offsetHeight correctly
+ if (Util.isIE6()) {
+ DOM.setStyleAttribute(getElement(), "zoom", "1");
+ }
+ }
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ super.updateFromUIDL(uidl, client);
+ iLayout();
+ }
+
+ private StackItem getSelectedStack() {
+ if (stack.size() == 0) {
+ return null;
+ }
+ return (StackItem) stack.get(activeTabIndex);
+ }
+
+ protected void renderTab(UIDL tabUidl, int index, boolean selected) {
+ // TODO check indexes, now new tabs get placed last (changing tab order
+ // is not supported from server-side)
+
+ StackItem item = new StackItem(tabUidl);
+
+ if (stack.size() == 0) {
+ item.addStyleDependentName("first");
+ }
+
+ stack.add(item);
+ add(item, getElement());
+
+ if (selected) {
+ item.open();
+ item.setContent(tabUidl.getChildUIDL(0));
+ } else if (tabUidl.getChildCount() > 0) {
+ // updating a drawn child on hidden tab
+ Paintable paintable = client.getPaintable(tabUidl.getChildUIDL(0));
+ paintable.updateFromUIDL(tabUidl.getChildUIDL(0), client);
+ }
+ }
+
+ protected void selectTab(final int index, final UIDL contentUidl) {
+ StackItem item = (StackItem) stack.get(index);
+ if (index != activeTabIndex) {
+ activeTabIndex = index;
+ item.open();
+ iLayout();
+ }
+ item.setContent(contentUidl);
+ }
+
+ public void onSelectTab(StackItem item) {
+ final int index = stack.indexOf(item);
+ if (index != activeTabIndex && !disabled && !readonly
+ && !disabledTabKeys.contains(tabKeys.get(index))) {
+ if (getSelectedStack() != null) {
+ getSelectedStack().close();
+ }
+ addStyleDependentName("loading");
+ // run updating variables in deferred command to bypass some FF
+ // optimization issues
+ DeferredCommand.addCommand(new Command() {
+ public void execute() {
+ client.updateVariable(id, "selected", ""
+ + tabKeys.get(index), true);
+ }
+ });
+ }
+ }
+
+ public void setWidth(String width) {
+ if (width.equals("100%")) {
+ super.setWidth("");
+ } else {
+ super.setWidth(width);
+ }
+ }
+
+ public void setHeight(String height) {
+ this.height = height;
+ }
+
+ public void iLayout() {
+ StackItem item = getSelectedStack();
+ if (item == null) {
+ return;
+ }
+
+ if (height != null && height != "") {
+ // Detach visible widget from document flow for a while to calculate
+ // used height correctly
+ Widget w = item.getPaintable();
+ String originalPositioning = "";
+ if (w != null) {
+ originalPositioning = DOM.getStyleAttribute(w.getElement(),
+ "position");
+ DOM.setStyleAttribute(w.getElement(), "visibility", "hidden");
+ DOM.setStyleAttribute(w.getElement(), "position", "absolute");
+ }
+ DOM.setStyleAttribute(item.getContainerElement(), "height", "0");
+
+ // Calculate target height
+ super.setHeight(height);
+ int targetHeight = DOM.getElementPropertyInt(DOM
+ .getParent(getElement()), "offsetHeight");
+ super.setHeight("");
+
+ // Calculate used height
+ int usedHeight = getOffsetHeight();
+
+ int h = targetHeight - usedHeight;
+ if (h < 0) {
+ h = 0;
+ }
+ DOM.setStyleAttribute(item.getContainerElement(), "height", h
+ + "px");
+
+ // Put widget back into normal flow
+ if (w != null) {
+ DOM.setStyleAttribute(w.getElement(), "position",
+ originalPositioning);
+ DOM.setStyleAttribute(w.getElement(), "visibility", "");
+ }
+ } else {
+ DOM.setStyleAttribute(item.getContainerElement(), "height", "");
+ }
+
+ Util.runDescendentsLayout(this);
+ }
+
+ /**
+ * TODO Caption widget not properly attached
+ */
+ protected class StackItem extends ComplexPanel implements ClickListener {
+
+ private Caption caption;
+ private boolean open = false;
+ private Element content;
+ private Element captionNode;
+ private Paintable paintable;
+
+ public StackItem(UIDL tabUidl) {
+ setElement(DOM.createDiv());
+ caption = new Caption(null, client);
+ caption.addClickListener(this);
+ content = DOM.createDiv();
+ captionNode = DOM.createDiv();
+ super.add(caption, captionNode);
+ DOM.appendChild(captionNode, caption.getElement());
+ DOM.appendChild(getElement(), captionNode);
+ DOM.appendChild(getElement(), content);
+ setStylePrimaryName(CLASSNAME + "-item");
+ DOM.setElementProperty(content, "className", CLASSNAME
+ + "-item-content");
+ DOM.setElementProperty(captionNode, "className", CLASSNAME
+ + "-item-caption");
+ DOM.setStyleAttribute(content, "overflow", "auto");
+ DOM.setStyleAttribute(content, "display", "none");
+ // Force 'hasLayout' in IE6 (prevents layout problems)
+ if (Util.isIE6()) {
+ DOM.setStyleAttribute(content, "zoom", "1");
+ }
+
+ caption.updateCaption(tabUidl);
+ }
+
+ public Element getContainerElement() {
+ return content;
+ }
+
+ public Widget getPaintable() {
+ if (getWidgetCount() > 1) {
+ return getWidget(1);
+ } else {
+ return null;
+ }
+ }
+
+ public void open() {
+ open = true;
+ DOM.setStyleAttribute(content, "display", "");
+ addStyleDependentName("open");
+ if (getPaintable() != null) {
+ add(getPaintable(), content);
+ }
+ }
+
+ public void close() {
+ open = false;
+ if (getPaintable() != null) {
+ remove(getPaintable());
+ }
+ DOM.setStyleAttribute(content, "display", "none");
+ removeStyleDependentName("open");
+ }
+
+ public boolean isOpen() {
+ return open;
+ }
+
+ public void setContent(UIDL contentUidl) {
+ final Paintable newPntbl = client.getPaintable(contentUidl);
+ // due hack #1 in ITabsheetBase
+ ((Widget) newPntbl).setVisible(true);
+ if (getPaintable() == null) {
+ add((Widget) newPntbl, content);
+ paintables.add(newPntbl);
+ } else if (getPaintable() != newPntbl) {
+ client.unregisterPaintable((Paintable) getWidget(1));
+ paintables.remove(getWidget(1));
+ remove(1);
+ add((Widget) newPntbl, content);
+ paintables.add(newPntbl);
+ }
+ paintable = newPntbl;
+ paintable.updateFromUIDL(contentUidl, client);
+ }
+
+ public void onClick(Widget sender) {
+ onSelectTab(this);
+ }
+ }
+
+ protected void clearPaintables() {
+ stack.clear();
+ clear();
+ }
+
+ protected Iterator getPaintableIterator() {
+ return paintables.iterator();
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/ui/IButton.java b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/IButton.java
new file mode 100644
index 0000000000..68d83f1a13
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/IButton.java
@@ -0,0 +1,117 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.Widget;
+import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
+import com.itmill.toolkit.terminal.gwt.client.BrowserInfo;
+import com.itmill.toolkit.terminal.gwt.client.Paintable;
+import com.itmill.toolkit.terminal.gwt.client.Tooltip;
+import com.itmill.toolkit.terminal.gwt.client.UIDL;
+
+public class IButton extends Button implements Paintable {
+
+ public static final String CLASSNAME = "i-button";
+
+ String id;
+
+ ApplicationConnection client;
+
+ private Element errorIndicatorElement;
+
+ private final Element captionElement = DOM.createSpan();
+
+ private Icon icon;
+
+ public IButton() {
+ setStyleName(CLASSNAME);
+
+ DOM.appendChild(getElement(), captionElement);
+
+ addClickListener(new ClickListener() {
+ public void onClick(Widget sender) {
+ if (id == null || client == null) {
+ return;
+ }
+ /*
+ * TODO isolata workaround. Safari don't always seem to fire
+ * onblur previously focused component before button is clicked.
+ */
+ IButton.this.setFocus(true);
+ client.updateVariable(id, "state", true, true);
+ }
+ });
+ sinkEvents(Tooltip.TOOLTIP_EVENTS);
+ }
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+
+ // Ensure correct implementation,
+ // but don't let container manage caption etc.
+ if (client.updateComponent(this, uidl, false)) {
+ return;
+ }
+
+ // Save details
+ this.client = client;
+ id = uidl.getId();
+
+ // Set text
+ setText(uidl.getStringAttribute("caption"));
+
+ // handle error
+ if (uidl.hasAttribute("error")) {
+ if (errorIndicatorElement == null) {
+ errorIndicatorElement = DOM.createDiv();
+ DOM.setElementProperty(errorIndicatorElement, "className",
+ "i-errorindicator");
+ }
+ DOM.insertChild(getElement(), errorIndicatorElement, 0);
+
+ // Fix for IE6, IE7
+ if (BrowserInfo.get().isIE()) {
+ DOM.setInnerText(errorIndicatorElement, " ");
+ }
+
+ } else if (errorIndicatorElement != null) {
+ DOM.removeChild(getElement(), errorIndicatorElement);
+ errorIndicatorElement = null;
+ }
+
+ if (uidl.hasAttribute("readonly")) {
+ setEnabled(false);
+ }
+
+ if (uidl.hasAttribute("icon")) {
+ if (icon == null) {
+ icon = new Icon(client);
+ DOM.insertChild(getElement(), icon.getElement(), 0);
+ }
+ icon.setUri(uidl.getStringAttribute("icon"));
+ } else {
+ if (icon != null) {
+ DOM.removeChild(getElement(), icon.getElement());
+ icon = null;
+ }
+ }
+ }
+
+ public void setText(String text) {
+ DOM.setInnerText(captionElement, text);
+ }
+
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+ if (client != null) {
+ client.handleTooltipEvent(event, this);
+ }
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/ui/ICheckBox.java b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/ICheckBox.java
new file mode 100644
index 0000000000..191db6023a
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/ICheckBox.java
@@ -0,0 +1,118 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.Widget;
+import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
+import com.itmill.toolkit.terminal.gwt.client.Paintable;
+import com.itmill.toolkit.terminal.gwt.client.Tooltip;
+import com.itmill.toolkit.terminal.gwt.client.UIDL;
+
+public class ICheckBox extends com.google.gwt.user.client.ui.CheckBox implements
+ Paintable, Field {
+
+ public static final String CLASSNAME = "i-checkbox";
+
+ String id;
+
+ boolean immediate;
+
+ ApplicationConnection client;
+
+ private Element errorIndicatorElement;
+
+ private Icon icon;
+
+ private boolean isBlockMode = false;
+
+ public ICheckBox() {
+ setStyleName(CLASSNAME);
+ addClickListener(new ClickListener() {
+
+ public void onClick(Widget sender) {
+ if (id == null || client == null) {
+ return;
+ }
+ client.updateVariable(id, "state", isChecked(), immediate);
+ }
+
+ });
+ sinkEvents(Tooltip.TOOLTIP_EVENTS);
+ }
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ // Save details
+ this.client = client;
+ id = uidl.getId();
+
+ // Ensure correct implementation
+ if (client.updateComponent(this, uidl, false)) {
+ return;
+ }
+
+ if (uidl.hasAttribute("error")) {
+ if (errorIndicatorElement == null) {
+ errorIndicatorElement = DOM.createDiv();
+ DOM.setElementProperty(errorIndicatorElement, "className",
+ "i-errorindicator");
+ DOM.appendChild(getElement(), errorIndicatorElement);
+ }
+ } else if (errorIndicatorElement != null) {
+ DOM.setStyleAttribute(errorIndicatorElement, "display", "none");
+ }
+
+ if (uidl.hasAttribute("readonly")) {
+ setEnabled(false);
+ }
+
+ if (uidl.hasAttribute("icon")) {
+ if (icon == null) {
+ icon = new Icon(client);
+ DOM.insertChild(getElement(), icon.getElement(), 1);
+ }
+ icon.setUri(uidl.getStringAttribute("icon"));
+ } else if (icon != null) {
+ // detach icon
+ DOM.removeChild(getElement(), icon.getElement());
+ icon = null;
+ }
+
+ // Set text
+ setText(uidl.getStringAttribute("caption"));
+ setChecked(uidl.getBooleanVariable("state"));
+ immediate = uidl.getBooleanAttribute("immediate");
+ }
+
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+ if (client != null) {
+ client.handleTooltipEvent(event, this);
+ }
+ }
+
+ public void setWidth(String width) {
+ setBlockMode();
+ super.setWidth(width);
+ }
+
+ public void setHeight(String height) {
+ setBlockMode();
+ super.setHeight(height);
+ }
+
+ /**
+ * makes container element (span) to be block element to enable sizing.
+ */
+ private void setBlockMode() {
+ if (!isBlockMode) {
+ DOM.setStyleAttribute(getElement(), "display", "block");
+ isBlockMode = true;
+ }
+ }
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/ui/ICustomComponent.java b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/ICustomComponent.java
new file mode 100644
index 0000000000..fcd4d4796b
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/ICustomComponent.java
@@ -0,0 +1,64 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
+import com.itmill.toolkit.terminal.gwt.client.Container;
+import com.itmill.toolkit.terminal.gwt.client.Paintable;
+import com.itmill.toolkit.terminal.gwt.client.UIDL;
+
+public class ICustomComponent extends SimplePanel implements Container {
+
+ private static final String CLASSNAME = "i-customcomponent";
+
+ public ICustomComponent() {
+ super();
+ setStyleName(CLASSNAME);
+ }
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ if (client.updateComponent(this, uidl, false)) {
+ return;
+ }
+
+ final UIDL child = uidl.getChildUIDL(0);
+ if (child != null) {
+ final Paintable p = client.getPaintable(child);
+ if (p != getWidget()) {
+ if (getWidget() != null) {
+ client.unregisterPaintable((Paintable) getWidget());
+ clear();
+ }
+ setWidget((Widget) p);
+ }
+ p.updateFromUIDL(child, client);
+ }
+
+ }
+
+ public boolean hasChildComponent(Widget component) {
+ if (getWidget() == component) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+ if (hasChildComponent(oldComponent)) {
+ clear();
+ setWidget(newComponent);
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public void updateCaption(Paintable component, UIDL uidl) {
+ // TODO custom component could handle its composition roots caption
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/client/ui/ICustomLayout.java b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/ICustomLayout.java
new file mode 100644
index 0000000000..366257fcaa
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/client/ui/ICustomLayout.java
@@ -0,0 +1,463 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.ComplexPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
+import com.itmill.toolkit.terminal.gwt.client.Caption;
+import com.itmill.toolkit.terminal.gwt.client.CaptionWrapper;
+import com.itmill.toolkit.terminal.gwt.client.Container;
+import com.itmill.toolkit.terminal.gwt.client.ContainerResizedListener;
+import com.itmill.toolkit.terminal.gwt.client.Paintable;
+import com.itmill.toolkit.terminal.gwt.client.UIDL;
+import com.itmill.toolkit.terminal.gwt.client.Util;
+
+/**
+ * Custom Layout implements complex layout defined with HTML template.
+ *
+ * @author IT Mill
+ *
+ */
+public class ICustomLayout extends ComplexPanel implements Paintable,
+ Container, ContainerResizedListener {
+
+ public static final String CLASSNAME = "i-customlayout";
+
+ /** Location-name to containing element in DOM map */
+ private final HashMap locationToElement = new HashMap();
+
+ /** Location-name to contained widget map */
+ private final HashMap locationToWidget = new HashMap();
+
+ /** Widget to captionwrapper map */
+ private final HashMap widgetToCaptionWrapper = new HashMap();
+
+ /** Currently rendered style */
+ String currentTemplate;
+
+ /** Unexecuted scripts loaded from the template */
+ private String scripts = "";
+
+ /** Paintable ID of this paintable */
+ private String pid;
+
+ private ApplicationConnection client;
+
+ public ICustomLayout() {
+ setElement(DOM.createDiv());
+ // Clear any unwanted styling
+ DOM.setStyleAttribute(getElement(), "border", "none");
+ DOM.setStyleAttribute(getElement(), "margin", "0");
+ DOM.setStyleAttribute(getElement(), "padding", "0");
+ setStyleName(CLASSNAME);
+ }
+
+ /**
+ * Sets widget to given location.
+ *
+ * If location already contains a widget it will be removed.
+ *
+ * @param widget
+ * Widget to be set into location.
+ * @param location
+ * location name where widget will be added
+ *
+ * @throws IllegalArgumentException
+ * if no such location is found in the layout.
+ */
+ public void setWidget(Widget widget, String location) {
+
+ if (widget == null) {
+ return;
+ }
+
+ // If no given location is found in the layout, and exception is throws
+ Element elem = (Element) locationToElement.get(location);
+ if (elem == null && hasTemplate()) {
+ throw new IllegalArgumentException("No location " + location
+ + " found");
+ }
+
+ // Get previous widget
+ final Widget previous = (Widget) locationToWidget.get(location);
+ // NOP if given widget already exists in this location
+ if (previous == widget) {
+ return;
+ }
+ remove(previous);
+
+ // if template is missing add element in order
+ if (!hasTemplate()) {
+ elem = getElement();
+ }
+
+ // Add widget to location
+ super.add(widget, elem);
+ locationToWidget.put(location, widget);
+ }
+
+ /** Update the layout from UIDL */
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ this.client = client;
+ // Client manages general cases
+ if (client.updateComponent(this, uidl, false)) {
+ return;
+ }
+
+ // Update PID
+ pid = uidl.getId();
+ if (!hasTemplate()) {
+ // Update HTML template only once
+ initializeHTML(uidl, client);
+ }
+
+ // Set size
+ if (uidl.hasAttribute("width")) {
+ setWidth(uidl.getStringAttribute("width"));
+ } else {
+ setWidth("100%");
+ }
+ if (uidl.hasAttribute("height")) {
+ setHeight(uidl.getStringAttribute("height"));
+ } else {
+ setHeight("100%");
+ }
+
+ // Evaluate scripts
+ eval(scripts);
+ scripts = null;
+
+ iLayout();
+
+ Set oldWidgets = new HashSet();
+ oldWidgets.addAll(locationToWidget.values());
+
+ // For all contained widgets
+ for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {
+ final UIDL uidlForChild = (UIDL) i.next();
+ if (uidlForChild.getTag().equals("location")) {
+ final String location = uidlForChild.getStringAttribute("name");
+ final Paintable child = client.getPaintable(uidlForChild
+ .getChildUIDL(0));
+ try {
+ setWidget((Widget) child, location);
+ child.updateFromUIDL(uidlForChild.getChildUIDL(0), client);
+ } catch (final IllegalArgumentException e) {
+ // If no location is found, this component is not visible
+ }
+ oldWidgets.remove(child);
+ }
+ }
+ for (Iterator iterator = oldWidgets.iterator(); iterator.hasNext();) {
+ Widget oldWidget = (Widget) iterator.next();
+ if (oldWidget.isAttached()) {
+ // slot of this widget is emptied, remove it
+ remove(oldWidget);
+ }
+ }
+
+ iLayout();
+ }
+
+ /** Initialize HTML-layout. */
+ private void initializeHTML(UIDL uidl, ApplicationConnection client) {
+
+ final String newTemplate = uidl.getStringAttribute("template");
+
+ // Get the HTML-template from client
+ String template = client
+ .getResource("layouts/" + newTemplate + ".html");
+ if (template == null) {
+ template = "Layout file layouts/"
+ + newTemplate
+ + ".html is missing. Components will be drawn for debug purposes.";
+ } else {
+ currentTemplate = newTemplate;
+ }
+
+ // Connect body of the template to DOM
+ template = extractBodyAndScriptsFromTemplate(template);
+ DOM.setInnerHTML(getElement(), template);
+
+ // Remap locations to elements
+ locationToElement.clear();
+ scanForLocations(getElement());
+
+ String themeUri = client.getThemeUri();
+ prefixImgSrcs(getElement(), themeUri + "/layouts/");
+
+ publishResizedFunction(DOM.getFirstChild(getElement()));
+
+ }
+
+ private native boolean uriEndsWithSlash()
+ /*-{
+ var path = $wnd.location.pathname;
+ if(path.charAt(path.length - 1) == "/")
+ return true;
+ return false;
+ }-*/;
+
+ private boolean hasTemplate() {
+ if (currentTemplate == null) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /** Collect locations from template */
+ private void scanForLocations(Element elem) {
+
+ final String location = getLocation(elem);
+ if (location != null) {
+ locationToElement.put(location, elem);
+ DOM.setInnerHTML(elem, "");
+ } else {
+ final int len = DOM.getChildCount(elem);
+ for (int i = 0; i < len; i++) {
+ scanForLocations(DOM.getChild(elem, i));
+ }
+ }
+ }
+
+ /** Get the location attribute for given element */
+ private static native String getLocation(Element elem)
+ /*-{
+ return elem.getAttribute("location");
+ }-*/;
+
+ /** Evaluate given script in browser document */
+ private static native void eval(String script)
+ /*-{
+ try {
+ if (script != null)
+ eval("{ var document = $doc; var window = $wnd; "+ script + "}");
+ } catch (e) {
+ }
+ }-*/;
+
+ /** Prefix all img tag srcs with given prefix. */
+ private static native void prefixImgSrcs(Element e, String srcPrefix)
+ /*-{
+ try {
+ var divs = e.getElementsByTagName("img");
+ var base = "" + $doc.location;
+ var l = base.length-1;
+ while (l >= 0 && base.charAt(l) != "/") l--;
+ base = base.substring(0,l+1);
+ for (var i = 0; i < divs.length; i++) {
+ var div = divs[i];
+ var src = div.getAttribute("src");
+ if (src.indexOf("/")==0 || src.match(/\w+:\/\//)) {
+ continue;
+ }
+ div.setAttribute("src",srcPrefix + src);
+ }
+ } catch (e) { alert(e + " " + srcPrefix);}
+ }-*/;
+
+ /**
+ * Extract body part and script tags from raw html-template.
+ *
+ * Saves contents of all script-tags to private property: scripts. Returns
+ * contents of the body part for the html without script-tags. Also replaces
+ * all _UID_ tags with an unique id-string.
+ *
+ * @param html
+ * Original HTML-template received from server
+ * @return html that is used to create the HTMLPanel.
+ */
+ private String extractBodyAndScriptsFromTemplate(String html) {
+
+ // Replace UID:s
+ html = html.replaceAll("_UID_", pid + "__");
+
+ // Exctract script-tags
+ scripts = "";
+ int endOfPrevScript = 0;
+ int nextPosToCheck = 0;
+ String lc = html.toLowerCase();
+ String res = "";
+ int scriptStart = lc.indexOf("", scriptStart);
+ scripts += html.substring(scriptStart + 1, j) + ";";
+ nextPosToCheck = endOfPrevScript = j + "".length();
+ scriptStart = lc.indexOf("