summaryrefslogtreecommitdiffstats
path: root/src/com/vaadin/automatedtests
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/vaadin/automatedtests')
-rw-r--r--src/com/vaadin/automatedtests/ComponentsInTable.java77
-rw-r--r--src/com/vaadin/automatedtests/SimplestApplication.java19
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/AccordionExample.java40
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/ButtonExample.java151
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/ClientCachingExample.java73
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/ComboBoxExample.java74
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/EmbeddedBrowserExample.java91
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/FeatureBrowser.java388
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/FormExample.java212
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/GeneratedColumnExample.java561
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/JavaScriptAPIExample.java97
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/LabelExample.java84
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/LayoutExample.java93
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/NotificationExample.java95
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/RichTextExample.java63
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/SelectExample.java108
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/TableExample.java302
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/TreeExample.java164
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/ValueInputExample.java163
-rw-r--r--src/com/vaadin/automatedtests/featurebrowser/WindowingExample.java112
-rw-r--r--src/com/vaadin/automatedtests/robustness/Robustness.java91
-rw-r--r--src/com/vaadin/automatedtests/robustness/RobustnessComplex.java45
-rw-r--r--src/com/vaadin/automatedtests/util/DebugId.java50
-rw-r--r--src/com/vaadin/automatedtests/util/Log.java136
-rw-r--r--src/com/vaadin/automatedtests/util/MultiListener.java35
-rw-r--r--src/com/vaadin/automatedtests/util/RandomComponents.java281
-rw-r--r--src/com/vaadin/automatedtests/util/StatusServlet.java89
27 files changed, 3694 insertions, 0 deletions
diff --git a/src/com/vaadin/automatedtests/ComponentsInTable.java b/src/com/vaadin/automatedtests/ComponentsInTable.java
new file mode 100644
index 0000000000..ccbe29d2d5
--- /dev/null
+++ b/src/com/vaadin/automatedtests/ComponentsInTable.java
@@ -0,0 +1,77 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests;
+
+import java.util.Date;
+import java.util.Random;
+import java.util.Vector;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.OrderedLayout;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Button.ClickEvent;
+
+@SuppressWarnings("serial")
+public class ComponentsInTable extends CustomComponent {
+
+ public ComponentsInTable(int cols, int rows) {
+ final OrderedLayout main = new OrderedLayout();
+ setCompositionRoot(main);
+
+ main.addComponent(getTestTable(cols, rows));
+ }
+
+ public static Table getTestTable(int cols, int rows) {
+ Random rnd = new Random(1);
+
+ final Table t = new Table();
+ t.setColumnCollapsingAllowed(true);
+ for (int i = 0; i < cols; i++) {
+ t.addContainerProperty(testString[i], String.class, "");
+ }
+ t.addContainerProperty("button", Button.class, null);
+ for (int i = 0; i < rows; i++) {
+ final Vector content = new Vector();
+ for (int j = 0; j < cols; j++) {
+ content.add(rndString(rnd));
+ }
+ content.add(new Button("b" + i, new Button.ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ System.out.println(event.getButton().getCaption()
+ + " click: " + (new Date()).toGMTString());
+ System.out.println(event.getButton().getApplication());
+
+ }
+ }));
+ t.addItem(content.toArray(), "" + i);
+ }
+ t.setRowHeaderMode(Table.ROW_HEADER_MODE_ID);
+ return t;
+ }
+
+ static String[] testString = new String[] { "Jacob", "Michael", "Joshua",
+ "Matthew", "Ethan", "Andrew", "Daniel", "Anthony", "Christopher",
+ "Joseph", "William", "Alexander", "Ryan", "David", "Nicholas",
+ "Tyler", "James", "John", "Jonathan", "Nathan", "Samuel",
+ "Christian", "Noah", "Dylan", "Benjamin", "Logan", "Brandon",
+ "Gabriel", "Zachary", "Jose", "Elijah", "Angel", "Kevin", "Jack",
+ "Caleb", "Justin", "Austin", "Evan", "Robert", "Thomas", "Luke",
+ "Mason", "Aidan", "Jackson", "Isaiah", "Jordan", "Gavin", "Connor",
+ "Aiden", "Isaac", "Jason", "Cameron", "Hunter", "Jayden", "Juan",
+ "Charles", "Aaron", "Lucas", "Luis", "Owen", "Landon", "Diego",
+ "Brian", "Adam", "Adrian", "Kyle", "Eric", "Ian", "Nathaniel",
+ "Carlos", "Alex", "Bryan", "Jesus", "Julian", "Sean", "Carter",
+ "Hayden", "Jeremiah", "Cole", "Brayden", "Wyatt", "Chase",
+ "Steven", "Timothy", "Dominic", "Sebastian", "Xavier", "Jaden",
+ "Jesse", "Devin", "Seth", "Antonio", "Richard", "Miguel", "Colin",
+ "Cody", "Alejandro", "Caden", "Blake", "Carson" };
+
+ public static String rndString(Random rnd) {
+ return testString[(int) (rnd.nextDouble() * testString.length)];
+ }
+
+}
diff --git a/src/com/vaadin/automatedtests/SimplestApplication.java b/src/com/vaadin/automatedtests/SimplestApplication.java
new file mode 100644
index 0000000000..7de7e0928e
--- /dev/null
+++ b/src/com/vaadin/automatedtests/SimplestApplication.java
@@ -0,0 +1,19 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests;
+
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Window;
+
+@SuppressWarnings("serial")
+public class SimplestApplication extends com.vaadin.Application {
+
+ @Override
+ public void init() {
+ final Window main = new Window("Simplest Application window");
+ setMainWindow(main);
+ main.addComponent(new Label("Simplest Application label"));
+ }
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/AccordionExample.java b/src/com/vaadin/automatedtests/featurebrowser/AccordionExample.java
new file mode 100644
index 0000000000..05894392ef
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/AccordionExample.java
@@ -0,0 +1,40 @@
+package com.vaadin.automatedtests.featurebrowser;
+
+import com.vaadin.ui.Accordion;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+
+/**
+ * Accordion is a derivative of TabSheet, a vertical tabbed layout that places
+ * the tab contents between the vertical tabs.
+ */
+@SuppressWarnings("serial")
+public class AccordionExample extends CustomComponent {
+
+ public AccordionExample() {
+ // Create a new accordion
+ final Accordion accordion = new Accordion();
+ setCompositionRoot(accordion);
+
+ // Add a few tabs to the accordion.
+ for (int i = 0; i < 5; i++) {
+ // Create a root component for a accordion tab
+ VerticalLayout layout = new VerticalLayout();
+ accordion.addComponent(layout);
+
+ // The accordion tab label is taken from the caption of the root
+ // component. Notice that layouts can have a caption too.
+ layout.setCaption("Tab " + (i + 1));
+
+ // Add some components in each accordion tab
+ Label label = new Label("These are the contents of Tab " + (i + 1)
+ + ".");
+ layout.addComponent(label);
+
+ TextField textfield = new TextField("Some text field");
+ layout.addComponent(textfield);
+ }
+ }
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/ButtonExample.java b/src/com/vaadin/automatedtests/featurebrowser/ButtonExample.java
new file mode 100644
index 0000000000..0cd5ea05ec
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/ButtonExample.java
@@ -0,0 +1,151 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.featurebrowser;
+
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+/**
+ * Shows a few variations of Buttons and Links.
+ *
+ * @author IT Mill Ltd.
+ */
+@SuppressWarnings("serial")
+public class ButtonExample extends CustomComponent implements
+ Button.ClickListener {
+
+ public ButtonExample() {
+
+ final VerticalLayout main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ final HorizontalLayout horiz = new HorizontalLayout();
+ horiz.setWidth("100%");
+ main.addComponent(horiz);
+ final Panel basic = new Panel("Basic buttons");
+ basic.setStyleName(Panel.STYLE_LIGHT);
+ horiz.addComponent(basic);
+
+ final Panel bells = new Panel("w/ bells & whistles");
+ bells.setStyleName(Panel.STYLE_LIGHT);
+ horiz.addComponent(bells);
+
+ Button b = new Button("Basic button");
+ b.setDebugId("Basic1");
+ b.addListener(this);
+ basic.addComponent(b);
+
+ b = new Button("Button w/ icon + tooltip");
+ b.setDebugId("Button2");
+ b.addListener(this);
+ b.setIcon(new ThemeResource("icons/ok.png"));
+ b.setDescription("This button does nothing, fast");
+ bells.addComponent(b);
+
+ b = new CheckBox("CheckBox - a switch-button");
+ b.setDebugId("Button3");
+ b.setImmediate(true); // checkboxes are not immediate by default
+ b.addListener(this);
+ basic.addComponent(b);
+
+ b = new CheckBox("CheckBox w/ icon + tooltip");
+ b.setDebugId("Button4");
+ b.setImmediate(true); // checkboxes are not immediate by default
+ b.addListener(this);
+ b.setIcon(new ThemeResource("icons/ok.png"));
+ b.setDescription("This is a CheckBox");
+ bells.addComponent(b);
+
+ b = new Button("Link-style button");
+ b.setDebugId("Button5");
+ b.addListener(this);
+ b.setStyleName(Button.STYLE_LINK);
+ basic.addComponent(b);
+
+ b = new Button("Link button w/ icon + tooltip");
+ b.setDebugId("Button6");
+ b.addListener(this);
+ b.setStyleName(Button.STYLE_LINK);
+ b.setIcon(new ThemeResource("icons/ok.png"));
+ b.setDescription("Link-style, icon+tootip, no caption");
+ bells.addComponent(b);
+
+ b = new Button();
+ b.setDebugId("Button7");
+ b.addListener(this);
+ b.setStyleName(Button.STYLE_LINK);
+ b.setIcon(new ThemeResource("icons/ok.png"));
+ b.setDescription("Link-style, icon+tootip, no caption");
+ basic.addComponent(b);
+
+ final Panel links = new Panel("Links");
+ links.setStyleName(Panel.STYLE_LIGHT);
+ main.addComponent(links);
+ final Label desc = new Label(
+ "The main difference between a Link and"
+ + " a link-styled Button is that the Link works client-"
+ + " side, whereas the Button works server side.<br/> This means"
+ + " that the Button triggers some event on the server,"
+ + " while the Link is a normal web-link. <br/><br/>Note that for"
+ + " opening new windows, the Link might be a safer "
+ + " choice, since popup-blockers might interfer with "
+ + " server-initiated window opening.");
+ desc.setContentMode(Label.CONTENT_XHTML);
+ links.addComponent(desc);
+ Link l = new Link("IT Mill home", new ExternalResource(
+ "http://www.itmill.com"));
+ l.setDebugId("Link1");
+ l.setDescription("Link without target name, opens in this window");
+ links.addComponent(l);
+
+ l = new Link("IT Mill home (new window)", new ExternalResource(
+ "http://www.itmill.com"));
+ l.setDebugId("Link2");
+ l.setTargetName("_blank");
+ l.setDescription("Link with target name, opens in new window");
+ links.addComponent(l);
+
+ l = new Link("IT Mill home (new window, less decor)",
+ new ExternalResource("http://www.itmill.com"));
+ l.setDebugId("Link3");
+ l.setTargetName("_blank");
+ l.setTargetBorder(Link.TARGET_BORDER_MINIMAL);
+ l.setTargetName("_blank");
+ l
+ .setDescription("Link with target name and BORDER_MINIMAL, opens in new window with less decor");
+ links.addComponent(l);
+
+ l = new Link("IT Mill home (new 200x200 window, no decor, icon)",
+ new ExternalResource("http://www.itmill.com"), "_blank", 200,
+ 200, Link.TARGET_BORDER_NONE);
+ l.setDebugId("Link4");
+ l.setTargetName("_blank");
+ l
+ .setDescription("Link with target name and BORDER_NONE, opens in new window with no decor");
+ l.setIcon(new ThemeResource("icons/ok.png"));
+ links.addComponent(l);
+
+ }
+
+ public void buttonClick(ClickEvent event) {
+ final Button b = event.getButton();
+ getWindow().showNotification(
+ "Clicked"
+ + (b instanceof CheckBox ? ", value: "
+ + event.getButton().getValue() : ""));
+
+ }
+
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/ClientCachingExample.java b/src/com/vaadin/automatedtests/featurebrowser/ClientCachingExample.java
new file mode 100644
index 0000000000..2012329df1
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/ClientCachingExample.java
@@ -0,0 +1,73 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.featurebrowser;
+
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.VerticalLayout;
+
+/**
+ * This example is a (simple) demonstration of client-side caching. The content
+ * in one tab is intentionally made very slow to produce server-side. When the
+ * user changes to this tab for the first time, there will be a 3 second wait
+ * before the content shows up, but the second time it shows up immediately
+ * since the content has not changed and is cached client-side.
+ *
+ * @author IT Mill Ltd.
+ */
+@SuppressWarnings("serial")
+public class ClientCachingExample extends CustomComponent {
+
+ private static final String msg = "This example is a (simple) demonstration of client-side caching."
+ + " The content in one tab is intentionally made very slow to"
+ + " 'produce' server-side. When you changes to this tab for the"
+ + " first time, there will be a 3 second wait before the content"
+ + " shows up, but the second time it shows up immediately since the"
+ + " content has not changed and is cached client-side.";
+
+ public ClientCachingExample() {
+
+ final VerticalLayout main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ main.addComponent(new Label(msg));
+
+ final TabSheet ts = new TabSheet();
+ main.addComponent(ts);
+
+ Layout layout = new VerticalLayout();
+ layout.setMargin(true);
+ Label l = new Label("This is a normal label, quick to render.");
+ l.setCaption("A normal label");
+ layout.addComponent(l);
+
+ ts.addTab(layout, "Normal", null);
+
+ layout = new VerticalLayout();
+ layout.setMargin(true);
+ l = new Label("Slow label - until cached client side.") {
+
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+ try {
+ Thread.sleep(3000);
+ } catch (final Exception e) {
+ // IGNORED
+ }
+ super.paintContent(target);
+ }
+
+ };
+ l.setCaption("A slow label");
+ layout.addComponent(l);
+ ts.addTab(layout, "Slow", null);
+
+ }
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/ComboBoxExample.java b/src/com/vaadin/automatedtests/featurebrowser/ComboBoxExample.java
new file mode 100644
index 0000000000..753c746fdb
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/ComboBoxExample.java
@@ -0,0 +1,74 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.featurebrowser;
+
+import java.util.Random;
+
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.OrderedLayout;
+import com.vaadin.ui.AbstractSelect.Filtering;
+
+/**
+ *
+ */
+@SuppressWarnings("serial")
+public class ComboBoxExample extends CustomComponent {
+
+ private static final String[] firstnames = new String[] { "John", "Mary",
+ "Joe", "Sarah", "Jeff", "Jane", "Peter", "Marc", "Robert", "Paula",
+ "Lenny", "Kenny", "Nathan", "Nicole", "Laura", "Jos", "Josie",
+ "Linus" };
+
+ private static final String[] lastnames = new String[] { "Torvalds",
+ "Smith", "Adams", "Black", "Wilson", "Richards", "Thompson",
+ "McGoff", "Halas", "Jones", "Beck", "Sheridan", "Picard", "Hill",
+ "Fielding", "Einstein" };
+
+ public ComboBoxExample() {
+ final OrderedLayout main = new OrderedLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ // starts-with filter
+ final ComboBox s1 = new ComboBox("Select with starts-with filter");
+ s1.setDebugId("ComboBoxStartFilter");
+ s1.setFilteringMode(Filtering.FILTERINGMODE_STARTSWITH);
+ s1.setColumns(20);
+ Random r = new Random(5);
+ for (int i = 0; i < 105; i++) {
+ s1
+ .addItem(firstnames[(int) (r.nextDouble() * (firstnames.length - 1))]
+ + " "
+ + lastnames[(int) (r.nextDouble() * (lastnames.length - 1))]);
+ }
+ s1.setImmediate(true);
+ main.addComponent(s1);
+
+ // contains filter
+ final ComboBox s2 = new ComboBox("Select with contains filter");
+ s2.setDebugId("ComboBoxContainsFilter");
+ s2.setFilteringMode(Filtering.FILTERINGMODE_CONTAINS);
+ s2.setColumns(20);
+ for (int i = 0; i < 500; i++) {
+ s2
+ .addItem(firstnames[(int) (r.nextDouble() * (firstnames.length - 1))]
+ + " "
+ + lastnames[(int) (r.nextDouble() * (lastnames.length - 1))]);
+ }
+ s2.setImmediate(true);
+ main.addComponent(s2);
+
+ // initially empty
+ final ComboBox s3 = new ComboBox("Initially empty; enter your own");
+ s3.setDebugId("EmptyComboBox");
+ s3.setColumns(20);
+ s3.setImmediate(true);
+ s3.setNewItemsAllowed(true);
+ main.addComponent(s3);
+
+ }
+
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/EmbeddedBrowserExample.java b/src/com/vaadin/automatedtests/featurebrowser/EmbeddedBrowserExample.java
new file mode 100644
index 0000000000..a62e120f46
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/EmbeddedBrowserExample.java
@@ -0,0 +1,91 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.featurebrowser;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.ui.Embedded;
+import com.vaadin.ui.Select;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window.Notification;
+
+/**
+ * Demonstrates the use of Embedded and "suggesting" Select by creating a simple
+ * web-browser. Note: does not check for recursion.
+ *
+ * @author IT Mill Ltd.
+ * @see com.vaadin.ui.Window
+ */
+@SuppressWarnings("serial")
+public class EmbeddedBrowserExample extends VerticalLayout implements
+ Select.ValueChangeListener {
+
+ // Default URL to open.
+ private static final String DEFAULT_URL = "http://www.itmill.com/index_itmill_toolkit.htm";
+
+ // The embedded page
+ Embedded emb = new Embedded();
+
+ public EmbeddedBrowserExample() {
+ this(new String[] { DEFAULT_URL,
+ "http://www.itmill.com/index_developers.htm",
+ "http://toolkit.itmill.com/demo/doc/api/",
+ "http://www.itmill.com/manual/index.html" });
+ }
+
+ public EmbeddedBrowserExample(String[] urls) {
+ setSizeFull();
+
+ // create the address combobox
+ final Select select = new Select();
+ // allow input
+ select.setNewItemsAllowed(true);
+ // no empty selection
+ select.setNullSelectionAllowed(false);
+ // no 'go' -button clicking necessary
+ select.setImmediate(true);
+ // add some pre-configured URLs
+ for (int i = 0; i < urls.length; i++) {
+ select.addItem(urls[i]);
+ }
+ // add to layout
+ addComponent(select);
+ // add listener and select initial URL
+ select.addListener(this);
+ select.setValue(urls[0]);
+
+ select.setWidth("100%");
+
+ // configure the embedded and add to layout
+ emb.setType(Embedded.TYPE_BROWSER);
+ emb.setSizeFull();
+ addComponent(emb);
+ // make the embedded as large as possible
+ setExpandRatio(emb, 1);
+
+ }
+
+ public void valueChange(ValueChangeEvent event) {
+ final String url = (String) event.getProperty().getValue();
+ if (url != null) {
+ try {
+ // the selected url has changed, let's go there
+ @SuppressWarnings("unused")
+ URL u = new URL(url);
+ emb.setSource(new ExternalResource(url));
+
+ } catch (MalformedURLException e) {
+ getWindow().showNotification("Invalid address",
+ e.getMessage() + " (example: http://www.itmill.com)",
+ Notification.TYPE_WARNING_MESSAGE);
+ }
+
+ }
+
+ }
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/FeatureBrowser.java b/src/com/vaadin/automatedtests/featurebrowser/FeatureBrowser.java
new file mode 100644
index 0000000000..bc3983aea2
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/FeatureBrowser.java
@@ -0,0 +1,388 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.featurebrowser;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.util.HierarchicalContainer;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Embedded;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.Select;
+import com.vaadin.ui.SplitPanel;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Tree;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+/**
+ *
+ * @author IT Mill Ltd.
+ * @see com.vaadin.ui.Window
+ */
+@SuppressWarnings("serial")
+public class FeatureBrowser extends com.vaadin.Application implements
+ Select.ValueChangeListener {
+
+ // Property IDs
+
+ private static final Object PROPERTY_ID_CATEGORY = "Category";
+ private static final Object PROPERTY_ID_NAME = "Name";
+ private static final Object PROPERTY_ID_DESC = "Description";
+ private static final Object PROPERTY_ID_CLASS = "Class";
+ private static final Object PROPERTY_ID_VIEWED = "Viewed";
+
+ // Global components
+ private Tree tree;
+ private Table table;
+ private TabSheet ts;
+
+ // Example "cache"
+ private final HashMap exampleInstances = new HashMap();
+ private String section;
+
+ // List of examples
+ private static final Object[][] demos = new Object[][] {
+ // Category, Name, Desc, Class, Viewed
+ // Getting started: Labels
+ { "Getting started", "Labels", "Some variations of Labels",
+ LabelExample.class },
+ // Getting started: Buttons
+ { "Getting started", "Buttons and links",
+ "Various Buttons and Links", ButtonExample.class },
+ // Getting started: Fields
+ { "Getting started", "Basic value input",
+ "TextFields, DateFields, and such", ValueInputExample.class },
+ //
+ { "Getting started", "RichText", "Rich text editing",
+ RichTextExample.class },
+ // Getting started: Selects
+ { "Getting started", "Choices, choices",
+ "Some variations of simple selects", SelectExample.class },
+ // Layouts
+ { "Layouts", "Basic layouts", "Laying out components",
+ LayoutExample.class },
+ // Layouts
+ { "Layouts", "Accordion", "Play the Accordion!",
+ AccordionExample.class },
+ // Wrangling data: ComboBox
+ { "Wrangling data", "ComboBox", "ComboBox - the swiss army select",
+ ComboBoxExample.class },
+ // Wrangling data: Table
+ {
+ "Wrangling data",
+ "Table (\"grid\")",
+ "Table with bells, whistles, editmode and actions (contextmenu)",
+ TableExample.class },
+ // Wrangling data: Form
+ { "Wrangling data", "Form", "Every application needs forms",
+ FormExample.class },
+ // Wrangling data: Tree
+ { "Wrangling data", "Tree", "A hierarchy of things",
+ TreeExample.class },
+ // Misc: Notifications
+ { "Misc", "Notifications", "Notifications can improve usability",
+ NotificationExample.class },
+ // Misc: Caching
+ { "Misc", "Client caching", "Demonstrating of client-side caching",
+ ClientCachingExample.class },
+ // Misc: Embedded
+ { "Misc", "Embedding",
+ "Embedding resources - another site in this case",
+ EmbeddedBrowserExample.class },
+ // Windowing
+ { "Misc", "Windowing", "About windowing", WindowingExample.class },
+ // JavaScript API
+ { "Misc", "JavaScript API",
+ "JavaScript to IT Mill Toolkit communication",
+ JavaScriptAPIExample.class },
+ // END
+ };
+
+ @Override
+ public void init() {
+
+ // Need to set a theme for ThemeResources to work
+ setTheme("example");
+
+ // Create new window for the application and give the window a visible.
+ final Window main = new Window("IT Mill Toolkit 5");
+ main.setDebugId("mainWindow");
+ // set as main window
+ setMainWindow(main);
+
+ final SplitPanel split = new SplitPanel(
+ SplitPanel.ORIENTATION_HORIZONTAL);
+ split.setSplitPosition(200, SplitPanel.UNITS_PIXELS);
+ main.setLayout(split);
+
+ final HashMap sectionIds = new HashMap();
+ final HierarchicalContainer container = createContainer();
+ final Object rootId = container.addItem();
+ Item item = container.getItem(rootId);
+ Property p = item.getItemProperty(PROPERTY_ID_NAME);
+ p.setValue("All examples");
+ for (int i = 0; i < demos.length; i++) {
+ final Object[] demo = demos[i];
+ final String section = (String) demo[0];
+ Object sectionId;
+ if (sectionIds.containsKey(section)) {
+ sectionId = sectionIds.get(section);
+ } else {
+ sectionId = container.addItem();
+ sectionIds.put(section, sectionId);
+ container.setParent(sectionId, rootId);
+ item = container.getItem(sectionId);
+ p = item.getItemProperty(PROPERTY_ID_NAME);
+ p.setValue(section);
+ }
+ final Object id = container.addItem();
+ container.setParent(id, sectionId);
+ initItem(container.getItem(id), demo);
+
+ }
+
+ tree = new Tree();
+ tree.setDebugId("FeatureBrowser: Main Tree");
+ tree.setSelectable(true);
+ tree.setMultiSelect(false);
+ tree.setNullSelectionAllowed(false);
+ tree.setContainerDataSource(container);
+ tree.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);
+ tree.setItemCaptionPropertyId(PROPERTY_ID_NAME);
+ tree.addListener(this);
+ tree.setImmediate(true);
+ tree.expandItemsRecursively(rootId);
+ for (Iterator<?> i = container.getItemIds().iterator(); i.hasNext();) {
+ Object id = i.next();
+ if (container.getChildren(id) == null) {
+ tree.setChildrenAllowed(id, false);
+ }
+ }
+
+ split.addComponent(tree);
+
+ final SplitPanel split2 = new SplitPanel();
+ split2.setSplitPosition(200, SplitPanel.UNITS_PIXELS);
+ split.addComponent(split2);
+
+ table = new Table();
+ table.setDebugId("FeatureBrowser: Main Table");
+ table.setSizeFull();
+ table.setColumnReorderingAllowed(true);
+ table.setColumnCollapsingAllowed(true);
+ table.setSelectable(true);
+ table.setMultiSelect(false);
+ table.setNullSelectionAllowed(false);
+ try {
+ table.setContainerDataSource((IndexedContainer) container.clone());
+ } catch (final Exception e) {
+ e.printStackTrace(System.err);
+ }
+ // Hide some columns
+ table.setVisibleColumns(new Object[] { PROPERTY_ID_CATEGORY,
+ PROPERTY_ID_NAME, PROPERTY_ID_DESC, PROPERTY_ID_VIEWED });
+ table.addListener(this);
+ table.setImmediate(true);
+ split2.addComponent(table);
+
+ final VerticalLayout exp = new VerticalLayout();
+ exp.setSizeFull();
+ exp.setMargin(true);
+ split2.addComponent(exp);
+
+ final HorizontalLayout wbLayout = new HorizontalLayout();
+ Button b = new Button("Open in sub-window", new Button.ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ Component component = (Component) ts.getComponentIterator()
+ .next();
+ String caption = ts.getTabCaption(component);
+ try {
+ component = component.getClass().newInstance();
+ } catch (Exception e) {
+ // Could not create
+ return;
+ }
+ Window w = new Window(caption);
+ w.setWidth("640px");
+ if (Layout.class.isAssignableFrom(component.getClass())) {
+ w.setLayout((Layout) component);
+ } else {
+ // w.getLayout().getSize().setSizeFull();
+ w.addComponent(component);
+ }
+ getMainWindow().addWindow(w);
+ }
+ });
+ b.setStyleName(Button.STYLE_LINK);
+ wbLayout.addComponent(b);
+ b = new Button("Open in native window", new Button.ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ Component component = (Component) ts.getComponentIterator()
+ .next();
+ final String caption = ts.getTabCaption(component);
+ Window w = getWindow(caption);
+ if (w == null) {
+ try {
+ component = component.getClass().newInstance();
+ } catch (final Exception e) {
+ // Could not create
+ return;
+ }
+ w = new Window(caption);
+ w.setName(caption);
+ if (Layout.class.isAssignableFrom(component.getClass())) {
+ w.setLayout((Layout) component);
+ } else {
+ // w.getLayout().getSize().setSizeFull();
+ w.addComponent(component);
+ }
+ addWindow(w);
+ }
+ getMainWindow().open(new ExternalResource(w.getURL()), caption);
+ }
+ });
+ b.setStyleName(Button.STYLE_LINK);
+ wbLayout.addComponent(b);
+
+ exp.addComponent(wbLayout);
+ exp.setComponentAlignment(wbLayout, Alignment.TOP_RIGHT);
+
+ ts = new TabSheet();
+ ts.setSizeFull();
+ ts.addTab(new Label(""), "Choose example", null);
+ exp.addComponent(ts);
+ exp.setExpandRatio(ts, 1);
+
+ final Label status = new Label(
+ "<a href=\"http://www.itmill.com/developers/\">Developer Area</a>"
+ + " | <a href=\"http://www.itmill.com/documentation/\">Documentation</a>");
+ status.setContentMode(Label.CONTENT_XHTML);
+ exp.addComponent(status);
+ exp.setComponentAlignment(status, Alignment.MIDDLE_RIGHT);
+
+ // select initial section ("All")
+ tree.setValue(rootId);
+
+ getMainWindow()
+ .showNotification(
+ "Welcome",
+ "Choose an example to begin.<br/><br/>And remember to experiment!",
+ Window.Notification.TYPE_TRAY_NOTIFICATION);
+ }
+
+ private void initItem(Item item, Object[] data) {
+ int p = 0;
+ Property prop = item.getItemProperty(PROPERTY_ID_CATEGORY);
+ prop.setValue(data[p++]);
+ prop = item.getItemProperty(PROPERTY_ID_NAME);
+ prop.setValue(data[p++]);
+ prop = item.getItemProperty(PROPERTY_ID_DESC);
+ prop.setValue(data[p++]);
+ prop = item.getItemProperty(PROPERTY_ID_CLASS);
+ prop.setValue(data[p++]);
+ }
+
+ private HierarchicalContainer createContainer() {
+ final HierarchicalContainer c = new HierarchicalContainer();
+ c.addContainerProperty(PROPERTY_ID_CATEGORY, String.class, null);
+ c.addContainerProperty(PROPERTY_ID_NAME, String.class, "");
+ c.addContainerProperty(PROPERTY_ID_DESC, String.class, "");
+ c.addContainerProperty(PROPERTY_ID_CLASS, Class.class, null);
+ c.addContainerProperty(PROPERTY_ID_VIEWED, Embedded.class, null);
+ return c;
+ }
+
+ public void valueChange(ValueChangeEvent event) {
+ if (event.getProperty() == tree) {
+ final Object id = tree.getValue();
+ if (id == null) {
+ return;
+ }
+ final Item item = tree.getItem(id);
+ //
+ String newSection;
+ if (tree.isRoot(id)) {
+ newSection = ""; // show all sections
+ } else if (tree.hasChildren(id)) {
+ newSection = (String) item.getItemProperty(PROPERTY_ID_NAME)
+ .getValue();
+ } else {
+ newSection = (String) item
+ .getItemProperty(PROPERTY_ID_CATEGORY).getValue();
+ }
+
+ table.setValue(null);
+ final IndexedContainer c = (IndexedContainer) table
+ .getContainerDataSource();
+
+ if (newSection != null && !newSection.equals(section)) {
+ c.removeAllContainerFilters();
+ c.addContainerFilter(PROPERTY_ID_CATEGORY, newSection, false,
+ true);
+ }
+ section = newSection;
+ if (!tree.hasChildren(id)) {
+ // Example, not section
+ // update table selection
+ table.setValue(id);
+ }
+
+ } else if (event.getProperty() == table) {
+ if (table.getValue() != null) {
+ table.removeListener(this);
+ tree.setValue(table.getValue());
+ table.addListener(this);
+ final Item item = table.getItem(table.getValue());
+ final Class<?> c = (Class<?>) item.getItemProperty(
+ PROPERTY_ID_CLASS).getValue();
+ final Component component = getComponent(c);
+ if (component != null) {
+ final String caption = (String) item.getItemProperty(
+ PROPERTY_ID_NAME).getValue();
+ ts.removeAllComponents();
+ ts.addTab(component, caption, null);
+ }
+ // update "viewed" state
+ final Property p = item.getItemProperty(PROPERTY_ID_VIEWED);
+ if (p.getValue() == null) {
+ p.setValue(new Embedded("", new ThemeResource(
+ "icons/ok.png")));
+ }
+ table.requestRepaint();
+ }
+ }
+
+ }
+
+ private Component getComponent(Class<?> componentClass) {
+ if (!exampleInstances.containsKey(componentClass)) {
+ try {
+ final Component c = (Component) componentClass.newInstance();
+ exampleInstances.put(componentClass, c);
+ } catch (final Exception e) {
+ return null;
+ }
+ }
+ return (Component) exampleInstances.get(componentClass);
+ }
+
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/FormExample.java b/src/com/vaadin/automatedtests/featurebrowser/FormExample.java
new file mode 100644
index 0000000000..927f2ba978
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/FormExample.java
@@ -0,0 +1,212 @@
+package com.vaadin.automatedtests.featurebrowser;
+
+import java.io.Serializable;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Validator;
+import com.vaadin.data.util.BeanItem;
+import com.vaadin.ui.BaseFieldFactory;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Field;
+import com.vaadin.ui.Form;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+/**
+ * This example demonstrates the most important features of the Form component:
+ * binding Form to a JavaBean so that form fields are automatically generated
+ * from the bean properties, creation of custom field editors using a
+ * FieldFactory, customizing the form without FieldFactory, buffering
+ * (commit/discard) and validation. Please note that the example is quite a bit
+ * more complex than real use, as it tries to demonstrate more features than
+ * needed in general case.
+ */
+@SuppressWarnings("serial")
+public class FormExample extends CustomComponent {
+
+ static final String cities[] = { "Amsterdam", "Berlin", "Helsinki",
+ "Hong Kong", "London", "Luxemburg", "New York", "Oslo", "Paris",
+ "Rome", "Stockholm", "Tokyo", "Turku" };
+
+ /** Compose the demo. */
+ public FormExample() {
+
+ // Example data model
+ final Address dataModel = new Address();
+ Button peekDataModelState = new Button("Show the data model state",
+ new Button.ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ getWindow().showNotification(
+ dataModel.getAddressAsText());
+ }
+ });
+
+ // Example form
+ final AddressForm form = new AddressForm("Contact Information");
+ form.setDataSource(dataModel);
+ form
+ .setDescription("Please enter valid name and address. Fields marked with * are required. "
+ + "If you try to commit with invalid values, a form error message is displayed. "
+ + "(Address is required but failing to give it a value does not display an error.)");
+
+ // Layout the example
+ VerticalLayout root = new VerticalLayout();
+ root.setMargin(true);
+ root.setSpacing(true);
+ root.addComponent(form);
+ root.addComponent(peekDataModelState);
+ setCompositionRoot(root);
+ }
+
+ public static class AddressForm extends Form {
+
+ public AddressForm(String caption) {
+
+ setCaption(caption);
+
+ // Use custom field factory to modify the defaults on how the
+ // components are created
+ setFieldFactory(new MyFieldFactory());
+
+ // Add Commit and Discard controls to the form.
+ Button commit = new Button("Save", this, "commit");
+ Button discard = new Button("Reset", this, "discard");
+ HorizontalLayout footer = new HorizontalLayout();
+ footer.addComponent(commit);
+ footer.addComponent(discard);
+ setFooter(footer);
+ }
+
+ public void setDataSource(Address dataModel) {
+
+ // Set the form to edit given datamodel by converting pojo used as
+ // the datamodel to Item
+ setItemDataSource(new BeanItem(dataModel));
+
+ // Ensure that the fields are shown in correct order as the
+ // datamodel does not force any specific order.
+ setVisibleItemProperties(new String[] { "name", "streetAddress",
+ "postalCode", "city" });
+
+ // For examples sake, customize some of the form fields directly
+ // here. The alternative way is to use custom field factory as shown
+ // above.
+ getField("name").setRequired(true);
+ getField("name").setRequiredError("Name is missing");
+ getField("streetAddress").setRequired(true); // No error message
+ getField("postalCode").setRequired(true); // No error message
+ replaceWithSelect("city", cities, cities).setNewItemsAllowed(true);
+
+ // Set the form to act immediately on user input. This is
+ // automatically transports data between the client and the server
+ // to do server-side validation.
+ setImmediate(true);
+
+ // Enable buffering so that commit() must be called for the form
+ // before input is written to the data. (Form input is not written
+ // immediately through to the underlying object.)
+ setWriteThrough(false);
+ }
+ }
+
+ /**
+ * This is example on how to customize field creation. Any kind of field
+ * components could be created on the fly.
+ */
+ static class MyFieldFactory extends BaseFieldFactory implements
+ Serializable {
+
+ @Override
+ public Field createField(Item item, Object propertyId,
+ Component uiContext) {
+
+ Field field = super.createField(item, propertyId, uiContext);
+
+ if ("postalCode".equals(propertyId)) {
+ ((TextField) field).setColumns(5);
+ field.addValidator(new PostalCodeValidator());
+ }
+
+ return field;
+ }
+
+ }
+
+ /**
+ * This is an example of how to create a custom validator for automatic
+ * input validation.
+ */
+ static class PostalCodeValidator implements Validator {
+
+ public boolean isValid(Object value) {
+ if (value == null || !(value instanceof String)) {
+ return false;
+ }
+
+ return ((String) value).matches("[0-9]{5}");
+ }
+
+ public void validate(Object value) throws InvalidValueException {
+ if (!isValid(value)) {
+ throw new InvalidValueException(
+ "Postal code must be a five digit number.");
+ }
+ }
+ }
+
+ /**
+ * Contact information data model created as POJO. Note that in many cases
+ * it would be a good idea to implement Item -interface for the datamodel to
+ * make it directly bindable to form (without BeanItem wrapper)
+ */
+ public static class Address implements Serializable {
+
+ String name = "";
+ String streetAddress = "";
+ String postalCode = "";
+ String city;
+
+ public String getAddressAsText() {
+ return name + "\n" + streetAddress + "\n" + postalCode + " "
+ + (city == null ? "" : city);
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setStreetAddress(String address) {
+ streetAddress = address;
+ }
+
+ public String getStreetAddress() {
+ return streetAddress;
+ }
+
+ public void setPostalCode(String postalCode) {
+ this.postalCode = postalCode;
+ }
+
+ public String getPostalCode() {
+ return postalCode;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ public String getCity() {
+ return city;
+ }
+ }
+
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/GeneratedColumnExample.java b/src/com/vaadin/automatedtests/featurebrowser/GeneratedColumnExample.java
new file mode 100644
index 0000000000..260716a31d
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/GeneratedColumnExample.java
@@ -0,0 +1,561 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.featurebrowser;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Vector;
+
+import com.vaadin.data.Container;
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.Container.Indexed;
+import com.vaadin.data.util.BeanItem;
+import com.vaadin.ui.AbstractField;
+import com.vaadin.ui.BaseFieldFactory;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Field;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+
+/**
+ * This example demonstrates the use of generated columns in a table. Generated
+ * columns can be used for formatting values or calculating them from other
+ * columns (or properties of the items).
+ *
+ * For the data model, we use POJOs bound to a custom Container with BeanItem
+ * items.
+ *
+ * @author magi
+ */
+@SuppressWarnings("serial")
+public class GeneratedColumnExample extends CustomComponent {
+
+ /**
+ * The business model: fill-up at a gas station.
+ */
+ public class FillUp {
+ Date date;
+ double quantity;
+ double total;
+
+ public FillUp() {
+ }
+
+ public FillUp(int day, int month, int year, double quantity,
+ double total) {
+ date = new GregorianCalendar(year, month - 1, day).getTime();
+ this.quantity = quantity;
+ this.total = total;
+ }
+
+ /** Calculates price per unit of quantity (€/l). */
+ public double price() {
+ if (quantity != 0.0) {
+ return total / quantity;
+ } else {
+ return 0.0;
+ }
+ }
+
+ /** Calculates average daily consumption between two fill-ups. */
+ public double dailyConsumption(FillUp other) {
+ double difference_ms = date.getTime() - other.date.getTime();
+ double days = difference_ms / 1000 / 3600 / 24;
+ if (days < 0.5) {
+ days = 1.0; // Avoid division by zero if two fill-ups on the
+ // same day.
+ }
+ return quantity / days;
+ }
+
+ /** Calculates average daily consumption between two fill-ups. */
+ public double dailyCost(FillUp other) {
+ return price() * dailyConsumption(other);
+ }
+
+ // Getters and setters
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public double getQuantity() {
+ return quantity;
+ }
+
+ public void setQuantity(double quantity) {
+ this.quantity = quantity;
+ }
+
+ public double getTotal() {
+ return total;
+ }
+
+ public void setTotal(double total) {
+ this.total = total;
+ }
+ };
+
+ /**
+ * This is a custom container that allows adding BeanItems inside it. The
+ * BeanItem objects must be bound to an object. The item ID is an Integer
+ * from 0 to 99.
+ *
+ * Most of the interface methods are implemented with just dummy
+ * implementations, as they are not needed in this example.
+ */
+ public class MySimpleIndexedContainer implements Container, Indexed {
+
+ Vector<BeanItem> items;
+ Object itemtemplate;
+
+ public MySimpleIndexedContainer(Object itemtemplate) {
+ this.itemtemplate = itemtemplate;
+ items = new Vector<BeanItem>(); // Yeah this is just a test
+ }
+
+ public boolean addContainerProperty(Object propertyId, Class type,
+ Object defaultValue) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Item addItem(Object itemId) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object addItem() throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * This addItem method is specific for this container and allows adding
+ * BeanItem objects. The BeanItems must be bound to MyBean objects.
+ */
+ public void addItem(BeanItem item) throws UnsupportedOperationException {
+ items.add(item);
+ }
+
+ public boolean containsId(Object itemId) {
+ if (itemId instanceof Integer) {
+ int pos = ((Integer) itemId).intValue();
+ if (pos >= 0 && pos < items.size()) {
+ return items.get(pos) != null;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * The Table will call this method to get the property objects for the
+ * columns. It uses the property objects to determine the data types of
+ * the columns.
+ */
+ public Property getContainerProperty(Object itemId, Object propertyId) {
+ if (itemId instanceof Integer) {
+ int pos = ((Integer) itemId).intValue();
+ if (pos >= 0 && pos < items.size()) {
+ Item item = items.get(pos);
+
+ // The BeanItem provides the property objects for the items.
+ return item.getItemProperty(propertyId);
+ }
+ }
+ return null;
+ }
+
+ /** Table calls this to get the column names. */
+ public Collection getContainerPropertyIds() {
+ Item item = new BeanItem(itemtemplate);
+
+ // The BeanItem knows how to get the property names from the bean.
+ return item.getItemPropertyIds();
+ }
+
+ public Item getItem(Object itemId) {
+ if (itemId instanceof Integer) {
+ int pos = ((Integer) itemId).intValue();
+ if (pos >= 0 && pos < items.size()) {
+ return items.get(pos);
+ }
+ }
+ return null;
+ }
+
+ public Collection getItemIds() {
+ Vector ids = new Vector(items.size());
+ for (int i = 0; i < items.size(); i++) {
+ ids.add(Integer.valueOf(i));
+ }
+ return ids;
+ }
+
+ public Class getType(Object propertyId) {
+ return BeanItem.class;
+ }
+
+ public boolean removeAllItems() throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean removeContainerProperty(Object propertyId)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean removeItem(Object itemId)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int size() {
+ return items.size();
+ }
+
+ public Object addItemAt(int index) throws UnsupportedOperationException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Item addItemAt(int index, Object newItemId)
+ throws UnsupportedOperationException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Object getIdByIndex(int index) {
+ return Integer.valueOf(index);
+ }
+
+ public int indexOfId(Object itemId) {
+ return ((Integer) itemId).intValue();
+ }
+
+ public Object addItemAfter(Object previousItemId)
+ throws UnsupportedOperationException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Item addItemAfter(Object previousItemId, Object newItemId)
+ throws UnsupportedOperationException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Object firstItemId() {
+ return new Integer(0);
+ }
+
+ public boolean isFirstId(Object itemId) {
+ return ((Integer) itemId).intValue() == 0;
+ }
+
+ public boolean isLastId(Object itemId) {
+ return ((Integer) itemId).intValue() == (items.size() - 1);
+ }
+
+ public Object lastItemId() {
+ return new Integer(items.size() - 1);
+ }
+
+ public Object nextItemId(Object itemId) {
+ int pos = indexOfId(itemId);
+ if (pos >= items.size() - 1) {
+ return null;
+ }
+ return getIdByIndex(pos + 1);
+ }
+
+ public Object prevItemId(Object itemId) {
+ int pos = indexOfId(itemId);
+ if (pos <= 0) {
+ return null;
+ }
+ return getIdByIndex(pos - 1);
+ }
+ }
+
+ /** Formats the dates in a column containing Date objects. */
+ class DateColumnGenerator implements Table.ColumnGenerator {
+ /**
+ * Generates the cell containing the Date value. The column is
+ * irrelevant in this use case.
+ */
+ public Component generateCell(Table source, Object itemId,
+ Object columnId) {
+ Property prop = source.getItem(itemId).getItemProperty(columnId);
+ if (prop.getType().equals(Date.class)) {
+ Label label = new Label(String.format("%tF",
+ new Object[] { (Date) prop.getValue() }));
+ label.addStyleName("column-type-date");
+ return label;
+ }
+
+ return null;
+ }
+ }
+
+ /** Formats the value in a column containing Double objects. */
+ class ValueColumnGenerator implements Table.ColumnGenerator {
+ String format; /* Format string for the Double values. */
+
+ /** Creates double value column formatter with the given format string. */
+ public ValueColumnGenerator(String format) {
+ this.format = format;
+ }
+
+ /**
+ * Generates the cell containing the Double value. The column is
+ * irrelevant in this use case.
+ */
+ public Component generateCell(Table source, Object itemId,
+ Object columnId) {
+ Property prop = source.getItem(itemId).getItemProperty(columnId);
+ if (prop.getType().equals(Double.class)) {
+ Label label = new Label(String.format(format,
+ new Object[] { (Double) prop.getValue() }));
+
+ // Set styles for the column: one indicating that it's a value
+ // and a more
+ // specific one with the column name in it. This assumes that
+ // the column
+ // name is proper for CSS.
+ label.addStyleName("column-type-value");
+ label.addStyleName("column-" + (String) columnId);
+ return label;
+ }
+ return null;
+ }
+ }
+
+ /** Table column generator for calculating price column. */
+ class PriceColumnGenerator implements Table.ColumnGenerator {
+ public Component generateCell(Table source, Object itemId,
+ Object columnId) {
+ // Retrieve the item.
+ BeanItem item = (BeanItem) source.getItem(itemId);
+
+ // Retrieves the underlying POJO from the item.
+ FillUp fillup = (FillUp) item.getBean();
+
+ // Do the business logic
+ double price = fillup.price();
+
+ // Create the generated component for displaying the calcucated
+ // value.
+ Label label = new Label(String.format("%1.2f €",
+ new Object[] { new Double(price) }));
+
+ // We set the style here. You can't use a CellStyleGenerator for
+ // generated columns.
+ label.addStyleName("column-price");
+ return label;
+ }
+ }
+
+ /** Table column generator for calculating consumption column. */
+ class ConsumptionColumnGenerator implements Table.ColumnGenerator {
+
+ /**
+ * Generates a cell containing value calculated from the item.
+ */
+ public Component generateCell(Table source, Object itemId,
+ Object columnId) {
+ Indexed indexedSource = (Indexed) source.getContainerDataSource();
+
+ // Can not calculate consumption for the first item.
+ if (indexedSource.isFirstId(itemId)) {
+ Label label = new Label("N/A");
+ label.addStyleName("column-consumption");
+ return label;
+ }
+
+ // Index of the previous item.
+ Object prevItemId = indexedSource.prevItemId(itemId);
+
+ // Retrieve the POJOs.
+ FillUp fillup = (FillUp) ((BeanItem) indexedSource.getItem(itemId))
+ .getBean();
+ FillUp prev = (FillUp) ((BeanItem) source.getItem(prevItemId))
+ .getBean();
+
+ // Do the business logic
+ return generateCell(fillup, prev);
+ }
+
+ public Component generateCell(FillUp fillup, FillUp prev) {
+ double consumption = fillup.dailyConsumption(prev);
+
+ // Generate the component for displaying the calculated value.
+ Label label = new Label(String.format("%3.2f l",
+ new Object[] { new Double(consumption) }));
+
+ // We set the style here. You can't use a CellStyleGenerator for
+ // generated columns.
+ label.addStyleName("column-consumption");
+ return label;
+ }
+ }
+
+ /** Table column generator for calculating daily cost column. */
+ class DailyCostColumnGenerator extends ConsumptionColumnGenerator {
+
+ @Override
+ public Component generateCell(FillUp fillup, FillUp prev) {
+ double dailycost = fillup.dailyCost(prev);
+
+ // Generate the component for displaying the calculated value.
+ Label label = new Label(String.format("%3.2f €",
+ new Object[] { new Double(dailycost) }));
+
+ // We set the style here. You can't use a CellStyleGenerator for
+ // generated columns.
+ label.addStyleName("column-dailycost");
+ return label;
+ }
+ }
+
+ /**
+ * Custom field factory that sets the fields as immediate.
+ */
+ public class ImmediateFieldFactory extends BaseFieldFactory {
+ @Override
+ public Field createField(Class type, Component uiContext) {
+ // Let the BaseFieldFactory create the fields
+ Field field = super.createField(type, uiContext);
+
+ // ...and just set them as immediate
+ ((AbstractField) field).setImmediate(true);
+
+ return field;
+ }
+ }
+
+ public GeneratedColumnExample() {
+ final Table table = new Table();
+
+ // Define table columns. These include also the column for the generated
+ // column, because we want to set the column label to something
+ // different than the property ID.
+ table
+ .addContainerProperty("date", Date.class, null, "Date", null,
+ null);
+ table.addContainerProperty("quantity", Double.class, null,
+ "Quantity (l)", null, null);
+ table.addContainerProperty("price", Double.class, null, "Price (€/l)",
+ null, null);
+ table.addContainerProperty("total", Double.class, null, "Total (€)",
+ null, null);
+ table.addContainerProperty("consumption", Double.class, null,
+ "Consumption (l/day)", null, null);
+ table.addContainerProperty("dailycost", Double.class, null,
+ "Daily Cost (€/day)", null, null);
+
+ // Define the generated columns and their generators.
+ table.addGeneratedColumn("date", new DateColumnGenerator());
+ table
+ .addGeneratedColumn("quantity", new ValueColumnGenerator(
+ "%.2f l"));
+ table.addGeneratedColumn("price", new PriceColumnGenerator());
+ table.addGeneratedColumn("total", new ValueColumnGenerator("%.2f €"));
+ table.addGeneratedColumn("consumption",
+ new ConsumptionColumnGenerator());
+ table.addGeneratedColumn("dailycost", new DailyCostColumnGenerator());
+
+ // Create a data source and bind it to the table.
+ MySimpleIndexedContainer data = new MySimpleIndexedContainer(
+ new FillUp());
+ table.setContainerDataSource(data);
+
+ // Generated columns are automatically placed after property columns, so
+ // we have to set the order of the columns explicitly.
+ table.setVisibleColumns(new Object[] { "date", "quantity", "price",
+ "total", "consumption", "dailycost" });
+
+ // Add some data.
+ data.addItem(new BeanItem(new FillUp(19, 2, 2005, 44.96, 51.21)));
+ data.addItem(new BeanItem(new FillUp(30, 3, 2005, 44.91, 53.67)));
+ data.addItem(new BeanItem(new FillUp(20, 4, 2005, 42.96, 49.06)));
+ data.addItem(new BeanItem(new FillUp(23, 5, 2005, 47.37, 55.28)));
+ data.addItem(new BeanItem(new FillUp(6, 6, 2005, 35.34, 41.52)));
+ data.addItem(new BeanItem(new FillUp(30, 6, 2005, 16.07, 20.00)));
+ data.addItem(new BeanItem(new FillUp(2, 7, 2005, 36.40, 36.19)));
+ data.addItem(new BeanItem(new FillUp(6, 7, 2005, 39.17, 50.90)));
+ data.addItem(new BeanItem(new FillUp(27, 7, 2005, 43.43, 53.03)));
+ data.addItem(new BeanItem(new FillUp(17, 8, 2005, 20, 29.18)));
+ data.addItem(new BeanItem(new FillUp(30, 8, 2005, 46.06, 59.09)));
+ data.addItem(new BeanItem(new FillUp(22, 9, 2005, 46.11, 60.36)));
+ data.addItem(new BeanItem(new FillUp(14, 10, 2005, 41.51, 50.19)));
+ data.addItem(new BeanItem(new FillUp(12, 11, 2005, 35.24, 40.00)));
+ data.addItem(new BeanItem(new FillUp(28, 11, 2005, 45.26, 53.27)));
+
+ // Have a check box that allows the user to make the quantity
+ // and total columns editable.
+ final CheckBox editable = new CheckBox(
+ "Edit the input values - calculated columns are regenerated");
+ editable.setImmediate(true);
+ editable.addListener(new ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ table.setEditable(editable.booleanValue());
+
+ // The columns may not be generated when we want to have them
+ // editable.
+ if (editable.booleanValue()) {
+ table.removeGeneratedColumn("quantity");
+ table.removeGeneratedColumn("total");
+ } else {
+ // In non-editable mode we want to show the formatted
+ // values.
+ table.addGeneratedColumn("quantity",
+ new ValueColumnGenerator("%.2f l"));
+ table.addGeneratedColumn("total", new ValueColumnGenerator(
+ "%.2f €"));
+ }
+ // The visible columns are affected by removal and addition of
+ // generated columns so we have to redefine them.
+ table.setVisibleColumns(new Object[] { "date", "quantity",
+ "price", "total", "consumption", "dailycost" });
+ }
+ });
+
+ // Use a custom field factory to set the edit fields as immediate.
+ // This is used when the table is in editable mode.
+ table.setFieldFactory(new ImmediateFieldFactory());
+
+ // Setting the table itself as immediate has no relevance in this
+ // example,
+ // because it is relevant only if the table is selectable and we want to
+ // get the selection changes immediately.
+ table.setImmediate(true);
+
+ table.setHeight("300px");
+
+ VerticalLayout layout = new VerticalLayout();
+ layout.setMargin(true);
+ layout
+ .addComponent(new Label(
+ "Table with column generators that format and calculate cell values."));
+ layout.addComponent(table);
+ layout.addComponent(editable);
+ layout.addComponent(new Label(
+ "Columns displayed in blue are calculated from Quantity and Total. "
+ + "Others are simply formatted."));
+ layout.setExpandRatio(table, 1);
+ layout.setSizeUndefined();
+ setCompositionRoot(layout);
+ // setSizeFull();
+ }
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/JavaScriptAPIExample.java b/src/com/vaadin/automatedtests/featurebrowser/JavaScriptAPIExample.java
new file mode 100644
index 0000000000..d902eb8323
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/JavaScriptAPIExample.java
@@ -0,0 +1,97 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.featurebrowser;
+
+import java.util.Date;
+
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+/**
+ * An example using a RichTextArea to edit a Label in XHTML-mode.
+ *
+ */
+public class JavaScriptAPIExample extends CustomComponent {
+
+ public static final String txt = "<p>For advanced client side programmers Toolkit offers a simple method which can be used to force sync client with server. This may be needed for example if another part of a mashup changes things on server.</p> (more examples will be added here as the APIs are made public)<br/><br/><A href=\"javascript:itmill.forceSync();\">javascript:itmill.forceSync();</A>";
+
+ private final VerticalLayout main;
+ private final Label l;
+ private final TextField editor = new TextField();
+
+ public JavaScriptAPIExample() {
+ // main layout
+ main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+ editor.setRows(7);
+ editor.setColumns(50);
+ // Add the label
+ l = new Label(txt);
+ l.setContentMode(Label.CONTENT_XHTML);
+ main.addComponent(l);
+ // Edit button with inline click-listener
+ Button b = new Button("Edit", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ // swap Label <-> RichTextArea
+ if (main.getComponentIterator().next() == l) {
+ editor.setValue(l.getValue());
+ main.replaceComponent(l, editor);
+ event.getButton().setCaption("Save");
+ } else {
+ l.setValue(editor.getValue());
+ main.replaceComponent(editor, l);
+ event.getButton().setCaption("Edit");
+ }
+ }
+ });
+ main.addComponent(b);
+ main.setComponentAlignment(b, Alignment.MIDDLE_RIGHT);
+
+ //
+ Label l = new Label(
+ "This label will update it's server-side value AFTER it's rendered to the client-side. "
+ + "The client will be synchronized on reload, when you click a button, "
+ + "or when itmill.forceSync() is called.") {
+
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+
+ super.paintContent(target);
+ Delay d = new Delay(this);
+ d.start();
+ }
+
+ };
+ main.addComponent(l);
+
+ }
+
+ private class Delay extends Thread {
+ Label label;
+
+ public Delay(Label l) {
+ label = l;
+ }
+
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(500);
+ label.setValue(new Date().toString());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ }
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/LabelExample.java b/src/com/vaadin/automatedtests/featurebrowser/LabelExample.java
new file mode 100644
index 0000000000..37b946824d
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/LabelExample.java
@@ -0,0 +1,84 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.featurebrowser;
+
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Panel;
+
+/**
+ * Shows a few variations of Labels, including the effects of XHTML- and
+ * pre-formatted mode.
+ *
+ * @author IT Mill Ltd.
+ */
+public class LabelExample extends CustomComponent {
+
+ private static final String xhtml = "This text has <b>HTML</b> formatting.<br/>"
+ + "A plain <i>Label</i> will show the markup, while a <u>XHTML-mode</u>"
+ + " <i>Label</i> will show the formatted text.";
+
+ private static final String pre = "This text has linebreaks.\n\n"
+ + "They will show up in a preformatted Label,\n"
+ + "but not in a \"plain\" Label.\n\n"
+ + " This is an indented row. \n Same indentation here.";
+
+ public LabelExample() {
+ final GridLayout g = new GridLayout(2, 4);
+ g.setMargin(true);
+ setCompositionRoot(g);
+ g.setWidth("100%");
+
+ // plain w/o caption
+ Panel p = getExpamplePanel("Plain");
+ Label l = new Label("A plain label without caption.");
+ l.setDebugId("label1");
+ p.addComponent(l);
+ g.addComponent(p);
+ // plain w/ caption
+ p = getExpamplePanel("Plain w/ caption + tooltip");
+ l = new Label("A plain label with caption.");
+ l.setCaption("Label caption");
+ l.setDebugId("label2");
+ l.setDescription("This is a description (tooltip) for the label.");
+ p.addComponent(l);
+ g.addComponent(p);
+ // plain w/ xhtml
+ p = getExpamplePanel("Plain w/ XHTML content");
+ l = new Label(xhtml);
+ l.setDebugId("label3");
+ p.addComponent(l);
+ g.addComponent(p);
+ // xhtml w/ xhtml
+ p = getExpamplePanel("XHTML-mode w/ XHTML content");
+ l = new Label(xhtml);
+ l.setDebugId("label4");
+ l.setContentMode(Label.CONTENT_XHTML);
+ p.addComponent(l);
+ g.addComponent(p);
+ // plain w/ preformatted
+ p = getExpamplePanel("Plain w/ preformatted content");
+ l = new Label(pre);
+ l.setDebugId("label5");
+ p.addComponent(l);
+ g.addComponent(p);
+ // preformatted w/ preformatted
+ p = getExpamplePanel("Preformatted-mode w/ preformatted content");
+ l = new Label(pre);
+ l.setDebugId("label6");
+ l.setContentMode(Label.CONTENT_PREFORMATTED);
+ p.addComponent(l);
+ g.addComponent(p);
+
+ }
+
+ private Panel getExpamplePanel(String caption) {
+ Panel p = new Panel(caption);
+ p.setDebugId(p.getCaption());
+ p.addStyleName(Panel.STYLE_LIGHT);
+ return p;
+ }
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/LayoutExample.java b/src/com/vaadin/automatedtests/featurebrowser/LayoutExample.java
new file mode 100644
index 0000000000..d5a0773fe2
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/LayoutExample.java
@@ -0,0 +1,93 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.featurebrowser;
+
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.VerticalLayout;
+
+/**
+ * A few examples of layout possibilities.
+ *
+ * @author IT Mill Ltd.
+ */
+public class LayoutExample extends CustomComponent {
+
+ public LayoutExample() {
+
+ final VerticalLayout main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ final GridLayout g = new GridLayout(2, 5);
+ g.setWidth("100%");
+ main.addComponent(g);
+
+ // panel
+ Panel p = new Panel("This is a normal panel");
+ p.setDebugId("NormalPanel");
+ Label l = new Label("A normal panel.");
+ p.addComponent(l);
+ g.addComponent(p);
+ // lightpanel
+ p = new Panel("This is a light panel");
+ p.setDebugId("LightPanel");
+ p.setStyleName(Panel.STYLE_LIGHT);
+ l = new Label("A light-style panel.");
+ p.addComponent(l);
+ g.addComponent(p);
+
+ TabSheet ts = new TabSheet();
+ g.addComponent(ts, 0, 1, 1, 1);
+
+ VerticalLayout ol = new VerticalLayout();
+ ol.setDebugId("VerticalOrderedLayout");
+ ol.setMargin(true);
+ ol.addComponent(new Label("Component 1"));
+ ol.addComponent(new Label("Component 2"));
+ ol.addComponent(new Label("Component 3"));
+ ts.addTab(ol, "Vertical OrderedLayout", null);
+
+ HorizontalLayout hl = new HorizontalLayout();
+ hl.setDebugId("HorizontalOrderedLayout");
+ hl.setMargin(true);
+ hl.addComponent(new Label("Component 1"));
+ hl.addComponent(new Label("Component 2"));
+ hl.addComponent(new Label("Component 3"));
+ ts.addTab(hl, "Horizontal OrderedLayout", null);
+
+ final GridLayout gl = new GridLayout(3, 3);
+ gl.setDebugId("GridLayout");
+ gl.setMargin(true);
+ gl.addComponent(new Label("Component 1.1"));
+ gl.addComponent(new Label("Component 1.2"));
+ gl.addComponent(new Label("Component 1.3"));
+ gl.addComponent(new Label("Component 2.2"), 1, 1);
+ gl.addComponent(new Label("Component 3.1"), 0, 2);
+ gl.addComponent(new Label("Component 3.3"), 2, 2);
+ ts.addTab(gl, "GridLayout", null);
+
+ /*- TODO spitpanel removed for now - do we need it here?
+ ts = new TabSheet();
+ ts.setHeight(150);
+ g.addComponent(ts, 0, 2, 1, 2);
+
+ SplitPanel sp = new SplitPanel();
+ sp.addComponent(new Label("Component 1"));
+ sp.addComponent(new Label("Component 2"));
+ ts.addTab(sp, "Vertical SplitPanel", null);
+
+ sp = new SplitPanel(SplitPanel.ORIENTATION_HORIZONTAL);
+ sp.addComponent(new Label("Component 1"));
+ sp.addComponent(new Label("Component 2"));
+ ts.addTab(sp, "Horizontal SplitPanel", null);
+ -*/
+
+ }
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/NotificationExample.java b/src/com/vaadin/automatedtests/featurebrowser/NotificationExample.java
new file mode 100644
index 0000000000..f3d46a7d00
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/NotificationExample.java
@@ -0,0 +1,95 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.featurebrowser;
+
+import com.vaadin.data.Item;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.RichTextArea;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+
+/**
+ * Demonstrates the use of Notifications.
+ *
+ * @author IT Mill Ltd.
+ * @see com.vaadin.ui.Window
+ */
+public class NotificationExample extends CustomComponent {
+
+ // Dropdown select for notification type, using the native dropdown
+ NativeSelect type;
+ // Textfield for the notification caption
+ TextField caption;
+ // Textfield for the notification content
+ TextField message;
+
+ /**
+ * Default constructor; We're subclassing CustomComponent, so we need to
+ * choose a root component and set it as composition root.
+ */
+ public NotificationExample() {
+ // Main layout
+ final VerticalLayout main = new VerticalLayout();
+ main.setSizeUndefined();
+ main.setSpacing(true);
+ main.setMargin(true); // use theme-specific margin
+ setCompositionRoot(main);
+
+ // Create the 'type' dropdown select.
+ type = new NativeSelect("Notification type");
+ main.addComponent(type);
+ // no empty selection allowed
+ type.setNullSelectionAllowed(false);
+ // we want a different caption than the value
+ type.addContainerProperty("caption", String.class, null);
+ type.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);
+ type.setItemCaptionPropertyId("caption");
+ // add some content (items) using the Container API
+ Item i = type.addItem(new Integer(
+ Window.Notification.TYPE_HUMANIZED_MESSAGE));
+ i.getItemProperty("caption").setValue("Humanized message");
+ i = type.addItem(new Integer(Window.Notification.TYPE_WARNING_MESSAGE));
+ i.getItemProperty("caption").setValue("Warning message");
+ i = type.addItem(new Integer(Window.Notification.TYPE_ERROR_MESSAGE));
+ i.getItemProperty("caption").setValue("Error message");
+ i = type
+ .addItem(new Integer(Window.Notification.TYPE_TRAY_NOTIFICATION));
+ i.getItemProperty("caption").setValue("Tray notification");
+ // set the initially selected item
+ type.setValue(new Integer(Window.Notification.TYPE_HUMANIZED_MESSAGE));
+
+ // Notification caption
+ caption = new TextField("Caption");
+ main.addComponent(caption);
+ caption.setColumns(20);
+ caption.setValue("Brown Fox!");
+
+ // Notification message
+ message = new RichTextArea();
+ main.addComponent(message);
+ message.setCaption("Message");
+ message.setValue("A quick one jumped over the lazy dog.");
+
+ // Button to show the notification
+ final Button b = new Button("Show notification", new ClickListener() {
+ // this is an inline ClickListener
+ public void buttonClick(ClickEvent event) {
+ // show the notification
+ getWindow().showNotification((String) caption.getValue(),
+ (String) message.getValue(),
+ ((Integer) type.getValue()).intValue());
+ }
+ });
+ main.addComponent(b);
+ main.setComponentAlignment(b, Alignment.MIDDLE_RIGHT);
+ }
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/RichTextExample.java b/src/com/vaadin/automatedtests/featurebrowser/RichTextExample.java
new file mode 100644
index 0000000000..0fb21b2200
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/RichTextExample.java
@@ -0,0 +1,63 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.featurebrowser;
+
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.RichTextArea;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+/**
+ * An example using a RichTextArea to edit a Label in XHTML-mode.
+ *
+ */
+public class RichTextExample extends CustomComponent {
+
+ public static final String txt = "<h1>RichText editor example</h1>"
+ + "To edit this text, press the <b>Edit</b> button below."
+ + "<br/>"
+ + "See the <A href=\"http://www.itmill.com/documentation/itmill-toolkit-5-reference-manual/\">manual</a> "
+ + "for more information.";
+
+ private final VerticalLayout main;
+ private final Label l;
+ private final RichTextArea editor = new RichTextArea();
+ private final Button b;
+
+ public RichTextExample() {
+ // main layout
+ main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ editor.setWidth("100%");
+
+ // Add the label
+ l = new Label(txt);
+ l.setContentMode(Label.CONTENT_XHTML);
+ main.addComponent(l);
+ // Edit button with inline click-listener
+ b = new Button("Edit", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ // swap Label <-> RichTextArea
+ if (main.getComponentIterator().next() == l) {
+ editor.setValue(l.getValue());
+ main.replaceComponent(l, editor);
+ b.setCaption("Save");
+ } else {
+ l.setValue(editor.getValue());
+ main.replaceComponent(editor, l);
+ b.setCaption("Edit");
+ }
+ }
+ });
+ main.addComponent(b);
+ main.setComponentAlignment(b, Alignment.MIDDLE_RIGHT);
+ }
+
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/SelectExample.java b/src/com/vaadin/automatedtests/featurebrowser/SelectExample.java
new file mode 100644
index 0000000000..ab6711efce
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/SelectExample.java
@@ -0,0 +1,108 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.featurebrowser;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Field;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.ListSelect;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.OptionGroup;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.TwinColSelect;
+import com.vaadin.ui.VerticalLayout;
+
+/**
+ * Shows some basic fields for value input; TextField, DateField, Slider...
+ *
+ * @author IT Mill Ltd.
+ */
+public class SelectExample extends CustomComponent {
+
+ // listener that shows a value change notification
+ private final Field.ValueChangeListener listener = new Field.ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ getWindow().showNotification("" + event.getProperty().getValue());
+ }
+ };
+
+ public SelectExample() {
+ final VerticalLayout main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ final HorizontalLayout horiz = new HorizontalLayout();
+ horiz.setWidth("100%");
+ main.addComponent(horiz);
+ final Panel single = new Panel("Single selects");
+ single.setStyleName(Panel.STYLE_LIGHT);
+ horiz.addComponent(single);
+ final Panel multi = new Panel("Multi selects");
+ multi.setStyleName(Panel.STYLE_LIGHT);
+ horiz.addComponent(multi);
+
+ // radio button group
+ AbstractSelect sel = new OptionGroup("OptionGroup");
+ sel.setDebugId("RadioButtons");
+ initSelect(sel);
+ single.addComponent(sel);
+ // checkbox group
+ sel = new OptionGroup("OptionGroup");
+ sel.setDebugId("OptionGroup");
+ sel.setMultiSelect(true); // TODO: throws if set after listener - why?
+ initSelect(sel);
+ multi.addComponent(sel);
+ // single-select list
+ sel = new ListSelect("ListSelect");
+ sel.setDebugId("SingleListSelect");
+ ((ListSelect) sel).setColumns(15);
+ initSelect(sel);
+ single.addComponent(sel);
+ // multi-select list
+ sel = new ListSelect("ListSelect");
+ sel.setDebugId("MultiListSelect");
+ ((ListSelect) sel).setColumns(15);
+ sel.setMultiSelect(true);
+ initSelect(sel);
+ multi.addComponent(sel);
+ // native-style dropdows
+ sel = new NativeSelect("NativeSelect");
+ sel.setDebugId("NativeSelect");
+ ((NativeSelect) sel).setColumns(15);
+ initSelect(sel);
+ single.addComponent(sel);
+ // combobox
+ sel = new ComboBox("ComboBox");
+ sel.setDebugId("ComboBox");
+ ((ComboBox) sel).setColumns(15);
+ initSelect(sel);
+ single.addComponent(sel);
+ // "twin column" select
+ sel = new TwinColSelect("TwinColSelect");
+ sel.setDebugId("TwinColSelect");
+ ((TwinColSelect) sel).setColumns(15);
+ initSelect(sel);
+ multi.addComponent(sel);
+ }
+
+ /*
+ * Initialize select with some values, make immediate and add listener.
+ */
+ private void initSelect(AbstractSelect sel) {
+ for (int i = 1; i <= 5; i++) {
+ sel.addItem("Item " + i);
+ }
+ // select one item
+ sel.select("Item 1");
+
+ // make immediate, add listener
+ sel.setImmediate(true);
+ sel.addListener(listener);
+ }
+
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/TableExample.java b/src/com/vaadin/automatedtests/featurebrowser/TableExample.java
new file mode 100644
index 0000000000..b1b4fccf6f
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/TableExample.java
@@ -0,0 +1,302 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.featurebrowser;
+
+import java.util.Iterator;
+import java.util.Random;
+import java.util.Set;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.event.Action;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+/**
+ * Table example.
+ *
+ * @author IT Mill Ltd.
+ */
+public class TableExample extends CustomComponent implements Action.Handler,
+ Button.ClickListener {
+
+ // Actions
+ private static final Action ACTION_SAVE = new Action("Save");
+ private static final Action ACTION_DELETE = new Action("Delete");
+ private static final Action ACTION_HIRE = new Action("Hire");
+ // Action sets
+ private static final Action[] ACTIONS_NOHIRE = new Action[] { ACTION_SAVE,
+ ACTION_DELETE };
+ private static final Action[] ACTIONS_HIRE = new Action[] { ACTION_HIRE,
+ ACTION_SAVE, ACTION_DELETE };
+ // Properties
+ private static final Object PROPERTY_SPECIES = "Species";
+ private static final Object PROPERTY_TYPE = "Type";
+ private static final Object PROPERTY_KIND = "Kind";
+ private static final Object PROPERTY_HIRED = "Hired";
+
+ // "global" components
+ Table source;
+ Table saved;
+ Button saveSelected;
+ Button hireSelected;
+ Button deleteSelected;
+ Button deselect;
+
+ public TableExample() {
+ VerticalLayout margin = new VerticalLayout();
+ margin.setMargin(true);
+
+ TabSheet root = new TabSheet();
+ setCompositionRoot(margin);
+ margin.addComponent(root);
+
+ // main layout
+ final VerticalLayout main = new VerticalLayout();
+ root.addComponent(main);
+ main.setCaption("Basic Table");
+ main.setMargin(true);
+
+ // "source" table with bells & whistlesenabled
+ source = new Table("All creatures");
+ source.setPageLength(7);
+ source.setWidth("550px");
+ source.setColumnCollapsingAllowed(true);
+ source.setColumnReorderingAllowed(true);
+ source.setSelectable(true);
+ source.setMultiSelect(true);
+ source.setRowHeaderMode(Table.ROW_HEADER_MODE_ID);
+ fillTable(source);
+ source.addActionHandler(this);
+ main.addComponent(source);
+ source.setDebugId("AllCreatures");
+
+ // x-selected button row
+ final HorizontalLayout horiz = new HorizontalLayout();
+
+ horiz.setMargin(false, false, true, false);
+ main.addComponent(horiz);
+ saveSelected = new Button("Save selected");
+ saveSelected.setStyleName(Button.STYLE_LINK);
+ saveSelected.addListener(this);
+ horiz.addComponent(saveSelected);
+ hireSelected = new Button("Hire selected");
+ hireSelected.setStyleName(Button.STYLE_LINK);
+ hireSelected.addListener(this);
+ horiz.addComponent(hireSelected);
+ deleteSelected = new Button("Delete selected");
+ deleteSelected.setStyleName(Button.STYLE_LINK);
+ deleteSelected.addListener(this);
+ horiz.addComponent(deleteSelected);
+ deselect = new Button("Deselect all");
+ deselect.setStyleName(Button.STYLE_LINK);
+ deselect.addListener(this);
+ horiz.addComponent(deselect);
+ final CheckBox editmode = new CheckBox("Editmode ");
+ editmode.setDebugId("editMode");
+ editmode.addListener(new CheckBox.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ source.setEditable(((Boolean) event.getButton().getValue())
+ .booleanValue());
+ }
+ });
+ editmode.setImmediate(true);
+ horiz.addComponent(editmode);
+
+ // "saved" table, minimalistic
+ saved = new Table("Saved creatures");
+ saved.setPageLength(5);
+ saved.setWidth("550px");
+ saved.setSelectable(false);
+ saved.setColumnHeaderMode(Table.COLUMN_HEADER_MODE_HIDDEN);
+ saved.setRowHeaderMode(Table.ROW_HEADER_MODE_ID);
+ initProperties(saved);
+ saved.addActionHandler(this);
+ main.addComponent(saved);
+ saved.setDebugId("SavedCreatures");
+
+ final CheckBox b = new CheckBox("Modify saved creatures");
+ b.setDebugId("modifySavedCreatures");
+ b.addListener(new CheckBox.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ saved.setEditable(((Boolean) event.getButton().getValue())
+ .booleanValue());
+ }
+ });
+ b.setImmediate(true);
+ main.addComponent(b);
+
+ GeneratedColumnExample gencols = new GeneratedColumnExample();
+ gencols.setCaption("Generated Columns");
+ root.addComponent(gencols);
+ }
+
+ // set up the properties (columns)
+ private void initProperties(Table table) {
+ table.addContainerProperty(PROPERTY_SPECIES, String.class, "");
+ table.addContainerProperty(PROPERTY_TYPE, String.class, "");
+ table.addContainerProperty(PROPERTY_KIND, String.class, "");
+ table
+ .addContainerProperty(PROPERTY_HIRED, Boolean.class,
+ Boolean.FALSE);
+ }
+
+ // fill the table with some random data
+ private void fillTable(Table table) {
+ initProperties(table);
+
+ final String[] sp = new String[] { "Fox", "Dog", "Cat", "Moose",
+ "Penguin", "Cow" };
+ final String[] ty = new String[] { "Quick", "Lazy", "Sleepy",
+ "Fidgety", "Crazy", "Kewl" };
+ final String[] ki = new String[] { "Jumping", "Walking", "Sleeping",
+ "Skipping", "Dancing" };
+
+ Random r = new Random(5);
+
+ for (int i = 0; i < 100; i++) {
+ final String s = sp[(int) (r.nextDouble() * sp.length)];
+ final String t = ty[(int) (r.nextDouble() * ty.length)];
+ final String k = ki[(int) (r.nextDouble() * ki.length)];
+ table.addItem(new Object[] { s, t, k, Boolean.FALSE }, new Integer(
+ i));
+ }
+
+ }
+
+ // Called for each item (row), returns valid actions for that item
+ public Action[] getActions(Object target, Object sender) {
+ if (sender == source) {
+ final Item item = source.getItem(target);
+ // save, delete, and hire if not already hired
+ if (item != null
+ && item.getItemProperty(PROPERTY_HIRED).getValue() == Boolean.FALSE) {
+ return ACTIONS_HIRE;
+ } else {
+ return ACTIONS_NOHIRE;
+ }
+ } else {
+ // "saved" table only has one action
+ return new Action[] { ACTION_DELETE };
+ }
+ }
+
+ // called when an action is invoked on an item (row)
+ public void handleAction(Action action, Object sender, Object target) {
+ if (sender == source) {
+ Item item = source.getItem(target);
+ if (action == ACTION_HIRE) {
+ // set HIRED property to true
+ item.getItemProperty(PROPERTY_HIRED).setValue(Boolean.TRUE);
+ if (saved.containsId(target)) {
+ item = saved.getItem(target);
+ item.getItemProperty(PROPERTY_HIRED).setValue(Boolean.TRUE);
+ }
+ getWindow().showNotification("Hired", "" + item);
+
+ } else if (action == ACTION_SAVE) {
+ if (saved.containsId(target)) {
+ // let's not save twice
+ getWindow().showNotification("Already saved", "" + item);
+ return;
+ }
+ // "manual" copy of the item properties we want
+ final Item added = saved.addItem(target);
+ Property p = added.getItemProperty(PROPERTY_SPECIES);
+ p.setValue(item.getItemProperty(PROPERTY_SPECIES).getValue());
+ p = added.getItemProperty(PROPERTY_TYPE);
+ p.setValue(item.getItemProperty(PROPERTY_TYPE).getValue());
+ p = added.getItemProperty(PROPERTY_KIND);
+ p.setValue(item.getItemProperty(PROPERTY_KIND).getValue());
+ p = added.getItemProperty(PROPERTY_HIRED);
+ p.setValue(item.getItemProperty(PROPERTY_HIRED).getValue());
+ getWindow().showNotification("Saved", "" + item);
+ } else {
+ // ACTION_DELETE
+ getWindow().showNotification("Deleted ", "" + item);
+ source.removeItem(target);
+ }
+
+ } else {
+ // sender==saved
+ if (action == ACTION_DELETE) {
+ final Item item = saved.getItem(target);
+ getWindow().showNotification("Deleted", "" + item);
+ saved.removeItem(target);
+ }
+ }
+ }
+
+ public void buttonClick(ClickEvent event) {
+ final Button b = event.getButton();
+ if (b == deselect) {
+ source.setValue(null);
+ } else if (b == saveSelected) {
+ // loop each selected and copy to "saved" table
+ final Set selected = (Set) source.getValue();
+ int s = 0;
+ for (final Iterator it = selected.iterator(); it.hasNext();) {
+ final Object id = it.next();
+ if (!saved.containsId(id)) {
+ final Item item = source.getItem(id);
+ final Item added = saved.addItem(id);
+ // "manual" copy of the properties we want
+ Property p = added.getItemProperty(PROPERTY_SPECIES);
+ p.setValue(item.getItemProperty(PROPERTY_SPECIES)
+ .getValue());
+ p = added.getItemProperty(PROPERTY_TYPE);
+ p.setValue(item.getItemProperty(PROPERTY_TYPE).getValue());
+ p = added.getItemProperty(PROPERTY_KIND);
+ p.setValue(item.getItemProperty(PROPERTY_KIND).getValue());
+ p = added.getItemProperty(PROPERTY_HIRED);
+ p.setValue(item.getItemProperty(PROPERTY_HIRED).getValue());
+ s++;
+ }
+ }
+ getWindow().showNotification("Saved " + s);
+
+ } else if (b == hireSelected) {
+ // loop each selected and set property HIRED to true
+ int s = 0;
+ final Set selected = (Set) source.getValue();
+ for (final Iterator it = selected.iterator(); it.hasNext();) {
+ final Object id = it.next();
+ Item item = source.getItem(id);
+ final Property p = item.getItemProperty(PROPERTY_HIRED);
+ if (p.getValue() == Boolean.FALSE) {
+ p.setValue(Boolean.TRUE);
+ s++;
+ }
+ if (saved.containsId(id)) {
+ // also update "saved" table
+ item = saved.getItem(id);
+ item.getItemProperty(PROPERTY_HIRED).setValue(Boolean.TRUE);
+ }
+ }
+ getWindow().showNotification("Hired " + s);
+
+ } else {
+ // loop trough selected and delete
+ int s = 0;
+ final Set selected = (Set) source.getValue();
+ for (final Iterator it = selected.iterator(); it.hasNext();) {
+ final Object id = it.next();
+ if (source.containsId(id)) {
+ s++;
+ source.removeItem(id);
+ }
+ }
+ getWindow().showNotification("Deleted " + s);
+ }
+
+ }
+
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/TreeExample.java b/src/com/vaadin/automatedtests/featurebrowser/TreeExample.java
new file mode 100644
index 0000000000..cf5a6a7f33
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/TreeExample.java
@@ -0,0 +1,164 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.featurebrowser;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.event.Action;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.Tree;
+
+/**
+ * Demonstrates basic Tree -functionality. Actions are used for add/remove item
+ * functionality, and a ValueChangeListener reacts to both the Tree and the
+ * TextField.
+ */
+public class TreeExample extends CustomComponent implements Action.Handler,
+ Tree.ValueChangeListener {
+
+ private static final Action ADD = new Action("Add item");
+ private static final Action DELETE = new Action("Delete item");
+ private static final Action[] actions = new Action[] { ADD, DELETE };
+
+ // Id for the caption property
+ private static final Object CAPTION_PROPERTY = "caption";
+
+ private static final String desc = "Try both right- and left-click!";
+
+ Tree tree;
+ TextField editor;
+
+ public TreeExample() {
+ final HorizontalLayout main = new HorizontalLayout();
+ main.setWidth("100%");
+ main.setDebugId("mainLayout");
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ // Panel w/ Tree
+ Panel p = new Panel("Select item");
+ p.setStyleName(Panel.STYLE_LIGHT);
+ p.setWidth("250px");
+ // Description
+ p.addComponent(new Label(desc));
+ // Tree with a few items
+ tree = new Tree();
+ tree.setDebugId("tree");
+ tree.setImmediate(true);
+ // we'll use a property for caption instead of the item id ("value"),
+ // so that multiple items can have the same caption
+ tree.addContainerProperty(CAPTION_PROPERTY, String.class, "");
+ tree.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);
+ tree.setItemCaptionPropertyId(CAPTION_PROPERTY);
+ for (int i = 1; i <= 3; i++) {
+ final Object id = addCaptionedItem("Section " + i, null);
+ tree.expandItem(id);
+ addCaptionedItem("Team A", id);
+ addCaptionedItem("Team B", id);
+ }
+ // listen for selections
+ tree.addListener(this);
+ // "context menu"
+ tree.addActionHandler(this);
+ p.addComponent(tree);
+ main.addComponent(p);
+
+ // Panel w/ TextField ("editor")
+ p = new Panel("Edit item caption");
+ p.setStyleName(Panel.STYLE_LIGHT);
+ editor = new TextField();
+ // make immediate, instead of adding an "apply" button
+ editor.setImmediate(true);
+ editor.setEnabled(false);
+ editor.setColumns(15);
+ p.addComponent(editor);
+ main.addComponent(p);
+ main.setExpandRatio(p, 1);
+ }
+
+ public Action[] getActions(Object target, Object sender) {
+ // We can provide different actions for each target (item), but we'll
+ // use the same actions all the time.
+ return actions;
+ }
+
+ public void handleAction(Action action, Object sender, Object target) {
+ if (action == DELETE) {
+ tree.removeItem(target);
+ } else {
+ // Add
+ final Object id = addCaptionedItem("New Item", target);
+ tree.expandItem(target);
+ tree.setValue(id);
+ editor.focus();
+ }
+ }
+
+ public void valueChange(ValueChangeEvent event) {
+ final Object id = tree.getValue(); // selected item id
+ if (event.getProperty() == tree) {
+ // a Tree item was (un) selected
+ if (id == null) {
+ // no selecteion, disable TextField
+ editor.removeListener(this);
+ editor.setValue("");
+ editor.setEnabled(false);
+ } else {
+ // item selected
+ // first remove previous listener
+ editor.removeListener(this);
+ // enable TextField and update value
+ editor.setEnabled(true);
+ final Item item = tree.getItem(id);
+ editor.setValue(item.getItemProperty(CAPTION_PROPERTY)
+ .getValue());
+ // listen for TextField changes
+ editor.addListener(this);
+ editor.focus();
+ }
+ } else {
+ // TextField
+ if (id != null) {
+ final Item item = tree.getItem(id);
+ final Property p = item.getItemProperty(CAPTION_PROPERTY);
+ p.setValue(editor.getValue());
+ tree.requestRepaint();
+ }
+
+ }
+ }
+
+ /**
+ * Helper to add an item with specified caption and (optional) parent.
+ *
+ * @param caption
+ * The item caption
+ * @param parent
+ * The (optional) parent item id
+ * @return the created item's id
+ */
+ private Object addCaptionedItem(String caption, Object parent) {
+ // add item, let tree decide id
+ final Object id = tree.addItem();
+ // get the created item
+ final Item item = tree.getItem(id);
+ // set our "caption" property
+ final Property p = item.getItemProperty(CAPTION_PROPERTY);
+ p.setValue(caption);
+ if (parent != null) {
+ tree.setChildrenAllowed(parent, true);
+ tree.setParent(id, parent);
+ tree.setChildrenAllowed(id, false);
+ }
+ return id;
+ }
+
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/ValueInputExample.java b/src/com/vaadin/automatedtests/featurebrowser/ValueInputExample.java
new file mode 100644
index 0000000000..14415d3794
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/ValueInputExample.java
@@ -0,0 +1,163 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.featurebrowser;
+
+import java.util.Date;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.Field;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.InlineDateField;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.Slider;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window.Notification;
+
+/**
+ * Shows some basic fields for value input; TextField, DateField, Slider...
+ *
+ * @author IT Mill Ltd.
+ */
+public class ValueInputExample extends CustomComponent {
+
+ @SuppressWarnings("deprecation")
+ public ValueInputExample() {
+ final VerticalLayout main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ // listener that shows a value change notification
+ final Field.ValueChangeListener listener = new Field.ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ getWindow().showNotification("Received",
+ "<pre>" + event.getProperty().getValue() + "</pre>",
+ Notification.TYPE_WARNING_MESSAGE);
+ }
+ };
+
+ // TextField
+ HorizontalLayout horiz = new HorizontalLayout();
+ horiz.setWidth("100%");
+ main.addComponent(horiz);
+ Panel left = new Panel("TextField");
+ left.setStyleName(Panel.STYLE_LIGHT);
+ horiz.addComponent(left);
+ Panel right = new Panel("multiline");
+ right.setStyleName(Panel.STYLE_LIGHT);
+ horiz.addComponent(right);
+ // basic TextField
+ TextField tf = new TextField("Basic");
+ tf.setDebugId("BasicTextField");
+ tf.setColumns(15);
+ tf.setImmediate(true);
+ tf.addListener(listener);
+ left.addComponent(tf);
+ // multiline TextField a.k.a TextArea
+ tf = new TextField("Area");
+ tf.setDebugId("AreaTextField");
+ tf.setColumns(15);
+ tf.setRows(5);
+ tf.setImmediate(true);
+ tf.addListener(listener);
+ right.addComponent(tf);
+
+ // DateFields
+ Date d = new Date(98, 1, 22, 13, 14, 15);
+ horiz = new HorizontalLayout();
+ horiz.setWidth("100%");
+ main.addComponent(horiz);
+ left = new Panel("DateField");
+ left.setStyleName(Panel.STYLE_LIGHT);
+ horiz.addComponent(left);
+ right = new Panel("inline");
+ right.setStyleName(Panel.STYLE_LIGHT);
+ horiz.addComponent(right);
+ // default
+ DateField df = new DateField("Day resolution");
+ df.setDebugId("DayResolutionDateField");
+ df.setValue(d);
+ df.addListener(listener);
+ df.setImmediate(true);
+ df.setResolution(DateField.RESOLUTION_DAY);
+ left.addComponent(df);
+ // minute
+ df = new DateField("Minute resolution");
+ df.setValue(d);
+ df.setDebugId("MinuteResolutionDateField");
+ df.addListener(listener);
+ df.setImmediate(true);
+ df.setResolution(DateField.RESOLUTION_MIN);
+ left.addComponent(df);
+ // year
+ df = new DateField("Year resolution");
+ df.setValue(d);
+ df.setDebugId("YearResolutionDateField");
+ df.addListener(listener);
+ df.setImmediate(true);
+ df.setResolution(DateField.RESOLUTION_YEAR);
+ left.addComponent(df);
+ // msec
+ df = new DateField("Millisecond resolution");
+ df.setValue(d);
+ df.setDebugId("MillisecondResolutionDateField");
+ df.addListener(listener);
+ df.setImmediate(true);
+ df.setResolution(DateField.RESOLUTION_MSEC);
+ left.addComponent(df);
+ // Inline
+ df = new InlineDateField();
+ df.setValue(d);
+ df.setDebugId("InlineDateField");
+ df.addListener(listener);
+ df.setImmediate(true);
+ right.addComponent(df);
+
+ // Slider
+ left = new Panel("Slider");
+ left.setStyleName(Panel.STYLE_LIGHT);
+ main.addComponent(left);
+ // int slider
+ Slider slider = new Slider(0, 100);
+ slider.setDebugId("Slider1");
+ slider.setWidth("300px");
+ slider.setImmediate(true);
+ slider.addListener(new Slider.ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ // update caption when value changes
+ final Slider s = (Slider) event.getProperty();
+ s.setCaption("Value: " + s.getValue());
+ }
+ });
+ try {
+ slider.setValue(20);
+ } catch (final Exception e) {
+ e.printStackTrace(System.err);
+ }
+ left.addComponent(slider);
+ // double slider
+ slider = new Slider(0.0, 1.0, 1);
+ slider.setOrientation(Slider.ORIENTATION_VERTICAL);
+ slider.setDebugId("Slider2");
+ slider.setImmediate(true);
+ slider.addListener(new Slider.ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ // update caption when value changes
+ final Slider s = (Slider) event.getProperty();
+ s.setCaption("Value: " + s.getValue());
+ }
+ });
+ try {
+ slider.setValue(0.5);
+ } catch (final Exception e) {
+ e.printStackTrace(System.err);
+ }
+ left.addComponent(slider);
+
+ }
+
+}
diff --git a/src/com/vaadin/automatedtests/featurebrowser/WindowingExample.java b/src/com/vaadin/automatedtests/featurebrowser/WindowingExample.java
new file mode 100644
index 0000000000..488d33702f
--- /dev/null
+++ b/src/com/vaadin/automatedtests/featurebrowser/WindowingExample.java
@@ -0,0 +1,112 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.featurebrowser;
+
+import java.net.URL;
+
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+/**
+ * @author marc
+ *
+ */
+public class WindowingExample extends CustomComponent {
+
+ public static final String txt = "<p>There are two main types of windows: application-level windows, and "
+ + "\"sub windows\".</p><p>A sub window is rendered as a \"inline\" popup window"
+ + " within the (native) browser window to which it was added. You can create"
+ + " a sub window by creating a new Window and adding it to a application-level window, for instance"
+ + " your main window. </p><p> In contrast, you create a application-level window by"
+ + " creating a new Window and adding it to the Application. Application-level"
+ + " windows are not shown by default - you need to open a browser window for"
+ + " the url representing the window. You can think of the application-level"
+ + " windows as separate views into your application - and a way to create a"
+ + " \"native\" browser window.</p><p>Depending on your needs, it's also"
+ + " possible to create a new window instance (with it's own internal state)"
+ + " for each new (native) browser window, or you can share the same instance"
+ + " (and state) between several browser windows (the latter is most useful"
+ + " for read-only views).</p>";
+
+ private URL windowUrl = null;
+
+ public WindowingExample() {
+ final VerticalLayout main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ final Label l = new Label(txt);
+ l.setContentMode(Label.CONTENT_XHTML);
+ main.addComponent(l);
+
+ Button b = new Button("Create a new subwindow",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ final Window w = new Window("Subwindow");
+ w.setWidth("50%");
+ final Label l = new Label(txt);
+ l.setContentMode(Label.CONTENT_XHTML);
+ w.addComponent(l);
+ getApplication().getMainWindow().addWindow(w);
+ }
+ });
+ b.setStyleName(Button.STYLE_LINK);
+ main.addComponent(b);
+ b = new Button("Create a new modal window", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ final Window w = new Window("Modal window");
+ w.setWidth("50%");
+ w.setModal(true);
+ final Label l = new Label(txt);
+ l.setContentMode(Label.CONTENT_XHTML);
+ w.addComponent(l);
+ getApplication().getMainWindow().addWindow(w);
+ }
+ });
+ b.setStyleName(Button.STYLE_LINK);
+ main.addComponent(b);
+ b = new Button("Open a application-level window, with shared state",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ if (windowUrl == null) {
+ final Window w = new Window("Subwindow");
+ final Label l = new Label(txt);
+ l.setContentMode(Label.CONTENT_XHTML);
+ w.addComponent(l);
+ getApplication().addWindow(w);
+ windowUrl = w.getURL();
+ }
+ getApplication().getMainWindow().open(
+ new ExternalResource(windowUrl), "_new");
+ }
+ });
+ b.setStyleName(Button.STYLE_LINK);
+ main.addComponent(b);
+ b = new Button(
+ "Create a new application-level window, with it's own state",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ final Window w = new Window("Subwindow");
+ getApplication().addWindow(w);
+ final Label l = new Label(
+ "Each opened window has its own"
+ + " name, and is accessed trough its own uri.");
+ l.setCaption("Window " + w.getName());
+ w.addComponent(l);
+ getApplication().getMainWindow().open(
+ new ExternalResource(w.getURL()), "_new");
+ }
+ });
+ b.setStyleName(Button.STYLE_LINK);
+ main.addComponent(b);
+
+ }
+
+}
diff --git a/src/com/vaadin/automatedtests/robustness/Robustness.java b/src/com/vaadin/automatedtests/robustness/Robustness.java
new file mode 100644
index 0000000000..13add217cd
--- /dev/null
+++ b/src/com/vaadin/automatedtests/robustness/Robustness.java
@@ -0,0 +1,91 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.robustness;
+
+import com.vaadin.automatedtests.util.Log;
+import com.vaadin.automatedtests.util.RandomComponents;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.ComponentContainer;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+public abstract class Robustness extends com.vaadin.Application
+ implements Button.ClickListener {
+
+ static int totalCount = 0;
+
+ int count = 0;
+
+ final Window main = new Window("Robustness tests by featurebrowser");
+
+ Button close = new Button("Close application");
+
+ Button remove = new Button("Remove all components");
+
+ Button create = new Button("Create");
+
+ Label label = new Label();
+
+ ComponentContainer stressLayout;
+
+ RandomComponents randomComponents = new RandomComponents();
+
+ @Override
+ public void init() {
+ createNewView();
+ }
+
+ public void createNewView() {
+ setMainWindow(main);
+ main.setDebugId("MainWindow");
+ main.removeAllComponents();
+
+ main.addComponent(label);
+ main.addComponent(close);
+ main.addComponent(remove);
+ main.addComponent(create);
+ close.addListener(this);
+ remove.addListener(this);
+ create.addListener(this);
+
+ remove.setDescription("After this garbage collector should"
+ + " be able to collect every component"
+ + " inside stressLayout.");
+
+ close.setDebugId("close");
+ remove.setDebugId("remove");
+ create.setDebugId("create");
+
+ }
+
+ public void buttonClick(ClickEvent event) {
+ if (event.getButton() == create) {
+ create();
+ } else if (event.getButton() == remove) {
+ main.removeAllComponents();
+ close.removeListener(this);
+ remove.removeListener(this);
+ create.removeListener(this);
+ close = null;
+ remove = null;
+ create = null;
+ label = null;
+ stressLayout = null;
+ System.out.println("main.getLayout()=" + main.getLayout());
+ System.out.println(Log.getMemoryStatistics());
+ } else if (event.getButton() == close) {
+ System.out.println("Before close, memory statistics:");
+ System.out.println(Log.getMemoryStatistics());
+ close();
+ // Still valueUnbound (session expiration) needs to occur for GC to
+ // do its work
+ System.out.println("After close, memory statistics:");
+ System.out.println(Log.getMemoryStatistics());
+ }
+ }
+
+ public abstract void create();
+}
diff --git a/src/com/vaadin/automatedtests/robustness/RobustnessComplex.java b/src/com/vaadin/automatedtests/robustness/RobustnessComplex.java
new file mode 100644
index 0000000000..9e72af8b86
--- /dev/null
+++ b/src/com/vaadin/automatedtests/robustness/RobustnessComplex.java
@@ -0,0 +1,45 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.robustness;
+
+import com.vaadin.automatedtests.util.Log;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+
+public class RobustnessComplex extends Robustness implements
+ Button.ClickListener {
+
+ /**
+ * Create complex layouts with components and listeners.
+ */
+ @Override
+ public void create() {
+ count++;
+
+ // remove old stressLayout, all dependant components should be now
+ // allowed for garbage collection.
+ if (stressLayout != null) {
+ main.removeComponent(stressLayout);
+ }
+
+ // create new stress layout
+ stressLayout = randomComponents
+ .getRandomComponentContainer("Component container " + count);
+
+ Label label = new Label("Label " + Log.getMemoryStatistics(),
+ Label.CONTENT_PREFORMATTED);
+ stressLayout.addComponent(label);
+
+ // fill with random components
+ randomComponents.fillLayout(stressLayout, 50);
+
+ // add new component container to main layout
+ main.addComponent(stressLayout);
+
+ // if ((count % 100) == 0) {
+ System.out.println("Created " + count + " times.");
+ // }
+ }
+}
diff --git a/src/com/vaadin/automatedtests/util/DebugId.java b/src/com/vaadin/automatedtests/util/DebugId.java
new file mode 100644
index 0000000000..8f2390933b
--- /dev/null
+++ b/src/com/vaadin/automatedtests/util/DebugId.java
@@ -0,0 +1,50 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.util;
+
+import java.io.Serializable;
+import java.util.HashMap;
+
+import com.vaadin.ui.Component;
+
+public class DebugId implements Serializable {
+
+ private static HashMap debugIds = new HashMap();
+
+ /**
+ * Generate static debug id based on package and component type. If
+ * duplicate package, component type then number of instances count is
+ * appended to debugId.
+ *
+ * @param c
+ */
+ public static void set(Component c, String description) {
+ String debugId = "";
+
+ // add package name
+ StackTraceElement[] st = new Throwable().fillInStackTrace()
+ .getStackTrace();
+ try {
+ debugId += st[3].getClassName();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ // add component type
+ debugId += c.getClass();
+
+ // add given description
+ debugId += description;
+
+ if (debugIds.containsKey(debugId)) {
+ int count = ((Integer) debugIds.get(debugId)).intValue();
+ count++;
+ debugIds.put(debugId, new Integer(count));
+ debugId = debugId + "-" + count;
+ }
+
+ c.setDebugId(debugId);
+ }
+}
diff --git a/src/com/vaadin/automatedtests/util/Log.java b/src/com/vaadin/automatedtests/util/Log.java
new file mode 100644
index 0000000000..f9948af60e
--- /dev/null
+++ b/src/com/vaadin/automatedtests/util/Log.java
@@ -0,0 +1,136 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.util;
+
+import java.io.Serializable;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ *
+ * Execution output and error messages should be handled through this class. It
+ * is likely that we need these messages back to TT Server at some point just to
+ * figure out what went wrong.
+ *
+ */
+public class Log implements Serializable {
+
+ // 3 (errors only)
+ // 2 (+ warnings)
+ // 1 (+logs)
+ // 0 (all, print messages also to System.out)
+ public static final int debug = 0;
+
+ // Should class.method() and it's call times be told on debug?
+ public static final boolean showClassInformation = true;
+
+ public static DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+ public static int DEBUG = 0;
+
+ public static int LOG = 1;
+
+ public static int WARN = 2;
+
+ public static int ERROR = 3;
+
+ private static Log log;
+
+ public static HashMap classMethodCallCounter = new HashMap();
+
+ static {
+ log = new Log();
+ }
+
+ public static void reset() {
+ classMethodCallCounter = new HashMap();
+ }
+
+ public static String getNow() {
+ return df.format(new Date());
+ }
+
+ private Log() {
+ }
+
+ public static String getSource() {
+ StackTraceElement[] st = new Throwable().fillInStackTrace()
+ .getStackTrace();
+ try {
+ String key = "";
+ String methodName = st[3].getMethodName();
+ int line = st[3].getLineNumber();
+
+ String clazz = st[3].getClassName() + ".java";
+ key = "(" + clazz + ":" + line + ")" + " " + methodName;
+ Integer value = (Integer) classMethodCallCounter.get(key);
+ if (value == null) {
+ value = new Integer(1);
+ } else {
+ value = new Integer(value.intValue() + 1);
+ }
+ classMethodCallCounter.put(key, value);
+ return value.intValue() + ": " + key;
+ } catch (Exception e) {
+ return "unknown class.method";
+ }
+
+ }
+
+ public static String getClassMethodCounters() {
+ String result = "";
+ for (final Iterator it = classMethodCallCounter.keySet().iterator(); it
+ .hasNext();) {
+ String key = (String) it.next();
+ result += classMethodCallCounter.get(key) + ": " + key + "\n";
+ }
+ return result;
+ }
+
+ public void add(int type, String message) {
+ String source = getSource();
+ if (type >= debug) {
+ if (showClassInformation) {
+ System.out.println(source + ": " + message);
+ } else {
+ System.out.println(message);
+ }
+ }
+ }
+
+ public static void debug(String message) {
+ log.add(DEBUG, message);
+ }
+
+ public static void log(String message) {
+ log.add(LOG, message);
+ }
+
+ public static void warn(String message) {
+ log.add(WARN, message);
+ }
+
+ public static void error(String message) {
+ log.add(ERROR, message);
+ }
+
+ /**
+ * Simple way to check for memory consumption without profiler.
+ */
+ public static String getMemoryStatistics() {
+ // You should call gc before printing statistics (if you are not using a
+ // profiler)
+ System.gc();
+ long inUse = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime()
+ .freeMemory());
+ return "Memory:\n" + inUse + " (Used)\n"
+ + Runtime.getRuntime().totalMemory() + " (Total)\n"
+ + Runtime.getRuntime().freeMemory() + " (Free)\n";
+
+ }
+}
diff --git a/src/com/vaadin/automatedtests/util/MultiListener.java b/src/com/vaadin/automatedtests/util/MultiListener.java
new file mode 100644
index 0000000000..5f7df2ab99
--- /dev/null
+++ b/src/com/vaadin/automatedtests/util/MultiListener.java
@@ -0,0 +1,35 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.util;
+
+import com.vaadin.data.Container.ItemSetChangeEvent;
+import com.vaadin.data.Container.ItemSetChangeListener;
+import com.vaadin.data.Container.PropertySetChangeEvent;
+import com.vaadin.data.Container.PropertySetChangeListener;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class MultiListener implements Button.ClickListener,
+ PropertySetChangeListener, ItemSetChangeListener, ValueChangeListener {
+
+ public void buttonClick(ClickEvent event) {
+ Log.debug("ClickEvent from " + event.getButton().getCaption());
+ }
+
+ public void containerPropertySetChange(PropertySetChangeEvent event) {
+ Log.debug("containerPropertySetChange from " + event.getContainer());
+ }
+
+ public void containerItemSetChange(ItemSetChangeEvent event) {
+ Log.debug("containerItemSetChange from " + event.getContainer());
+ }
+
+ public void valueChange(ValueChangeEvent event) {
+ Log.debug("valueChange from " + event.getProperty());
+ }
+
+}
diff --git a/src/com/vaadin/automatedtests/util/RandomComponents.java b/src/com/vaadin/automatedtests/util/RandomComponents.java
new file mode 100644
index 0000000000..8ddafaf62b
--- /dev/null
+++ b/src/com/vaadin/automatedtests/util/RandomComponents.java
@@ -0,0 +1,281 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.util;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Random;
+
+import com.vaadin.automatedtests.ComponentsInTable;
+import com.vaadin.data.Container.ItemSetChangeListener;
+import com.vaadin.data.Container.PropertySetChangeListener;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.demo.featurebrowser.ButtonExample;
+import com.vaadin.demo.featurebrowser.ClientCachingExample;
+import com.vaadin.demo.featurebrowser.ComboBoxExample;
+import com.vaadin.demo.featurebrowser.EmbeddedBrowserExample;
+import com.vaadin.demo.featurebrowser.LabelExample;
+import com.vaadin.demo.featurebrowser.LayoutExample;
+import com.vaadin.demo.featurebrowser.NotificationExample;
+import com.vaadin.demo.featurebrowser.RichTextExample;
+import com.vaadin.demo.featurebrowser.SelectExample;
+import com.vaadin.demo.featurebrowser.TableExample;
+import com.vaadin.demo.featurebrowser.TreeExample;
+import com.vaadin.demo.featurebrowser.ValueInputExample;
+import com.vaadin.demo.featurebrowser.WindowingExample;
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.AbstractComponent;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.ComponentContainer;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.Embedded;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.OrderedLayout;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.Select;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.TextField;
+
+public class RandomComponents implements Serializable {
+
+ private Random rand = null;
+
+ private static Date date = new Date(2002, 2, 3, 4, 5, 6);
+
+ public RandomComponents() {
+ // Always use the same seed, used to ensure deterministic behaviour
+ rand = new Random(1);
+ }
+
+ /**
+ * Get random component container
+ *
+ * @param caption
+ * @return
+ */
+ public ComponentContainer getRandomComponentContainer(String caption) {
+ ComponentContainer result = null;
+ final int randint = rand.nextInt(5);
+ switch (randint) {
+
+ case 0:
+ result = new OrderedLayout(OrderedLayout.ORIENTATION_HORIZONTAL);
+ ((OrderedLayout) result).setCaption("OrderedLayout_horizontal_"
+ + caption);
+ break;
+ case 1:
+ result = new OrderedLayout(OrderedLayout.ORIENTATION_VERTICAL);
+ ((OrderedLayout) result).setCaption("OrderedLayout_vertical_"
+ + caption);
+ break;
+ case 2:
+ GridLayout gl;
+ if (rand.nextInt(1) > 0) {
+ gl = new GridLayout();
+ } else {
+ gl = new GridLayout(rand.nextInt(3) + 1, rand.nextInt(3) + 1);
+ }
+ gl.setCaption("GridLayout_" + caption);
+ gl.setDescription(gl.getCaption());
+ for (int x = 0; x < gl.getColumns(); x++) {
+ for (int y = 0; y < gl.getRows(); y++) {
+ // gl.addComponent(getExamplePicture("x=" + x + ", y=" + y),
+ // x, y);
+ gl.addComponent(new Label("x=" + x + ", y=" + y));
+ }
+ }
+ result = gl;
+ break;
+ case 3:
+ result = new Panel();
+ ((Panel) result).setCaption("Panel_" + caption);
+ break;
+ case 4:
+ final TabSheet ts = new TabSheet();
+ ts.setCaption("TabSheet_" + caption);
+ // randomly select one of the tabs
+ final int selectedTab = rand.nextInt(3);
+ final ArrayList tabs = new ArrayList();
+ for (int i = 0; i < 3; i++) {
+ String tabCaption = "tab" + i;
+ if (selectedTab == i) {
+ tabCaption = "tabX";
+ }
+ tabs.add(new OrderedLayout());
+ ts.addTab((ComponentContainer) tabs.get(tabs.size() - 1),
+ tabCaption, null);
+ }
+ ts.setSelectedTab((ComponentContainer) tabs.get(selectedTab));
+ result = ts;
+ break;
+ }
+
+ return result;
+ }
+
+ public AbstractComponent getRandomComponent(int caption) {
+ AbstractComponent result = null;
+ int randint = rand.nextInt(23);
+ MultiListener l = new MultiListener();
+ switch (randint) {
+ case 0:
+ // Label
+ result = new Label();
+ result.setCaption("Label component " + caption);
+ result.setDebugId(result.getCaption());
+ break;
+ case 1:
+ // Button
+ result = new Button();
+ result.setCaption("Button component " + caption);
+ result.setDebugId(result.getCaption());
+ // some listeners
+ ((Button) result).addListener((Button.ClickListener) l);
+ break;
+ case 2:
+ // TextField
+ result = new TextField();
+ result.setCaption("TextField component " + caption);
+ result.setDebugId(result.getCaption());
+ break;
+ case 3:
+ // Select
+ result = new Select("Select component " + caption);
+ result.setCaption("Select component " + caption);
+ result.setDebugId(result.getCaption());
+ result.setImmediate(true);
+ ((Select) result).setNewItemsAllowed(true);
+ // items
+ ((Select) result).addItem("first");
+ ((Select) result).addItem("first");
+ ((Select) result).addItem("first");
+ ((Select) result).addItem("second");
+ ((Select) result).addItem("third");
+ ((Select) result).addItem("fourth");
+ // some listeners
+ ((Select) result).addListener((ValueChangeListener) l);
+ ((Select) result).addListener((PropertySetChangeListener) l);
+ ((Select) result).addListener((ItemSetChangeListener) l);
+ break;
+ case 4:
+ // Link
+ result = new Link("", new ExternalResource("http://www.itmill.com"));
+ result.setCaption("Link component " + caption);
+ break;
+ case 5:
+ // Link
+ result = new Panel();
+ result.setCaption("Panel component " + caption);
+ ((Panel) result)
+ .addComponent(new Label(
+ "Panel is a container for other components, by default it draws a frame around it's "
+ + "extremities and may have a caption to clarify the nature of the contained components' purpose."
+ + " Panel contains an layout where the actual contained components are added, "
+ + "this layout may be switched on the fly."));
+ ((Panel) result).setWidth(250);
+ break;
+ case 6:
+ // Datefield
+ result = new DateField();
+ ((DateField) result).setStyleName("calendar");
+ ((DateField) result).setValue(date);
+ result.setCaption("Calendar component " + caption);
+ result.setDebugId(result.getCaption());
+ break;
+ case 7:
+ // Datefield
+ result = new DateField();
+ ((DateField) result).setValue(date);
+ result.setCaption("Calendar component " + caption);
+ result.setDebugId(result.getCaption());
+ break;
+ case 8:
+ result = new OrderedLayout();
+ ((OrderedLayout) result).addComponent(new ButtonExample());
+ break;
+ case 9:
+ result = new OrderedLayout();
+ ((OrderedLayout) result).addComponent(new ClientCachingExample());
+ break;
+ case 10:
+ result = new OrderedLayout();
+ ((OrderedLayout) result).addComponent(new ComboBoxExample());
+ break;
+ case 11:
+ result = new OrderedLayout();
+ ((OrderedLayout) result).addComponent(new EmbeddedBrowserExample());
+ break;
+ case 12:
+ result = new OrderedLayout();
+ ((OrderedLayout) result).addComponent(new EmbeddedBrowserExample());
+ break;
+ case 13:
+ result = new OrderedLayout();
+ ((OrderedLayout) result).addComponent(new LabelExample());
+ break;
+ case 14:
+ result = new OrderedLayout();
+ ((OrderedLayout) result).addComponent(new LayoutExample());
+ break;
+ case 15:
+ result = new OrderedLayout();
+ ((OrderedLayout) result).addComponent(new NotificationExample());
+ break;
+ case 16:
+ result = new OrderedLayout();
+ ((OrderedLayout) result).addComponent(new RichTextExample());
+ break;
+ case 17:
+ result = new OrderedLayout();
+ ((OrderedLayout) result).addComponent(new SelectExample());
+ break;
+ case 18:
+ result = new OrderedLayout();
+ ((OrderedLayout) result).addComponent(new ValueInputExample());
+ break;
+ case 19:
+ result = new OrderedLayout();
+ ((OrderedLayout) result).addComponent(new WindowingExample());
+ break;
+ case 20:
+ result = new OrderedLayout();
+ ((OrderedLayout) result).addComponent(new TreeExample());
+ break;
+ case 21:
+ result = new OrderedLayout();
+ ((OrderedLayout) result).addComponent(new TableExample());
+ break;
+ case 22:
+ result = new OrderedLayout();
+ ((OrderedLayout) result)
+ .addComponent(new ComponentsInTable(4, 1000));
+ break;
+ }
+
+ return result;
+ }
+
+ /**
+ * Add demo components to given container
+ *
+ * @param container
+ */
+ public void fillLayout(ComponentContainer container, int numberOfComponents) {
+ for (int i = 0; i < numberOfComponents; i++) {
+ container.addComponent(getRandomComponent(i));
+ }
+ }
+
+ public AbstractComponent getExamplePicture(String caption) {
+ final ThemeResource res = new ThemeResource("test.png");
+ final Embedded em = new Embedded("Embedded " + caption, res);
+ return em;
+ }
+
+}
diff --git a/src/com/vaadin/automatedtests/util/StatusServlet.java b/src/com/vaadin/automatedtests/util/StatusServlet.java
new file mode 100644
index 0000000000..c0b3c7c118
--- /dev/null
+++ b/src/com/vaadin/automatedtests/util/StatusServlet.java
@@ -0,0 +1,89 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.automatedtests.util;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@SuppressWarnings("serial")
+public class StatusServlet extends HttpServlet {
+
+ public static DateFormat dfHuman = new SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss");
+
+ /**
+ * Version number of this release. For example "5.0.0".
+ */
+ public static final String VERSION;
+
+ /**
+ * Major version number. For example 5 in 5.1.0.
+ */
+ public static final int VERSION_MAJOR;
+
+ /**
+ * Minor version number. For example 1 in 5.1.0.
+ */
+ public static final int VERSION_MINOR;
+
+ /**
+ * Builds number. For example 0-custom_tag in 5.0.0-custom_tag.
+ */
+ public static final String VERSION_BUILD;
+
+ /* Initialize version numbers from string replaced by build-script. */
+ static {
+ if ("@VERSION@".equals("@" + "VERSION" + "@")) {
+ VERSION = "5.9.9-INTERNAL-NONVERSIONED-DEBUG-BUILD";
+ } else {
+ VERSION = "@VERSION@";
+ }
+ final String[] digits = VERSION.split("\\.");
+ VERSION_MAJOR = Integer.parseInt(digits[0]);
+ VERSION_MINOR = Integer.parseInt(digits[1]);
+ VERSION_BUILD = digits[2];
+ }
+
+ @Override
+ public void init(javax.servlet.ServletConfig servletConfig)
+ throws javax.servlet.ServletException {
+ super.init(servletConfig);
+ }
+
+ @Override
+ protected void service(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+ Writer w = response.getWriter();
+
+ // not cacheable
+ response.setHeader("Cache-Control", "no-cache");
+ response.setHeader("Pragma", "no-cache");
+ response.setDateHeader("Expires", 0);
+ response.setContentType("text/html");
+
+ String p = "";
+ p += "<p>StatusServlet " + dfHuman.format(new Date()) + "</p>";
+ for (int i = 0; i < 30; i++) {
+ System.gc();
+ }
+ long inUse = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime()
+ .freeMemory());
+ p += "<p>Memory:<br />\n<memused>" + inUse
+ + "</memused> (Used)<br />\n" + "<memtotal>"
+ + Runtime.getRuntime().totalMemory()
+ + "<memtotal> (Total)<br />\n" + "<memfree>"
+ + Runtime.getRuntime().freeMemory() + "<memfree> (Free)</p>\n";
+
+ w.write("<html>\n" + p + "</html>\n");
+ }
+}