aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Koivuviita <jouni.koivuviita@itmill.com>2009-04-08 13:16:16 +0000
committerJouni Koivuviita <jouni.koivuviita@itmill.com>2009-04-08 13:16:16 +0000
commit9981d776a916d059b7033fa236dc0e41b2440e01 (patch)
tree9e8e1b61650d73a3c69bc1a86a503fa4aa3ccd91
parent37362aa752f7edd7c2b37706090ebcd791230ad1 (diff)
parent3904bc38dc84a2428497469440a542c316d78ad1 (diff)
downloadvaadin-framework-9981d776a916d059b7033fa236dc0e41b2440e01.tar.gz
vaadin-framework-9981d776a916d059b7033fa236dc0e41b2440e01.zip
Merges from 6.0 branch.
svn changeset:7370/svn branch:theme_2009_03
-rw-r--r--WebContent/ITMILL/themes/default/select/select.css6
-rw-r--r--WebContent/ITMILL/themes/default/styles.css18
-rw-r--r--WebContent/ITMILL/themes/default/textfield/textfield.css7
-rw-r--r--WebContent/ITMILL/themes/default/window/window.css5
-rw-r--r--WebContent/ITMILL/themes/tests-tickets/styles.css14
-rw-r--r--WebContent/index.html6
-rw-r--r--WebContent/release-notes.html286
-rw-r--r--build/VERSION.properties2
-rwxr-xr-xbuild/bin/mergetool.py707
-rwxr-xr-xbuild/bin/svnlog-to-rn.py109
-rw-r--r--build/bin/svnlog-to-rn.xsl19
-rw-r--r--build/build-www.itmill.com.xml192
-rw-r--r--build/build.properties5
-rw-r--r--build/build.xml565
-rw-r--r--build/package/build-widgetset.xml4
-rw-r--r--build/package/eclipse-IT Mill Toolkit Hosted Mode-launch2
-rw-r--r--build/package/eclipse-classpath1
-rw-r--r--src/com/itmill/toolkit/Application.java19
-rw-r--r--src/com/itmill/toolkit/data/Container.java17
-rw-r--r--src/com/itmill/toolkit/data/util/BeanItem.java124
-rw-r--r--src/com/itmill/toolkit/data/util/BeanItemContainer.java449
-rw-r--r--src/com/itmill/toolkit/data/util/Filter.java87
-rw-r--r--src/com/itmill/toolkit/data/util/IndexedContainer.java249
-rw-r--r--src/com/itmill/toolkit/data/util/PropertysetItem.java15
-rw-r--r--src/com/itmill/toolkit/data/validator/AbstractStringValidator.java54
-rw-r--r--src/com/itmill/toolkit/data/validator/AbstractValidator.java67
-rw-r--r--src/com/itmill/toolkit/data/validator/CompositeValidator.java58
-rw-r--r--src/com/itmill/toolkit/data/validator/DoubleValidator.java36
-rw-r--r--src/com/itmill/toolkit/data/validator/EmailValidator.java31
-rw-r--r--src/com/itmill/toolkit/data/validator/IntegerValidator.java37
-rw-r--r--src/com/itmill/toolkit/data/validator/RegexpValidator.java86
-rw-r--r--src/com/itmill/toolkit/data/validator/StringLengthValidator.java78
-rw-r--r--src/com/itmill/toolkit/demo/sampler/APIResource.java2
-rw-r--r--src/com/itmill/toolkit/demo/sampler/FeatureSet.java4
-rw-r--r--src/com/itmill/toolkit/demo/sampler/features/selects/75-ComboBoxInputPrompt.pngbin0 -> 3317 bytes
-rw-r--r--src/com/itmill/toolkit/demo/sampler/features/selects/ComboBoxInputPrompt.java44
-rw-r--r--src/com/itmill/toolkit/demo/sampler/features/selects/ComboBoxInputPromptExample.java39
-rw-r--r--src/com/itmill/toolkit/demo/sampler/features/text/75-TextFieldInputPrompt.pngbin0 -> 4911 bytes
-rw-r--r--src/com/itmill/toolkit/demo/sampler/features/text/TextFieldInputPrompt.java47
-rw-r--r--src/com/itmill/toolkit/demo/sampler/features/text/TextFieldInputPromptExample.java49
-rw-r--r--src/com/itmill/toolkit/terminal/gwt/client/ApplicationConfiguration.java8
-rwxr-xr-xsrc/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java110
-rw-r--r--src/com/itmill/toolkit/terminal/gwt/client/ComponentLocator.java278
-rw-r--r--src/com/itmill/toolkit/terminal/gwt/client/ui/IFilterSelect.java106
-rw-r--r--src/com/itmill/toolkit/terminal/gwt/client/ui/IForm.java9
-rw-r--r--src/com/itmill/toolkit/terminal/gwt/client/ui/INativeSelect.java8
-rw-r--r--src/com/itmill/toolkit/terminal/gwt/client/ui/IScrollTable.java291
-rw-r--r--src/com/itmill/toolkit/terminal/gwt/client/ui/ITextField.java34
-rw-r--r--src/com/itmill/toolkit/terminal/gwt/client/ui/ITextualDate.java3
-rw-r--r--src/com/itmill/toolkit/terminal/gwt/client/ui/ITree.java7
-rw-r--r--src/com/itmill/toolkit/terminal/gwt/client/ui/IView.java39
-rw-r--r--src/com/itmill/toolkit/terminal/gwt/client/ui/IWindow.java50
-rw-r--r--src/com/itmill/toolkit/terminal/gwt/client/ui/SubPartAware.java11
-rw-r--r--src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java54
-rw-r--r--src/com/itmill/toolkit/terminal/gwt/server/CommunicationManager.java22
-rw-r--r--src/com/itmill/toolkit/tests/TestBench.java574
-rw-r--r--src/com/itmill/toolkit/tests/book/BookTestApplication.java3365
-rw-r--r--src/com/itmill/toolkit/tests/book/DefaultButtonExample.java139
-rw-r--r--src/com/itmill/toolkit/tests/components/MultipleDebugIds.java35
-rw-r--r--src/com/itmill/toolkit/tests/components/form/FormRenderingFlicker.java65
-rw-r--r--src/com/itmill/toolkit/tests/components/table/ColumnExpandRatio.java70
-rw-r--r--src/com/itmill/toolkit/tests/components/table/ColumnWidths.java68
-rw-r--r--src/com/itmill/toolkit/tests/components/table/PropertyValueChange.java158
-rw-r--r--src/com/itmill/toolkit/tests/components/table/RowAdditionTest.java59
-rw-r--r--src/com/itmill/toolkit/tests/components/table/TableRowHeight2.java4
-rw-r--r--src/com/itmill/toolkit/tests/components/table/TableRowHeight3.java61
-rw-r--r--src/com/itmill/toolkit/tests/components/window/WindowResizeListener.java99
-rw-r--r--src/com/itmill/toolkit/tests/containers/BeanItemContainerFilteringTest.java172
-rw-r--r--src/com/itmill/toolkit/tests/containers/BeanItemContainerTest.java75
-rw-r--r--src/com/itmill/toolkit/tests/containers/IndexedContainerFilteringTest.java139
-rw-r--r--src/com/itmill/toolkit/tests/tickets/Ticket2742.java42
-rw-r--r--src/com/itmill/toolkit/tests/validation/TestValidators.java163
-rw-r--r--src/com/itmill/toolkit/ui/ComboBox.java31
-rw-r--r--src/com/itmill/toolkit/ui/DateField.java49
-rw-r--r--src/com/itmill/toolkit/ui/Layout.java39
-rw-r--r--src/com/itmill/toolkit/ui/ProgressIndicator.java8
-rw-r--r--src/com/itmill/toolkit/ui/RichTextArea.java11
-rw-r--r--src/com/itmill/toolkit/ui/Slider.java5
-rw-r--r--src/com/itmill/toolkit/ui/Table.java290
-rw-r--r--src/com/itmill/toolkit/ui/TextField.java34
-rw-r--r--src/com/itmill/toolkit/ui/Tree.java50
-rw-r--r--src/com/itmill/toolkit/ui/Window.java98
-rw-r--r--tests/com/itmill/toolkit/tests/sampler/SamplerSmokeTest.java32
-rw-r--r--tests/com/itmill/toolkit/tests/sampler/SamplerSmokeTest2.java57
84 files changed, 7021 insertions, 3541 deletions
diff --git a/WebContent/ITMILL/themes/default/select/select.css b/WebContent/ITMILL/themes/default/select/select.css
index 52c000998d..5c5d57507a 100644
--- a/WebContent/ITMILL/themes/default/select/select.css
+++ b/WebContent/ITMILL/themes/default/select/select.css
@@ -102,7 +102,11 @@
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -4px;
}
-
+.i-filterselect-prompt .i-filterselect-input {
+ /* input prompt active, i.e empty select */
+ color: #999;
+ font-style: italic;
+}
.i-filterselect-button {
float: right;
width: 25px;
diff --git a/WebContent/ITMILL/themes/default/styles.css b/WebContent/ITMILL/themes/default/styles.css
index 2e9c637b01..439f4f2aec 100644
--- a/WebContent/ITMILL/themes/default/styles.css
+++ b/WebContent/ITMILL/themes/default/styles.css
@@ -1384,7 +1384,11 @@ input.i-modified,
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -4px;
}
-
+.i-filterselect-prompt .i-filterselect-input {
+ /* input prompt active, i.e empty select */
+ color: #999;
+ font-style: italic;
+}
.i-filterselect-button {
float: right;
width: 25px;
@@ -2483,6 +2487,12 @@ input.i-modified,
border-color: #5daee8;
}
+input.i-textfield-prompt,
+textarea.i-textarea-prompt {
+ color: #999;
+ font-style: italic;
+}
+
.i-textfield.i-readonly,
.i-textarea.i-readonly {
background: transparent;
@@ -2490,7 +2500,6 @@ input.i-modified,
border: none;
}
-
.i-richtextarea {
border: 1px solid #b6b6b6;
overflow: hidden;
@@ -2651,8 +2660,9 @@ input.i-modified,
.i-window-footer {
height: 8px;
margin-left: 9px;
- background: transparent url(window/img/bottom-right.png) no-repeat right top;
- /* IE7 bug fix */
+ background: transparent url(window/img/bottom-right.png) no-repeat right top;
+}
+.i-ie7 .i-window-footer {
position:relative;
}
diff --git a/WebContent/ITMILL/themes/default/textfield/textfield.css b/WebContent/ITMILL/themes/default/textfield/textfield.css
index 0a91a97b2e..16d36e3256 100644
--- a/WebContent/ITMILL/themes/default/textfield/textfield.css
+++ b/WebContent/ITMILL/themes/default/textfield/textfield.css
@@ -27,6 +27,12 @@
border-color: #5daee8;
}
+input.i-textfield-prompt,
+textarea.i-textarea-prompt {
+ color: #999;
+ font-style: italic;
+}
+
.i-textfield.i-readonly,
.i-textarea.i-readonly {
background: transparent;
@@ -34,7 +40,6 @@
border: none;
}
-
.i-richtextarea {
border: 1px solid #b6b6b6;
overflow: hidden;
diff --git a/WebContent/ITMILL/themes/default/window/window.css b/WebContent/ITMILL/themes/default/window/window.css
index 684171ae9b..2ecd0dd70b 100644
--- a/WebContent/ITMILL/themes/default/window/window.css
+++ b/WebContent/ITMILL/themes/default/window/window.css
@@ -58,8 +58,9 @@
.i-window-footer {
height: 8px;
margin-left: 9px;
- background: transparent url(img/bottom-right.png) no-repeat right top;
- /* IE7 bug fix */
+ background: transparent url(img/bottom-right.png) no-repeat right top;
+}
+.i-ie7 .i-window-footer {
position:relative;
}
diff --git a/WebContent/ITMILL/themes/tests-tickets/styles.css b/WebContent/ITMILL/themes/tests-tickets/styles.css
index 0cdad264dd..225bbd6d1d 100644
--- a/WebContent/ITMILL/themes/tests-tickets/styles.css
+++ b/WebContent/ITMILL/themes/tests-tickets/styles.css
@@ -1,5 +1,7 @@
@import url(../default/styles.css);
+/* DO NOT ADD GENERIC RULES LIKE .i-table IN THIS FILE */
+
/*****************************************************************************/
/* Ticket 1904 */
/*****************************************************************************/
@@ -442,10 +444,12 @@ padding:2px;
.i-table-row:hover, .i-table-row-odd:hover {
background: #c8def9;
}
+/*
.i-table-header-wrap {
background: #d4e7fe url(img/table/column_header_bg.png) top left repeat-x;
height: 25px;
}
+*/
.i-table-header-cell:hover,
.i-table-header-cell-asc:hover,
.i-table-header-cell-desc:hover {
@@ -456,7 +460,7 @@ padding:2px;
border-right: 1px solid #e3e7f0;
margin: 0;
padding: 2px 2px 2px 3px;
- height: 20px;
+/* height: 20px;*/
}
.i-table-header-cell-asc .i-table-caption-container {
background: url(img/table/order_asc.png) right 50% no-repeat;
@@ -1266,4 +1270,10 @@ padding:2px;
/* #2434 */
.i-table-bordered .i-table-body td {
border-bottom: 1px solid red;
-} \ No newline at end of file
+}
+
+/* #2747 */
+.i-button-nowraplink span {
+ white-space: normal;
+}
+
diff --git a/WebContent/index.html b/WebContent/index.html
index 02cbaf26b9..cd5b6dd5df 100644
--- a/WebContent/index.html
+++ b/WebContent/index.html
@@ -135,7 +135,7 @@
<h4>Eclipse IDE QuickStart</h4>
<p>The easiest way to start working with IT Mill Toolkit is to
use Eclipse IDE with the Toolkit QuickStart project.
- <a href="doc/manual/intro.quickstart.html" class="more">Instant Toolkit workspace for Eclipse</a></p>
+ <a href="doc/manual/getting-started.quickstart.html" class="more">Instant Toolkit workspace for Eclipse</a></p>
</div> <!-- /getting-started -->
@@ -164,14 +164,14 @@
<div class="top"></div>
<h3>&raquo; Package contents</h3>
- <em>Version <version></version></em>
+ <em>Version @version@</em>
<div id="package-contents-content"> <!-- For JavaScript hooking -->
<div class="library">
<h5>Library</h5>
<p>Contains all you need to start a new Toolkit project (binaries, sources, default
- themes and widgetsets). <a href="itmill-toolkit-<version></version>.jar">Toolkit JAR</a></p>
+ themes and widgetsets). <a href="itmill-toolkit-@version@.jar">Toolkit JAR</a></p>
</div>
<div class="documentation">
diff --git a/WebContent/release-notes.html b/WebContent/release-notes.html
index 4ac661912d..22319c3147 100644
--- a/WebContent/release-notes.html
+++ b/WebContent/release-notes.html
@@ -25,250 +25,12 @@ support site forum.itmill.com</a></div>
<div class="content">
<div>
-<h2>Release Notes for IT Mill Toolkit Version <version></version></h2>
+<h2>Release Notes for IT Mill Toolkit Version @version@</h2>
<p>Version 5.3.0 is the first stable release of IT Mill Toolkit 5,
meaning that there are no known major problems and the API will be kept
backward compatible.</p>
-<h2 id="ClientsideiscompiledwithGWT1.5">Google Web Toolkit Upgraded
-to Version 1.5</h2>
-
-<p>The GWT used in IT Mill Toolkit is upgraded to version 1.5. If
-you have made your own client side components, you will need to upgrade
-your GWT library. Many things have changed in GWT 1.5, but upgrading is
-rather straightforward and, as a bonus, you will get the nice features
-from Java 1.5. For more details on GWT 1.5, see the <a class="ext-link"
- href="http://code.google.com/webtoolkit/"><span class="icon">GWT
-web site</span></a>.</p>
-
-<h2 id="Java5isrequired">Java 5 Now Required</h2>
-
-<p>As GWT now requires Java 5, support for Java 1.4 is discontinued
-also in IT Mill Toolkit.</p>
-
-<p>IT Mill Toolkit supports the Sun Microsystems JDK and JRE, though others should work as
-well. When running the demo application, the Jetty web server may produce errors in the
-console if using certain other Java implementations, especially the GNU JRE.</p>
-
-<h2>Debug Mode Enabled by Default</h2>
-
-<p>The debug mode is now enabled by default, to allow debugging
-layout and other problems more easily. The debug mode:</p>
-
-<ul>
- <li>Displays debug data to the server console/log.</li>
-
- <li>Allows showing the client-side logging window, which you can
- enable by adding the request parameter "<tt>?debug=true</tt>" to the
- application URI.</li>
-
- <li>"Analyze layouts" -button in the debug window runs basic
- checks on usage of relative units. Potentially problematic layouts will
- be shown in the debug window and in <tt>System.out</tt>.</li>
-</ul>
-
-<p>You should disable the debug mode when releasing your application
-for production use. You can do this by including the following setting
-in your <tt>web.xml</tt>.</p>
-
-<pre class="wiki"> &lt;context-param&gt;
- &lt;param-name&gt;productionMode&lt;/param-name&gt;
- &lt;param-value&gt;true&lt;/param-value&gt;
- &lt;description&gt;IT Mill Toolkit production mode&lt;/description&gt;
- &lt;/context-param&gt;
-</pre>
-
-<h2 id="Layoutchanges">Layout Changes</h2>
-
-<p>The stable IT Mill Toolkit version 5.3 introduces a major rework
-of layout components since the beta versions 5.2.x and before.</p>
-
-<p>Major changes include:</p>
-
-<ul>
- <li>Layouts are stricter than before - <i>usage of debug mode
- during development is recommended. Use "Analyze layouts" in client side
- debug window if you encounter problems with relative size.</i></li>
- <li><b>VerticalLayout</b> and <b>HorizontalLayout</b> obsolete <b>
- <s>OrderedLayout</s></b></li>
- <li>Layout cell alignment has changed</li>
- <li><b><s>ExpandLayout</s></b> deprecated</li>
- <li>Default sizes have changed</li>
-</ul>
-
-<h3>OrderedLayout deprecated</h3>
-
-<p><b>VerticalLayout</b> and <b>HorizontalLayout</b> replace the old
-<b><s>OrderedLayout</s></b>, which is now deprecated.</p>
-
-<p>Essentially, this makes the creation of these basic layouts a bit
-tidier as you don't have to give the orientation as an ugly parameter to
-the constructor. You won't be able to change the orientation with <tt>setOrientation()</tt>
-any longer, though such need is rare anyhow.</p>
-
-<h3>Layout Cell Alignment Changed</h3>
-
-<p>Previously, the alignment of components within layout cells was set with
-<i>setComponentAlignment()</i> with constants for <b><s>OrderedLayout</s></b> (now
-<b>VerticalLayout</b> and <b>HorizontalLayout</b>) and <b>GridLayout</b> separately, such
-as <tt>OrderedLayout.ALIGNMENT_TOP_LEFT</tt>. Now the method takes constants defined in
-<b>Alignment</b>.</p>
-
-<p>For example, aligning a component "top left" is now:</p>
-
-<pre>mylayout.setComponentAlignment(mycomponent, Alignment.TOP_LEFT);</pre>
-
-<p>You can also give an <b>Alignment</b> object as a parameter and give horizontal and
-vertical alignment separately with bitmask parameters.</p>
-
-<h3 id="HandlingofrelativesizeshavechangedExpandLayoutdeprecated">Handling
-of relative sizes has changed, ExpandLayout deprecated</h3>
-
-<p><b><s>ExpandLayout</s></b> is deprecated. You can now define the
-relative sizes of components more flexibly with <tt>setExpandRatio()</tt>
-method available in <b>VerticalLayout</b> or <b>HorizontalLayout</b>.</p>
-
-<p>See the article on <a class="wiki"
- href="http://dev.itmill.com/wiki/DevDocs/RFC/RelativeSizes">Relative
-sizes in IT Mill Toolkit</a> for details.</p>
-
-<h3 id="Somecomponentsnowhavedefaultsizes">Some components now have
-default sizes</h3>
-
-<p>Previously, almost all components had undefined size by default.
-Now some containers have 100% width by default. These components are:</p>
-
-<ul>
- <li><b>VerticalLayout</b></li>
- <li><b>Window</b></li>
- <li><b>Panel</b></li>
- <li><b>TabSheet</b></li>
- <li><b>SplitPanel</b> (note that <b>SplitPanel</b> also has 100%
- height by default)</li>
- <li><b>Form</b></li>
- <li><b>FormLayout</b></li>
- <li><b>Label</b></li>
-</ul>
-
-<p>If the width of a <b>Label</b> is set defined, as is now the default, the label text
-will wrap appropriately, but if it is set as undefined, the text will never wrap.</p>
-
-<h3>Miscellaneous Layout Changes</h3>
-
-<ul>
- <li>You can now give component alignments inside layouts easily
- with <tt>setComponentAlignment()</tt> as a string, such as "<tt>top
- left</tt>" or "<tt>m,c</tt>" (for middle-center). See <a
- href="http://dev.itmill.com/ticket/2279">#2279</a>.</li>
-
- <li><b>Form</b> no longer copies all components from the old
- layout to the new one when doing <tt>setLayout()</tt>, instead only
- fields belonging to the <b>Form</b> are copied.</li>
-</ul>
-
-
-<h2 id="Customtailoredclientsidecomponents">Custom Tailored
-Client-Side Components</h2>
-
-<p>Due to the layout changes, all child component size changes
-(outside the <i>updateFromUIDL()</i> function) must be announced. Most
-commonly, this kind of change occurs when an image gets loaded inside a
-component. There is a helper method <i>componentSizeUpdated()</i> in the
-<b><i>Util</i></b> class for making the announcement:</p>
-
-<pre class="wiki"> Set&lt;Widget&gt; w = new HashSet&lt;Widget&gt;();
- w.add(this);
- Util.componentSizeUpdated(w);
-</pre>
-
-<h2 id="Themes">Themes</h2>
-
-<p>Many components have changed significantly due to layout
-refactoring. Especially the DOM structures of the components have
-changed, which may break old themes.</p>
-
-<p>Building themes for Toolkit is not the most straightforward
-process as there is quite a lot of JavaScript magic done while rendering
-the components, e.g., dimension measuring, etc. If you use unsupported
-CSS, a component may be rendered in an unexpected way in a browser. A
-"Theme builder's Handbook" is at the top of our TODO list. In the mean
-time, it is often safest to override the values defined in the default
-theme.</p>
-
-<p>Especially, if you encounter problems with margins or spacings,
-check the manual. Some CSS class names and conventions have changed as
-well. (Many of the changes are not yet included in the manual.)</p>
-
-<p>If you have or get "broken" component on your screen, the first
-thing to do is to comment out all your custom theme. If it works, you
-may have the rework your CSS for that particular component. Below are a
-few things to check:</p>
-
-<ul>
-
- <li>Do not use custom margins outside a component. In IT Mill
- Toolkit, no component should have a margin defined. Settings
- width/height on the server-side would mean offset width/height on
- client-side, so using custom margins for components using CSS may break
- some features in the layouts.</li>
-
- <li>The same goes for borders and paddings for the main element
- unless they are used for the main element in the default theme. It is
- often safer to use borders in the same elements that have borders in
- the default theme or in inner elements.</li>
-
-</ul>
-
-<p>The easiest and safest way to build a custom theme is, often, to
-override the values from the default theme.</p>
-
-<h2 id="Browsersupportchangessince5.2.x">Browser support changes
-since 5.2.x</h2>
-
-<p>Safari 2, Firefox 1.5, and versions of Opera prior to version 9.6
-are no longer supported. Users of these browsers are strongly encouraged
-to upgrade to a newer version.</p>
-
-<p>Google Chrome is not yet supported, but it is known to work
-rather well as it is a close relative to Safari.</p>
-
-<p>The GWT Hosted Mode Browser on Linux uses same Gecko version as
-FF 1.5 and is currently partially broken. Some layouts do not render
-properly. We hope to resolve these issues soon with next generation
-Hosted Mode Browser aka OOPHM or with minor hacks to the client side
-code.</p>
-
-<h2 id="MinorChanges">Miscellaneous Changes and Enhancements</h2>
-
-<p>Version 5.3 also contains a large number (more than 200) of small
-changes, which might not be worth mentioning in the release notes, but
-below are some of them.</p>
-
-<ul>
- <li>A new sub-window theme</li>
- <li>The HTML structure of <b>TabSheet</b> has changed</li>
- <li>Better shadow support for overlay elements</li>
- <li>Row and column icons for <b>Table</b></li>
- <li>New component: <b>PopupPanel</b>/<B>PopupView</b></li>
- <li>Theme changing on-the-fly</li>
- <li><b>Table</b> cellstyle and rowstyle generators</li>
- <li>New component: <b>MenuBar</b></li>
- <li>Security: double-cookie submission pattern</li>
- <li>Low-level support for bookmarking and history</li>
- <li>Sub-windows can be centered on screen. Modal windows are
- centered automatically</li>
- <li>The <b>Link</b> component now behaves like a normal "weblink"</li>
-</ul>
-
-<p>The <version></version> release of IT Mill Toolkit includes new
-features and a large number of fixes to problems compared to the older
-5.2.x version. Major enhancements and dozens of bug fixes have been
-implemented. Only the most significant issues are mentioned here.</p>
-
-<p>For up-to-date status of known problems, see the developer
-website <a href="http://dev.itmill.com/">dev.itmill.com</a>.</p>
-
<h2>Package for the experimental GWT Out-of-Process Hosted Mode</h2>
<p>We provide a separate (platform independent) installation package
@@ -294,7 +56,7 @@ debugging purposes during development. For production use, you should
compile your custom widget sets with the regular IT Mill Toolkit package
for your platform.</p>
-<h2>Important known problems in <version></version></h2>
+<h2>Important known problems in @version@</h2>
<ul>
<li><a href="http://dev.itmill.com/ticket/1155">#1155</a>
@@ -331,7 +93,7 @@ for your platform.</p>
</ul>
<p>IT Mill Toolkit supports Java Servlet API 2.3 and later versions and should work with
-any Java application servers that conform to the standard. It supports the following
+any Java application server that conforms to the standard. It supports the following
application servers:</p>
<ul>
@@ -348,30 +110,46 @@ it:</p>
<ul>
<li>Mozilla Firefox releases 2, and 3 (see notice above about
- Gecco 1.7).</li>
- <li>Internet Explorer releases 6, 7, and 8.</li>
+ Gecko 1.7).</li>
+ <li>Internet Explorer releases 6, 7, and 8<sup>&#8224;</sup>.</li>
<li>Safari 3</li>
- <li>Opera 9.6</li>
+ <li>Opera 9.6<sup>&#8225;</sup></li>
</ul>
-<p>There may be differences between the exact versions of the supported browsers that may
-cause incompatibility with applications made with IT Mill Toolkit. Support for Opera
-has currently some limitations, such as the front page of the Sampler demo.</p>
+<p style="font-size: 80%;">&#8224; Internet Explorer 8 RC1 may not be usable because of a
+serious bug in the RC1. <a href="http://dev.itmill.com/ticket/2578">#2578</a><br/>
+
+&#8225; The current support for Opera has some limitations, such as the front page of
+the Sampler demo. <a href="http://dev.itmill.com/ticket/2652">#2652</a></p>
+
+<p>The support for browsers follows the support by GWT. The browsers are supported on both
+Windows and Mac, if available. Firefox is supported also on Linux (Opera 10a1 works also
+on Linux though also suffers from <a
+href="http://dev.itmill.com/ticket/2652">#2652</a>). There may be differences between the
+exact versions of the supported browsers that may cause incompatibility with applications
+made with IT Mill Toolkit.</p>
<p>The following browsers are not supported but have been found to
work to a large degree:</p>
+
<ul>
- <li>Safari 2</li>
+ <li>Safari 2, and 4 beta</li>
<li>Firefox 1.5</li>
- <li>iPhone</li>
- <li>Epiphany, Galeon, and other Gecco-based browsers (see notice
- about Gecco 1.7 above).</li>
+ <li>Google Chrome 1.0.x (available only for Windows)</li>
+ <li>iPhone (firmware 2.2)</li>
+ <li>Midori (0.1.2)</li>
+ <li>Epiphany (2.22.3), Galeon, and other Gecko-based browsers (see the notice
+ regarding Gecko 1.7 above). Also WebKit-based Epiphany (2.22.3) works.</li>
+ <li>Konqueror 4.2 (3.5.x does not work)</li>
<li>Nokia Internet Tablet N800 and N810 (ITOS 2008, Opera-based browser).</li>
</ul>
-<p>Nokia E-series phones with at least 128MB of memory have been known to work with older
-versions, but not with IT Mill Toolkit 5.2 and later. Konqueror, the default browser in
-many Linux distributions, is known to not work.</p>
+<p>The reported versions are those that have been tested, though other versions may work
+as well.</p>
+
+<p>Nokia E-series phones, such as E90, have been known to work with older versions, but
+not with IT Mill Toolkit 5.2 and later. Links, Lynx, and other text-based browsers do not
+work.</p>
<!-- h2>ChangeLog Between IT Mill Toolkit 5.1.2 and 5.2.0</h2 --></div>
<!-- /getting-started -->
diff --git a/build/VERSION.properties b/build/VERSION.properties
index 1d7413b235..85aede4896 100644
--- a/build/VERSION.properties
+++ b/build/VERSION.properties
@@ -1 +1 @@
-version=5.3.0-rc13
+version=5.3.0
diff --git a/build/bin/mergetool.py b/build/bin/mergetool.py
new file mode 100755
index 0000000000..91d9d5105c
--- /dev/null
+++ b/build/bin/mergetool.py
@@ -0,0 +1,707 @@
+#!/usr/bin/python
+
+import sys,re,os,string,urllib,httplib
+
+################################################################################
+# Configuration
+################################################################################
+
+# Determine repository root
+pin = os.popen("svn info|grep 'Repository Root'|sed -e 's/^.\+: //'", "r")
+REPOSITORY = pin.read().rstrip()+"/"
+pin.close()
+
+print "Repository: %s" % (REPOSITORY)
+
+################################################################################
+# Parse command-line arguments
+################################################################################
+def help(exitvalue = 0):
+ print "Usage: batchmerge [options] <command>\n"
+ print "Options:"
+ print "\t-m\tOnly merge. (For 'single' command.)"
+ print "\t-c\tOnly commit. (For 'single' command.)"
+ print "\t-html\tHTML output. (For 'log' command.)"
+ print "\t-author\tHTML output. (Include author in HTML log.)"
+ print "\t-milestone <ms>\tList tickets in milestone (For 'log' command.)"
+ print "\nCommands:"
+ print "massmerge <cfg> <src> [<from>] "
+ print " - Merges changesets listed in the configuration"
+ print " file. The file is in svn log (text) format."
+ print " You can comment out unwanted changesets."
+ print " Merge is stopped on conflict."
+ print " If you give the optional <from> parameter,"
+ print " merge is started from the changeset number. "
+ print "single <chg#> <target> - Merges a single changeset. If -m is given,"
+ print " only merge is done. If -c is given, only commit is done."
+ print "revert - Reverts all changes made to repository except"
+ print " changes in this program and the merge files."
+ print "log <cfg> <src> <trg> - Prints a ChangeLog as it will appear in the"
+ print " commit log. If -html option is given,"
+ print " the log is printed in a HTML format"
+ print " suitable for the Release Notes."
+ print "commit <cfg> <src> <trg> - Commits all changes, except changes to this"
+ print " program and merge files. The commit log"
+ print " comment includes list of all changesets"
+ print " listed in the configuration. The <target>"
+ print " is the branch name, e.g., \"5.2\".\n"
+ print "Common parameters:"
+ print " <cfg> - Configuration file (svn text log format)."
+ print " <src> - Source branch relative to repository URI."
+ print " <trg> - Target branch relative to repository URI."
+ print "You must run the command in the root directory of the branch."
+ print "The program file contains some basic configuration parameters."
+ sys.exit(exitvalue)
+
+################################################################################
+# Globals
+################################################################################
+tickets = {}
+
+################################################################################
+# Utility Functions
+################################################################################
+def command(cmd, dryrun=0):
+ print cmd
+ if not dryrun:
+ if os.system(cmd):
+ print "Command failed, exiting."
+ sys.exit(1)
+ else:
+ print "Dry run - not executing."
+
+def listChangedFiles():
+ # Get Svn status
+ pin = os.popen("svn st", "r")
+ lines = pin.readlines()
+ pin.close()
+
+ changed = []
+ for line in lines:
+ # Remove trailing newline
+ line = line.rstrip()
+ print line
+
+ # Extract the file state and name
+ filestate = line[0:2].strip()
+ filename = line[7:].strip()
+
+ # Ignore files in build directory
+ if (filename.startswith("build/merge/") \
+ or filename.startswith("build/bin/mergetool.py") \
+ or filename.startswith("build/testing")) \
+ and filestate == "M":
+ continue
+
+ # File is changed if it is not local
+ if filestate != "?":
+ changed.append(filename)
+
+ return changed
+
+# Retrieves ticket summary string with HTTP
+# Returns: (summary, milestone)
+def fetchSummary(ticketno):
+ params = urllib.urlencode({'format': 'tab'})
+ conn = httplib.HTTPConnection("dev.itmill.com")
+ conn.request("GET", "/ticket/%d?%s" % (ticketno, params) )
+ response = conn.getresponse()
+ data = response.read()
+ conn.close()
+
+ lines = data.split("\n")
+ data = reduce(lambda x,y: x+"\n"+y, lines[1:])
+ #cols = lines[1].split("\t")
+
+ cols = data.split("\t")
+
+ return (cols[1],cols[8])
+
+# Adds summary to ticket number, unless the context already has it
+# Returns: (summary, milestone)
+def addSummary(m):
+ ticketnum = int(m.group(1))
+ context = m.group(2)
+ if re.match(" *\(", context):
+ # The context already has ticket summary
+ return "#%d%s" % (ticketnum, context)
+
+ (summary,milestone) = fetchSummary(ticketnum)
+
+ # Remove possible " quotation from the summary
+ if summary.startswith('"'):
+ summary = summary.strip('"')
+ summary = summary.replace('""', '"')
+
+ # Add summaries to further ticket numbers recursively
+ context = re.sub(r'#([0-9]+)(.*)', addSummary, context)
+
+ return "#%s (<i>%s</i>) %s" % (ticketnum, summary, context)
+
+################################################################################
+# Change
+################################################################################
+class Ticket:
+ def __init__(self, id, summary=None, milestone=None):
+ self.id = id
+ self.summary = summary
+ self.milestone = milestone
+
+ def fetchData(self):
+ (summary, milestone) = fetchSummary(self.id)
+ self.summary = summary
+ self.milestone = milestone
+
+################################################################################
+# Change
+################################################################################
+class Change:
+ def __init__(self, id, undo=0, author=""):
+ self.id = id
+ self.author = author
+ self.comment = ""
+ self.undo = undo
+ self.tickets = []
+
+ def addCommentLine(self, line):
+ self.comment += line
+
+ def merge(self, trunkURI, dryrun=0):
+ drycmd = ""
+ if dryrun:
+ drycmd = "--dry-run"
+
+ # Handle negative merge
+ mergesign = ""
+ if self.undo:
+ mergesign = "-"
+
+ # Build the merge command
+ cmd = "svn merge --non-interactive %s -c %s%d %s" % (drycmd, mergesign, self.id, trunkURI)
+ print cmd
+
+ # Run the merge command
+ pin = os.popen(cmd, "r")
+ lines = pin.readlines()
+ pin.close()
+
+ # Parse the lines for conflicts
+ conflicts = 0
+ for line in lines:
+ print line[:-1]
+
+ # Check for conflict
+ if line.startswith("C"):
+ conflicts += 1
+
+ # Check for skipped file
+ elif line.startswith("Skipped"):
+ conflicts += 1
+
+ filename = line[8:-1]
+
+ # Simply exit if there was any problem
+ if conflicts > 0:
+ print "Problems detected. Exiting."
+ sys.exit(1)
+
+ def fetchComment(self, trunkURI):
+ cmd = "svn log -r %d %s" % (self.id, trunkURI)
+
+ # Run the log command
+ pin = os.popen(cmd, "r")
+ lines = pin.readlines()
+ pin.close()
+
+ STATE_START = 0
+ STATE_COMMENT = 1
+ comment = None
+ state = STATE_START
+ for line in lines:
+ if state == STATE_START:
+ if line == "\n":
+ state = STATE_COMMENT
+ elif state == STATE_COMMENT:
+ if line.startswith("-----------------"):
+ self.comment = comment
+ return comment
+ elif comment:
+ comment += "\n" + line.rstrip("\n")
+ else:
+ comment = line.rstrip("\n")
+
+ self.comment = comment
+ return comment
+
+ def commit(self):
+ # Write the log comment to a temporary file
+ logtmpname = "/tmp/merge-single-%d.log" % (os.getpid())
+ fout = open(logtmpname, "w")
+ fout.write(self.comment)
+ fout.close()
+
+ # Get listo
+ files = listChangedFiles()
+ if len(files) == 0:
+ print "Error: Will not do empty commit."
+ sys.exit(1)
+
+ # Write the list of files to be committed to a temporary file
+ changedfiles = ("\n".join(files)) + "\n"
+ targettmpname = "/tmp/merge-targets-%d.txt" % (os.getpid())
+ fout = open(targettmpname, "w")
+ fout.write(changedfiles)
+ fout.close()
+ print changedfiles,
+
+ command("svn commit --file %s --targets %s" % (logtmpname, targettmpname))
+
+ command("rm %s %s" % (logtmpname, targettmpname))
+
+
+ def getNumber(self):
+ return self.id
+
+ def getComment(self):
+ return self.comment
+
+ def getUndo(self):
+ return self.undo
+
+ def getAuthor(self):
+ return self.author
+
+ def isForMilestone(self, milestone):
+ return self.author
+
+ def addSummary(self, m, target_milestone=None):
+ ticketnum = int(m.group(1))
+ context = m.group(2)
+ if re.match(" *\(", context):
+ # The context already has ticket summary
+ return "#%d%s" % (ticketnum, context)
+
+ # Check for cached ticket
+ if tickets.has_key(ticketnum):
+ summary = tickets[ticketnum].summary
+ ticket_milestone = tickets[ticketnum].milestone
+ else:
+ # Fetch ticket from server and add to cache
+ (summary,ticket_milestone) = fetchSummary(ticketnum)
+ tickets[ticketnum] = Ticket(ticketnum,summary,ticket_milestone)
+
+ self.tickets.append(ticketnum);
+
+ # Remove possible " quotation from the summary
+ if summary.startswith('"'):
+ summary = summary.strip('"')
+ summary = summary.replace('""', '"')
+
+ ticketnum = "#%s" % (ticketnum)
+
+ # Emphasize tickets matching the target milestone
+ if target_milestone:
+ if ticket_milestone.find(target_milestone) != -1:
+ ticketnum = "<b>%s</b>" % (ticketnum)
+
+ # Add summaries to further ticket numbers recursively
+ context = re.sub(r'#([0-9]+)(.*)', lambda m: self.addSummary(m, target_milestone=target_milestone), context)
+
+ return "%s (<i>%s</i>) %s" % (ticketnum, summary, context)
+
+ def registerTicket(self, m, ticketNumbers):
+ ticketNumbers[int(m.group(1))] = 1
+ return ""
+
+ # Returns a list of ticket numbers referenced by this change
+ def listTickets(self):
+ ticketNumbers = {}
+ re.sub(r'#([0-9]+)', lambda m: self.registerTicket(m,ticketNumbers=ticketNumbers), self.comment)
+ return ticketNumbers.keys()
+
+################################################################################
+# Read configuration file
+################################################################################
+class Configuration:
+ def __init__(self, cfgfilename, startfrom=0):
+ self.changes = []
+ self.readConfig(cfgfilename, startfrom)
+
+ def readConfig(self, cfgfilename, startfrom=0):
+ fin = open(cfgfilename, "r")
+ content = fin.readlines()
+ fin.close()
+
+ # Parse configuration
+ currentChange = None
+ skipChange = 0
+ for line in content:
+ m_changestart = re.match(r'(-?)r([0-9]+)', line)
+ m_endofchange = re.match(r'------+', line)
+ m_emptyline = re.match(r'^$', line)
+ if m_changestart:
+ # Parse negative merge
+ undo = 0
+ if m_changestart.group(1) == "-":
+ undo = 1
+
+ # Get changeset number
+ id = int(m_changestart.group(2))
+
+ # Skip the target if its number is too small
+ if startfrom != 0 and id < startfrom:
+ skipChange = 1
+
+ # Get the author
+ author = re.sub(r'\@.+', '', line.split("|")[1].strip())
+
+ currentChange = Change(id, undo=undo, author=author)
+
+ elif m_endofchange:
+ # Register changeset, unless it is marked
+ # for skipping.
+ if currentChange:
+ if skipChange:
+ skipChange = 0
+ else:
+ self.changes.append(currentChange)
+ currentChange = None
+ elif m_emptyline:
+ pass
+ else:
+ if currentChange:
+ currentChange.addCommentLine(line)
+
+ def massMerge(self, trunkURI, dryrun=0, allatonce=0):
+ if not allatonce:
+ # Merge one changeset at a time
+ for change in self.changes:
+ change.merge(trunkURI, dryrun=dryrun)
+ else:
+ # What is the first changeset in the merge?
+ smallest = 99999999
+ for change in self.changes:
+ if change.getNumber() < smallest:
+ smallest = change.getNumber()
+
+ drycmd = ""
+ if dryrun:
+ drycmd = "--dry-run"
+
+ # Merge from the first changeset to HEAD
+ cmd = "svn merge --non-interactive %s -r %d:HEAD %s" % (drycmd, smallest, trunkURI)
+ print cmd
+ command(cmd)
+
+ def createLogComment(self):
+ # Create a log comment that lists all merged changesets with
+ # comments
+ logcomment = "Merge from %s to %s:\n" % (sourcebranch, targetbranch)
+ for change in self.changes:
+ changeno = change.getNumber()
+ changecomment = change.getComment().rstrip("\n")
+ if change.getUndo():
+ logcomment += "Reverted [%d] merge: %s\n" % (changeno, changecomment)
+ else:
+ logcomment += "Merged [%d]: %s\n" % (changeno, changecomment)
+ return logcomment
+
+ def logHtml(self, author=0, milestone=None):
+ # In author inclusion mode, include some styles to make a printout look better
+ if author:
+ print "<head>\n<style type=\"text/css\">\n"+ \
+ "tr {\n vertical-align: top;\n}\ntd {\n font-size: 8pt;\n}\n</style>\n</head>\n"
+
+ # Print header
+ print "<table id=\"changelog-table\">"
+ authorcolumnheader = ""
+ if author:
+ authorcolumnheader = "<td>Author</td>"
+ print " <tr><td>#</td><td>Changeset Comment</td>%s</tr>" % (authorcolumnheader)
+
+ # Print body: the changes
+ for change in self.changes:
+ changeno = change.getNumber()
+ changecomment = change.getComment().rstrip("\n")
+
+ changeref = "[%d]" % (changeno)
+
+ # Handle merge undo markup
+ if change.getUndo():
+ changeref = "<font class=\"changeset-merge-undone\">%s</font>" % (changeref)
+ changecomment = "<font class=\"changeset-merge-undone\">%s</font>" % (changecomment)
+ changecomment = "Reverted a change: "+changecomment
+
+ authorcolumn = ""
+ if author:
+ authorcolumn = "<td>%s</td>" % (change.getAuthor())
+
+ # Add ticket summary after ticket number, if missing
+ # TODO: this handles only one
+ changecomment = re.sub(r'#([0-9]+)(.*)', lambda m: change.addSummary(m, target_milestone=milestone), changecomment, 100)
+ # item = re.sub(r'#([0-9]+)(.*)', '#\\1 (SUMMARY) \\2', item)
+
+ # Change ticket numbers to references to tickets
+ changecomment = re.sub(r'#([0-9]+)', '#<a href="http://dev.itmill.com/ticket/\\1">\\1</a>', changecomment)
+
+ # Change changeset numbers to references to changesets
+ changecomment = re.sub(r'\[([0-9]+)\]', '[<a href="http://dev.itmill.com/changeset/\\1">\\1</a>]', changecomment)
+ changeref = re.sub(r'\[([0-9]+)\]', '[<a href="http://dev.itmill.com/changeset/\\1">\\1</a>]', changeref)
+
+ # See if any of the tickets have milestone under work.
+ if milestone:
+ for ticketnum in change.tickets:
+ ticket = tickets[ticketnum]
+ if ticket.milestone.find(milestone) != -1:
+ changeref = "<b>%s</b>" % (changeref)
+
+ # Make basic HTML formatting
+ item = " <tr><td>%s:</td><td>%s</td>%s</tr>" % (changeref, changecomment, authorcolumn)
+
+ print item
+ sys.stdout.flush()
+ print "</table>"
+
+ # Prints a commit log to standard output
+ def log(self, sourcebranch, targetbranch, html=0, author=0, milestone=None):
+ if html:
+ self.logHtml(author=author,milestone=milestone)
+ return
+ sys.stdout.write(self.createLogComment())
+
+ def commit(self, sourcebranch, targetbranch, dryrun=0):
+ logcomment = self.createLogComment()
+
+ # Write the log comment to a temporary file
+ logtmpname = "/tmp/massmerge-pid-%d.log" % (os.getpid())
+ fout = open(logtmpname, "w")
+ fout.write(logcomment)
+ fout.close()
+
+ # Write the list of files to be committed to a temporary file
+ changedfiles = "\n".join(listChangedFiles())
+ targettmpname = "/tmp/massmerge-targets-%d.txt" % (os.getpid())
+ fout = open(targettmpname, "w")
+ fout.write(changedfiles)
+ fout.close()
+
+ if dryrun:
+ print "Log:"
+ os.system("cat %s" % (logtmpname))
+ print "\nChanged Files:"
+ os.system("cat %s" % (targettmpname))
+ print "\n"
+
+ command("svn commit --file %s --targets %s" % (logtmpname, targettmpname), dryrun=dryrun)
+
+ command("rm %s %s" % (logtmpname, targettmpname))
+
+ def listTickets(self):
+ fixed = {}
+
+ for change in self.changes:
+ changeno = change.getNumber()
+ changeTickets = change.listTickets()
+ if len(changeTickets)>0 and change.comment.lower().find("fix") != -1:
+ for ticket in changeTickets:
+ fixed[ticket] = 1
+
+ fixedlist = fixed.keys()
+ fixedlist.sort()
+ # print "Fixed:", fixedlist
+
+ print "<ul>"
+
+ for ticketNum in fixedlist:
+ if not tickets.has_key(ticketNum):
+ ticket = Ticket(ticketNum)
+ ticket.fetchData()
+ tickets[ticketNum] = ticket
+
+ ticket = tickets[ticketNum]
+ # print "%d: %s" % (ticket.id, ticket.summary)
+ print " <li><a href=\"http://dev.itmill.com/ticket/%d\">#%d</a>: %s</li>" % (ticket.id, ticket.id, ticket.summary)
+ sys.stdout.flush()
+
+ print "</ul>"
+
+################################################################################
+# Commands
+################################################################################
+
+# Command: revert
+def commandRevert():
+ # Get Svn status
+ pin = os.popen("svn st", "r")
+ lines = pin.readlines()
+ pin.close()
+
+ reverted = []
+ removed = []
+ for line in lines:
+ # Remove trailing newline
+ line = line[:-1]
+
+ # Extract the file state and name
+ filestate = line[0:2].strip()
+ filename = line[7:].strip()
+
+ # Ignore files in build directory
+ if (filename.startswith("build/merge/") \
+ or filename.startswith("build/bin/")) \
+ and filestate == "M":
+ continue
+
+ # Added files are simply deleted
+ if filestate != "?":
+ reverted.append(filename)
+
+ # Added files have to be removed in addition to reverting
+ if filestate == "A":
+ removed.append(filename)
+
+ # Remove conflict choises
+ elif filestate == "?" and \
+ (filename.find(".merge-left.r") != -1 or \
+ filename.find(".merge-right.r") != -1):
+ removed.append(filename)
+
+ # Revert files marked for reverting
+ donework = 0
+ if len(reverted) > 0:
+ files = " ".join(reverted)
+ command("svn revert -R %s" % (files))
+ donework = 1
+
+ # Remove files marked for deletion
+ if len(removed) > 0:
+ files = " ".join(removed)
+ command("rm %s" % (files))
+ donework = 1
+
+ if not donework:
+ print "Nothing to do."
+
+# Command: massmerge
+def commandMassmerge(cfgfilename, sourceuri, startfrom, dryrun=0, allatonce=0):
+ cfg = Configuration(cfgfilename, startfrom=startfrom)
+ cfg.massMerge(sourceuri, dryrun=dryrun, allatonce=allatonce)
+
+# Command: single
+def commandSingle(trunkuri, changeset, sourcebranch, targetbranch, onlymerge=0, onlycommit=0):
+ change = Change(changeset)
+ print "Found changeset with log comment:\n "+change.fetchComment(trunkuri) + "\n"
+
+ change.merge(trunkuri, dryrun=onlycommit)
+ if onlycommit:
+ print "Got file list."
+ else:
+ print "Merge successful."
+
+ # Change the comment
+ change.comment = "Merged [%d] from %s to %s branch: %s" % (change.id, sourcebranch, branchname, change.comment)
+ print "\nLog comment: \"%s\"" % (change.comment)
+
+ if not onlymerge:
+ print "Committing."
+ change.commit()
+
+# Command: commit
+def commandCommit(cfgfilename, sourcebranch, targetbranch, dryrun=0):
+ cfg = Configuration(cfgfilename)
+ cfg.commit(sourcebranch, targetbranch, dryrun=dryrun)
+
+# Command: log
+def commandLog(cfgfilename, sourcebranch, targetbranch, html=0, author=0, milestone=None):
+ cfg = Configuration(cfgfilename)
+ cfg.log(sourcebranch, targetbranch, html=html, author=author, milestone=milestone)
+
+# Command: tickets
+def commandTickets(cfgfilename):
+ cfg = Configuration(cfgfilename)
+ cfg.listTickets()
+
+################################################################################
+# Main Program
+################################################################################
+
+# Handle switches
+dryrun = 0
+html = 0
+html_author = 0
+html_milestone = None
+onlymerge = 0
+onlycommit = 0
+all = 0
+while len(sys.argv)>1 and sys.argv[1][0] == '-':
+ if sys.argv[1] == "-d":
+ dryrun = 1
+ del sys.argv[1:2]
+
+ elif sys.argv[1] == "-html":
+ html = 1
+ del sys.argv[1:2]
+
+ elif sys.argv[1] == "-author":
+ html_author = 1
+ del sys.argv[1:2]
+
+ elif sys.argv[1] == "-milestone":
+ html_milestone = sys.argv[2]
+ del sys.argv[1:3]
+
+ elif sys.argv[1] == "-m":
+ onlymerge = 1
+ del sys.argv[1:2]
+
+ elif sys.argv[1] == "-c":
+ onlycommit = 1
+ del sys.argv[1:2]
+
+ elif sys.argv[1] == "-all":
+ all = 1
+ del sys.argv[1:2]
+
+ else:
+ print "Invalid option '%s'." % (sys.argv[1])
+ sys.exit(1)
+
+if len(sys.argv) < 2:
+ help(1)
+
+# Handle commands
+if sys.argv[1] == "revert":
+ commandRevert()
+
+elif (len(sys.argv) == 4 or len(sys.argv)==5) and sys.argv[1] == "massmerge":
+ cfgfilename = sys.argv[2]
+ sourcebranch = sys.argv[3]
+ startfrom = None
+ if len(sys.argv)>4:
+ startfrom = int(sys.argv[4])
+ commandMassmerge(cfgfilename, sourceuri=REPOSITORY+sourcebranch, startfrom=startfrom, dryrun=dryrun, allatonce=all)
+
+elif len(sys.argv) == 5 and sys.argv[1] == "single":
+ changeset = int(sys.argv[2])
+ sourcebranch = sys.argv[3]
+ targetbranch = sys.argv[4]
+ commandSingle(REPOSITORY+sourcebranch, changeset, targetbranch, onlymerge=onlymerge, onlycommit=onlycommit)
+
+elif len(sys.argv) == 5 and sys.argv[1] == "commit":
+ cfgfilename = sys.argv[2]
+ sourcebranch = sys.argv[3]
+ targetbranch = sys.argv[4]
+ commandCommit(cfgfilename, sourcebranch, targetbranch, dryrun=dryrun)
+
+elif len(sys.argv) == 5 and sys.argv[1] == "log":
+ cfgfilename = sys.argv[2]
+ sourcebranch = sys.argv[3]
+ targetbranch = sys.argv[4]
+ commandLog(cfgfilename, sourcebranch, targetbranch, html=html, author=html_author, milestone=html_milestone)
+
+elif len(sys.argv) == 3 and sys.argv[1] == "tickets":
+ cfgfilename = sys.argv[2]
+ commandTickets(cfgfilename)
+
+else:
+ help(1)
diff --git a/build/bin/svnlog-to-rn.py b/build/bin/svnlog-to-rn.py
new file mode 100755
index 0000000000..5cca3705f9
--- /dev/null
+++ b/build/bin/svnlog-to-rn.py
@@ -0,0 +1,109 @@
+#!/usr/bin/python
+################################################################################
+# SVN Log to ChangeLog generator for Release Notes
+#
+# Generates list of changes in HTML for ChangeLog
+# from SVN Log in XML format. You typically generate the log with
+# a command such as:
+# svn log -v -r 1234:HEAD > svnlog-1234:HEAD.log.xml
+# The command must be executed in the root directory of Toolkit project,
+# either in the trunk or in the proper branch. The converter is then
+# used as follows:
+# ./build/bin/svnlog-to-rn.py svnlog-1234:HEAD.log.xml
+#
+# The ChangeLog generator will strip away any merges that begin with
+# "Merged [...] from trunk to x.x branch."
+#
+# The generator will handle the following markup:
+# - Changeset tags such as [1234] to links to dev.itmill.com/changeset/1234
+# - Ticket references such as #1234 to links to dev.itmill.com/ticket/1234
+# - If ticket reference does not have explanation in parentheses,
+# the script will fetch the summary of the ticket from Trac and
+# add it in parentheses after the reference, such as:
+# "fixes #1234 (A nasty bug I found)".
+#
+# Requirements:
+# - Xalan
+################################################################################
+
+import sys,re,os,httplib,urllib
+
+################################################################################
+# Convert XML to XHTML
+# - The transformation includes various relevent information
+# and does basic formatting
+################################################################################
+
+# Determine path to XSLT file
+pathToScript = sys.argv[0]
+sloc = pathToScript.rfind("/")
+pathToScript = pathToScript[:sloc]
+
+if len(sys.argv) != 2:
+ print "Usage: svnlog-to-rn.py <logfile.xml>"
+ print "Read the svnlog-to-rn.py header for more info."
+ sys.exit(1)
+
+# Open Xalan
+filename = sys.argv[1]
+fin = open(filename, "r")
+(pout,pin) = os.popen2("xalan -xsl %s/svnlog-to-rn.xsl" % (pathToScript))
+
+# Preprocessing before feeding to XSLT Processor
+lines = fin.readlines()
+out = ""
+for line in lines:
+ if line.find("action") != -1:
+ line = line.replace(r'>[^<]+/', '')
+ #print line,
+ pout.write(line)
+pout.close()
+
+################################################################################
+# Helper functions for postprocessing
+################################################################################
+
+# Retrieves summary string with HTTP
+def fetchSummary(ticketno):
+ params = urllib.urlencode({'format': 'tab'})
+ conn = httplib.HTTPConnection("dev.itmill.com")
+ conn.request("GET", "/ticket/%d?%s" % (ticketno, params) )
+ response = conn.getresponse()
+ data = response.read()
+ conn.close()
+
+ lines = data.split("\n")
+ cols = lines[1].split("\t")
+ return cols[1]
+
+# Adds summary to ticket number, unless the context already has it
+def addSummary(m):
+ ticketnum = int(m.group(1))
+ context = m.group(2)
+ if re.match(" *\(", context):
+ # The context already has ticket summary
+ return "#%d%s" % (ticketnum, context)
+
+ summary = fetchSummary(ticketnum)
+
+ return "#%s (<i>%s</i>) %s" % (ticketnum, summary, context)
+
+################################################################################
+# Postprocessing for XSLT output
+################################################################################
+
+lines = pin.readlines()
+for line in lines:
+ # Add ticket summary after ticket number, if missing
+ line = re.sub(r'#([0-9]+)(.*)', addSummary, line)
+
+ # Change ticket numbers to references to tickets
+ line = re.sub(r'#([0-9]+)', '#<a href="http://dev.itmill.com/ticket/\\1">\\1</a>', line)
+
+ # Change changeset numbers to references to changesets
+ #line = re.sub(r'\[([0-9]+)\]', '[<a href="http://dev.itmill.com/changeset/\\1">\\1</a>]', line)
+
+ # Remove prefix about merging
+ line = re.sub(r'Merged.+from trunk to [0-9]+.[0-9]+ branch: ', '', line)
+
+ print line,
diff --git a/build/bin/svnlog-to-rn.xsl b/build/bin/svnlog-to-rn.xsl
new file mode 100644
index 0000000000..75dd762db9
--- /dev/null
+++ b/build/bin/svnlog-to-rn.xsl
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0">
+
+ <xsl:output method="html"/>
+
+ <xsl:template match="logentry">
+ <li>[<xsl:element name="a"><xsl:attribute name="href">http://dev.itmill.com/changeset/<xsl:value-of select="@revision"/></xsl:attribute><xsl:value-of select="@revision"/></xsl:element>]: <xsl:value-of select="msg"/></li>
+ </xsl:template>
+
+ <xsl:template match="/">
+ <html>
+ <body bgcolor="#FFFFFF">
+ <xsl:apply-templates/>
+ </body>
+ </html>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/build/build-www.itmill.com.xml b/build/build-www.itmill.com.xml
deleted file mode 100644
index e983908446..0000000000
--- a/build/build-www.itmill.com.xml
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0"?>
-
-<project name="www.itmill.com" basedir="../" default="site">
-
- <target name="site" depends="clean-all, manual-html, tutorial-html" />
-
- <target name="init">
-
- <!-- Create result dir unless already exists -->
- <mkdir dir="build/result" />
-
- <property file="build/VERSION.properties" />
- <property name="product-file" value="itmill-toolkit" />
- <property name="product-name" value="IT Mill Toolkit" />
- <property name="toolkit-package" value="com/itmill/toolkit" />
-
- <property file="build/html-style.properties" />
-
- <!-- Destination files -->
- <property name="package-file-name" value="${product-file}-${version}.zip" />
- <property name="lib-bin-jar-name" value="${product-file}-${version}.jar" />
- <property name="demo-lib-jar-name" value="${product-file}-demo-${version}.jar" />
- <property name="lib-src-jar-name" value="${product-file}-src-${version}.jar" />
- <property name="themes-jar-name" value="${product-file}-themes-${version}.jar" />
- <property name="demo-war-name" value="${product-file}-demo-${version}.war" />
-
- <echo message="Prepared to build www.itmill.com html files" />
-
- </target>
-
- <!-- ================================================================== -->
- <!-- Build Reference Manual. -->
- <!-- ================================================================== -->
-
- <!-- Initialize properties especially for the Reference Manual. -->
- <target name="init-manual" depends="">
- <!-- Sets the current date as the publication date of the Manual. -->
- <tstamp>
- <format property="manual.pubdate" pattern="yyyy-MM-dd"/>
- </tstamp>
- </target>
-
- <target name="manual-html" depends="init, init-manual">
- <echo message="Building manual" />
- <mkdir dir="build/result/www.itmill.com/manual" />
- <delete file="build/docbook/conf/temp.xsl" />
- <copy file="build/docbook/www.itmill.com/custom-www.itmill.com-docbook.xsl" tofile="build/docbook/conf/temp.xsl">
-
- <filterchain>
- <replacetokens>
- <token key="BODYHEADER" value="${www.manual.body.start1}${www.manual.docbook.head.title}${www.manual.body.start2}" />
- <token key="BODYFOOTER" value="${www.manual.body.end}" />
- </replacetokens>
- </filterchain>
- </copy>
- <path id="docbook-xsl.classpath">
- <pathelement path="build/lib/fserializer.jar" />
- <pathelement path="build/lib/xalan.jar" />
- <pathelement path="build/lib/xercesImpl.jar" />
- <pathelement path="build/lib/xml-apis.jar" />
- </path>
- <java classname="org.apache.xalan.xslt.Process" failonerror="yes" fork="yes" maxmemory="1300m">
- <arg value="-in" />
- <arg value="doc/manual/book.xml" />
- <arg value="-xsl" />
- <arg value="build/docbook/conf/temp.xsl" />
- <arg value="-out" />
- <arg value="build/result/www.itmill.com/manual/index.html" />
- <arg value="-param" />
- <arg value="section.autolabel" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="section.label.includes.component.label" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="section.autolabel.max.depth" />
- <arg value="2" />
- <arg value="-param" />
- <arg value="use.extensions" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="manual.pubdate" />
- <arg value="${manual.pubdate}" />
- <arg value="-param" />
- <arg value="manual.version" />
- <arg value="${version}" />
- <classpath refid="docbook-xsl.classpath" />
- </java>
- <delete file="build/docbook/conf/temp.xsl" />
- <copy todir="build/result/www.itmill.com/manual/img">
- <fileset dir="doc/manual/img">
- <exclude name="**/.svn" />
- </fileset>
- </copy>
- <!-- rename to JSP -->
- <move todir="build/result/www.itmill.com/manual">
- <fileset dir="build/result/www.itmill.com/manual">
- <include name="*.html" />
- </fileset>
- <mapper type="glob" from="*.html" to="*.jsp" />
- </move>
- <!-- make a zip file -->
- <zip destfile="build/result/www.itmill.com/itmill-toolkit-5-manual.zip" basedir="build/result/www.itmill.com/manual" />
- </target>
-
- <!-- ================================================================== -->
- <!-- Build Application Tutorial. -->
- <!-- ================================================================== -->
-
- <!-- Initialize properties especially for the Tutorial. -->
- <target name="init-tutorial" depends="">
- <!-- Sets the current date as the publication date of the Tutorial. -->
- <tstamp>
- <format property="tutorial.pubdate" pattern="yyyy-MM-dd"/>
- </tstamp>
-
- <mkdir dir="build/result/www.itmill.com/tutorial" />
- </target>
-
- <target name="tutorial-html" depends="init, init-tutorial">
- <echo message="Building tutorial" />
- <echo>Publication date is ${tutorial.pubdate}</echo>
-
- <delete file="build/docbook/conf/temp-tutorial.xsl" />
- <copy file="build/docbook/www.itmill.com/custom-www.itmill.com-docbook.xsl" tofile="build/docbook/conf/temp-tutorial.xsl">
-
- <filterchain>
- <replacetokens>
- <token key="BODYHEADER" value="${www.manual.body.start1}${www.manual.docbook.head.title}${www.manual.body.start2}" />
- <token key="BODYFOOTER" value="${www.manual.body.end}" />
- </replacetokens>
- </filterchain>
- </copy>
- <path id="docbook-xsl.classpath">
- <pathelement path="build/lib/fserializer.jar" />
- <pathelement path="build/lib/xalan.jar" />
- <pathelement path="build/lib/xercesImpl.jar" />
- <pathelement path="build/lib/xml-apis.jar" />
- </path>
- <java classname="org.apache.xalan.xslt.Process" failonerror="yes" fork="yes" maxmemory="512m">
- <arg value="-in" />
- <arg value="doc/tutorial/tutorial.xml" />
- <arg value="-xsl" />
- <arg value="build/docbook/conf/temp-tutorial.xsl" />
- <arg value="-out" />
- <arg value="build/result/www.itmill.com/tutorial/index.html" />
- <arg value="-param" />
- <arg value="section.autolabel" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="section.label.includes.component.label" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="section.autolabel.max.depth" />
- <arg value="2" />
- <arg value="-param" />
- <arg value="use.extensions" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="manual.pubdate" />
- <arg value="${tutorial.pubdate}" />
- <arg value="-param" />
- <arg value="manual.version" />
- <arg value="${version}" />
- <classpath refid="docbook-xsl.classpath" />
- </java>
- <delete file="build/docbook/conf/temp-tutorial.xsl" />
- <copy todir="build/result/www.itmill.com/tutorial/img">
- <fileset dir="doc/tutorial/img">
- <exclude name="**/.svn" />
- </fileset>
- </copy>
- <!-- rename to JSP -->
- <move todir="build/result/www.itmill.com/tutorial">
- <fileset dir="build/result/www.itmill.com/tutorial">
- <include name="*.html" />
- </fileset>
- <mapper type="glob" from="*.html" to="*.jsp" />
- </move>
- <!-- make a zip file -->
- <zip destfile="build/result/www.itmill.com//itmill-toolkit-5-tutorial.zip" basedir="build/result/www.itmill.com/tutorial" />
- </target>
-
- <!-- Clean results - - - - - - - - - - - - - - - - - - - - - - - - - -->
- <target name="clean-all" depends="">
- <delete includeemptydirs="true" defaultexcludes="false">
- <fileset dir="build/result" includes="**/*" />
- </delete>
- <delete file="build/docbook/conf/temp.xsl" />
- </target>
-
-</project>
diff --git a/build/build.properties b/build/build.properties
index 3580fe286d..9208f4ed92 100644
--- a/build/build.properties
+++ b/build/build.properties
@@ -1,7 +1,8 @@
result-path=build/result
+checkout-path=build/checkout
product-file=itmill-toolkit
product-name=IT Mill Toolkit
toolkit-package=com/itmill/toolkit
-eclipse-workspace-name=itmill-toolkit-examples
+eclipse-workspace-name=vaadin-6-theme
eclipse-launch-vmargs=-Xms256M -Xmx512M
-gwt-dir=build/gwt
+gwt-dir=build/gwt/gwt
diff --git a/build/build.xml b/build/build.xml
index b7e75dfb24..06bcd3fb79 100644
--- a/build/build.xml
+++ b/build/build.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
-<project name="IT Mill Toolkit" basedir="../" default="package-all">
+<project
+ xmlns:antcontrib="antlib:net.sf.antcontrib"
+ name="IT Mill Toolkit"
+ basedir="../" default="package-all">
<!-- Package creation - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -24,6 +27,12 @@
${gwt-dir}/${platform} (linux|windows|mac) are used for
a) compile WebContent/ITMILL/widgetsets
b) creating platform specific release ZIP/TGZ packages.
+
+ NOTE FOR USING OOPHM:
+ * To build with oophm define the property platform=oophm
+ * In Eclipse this is done in External Tools Configurations -> properties
+ * If you are using windows you must use JDK 1.6 and not 1.5
+ * To enable building with JDK 1.6, define ignoreversion=1
-->
<!--
@@ -32,33 +41,44 @@
<target name="package-all" depends="clean-all, package-init, init, build, docs, internal-package-mac, internal-package-windows, internal-package-linux, internal-package-war" description="Build public packages for Windows, Linux and Mac platforms.">
</target>
- <target name="package-mac" depends="clean-all, package-init, init, build, docs, internal-package-mac" description="Create public tar.gz package for Mac.">
+ <target name="package-mac" depends="clean-result, package-init, init, build, docs, internal-package-mac" description="Create public tar.gz package for Mac.">
</target>
- <target name="package-windows" depends="clean-all, package-init, init, build, docs, internal-package-windows" description="Create public ZIP package for Windows.">
+ <target name="package-windows" depends="clean-result, package-init, init, build, docs, internal-package-windows" description="Create public ZIP package for Windows.">
</target>
- <target name="package-linux" depends="clean-all, package-init, init, build, docs, internal-package-linux" description="Create public tar.bz2 package for Linux.">
+ <target name="package-linux" depends="clean-result, package-init, init, build, docs, internal-package-linux" description="Create public tar.bz2 package for Linux.">
</target>
- <target name="package-oophm" depends="clean-all, package-init, init-oophm, build, docs, internal-package-oophm" description="Create public tar.gz package for OOPHM.">
+ <target name="package-oophm" depends="clean-result, package-init, init-oophm, build, docs, internal-package-oophm" description="Create public tar.gz package for OOPHM.">
</target>
- <target name="package-jar" depends="clean-all, package-init, init, libs" description="Create itmill-toolkit-x.y.z.jar file.">
+ <target name="package-jar" depends="clean-result, package-init, init, libs" description="Create itmill-toolkit-x.y.z.jar file.">
</target>
- <target name="package-war" depends="clean-all, package-init, init, build, docs, internal-package-mac, internal-package-war">
+ <target name="package-war" depends="clean-result, package-init, init, build, docs, internal-package-mac, internal-package-war">
</target>
+ <target name="package-test" depends="clean-result, nightly-init, package-init, init, build, docs, internal-package-linux, nightly-install">
+ </target>
+
+ <!-- ant contrib required for flow control (for loop, if, property override) -->
+ <!-- Note that we have to use a namespace to avoid clash when running sub-ant. -->
+ <taskdef uri="antlib:net.sf.antcontrib" resource="net/sf/antcontrib/antlib.xml">
+ <classpath>
+ <pathelement location="build/lib/ant-contrib-1.0b3.jar" />
+ </classpath>
+ </taskdef>
+
<!-- internal tests for packaging -->
- <target name="test-build" depends="clean-all, init, build" description="used for testing build.xml">
+ <target name="test-build" depends="clean-result, init, build" description="used for testing build.xml">
</target>
<target name="test-package" depends="init" description="used for testing build.xml">
<echo>Creating package for Mac platform.</echo>
- <var name="package-platform" value="mac" />
- <var name="eclipse-launch-vmargs" value="-XstartOnFirstThread -Xms128M -Xmx512M" />
+ <antcontrib:var name="package-platform" value="mac" />
+ <antcontrib:var name="eclipse-launch-vmargs" value="-XstartOnFirstThread -Xms128M -Xmx512M" />
<antcall target="add-platform-specific-files" inheritAll="true" inheritRefs="true" />
<delete file="${result-path}/eclipse-test" followsymlinks="false" />
<exec executable="ln" failonerror="false">
@@ -79,32 +99,43 @@
</target>
<!-- Clean results - - - - - - - - - - - - - - - - - - - - - - - - - -->
- <target name="clean-all" depends="">
+ <target name="clean-result" depends="">
<property file="build/build.properties" />
- <delete dir="${result-path}" includes="**/*" followsymlinks="false" defaultexcludes="false" includeemptydirs="true" failonerror="false">
- </delete>
+
+ <!-- Clean build result directory. -->
+ <delete dir="${result-path}" includes="**/*" followsymlinks="false" defaultexcludes="false" includeemptydirs="true" failonerror="false"/>
+ </target>
+
+ <!-- Clean checkout directory. -->
+ <target name="clean-checkout" depends="">
+ <property file="build/build.properties" />
+
+ <delete dir="${checkout-path}" includes="**/*" followsymlinks="false" defaultexcludes="false" includeemptydirs="true" failonerror="false"/>
</target>
+ <target name="clean-all" depends="clean-result, clean-checkout">
+ </target>
+
<!-- Find out which platform we are in -->
<target name="init-platform">
- <if>
+ <antcontrib:if>
<contains string="${os.name}" substring="Windows" />
<then>
<property name="platform" value="windows" />
</then>
- </if>
- <if>
+ </antcontrib:if>
+ <antcontrib:if>
<equals arg1="${os.name}" arg2="Linux" />
<then>
<property name="platform" value="linux" />
</then>
- </if>
- <if>
+ </antcontrib:if>
+ <antcontrib:if>
<equals arg1="${os.name}" arg2="Mac OS X" />
<then>
<property name="platform" value="mac" />
</then>
- </if>
+ </antcontrib:if>
</target>
<target name="init-oophm-platform"><property name="platform" value="oophm" /></target>
@@ -206,12 +237,13 @@
<pathelement path="${gwt-dir}/${platform}/gwt-user.jar" />
<pathelement path="${gwt-dir}/${platform}/${lib-gwt-dev}" />
</path>
+
</target>
<target name="internal-package-windows">
- <var name="package-platform" value="windows" />
+ <antcontrib:var name="package-platform" value="windows" />
<echo>Creating package for ${package-platform} platform.</echo>
- <var name="eclipse-launch-vmargs" value="-Xms256M -Xmx512M" />
+ <antcontrib:var name="eclipse-launch-vmargs" value="-Xms256M -Xmx512M" />
<antcall target="add-platform-specific-files" inheritAll="true" inheritRefs="true" />
<zip zipfile="${result-path}/${product-file}-${package-platform}-${version}.zip">
<zipfileset prefix="${product-file}-${package-platform}-${version}" dir="${result-path}/${product-file}-${version}">
@@ -228,9 +260,9 @@
</target>
<target name="internal-package-linux">
- <var name="package-platform" value="linux" />
+ <antcontrib:var name="package-platform" value="linux" />
<echo>Creating package for ${package-platform} platform.</echo>
- <var name="eclipse-launch-vmargs" value="-Xms256M -Xmx512M" />
+ <antcontrib:var name="eclipse-launch-vmargs" value="-Xms256M -Xmx512M" />
<antcall target="add-platform-specific-files" inheritAll="true" inheritRefs="true" />
<tar destfile="${result-path}/${product-file}-${package-platform}-${version}.tar.gz" compression="gzip" longfile="gnu">
<!-- TODO use very slow but effective bzip2
@@ -250,9 +282,9 @@
</target>
<target name="internal-package-oophm">
- <var name="package-platform" value="oophm" />
+ <antcontrib:var name="package-platform" value="oophm" />
<echo>Creating package for ${package-platform} platform.</echo>
- <var name="eclipse-launch-vmargs" value="-Xms256M -Xmx512M" />
+ <antcontrib:var name="eclipse-launch-vmargs" value="-Xms256M -Xmx512M" />
<antcall target="add-platform-specific-files" inheritAll="true" inheritRefs="true" />
<tar destfile="${result-path}/${product-file}-${package-platform}-${version}.tar.gz" compression="gzip" longfile="gnu">
<tarfileset prefix="${product-file}-${package-platform}-${version}" dir="${result-path}/${product-file}-${version}">
@@ -269,9 +301,9 @@
</target>
<target name="internal-package-mac">
- <var name="package-platform" value="mac" />
+ <antcontrib:var name="package-platform" value="mac" />
<echo>Creating package for ${package-platform} platform.</echo>
- <var name="eclipse-launch-vmargs" value="-XstartOnFirstThread -Xms256M -Xmx512M" />
+ <antcontrib:var name="eclipse-launch-vmargs" value="-XstartOnFirstThread -Xms256M -Xmx512M" />
<antcall target="add-platform-specific-files" inheritAll="true" inheritRefs="true" />
<tar destfile="${result-path}/${product-file}-${package-platform}-${version}.tar.gz" compression="gzip" longfile="gnu">
<tarfileset prefix="${product-file}-${package-platform}-${version}" dir="${result-path}/${product-file}-${version}">
@@ -304,7 +336,7 @@
<property name="mount.dir" value="${result-path}/mac-mounted-image" />
<mkdir dir="${mount.dir}" />
<delete file="${result-path}/*.dmg" />
- <if>
+ <antcontrib:if>
<equals arg1="${platform}" arg2="mac" />
<then>
<untar src="${result-path}/${product-file}-${package-platform}-${version}.tar.gz" dest="${result-path}/" compression="gzip" />
@@ -362,7 +394,7 @@
<arg line='internet-enable ${result-path}/${product-file}-${package-platform}-${version}.dmg' />
</exec>
</then>
- </if>
+ </antcontrib:if>
</target>
<target name="add-platform-specific-files">
@@ -381,13 +413,11 @@
<copy todir="${output-dir}">
<filterchain>
<expandproperties />
- <replacetokens begintoken="&lt;" endtoken=">">
+ <replacetokens begintoken="@" endtoken="@">
<token key="version" value="${version}" />
- <token key="/version" value="" />
</replacetokens>
- <replacetokens begintoken="&lt;" endtoken=">">
+ <replacetokens begintoken="@" endtoken="@">
<token key="platform" value="${package-platform}" />
- <token key="/platform" value="" />
</replacetokens>
</filterchain>
<fileset dir="WebContent/license">
@@ -397,11 +427,11 @@
<copy todir="${output-dir}/WebContent">
<filterchain>
<expandproperties />
- <replacetokens begintoken="&lt;" endtoken=">">
+ <replacetokens begintoken="@" endtoken="@">
<token key="version" value="${version}" />
<token key="/version" value="" />
</replacetokens>
- <replacetokens begintoken="&lt;" endtoken=">">
+ <replacetokens begintoken="@" endtoken="@">
<token key="platform" value="${package-platform}" />
<token key="/platform" value="" />
</replacetokens>
@@ -438,9 +468,9 @@
<token key="/platform-specific-entries" value="" />
</replacetokens>
<!-- .classpath, HostedMode.launch, build-widgetset.xml -->
- <replacetokens begintoken="&lt;" endtoken=">">
+ <!-- We can't use XML notation for this, because it can be inside an attribute definition. -->
+ <replacetokens begintoken="@" endtoken="@">
<token key="platform" value="${package-platform}" />
- <token key="/platform" value="" />
</replacetokens>
<!-- .project, *.launch -->
<replacetokens begintoken="&lt;" endtoken=">">
@@ -470,7 +500,7 @@
<mkdir dir="${output-dir}/.settings" />
<move file="${output-dir}/eclipse-org.eclipse.core.resources.prefs" tofile="${output-dir}/.settings/org.eclipse.core.resources.prefs" />
<move file="${output-dir}/eclipse-org.eclipse.jdt.core.prefs" tofile="${output-dir}/.settings/org.eclipse.jdt.core.prefs" />
- <if>
+ <antcontrib:if>
<equals arg1="${package-platform}" arg2="windows" />
<then>
<copy todir="${output-dir}">
@@ -479,8 +509,8 @@
</fileset>
</copy>
</then>
- </if>
- <if>
+ </antcontrib:if>
+ <antcontrib:if>
<equals arg1="${package-platform}" arg2="linux" />
<then>
<copy todir="${output-dir}">
@@ -494,8 +524,8 @@
<arg line="${output-dir}/start.sh" />
</exec>
</then>
- </if>
- <if>
+ </antcontrib:if>
+ <antcontrib:if>
<equals arg1="${package-platform}" arg2="oophm" />
<then>
<copy todir="${output-dir}">
@@ -509,8 +539,8 @@
<arg line="${output-dir}/start.sh" />
</exec>
</then>
- </if>
- <if>
+ </antcontrib:if>
+ <antcontrib:if>
<equals arg1="${package-platform}" arg2="mac" />
<then>
<copy todir="${output-dir}">
@@ -543,10 +573,10 @@
<arg line="${output-dir}/start.sh" />
</exec>
</then>
- </if>
+ </antcontrib:if>
</target>
- <target name="build" depends="demo" description="Build package required files, without packing them.">
+ <target name="build" depends="libs, compile-client-side, demo" description="Build package required files, without packing them.">
</target>
<!-- Copy and preprocess sources for packaging
@@ -568,6 +598,7 @@
<include name="**/*.html" />
<include name="**/*.css" />
<include name="**/*.xml" />
+ <exclude name="**/tests/**"/>
<exclude name="**/demo/sampler/**" if="build.sampler.disabled" />
</patternset>
</fileset>
@@ -587,6 +618,7 @@
<exclude name="**/*.html" />
<exclude name="**/*.css" />
<exclude name="**/*.xml" />
+ <exclude name="**/tests/**"/>
<exclude name="**/demo/sampler/**" if="build.sampler.disabled" />
</patternset>
</fileset>
@@ -641,7 +673,6 @@
<exclude name="ITMILL/themes/sampler/**" if="build.sampler.disabled" />
<include name="demo/**/*" />
<include name="WEB-INF/lib/hsqldb.jar" />
- <include name="WEB-INF/lib/beanitemcontainer-20090216.jar" />
<include name="ITMILL/themes/**/*" />
<include name="META-INF/**/*" />
</fileset>
@@ -682,11 +713,9 @@
<mkdir dir="${result-path}/classes" />
<javac source="1.5" target="1.5" classpathref="compile.classpath.server-side" destdir="${result-path}/classes" debug="true" encoding="UTF-8">
<src path="${result-path}/src"/>
- <classpath>
- <pathelement location="WebContent/WEB-INF/lib/beanitemcontainer-20090216.jar" />
- </classpath>
<!-- This seems to be included by default: include name="${toolkit-package}/**"/ -->
<exclude name="${toolkit-package}/demo/sampler/**" if="build.sampler.disabled" />
+ <exclude name="${toolkit-package}/tests/**"/>
</javac>
</target>
@@ -869,7 +898,9 @@
<target name="widgetset-colorpicker" depends="init-nonpackage, compile-widgetset-colorpicker">
</target>
- <target name="libs" depends="compile-java, webcontent, compile-client-side">
+ <!-- Compile the Toolkit library JAR. -->
+ <!-- Only need the default widgetset for this. -->
+ <target name="libs" depends="compile-java, webcontent, compile-widgetset-default">
<echo>Creating libs (server-side) ${lib-jar-name}</echo>
<!-- Create Toolkit JAR -->
<jar jarfile="${output-dir}/WebContent/WEB-INF/lib/${lib-jar-name}" compress="true">
@@ -924,16 +955,56 @@
</copy>
</target>
- <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Documentation
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
- <target name="docs" depends="javadoc,manual-pdf,manual-html,package-docs">
+ <!-- ================================================================== -->
+ <!-- Documentation -->
+ <!-- ================================================================== -->
+ <target name="docs" depends="init, manual">
</target>
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+ <!-- Manual: Build from external repository. -->
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
- <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Documentation: Add documentation including style files
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+ <!-- Checkout doc repository. -->
+ <target name="manual-checkout" unless="docdir">
+ <mkdir dir="${checkout-path}"/>
+
+ <exec executable="svn" dir="${checkout-path}">
+ <arg value="checkout"/>
+ <arg value="http://dev.itmill.com/svn/doc/trunk"/>
+ <arg value="doc"/>
+ </exec>
+
+ <property name="docdir" value="${checkout-path}/doc"/>
+
+ <!-- If we have a XEP license, copy it to proper place. -->
+ <copy file="/opt/RenderX/XEP/license.xml" todir="${docdir}/build/lib/XEP"/>
+ </target>
+
+ <!-- Build manual. -->
+ <target name="manual-build">
+ <ant dir="${docdir}" antfile="build/build.xml" inheritAll="false">
+ <property name="version" value="${version}"/>
+ </ant>
+ </target>
+
+ <!-- Copy the manual from sub Ant results to our output directory. -->
+ <target name="manual-copy" depends="init, manual-checkout">
+ <copy todir="${output-dir}/WebContent/doc">
+ <fileset dir="${docdir}/build/result/package/WebContent/doc">
+ <exclude name="**/.svn" />
+ <include name="manual/**" />
+ <include name="manual.pdf" />
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="manual" depends="init, manual-checkout, manual-build, manual-copy">
+ </target>
+
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+ <!-- Documentation: Add documentation including style files -->
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<target name="package-docs">
<copy todir="${output-dir}/WebContent/doc/manual/html-style">
<fileset dir="doc/manual/html-style">
@@ -949,10 +1020,9 @@
</copy>
</target>
-
- <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Documentation: Add Javadoc to doc
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+ <!-- Documentation: Add Javadoc to doc -->
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<target name="javadoc" depends="preprocess-src">
<javadoc destdir="${output-dir}/WebContent/doc/api" author="true" version="true" use="true" windowtitle="${product-name}" classpathref="compile.classpath.client-side">
<packageset dir="${result-path}/src">
@@ -969,317 +1039,112 @@
</javadoc>
</target>
-
- <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Documentation: Add book part 2 (TBD)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
- <target name="book-part2" depends="dbdoclet">
- <!-- TODO Add XSLT to transform dbdoclet results to book part 2 -->
- </target>
-
-
- <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Documentation: Add manual
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
- <target name="dbdoclet" depends="preprocess-src">
- <echo>Manual: DocBookDoclet</echo>
- <javadoc access="public" charset="UTF-8" docencoding="UTF-8" encoding="ISO-8859-15" failonerror="yes" maxmemory="512m" source="1.5">
- <packageset dir="${result-path}/src">
- <include name="${toolkit-package}/**" />
- <exclude name="${toolkit-package}/demo/**" />
- <exclude name="${toolkit-package}/tests/**/*" />
- </packageset>
- <doclet name="org.dbdoclet.doclet.docbook.DocBookDoclet" path="build/lib/jdk${java.specification.version}/dbdoclet.jar">
- <param name="-d" value="result/docbook" />
- </doclet>
- </javadoc>
- </target>
+ <!-- java2html converter -->
+ <taskdef name="java2html" classname="de.java2html.anttasks.Java2HtmlTask" classpath="build/lib/java2html.jar" />
<!-- ================================================================== -->
- <!-- Build Reference Manual. -->
+ <!-- Nightly build. -->
<!-- ================================================================== -->
- <!-- Initialize properties especially for the Reference Manual. -->
- <target name="init-manual" depends="">
- <!-- Sets the current date as the publication date of the Manual. -->
- <tstamp>
- <format property="manual.pubdate" pattern="yyyy-MM-dd"/>
- </tstamp>
- </target>
-
- <!-- Build PDF manual from sources or just copy it. -->
- <target name="manual-pdf" depends="init, init-manual, build-manual-pdf, copy-manual-pdf">
- </target>
+ <!-- Main target for the nightly build. -->
+ <target name="nightly" depends="clean-result, nightly-init, package-init, init, build, internal-package-linux, nightly-install">
+ </target>
- <!-- Just copy a prebuilt PDF manual. -->
- <target name="copy-manual-pdf" unless="xep.license.available">
- <echo>PDF Manual: No XEP license available, just copy a prebuilt PDF.</echo>
- <copy file="doc/manual/book.pdf" tofile="${output-dir}/WebContent/doc/manual.pdf" />
- </target>
+ <!-- Create symlink to GWT installation directory. -->
+ <target name="gwt-symlink">
- <!-- XEP-based FO building -->
- <target name="build-manual-pdf" if="xep.license.available">
- <echo>PDF Manual: processing images (TBD)</echo>
- <!-- TBD -->
- <echo>PDF Manual: converting xml to fo</echo>
+ <!-- Optional property. -->
+ <property name="gwt.link.target" value="../../gwt-1.5"/>
- <echo>Publication date is ${manual.pubdate}</echo>
+ <!-- Remove the old link, as the link target may have changed. -->
+ <exec executable="rm" dir="build" searchpath="true" failonerror="false">
+ <arg value="gwt"/>
+ </exec>
- <java classname="org.apache.xalan.xslt.Process" failonerror="yes" fork="yes" maxmemory="512m">
- <arg value="-xsl" />
- <arg value="build/docbook/conf/custom-fo-docbook.xsl" />
- <arg value="-in" />
- <arg value="doc/manual/book.xml" />
- <arg value="-out" />
- <arg value="${result-path}/book.fo" />
- <arg value="-param" />
- <arg value="section.autolabel" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="section.label.includes.component.label" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="section.autolabel.max.depth" />
- <arg value="2" />
- <arg value="-param" />
- <arg value="draft.watermark.image" />
- <arg value="''" />
- <arg value="-param" />
- <arg value="draft.mode" />
- <arg value="'no'" />
- <arg value="-param" />
- <arg value="double.sided" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="manual.pubdate" />
- <arg value="${manual.pubdate}" />
- <arg value="-param" />
- <arg value="manual.version" />
- <arg value="${version}" />
- <classpath>
- <pathelement location="build/lib/xalan.jar" />
- <pathelement location="build/lib/xercesImpl.jar" />
- <pathelement location="build/lib/xml-apis.jar" />
- </classpath>
- </java>
- <echo>PDF Manual: converting fo to pdf</echo>
- <!-- Run XEP FO processor to convert FO to PDF -->
- <java classname="com.renderx.xep.XSLDriver" error="${result-path}/xep-error.log" failonerror="yes" fork="yes" maxmemory="512m" input="${result-path}/book.fo" output="${output-dir}/WebContent/doc/manual.pdf">
- <arg value="-Dcom.renderx.xep.CONFIG=build/lib/XEP/xep.xml" />
- <classpath>
- <pathelement location="build/lib/XEP/lib/tools.jar" />
- <pathelement location="build/lib/XEP/lib/xep.jar" />
- <pathelement location="build/lib/XEP/lib/saxon.jar" />
- <pathelement location="build/lib/XEP/lib/xt.jar" />
- </classpath>
- </java>
- </target>
+ <echo>Creating symlink to GWT installation directory.</echo>
+ <exec executable="ln" dir="build" searchpath="true" failonerror="true">
+ <arg value="-s"/> <!-- Symlink. -->
+ <arg value="-f"/> <!-- Overwrite. -->
+ <arg value="${gwt.link.target}"/>
+ <arg value="gwt"/>
+ </exec>
+ </target>
- <target name="manual-html" depends="init, init-manual, preprocess-src">
- <echo>Manual: HTML</echo>
- <delete file="build/docbook/conf/temp.xsl" />
- <copy file="build/docbook/conf/custom-html-docbook.xsl" tofile="build/docbook/conf/temp.xsl">
- <filterchain>
- <replacetokens>
- <token key="BODYHEADER" value="${html.body.start1}${docbook.head.title}${html.body.start2}" />
- <token key="BODYFOOTER" value="${html.body.end}" />
- </replacetokens>
- </filterchain>
- </copy>
- <path id="docbook-xsl.classpath">
- <pathelement path="build/lib/fserializer.jar" />
- <pathelement path="build/lib/xalan.jar" />
- <pathelement path="build/lib/xercesImpl.jar" />
- <pathelement path="build/lib/xml-apis.jar" />
- </path>
- <java classname="org.apache.xalan.xslt.Process" failonerror="yes" fork="yes" maxmemory="512m">
- <arg value="-in" />
- <arg value="doc/manual/book.xml" />
- <arg value="-xsl" />
- <arg value="build/docbook/conf/temp.xsl" />
- <arg value="-out" />
- <arg value="${output-dir}/WebContent/doc/manual/index.html" />
- <arg value="-param" />
- <arg value="section.autolabel" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="section.label.includes.component.label" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="section.autolabel.max.depth" />
- <arg value="2" />
- <arg value="-param" />
- <arg value="use.extensions" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="manual.pubdate" />
- <arg value="${manual.pubdate}" />
- <arg value="-param" />
- <arg value="manual.version" />
- <arg value="${version}" />
- <classpath refid="docbook-xsl.classpath" />
- </java>
- <delete file="build/docbook/conf/temp.xsl" />
- <copy todir="${output-dir}/WebContent/doc/manual/img">
- <fileset dir="doc/manual/img">
- <exclude name="**/.svn" />
- </fileset>
- </copy>
- </target>
+ <!-- Initialize a nightly build. -->
+ <target name="nightly-init" depends="gwt-symlink">
- <!-- ant contrib required for flow control (for loop, if, property override) -->
- <taskdef resource="net/sf/antcontrib/antlib.xml">
- <classpath>
- <pathelement location="build/lib/ant-contrib-1.0b3.jar" />
- </classpath>
- </taskdef>
+ <!-- Mandatory parameters. -->
+ <fail unless="version.minor" message="The version.minor property must be defined."/>
+ <fail unless="build.number" message="The build.number property must be defined."/>
+ <fail unless="nightly.publish" message="The nightly.publish property must be defined."/>
- <!-- java2html converter -->
- <taskdef name="java2html" classname="de.java2html.anttasks.Java2HtmlTask" classpath="build/lib/java2html.jar" />
+ <!-- Optional parameters. -->
+ <property name="build.tag" value="dev"/>
- <!-- ================================================================== -->
- <!-- Build Application Tutorial. -->
- <!-- ================================================================== -->
+ <echo>Minor version: ${version.minor}</echo>
+ <echo>Build number: ${build.number}</echo>
+ <echo>Build tag: ${build.tag}</echo>
+ <echo>Publish target: ${nightly.publish}</echo>
- <!-- Initialize properties especially for the Reference Tutorial. -->
- <target name="init-tutorial" depends="">
- <!-- Sets the current date as the publication date of the Tutorial. -->
+ <!-- Set build number. -->
<tstamp>
- <format property="tutorial.pubdate" pattern="yyyy-MM-dd"/>
+ <format property="nightly.date" pattern="yyyyMMdd"/>
</tstamp>
+ <property name="version" value="${version.minor}.${build.tag}-${nightly.date}-c${build.number}"/>
+ <echo>Version will be: ${version}</echo>
- <mkdir dir="${output-dir}/WebContent/doc/tutorial" />
- </target>
+ <!-- Tell TeamCity the build name. Have to do it this way, because -->
+ <!-- this script needs to get the plain build number as a parameter. -->
+ <echo>##teamcity[buildNumber '${version.minor}-c${build.number}']</echo>
- <!-- Build PDF tutorial from sources or just copy it. -->
- <target name="tutorial-pdf" depends="init, init-tutorial, build-tutorial-pdf, copy-tutorial-pdf">
- </target>
+ </target>
- <!-- Just copy a prebuilt PDF tutorial. -->
- <target name="copy-tutorial-pdf" unless="xep.license.available">
- <echo>PDF Tutorial: No XEP license available, just copy a prebuilt PDF.</echo>
- <copy file="doc/tutorial/itmill-toolkit-tutorial.pdf" tofile="${output-dir}/WebContent/doc/itmill-toolkit-tutorial.pdf" />
- </target>
+ <target name="nightly-teamcity-publish">
+ <!-- Publish as a TeamCity artifact. -->
+ <echo>##teamcity[publishArtifacts '${output-dir}/WebContent/WEB-INF/lib/${lib-jar-name}']</echo>
+ </target>
- <!-- XEP-based FO building -->
- <target name="build-tutorial-pdf" if="xep.license.available">
- <echo>PDF Tutorial: processing images (TBD)</echo>
- <!-- TBD -->
- <echo>PDF Tutorial: converting xml to fo</echo>
+ <!-- Copies the nightly build artifacts to the download server. -->
+ <target name="nightly-download-publish" if="nightly.publish">
+ <!-- Publish to the download server. -->
+ <echo>Installing ${output-dir}/WebContent/${lib-jar-name} to ${nightly.publish}</echo>
+ <echo>Hopefully you have permissions for the copy operation with SSH.</echo>
- <echo>Publication date is ${tutorial.pubdate}</echo>
+ <!-- The test task will need this. -->
+ <property name="package.linux.filename" value="${result-path}/${product-file}-${package-platform}-${version}.tar.gz"/>
- <java classname="org.apache.xalan.xslt.Process" failonerror="yes" fork="yes" maxmemory="512m">
- <arg value="-xsl" />
- <arg value="build/docbook/conf/custom-fo-docbook.xsl" />
- <arg value="-in" />
- <arg value="doc/tutorial/tutorial.xml" />
- <arg value="-out" />
- <arg value="${result-path}/itmill-toolkit-tutorial.fo" />
- <arg value="-param" />
- <arg value="section.autolabel" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="section.label.includes.component.label" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="section.autolabel.max.depth" />
- <arg value="2" />
- <arg value="-param" />
- <arg value="draft.watermark.image" />
- <arg value="''" />
- <arg value="-param" />
- <arg value="draft.mode" />
- <arg value="'no'" />
- <arg value="-param" />
- <arg value="double.sided" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="manual.pubdate" />
- <arg value="${tutorial.pubdate}" />
- <arg value="-param" />
- <arg value="manual.version" />
- <arg value="${version}" />
- <classpath>
- <pathelement location="build/lib/xalan.jar" />
- <pathelement location="build/lib/xercesImpl.jar" />
- <pathelement location="build/lib/xml-apis.jar" />
- </classpath>
- </java>
- <echo>PDF Tutorial: converting fo to pdf</echo>
- <!-- Run XEP FO processor to convert FO to PDF -->
- <java classname="com.renderx.xep.XSLDriver" error="${result-path}/xep-error.log" failonerror="yes" fork="yes" maxmemory="512m" input="${result-path}/itmill-toolkit-tutorial.fo" output="${output-dir}/WebContent/doc/itmill-toolkit-tutorial.pdf">
- <arg value="-Dcom.renderx.xep.CONFIG=build/lib/XEP/xep.xml" />
- <classpath>
- <pathelement location="build/lib/XEP/lib/tools.jar" />
- <pathelement location="build/lib/XEP/lib/xep.jar" />
- <pathelement location="build/lib/XEP/lib/saxon.jar" />
- <pathelement location="build/lib/XEP/lib/xt.jar" />
- </classpath>
- </java>
- </target>
+ <!-- Copy the linux installation package and the JAR. -->
+ <exec executable="scp" searchpath="true" resultproperty="nightly.install.scp.result">
+ <arg value="-B"/>
+ <arg value="${output-dir}/WebContent/${lib-jar-name}"/>
+ <arg value="${package.linux.filename}"/>
+ <arg value="${nightly.publish}"/>
+ </exec>
- <target name="tutorial-html" depends="init, init-tutorial, preprocess-src">
- <echo>Tutorial: HTML</echo>
- <echo>Publication date is ${tutorial.pubdate}</echo>
+ <echo>Result: ${nightly.install.scp.result}</echo>
+ </target>
- <delete file="build/docbook/conf/temp.xsl" />
- <copy file="build/docbook/conf/custom-html-docbook.xsl" tofile="build/docbook/conf/temp.xsl">
- <filterchain>
- <replacetokens>
- <token key="BODYHEADER" value="${html.body.start1}${docbook.head.title}${html.body.start2}" />
- <token key="BODYFOOTER" value="${html.body.end}" />
- </replacetokens>
- </filterchain>
- </copy>
- <path id="docbook-xsl.classpath">
- <pathelement path="build/lib/fserializer.jar" />
- <pathelement path="build/lib/xalan.jar" />
- <pathelement path="build/lib/xercesImpl.jar" />
- <pathelement path="build/lib/xml-apis.jar" />
- </path>
- <java classname="org.apache.xalan.xslt.Process" failonerror="yes" fork="yes" maxmemory="512m">
- <arg value="-in" />
- <arg value="doc/tutorial/tutorial.xml" />
- <arg value="-xsl" />
- <arg value="build/docbook/conf/temp.xsl" />
- <arg value="-out" />
- <arg value="${output-dir}/WebContent/doc/tutorial/index.html" />
- <arg value="-param" />
- <arg value="section.autolabel" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="section.label.includes.component.label" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="section.autolabel.max.depth" />
- <arg value="2" />
- <arg value="-param" />
- <arg value="use.extensions" />
- <arg value="1" />
- <arg value="-param" />
- <arg value="manual.pubdate" />
- <arg value="${tutorial.pubdate}" />
- <arg value="-param" />
- <arg value="manual.version" />
- <arg value="${version}" />
- <classpath refid="docbook-xsl.classpath" />
- </java>
- <delete file="build/docbook/conf/temp.xsl" />
- <copy todir="${output-dir}/WebContent/doc/tutorial/img">
- <fileset dir="doc/tutorial/img">
- <exclude name="**/.svn" />
- </fileset>
- </copy>
- </target>
+ <target name="nightly-install" depends="nightly-teamcity-publish, nightly-download-publish">
+ </target>
- <!-- ant contrib required for flow control (for loop, if, property override) -->
- <taskdef resource="net/sf/antcontrib/antlib.xml">
- <classpath>
- <pathelement location="build/lib/ant-contrib-1.0b3.jar" />
- </classpath>
- </taskdef>
+ <target name="testingtools-test">
+ <!-- Run the separate test script. -->
+ <ant antfile="build/testing/test.xml" inheritall="true">
+ </ant>
+ </target>
- <!-- java2html converter -->
- <taskdef name="java2html" classname="de.java2html.anttasks.Java2HtmlTask" classpath="build/lib/java2html.jar" />
+ <!-- ================================================================== -->
+ <!-- Automated tests. -->
+ <!-- ================================================================== -->
+
+ <target name="ant-tests">
+ <echo>##teamcity[testSuiteStarted name='com.itmill.toolkit.tests.test-framework']</echo>
+
+ <!-- A smoke test for testing the testing framework. -->
+ <echo>##teamcity[testStarted name='testingSmoketest']</echo>
+ <echo>##teamcity[testStdOut name='testingSmoketest' out='Here be some text related to the test.]</echo>
+ <echo>##teamcity[testFinished name='testingSmoketest']</echo>
+
+ <echo>##teamcity[testSuiteFinished name='com.itmill.toolkit.tests.test-framework']</echo>
+ </target>
</project>
diff --git a/build/package/build-widgetset.xml b/build/package/build-widgetset.xml
index ec400c2d70..2a82e5fd4b 100644
--- a/build/package/build-widgetset.xml
+++ b/build/package/build-widgetset.xml
@@ -31,13 +31,13 @@ See configure target to adjust this buildfile.
<property name="base" value="../../../" />
<!-- which platform we are in, possible values are windows, linux and mac -->
- <property name="gwt-platform" value="<platform></platform>" />
+ <property name="gwt-platform" value="@platform@" />
<!-- where platform specific GWT distribution is located -->
<property name="gwt-location" value="${base}gwt" />
<!-- where Toolkit jar is located -->
- <property name="toolkit-jar-location" value="${base}WebContent/WEB-INF/lib/itmill-toolkit-<version></version>.jar" />
+ <property name="toolkit-jar-location" value="${base}WebContent/WEB-INF/lib/itmill-toolkit-@version@.jar" />
<!-- where project client-side widgetset source files are located -->
<property name="client-side-src-location" value="${base}WebContent/WEB-INF/src" />
diff --git a/build/package/eclipse-IT Mill Toolkit Hosted Mode-launch b/build/package/eclipse-IT Mill Toolkit Hosted Mode-launch
index 3ae558420a..7479aeb801 100644
--- a/build/package/eclipse-IT Mill Toolkit Hosted Mode-launch
+++ b/build/package/eclipse-IT Mill Toolkit Hosted Mode-launch
@@ -2,7 +2,7 @@
<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
<stringAttribute key="bad_container_name" value="/<eclipse-workspace-name></eclipse-workspace-name>/IT Mill Toolkit Hosted Mode.launch"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry value="/<eclipse-workspace-name></eclipse-workspace-name>/gwt/gwt-dev-<platform></platform>.jar"/>
+<listEntry value="/<eclipse-workspace-name></eclipse-workspace-name>/gwt/gwt-dev-@platform@.jar"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
diff --git a/build/package/eclipse-classpath b/build/package/eclipse-classpath
index 9cd2ee212b..d5a181374d 100644
--- a/build/package/eclipse-classpath
+++ b/build/package/eclipse-classpath
@@ -3,7 +3,6 @@
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="src" path="WebContent/WEB-INF/src"/>
<classpathentry kind="lib" path="WebContent/WEB-INF/lib/itmill-toolkit-<version></version>.jar"/>
- <classpathentry kind="lib" path="WebContent/WEB-INF/lib/beanitemcontainer-20090216.jar"/>
<classpathentry kind="lib" path="gwt/gwt-user.jar" />
<classpathentry kind="lib" path="gwt/gwt-servlet.jar" />
<classpathentry kind="lib" path="WebContent/demo/lib/reservr/gwt-maps.jar" />
diff --git a/src/com/itmill/toolkit/Application.java b/src/com/itmill/toolkit/Application.java
index 1b3f184382..60045ac702 100644
--- a/src/com/itmill/toolkit/Application.java
+++ b/src/com/itmill/toolkit/Application.java
@@ -1096,7 +1096,7 @@ public abstract class Application implements URIHandler, Terminal.ErrorListener
* @see com.itmill.toolkit.terminal.Terminal.ErrorListener#terminalError(com.itmill.toolkit.terminal.Terminal.ErrorEvent)
*/
public void terminalError(Terminal.ErrorEvent event) {
- Throwable t = event.getThrowable();
+ final Throwable t = event.getThrowable();
if (t instanceof SocketException) {
// Most likely client browser closed socket
System.err
@@ -1119,21 +1119,16 @@ public abstract class Application implements URIHandler, Terminal.ErrorListener
// Shows the error in AbstractComponent
if (owner instanceof AbstractComponent) {
- final Throwable e = event.getThrowable();
- if (e instanceof ErrorMessage) {
- ((AbstractComponent) owner).setComponentError((ErrorMessage) e);
+ if (t instanceof ErrorMessage) {
+ ((AbstractComponent) owner).setComponentError((ErrorMessage) t);
} else {
((AbstractComponent) owner)
- .setComponentError(new SystemError(e));
+ .setComponentError(new SystemError(t));
}
- } else {
- /*
- * Can't show it to the user in any way so we print to standard
- * error
- */
- t.printStackTrace();
-
}
+
+ // also print the error on console
+ t.printStackTrace();
}
/**
diff --git a/src/com/itmill/toolkit/data/Container.java b/src/com/itmill/toolkit/data/Container.java
index 36b0caca93..5df1b34f91 100644
--- a/src/com/itmill/toolkit/data/Container.java
+++ b/src/com/itmill/toolkit/data/Container.java
@@ -543,8 +543,8 @@ public interface Container {
}
/**
- * Interface is implemented by containers that allow reducing their
- * visiblecontents with set of filters.
+ * Interface is implemented by containers that allow reducing their visible
+ * contents with set of filters.
*
* When a set of filters are set, only items that match the filters are
* included in the visible contents of the container. Still new items that
@@ -553,6 +553,19 @@ public interface Container {
* multiple filters are added, all filters must match for an item to be
* visible in the container.
*
+ * When an {@link com.itmill.toolkit.data.Ordered} or
+ * {@link com.itmill.toolkit.data.Indexed} container is filtered, all
+ * operations of these interfaces should only use the filtered contents and
+ * the filtered indices to the container.
+ *
+ * Adding items (if supported) to a filtered
+ * {@link com.itmill.toolkit.data.Ordered} or
+ * {@link com.itmill.toolkit.data.Indexed} container should insert them
+ * immediately after the indicated visible item. The unfiltered position of
+ * items added at index 0, at index
+ * {@link com.itmill.toolkit.data.Container#size()} or at an undefined
+ * position is up to the implementation.
+ *
* @since 5.0
*/
public interface Filterable extends Container {
diff --git a/src/com/itmill/toolkit/data/util/BeanItem.java b/src/com/itmill/toolkit/data/util/BeanItem.java
index f30d5fd820..65bc57a1b3 100644
--- a/src/com/itmill/toolkit/data/util/BeanItem.java
+++ b/src/com/itmill/toolkit/data/util/BeanItem.java
@@ -10,7 +10,7 @@ import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Iterator;
+import java.util.LinkedHashMap;
import com.itmill.toolkit.data.Property;
@@ -47,30 +47,35 @@ public class BeanItem extends PropertysetItem {
*
*/
public BeanItem(Object bean) {
+ this(bean, getPropertyDescriptors(bean.getClass()));
+ }
- this.bean = bean;
+ /**
+ * <p>
+ * Creates a new instance of <code>BeanItem</code> using a pre-computed set
+ * of properties. The properties are identified by their respective bean
+ * names.
+ * </p>
+ *
+ * @param bean
+ * the Java Bean to copy properties from.
+ * @param propertyDescriptors
+ * pre-computed property descriptors
+ */
+ BeanItem(Object bean,
+ LinkedHashMap<String, PropertyDescriptor> propertyDescriptors) {
- // Try to introspect, if it fails, we just have an empty Item
- try {
- // Create bean information
- final BeanInfo info = Introspector.getBeanInfo(bean.getClass());
- final PropertyDescriptor[] pd = info.getPropertyDescriptors();
+ this.bean = bean;
- // Add all the bean properties as MethodProperties to this Item
- for (int i = 0; i < pd.length; i++) {
- final Method getMethod = pd[i].getReadMethod();
- final Method setMethod = pd[i].getWriteMethod();
- final Class type = pd[i].getPropertyType();
- final String name = pd[i].getName();
+ for (PropertyDescriptor pd : propertyDescriptors.values()) {
+ final Method getMethod = pd.getReadMethod();
+ final Method setMethod = pd.getWriteMethod();
+ final Class<?> type = pd.getPropertyType();
+ final String name = pd.getName();
+ final Property p = new MethodProperty(type, bean, getMethod,
+ setMethod);
+ addItemProperty(name, p);
- if ((getMethod != null)
- && getMethod.getDeclaringClass() != Object.class) {
- final Property p = new MethodProperty(type, bean,
- getMethod, setMethod);
- addItemProperty(name, p);
- }
- }
- } catch (final java.beans.IntrospectionException ignored) {
}
}
@@ -96,31 +101,22 @@ public class BeanItem extends PropertysetItem {
this.bean = bean;
- // Try to introspect, if it fails, we just have an empty Item
- try {
- // Create bean information
- final BeanInfo info = Introspector.getBeanInfo(bean.getClass());
- final PropertyDescriptor[] pd = info.getPropertyDescriptors();
-
- // Add all the bean properties as MethodProperties to this Item
- for (final Iterator iter = propertyIds.iterator(); iter.hasNext();) {
- final Object id = iter.next();
- for (int i = 0; i < pd.length; i++) {
- final String name = pd[i].getName();
- if (name.equals(id)) {
- final Method getMethod = pd[i].getReadMethod();
- final Method setMethod = pd[i].getWriteMethod();
- final Class type = pd[i].getPropertyType();
- if ((getMethod != null)) {
- final Property p = new MethodProperty(type, bean,
- getMethod, setMethod);
- addItemProperty(name, p);
- }
- }
- }
+ // Create bean information
+ LinkedHashMap<String, PropertyDescriptor> pds = getPropertyDescriptors(bean
+ .getClass());
+
+ // Add all the bean properties as MethodProperties to this Item
+ for (Object id : propertyIds) {
+ PropertyDescriptor pd = pds.get(id);
+ if (pd != null) {
+ final String name = pd.getName();
+ final Method getMethod = pd.getReadMethod();
+ final Method setMethod = pd.getWriteMethod();
+ final Class<?> type = pd.getPropertyType();
+ final Property p = new MethodProperty(type, bean, getMethod,
+ setMethod);
+ addItemProperty(name, p);
}
-
- } catch (final java.beans.IntrospectionException ignored) {
}
}
@@ -148,6 +144,44 @@ public class BeanItem extends PropertysetItem {
}
/**
+ * <p>
+ * Perform introspection on a Java Bean class to find its properties.
+ * </p>
+ *
+ * <p>
+ * Note : This version only supports introspectable bean properties and
+ * their getter and setter methods. Stand-alone <code>is</code> and
+ * <code>are</code> methods are not supported.
+ * </p>
+ *
+ * @param beanClass
+ * the Java Bean class to get properties for.
+ * @return an ordered map from property names to property descriptors
+ */
+ static LinkedHashMap<String, PropertyDescriptor> getPropertyDescriptors(
+ final Class<?> beanClass) {
+ final LinkedHashMap<String, PropertyDescriptor> pdMap = new LinkedHashMap<String, PropertyDescriptor>();
+
+ // Try to introspect, if it fails, we just have an empty Item
+ try {
+ final BeanInfo info = Introspector.getBeanInfo(beanClass);
+ final PropertyDescriptor[] pds = info.getPropertyDescriptors();
+
+ // Add all the bean properties as MethodProperties to this Item
+ for (int i = 0; i < pds.length; i++) {
+ final Method getMethod = pds[i].getReadMethod();
+ if ((getMethod != null)
+ && getMethod.getDeclaringClass() != Object.class) {
+ pdMap.put(pds[i].getName(), pds[i]);
+ }
+ }
+ } catch (final java.beans.IntrospectionException ignored) {
+ }
+
+ return pdMap;
+ }
+
+ /**
* Gets the underlying JavaBean object.
*
* @return the bean object.
diff --git a/src/com/itmill/toolkit/data/util/BeanItemContainer.java b/src/com/itmill/toolkit/data/util/BeanItemContainer.java
new file mode 100644
index 0000000000..5ba44568ad
--- /dev/null
+++ b/src/com/itmill/toolkit/data/util/BeanItemContainer.java
@@ -0,0 +1,449 @@
+package com.itmill.toolkit.data.util;
+
+import java.beans.PropertyDescriptor;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.itmill.toolkit.data.Container;
+import com.itmill.toolkit.data.Item;
+import com.itmill.toolkit.data.Property;
+import com.itmill.toolkit.data.Container.Filterable;
+import com.itmill.toolkit.data.Container.Indexed;
+import com.itmill.toolkit.data.Container.ItemSetChangeNotifier;
+import com.itmill.toolkit.data.Container.Sortable;
+import com.itmill.toolkit.data.Property.ValueChangeEvent;
+import com.itmill.toolkit.data.Property.ValueChangeListener;
+import com.itmill.toolkit.data.Property.ValueChangeNotifier;
+
+/**
+ * An {@link ArrayList} backed container for {@link BeanItem}s.
+ * <p>
+ * Bean objects act as identifiers. For this reason, they should implement
+ * Object.equals(Object) and Object.hashCode().
+ * </p>
+ *
+ * @param <BT>
+ *
+ * @since 5.4
+ */
+public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
+ ItemSetChangeNotifier, ValueChangeListener {
+ // filtered and unfiltered item IDs
+ private ArrayList<BT> list = new ArrayList<BT>();
+ private ArrayList<BT> allItems = new ArrayList<BT>();
+ private final Map<BT, BeanItem> beanToItem = new HashMap<BT, BeanItem>();
+
+ // internal data model to obtain property IDs etc.
+ private final Class<BT> type;
+ private final LinkedHashMap<String, PropertyDescriptor> model;
+
+ private List<ItemSetChangeListener> itemSetChangeListeners;
+
+ private Set<Filter> filters = new HashSet<Filter>();
+
+ public BeanItemContainer(Class<BT> type) throws InstantiationException,
+ IllegalAccessException {
+ this.type = type;
+ model = BeanItem.getPropertyDescriptors(type);
+ }
+
+ /**
+ * Constructs BeanItemContainer with given collection of beans in it.
+ *
+ * @param list
+ * non empty {@link Collection} of beans.
+ * @throws IllegalAccessException
+ * @throws InstantiationException
+ */
+ @SuppressWarnings("unchecked")
+ public BeanItemContainer(Collection<BT> list)
+ throws InstantiationException, IllegalAccessException {
+ type = (Class<BT>) list.iterator().next().getClass();
+ model = BeanItem.getPropertyDescriptors(type);
+ int i = 0;
+ for (BT bt : list) {
+ addItemAt(i++, bt);
+ }
+ }
+
+ public Object addItemAt(int index) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Item addItemAt(int index, Object newItemId)
+ throws UnsupportedOperationException {
+ if (index < 0 || index > size()) {
+ return null;
+ } else if (index == 0) {
+ // add before any item, visible or not
+ return addItemAtInternalIndex(0, newItemId);
+ } else {
+ // if index==size(), adds immediately after last visible item
+ return addItemAfter(getIdByIndex(index - 1), newItemId);
+ }
+ }
+
+ /**
+ * Adds new item at given index of the internal (unfiltered) list.
+ * <p>
+ * The item is also added in the visible part of the list if it passes the
+ * filters.
+ * </p>
+ *
+ * @param index
+ * Internal index to add the new item.
+ * @param newItemId
+ * Id of the new item to be added.
+ * @return Returns new item or null if the operation fails.
+ */
+ @SuppressWarnings("unchecked")
+ private Item addItemAtInternalIndex(int index, Object newItemId) {
+ // Make sure that the Item has not been created yet
+ if (allItems.contains(newItemId)) {
+ return null;
+ }
+ if (type.isAssignableFrom(newItemId.getClass())) {
+ BT pojo = (BT) newItemId;
+ // "list" will be updated in filterAll()
+ allItems.add(index, pojo);
+ BeanItem beanItem = new BeanItem(pojo, model);
+ beanToItem.put(pojo, beanItem);
+ // add listeners to be able to update filtering on property changes
+ for (Filter filter : filters) {
+ // addValueChangeListener avoids adding duplicates
+ addValueChangeListener(beanItem, filter.propertyId);
+ }
+
+ // it is somewhat suboptimal to filter all items
+ filterAll();
+ return beanItem;
+ } else {
+ return null;
+ }
+ }
+
+ public Object getIdByIndex(int index) {
+ return list.get(index);
+ }
+
+ public int indexOfId(Object itemId) {
+ return list.indexOf(itemId);
+ }
+
+ public Object addItemAfter(Object previousItemId)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Item addItemAfter(Object previousItemId, Object newItemId)
+ throws UnsupportedOperationException {
+ // only add if the previous item is visible
+ if (list.contains(previousItemId)) {
+ return addItemAtInternalIndex(allItems.indexOf(previousItemId) + 1,
+ newItemId);
+ } else {
+ return null;
+ }
+ }
+
+ public Object firstItemId() {
+ if (list.size() > 0) {
+ return list.get(0);
+ } else {
+ return null;
+ }
+ }
+
+ public boolean isFirstId(Object itemId) {
+ return firstItemId() == itemId;
+ }
+
+ public boolean isLastId(Object itemId) {
+ return lastItemId() == itemId;
+ }
+
+ public Object lastItemId() {
+ if (list.size() > 0) {
+ return list.get(list.size() - 1);
+ } else {
+ return null;
+ }
+ }
+
+ public Object nextItemId(Object itemId) {
+ int index = list.indexOf(itemId);
+ if (index >= 0 && index < list.size() - 1) {
+ return list.get(index + 1);
+ } else {
+ // out of bounds
+ return null;
+ }
+ }
+
+ public Object prevItemId(Object itemId) {
+ int index = list.indexOf(itemId);
+ if (index > 0) {
+ return list.get(index - 1);
+ } else {
+ // out of bounds
+ return null;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public boolean addContainerProperty(Object propertyId, Class type,
+ Object defaultValue) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object addItem() throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Item addItem(Object itemId) throws UnsupportedOperationException {
+ if (list.size() > 0) {
+ // add immediately after last visible item
+ int lastIndex = allItems.indexOf(lastItemId());
+ return addItemAtInternalIndex(lastIndex + 1, itemId);
+ } else {
+ return addItemAtInternalIndex(0, itemId);
+ }
+ }
+
+ public boolean containsId(Object itemId) {
+ // only look at visible items after filtering
+ return list.contains(itemId);
+ }
+
+ public Property getContainerProperty(Object itemId, Object propertyId) {
+ return beanToItem.get(itemId).getItemProperty(propertyId);
+ }
+
+ @SuppressWarnings("unchecked")
+ public Collection getContainerPropertyIds() {
+ return model.keySet();
+ }
+
+ public Item getItem(Object itemId) {
+ return beanToItem.get(itemId);
+ }
+
+ @SuppressWarnings("unchecked")
+ public Collection getItemIds() {
+ return (Collection) list.clone();
+ }
+
+ public Class<?> getType(Object propertyId) {
+ return model.get(propertyId).getPropertyType();
+ }
+
+ public boolean removeAllItems() throws UnsupportedOperationException {
+ allItems.clear();
+ list.clear();
+ // detach listeners from all BeanItems
+ for (BeanItem item : beanToItem.values()) {
+ removeAllValueChangeListeners(item);
+ }
+ beanToItem.clear();
+ fireItemSetChange();
+ return true;
+ }
+
+ public boolean removeContainerProperty(Object propertyId)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean removeItem(Object itemId)
+ throws UnsupportedOperationException {
+ if (!allItems.remove(itemId)) {
+ return false;
+ }
+ // detach listeners from Item
+ removeAllValueChangeListeners(beanToItem.get(itemId));
+ // remove item
+ beanToItem.remove(itemId);
+ list.remove(itemId);
+ fireItemSetChange();
+ return true;
+ }
+
+ private void addValueChangeListener(BeanItem beanItem, Object propertyId) {
+ Property property = beanItem.getItemProperty(propertyId);
+ if (property instanceof ValueChangeNotifier) {
+ // avoid multiple notifications for the same property if
+ // multiple filters are in use
+ ValueChangeNotifier notifier = (ValueChangeNotifier) property;
+ notifier.removeListener(this);
+ notifier.addListener(this);
+ }
+ }
+
+ private void removeValueChangeListener(BeanItem item, Object propertyId) {
+ Property property = item.getItemProperty(propertyId);
+ if (property instanceof ValueChangeNotifier) {
+ ((ValueChangeNotifier) property).removeListener(this);
+ }
+ }
+
+ private void removeAllValueChangeListeners(BeanItem item) {
+ for (Object propertyId : item.getItemPropertyIds()) {
+ removeValueChangeListener(item, propertyId);
+ }
+ }
+
+ public int size() {
+ return list.size();
+ }
+
+ public Collection<Object> getSortableContainerPropertyIds() {
+ LinkedList<Object> sortables = new LinkedList<Object>();
+ for (Object propertyId : getContainerPropertyIds()) {
+ Class<?> propertyType = getType(propertyId);
+ if (Comparable.class.isAssignableFrom(propertyType)) {
+ sortables.add(propertyId);
+ }
+ }
+ return sortables;
+ }
+
+ public void sort(Object[] propertyId, boolean[] ascending) {
+ for (int i = 0; i < ascending.length; i++) {
+ final boolean asc = ascending[i];
+ final Object property = propertyId[i];
+ // sort allItems, then filter and notify
+ Collections.sort(allItems, new Comparator<BT>() {
+ @SuppressWarnings("unchecked")
+ public int compare(BT a, BT b) {
+ Comparable va = (Comparable) beanToItem.get(a)
+ .getItemProperty(property).getValue();
+ Comparable vb = (Comparable) beanToItem.get(b)
+ .getItemProperty(property).getValue();
+
+ return asc ? va.compareTo(vb) : vb.compareTo(va);
+ }
+ });
+ }
+ // notifies if anything changes in the filtered list, including order
+ filterAll();
+ }
+
+ public void addListener(ItemSetChangeListener listener) {
+ if (itemSetChangeListeners == null) {
+ itemSetChangeListeners = new LinkedList<ItemSetChangeListener>();
+ }
+ itemSetChangeListeners.add(listener);
+ }
+
+ public void removeListener(ItemSetChangeListener listener) {
+ if (itemSetChangeListeners != null) {
+ itemSetChangeListeners.remove(listener);
+ }
+ }
+
+ private void fireItemSetChange() {
+ if (itemSetChangeListeners != null) {
+ final Container.ItemSetChangeEvent event = new Container.ItemSetChangeEvent() {
+ public Container getContainer() {
+ return BeanItemContainer.this;
+ }
+ };
+ for (ItemSetChangeListener listener : itemSetChangeListeners) {
+ listener.containerItemSetChange(event);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void addContainerFilter(Object propertyId, String filterString,
+ boolean ignoreCase, boolean onlyMatchPrefix) {
+ if (filters.isEmpty()) {
+ list = (ArrayList<BT>) allItems.clone();
+ }
+ // listen to change events to be able to update filtering
+ for (BeanItem item : beanToItem.values()) {
+ addValueChangeListener(item, propertyId);
+ }
+ Filter f = new Filter(propertyId, filterString, ignoreCase,
+ onlyMatchPrefix);
+ filter(f);
+ filters.add(f);
+ fireItemSetChange();
+ }
+
+ /**
+ * Filter the view to recreate the visible item list from the unfiltered
+ * items, and send a notification if the set of visible items changed in any
+ * way.
+ */
+ @SuppressWarnings("unchecked")
+ protected void filterAll() {
+ // avoid notification if the filtering had no effect
+ List<BT> originalItems = list;
+ // it is somewhat inefficient to do a (shallow) clone() every time
+ list = (ArrayList<BT>) allItems.clone();
+ for (Filter f : filters) {
+ filter(f);
+ }
+ // check if exactly the same items are there after filtering to avoid
+ // unnecessary notifications
+ // this may be slow in some cases as it uses BT.equals()
+ if (!originalItems.equals(list)) {
+ fireItemSetChange();
+ }
+ }
+
+ protected void filter(Filter f) {
+ Iterator<BT> iterator = list.iterator();
+ while (iterator.hasNext()) {
+ BT bean = iterator.next();
+ if (!f.passesFilter(getItem(bean))) {
+ iterator.remove();
+ }
+ }
+ }
+
+ public void removeAllContainerFilters() {
+ if (!filters.isEmpty()) {
+ filters = new HashSet<Filter>();
+ // stop listening to change events for any property
+ for (BeanItem item : beanToItem.values()) {
+ removeAllValueChangeListeners(item);
+ }
+ filterAll();
+ }
+ }
+
+ public void removeContainerFilters(Object propertyId) {
+ if (!filters.isEmpty()) {
+ for (Iterator<Filter> iterator = filters.iterator(); iterator
+ .hasNext();) {
+ Filter f = iterator.next();
+ if (f.propertyId.equals(propertyId)) {
+ iterator.remove();
+ }
+ }
+ // stop listening to change events for the property
+ for (BeanItem item : beanToItem.values()) {
+ removeValueChangeListener(item, propertyId);
+ }
+ filterAll();
+ }
+ }
+
+ public void valueChange(ValueChangeEvent event) {
+ // if a property that is used in a filter is changed, refresh filtering
+ filterAll();
+ }
+
+}
diff --git a/src/com/itmill/toolkit/data/util/Filter.java b/src/com/itmill/toolkit/data/util/Filter.java
new file mode 100644
index 0000000000..cbb1efae0d
--- /dev/null
+++ b/src/com/itmill/toolkit/data/util/Filter.java
@@ -0,0 +1,87 @@
+package com.itmill.toolkit.data.util;
+
+import com.itmill.toolkit.data.Item;
+import com.itmill.toolkit.data.Property;
+
+/**
+ * A default filter that can be used to implement
+ * {@link com.itmill.toolkit.data.Container.Filterable}.
+ *
+ * @since 5.4
+ */
+public class Filter {
+ final Object propertyId;
+ final String filterString;
+ final boolean ignoreCase;
+ final boolean onlyMatchPrefix;
+
+ Filter(Object propertyId, String filterString, boolean ignoreCase,
+ boolean onlyMatchPrefix) {
+ this.propertyId = propertyId;
+ ;
+ this.filterString = ignoreCase ? filterString.toLowerCase()
+ : filterString;
+ this.ignoreCase = ignoreCase;
+ this.onlyMatchPrefix = onlyMatchPrefix;
+ }
+
+ /**
+ * Check if an item passes the filter.
+ *
+ * @param item
+ * @return true if the item is accepted by this filter
+ */
+ public boolean passesFilter(Item item) {
+ final Property p = item.getItemProperty(propertyId);
+ if (p == null || p.toString() == null) {
+ return false;
+ }
+ final String value = ignoreCase ? p.toString().toLowerCase() : p
+ .toString();
+ if (onlyMatchPrefix) {
+ if (!value.startsWith(filterString)) {
+ return false;
+ }
+ } else {
+ if (!value.contains(filterString)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+
+ // Only ones of the objects of the same class can be equal
+ if (!(obj instanceof Filter)) {
+ return false;
+ }
+ final Filter o = (Filter) obj;
+
+ // Checks the properties one by one
+ if (propertyId != o.propertyId && o.propertyId != null
+ && !o.propertyId.equals(propertyId)) {
+ return false;
+ }
+ if (filterString != o.filterString && o.filterString != null
+ && !o.filterString.equals(filterString)) {
+ return false;
+ }
+ if (ignoreCase != o.ignoreCase) {
+ return false;
+ }
+ if (onlyMatchPrefix != o.onlyMatchPrefix) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return (propertyId != null ? propertyId.hashCode() : 0)
+ ^ (filterString != null ? filterString.hashCode() : 0);
+ }
+
+} \ No newline at end of file
diff --git a/src/com/itmill/toolkit/data/util/IndexedContainer.java b/src/com/itmill/toolkit/data/util/IndexedContainer.java
index f8ba1f13b8..0dbe44fc46 100644
--- a/src/com/itmill/toolkit/data/util/IndexedContainer.java
+++ b/src/com/itmill/toolkit/data/util/IndexedContainer.java
@@ -16,6 +16,7 @@ import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
+import java.util.List;
import java.util.NoSuchElementException;
import com.itmill.toolkit.data.Container;
@@ -118,7 +119,7 @@ public class IndexedContainer implements Container.Indexed,
* Filters that are applied to the container to limit the items visible in
* it
*/
- private HashSet filters;
+ private HashSet<Filter> filters;
private HashMap<Object, Object> defaultPropertyValues;
@@ -144,12 +145,8 @@ public class IndexedContainer implements Container.Indexed,
*/
public Item getItem(Object itemId) {
- // Null ids are not accepted
- if (itemId == null) {
- throw new NullPointerException("Container item id can not be null");
- }
-
- if (items.containsKey(itemId)
+ if (itemId != null
+ && items.containsKey(itemId)
&& (filteredItemIds == null || filteredItemIds.contains(itemId))) {
return new IndexedContainerItem(itemId);
}
@@ -196,7 +193,9 @@ public class IndexedContainer implements Container.Indexed,
* java.lang.Object)
*/
public Property getContainerProperty(Object itemId, Object propertyId) {
- if (filteredItemIds == null) {
+ if (itemId == null) {
+ return null;
+ } else if (filteredItemIds == null) {
if (!items.containsKey(itemId)) {
return null;
}
@@ -225,6 +224,9 @@ public class IndexedContainer implements Container.Indexed,
* @see com.itmill.toolkit.data.Container#containsId(java.lang.Object)
*/
public boolean containsId(Object itemId) {
+ if (itemId == null) {
+ return false;
+ }
if (filteredItemIds != null) {
return filteredItemIds.contains(itemId);
}
@@ -318,23 +320,20 @@ public class IndexedContainer implements Container.Indexed,
*/
public Item addItem(Object itemId) {
- // Null ids are not accepted
- if (itemId == null) {
- throw new NullPointerException("Container item id can not be null");
- }
-
- // Makes sure that the Item has not been created yet
- if (items.containsKey(itemId)) {
+ // Make sure that the Item is valid and has not been created yet
+ if (itemId == null || items.containsKey(itemId)) {
return null;
}
- // Adds the Item to container
+ // Adds the Item to container (at the end of the unfiltered list)
itemIds.add(itemId);
Hashtable t = new Hashtable();
items.put(itemId, t);
addDefaultValues(t);
+ // this optimization is why some code is duplicated with
+ // addItemAtInternalIndex()
final Item item = new IndexedContainerItem(itemId);
if (filteredItemIds != null) {
if (passesFilters(item)) {
@@ -460,13 +459,10 @@ public class IndexedContainer implements Container.Indexed,
*/
public Object nextItemId(Object itemId) {
if (filteredItemIds != null) {
- if (!filteredItemIds.contains(itemId)) {
+ if (itemId == null || !filteredItemIds.contains(itemId)) {
return null;
}
final Iterator i = filteredItemIds.iterator();
- if (itemId == null) {
- return null;
- }
while (i.hasNext() && !itemId.equals(i.next())) {
;
}
@@ -560,7 +556,7 @@ public class IndexedContainer implements Container.Indexed,
public Item addItemAfter(Object previousItemId, Object newItemId) {
// Get the index of the addition
- int index = 0;
+ int index = -1;
if (previousItemId != null) {
index = 1 + indexOfId(previousItemId);
if (index <= 0 || index > size()) {
@@ -579,16 +575,10 @@ public class IndexedContainer implements Container.Indexed,
*/
public Object addItemAfter(Object previousItemId) {
- // Get the index of the addition
- int index = 0;
- if (previousItemId != null) {
- index = 1 + indexOfId(previousItemId);
- if (index <= 0 || index > size()) {
- return null;
- }
- }
+ // Creates a new id
+ final Object id = new Object();
- return addItemAt(index);
+ return addItemAfter(previousItemId, id);
}
/*
@@ -628,15 +618,15 @@ public class IndexedContainer implements Container.Indexed,
if (itemId == null) {
return -1;
}
- try {
- for (final Iterator i = filteredItemIds.iterator(); itemId
- .equals(i.next());) {
- index++;
+ final Iterator i = filteredItemIds.iterator();
+ while (i.hasNext()) {
+ Object id = i.next();
+ if (itemId.equals(id)) {
+ return index;
}
- return index;
- } catch (final NoSuchElementException e) {
- return -1;
+ index++;
}
+ return -1;
}
return itemIds.indexOf(itemId);
}
@@ -649,24 +639,26 @@ public class IndexedContainer implements Container.Indexed,
*/
public Item addItemAt(int index, Object newItemId) {
- // Make sure that the Item has not been created yet
- if (items.containsKey(newItemId)) {
- return null;
- }
-
- // Adds the Item to container
- itemIds.add(index, newItemId);
- Hashtable t = new Hashtable();
- items.put(newItemId, t);
- addDefaultValues(t);
-
- if (filteredItemIds != null) {
- updateContainerFiltering();
+ // add item based on a filtered index
+ int internalIndex = -1;
+ if (filteredItemIds == null) {
+ internalIndex = index;
+ } else if (index == 0) {
+ internalIndex = 0;
+ } else if (index == size()) {
+ // add just after the last item
+ Object id = getIdByIndex(index - 1);
+ internalIndex = itemIds.indexOf(id) + 1;
+ } else if (index > 0 && index < size()) {
+ // map the index of the visible item to its unfiltered index
+ Object id = getIdByIndex(index);
+ internalIndex = itemIds.indexOf(id);
+ }
+ if (internalIndex >= 0) {
+ return addItemAtInternalIndex(internalIndex, newItemId);
} else {
- fireContentsChange(index);
+ return null;
}
-
- return getItem(newItemId);
}
/*
@@ -688,6 +680,43 @@ public class IndexedContainer implements Container.Indexed,
/* Event notifiers */
/**
+ * Adds new item at given index of the internal (unfiltered) list.
+ * <p>
+ * The item is also added in the visible part of the list if it passes the
+ * filters.
+ * </p>
+ *
+ * @param index
+ * Internal index to add the new item.
+ * @param newItemId
+ * Id of the new item to be added.
+ * @return Returns new item or null if the operation fails.
+ */
+ private Item addItemAtInternalIndex(int index, Object newItemId) {
+ // Make sure that the Item is valid and has not been created yet
+ if (index < 0 || index > itemIds.size() || newItemId == null
+ || items.containsKey(newItemId)) {
+ return null;
+ }
+
+ // Adds the Item to container
+ itemIds.add(index, newItemId);
+ Hashtable t = new Hashtable();
+ items.put(newItemId, t);
+ addDefaultValues(t);
+
+ if (filteredItemIds != null) {
+ // when the item data is set later (IndexedContainerProperty),
+ // filtering is updated
+ updateContainerFiltering();
+ } else {
+ fireContentsChange(index);
+ }
+
+ return new IndexedContainerItem(newItemId);
+ }
+
+ /**
* An <code>event</code> object specifying the list whose Property set has
* changed.
*
@@ -766,8 +795,8 @@ public class IndexedContainer implements Container.Indexed,
}
/**
- * An <code>event</code> object specifying the Propery in a list whose value
- * has changed.
+ * An <code>event</code> object specifying the Property in a list whose
+ * value has changed.
*
* @author IT Mill Ltd.
* @version
@@ -1270,6 +1299,9 @@ public class IndexedContainer implements Container.Indexed,
}
}
+ // update the container filtering if this property is being filtered
+ updateContainerFiltering(propertyId);
+
firePropertyValueChange(this);
}
@@ -1359,11 +1391,11 @@ public class IndexedContainer implements Container.Indexed,
* @see com.itmill.toolkit.data.Container.Sortable#sort(java.lang.Object[],
* boolean[])
*/
- public synchronized void sort(Object[] propertyId, boolean[] ascending) {
+ public void sort(Object[] propertyId, boolean[] ascending) {
// Removes any non-sortable property ids
- final ArrayList ids = new ArrayList();
- final ArrayList orders = new ArrayList();
+ final List ids = new ArrayList();
+ final List<Boolean> orders = new ArrayList<Boolean>();
final Collection sortable = getSortableContainerPropertyIds();
for (int i = 0; i < propertyId.length; i++) {
if (sortable.contains(propertyId[i])) {
@@ -1379,7 +1411,7 @@ public class IndexedContainer implements Container.Indexed,
sortPropertyId = ids.toArray();
sortDirection = new boolean[orders.size()];
for (int i = 0; i < sortDirection.length; i++) {
- sortDirection[i] = ((Boolean) orders.get(i)).booleanValue();
+ sortDirection[i] = (orders.get(i)).booleanValue();
}
// Sort
@@ -1503,7 +1535,7 @@ public class IndexedContainer implements Container.Indexed,
.clone() : null;
nc.types = types != null ? (Hashtable) types.clone() : null;
- nc.filters = filters == null ? null : (HashSet) filters.clone();
+ nc.filters = filters == null ? null : (HashSet<Filter>) filters.clone();
nc.filteredItemIds = filteredItemIds == null ? null
: (LinkedHashSet) filteredItemIds.clone();
@@ -1534,61 +1566,10 @@ public class IndexedContainer implements Container.Indexed,
return super.equals(obj);
}
- private class Filter {
- Object propertyId;
- String filterString;
- boolean ignoreCase;
- boolean onlyMatchPrefix;
-
- Filter(Object propertyId, String filterString, boolean ignoreCase,
- boolean onlyMatchPrefix) {
- this.propertyId = propertyId;
- ;
- this.filterString = filterString;
- this.ignoreCase = ignoreCase;
- this.onlyMatchPrefix = onlyMatchPrefix;
- }
-
- @Override
- public boolean equals(Object obj) {
-
- // Only ones of the objects of the same class can be equal
- if (!(obj instanceof Filter)) {
- return false;
- }
- final Filter o = (Filter) obj;
-
- // Checks the properties one by one
- if (propertyId != o.propertyId && o.propertyId != null
- && !o.propertyId.equals(propertyId)) {
- return false;
- }
- if (filterString != o.filterString && o.filterString != null
- && !o.filterString.equals(filterString)) {
- return false;
- }
- if (ignoreCase != o.ignoreCase) {
- return false;
- }
- if (onlyMatchPrefix != o.onlyMatchPrefix) {
- return false;
- }
-
- return true;
- }
-
- @Override
- public int hashCode() {
- return (propertyId != null ? propertyId.hashCode() : 0)
- ^ (filterString != null ? filterString.hashCode() : 0);
- }
-
- }
-
public void addContainerFilter(Object propertyId, String filterString,
boolean ignoreCase, boolean onlyMatchPrefix) {
if (filters == null) {
- filters = new HashSet();
+ filters = new HashSet<Filter>();
}
filters.add(new Filter(propertyId, filterString, ignoreCase,
onlyMatchPrefix));
@@ -1607,8 +1588,9 @@ public class IndexedContainer implements Container.Indexed,
if (filters == null || propertyId == null) {
return;
}
- for (final Iterator i = filters.iterator(); i.hasNext();) {
- final Filter f = (Filter) i.next();
+ final Iterator<Filter> i = filters.iterator();
+ while (i.hasNext()) {
+ final Filter f = i.next();
if (propertyId.equals(f.propertyId)) {
i.remove();
}
@@ -1616,6 +1598,22 @@ public class IndexedContainer implements Container.Indexed,
updateContainerFiltering();
}
+ private void updateContainerFiltering(Object propertyId) {
+ if (filters == null || propertyId == null) {
+ return;
+ }
+ // update container filtering if there is a filter for the given
+ // property
+ final Iterator<Filter> i = filters.iterator();
+ while (i.hasNext()) {
+ final Filter f = i.next();
+ if (propertyId.equals(f.propertyId)) {
+ updateContainerFiltering();
+ return;
+ }
+ }
+ }
+
private void updateContainerFiltering() {
// Clearing filters?
@@ -1628,7 +1626,7 @@ public class IndexedContainer implements Container.Indexed,
return;
}
- // Reset filteres list
+ // Reset filtered list
if (filteredItemIds == null) {
filteredItemIds = new LinkedHashSet();
} else {
@@ -1653,25 +1651,12 @@ public class IndexedContainer implements Container.Indexed,
if (item == null) {
return false;
}
- for (final Iterator i = filters.iterator(); i.hasNext();) {
- final Filter f = (Filter) i.next();
- final String s1 = f.ignoreCase ? f.filterString.toLowerCase()
- : f.filterString;
- final Property p = item.getItemProperty(f.propertyId);
- if (p == null || p.toString() == null) {
+ final Iterator<Filter> i = filters.iterator();
+ while (i.hasNext()) {
+ final Filter f = i.next();
+ if (!f.passesFilter(item)) {
return false;
}
- final String s2 = f.ignoreCase ? p.toString().toLowerCase() : p
- .toString();
- if (f.onlyMatchPrefix) {
- if (s2.indexOf(s1) != 0) {
- return false;
- }
- } else {
- if (s2.indexOf(s1) < 0) {
- return false;
- }
- }
}
return true;
}
diff --git a/src/com/itmill/toolkit/data/util/PropertysetItem.java b/src/com/itmill/toolkit/data/util/PropertysetItem.java
index dfc819ca7e..c6c01743e2 100644
--- a/src/com/itmill/toolkit/data/util/PropertysetItem.java
+++ b/src/com/itmill/toolkit/data/util/PropertysetItem.java
@@ -259,15 +259,9 @@ public class PropertysetItem implements Item, Item.PropertySetChangeNotifier,
return npsi;
}
- /**
- * Returns <code>true</code> if and only if the argument is not
- * <code>null</code> and is a Boolean object that represents the same
- * boolean value as this object.
+ /*
+ * (non-Javadoc)
*
- * @param obj
- * the object to compare with.
- * @return <code>true</code> if the Boolean objects represent the same value
- * otherwise <code>false</code>.
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -308,10 +302,9 @@ public class PropertysetItem implements Item, Item.PropertySetChangeNotifier,
return true;
}
- /**
- * Returns the hash code value for this list.
+ /*
+ * (non-Javadoc)
*
- * @return the hash code value.
* @see java.lang.Object#hashCode()
*/
@Override
diff --git a/src/com/itmill/toolkit/data/validator/AbstractStringValidator.java b/src/com/itmill/toolkit/data/validator/AbstractStringValidator.java
new file mode 100644
index 0000000000..7f26a87861
--- /dev/null
+++ b/src/com/itmill/toolkit/data/validator/AbstractStringValidator.java
@@ -0,0 +1,54 @@
+package com.itmill.toolkit.data.validator;
+
+/**
+ * Validator base class for validating strings. See
+ * {@link com.itmill.toolkit.data.validator.AbstractValidator} for more
+ * information.
+ *
+ * <p>
+ * If the validation fails, the exception thrown contains the error message with
+ * its argument 0 replaced with the string being validated.
+ * </p>
+ *
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 5.4
+ */
+public abstract class AbstractStringValidator extends AbstractValidator {
+
+ /**
+ * Constructs a validator for strings.
+ * <p>
+ * Null and empty string values are always accepted. To disallow empty
+ * values, set the field being validated as required.
+ * </p>
+ *
+ * @param errorMessage
+ * the message included in the exception (with its parameter {0}
+ * replaced by the string to be validated) in case the validation
+ * fails
+ */
+ public AbstractStringValidator(String errorMessage) {
+ super(errorMessage);
+ }
+
+ public boolean isValid(Object value) {
+ if (value == null) {
+ return true;
+ }
+ if (!(value instanceof String)) {
+ return false;
+ }
+ return isValidString((String) value);
+ }
+
+ /**
+ * Checks if the given string is valid.
+ *
+ * @param value
+ * String to check. Can never be null.
+ * @return true if the string is valid, false otherwise
+ */
+ protected abstract boolean isValidString(String value);
+}
diff --git a/src/com/itmill/toolkit/data/validator/AbstractValidator.java b/src/com/itmill/toolkit/data/validator/AbstractValidator.java
new file mode 100644
index 0000000000..93d6ae41fa
--- /dev/null
+++ b/src/com/itmill/toolkit/data/validator/AbstractValidator.java
@@ -0,0 +1,67 @@
+package com.itmill.toolkit.data.validator;
+
+import com.itmill.toolkit.data.Validator;
+
+/**
+ * Default Validator base class. See
+ * {@link com.itmill.toolkit.data.validator.Validator} for more information.
+ * <p>
+ * If the validation fails, the exception thrown contains the error message with
+ * its argument 0 replaced with the toString() of the object being validated.
+ * </p>
+ *
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 5.4
+ */
+public abstract class AbstractValidator implements Validator {
+
+ /**
+ * Error message.
+ */
+ private String errorMessage;
+
+ /**
+ * Constructs a validator with an error message.
+ *
+ * @param errorMessage
+ * the message included in the exception (with its parameter {0}
+ * replaced by toString() of the object to be validated) in case
+ * the validation fails
+ */
+ public AbstractValidator(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
+ public void validate(Object value) throws InvalidValueException {
+ if (!isValid(value)) {
+ String message;
+ if (value == null) {
+ message = errorMessage.replace("{0}", "null");
+ } else {
+ message = errorMessage.replace("{0}", value.toString());
+ }
+ throw new InvalidValueException(message);
+ }
+ }
+
+ /**
+ * Gets the message to be displayed in case the value does not validate.
+ *
+ * @return the Error Message.
+ */
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ /**
+ * Sets the message to be displayed in case the value does not validate.
+ *
+ * @param errorMessage
+ * the Error Message to set.
+ */
+ public void setErrorMessage(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+}
diff --git a/src/com/itmill/toolkit/data/validator/CompositeValidator.java b/src/com/itmill/toolkit/data/validator/CompositeValidator.java
index f8ac2fc7eb..6aa9d07b99 100644
--- a/src/com/itmill/toolkit/data/validator/CompositeValidator.java
+++ b/src/com/itmill/toolkit/data/validator/CompositeValidator.java
@@ -6,8 +6,8 @@ package com.itmill.toolkit.data.validator;
import java.util.Collection;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.LinkedList;
+import java.util.List;
import com.itmill.toolkit.data.Validator;
@@ -23,7 +23,7 @@ import com.itmill.toolkit.data.Validator;
* @VERSION@
* @since 3.0
*/
-public class CompositeValidator implements Validator {
+public class CompositeValidator extends AbstractValidator {
/**
* The validators are combined with <code>AND</code> clause: validity of the
@@ -53,26 +53,22 @@ public class CompositeValidator implements Validator {
/**
* List of contained validators.
*/
- private final LinkedList validators = new LinkedList();
-
- /**
- * Error message.
- */
- private String errorMessage;
+ private final List<Validator> validators = new LinkedList<Validator>();
/**
* Construct a composite validator in <code>AND</code> mode without error
* message.
*/
public CompositeValidator() {
+ super("");
}
/**
* Constructs a composite validator in given mode.
*/
public CompositeValidator(int mode, String errorMessage) {
+ super(errorMessage);
setMode(mode);
- setErrorMessage(errorMessage);
}
/**
@@ -94,19 +90,20 @@ public class CompositeValidator implements Validator {
* @throws Validator.InvalidValueException
* if the value is not valid.
*/
+ @Override
public void validate(Object value) throws Validator.InvalidValueException {
switch (mode) {
case MODE_AND:
- for (final Iterator i = validators.iterator(); i.hasNext();) {
- ((Validator) i.next()).validate(value);
+ for (Validator validator : validators) {
+ validator.validate(value);
}
return;
case MODE_OR:
Validator.InvalidValueException first = null;
- for (final Iterator i = validators.iterator(); i.hasNext();) {
+ for (Validator v : validators) {
try {
- ((Validator) i.next()).validate(value);
+ v.validate(value);
return;
} catch (final Validator.InvalidValueException e) {
if (first == null) {
@@ -141,8 +138,7 @@ public class CompositeValidator implements Validator {
public boolean isValid(Object value) {
switch (mode) {
case MODE_AND:
- for (final Iterator i = validators.iterator(); i.hasNext();) {
- final Validator v = (Validator) i.next();
+ for (Validator v : validators) {
if (!v.isValid(value)) {
return false;
}
@@ -150,8 +146,7 @@ public class CompositeValidator implements Validator {
return true;
case MODE_OR:
- for (final Iterator i = validators.iterator(); i.hasNext();) {
- final Validator v = (Validator) i.next();
+ for (Validator v : validators) {
if (v.isValid(value)) {
return true;
}
@@ -193,9 +188,10 @@ public class CompositeValidator implements Validator {
* Gets the error message for the composite validator. If the error message
* is null, original error messages of the sub-validators are used instead.
*/
+ @Override
public String getErrorMessage() {
- if (errorMessage != null) {
- return errorMessage;
+ if (getErrorMessage() != null) {
+ return getErrorMessage();
}
// TODO Return composite error message
@@ -204,17 +200,6 @@ public class CompositeValidator implements Validator {
}
/**
- * Sets the error message for the composite validator. If the error message
- * is null, original error messages of the sub-validators are used instead.
- *
- * @param errorMessage
- * the Error Message to set.
- */
- public void setErrorMessage(String errorMessage) {
- this.errorMessage = errorMessage;
- }
-
- /**
* Adds validator to the interface.
*
* @param validator
@@ -254,23 +239,22 @@ public class CompositeValidator implements Validator {
* validators of given type null is returned.
* </p>
*
- * @return Collection of validators compatible with given type that must
- * apply or null if none fould.
+ * @return Collection<Validator> of validators compatible with given type
+ * that must apply or null if none fould.
*/
- public Collection getSubValidators(Class validatorType) {
+ public Collection<Validator> getSubValidators(Class validatorType) {
if (mode != MODE_AND) {
return null;
}
- final HashSet found = new HashSet();
- for (final Iterator i = validators.iterator(); i.hasNext();) {
- final Validator v = (Validator) i.next();
+ final HashSet<Validator> found = new HashSet<Validator>();
+ for (Validator v : validators) {
if (validatorType.isAssignableFrom(v.getClass())) {
found.add(v);
}
if (v instanceof CompositeValidator
&& ((CompositeValidator) v).getMode() == MODE_AND) {
- final Collection c = ((CompositeValidator) v)
+ final Collection<Validator> c = ((CompositeValidator) v)
.getSubValidators(validatorType);
if (c != null) {
found.addAll(c);
diff --git a/src/com/itmill/toolkit/data/validator/DoubleValidator.java b/src/com/itmill/toolkit/data/validator/DoubleValidator.java
new file mode 100644
index 0000000000..56f537f5e4
--- /dev/null
+++ b/src/com/itmill/toolkit/data/validator/DoubleValidator.java
@@ -0,0 +1,36 @@
+package com.itmill.toolkit.data.validator;
+
+/**
+ * String validator for a double precision floating point number. See
+ * {@link com.itmill.toolkit.data.validator.AbstractStringValidator} for more
+ * information.
+ *
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 5.4
+ */
+public class DoubleValidator extends AbstractStringValidator {
+
+ /**
+ * Creates a validator for checking that a string can be parsed as an
+ * double.
+ *
+ * @param errorMessage
+ * the message to display in case the value does not validate.
+ */
+ public DoubleValidator(String errorMessage) {
+ super(errorMessage);
+ }
+
+ @Override
+ protected boolean isValidString(String value) {
+ try {
+ Double.parseDouble(value);
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+}
diff --git a/src/com/itmill/toolkit/data/validator/EmailValidator.java b/src/com/itmill/toolkit/data/validator/EmailValidator.java
new file mode 100644
index 0000000000..b5abb4d712
--- /dev/null
+++ b/src/com/itmill/toolkit/data/validator/EmailValidator.java
@@ -0,0 +1,31 @@
+package com.itmill.toolkit.data.validator;
+
+/**
+ * String validator for e-mail addresses. The e-mail address syntax is not
+ * complete according to RFC 822 but handles the vast majority of valid e-mail
+ * addresses correctly.
+ *
+ * See {@link com.itmill.toolkit.data.validator.AbstractStringValidator} for
+ * more information.
+ *
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 5.4
+ */
+public class EmailValidator extends RegexpValidator {
+
+ /**
+ * Creates a validator for checking that a string is a syntactically valid
+ * e-mail address.
+ *
+ * @param errorMessage
+ * the message to display in case the value does not validate.
+ */
+ public EmailValidator(String errorMessage) {
+ super(
+ "^([a-zA-Z0-9_\\.\\-+])+@(([a-zA-Z0-9-])+\\.)+([a-zA-Z0-9]{2,4})+$",
+ true, errorMessage);
+ }
+
+}
diff --git a/src/com/itmill/toolkit/data/validator/IntegerValidator.java b/src/com/itmill/toolkit/data/validator/IntegerValidator.java
new file mode 100644
index 0000000000..f48e85943e
--- /dev/null
+++ b/src/com/itmill/toolkit/data/validator/IntegerValidator.java
@@ -0,0 +1,37 @@
+package com.itmill.toolkit.data.validator;
+
+/**
+ * String validator for integers. See
+ * {@link com.itmill.toolkit.data.validator.AbstractStringValidator} for more
+ * information.
+ *
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 5.4
+ */
+public class IntegerValidator extends AbstractStringValidator {
+
+ /**
+ * Creates a validator for checking that a string can be parsed as an
+ * integer.
+ *
+ * @param errorMessage
+ * the message to display in case the value does not validate.
+ */
+ public IntegerValidator(String errorMessage) {
+ super(errorMessage);
+
+ }
+
+ @Override
+ protected boolean isValidString(String value) {
+ try {
+ Integer.parseInt(value);
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+}
diff --git a/src/com/itmill/toolkit/data/validator/RegexpValidator.java b/src/com/itmill/toolkit/data/validator/RegexpValidator.java
new file mode 100644
index 0000000000..56316bea84
--- /dev/null
+++ b/src/com/itmill/toolkit/data/validator/RegexpValidator.java
@@ -0,0 +1,86 @@
+package com.itmill.toolkit.data.validator;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * String validator comparing the string against a Java regular expression. Both
+ * complete matches and substring matches are supported.
+ *
+ * <p>
+ * For the Java regular expression syntax, see
+ * {@link java.util.regex.Pattern#sum}
+ * </p>
+ * <p>
+ * See {@link com.itmill.toolkit.data.validator.AbstractStringValidator} for
+ * more information.
+ * </p>
+ *
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 5.4
+ */
+public class RegexpValidator extends AbstractStringValidator {
+
+ private Pattern pattern;
+ private boolean complete;
+ private Matcher matcher = null;
+
+ /**
+ * Creates a validator for checking that the regular expression matches the
+ * complete string to validate.
+ *
+ * @param regexp
+ * a Java regular expression
+ * @param errorMessage
+ * the message to display in case the value does not validate.
+ */
+ public RegexpValidator(String regexp, String errorMessage) {
+ this(regexp, true, errorMessage);
+ }
+
+ /**
+ * Creates a validator for checking that the regular expression matches the
+ * string to validate.
+ *
+ * @param regexp
+ * a Java regular expression
+ * @param complete
+ * true to use check for a complete match, false to look for a
+ * matching substring
+ * @param errorMessage
+ * the message to display in case the value does not validate.
+ */
+ public RegexpValidator(String regexp, boolean complete, String errorMessage) {
+ super(errorMessage);
+ pattern = Pattern.compile(regexp);
+ this.complete = complete;
+ }
+
+ @Override
+ protected boolean isValidString(String value) {
+ if (complete) {
+ return getMatcher(value).matches();
+ } else {
+ return getMatcher(value).find();
+ }
+ }
+
+ /**
+ * Get a new or reused matcher for the pattern
+ *
+ * @param value
+ * the string to find matches in
+ * @return Matcher for the string
+ */
+ private Matcher getMatcher(String value) {
+ if (matcher == null) {
+ matcher = pattern.matcher(value);
+ } else {
+ matcher.reset(value);
+ }
+ return matcher;
+ }
+
+}
diff --git a/src/com/itmill/toolkit/data/validator/StringLengthValidator.java b/src/com/itmill/toolkit/data/validator/StringLengthValidator.java
index df702cfea4..e4c28041a7 100644
--- a/src/com/itmill/toolkit/data/validator/StringLengthValidator.java
+++ b/src/com/itmill/toolkit/data/validator/StringLengthValidator.java
@@ -4,8 +4,6 @@
package com.itmill.toolkit.data.validator;
-import com.itmill.toolkit.data.Validator;
-
/**
* This <code>StringLengthValidator</code> is used to validate the length of
* strings.
@@ -15,7 +13,7 @@ import com.itmill.toolkit.data.Validator;
* @VERSION@
* @since 3.0
*/
-public class StringLengthValidator implements Validator {
+public class StringLengthValidator extends AbstractValidator {
private int minLength = -1;
@@ -23,8 +21,6 @@ public class StringLengthValidator implements Validator {
private boolean allowNull = true;
- private String errorMessage;
-
/**
* Creates a new StringLengthValidator with a given error message.
*
@@ -32,7 +28,7 @@ public class StringLengthValidator implements Validator {
* the message to display in case the value does not validate.
*/
public StringLengthValidator(String errorMessage) {
- setErrorMessage(errorMessage);
+ super(errorMessage);
}
/**
@@ -42,11 +38,12 @@ public class StringLengthValidator implements Validator {
* @param errorMessage
* the message to display in case the value does not validate.
* @param minLength
- * the minimum permissable length of the string.
+ * the minimum permissible length of the string.
* @param maxLength
- * the maximum permissable length of the string.
+ * the maximum permissible length of the string.
* @param allowNull
- * Are null strings permissable?
+ * Are null strings permissible? This can be handled better by
+ * setting a field as required or not.
*/
public StringLengthValidator(String errorMessage, int minLength,
int maxLength, boolean allowNull) {
@@ -57,37 +54,6 @@ public class StringLengthValidator implements Validator {
}
/**
- * Validates the value.
- *
- * @param value
- * the value to validate.
- * @throws Validator.InvalidValueException
- * if the value was invalid.
- */
- public void validate(Object value) throws Validator.InvalidValueException {
- if (value == null) {
- if (allowNull) {
- return;
- } else {
- throw new Validator.InvalidValueException(errorMessage);
- }
- }
- final String s = value.toString();
- if (s == null) {
- if (allowNull) {
- return;
- } else {
- throw new Validator.InvalidValueException(errorMessage);
- }
- }
- final int len = s.length();
- if ((minLength >= 0 && len < minLength)
- || (maxLength >= 0 && len > maxLength)) {
- throw new Validator.InvalidValueException(errorMessage);
- }
- }
-
- /**
* Checks if the given value is valid.
*
* @param value
@@ -116,12 +82,13 @@ public class StringLengthValidator implements Validator {
* @return <code>true</code> if allows null string, otherwise
* <code>false</code>.
*/
+ @Deprecated
public final boolean isNullAllowed() {
return allowNull;
}
/**
- * Gets the maximum permissable length of the string.
+ * Gets the maximum permissible length of the string.
*
* @return the maximum length of the string.
*/
@@ -130,7 +97,7 @@ public class StringLengthValidator implements Validator {
}
/**
- * Gets the minimum permissable length of the string.
+ * Gets the minimum permissible length of the string.
*
* @return the minimum length of the string.
*/
@@ -139,14 +106,16 @@ public class StringLengthValidator implements Validator {
}
/**
- * Sets whether null-strings are to be allowed.
+ * Sets whether null-strings are to be allowed. This can be better handled
+ * by setting a field as required or not.
*/
+ @Deprecated
public void setNullAllowed(boolean allowNull) {
this.allowNull = allowNull;
}
/**
- * Sets the maximum permissable length of the string.
+ * Sets the maximum permissible length of the string.
*
* @param maxLength
* the length to set.
@@ -159,7 +128,7 @@ public class StringLengthValidator implements Validator {
}
/**
- * Sets the minimum permissable length.
+ * Sets the minimum permissible length.
*
* @param minLength
* the length to set.
@@ -171,23 +140,4 @@ public class StringLengthValidator implements Validator {
this.minLength = minLength;
}
- /**
- * Gets the message to be displayed in case the value does not validate.
- *
- * @return the Error Message.
- */
- public String getErrorMessage() {
- return errorMessage;
- }
-
- /**
- * Sets the message to be displayer in case the value does not validate.
- *
- * @param errorMessage
- * the Error Message to set.
- */
- public void setErrorMessage(String errorMessage) {
- this.errorMessage = errorMessage;
- }
-
}
diff --git a/src/com/itmill/toolkit/demo/sampler/APIResource.java b/src/com/itmill/toolkit/demo/sampler/APIResource.java
index 183c9c3a52..e1973f9140 100644
--- a/src/com/itmill/toolkit/demo/sampler/APIResource.java
+++ b/src/com/itmill/toolkit/demo/sampler/APIResource.java
@@ -2,7 +2,7 @@ package com.itmill.toolkit.demo.sampler;
/**
* A NamedExternalResource pointing to the javadoc for the given class. Knows
- * where the javadocs are located for som common APIs, but one can also specify
+ * where the javadocs are located for some common APIs, but one can also specify
* a javadoc baseurl. The name will be set to the class simpleName.
*
*/
diff --git a/src/com/itmill/toolkit/demo/sampler/FeatureSet.java b/src/com/itmill/toolkit/demo/sampler/FeatureSet.java
index 6c9da622ac..ec521cbc9b 100644
--- a/src/com/itmill/toolkit/demo/sampler/FeatureSet.java
+++ b/src/com/itmill/toolkit/demo/sampler/FeatureSet.java
@@ -43,6 +43,7 @@ import com.itmill.toolkit.demo.sampler.features.notifications.NotificationWarnin
import com.itmill.toolkit.demo.sampler.features.panels.PanelBasic;
import com.itmill.toolkit.demo.sampler.features.panels.PanelLight;
import com.itmill.toolkit.demo.sampler.features.selects.ComboBoxContains;
+import com.itmill.toolkit.demo.sampler.features.selects.ComboBoxInputPrompt;
import com.itmill.toolkit.demo.sampler.features.selects.ComboBoxNewItems;
import com.itmill.toolkit.demo.sampler.features.selects.ComboBoxPlain;
import com.itmill.toolkit.demo.sampler.features.selects.ComboBoxStartsWith;
@@ -70,6 +71,7 @@ import com.itmill.toolkit.demo.sampler.features.text.LabelPreformatted;
import com.itmill.toolkit.demo.sampler.features.text.LabelRich;
import com.itmill.toolkit.demo.sampler.features.text.RichTextEditor;
import com.itmill.toolkit.demo.sampler.features.text.TextArea;
+import com.itmill.toolkit.demo.sampler.features.text.TextFieldInputPrompt;
import com.itmill.toolkit.demo.sampler.features.text.TextFieldSecret;
import com.itmill.toolkit.demo.sampler.features.text.TextFieldSingle;
import com.itmill.toolkit.demo.sampler.features.trees.TreeActions;
@@ -213,6 +215,7 @@ public class FeatureSet extends Feature {
new TwinColumnSelect(), //
new NativeSelection(), //
new ComboBoxPlain(), //
+ new ComboBoxInputPrompt(), //
new ComboBoxStartsWith(), //
new ComboBoxContains(), //
new ComboBoxNewItems(), //
@@ -368,6 +371,7 @@ public class FeatureSet extends Feature {
//
new TextFieldSingle(), //
new TextFieldSecret(), //
+ new TextFieldInputPrompt(), //
new TextArea(), //
new RichTextEditor(), //
});
diff --git a/src/com/itmill/toolkit/demo/sampler/features/selects/75-ComboBoxInputPrompt.png b/src/com/itmill/toolkit/demo/sampler/features/selects/75-ComboBoxInputPrompt.png
new file mode 100644
index 0000000000..3ef7a48faa
--- /dev/null
+++ b/src/com/itmill/toolkit/demo/sampler/features/selects/75-ComboBoxInputPrompt.png
Binary files differ
diff --git a/src/com/itmill/toolkit/demo/sampler/features/selects/ComboBoxInputPrompt.java b/src/com/itmill/toolkit/demo/sampler/features/selects/ComboBoxInputPrompt.java
new file mode 100644
index 0000000000..2155f874f9
--- /dev/null
+++ b/src/com/itmill/toolkit/demo/sampler/features/selects/ComboBoxInputPrompt.java
@@ -0,0 +1,44 @@
+package com.itmill.toolkit.demo.sampler.features.selects;
+
+import com.itmill.toolkit.demo.sampler.APIResource;
+import com.itmill.toolkit.demo.sampler.Feature;
+import com.itmill.toolkit.demo.sampler.NamedExternalResource;
+import com.itmill.toolkit.demo.sampler.features.text.TextFieldInputPrompt;
+import com.itmill.toolkit.ui.ComboBox;
+
+public class ComboBoxInputPrompt extends Feature {
+ @Override
+ public String getName() {
+ return "Combobox with input prompt";
+ }
+
+ @Override
+ public String getDescription() {
+ return "ComboBox is a drop-down selection component with single item selection."
+ + " It can have an <i>input prompt</i> - a textual hint that is shown within"
+ + " the select when no value is selected.<br/>"
+ + " You can use an input prompt instead of a caption to save"
+ + " space, but only do so if the function of the ComboBox is"
+ + " still clear when a value is selected and the prompt is no"
+ + " longer visible.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(ComboBox.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { ComboBoxStartsWith.class, ComboBoxContains.class,
+ ComboBoxNewItems.class, TextFieldInputPrompt.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return new NamedExternalResource[] { new NamedExternalResource(
+ "UI Patterns, Input Prompt",
+ "http://ui-patterns.com/pattern/InputPrompt") };
+ }
+
+}
diff --git a/src/com/itmill/toolkit/demo/sampler/features/selects/ComboBoxInputPromptExample.java b/src/com/itmill/toolkit/demo/sampler/features/selects/ComboBoxInputPromptExample.java
new file mode 100644
index 0000000000..4146614659
--- /dev/null
+++ b/src/com/itmill/toolkit/demo/sampler/features/selects/ComboBoxInputPromptExample.java
@@ -0,0 +1,39 @@
+package com.itmill.toolkit.demo.sampler.features.selects;
+
+import com.itmill.toolkit.data.Property;
+import com.itmill.toolkit.data.Property.ValueChangeEvent;
+import com.itmill.toolkit.ui.ComboBox;
+import com.itmill.toolkit.ui.VerticalLayout;
+
+public class ComboBoxInputPromptExample extends VerticalLayout implements
+ Property.ValueChangeListener {
+
+ private static final String[] cities = new String[] { "Berlin", "Brussels",
+ "Helsinki", "Madrid", "Oslo", "Paris", "Stockholm" };
+
+ public ComboBoxInputPromptExample() {
+ setMargin(true); // for looks: more 'air'
+
+ // Create & set input prompt
+ ComboBox l = new ComboBox();
+ l.setInputPrompt("Please select a city");
+
+ // configure & load content
+ l.setImmediate(true);
+ l.addListener(this);
+ for (int i = 0; i < cities.length; i++) {
+ l.addItem(cities[i]);
+ }
+
+ // add to the layout
+ addComponent(l);
+ }
+
+ /*
+ * Shows a notification when a selection is made.
+ */
+ public void valueChange(ValueChangeEvent event) {
+ getWindow().showNotification("Selected city: " + event.getProperty());
+
+ }
+}
diff --git a/src/com/itmill/toolkit/demo/sampler/features/text/75-TextFieldInputPrompt.png b/src/com/itmill/toolkit/demo/sampler/features/text/75-TextFieldInputPrompt.png
new file mode 100644
index 0000000000..dc7fbb38f9
--- /dev/null
+++ b/src/com/itmill/toolkit/demo/sampler/features/text/75-TextFieldInputPrompt.png
Binary files differ
diff --git a/src/com/itmill/toolkit/demo/sampler/features/text/TextFieldInputPrompt.java b/src/com/itmill/toolkit/demo/sampler/features/text/TextFieldInputPrompt.java
new file mode 100644
index 0000000000..5299916e31
--- /dev/null
+++ b/src/com/itmill/toolkit/demo/sampler/features/text/TextFieldInputPrompt.java
@@ -0,0 +1,47 @@
+package com.itmill.toolkit.demo.sampler.features.text;
+
+import com.itmill.toolkit.demo.sampler.APIResource;
+import com.itmill.toolkit.demo.sampler.Feature;
+import com.itmill.toolkit.demo.sampler.FeatureSet;
+import com.itmill.toolkit.demo.sampler.NamedExternalResource;
+import com.itmill.toolkit.demo.sampler.features.selects.ComboBoxInputPrompt;
+import com.itmill.toolkit.demo.sampler.features.selects.ComboBoxNewItems;
+import com.itmill.toolkit.ui.TextField;
+
+public class TextFieldInputPrompt extends Feature {
+ @Override
+ public String getName() {
+ return "Text field with input prompt";
+ }
+
+ @Override
+ public String getDescription() {
+ return " The TextField can have an <i>input prompt</i> - a textual hint that is shown within"
+ + " the field when the field is otherwise empty.<br/>"
+ + " You can use an input prompt instead of a caption to save"
+ + " space, but only do so if the function of the TextField is"
+ + " still clear when a value has been entered and the prompt is no"
+ + " longer visible.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(TextField.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ // TODO update CB -ref to 'suggest' pattern, when available
+ return new Class[] { TextFieldSingle.class, TextFieldSecret.class,
+ ComboBoxInputPrompt.class, ComboBoxNewItems.class,
+ FeatureSet.Texts.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return new NamedExternalResource[] { new NamedExternalResource(
+ "UI Patterns, Input Prompt",
+ "http://ui-patterns.com/pattern/InputPrompt") };
+ }
+
+}
diff --git a/src/com/itmill/toolkit/demo/sampler/features/text/TextFieldInputPromptExample.java b/src/com/itmill/toolkit/demo/sampler/features/text/TextFieldInputPromptExample.java
new file mode 100644
index 0000000000..19f995044a
--- /dev/null
+++ b/src/com/itmill/toolkit/demo/sampler/features/text/TextFieldInputPromptExample.java
@@ -0,0 +1,49 @@
+package com.itmill.toolkit.demo.sampler.features.text;
+
+import com.itmill.toolkit.data.Property;
+import com.itmill.toolkit.data.Property.ValueChangeEvent;
+import com.itmill.toolkit.ui.TextField;
+import com.itmill.toolkit.ui.VerticalLayout;
+
+public class TextFieldInputPromptExample extends VerticalLayout implements
+ Property.ValueChangeListener {
+
+ public TextFieldInputPromptExample() {
+ // add som 'air' to the layout
+ setSpacing(true);
+ setMargin(true);
+
+ // Username field + input prompt
+ TextField username = new TextField();
+ username.setInputPrompt("Username");
+ // configure & add to layout
+ username.setImmediate(true);
+ username.addListener(this);
+ addComponent(username);
+
+ // Password field + input prompt
+ TextField password = new TextField();
+ password.setInputPrompt("Password");
+ // configure & add to layout
+ password.setSecret(true);
+ password.setImmediate(true);
+ password.addListener(this);
+ addComponent(password);
+
+ // Comment field + input prompt
+ TextField comment = new TextField();
+ comment.setInputPrompt("Comment");
+ // configure & add to layout
+ comment.setRows(3);
+ comment.setImmediate(true);
+ comment.addListener(this);
+ addComponent(comment);
+
+ }
+
+ public void valueChange(ValueChangeEvent event) {
+ getWindow().showNotification("Received " + event.getProperty());
+
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConfiguration.java b/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConfiguration.java
index 69006a81e2..0560385799 100644
--- a/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConfiguration.java
+++ b/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConfiguration.java
@@ -21,6 +21,7 @@ public class ApplicationConfiguration {
private String communicationErrorCaption;
private String communicationErrorMessage;
private String communicationErrorUrl;
+ private boolean useDebugIdInDom = true;
private static ArrayList<ApplicationConnection> unstartedApplications = new ArrayList<ApplicationConnection>();
private static ArrayList<ApplicationConnection> runningApplications = new ArrayList<ApplicationConnection>();
@@ -85,6 +86,9 @@ public class ApplicationConfiguration {
if(jsobj.windowName) {
this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConfiguration::windowName = jsobj.windowName;
}
+ if('useDebugIdInDom' in jsobj && typeof(jsobj.useDebugIdInDom) == "boolean") {
+ this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConfiguration::useDebugIdInDom = jsobj.useDebugIdInDom;
+ }
if(jsobj.versionInfo) {
this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConfiguration::versionInfo = jsobj.versionInfo;
}
@@ -190,4 +194,8 @@ public class ApplicationConfiguration {
/*-{
return this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConfiguration::versionInfo.applicationVersion;
}-*/;
+
+ public boolean useDebugIdInDOM() {
+ return useDebugIdInDom;
+ }
}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java b/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java
index df0f9f5519..f3541b5bb3 100755
--- a/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java
+++ b/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java
@@ -31,7 +31,6 @@ import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.WindowCloseListener;
import com.google.gwt.user.client.impl.HTTPRequestImpl;
import com.google.gwt.user.client.ui.FocusWidget;
import com.google.gwt.user.client.ui.HasWidgets;
@@ -72,8 +71,6 @@ public class ApplicationConnection {
private static Console console;
- private static boolean testingMode;
-
private final Vector<String> pendingVariables = new Vector<String>();
private final ComponentDetailMap idToPaintableDetail = ComponentDetailMap
@@ -92,21 +89,6 @@ public class ApplicationConnection {
private boolean applicationRunning = false;
- /**
- * True if each Paintable objects id is injected to DOM. Used for Testing
- * Tools.
- */
- private boolean usePaintableIdsInDOM = false;
-
- /**
- * Contains reference for client wrapper given to Testing Tools.
- *
- * Used in JSNI functions
- *
- */
- @SuppressWarnings("unused")
- private final JavaScriptObject ttClientWrapper = null;
-
private int activeRequests = 0;
/** Parameters for this application connection loaded from the web-page */
@@ -137,26 +119,19 @@ public class ApplicationConnection {
this.widgetSet = widgetSet;
configuration = cnf;
windowName = configuration.getInitialWindowName();
-
if (isDebugMode()) {
console = new IDebugConsole(this, cnf, !isQuietDebugMode());
} else {
console = new NullConsole();
}
- if (checkTestingMode()) {
- usePaintableIdsInDOM = true;
- initializeTestingTools();
- Window.addWindowCloseListener(new WindowCloseListener() {
- public void onWindowClosed() {
- uninitializeTestingTools();
- }
+ ComponentLocator componentLocator = new ComponentLocator(this);
- public String onWindowClosing() {
- return null;
- }
- });
- }
+ String appRootPanelName = cnf.getRootPanelId();
+ // remove the end (window name) of autogenarated rootpanel id
+ appRootPanelName = appRootPanelName.replaceFirst("-\\d+$", "");
+
+ initializeTestingToolsHooks(componentLocator, appRootPanelName);
initializeClientHooks();
@@ -176,33 +151,8 @@ public class ApplicationConnection {
makeUidlRequest("", true, false, false);
}
- /**
- * Method to check if application is in testing mode. Can be used after
- * application init.
- *
- * @return true if in testing mode
- */
- public static boolean isTestingMode() {
- return testingMode;
- }
-
- /**
- * Check is application is run in testing mode.
- *
- * @return true if in testing mode
- */
- private native static boolean checkTestingMode()
- /*-{
- try {
- @com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::testingMode = $wnd.top.itmill && $wnd.top.itmill.registerToTT ? true : false;
- return @com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::testingMode;
- } catch(e) {
- // if run in iframe SOP may cause exception, return false then
- return false;
- }
- }-*/;
-
- private native void initializeTestingTools()
+ private native void initializeTestingToolsHooks(
+ ComponentLocator componentLocator, String TTAppId)
/*-{
var ap = this;
var client = {};
@@ -215,8 +165,19 @@ public class ApplicationConnection {
return vi;
}
}
- $wnd.top.itmill.registerToTT(client);
- this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::ttClientWrapper = client;
+
+ client.getElementByPath = function(id) {
+ return componentLocator.@com.itmill.toolkit.terminal.gwt.client.ComponentLocator::getElementByPath(Ljava/lang/String;)(id);
+ }
+ client.getPathForElement = function(element) {
+ return componentLocator.@com.itmill.toolkit.terminal.gwt.client.ComponentLocator::getPathForElement(Lcom/google/gwt/user/client/Element;)(element);
+ }
+
+ if(!$wnd.itmill.clients) {
+ $wnd.itmill.clients = {};
+ }
+
+ $wnd.itmill.clients[TTAppId] = client;
}-*/;
/**
@@ -227,11 +188,6 @@ public class ApplicationConnection {
return configuration.getVersionInfoJSObject();
}
- private native void uninitializeTestingTools()
- /*-{
- $wnd.top.itmill.unregisterFromTT(this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConnection::ttClientWrapper);
- }-*/;
-
/**
* Publishes a JavaScript API for mash-up applications.
* <ul>
@@ -804,15 +760,19 @@ public class ApplicationConnection {
el.tkPid = pid;
}-*/;
- private String getPid(Paintable paintable) {
+ public String getPid(Paintable paintable) {
return getPid(((Widget) paintable).getElement());
}
- private native String getPid(Element el)
+ public native String getPid(Element el)
/*-{
return el.tkPid;
}-*/;
+ public Element getElementByPid(String pid) {
+ return ((Widget) getPaintable(pid)).getElement();
+ }
+
public void unregisterPaintable(Paintable p) {
if (p == null) {
ApplicationConnection.getConsole().error(
@@ -1165,8 +1125,9 @@ public class ApplicationConnection {
}
}
- if (usePaintableIdsInDOM) {
- DOM.setElementProperty(component.getElement(), "id", uidl.getId());
+ if (configuration.useDebugIdInDOM() && uidl.getId().startsWith("PID_S")) {
+ DOM.setElementProperty(component.getElement(), "id", uidl.getId()
+ .substring(5));
}
/*
@@ -1499,10 +1460,8 @@ public class ApplicationConnection {
public IContextMenu getContextMenu() {
if (contextMenu == null) {
contextMenu = new IContextMenu();
- if (usePaintableIdsInDOM) {
- DOM.setElementProperty(contextMenu.getElement(), "id",
- "PID_TOOLKIT_CM");
- }
+ DOM.setElementProperty(contextMenu.getElement(), "id",
+ "PID_TOOLKIT_CM");
}
return contextMenu;
}
@@ -1660,4 +1619,9 @@ public class ApplicationConnection {
public void analyzeLayouts() {
makeUidlRequest("", true, false, true);
}
+
+ public IView getView() {
+ return view;
+ }
+
}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ComponentLocator.java b/src/com/itmill/toolkit/terminal/gwt/client/ComponentLocator.java
new file mode 100644
index 0000000000..b0078868dc
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/ComponentLocator.java
@@ -0,0 +1,278 @@
+package com.itmill.toolkit.terminal.gwt.client;
+
+import java.util.Iterator;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.HasWidgets;
+import com.google.gwt.user.client.ui.Widget;
+import com.itmill.toolkit.terminal.gwt.client.ui.IView;
+import com.itmill.toolkit.terminal.gwt.client.ui.SubPartAware;
+
+/**
+ * Helper class for TestingTools that builds appropriate locators for browser
+ * bot.
+ */
+public class ComponentLocator {
+
+ private static final String PARENTCHILD_SEPARATOR = "/";
+ private static final String SUBPART_SEPARATOR = "#";
+
+ private ApplicationConnection client;
+
+ public ComponentLocator(ApplicationConnection client) {
+ this.client = client;
+ }
+
+ public String getPathForElement(Element targetElement) {
+ String pid = null;
+
+ Element e = targetElement;
+
+ while (true) {
+ pid = client.getPid(e);
+ if (pid != null) {
+ break;
+ }
+
+ e = DOM.getParent(e);
+ if (e == null) {
+ break;
+ }
+ }
+
+ if (e == null || pid == null) {
+ return null;
+ }
+
+ Widget w = (Widget) client.getPaintable(pid);
+ if (w == null) {
+ return null;
+ }
+ // ApplicationConnection.getConsole().log(
+ // "First parent widget: " + Util.getSimpleName(w));
+
+ String path = getPathForWidget(w);
+ // ApplicationConnection.getConsole().log(
+ // "getPathFromWidget returned " + path);
+ if (w.getElement() == targetElement) {
+ // ApplicationConnection.getConsole().log(
+ // "Path for " + Util.getSimpleName(w) + ": " + path);
+
+ return path;
+ } else if (w instanceof SubPartAware) {
+ return path + SUBPART_SEPARATOR
+ + ((SubPartAware) w).getSubPartName(targetElement);
+ } else {
+ path = path + getDOMPathForElement(targetElement, w.getElement());
+ // ApplicationConnection.getConsole().log(
+ // "Path with dom addition for " + Util.getSimpleName(w)
+ // + ": " + path);
+
+ return path;
+ }
+ }
+
+ private Element getElementByDOMPath(Element baseElement, String path) {
+ String parts[] = path.split(PARENTCHILD_SEPARATOR);
+ Element element = baseElement;
+
+ for (String part : parts) {
+ if (part.startsWith("domChild[")) {
+ String childIndexString = part.substring("domChild[".length(),
+ part.length() - 1);
+ try {
+ int childIndex = Integer.parseInt(childIndexString);
+ element = DOM.getChild(element, childIndex);
+ } catch (Exception e) {
+ // ApplicationConnection.getConsole().error(
+ // "Failed to parse integer in " + childIndexString);
+ return null;
+ }
+ }
+ }
+
+ return element;
+ }
+
+ private String getDOMPathForElement(Element element, Element baseElement) {
+ Element e = element;
+ String path = "";
+ while (true) {
+ Element parent = DOM.getParent(e);
+ if (parent == null) {
+ return "ERROR, baseElement is not a parent to element";
+ }
+
+ int childIndex = -1;
+
+ int childCount = DOM.getChildCount(parent);
+ for (int i = 0; i < childCount; i++) {
+ if (e == DOM.getChild(parent, i)) {
+ childIndex = i;
+ break;
+ }
+ }
+ if (childIndex == -1) {
+ return "ERROR, baseElement is not a parent to element.";
+ }
+
+ path = PARENTCHILD_SEPARATOR + "domChild[" + childIndex + "]"
+ + path;
+
+ if (parent == baseElement) {
+ break;
+ }
+
+ e = parent;
+ }
+
+ return path;
+ }
+
+ public Element getElementByPath(String path) {
+ // ApplicationConnection.getConsole()
+ // .log("getElementByPath(" + path + ")");
+
+ // Path is of type "PID/componentPart"
+ String parts[] = path.split(SUBPART_SEPARATOR, 2);
+ String widgetPath = parts[0];
+ Widget w = getWidgetFromPath(widgetPath);
+ if (w == null) {
+ return null;
+ }
+
+ if (parts.length == 1) {
+ int pos = widgetPath.indexOf("domChild");
+ if (pos == -1) {
+ return w.getElement();
+ }
+
+ // Contains dom reference to a sub element of the widget
+ String subPath = widgetPath.substring(pos);
+ return getElementByDOMPath(w.getElement(), subPath);
+ } else if (parts.length == 2) {
+ if (w instanceof SubPartAware) {
+ // ApplicationConnection.getConsole().log(
+ // "subPartAware: " + parts[1]);
+ return ((SubPartAware) w).getSubPartElement(parts[1]);
+ } else {
+ // ApplicationConnection.getConsole().error(
+ // "getElementByPath failed because "
+ // + Util.getSimpleName(w)
+ // + " is not SubPartAware");
+ return null;
+ }
+ }
+
+ return null;
+ }
+
+ private String getPathForWidget(Widget w) {
+ String pid = client.getPid(w.getElement());
+ if (isStaticPid(pid)) {
+ return pid;
+ }
+
+ if (w instanceof IView) {
+ return "";
+ }
+
+ Widget parent = w.getParent();
+
+ String basePath = getPathForWidget(parent);
+
+ String simpleName = Util.getSimpleName(w);
+
+ Iterator i = ((HasWidgets) parent).iterator();
+ int pos = 0;
+ while (i.hasNext()) {
+ Object child = i.next();
+ if (child == w) {
+ return basePath + PARENTCHILD_SEPARATOR + simpleName + "["
+ + pos + "]";
+ }
+ String simpleName2 = Util.getSimpleName(child);
+ if (simpleName.equals(simpleName2)) {
+ pos++;
+ }
+ }
+
+ return "NOTFOUND";
+ }
+
+ private Widget getWidgetFromPath(String path) {
+ Widget w = null;
+ String parts[] = path.split(PARENTCHILD_SEPARATOR);
+
+ // ApplicationConnection.getConsole().log(
+ // "getWidgetFromPath(" + path + ")");
+
+ for (String part : parts) {
+ // ApplicationConnection.getConsole().log("Part: " + part);
+ // ApplicationConnection.getConsole().log(
+ // "Widget: " + Util.getSimpleName(w));
+ if (part.equals("")) {
+ w = client.getView();
+ } else if (w == null) {
+ w = (Widget) client.getPaintable(part);
+ } else if (part.startsWith("domChild[")) {
+ break;
+ } else if (w instanceof HasWidgets) {
+ HasWidgets parent = (HasWidgets) w;
+
+ String simpleName = Util.getSimpleName(parent);
+
+ Iterator i = parent.iterator();
+
+ boolean ok = false;
+ String[] split = part.split("\\[");
+ int pos = Integer.parseInt(split[1].substring(0, split[1]
+ .length() - 1));
+ // ApplicationConnection.getConsole().log(
+ // "Looking for child " + pos);
+ while (i.hasNext()) {
+ // ApplicationConnection.getConsole().log("- child found");
+
+ Widget child = (Widget) i.next();
+ String simpleName2 = Util.getSimpleName(child);
+
+ if (split[0].equals(simpleName2)) {
+ if (pos == 0) {
+ w = child;
+ ok = true;
+ break;
+ }
+ pos--;
+ }
+ }
+
+ if (!ok) {
+ // Did not find the child
+ // ApplicationConnection.getConsole().error(
+ // "getWidgetFromPath(" + path + ") - did not find '"
+ // + part + "' for "
+ // + Util.getSimpleName(parent));
+
+ return null;
+ }
+ } else {
+ // ApplicationConnection.getConsole().error(
+ // "getWidgetFromPath(" + path + ") - failed for '" + part
+ // + "'");
+ return null;
+ }
+ }
+
+ return w;
+ }
+
+ private boolean isStaticPid(String pid) {
+ if (pid == null) {
+ return false;
+ }
+
+ return pid.startsWith("PID_S");
+ }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IFilterSelect.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IFilterSelect.java
index e76374cfc2..176f596ce3 100644
--- a/src/com/itmill/toolkit/terminal/gwt/client/ui/IFilterSelect.java
+++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IFilterSelect.java
@@ -131,11 +131,9 @@ public class IFilterSelect extends Composite implements Paintable, Field,
Collection<FilterSelectSuggestion> currentSuggestions,
int currentPage, int totalSuggestions) {
- if (ApplicationConnection.isTestingMode()) {
- // Add TT anchor point
- DOM.setElementProperty(getElement(), "id", paintableId
- + "_OPTIONLIST");
- }
+ // Add TT anchor point
+ DOM.setElementProperty(getElement(), "id",
+ "TOOLKIT_COMBOBOX_OPTIONLIST");
menu.setSuggestions(currentSuggestions);
final int x = IFilterSelect.this.getAbsoluteLeft();
@@ -454,8 +452,7 @@ public class IFilterSelect extends Composite implements Paintable, Field,
}
if (allowNewItem) {
- if (!enteredItemValue.equals(emptyText)
- && !enteredItemValue.equals(lastNewItemString)) {
+ if (!prompting && !enteredItemValue.equals(lastNewItemString)) {
/*
* Store last sent new item string to avoid double sends
*/
@@ -471,13 +468,18 @@ public class IFilterSelect extends Composite implements Paintable, Field,
} else {
if (currentSuggestion != null) {
String text = currentSuggestion.getReplacementString();
- tb.setText((text.equals("") ? emptyText : text));
- // TODO add/remove class CLASSNAME_EMPTY
+ /* TODO?
+ if (text.equals("")) {
+ addStyleDependentName(CLASSNAME_PROMPT);
+ tb.setText(inputPrompt);
+ prompting = true;
+ } else {
+ tb.setText(text);
+ prompting = false;
+ removeStyleDependentName(CLASSNAME_PROMPT);
+ }
+ */
selectedOptionKey = currentSuggestion.key;
- } else {
- tb.setText(emptyText);
- // TODO add class CLASSNAME_EMPTY
- selectedOptionKey = null;
}
}
suggestionPopup.hide();
@@ -548,7 +550,11 @@ public class IFilterSelect extends Composite implements Paintable, Field,
private boolean enabled;
// shown in unfocused empty field, disappears on focus (e.g "Search here")
- private String emptyText = "";
+ private static final String CLASSNAME_PROMPT = "prompt";
+ private static final String ATTR_INPUTPROMPT = "prompt";
+ private String inputPrompt = "";
+ private boolean prompting = false;
+
// Set true when popupopened has been clicked. Cleared on each UIDL-update.
// This handles the special case where are not filtering yet and the
// selected value has changed on the server-side. See #2119
@@ -557,13 +563,12 @@ public class IFilterSelect extends Composite implements Paintable, Field,
private int textboxPadding = -1;
private int componentPadding = -1;
private int suggestionPopupMinWidth = 0;
- // private static final String CLASSNAME_EMPTY = "empty";
- private static final String ATTR_EMPTYTEXT = "emptytext";
/*
* Stores the last new item string to avoid double submissions. Cleared on
* uidl updates
*/
private String lastNewItemString;
+ private boolean focused = false;
public IFilterSelect() {
selectedItemIcon.setVisible(false);
@@ -658,9 +663,11 @@ public class IFilterSelect extends Composite implements Paintable, Field,
currentPage = uidl.getIntVariable("page");
- if (uidl.hasAttribute(ATTR_EMPTYTEXT)) {
- // "emptytext" changed from server
- emptyText = uidl.getStringAttribute(ATTR_EMPTYTEXT);
+ if (uidl.hasAttribute(ATTR_INPUTPROMPT)) {
+ // input prompt changed from server
+ inputPrompt = uidl.getStringAttribute(ATTR_INPUTPROMPT);
+ } else {
+ inputPrompt = "";
}
suggestionPopup.setPagingEnabled(true);
@@ -673,7 +680,7 @@ public class IFilterSelect extends Composite implements Paintable, Field,
final UIDL options = uidl.getChildUIDL(0);
totalMatches = uidl.getIntAttribute("totalMatches");
- String captions = emptyText;
+ String captions = inputPrompt;
for (final Iterator i = options.getChildIterator(); i.hasNext();) {
final UIDL optionUidl = (UIDL) i.next();
@@ -699,9 +706,10 @@ public class IFilterSelect extends Composite implements Paintable, Field,
if ((!filtering || popupOpenerClicked) && uidl.hasVariable("selected")
&& uidl.getStringArrayVariable("selected").length == 0) {
// select nulled
- tb.setText(emptyText);
+ if (!filtering || !popupOpenerClicked) {
+ setPromptingOn();
+ }
selectedOptionKey = null;
- // TODO add class CLASSNAME_EMPTY
}
if (filtering
@@ -743,6 +751,18 @@ public class IFilterSelect extends Composite implements Paintable, Field,
updateRootWidth();
}
+ private void setPromptingOn() {
+ prompting = true;
+ addStyleDependentName(CLASSNAME_PROMPT);
+ tb.setText(inputPrompt);
+ }
+
+ private void setPromptingOff(String text) {
+ tb.setText(text);
+ prompting = false;
+ removeStyleDependentName(CLASSNAME_PROMPT);
+ }
+
public void onSuggestionSelected(FilterSelectSuggestion suggestion) {
currentSuggestion = suggestion;
String newKey;
@@ -753,9 +773,13 @@ public class IFilterSelect extends Composite implements Paintable, Field,
// normal selection
newKey = String.valueOf(suggestion.getOptionKey());
}
+
String text = suggestion.getReplacementString();
- tb.setText(text.equals("") ? emptyText : text);
- // TODO add/remove class CLASSNAME_EMPTY
+ if ("".equals(newKey) && !focused) {
+ setPromptingOn();
+ } else {
+ setPromptingOff(text);
+ }
setSelectedItemIcon(suggestion.getIconUri());
if (!newKey.equals(selectedOptionKey)) {
selectedOptionKey = newKey;
@@ -846,12 +870,10 @@ public class IFilterSelect extends Composite implements Paintable, Field,
case KeyboardListener.KEY_ESCAPE:
if (currentSuggestion != null) {
String text = currentSuggestion.getReplacementString();
- tb.setText((text.equals("") ? emptyText : text));
- // TODO add/remove class CLASSNAME_EMPTY
+ setPromptingOff(text);
selectedOptionKey = currentSuggestion.key;
} else {
- tb.setText(emptyText);
- // TODO add class CLASSNAME_EMPTY
+ setPromptingOn();
selectedOptionKey = null;
}
lastFilter = "";
@@ -870,12 +892,14 @@ public class IFilterSelect extends Composite implements Paintable, Field,
public void onClick(Widget sender) {
if (enabled) {
// ask suggestionPopup if it was just closed, we are using GWT
- // Popup's
- // auto close feature
+ // Popup's auto close feature
if (!suggestionPopup.isJustClosed()) {
filterOptions(-1, "");
popupOpenerClicked = true;
lastFilter = "";
+ } else if (selectedOptionKey == null) {
+ tb.setText(inputPrompt);
+ prompting = true;
}
DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
tb.setFocus(true);
@@ -890,13 +914,13 @@ public class IFilterSelect extends Composite implements Paintable, Field,
private native int minWidth(String captions)
/*-{
if(!captions || captions.length <= 0)
- return 0;
+ return 0;
captions = captions.split("|");
var d = $wnd.document.createElement("div");
var html = "";
for(var i=0; i < captions.length; i++) {
- html += "<div>" + captions[i] + "</div>";
- // TODO apply same CSS classname as in suggestionmenu
+ html += "<div>" + captions[i] + "</div>";
+ // TODO apply same CSS classname as in suggestionmenu
}
d.style.position = "absolute";
d.style.top = "0";
@@ -910,26 +934,30 @@ public class IFilterSelect extends Composite implements Paintable, Field,
}-*/;
public void onFocus(Widget sender) {
- if (emptyText.equals(tb.getText())) {
- tb.setText("");
- // TODO remove class CLASSNAME_EMPTY
+ focused = true;
+ if (prompting) {
+ setPromptingOff("");
}
addStyleDependentName("focus");
}
public void onLostFocus(Widget sender) {
+ focused = false;
if (!suggestionPopup.isAttached() || suggestionPopup.isJustClosed()) {
// typing so fast the popup was never opened, or it's just closed
suggestionPopup.menu.doSelectedItemAction();
}
- if ("".equals(tb.getText())) {
- tb.setText(emptyText);
- // TODO add CLASSNAME_EMPTY
+ if (selectedOptionKey == null) {
+ setPromptingOn();
}
removeStyleDependentName("focus");
}
public void focus() {
+ focused = true;
+ if (prompting) {
+ setPromptingOff("");
+ }
tb.setFocus(true);
}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IForm.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IForm.java
index 1550d85446..0b91268d25 100644
--- a/src/com/itmill/toolkit/terminal/gwt/client/ui/IForm.java
+++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IForm.java
@@ -52,6 +52,8 @@ public class IForm extends ComplexPanel implements Container {
private int borderPaddingVertical;
+ private boolean rendering = false;
+
public IForm() {
setElement(DOM.createDiv());
DOM.appendChild(getElement(), fieldSet);
@@ -72,6 +74,8 @@ public class IForm extends ComplexPanel implements Container {
}
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ rendering = true;
+
if (this.client == null) {
this.client = client;
borderPaddingVertical = getOffsetHeight();
@@ -79,6 +83,7 @@ public class IForm extends ComplexPanel implements Container {
}
if (client.updateComponent(this, uidl, false)) {
+ rendering = false;
return;
}
@@ -159,6 +164,8 @@ public class IForm extends ComplexPanel implements Container {
client.unregisterPaintable(footer);
}
}
+
+ rendering = false;
}
public void updateSize() {
@@ -266,7 +273,7 @@ public class IForm extends ComplexPanel implements Container {
updateSize();
- if (height.equals("")) {
+ if (!rendering && height.equals("")) {
// Width might affect height
Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this);
}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/INativeSelect.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/INativeSelect.java
index 536ed15de6..5c7c3b9f1f 100644
--- a/src/com/itmill/toolkit/terminal/gwt/client/ui/INativeSelect.java
+++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/INativeSelect.java
@@ -8,7 +8,9 @@ import java.util.Iterator;
import java.util.Vector;
import com.google.gwt.user.client.ui.Widget;
+import com.itmill.toolkit.terminal.gwt.client.BrowserInfo;
import com.itmill.toolkit.terminal.gwt.client.UIDL;
+import com.itmill.toolkit.terminal.gwt.client.Util;
public class INativeSelect extends IOptionGroupBase implements Field {
@@ -51,7 +53,11 @@ public class INativeSelect extends IOptionGroupBase implements Field {
select.insertItem("", null, 0);
select.setItemSelected(0, true);
}
-
+ if (BrowserInfo.get().isIE6()) {
+ // lazy size change - IE6 uses naive dropdown that does not have a
+ // proper size yet
+ Util.notifyParentOfSizeChange(this, true);
+ }
}
@Override
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IScrollTable.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IScrollTable.java
index 7470662828..f7a925ad00 100644
--- a/src/com/itmill/toolkit/terminal/gwt/client/ui/IScrollTable.java
+++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IScrollTable.java
@@ -140,6 +140,7 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
private final ArrayList lazyUnregistryBag = new ArrayList();
private String height;
private String width = "";
+ private boolean rendering = false;
public IScrollTable() {
bodyContainer.addScrollListener(this);
@@ -154,7 +155,9 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
}
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ rendering = true;
if (client.updateComponent(this, uidl, true)) {
+ rendering = false;
return;
}
@@ -274,6 +277,7 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
}
hideScrollPositionAnnotation();
purgeUnregistryBag();
+ rendering = false;
}
/**
@@ -417,9 +421,9 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
return tHead.getHeaderCell(index).getColKey();
}
- private void setColWidth(int colIndex, int w) {
+ private void setColWidth(int colIndex, int w, boolean isDefinedWidth) {
final HeaderCell cell = tHead.getHeaderCell(colIndex);
- cell.setWidth(w);
+ cell.setWidth(w, isDefinedWidth);
tBody.setColWidth(colIndex, w);
}
@@ -537,6 +541,7 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
int i = 0;
int totalExplicitColumnsWidths = 0;
int total = 0;
+ float expandRatioDivider = 0;
final int[] widths = new int[tHead.visibleCells.size()];
@@ -549,9 +554,19 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
// server has defined column width explicitly
totalExplicitColumnsWidths += w;
} else {
- final int hw = hCell.getOffsetWidth();
- final int cw = tBody.getColWidth(i);
- w = (hw > cw ? hw : cw) + IScrollTableBody.CELL_EXTRA_WIDTH;
+ if (hCell.getExpandRatio() > 0) {
+ expandRatioDivider += hCell.getExpandRatio();
+ w = IScrollTableBody.CELL_EXTRA_WIDTH
+ + IScrollTableBody.CELL_CONTENT_PADDING;
+ } else {
+ // get and store greater of header width and column width,
+ // and
+ // store it as a minimumn natural col width
+ final int hw = hCell.getOffsetWidth();
+ final int cw = tBody.getColWidth(i);
+ w = (hw > cw ? hw : cw) + IScrollTableBody.CELL_EXTRA_WIDTH;
+ }
+ hCell.setNaturalMinimumColumnWidth(w);
}
widths[i] = w;
total += w;
@@ -571,10 +586,13 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
// Hey IE, are you really sure about this?
availW = tBody.getAvailableWidth();
+ // FIXME this may fail if pagelenth does not correlate well with actual
+ // height (via setHeight())
boolean verticalScrollbarVisible = (pageLength < totalRows);
if (verticalScrollbarVisible) {
- // There will be a vertical scrollbar and its width is not included in availW
+ // There will be a vertical scrollbar and its width is not included
+ // in availW
availW -= Util.getNativeScrollbarSize();
}
@@ -586,7 +604,6 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
int totalWidthR = total - totalExplicitColumnsWidths;
if (totalWidthR > 0) {
needsReLayout = true;
-
/*
* If the table has a relative width and there is enough space
* for a scrollbar we reserve this in the last column
@@ -602,27 +619,47 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
HeaderCell headerCell = tHead.getHeaderCell(columnindex);
if (headerCell.getWidth() == -1) {
totalWidthR += scrollbarWidthReserved;
+ headerCell.setNaturalMinimumColumnWidth(headerCell
+ .getNaturalColumnWidth()
+ + scrollbarWidthReserved);
}
extraSpace -= scrollbarWidthReserved;
scrollbarWidthReservedInColumn = columnindex;
}
-
- // now we will share this sum relatively to those without
- // explicit width
- headCells = tHead.iterator();
- i = 0;
- HeaderCell hCell;
- while (headCells.hasNext()) {
- hCell = (HeaderCell) headCells.next();
- if (hCell.getWidth() == -1) {
- int w = widths[i];
- final int newSpace = extraSpace * w / totalWidthR;
- w += newSpace;
- widths[i] = w;
+ if (expandRatioDivider > 0) {
+ // visible columns have some active expand ratios, excess
+ // space is divided according to them
+ headCells = tHead.iterator();
+ i = 0;
+ while (headCells.hasNext()) {
+ HeaderCell hCell = (HeaderCell) headCells.next();
+ if (hCell.getExpandRatio() > 0) {
+ int w = widths[i];
+ final int newSpace = (int) (extraSpace * (hCell
+ .getExpandRatio() / expandRatioDivider));
+ w += newSpace;
+ widths[i] = w;
+ }
+ i++;
+ }
+ } else {
+ // now we will share this sum relatively to those without
+ // explicit width
+ headCells = tHead.iterator();
+ i = 0;
+ while (headCells.hasNext()) {
+ HeaderCell hCell = (HeaderCell) headCells.next();
+ if (hCell.getWidth() == -1) {
+ int w = widths[i];
+ final int newSpace = extraSpace * w / totalWidthR;
+ w += newSpace;
+ widths[i] = w;
+ }
+ i++;
}
- i++;
}
}
+
} else {
// bodys size will be more than available and scrollbar will appear
}
@@ -634,7 +671,7 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
final HeaderCell hCell = (HeaderCell) headCells.next();
if (isNewBody || hCell.getWidth() == -1) {
final int w = widths[i];
- setColWidth(i, w);
+ setColWidth(i, w, false);
}
i++;
}
@@ -651,8 +688,17 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
* We must force an update of the row height as this point as it
* might have been (incorrectly) calculated earlier
*/
- int bodyHeight = (tBody.getRowHeight(true) * pageLength);
- bodyContainer.setHeight(bodyHeight + "px");
+ if (pageLength == totalRows) {
+ /*
+ * We want to show all rows so the bodyHeight should be equal to
+ * the table height
+ */
+ int bodyHeight = tBody.getTableHeight();
+ bodyContainer.setHeight(bodyHeight + "px");
+ } else {
+ int bodyHeight = (tBody.getRowHeight(true) * pageLength);
+ bodyContainer.setHeight(bodyHeight + "px");
+ }
}
isNewBody = false;
@@ -972,12 +1018,22 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
private int width = -1;
+ private int naturalWidth = 0;
+
private char align = ALIGN_LEFT;
+ boolean definedWidth = false;
+
+ private float expandRatio = 0;
+
public void setSortable(boolean b) {
sortable = b;
}
+ public void setNaturalMinimumColumnWidth(int w) {
+ naturalWidth = w;
+ }
+
public HeaderCell(String colId, String headerText) {
cid = colId;
@@ -1006,7 +1062,15 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
setElement(td);
}
- public void setWidth(int w) {
+ public void setWidth(int w, boolean ensureDefinedWidth) {
+ if (ensureDefinedWidth) {
+ definedWidth = true;
+ // on column resize expand ratio becomes zero
+ expandRatio = 0;
+ }
+ if (width == w) {
+ return;
+ }
if (width == -1) {
// go to default mode, clip content if necessary
DOM.setStyleAttribute(captionContainer, "overflow", "");
@@ -1023,6 +1087,21 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
}
}
+ public void setUndefinedWidth() {
+ definedWidth = false;
+ setWidth(-1, false);
+ }
+
+ /**
+ * Detects if width is fixed by developer on server side or resized to
+ * current width by user.
+ *
+ * @return true if defined, false if "natural" width
+ */
+ public boolean isDefinedWidth() {
+ return definedWidth;
+ }
+
public int getWidth() {
return width;
}
@@ -1207,7 +1286,9 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
case Event.ONMOUSEUP:
isResizing = false;
DOM.releaseCapture(getElement());
- tBody.reLayoutComponents();
+ // readjust undefined width columns
+ lazyAdjustColumnWidths.cancel();
+ lazyAdjustColumnWidths.schedule(1);
break;
case Event.ONMOUSEMOVE:
if (isResizing) {
@@ -1220,7 +1301,7 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
if (newWidth < MINIMUM_COL_WIDTH) {
newWidth = MINIMUM_COL_WIDTH;
}
- setColWidth(colIndex, newWidth);
+ setColWidth(colIndex, newWidth, true);
}
break;
default:
@@ -1259,6 +1340,29 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
return align;
}
+ /**
+ * Detects the natural minimum width for the column of this header cell.
+ * If column is resized by user or the width is defined by server the
+ * actual width is returned. Else the natural min width is returned.
+ *
+ * @return
+ */
+ public int getNaturalColumnWidth() {
+ if (isDefinedWidth()) {
+ return width;
+ } else {
+ return naturalWidth;
+ }
+ }
+
+ public void setExpandRatio(float floatAttribute) {
+ expandRatio = floatAttribute;
+ }
+
+ public float getExpandRatio() {
+ return expandRatio;
+ }
+
}
/**
@@ -1369,9 +1473,12 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
}
if (col.hasAttribute("width")) {
final String width = col.getStringAttribute("width");
- c.setWidth(Integer.parseInt(width));
+ c.setWidth(Integer.parseInt(width), true);
} else if (recalcWidths) {
- c.setWidth(-1);
+ c.setUndefinedWidth();
+ }
+ if (col.hasAttribute("er")) {
+ c.setExpandRatio(col.getFloatAttribute("er"));
}
}
// check for orphaned header cells
@@ -1935,8 +2042,7 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
return rowHeight;
} else {
if (DOM.getChildCount(tBody) > 0) {
- rowHeight = tBody.getParentElement().getOffsetHeight()
- / DOM.getChildCount(tBody);
+ rowHeight = getTableHeight() / DOM.getChildCount(tBody);
} else {
return DEFAULT_ROW_HEIGHT;
}
@@ -1945,6 +2051,10 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
}
}
+ public int getTableHeight() {
+ return table.getOffsetHeight();
+ }
+
public int getColWidth(int i) {
if (initDone) {
final Element e = DOM.getChild(DOM.getChild(tBody, 0), i);
@@ -2210,28 +2320,31 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
*/
@Override
public void onBrowserEvent(Event event) {
- Element targetTdOrTr = getEventTargetTdOrTr(event);
- if (targetTdOrTr != null) {
- switch (DOM.eventGetType(event)) {
- case Event.ONCLICK:
- handleClickEvent(event, targetTdOrTr);
- if (selectMode > Table.SELECT_MODE_NONE) {
- toggleSelection();
- // Note: changing the immediateness of this might
- // require changes to "clickEvent" immediateness
- // also.
- client.updateVariable(paintableId, "selected",
- selectedRowKeys.toArray(), immediate);
+ if (enabled) {
+ Element targetTdOrTr = getEventTargetTdOrTr(event);
+ if (targetTdOrTr != null) {
+ switch (DOM.eventGetType(event)) {
+ case Event.ONCLICK:
+ handleClickEvent(event, targetTdOrTr);
+ if (selectMode > Table.SELECT_MODE_NONE) {
+ toggleSelection();
+ // Note: changing the immediateness of this
+ // might
+ // require changes to "clickEvent" immediateness
+ // also.
+ client.updateVariable(paintableId, "selected",
+ selectedRowKeys.toArray(), immediate);
+ }
+ break;
+ case Event.ONDBLCLICK:
+ handleClickEvent(event, targetTdOrTr);
+ break;
+ case Event.ONCONTEXTMENU:
+ showContextMenu(event);
+ break;
+ default:
+ break;
}
- break;
- case Event.ONDBLCLICK:
- handleClickEvent(event, targetTdOrTr);
- break;
- case Event.ONCONTEXTMENU:
- showContextMenu(event);
- break;
- default:
- break;
}
}
super.onBrowserEvent(event);
@@ -2449,7 +2562,7 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
int col = scrollbarWidthReservedInColumn;
String colKey = getColKeyByIndex(col);
setColWidth(scrollbarWidthReservedInColumn, getColWidth(colKey)
- - (oldWidth - newWidth));
+ - (oldWidth - newWidth), false);
scrollbarWidthReservedInColumn = -1;
}
@@ -2458,11 +2571,83 @@ public class IScrollTable extends FlowPanel implements Table, ScrollListener {
innerPixels = 0;
}
setContentWidth(innerPixels);
+
+ if (!rendering) {
+ // readjust undefined width columns
+ lazyAdjustColumnWidths.cancel();
+ lazyAdjustColumnWidths.schedule(LAZY_COLUMN_ADJUST_TIMEOUT);
+ }
+
} else {
super.setWidth("");
}
+
}
+ private static final int LAZY_COLUMN_ADJUST_TIMEOUT = 300;
+
+ private final Timer lazyAdjustColumnWidths = new Timer() {
+ /**
+ * Check for column widths, and available width, to see if we can fix
+ * column widths "optimally". Doing this lazily to avoid expensive
+ * calculation when resizing is not yet finished.
+ */
+ @Override
+ public void run() {
+
+ Iterator<Widget> headCells = tHead.iterator();
+ int usedMinimumWidth = 0;
+ int totalExplicitColumnsWidths = 0;
+ float expandRatioDivider = 0;
+ while (headCells.hasNext()) {
+ final HeaderCell hCell = (HeaderCell) headCells.next();
+ usedMinimumWidth += hCell.getNaturalColumnWidth();
+ if (hCell.isDefinedWidth()) {
+ totalExplicitColumnsWidths += hCell.getWidth();
+ } else {
+ expandRatioDivider += hCell.getExpandRatio();
+ }
+ }
+
+ int availW = tBody.getAvailableWidth();
+ // Hey IE, are you really sure about this?
+ availW = tBody.getAvailableWidth();
+
+ int extraSpace = availW - usedMinimumWidth;
+ if (extraSpace < 0) {
+ extraSpace = 0;
+ }
+ int totalWidthR = usedMinimumWidth - totalExplicitColumnsWidths;
+ if (totalWidthR < 0) {
+ totalWidthR = 0;
+ }
+
+ // we have some space that can be divided optimally
+ HeaderCell hCell;
+ int i = 0;
+ headCells = tHead.iterator();
+ while (headCells.hasNext()) {
+ hCell = (HeaderCell) headCells.next();
+ if (!hCell.isDefinedWidth()) {
+ int w = hCell.getNaturalColumnWidth();
+ int newSpace;
+ if (expandRatioDivider > 0) {
+ // divide excess space by expand ratios
+ newSpace = (int) (w + extraSpace
+ * hCell.getExpandRatio() / expandRatioDivider);
+ } else {
+ // divide relatively to natural column widths
+ newSpace = w + extraSpace * w / totalWidthR;
+ }
+ setColWidth(i, newSpace, false);
+ }
+ i++;
+ }
+ Util.runWebkitOverflowAutoFix(bodyContainer.getElement());
+ tBody.reLayoutComponents();
+ }
+ };
+
/**
* helper to set pixel size of head and body part
*
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/ITextField.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/ITextField.java
index 0e342428e8..e21a5fe5b3 100644
--- a/src/com/itmill/toolkit/terminal/gwt/client/ui/ITextField.java
+++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/ITextField.java
@@ -47,6 +47,11 @@ public class ITextField extends TextBoxBase implements Paintable, Field,
private int extraVerticalPixels = -1;
private int maxLength = -1;
+ private static final String CLASSNAME_PROMPT = "prompt";
+ private static final String ATTR_INPUTPROMPT = "prompt";
+ private String inputPrompt = null;
+ private boolean prompting = false;
+
public ITextField() {
this(DOM.createInputText());
}
@@ -86,6 +91,8 @@ public class ITextField extends TextBoxBase implements Paintable, Field,
setReadOnly(false);
}
+ inputPrompt = uidl.getStringAttribute(ATTR_INPUTPROMPT);
+
setMaxLength(uidl.hasAttribute("maxLength") ? uidl
.getIntAttribute("maxLength") : -1);
@@ -95,7 +102,15 @@ public class ITextField extends TextBoxBase implements Paintable, Field,
setColumns(new Integer(uidl.getStringAttribute("cols")).intValue());
}
- setText(uidl.getStringVariable("text"));
+ String text = uidl.getStringVariable("text");
+ prompting = inputPrompt != null && (text == null || text.equals(""));
+ if (prompting) {
+ setText(inputPrompt);
+ addStyleDependentName(CLASSNAME_PROMPT);
+ } else {
+ setText(text);
+ removeStyleDependentName(CLASSNAME_PROMPT);
+ }
valueBeforeEdit = uidl.getStringVariable("text");
}
@@ -103,13 +118,13 @@ public class ITextField extends TextBoxBase implements Paintable, Field,
if (newMaxLength > 0) {
maxLength = newMaxLength;
if (getElement().getTagName().toLowerCase().equals("textarea")) {
- // NOP no maxlenght property for textarea
+ // NOP no maxlength property for textarea
} else {
getElement().setPropertyInt("maxLength", maxLength);
}
} else if (maxLength != -1) {
if (getElement().getTagName().toLowerCase().equals("textarea")) {
- // NOP no maxlenght property for textarea
+ // NOP no maxlength property for textarea
} else {
getElement().setAttribute("maxlength", "");
}
@@ -125,7 +140,8 @@ public class ITextField extends TextBoxBase implements Paintable, Field,
public void onChange(Widget sender) {
if (client != null && id != null) {
String newText = getText();
- if (newText != null && !newText.equals(valueBeforeEdit)) {
+ if (!prompting && newText != null
+ && !newText.equals(valueBeforeEdit)) {
client.updateVariable(id, "text", getText(), immediate);
valueBeforeEdit = newText;
}
@@ -142,12 +158,22 @@ public class ITextField extends TextBoxBase implements Paintable, Field,
public void onFocus(Widget sender) {
addStyleDependentName(CLASSNAME_FOCUS);
+ if (prompting) {
+ setText("");
+ removeStyleDependentName(CLASSNAME_PROMPT);
+ }
focusedTextField = this;
}
public void onLostFocus(Widget sender) {
removeStyleDependentName(CLASSNAME_FOCUS);
focusedTextField = null;
+ String text = getText();
+ prompting = inputPrompt != null && (text == null || "".equals(text));
+ if (prompting) {
+ setText(inputPrompt);
+ addStyleDependentName(CLASSNAME_PROMPT);
+ }
onChange(sender);
}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/ITextualDate.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/ITextualDate.java
index e68342dcf6..dcd411c129 100644
--- a/src/com/itmill/toolkit/terminal/gwt/client/ui/ITextualDate.java
+++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/ITextualDate.java
@@ -155,6 +155,7 @@ public class ITextualDate extends IDateField implements Paintable, Field,
ClientExceptionHandler.displayError(e.getMessage());
addStyleName(PARSE_ERROR_CLASSNAME);
+ // this is a hack that may eventually be removed
client.updateVariable(id, "lastInvalidDateString", text
.getText(), false);
date = null;
@@ -164,6 +165,8 @@ public class ITextualDate extends IDateField implements Paintable, Field,
// remove possibly added invalid value indication
removeStyleName(PARSE_ERROR_CLASSNAME);
}
+ // always send the date string
+ client.updateVariable(id, "dateString", text.getText(), false);
if (date != null) {
showingDate = new Date(date.getTime());
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/ITree.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/ITree.java
index dd11136aa4..678f08a886 100644
--- a/src/com/itmill/toolkit/terminal/gwt/client/ui/ITree.java
+++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/ITree.java
@@ -142,6 +142,11 @@ public class ITree extends FlowPanel implements Paintable {
rootNode.renderChildNodes(uidl.getChildIterator());
}
+ if (uidl.hasVariable("selected")) {
+ // update selection in case selected nodes were not visible
+ selectedIds = uidl.getStringArrayVariableAsSet("selected");
+ }
+
}
public void setSelected(TreeNode treeNode, boolean selected) {
@@ -152,7 +157,7 @@ public class ITree extends FlowPanel implements Paintable {
final TreeNode oldSelection = keyToNode.get(id);
if (oldSelection != null) {
// can be null if the node is not visible (parent
- // expanded)
+ // collapsed)
oldSelection.setSelected(false);
}
selectedIds.remove(id);
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IView.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IView.java
index 5d4e8c86d9..0c22da4a1e 100644
--- a/src/com/itmill/toolkit/terminal/gwt/client/ui/IView.java
+++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IView.java
@@ -8,6 +8,8 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
+import com.google.gwt.dom.client.DivElement;
+import com.google.gwt.dom.client.Document;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
@@ -72,6 +74,8 @@ public class IView extends SimplePanel implements Container,
private boolean scrollable;
+ private boolean immediate;
+
public IView(String elementId) {
super();
setStyleName(CLASSNAME);
@@ -138,6 +142,8 @@ public class IView extends SimplePanel implements Container,
boolean firstPaint = connection == null;
connection = client;
+ immediate = uidl.hasAttribute("immediate");
+
String newTheme = uidl.getStringAttribute("theme");
if (theme != null && !newTheme.equals(theme)) {
// Complete page refresh is needed due css can affect layout
@@ -396,6 +402,8 @@ public class IView extends SimplePanel implements Container,
.log(
"Running layout functions due window resize");
connection.runDescendentsLayout(IView.this);
+
+ sendClientResized();
}
}
};
@@ -419,10 +427,19 @@ public class IView extends SimplePanel implements Container,
connection.runDescendentsLayout(this);
Util.runWebkitOverflowAutoFix(getElement());
+ sendClientResized();
}
}
+ /**
+ * Send new dimensions to the server.
+ */
+ private void sendClientResized() {
+ connection.updateVariable(id, "height", height, false);
+ connection.updateVariable(id, "width", width, immediate);
+ }
+
public native static void goTo(String url)
/*-{
$wnd.location = url;
@@ -459,13 +476,31 @@ public class IView extends SimplePanel implements Container,
}
private void detectExcessSize() {
+ // TODO define that iview cannot be themed and decorations should
+ // get to parent element, then get rid of this expensive and error
+ // prone function
final String overflow = getElement().getStyle().getProperty(
"overflow");
getElement().getStyle().setProperty("overflow", "hidden");
+ if (BrowserInfo.get().isIE()
+ && getElement().getPropertyInt("clientWidth") == 0) {
+ // can't detect possibly themed border/padding width in some
+ // situations (with some layout configurations), use empty div
+ // to measure width properly
+ DivElement div = Document.get().createDivElement();
+ div.setInnerHTML("&nbsp;");
+ div.getStyle().setProperty("overflow", "hidden");
+ div.getStyle().setProperty("height", "1px");
+ getElement().appendChild(div);
+ excessWidth = getElement().getOffsetWidth()
+ - div.getOffsetWidth();
+ getElement().removeChild(div);
+ } else {
+ excessWidth = getElement().getOffsetWidth()
+ - getElement().getPropertyInt("clientWidth");
+ }
excessHeight = getElement().getOffsetHeight()
- getElement().getPropertyInt("clientHeight");
- excessWidth = getElement().getOffsetWidth()
- - getElement().getPropertyInt("clientWidth");
getElement().getStyle().setProperty("overflow", overflow);
}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IWindow.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IWindow.java
index 915f4b521e..e329d410c0 100644
--- a/src/com/itmill/toolkit/terminal/gwt/client/ui/IWindow.java
+++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IWindow.java
@@ -115,6 +115,16 @@ public class IWindow extends IToolkitOverlay implements Container,
private boolean readonly;
+ boolean dynamicWidth = false;
+ boolean dynamicHeight = false;
+ boolean layoutRelativeWidth = false;
+ boolean layoutRelativeHeight = false;
+
+ // If centered (via UIDL), the window should stay in the centered -mode
+ // until a position is received from the server, or the user moves or
+ // resizes the window.
+ boolean centered = false;
+
private RenderSpace renderSpace = new RenderSpace(MIN_WIDTH, MIN_HEIGHT,
true);
@@ -122,6 +132,8 @@ public class IWindow extends IToolkitOverlay implements Container,
private String height;
+ private boolean immediate;
+
public IWindow() {
super(false, false, true); // no autohide, not modal, shadow
// Different style of shadow for windows
@@ -239,6 +251,8 @@ public class IWindow extends IToolkitOverlay implements Container,
return;
}
+ immediate = uidl.hasAttribute("immediate");
+
if (uidl.getBooleanAttribute("resizable") != resizable) {
setResizable(!resizable);
}
@@ -304,20 +318,17 @@ public class IWindow extends IToolkitOverlay implements Container,
layout = lo;
}
- boolean dynamicWidth = !uidl.hasAttribute("width");
- boolean dynamicHeight = !uidl.hasAttribute("height");
- boolean widthHasBeenFixed = false;
+ dynamicWidth = !uidl.hasAttribute("width");
+ dynamicHeight = !uidl.hasAttribute("height");
- boolean layoutRelativeWidth = uidl.hasAttribute("layoutRelativeWidth");
- boolean layoutRelativeHeight = uidl
- .hasAttribute("layoutRelativeHeight");
+ layoutRelativeWidth = uidl.hasAttribute("layoutRelativeWidth");
+ layoutRelativeHeight = uidl.hasAttribute("layoutRelativeHeight");
if (dynamicWidth && layoutRelativeWidth) {
/*
* Relative layout width, fix window width before rendering (width
* according to caption)
*/
- widthHasBeenFixed = true;
setNaturalWidth();
}
@@ -335,9 +346,8 @@ public class IWindow extends IToolkitOverlay implements Container,
* No explicit width is set and the layout does not have relative width
* so fix the size according to the layout.
*/
- if (dynamicWidth && !widthHasBeenFixed) {
+ if (dynamicWidth && !layoutRelativeWidth) {
setNaturalWidth();
- widthHasBeenFixed = true;
}
if (dynamicHeight && layoutRelativeHeight) {
@@ -402,7 +412,12 @@ public class IWindow extends IToolkitOverlay implements Container,
// This has to be here because we might not know the content size before
// everything is painted into the window
if (uidl.getBooleanAttribute("center")) {
+ // mark as centered - this is unset on move/resize
+ centered = true;
center();
+ } else {
+ // don't try to center the window anymore
+ centered = false;
}
updateShadowSizeAndPosition();
@@ -444,7 +459,12 @@ public class IWindow extends IToolkitOverlay implements Container,
naturalWidth = getElement().getOffsetWidth();
headerText.getStyle().setProperty("width", headerW);
} else {
- naturalWidth = getElement().getOffsetWidth();
+ // use max(layout width, window width)
+ // i.e layout content width or caption width
+ int lowidth = contentPanel.getElement().getScrollWidth()
+ + borderWidth; // layout does not know about border
+ int elwidth = getElement().getOffsetWidth();
+ naturalWidth = (lowidth > elwidth ? lowidth : elwidth);
}
setWidth(naturalWidth + "px");
@@ -711,6 +731,7 @@ public class IWindow extends IToolkitOverlay implements Container,
resizing = false;
case Event.ONMOUSEMOVE:
if (resizing) {
+ centered = false;
setSize(event, false);
event.preventDefault();
}
@@ -739,7 +760,7 @@ public class IWindow extends IToolkitOverlay implements Container,
if (updateVariables) {
// sending width back always as pixels, no need for unit
client.updateVariable(id, "width", w, false);
- client.updateVariable(id, "height", h, false);
+ client.updateVariable(id, "height", h, immediate);
}
// Update child widget dimensions
@@ -859,6 +880,7 @@ public class IWindow extends IToolkitOverlay implements Container,
break;
case Event.ONMOUSEMOVE:
if (dragging) {
+ centered = false;
final int x = DOM.eventGetScreenX(event) - startX + origX;
final int y = DOM.eventGetScreenY(event) - startY + origY;
setPopupPosition(x, y);
@@ -962,6 +984,12 @@ public class IWindow extends IToolkitOverlay implements Container,
}
public boolean requestLayout(Set<Paintable> child) {
+ if (dynamicWidth && !layoutRelativeWidth) {
+ setNaturalWidth();
+ }
+ if (centered) {
+ center();
+ }
updateShadowSizeAndPosition();
return true;
}
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/SubPartAware.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/SubPartAware.java
new file mode 100644
index 0000000000..76ba7524be
--- /dev/null
+++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/SubPartAware.java
@@ -0,0 +1,11 @@
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+import com.google.gwt.user.client.Element;
+
+public interface SubPartAware {
+
+ Element getSubPartElement(String subPart);
+
+ String getSubPartName(Element subElement);
+
+} \ No newline at end of file
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java b/src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java
index 2321e50051..b9c8d58ff5 100644
--- a/src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java
+++ b/src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java
@@ -10,7 +10,6 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
-import java.io.Writer;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -165,10 +164,6 @@ public class ApplicationServlet extends HttpServlet {
private ClassLoader classLoader;
- private boolean testingToolsActive = false;
-
- private String testingToolsServerUri = null;
-
/**
* Called by the servlet container to indicate to a servlet that the servlet
* is being placed into service.
@@ -234,14 +229,6 @@ public class ApplicationServlet extends HttpServlet {
System.err.println(NOT_PRODUCTION_MODE_INFO);
}
- // Gets Testing Tools parameters if feature is activated
- if (getApplicationOrSystemProperty("testingToolsActive", "false")
- .equals("true")) {
- testingToolsActive = true;
- testingToolsServerUri = getApplicationOrSystemProperty(
- "testingToolsServerUri", null);
- }
-
// Gets custom class loader
final String classLoaderName = getApplicationOrSystemProperty(
"ClassLoader", null);
@@ -577,7 +564,8 @@ public class ApplicationServlet extends HttpServlet {
.getInternalErrorCaption(), ci
.getInternalErrorMessage(), ci.getInternalErrorURL());
if (application != null) {
- application.terminalError(new RequestError(e));
+ application.getErrorHandler().terminalError(
+ new RequestError(e));
} else {
throw new ServletException(e);
}
@@ -843,9 +831,6 @@ public class ApplicationServlet extends HttpServlet {
themeUri = staticFilePath + "/" + THEME_DIRECTORY_PATH + themeName;
}
- boolean testingApplication = testingToolsActive
- && request.getParameter("TT") != null;
-
if (!fragment) {
// Window renders are not cacheable
response.setHeader("Cache-Control", "no-cache");
@@ -878,12 +863,6 @@ public class ApplicationServlet extends HttpServlet {
page.write("<title>" + title + "</title>");
- if (testingApplication) {
- // TT script needs to be in head as it needs to be the first
- // to hook capturing event listeners
- writeTestingToolsScripts(page, request);
- }
-
page
.write("\n</head>\n<body scroll=\"auto\" class=\"i-generated-body\">\n");
}
@@ -895,7 +874,11 @@ public class ApplicationServlet extends HttpServlet {
appId = appId.replaceAll("[^a-zA-Z0-9]", "");
// Add hashCode to the end, so that it is still (sort of) predictable,
// but indicates that it should not be used in CSS and such:
- appId = appId + appId.hashCode();
+ int hashCode = appId.hashCode();
+ if (hashCode < 0) {
+ hashCode = -hashCode;
+ }
+ appId = appId + "-" + hashCode;
// Get system messages
Application.SystemMessages systemMessages = null;
@@ -1118,29 +1101,6 @@ public class ApplicationServlet extends HttpServlet {
return false;
}
- private void writeTestingToolsScripts(Writer page,
- HttpServletRequest request) throws IOException {
- // Testing Tools script and CSS files are served from Testing Tools
- // Server
- String ext = getTestingToolsUri(request);
- ext = ext.substring(0, ext.lastIndexOf('/'));
- page.write("<script src=\"" + ext + "/ext/TT.js"
- + "\" type=\"text/javascript\"></script>\n");
- page.write("<link rel=\"stylesheet\" href=\"" + ext + "/ext/TT.css"
- + "\" type=\"text/css\" />\n");
-
- }
-
- private String getTestingToolsUri(HttpServletRequest request) {
- if (testingToolsServerUri == null) {
- // Default behavior is that Testing Tools Server application exists
- // on same host as current application does in port 8099.
- testingToolsServerUri = "http" + "://" + request.getServerName()
- + ":8099" + "/TestingToolsServer";
- }
- return testingToolsServerUri;
- }
-
/**
* Handles the requested URI. An application can add handlers to do special
* processing, when a certain URI is requested. The handlers are invoked
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/CommunicationManager.java b/src/com/itmill/toolkit/terminal/gwt/server/CommunicationManager.java
index 7510c401ef..5cb8405d2a 100644
--- a/src/com/itmill/toolkit/terminal/gwt/server/CommunicationManager.java
+++ b/src/com/itmill/toolkit/terminal/gwt/server/CommunicationManager.java
@@ -1110,8 +1110,25 @@ public class CommunicationManager implements Paintable.RepaintRequestListener {
} else {
id = "PID_S" + id;
}
+ Paintable old = idPaintableMap.put(id, paintable);
+ if (old != null && old != paintable) {
+ /*
+ * Two paintables have the same id. We still make sure the old
+ * one is a component which is still attached to the
+ * application. This is just a precaution and should not be
+ * absolutely necessary.
+ */
+
+ if (old instanceof Component
+ && ((Component) old).getApplication() != null) {
+ throw new IllegalStateException("Two paintables ("
+ + paintable.getClass().getSimpleName() + ","
+ + old.getClass().getSimpleName()
+ + ") have been assigned the same id: "
+ + paintable.getDebugId());
+ }
+ }
paintableIdMap.put(paintable, id);
- idPaintableMap.put(id, paintable);
}
return id;
@@ -1456,7 +1473,8 @@ public class CommunicationManager implements Paintable.RepaintRequestListener {
}
} catch (final Throwable t) {
- application.terminalError(new URIHandlerErrorImpl(application, t));
+ application.getErrorHandler().terminalError(
+ new URIHandlerErrorImpl(application, t));
return null;
}
}
diff --git a/src/com/itmill/toolkit/tests/TestBench.java b/src/com/itmill/toolkit/tests/TestBench.java
index 99e770f487..1ea727a8a3 100644
--- a/src/com/itmill/toolkit/tests/TestBench.java
+++ b/src/com/itmill/toolkit/tests/TestBench.java
@@ -41,292 +41,292 @@ import com.itmill.toolkit.ui.UriFragmentUtility.FragmentChangedEvent;
*
*/
public class TestBench extends com.itmill.toolkit.Application implements
- Property.ValueChangeListener {
-
- // Add here packages which are used for finding testable classes
- String[] testablePackages = { "com.itmill.toolkit.tests",
- "com.itmill.toolkit.demo", "com.itmill.toolkit.demo.colorpicker",
- "com.itmill.toolkit.demo.reservation",
- "com.itmill.toolkit.demo.features",
- "com.itmill.toolkit.tests.tickets" };
-
- HierarchicalContainer testables = new HierarchicalContainer();
-
- Window mainWindow = new Window("TestBench window");
-
- // Main layout consists of tree menu and body layout
- SplitPanel mainLayout = new SplitPanel(SplitPanel.ORIENTATION_HORIZONTAL);
-
- Tree menu;
-
- Panel bodyLayout = new Panel();
-
- HashMap itemCaptions = new HashMap();
-
- @Override
- public void init() {
-
- // Add testable classes to hierarchical container
- for (int p = 0; p < testablePackages.length; p++) {
- testables.addItem(testablePackages[p]);
- try {
- final List testableClasses = getTestableClassesForPackage(testablePackages[p]);
- for (final Iterator it = testableClasses.iterator(); it
- .hasNext();) {
- final Class t = (Class) it.next();
- // ignore TestBench itself
- if (t.equals(TestBench.class)) {
- continue;
- }
- try {
- testables.addItem(t);
- itemCaptions.put(t, t.getName());
- testables.setParent(t, testablePackages[p]);
- testables.setChildrenAllowed(t, false);
- continue;
- } catch (final Exception e) {
- try {
- testables.addItem(t);
- itemCaptions.put(t, t.getName());
- testables.setParent(t, testablePackages[p]);
- testables.setChildrenAllowed(t, false);
- continue;
- } catch (final Exception e1) {
- e1.printStackTrace();
- }
- }
- }
- } catch (final Exception e) {
- e.printStackTrace();
- }
- }
-
- menu = new Tree("Testables", testables);
-
- for (final Iterator i = itemCaptions.keySet().iterator(); i.hasNext();) {
- final Class testable = (Class) i.next();
- // simplify captions
- final String name = testable.getName().substring(
- testable.getName().lastIndexOf('.') + 1);
- menu.setItemCaption(testable, name);
- }
- // expand all root items
- for (final Iterator i = menu.rootItemIds().iterator(); i.hasNext();) {
- menu.expandItemsRecursively(i.next());
- }
-
- menu.addListener(this);
- menu.setImmediate(true);
- menu.setNullSelectionAllowed(false);
- VerticalLayout lo = new VerticalLayout();
- lo.addComponent(menu);
-
- UriFragmentUtility uri = new UriFragmentUtility();
- lo.addComponent(uri);
-
- uri.addListener(new UriFragmentUtility.FragmentChangedListener() {
- public void fragmentChanged(FragmentChangedEvent source) {
- String fragment = source.getUriFragmentUtility().getFragment();
- if (fragment != null && !"".equals(fragment)) {
- // try to find a proper test class
-
- // exact match
- Iterator iterator = menu.getItemIds().iterator();
- while (iterator.hasNext()) {
- Object next = iterator.next();
- if (next instanceof Class) {
- Class c = (Class) next;
- String string = c.getName();
- if (string.equals(fragment)) {
- menu.setValue(c);
- mainLayout.setSplitPosition(0);
- return;
- }
- }
- }
-
- // simple name match
- iterator = menu.getItemIds().iterator();
- while (iterator.hasNext()) {
- Object next = iterator.next();
- if (next instanceof Class) {
- Class c = (Class) next;
- String string = c.getSimpleName();
- if (string.equals(fragment)) {
- menu.setValue(c);
- mainLayout.setSplitPosition(0);
- return;
- }
- }
- }
- // ticket match
- iterator = menu.getItemIds().iterator();
- while (iterator.hasNext()) {
- Object next = iterator.next();
- if (next instanceof Class) {
- Class c = (Class) next;
- String string = c.getSimpleName();
- if (string.startsWith("Ticket" + fragment)) {
- menu.setValue(c);
- mainLayout.setSplitPosition(0);
- return;
- }
- }
- }
-
- // just partly mach lowercase
- iterator = menu.getItemIds().iterator();
- while (iterator.hasNext()) {
- Object next = iterator.next();
- if (next instanceof Class) {
- Class c = (Class) next;
- String string = c.getSimpleName();
- if (string.toLowerCase().contains(
- fragment.toLowerCase())) {
- menu.setValue(c);
- mainLayout.setSplitPosition(0);
- return;
- }
- }
- }
-
- getMainWindow().showNotification(
- "No potential matc for #" + fragment);
-
- }
-
- }
- });
-
- mainLayout.addComponent(lo);
-
- bodyLayout.addStyleName("light");
- bodyLayout.setSizeFull();
- bodyLayout.setLayout(new ExpandLayout());
-
- mainLayout.addComponent(bodyLayout);
-
- mainLayout.setSplitPosition(30);
-
- mainWindow.setLayout(mainLayout);
-
- setMainWindow(mainWindow);
- }
-
- private Component createTestable(Class c) {
- try {
- final Application app = (Application) c.newInstance();
- app.init();
- Layout lo = app.getMainWindow().getLayout();
- lo.setParent(null);
- return lo;
- } catch (final Exception e) {
- try {
- final CustomComponent cc = (CustomComponent) c.newInstance();
- cc.setSizeFull();
- return cc;
- } catch (final Exception e1) {
- e1.printStackTrace();
- VerticalLayout lo = new VerticalLayout();
- lo.addComponent(new Label(
- "Cannot create application / custom component: "
- + e1.toString()));
-
- Link l = new Link("Try opening via app runner",
- new ExternalResource("../run/" + c.getName()));
- lo.addComponent(l);
-
- return lo;
- }
- }
- }
-
- // Handle menu selection and update body
- public void valueChange(Property.ValueChangeEvent event) {
- bodyLayout.removeAllComponents();
- bodyLayout.setCaption(null);
-
- final Object o = menu.getValue();
- if (o != null && o instanceof Class) {
- final Class c = (Class) o;
- final String title = c.getName();
- bodyLayout.setCaption(title);
- bodyLayout.addComponent(createTestable(c));
- } else {
- // NOP node selected or deselected tree item
- }
- }
-
- /**
- * Return all testable classes within given package. Class is considered
- * testable if it's superclass is Application or CustomComponent.
- *
- * @param packageName
- * @return
- * @throws ClassNotFoundException
- */
- public static List getTestableClassesForPackage(String packageName)
- throws Exception {
- final ArrayList directories = new ArrayList();
- try {
- final ClassLoader cld = Thread.currentThread()
- .getContextClassLoader();
- if (cld == null) {
- throw new ClassNotFoundException("Can't get class loader.");
- }
- final String path = packageName.replace('.', '/');
- // Ask for all resources for the path
- final Enumeration resources = cld.getResources(path);
- while (resources.hasMoreElements()) {
- final URL url = (URL) resources.nextElement();
- directories.add(new File(url.getFile()));
- }
- } catch (final Exception x) {
- throw new Exception(packageName
- + " does not appear to be a valid package.");
- }
-
- final ArrayList classes = new ArrayList();
- // For every directory identified capture all the .class files
- for (final Iterator it = directories.iterator(); it.hasNext();) {
- final File directory = (File) it.next();
- if (directory.exists()) {
- // Get the list of the files contained in the package
- final String[] files = directory.list();
- for (int j = 0; j < files.length; j++) {
- // we are only interested in .class files
- if (files[j].endsWith(".class")) {
- // removes the .class extension
- final String p = packageName + '.'
- + files[j].substring(0, files[j].length() - 6);
- final Class c = Class.forName(p);
- if (c.getSuperclass() != null) {
- if ((c.getSuperclass()
- .equals(com.itmill.toolkit.Application.class))) {
- classes.add(c);
- } else if ((c.getSuperclass()
- .equals(com.itmill.toolkit.ui.CustomComponent.class))) {
- classes.add(c);
- }
- }
-
- // for (int i = 0; i < c.getInterfaces().length; i++) {
- // Class cc = c.getInterfaces()[i];
- // if (c.getInterfaces()[i].equals(Testable.class)) {
- // // Class is testable
- // classes.add(c);
- // }
- // }
- }
- }
- } else {
- throw new ClassNotFoundException(packageName + " ("
- + directory.getPath()
- + ") does not appear to be a valid package");
- }
- }
-
- return classes;
- }
+ Property.ValueChangeListener {
+
+ // Add here packages which are used for finding testable classes
+ String[] testablePackages = { "com.itmill.toolkit.tests",
+ "com.itmill.toolkit.demo", "com.itmill.toolkit.demo.colorpicker",
+ "com.itmill.toolkit.demo.reservation",
+ "com.itmill.toolkit.demo.features",
+ "com.itmill.toolkit.tests.tickets", "com.itmill.toolkit.tests.book" };
+
+ HierarchicalContainer testables = new HierarchicalContainer();
+
+ Window mainWindow = new Window("TestBench window");
+
+ // Main layout consists of tree menu and body layout
+ SplitPanel mainLayout = new SplitPanel(SplitPanel.ORIENTATION_HORIZONTAL);
+
+ Tree menu;
+
+ Panel bodyLayout = new Panel();
+
+ HashMap itemCaptions = new HashMap();
+
+ @Override
+ public void init() {
+
+ // Add testable classes to hierarchical container
+ for (int p = 0; p < testablePackages.length; p++) {
+ testables.addItem(testablePackages[p]);
+ try {
+ final List testableClasses = getTestableClassesForPackage(testablePackages[p]);
+ for (final Iterator it = testableClasses.iterator(); it
+ .hasNext();) {
+ final Class t = (Class) it.next();
+ // ignore TestBench itself
+ if (t.equals(TestBench.class)) {
+ continue;
+ }
+ try {
+ testables.addItem(t);
+ itemCaptions.put(t, t.getName());
+ testables.setParent(t, testablePackages[p]);
+ testables.setChildrenAllowed(t, false);
+ continue;
+ } catch (final Exception e) {
+ try {
+ testables.addItem(t);
+ itemCaptions.put(t, t.getName());
+ testables.setParent(t, testablePackages[p]);
+ testables.setChildrenAllowed(t, false);
+ continue;
+ } catch (final Exception e1) {
+ e1.printStackTrace();
+ }
+ }
+ }
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ menu = new Tree("Testables", testables);
+
+ for (final Iterator i = itemCaptions.keySet().iterator(); i.hasNext();) {
+ final Class testable = (Class) i.next();
+ // simplify captions
+ final String name = testable.getName().substring(
+ testable.getName().lastIndexOf('.') + 1);
+ menu.setItemCaption(testable, name);
+ }
+ // expand all root items
+ for (final Iterator i = menu.rootItemIds().iterator(); i.hasNext();) {
+ menu.expandItemsRecursively(i.next());
+ }
+
+ menu.addListener(this);
+ menu.setImmediate(true);
+ menu.setNullSelectionAllowed(false);
+ VerticalLayout lo = new VerticalLayout();
+ lo.addComponent(menu);
+
+ UriFragmentUtility uri = new UriFragmentUtility();
+ lo.addComponent(uri);
+
+ uri.addListener(new UriFragmentUtility.FragmentChangedListener() {
+ public void fragmentChanged(FragmentChangedEvent source) {
+ String fragment = source.getUriFragmentUtility().getFragment();
+ if (fragment != null && !"".equals(fragment)) {
+ // try to find a proper test class
+
+ // exact match
+ Iterator iterator = menu.getItemIds().iterator();
+ while (iterator.hasNext()) {
+ Object next = iterator.next();
+ if (next instanceof Class) {
+ Class c = (Class) next;
+ String string = c.getName();
+ if (string.equals(fragment)) {
+ menu.setValue(c);
+ mainLayout.setSplitPosition(0);
+ return;
+ }
+ }
+ }
+
+ // simple name match
+ iterator = menu.getItemIds().iterator();
+ while (iterator.hasNext()) {
+ Object next = iterator.next();
+ if (next instanceof Class) {
+ Class c = (Class) next;
+ String string = c.getSimpleName();
+ if (string.equals(fragment)) {
+ menu.setValue(c);
+ mainLayout.setSplitPosition(0);
+ return;
+ }
+ }
+ }
+ // ticket match
+ iterator = menu.getItemIds().iterator();
+ while (iterator.hasNext()) {
+ Object next = iterator.next();
+ if (next instanceof Class) {
+ Class c = (Class) next;
+ String string = c.getSimpleName();
+ if (string.startsWith("Ticket" + fragment)) {
+ menu.setValue(c);
+ mainLayout.setSplitPosition(0);
+ return;
+ }
+ }
+ }
+
+ // just partly mach lowercase
+ iterator = menu.getItemIds().iterator();
+ while (iterator.hasNext()) {
+ Object next = iterator.next();
+ if (next instanceof Class) {
+ Class c = (Class) next;
+ String string = c.getSimpleName();
+ if (string.toLowerCase().contains(
+ fragment.toLowerCase())) {
+ menu.setValue(c);
+ mainLayout.setSplitPosition(0);
+ return;
+ }
+ }
+ }
+
+ getMainWindow().showNotification(
+ "No potential matc for #" + fragment);
+
+ }
+
+ }
+ });
+
+ mainLayout.addComponent(lo);
+
+ bodyLayout.addStyleName("light");
+ bodyLayout.setSizeFull();
+ bodyLayout.setLayout(new ExpandLayout());
+
+ mainLayout.addComponent(bodyLayout);
+
+ mainLayout.setSplitPosition(30);
+
+ mainWindow.setLayout(mainLayout);
+
+ setMainWindow(mainWindow);
+ }
+
+ private Component createTestable(Class c) {
+ try {
+ final Application app = (Application) c.newInstance();
+ app.init();
+ Layout lo = app.getMainWindow().getLayout();
+ lo.setParent(null);
+ return lo;
+ } catch (final Exception e) {
+ try {
+ final CustomComponent cc = (CustomComponent) c.newInstance();
+ cc.setSizeFull();
+ return cc;
+ } catch (final Exception e1) {
+ e1.printStackTrace();
+ VerticalLayout lo = new VerticalLayout();
+ lo.addComponent(new Label(
+ "Cannot create application / custom component: "
+ + e1.toString()));
+
+ Link l = new Link("Try opening via app runner",
+ new ExternalResource("../run/" + c.getName()));
+ lo.addComponent(l);
+
+ return lo;
+ }
+ }
+ }
+
+ // Handle menu selection and update body
+ public void valueChange(Property.ValueChangeEvent event) {
+ bodyLayout.removeAllComponents();
+ bodyLayout.setCaption(null);
+
+ final Object o = menu.getValue();
+ if (o != null && o instanceof Class) {
+ final Class c = (Class) o;
+ final String title = c.getName();
+ bodyLayout.setCaption(title);
+ bodyLayout.addComponent(createTestable(c));
+ } else {
+ // NOP node selected or deselected tree item
+ }
+ }
+
+ /**
+ * Return all testable classes within given package. Class is considered
+ * testable if it's superclass is Application or CustomComponent.
+ *
+ * @param packageName
+ * @return
+ * @throws ClassNotFoundException
+ */
+ public static List getTestableClassesForPackage(String packageName)
+ throws Exception {
+ final ArrayList directories = new ArrayList();
+ try {
+ final ClassLoader cld = Thread.currentThread()
+ .getContextClassLoader();
+ if (cld == null) {
+ throw new ClassNotFoundException("Can't get class loader.");
+ }
+ final String path = packageName.replace('.', '/');
+ // Ask for all resources for the path
+ final Enumeration resources = cld.getResources(path);
+ while (resources.hasMoreElements()) {
+ final URL url = (URL) resources.nextElement();
+ directories.add(new File(url.getFile()));
+ }
+ } catch (final Exception x) {
+ throw new Exception(packageName
+ + " does not appear to be a valid package.");
+ }
+
+ final ArrayList classes = new ArrayList();
+ // For every directory identified capture all the .class files
+ for (final Iterator it = directories.iterator(); it.hasNext();) {
+ final File directory = (File) it.next();
+ if (directory.exists()) {
+ // Get the list of the files contained in the package
+ final String[] files = directory.list();
+ for (int j = 0; j < files.length; j++) {
+ // we are only interested in .class files
+ if (files[j].endsWith(".class")) {
+ // removes the .class extension
+ final String p = packageName + '.'
+ + files[j].substring(0, files[j].length() - 6);
+ final Class c = Class.forName(p);
+ if (c.getSuperclass() != null) {
+ if ((c.getSuperclass()
+ .equals(com.itmill.toolkit.Application.class))) {
+ classes.add(c);
+ } else if ((c.getSuperclass()
+ .equals(com.itmill.toolkit.ui.CustomComponent.class))) {
+ classes.add(c);
+ }
+ }
+
+ // for (int i = 0; i < c.getInterfaces().length; i++) {
+ // Class cc = c.getInterfaces()[i];
+ // if (c.getInterfaces()[i].equals(Testable.class)) {
+ // // Class is testable
+ // classes.add(c);
+ // }
+ // }
+ }
+ }
+ } else {
+ throw new ClassNotFoundException(packageName + " ("
+ + directory.getPath()
+ + ") does not appear to be a valid package");
+ }
+ }
+
+ return classes;
+ }
}
diff --git a/src/com/itmill/toolkit/tests/book/BookTestApplication.java b/src/com/itmill/toolkit/tests/book/BookTestApplication.java
index 2402b0a57d..678f49c7dc 100644
--- a/src/com/itmill/toolkit/tests/book/BookTestApplication.java
+++ b/src/com/itmill/toolkit/tests/book/BookTestApplication.java
@@ -14,8 +14,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
-import javax.management.Notification;
-
import com.itmill.toolkit.data.Item;
import com.itmill.toolkit.data.Validator;
import com.itmill.toolkit.data.Property.ValueChangeEvent;
@@ -63,1682 +61,1689 @@ import com.itmill.toolkit.ui.Layout.AlignmentHandler;
import com.itmill.toolkit.ui.MenuBar.MenuItem;
public class BookTestApplication extends com.itmill.toolkit.Application {
- Window main = new Window("Application window");
-
- TheButton butts1;
- TheButtons butts2;
- TheButtons2 butts3;
-
- Label mylabel1;
- Label mylabel2;
- Label mylabel3;
-
- StreamResource strres;
- VerticalLayout ol;
- int getwincount = 0;
-
- public void init() {
- setTheme("tests-book");
-
- setMainWindow(main);
-
- // Demo the use of parameter and URI handlers
- main.addParameterHandler(new MyParameterHandler());
- main.addURIHandler(new MyURIHandler());
-
- MyDynamicResource myresource = new MyDynamicResource();
- main.addParameterHandler(myresource);
- main.addURIHandler(myresource);
-
- main.addURIHandler(new BookTestURIHandler());
- }
-
- class MyParameterHandler implements ParameterHandler {
- public void handleParameters(Map parameters) {
- // Print out the parameters to standard output
- for (Iterator it = parameters.keySet().iterator(); it.hasNext();) {
- String key = (String) it.next();
- String value = ((String[]) parameters.get(key))[0];
- System.out.println("Key: " + key + ", value: " + value);
- }
- }
- }
-
- class MyURIHandler implements URIHandler {
- public DownloadStream handleURI(URL context, String relativeUri) {
- System.out.println("Context: " + context.toString()
- + ", relative: " + relativeUri);
- return null; // Let the Application provide the response
- }
- }
-
- class BookTestURIHandler implements URIHandler {
- public DownloadStream handleURI(URL context, String relativeUri) {
- String example;
- String param = null;
-
- final int slashPos = relativeUri.indexOf("/");
- if (slashPos > 0) {
- example = relativeUri.substring(0, slashPos);
- param = relativeUri.substring(slashPos + 1);
- } else {
- example = relativeUri;
- }
-
- /* Remove existing components and windows. */
- main.removeAllComponents();
- final Set childwindows = main.getChildWindows();
- for (final Iterator cwi = childwindows.iterator(); cwi.hasNext();) {
- final Window child = (Window) cwi.next();
- main.removeWindow(child);
- }
-
- // The index is listed inside a grid layout
- main.setLayout(new VerticalLayout());
- GridLayout grid = new GridLayout(4, 4);
- grid.addStyleName("index");
- main.addComponent(grid);
-
- if (example.equals("index")) {
- final String examples[] = { "defaultbutton", "label",
- "labelcontent", "tree", "embedded", "textfield",
- "textfieldvalidation", "datefield", "button",
- "select/select", "select/native", "select/optiongroup",
- "select/twincol", "filterselect", "validator", "table",
- "table/select", "table/component", "table/paging",
- "table/editable", "upload", "link", "gridlayout",
- "orderedlayout", "formlayout", "form", "form/simple",
- "form/layout", "panel", "expandlayout",
- "expandlayout/root", "tabsheet", "alignment",
- "alignment/grid", "window", "window/opener",
- "window/multiple", "classresource", "usererror",
- "progress/window", "progress/thread", "progress",
- "customlayout", "spacing", "margin", "clientinfo",
- "fillinform/templates", "notification", "print",
- "richtextfield", "querycontainer", "menubar" };
- for (int i = 0; i < examples.length; i++) {
- grid.addComponent(new Label("<a href='"
- + context.toString() + examples[i] + "'>"
- + examples[i] + "</a>", Label.CONTENT_XHTML));
- }
- return null;
- }
-
- if (example.equals("defaultbutton")) {
- example_defaultButton(main, param);
- } else if (example.equals("label")) {
- example_Label(main, param);
- } else if (example.equals("labelcontent")) {
- example_LabelContent(main, param);
- } else if (example.equals("tree")) {
- example_Tree(main, param);
- } else if (example.equals("embedded")) {
- example_Embedded(main, param);
- } else if (example.equals("textfield")) {
- example_TextField(main, param);
- } else if (example.equals("textfieldvalidation")) {
- example_TextFieldValidation(main, param);
- } else if (example.equals("usererror")) {
- example_UserError(main, param);
- } else if (example.equals("datefield")) {
- example_DateField(main, param);
- } else if (example.equals("button")) {
- example_Button(main, param);
- } else if (example.equals("checkbox")) {
- example_CheckBox(main, param);
- } else if (example.equals("select")) {
- example_Select(main, param);
- } else if (example.equals("filterselect")) {
- example_FilterSelect(main, param);
- } else if (example.equals("validator")) {
- example_Validator(main, param);
- } else if (example.equals("table")) {
- example_Table(main, param);
- } else if (example.equals("upload")) {
- example_Upload(main, param);
- } else if (example.equals("link")) {
- example_Link(main, param);
- } else if (example.equals("gridlayout")) {
- example_GridLayout(main, param);
- } else if (example.equals("orderedlayout")) {
- example_OrderedLayout(main, param);
- } else if (example.equals("formlayout")) {
- example_FormLayout(main, param);
- } else if (example.equals("form")) {
- example_Form(main, param);
- } else if (example.equals("tabsheet")) {
- example_TabSheet(main, param);
- } else if (example.equals("panel")) {
- example_Panel(main, param);
- } else if (example.equals("expandlayout")) {
- example_ExpandLayout(main, param);
- } else if (example.equals("alignment")) {
- example_Alignment(main, param);
- } else if (example.equals("window")) {
- example_Window(main, param);
- } else if (example.equals("classresource")) {
- example_ClassResource(main, param);
- } else if (example.equals("progress")) {
- example_ProgressIndicator(main, param);
- } else if (example.equals("customlayout")) {
- example_CustomLayout(main, param);
- } else if (example.equals("spacing")) {
- example_Spacing(main, param);
- } else if (example.equals("margin")) {
- example_Margin(main, param);
- } else if (example.equals("clientinfo")) {
- example_ClientInfo(main, param);
- } else if (example.equals("fillinform")) {
- example_FillInForm(main, param);
- } else if (example.equals("notification")) {
- example_Notification(main, param);
- } else if (example.equals("print")) {
- example_Print(main, param);
- } else if (example.equals("richtextfield")) {
- example_RichTextArea(main, param);
- } else if (example.equals("querycontainer")) {
- example_QueryContainer(main, param);
- } else if (example.equals("menubar")) {
- example_MenuBar(main, param);
- } else {
- ; // main.addComponent(new
- // Label("Unknown test '"+example+"'."));
- }
-
- return null;
- }
- }
-
- /*
- * public Window getWindow(String name) { Window superwin =
- * super.getWindow(name); if (superwin != null) return superwin;
- *
- * main.addComponent(new Label("Request 2 for window '"+name+"'.")); if
- * (name.equals("panel")) { Window window = new Window("Other Window " +
- * getwincount++); example_Panel(window, null); return window; } return
- * null; }
- */
- public void handleButton(Button.ClickEvent event) {
- ol.addStyleName("myLayout2");
- }
-
- void example_defaultButton(Window main, String param) {
- main.addComponent(new DefaultButtonExample(main));
- }
-
- void example_Label(Window main, String param) {
- /* Some container for the Label. */
- final Panel panel = new Panel("Panel Containing a Label");
- main.addComponent(panel);
-
- panel.addComponent(new Label(
- "This is a Label inside a Panel. There is enough "
- + "text in the label to make the text wrap if it "
- + "exceeds the width of the panel."));
- }
-
- void example_LabelContent(Window main, String param) {
- final GridLayout labelgrid = new GridLayout(2, 1);
- labelgrid.addStyleName("labelgrid");
- labelgrid.addComponent(new Label("CONTENT_DEFAULT"));
- labelgrid.addComponent(new Label(
- "This is a label in default mode: <plain text>",
- Label.CONTENT_DEFAULT));
- labelgrid.addComponent(new Label("CONTENT_PREFORMATTED"));
- labelgrid
- .addComponent(new Label(
- "This is a preformatted label.\nThe newline character \\n breaks the line.",
- Label.CONTENT_PREFORMATTED));
- labelgrid.addComponent(new Label("CONTENT_RAW"));
- labelgrid
- .addComponent(new Label(
- "This is a label in raw mode.<br>It can contain, for example, unbalanced markup.",
- Label.CONTENT_RAW));
- labelgrid.addComponent(new Label("CONTENT_TEXT"));
- labelgrid.addComponent(new Label(
- "This is a label in (plain) text mode", Label.CONTENT_TEXT));
- labelgrid.addComponent(new Label("CONTENT_XHTML"));
- labelgrid.addComponent(new Label(
- "<i>This</i> is an <b>XHTML<b> formatted label",
- Label.CONTENT_XHTML));
- labelgrid.addComponent(new Label("CONTENT_XML"));
- labelgrid.addComponent(new Label(
- "This is an <myelement>XML</myelement> formatted label",
- Label.CONTENT_XML));
- main.addComponent(labelgrid);
-
- final ClassResource labelimage = new ClassResource("smiley.jpg", this);
- main.addComponent(new Label("Here we have an image <img src=\""
- + getRelativeLocation(labelimage) + "\"/> within some text.",
- Label.CONTENT_XHTML));
- }
-
- void example_Tree(Window main, String param) {
- final Object[][] planets = new Object[][] {
- new Object[] { "Mercury" },
- new Object[] { "Venus" },
- new Object[] { "Earth", "The Moon" },
- new Object[] { "Mars", "Phobos", "Deimos" },
- new Object[] { "Jupiter", "Io", "Europa", "Ganymedes",
- "Callisto" },
- new Object[] { "Saturn", "Titan", "Tethys", "Dione", "Rhea",
- "Iapetus" },
- new Object[] { "Uranus", "Miranda", "Ariel", "Umbriel",
- "Titania", "Oberon" },
- new Object[] { "Neptune", "Triton", "Proteus", "Nereid",
- "Larissa" } };
-
- final Tree tree = new Tree();
-
- // Add planets as root items in the tree.
- for (int i = 0; i < planets.length; i++) {
- final String planet = (String) (planets[i][0]);
- tree.addItem(planet);
-
- if (planets[i].length == 1) {
- // The planet has no moons so make it a leaf.
- tree.setChildrenAllowed(planet, false);
- } else {
- // Add children (moons) under the planets.
- for (int j = 1; j < planets[i].length; j++) {
- final String moon = (String) planets[i][j];
-
- // Add the item as a regular item.
- tree.addItem(moon);
-
- // Set it to be a child.
- tree.setParent(moon, planet);
-
- // Make the moons look like leaves.
- tree.setChildrenAllowed(moon, false);
- }
-
- // Expand the subtree.
- tree.expandItemsRecursively(planet);
- }
- }
-
- // Horizontal layout with the tree on the left and a details panel on
- // the right.
- final HorizontalLayout horlayout = new HorizontalLayout();
- horlayout.addStyleName("treeexample");
- horlayout.setSizeFull();
-
- final Panel treepanel = new Panel("The Planets and Major Moons");
- treepanel.addComponent(tree);
- horlayout.addComponent(treepanel);
-
- final Panel detailspanel = new Panel("Details");
- horlayout.addComponent(detailspanel);
- horlayout.setExpandRatio(detailspanel, 1);
-
- final VerticalLayout detailslayout = new VerticalLayout();
- detailspanel.setLayout(detailslayout);
-
- // Allow null selection - this is the default actually.
- tree.setNullSelectionAllowed(true);
-
- // When a tree item (planet or moon) is clicked, open the item in
- // Details view.
- tree.setImmediate(true);
- tree.addListener(new ValueChangeListener() {
- String lastselected = null;
-
- public void valueChange(ValueChangeEvent event) {
- String planet = (String) tree.getValue();
-
- // Reselect a selected item if it is unselected by clicking it.
- if (planet == null) {
- planet = lastselected;
- tree.setValue(planet);
- }
- lastselected = planet;
-
- detailspanel.setCaption("Details on " + planet);
- detailslayout.removeAllComponents();
-
- // Put some stuff in the Details view.
- detailslayout.addComponent(new Label("Where is the cat?"));
- detailslayout.addComponent(new Label("The cat is in " + planet
- + "."));
-
- }
- });
-
- main.setLayout(horlayout);
- }
-
- void example_Select(Window main, String param) {
- final HorizontalLayout layout = new HorizontalLayout();
- layout.addStyleName("aligntop");
-
- if (param.equals("twincol")) {
- final SelectExample select1 = new SelectExample(this, param,
- "Select some items", true);
- layout.addComponent(select1);
- } else if (param.equals("filter")) {
- final SelectExample select1 = new SelectExample(this, param,
- "Enter containing substring", false);
- layout.addComponent(select1);
- } else {
- final SelectExample select1 = new SelectExample(this, param,
- "Single Selection Mode", false);
- final SelectExample select2 = new SelectExample(this, param,
- "Multiple Selection Mode", true);
- layout.addComponent(select1);
- layout.addComponent(select2);
- }
- main.addComponent(layout);
- }
-
- void example_FilterSelect(Window main, String param) {
- final Select select = new Select("Enter containing substring");
- main.addComponent(select);
-
- select
- .setFilteringMode(AbstractSelect.Filtering.FILTERINGMODE_CONTAINS);
-
- /* Fill the component with some items. */
- final String[] planets = new String[] { "Mercury", "Venus", "Earth",
- "Mars", "Jupiter", "Saturn", "Uranus", "Neptune" };
-
- for (int i = 0; i < planets.length; i++) {
- for (int j = 0; j < planets.length; j++) {
- select.addItem(planets[j] + " to " + planets[i]);
- }
- }
- }
-
- void example_TextField(Window main, String param) {
- /* Add a single-line text field. */
- final TextField subject = new TextField("Subject");
- subject.setColumns(40);
- main.addComponent(subject);
-
- /* Add a multi-line text field. */
- final TextField message = new TextField("Message");
- message.setRows(7);
- message.setColumns(40);
- main.addComponent(message);
- }
-
- void example_TextFieldValidation(Window main, String param) {
- // Create a text field with a label
- final TextField username = new TextField("Username");
- main.addComponent(username);
-
- // Set visible length to 16 characters
- username.setColumns(16);
-
- // Set content length to minimum of 6 and maximum of 16 characters.
- // The string also may not be null.
- username.addValidator(new StringLengthValidator(
- "Must be 6 to 16 characters long", 6, 16, false));
-
- // Setting component immediate causes a ValueChangeEvent to occur
- // when the TextField loses focus.
- username.setImmediate(true);
-
- // Listen for ValueChangeEvents and handle them
- username.addListener(new ValueChangeListener() {
- public void valueChange(ValueChangeEvent event) {
- // Get the source of the event
- final TextField username = (TextField) (event.getProperty());
-
- try {
- // Validate the field value.
- username.validate();
- } catch (final Validator.InvalidValueException e) {
- // The value was not ok. The error was set.
- }
- }
- });
- }
-
- void example_UserError(final Window main, String param) {
- if (param != null) {
- if (param.equals("form")) {
-
- final FormLayout layout = new FormLayout();
- main.addComponent(layout);
-
- final TextField textfield = new TextField("Enter code");
- layout.addComponent(textfield);
- textfield.setComponentError(null);
-
- final Button button = new Button("Ok!");
- layout.addComponent(button);
-
- button.addListener(new Button.ClickListener() {
- public void buttonClick(ClickEvent event) {
- if (((String) textfield.getValue()).length() == 0) {
- textfield.setComponentError(new UserError(
- "Must be letters and numbers."));
- } else {
- textfield.setComponentError(null);
- }
- }
- });
- }
- } else {
- main.setLayout(new HorizontalLayout());
-
- // Create a field.
- final TextField textfield = new TextField("Enter code");
- main.addComponent(textfield);
-
- // Let the component error be initially clear. (It actually is by default.)
- textfield.setComponentError(null);
-
- // Have a button right of the field (and align it properly).
- final Button button = new Button("Ok!");
- main.addComponent(button);
- ((HorizontalLayout)main.getLayout()).setComponentAlignment(button,
- HorizontalLayout.ALIGNMENT_LEFT, HorizontalLayout.ALIGNMENT_BOTTOM);
-
- // Handle button clicks
- button.addListener(new Button.ClickListener() {
- public void buttonClick(ClickEvent event) {
- // If the field value is bad, set its error.
- // (Here the content must be only alphanumeric characters.)
- if (! ((String) textfield.getValue()).matches("^\\w*$")) {
- // Put the component in error state and set the error message.
- textfield.setComponentError(new UserError("Must be letters and numbers"));
- } else {
- // Otherwise clear it.
- textfield.setComponentError(null);
- }
- }
- });
- }
- }
-
- void example_DateField(Window main, String param) {
- HorizontalLayout layout = new HorizontalLayout();
-
- /* Create a DateField with the calendar style. */
- final DateField popupdate = new PopupDateField("Popup calendar field");
-
- /* Set resolution of the date/time display. */
- popupdate.setResolution(DateField.RESOLUTION_MIN);
-
- /* Set the date and time to present. */
- popupdate.setValue(new java.util.Date());
-
- /* Create a DateField with the calendar style. */
- final DateField inlinedate = new InlineDateField(
- "Inline calendar field");
-
- /* Set locale of the DateField to American English. */
- inlinedate.setLocale(new Locale("en", "US"));
-
- /* Set the date and time to present. */
- inlinedate.setValue(new java.util.Date());
-
- /* Set resolution of the date/time display. */
- inlinedate.setResolution(DateField.RESOLUTION_MIN);
-
- layout.addComponent(popupdate);
- layout.addComponent(inlinedate);
- layout.setSpacing(true);
- main.addComponent(layout);
- }
-
- void example_Validator(Window main, String param) {
- if (param != null && param.equals("required")) {
- Form form = new Form();
- form.setCaption("My Form");
- form.setRequired(true);
- main.addComponent(form);
-
- TextField text = new TextField("This is a required text field");
- text.setRequired(true);
- text.setImmediate(true);
- form.getLayout().addComponent(text);
- return;
- }
- main.addComponent(new SSNField());
- }
-
- class PagingTable extends Table {
- public String getTag() {
- return "pagingtable";
- }
- }
-
- void example_Table(Window main, String param) {
- if (param != null) {
- if (param.equals("select")) {
- main.addComponent(new TableExample2());
- } else if (param.equals("component")) {
- main.addComponent(new TableExample3());
- } else if (param.equals("editable")) {
- main.addComponent(new TableEditable());
- } else if (param.equals("bean")) {
- main.addComponent(new TableEditableBean());
- } else if (param.equals("long")) {
- main.addComponent(new TableExample());
- } else if (param.equals("cellstyle")) {
- main.addComponent(new TableCellStyle());
- } else if (param.equals("huge")) {
- main.addComponent(new TableHuge());
- } else if (param.equals("paging")) {
- PagingTable table = new PagingTable();
- table.addContainerProperty("Column 1", String.class, null);
- for (int i = 0; i < 100; i++) {
- table.addItem(new Object[] { "Item " + i }, new Integer(i));
- }
- main.addComponent(table);
- }
- } else {
- main.addComponent(new TableExample1());
- }
- }
-
- void example_Upload(Window main, String param) {
- main.addComponent(new MyUploader());
- }
-
- void example_Link(Window main, String param) {
-
- /* Create a link that opens the popup window. */
- final Link alink = new Link();
-
- /* Set the resource to be opened in the window. */
- alink.setResource(new ExternalResource("http://www.itmill.com/"));
-
- main.addComponent(alink);
-
- final ClassResource mydocument = new ClassResource("mydocument.pdf",
- this);
- main.addComponent(new Link("The document (pdf)", mydocument));
- main.addComponent(new Link("link to a resource", new ExternalResource(
- "http://www.itmill.com/")));
- }
-
- void example_Button(Window main, String param) {
- if (param != null) {
- if (param.equals("buttons")) {
- main.addComponent(new TheButton());
- }
- return;
- }
-
- // butts1 = new TheButton ();
- // main.addComponent(butts1);
-
- // butts2 = new TheButtons (main);
- // butts3 = new TheButtons2 (main);
-
- // Button checkbox = new Button ("This is a checkbox");
-
- // main.addComponent(checkbox);
- final Button button = new Button("My Button");
- main.addComponent(button);
- }
-
- void example_CheckBox(Window main, String param) {
- /* A check box with default state (not checked, i.e., false). */
- final CheckBox checkbox1 = new CheckBox("My CheckBox");
- checkbox1.addStyleName("mybox");
- main.addComponent(checkbox1);
-
- /* Another check box with explicitly set checked state. */
- final CheckBox checkbox2 = new CheckBox("Checked CheckBox");
- /*
- * @TODO: Build fails here, why? checkbox2.setValue(true);
- */
- main.addComponent(checkbox2);
-
- /*
- * Make some application logic. We use anynymous listener classes here.
- * The above references were defined as "final" to allow accessing them
- * from inside anonymous classes.
- */
- checkbox1.addListener(new ValueChangeListener() {
- public void valueChange(ValueChangeEvent event) {
- /* Copy the value to the other checkbox. */
- checkbox2.setValue(checkbox1.getValue());
- }
- });
- checkbox2.addListener(new ValueChangeListener() {
- public void valueChange(ValueChangeEvent event) {
- /* Copy the value to the other checkbox. */
- checkbox1.setValue(checkbox2.getValue());
- }
- });
- }
-
- void example_Panel(Window main, String param) {
- // Create a panel with a caption.
- final Panel panel = new Panel("Contact Information");
-
- // Create a layout inside the panel
- final FormLayout form = new FormLayout();
-
- // Set the layout as the root layout of the panel
- panel.setLayout(form);
-
- // Add some components
- form.addComponent(new TextField("Name"));
- form.addComponent(new TextField("Email"));
-
- // Add the panel to the main window
- final ClassResource icon = new ClassResource("smiley.jpg", main
- .getApplication());
- form.addComponent(new Embedded("Image", icon));
- panel.setIcon(icon);
- panel.addComponent(form);
- main.addComponent(panel);
- }
-
- void example_GridLayout(Window main, String param) {
- if (param.equals("embedded")) {
- final GridLayout grid = new GridLayout(3, 3);
- for (int i = 0; i < 3 * 3; i++) {
- ClassResource img = new ClassResource("smiley.jpg", main
- .getApplication());
- Embedded embedded = new Embedded("", img);
- grid.addComponent(embedded);
- }
- main.addComponent(grid);
- return;
- }
- /* Create a 4 by 4 grid layout. */
- final GridLayout grid = new GridLayout(4, 4);
- grid.addStyleName("example-gridlayout");
-
- /* Fill out the first row using the cursor. */
- grid.addComponent(new Button("R/C 1"));
- for (int i = 0; i < 3; i++) {
- grid.addComponent(new Button("Col " + (grid.getCursorX() + 1)));
- }
-
- /* Fill out the first column using coordinates. */
- for (int i = 1; i < 4; i++) {
- grid.addComponent(new Button("Row " + i), 0, i);
- }
-
- /* Add some components of various shapes. */
- grid.addComponent(new Button("3x1 button"), 1, 1, 3, 1);
- grid.addComponent(new Label("1x2 cell"), 1, 2, 1, 3);
- final InlineDateField date = new InlineDateField("A 2x2 date field");
- date.setResolution(DateField.RESOLUTION_DAY);
- grid.addComponent(date, 2, 2, 3, 3);
-
- main.addComponent(grid);
- }
-
- void example_Alignment(Window main, String param) {
- if (param.equals("grid")) {
- /* Create a 3 by 3 grid layout. */
- final GridLayout layout = new GridLayout(3, 3);
- // OrderedLayout layout = new
- // OrderedLayout(OrderedLayout.ORIENTATION_VERTICAL);
- main.setLayout(layout);
- layout.addStyleName("example-alignment");
-
- layout.setWidth(400, Sizeable.UNITS_PIXELS);
- layout.setHeight(400, Sizeable.UNITS_PIXELS);
-
- /* Define cells and their layouts to create. */
-
- Object cells[][] = {
- { new Button("Top Left"),
- new Integer(AlignmentHandler.ALIGNMENT_LEFT),
- new Integer(AlignmentHandler.ALIGNMENT_TOP) },
- {
- new Label("Top Center"),
- new Integer(
- AlignmentHandler.ALIGNMENT_HORIZONTAL_CENTER),
- new Integer(AlignmentHandler.ALIGNMENT_TOP) },
- { new Label("Top Right"),
- new Integer(AlignmentHandler.ALIGNMENT_RIGHT),
- new Integer(AlignmentHandler.ALIGNMENT_TOP) },
- {
- new Button("Center Left"),
- new Integer(AlignmentHandler.ALIGNMENT_LEFT),
- new Integer(
- AlignmentHandler.ALIGNMENT_VERTICAL_CENTER) },
- {
- new Button("Center Center"),
- new Integer(
- AlignmentHandler.ALIGNMENT_HORIZONTAL_CENTER),
- new Integer(
- AlignmentHandler.ALIGNMENT_VERTICAL_CENTER) },
- {
- new Button("Center Right"),
- new Integer(AlignmentHandler.ALIGNMENT_RIGHT),
- new Integer(
- AlignmentHandler.ALIGNMENT_VERTICAL_CENTER) },
- { new Button("Bottom Left"),
- new Integer(AlignmentHandler.ALIGNMENT_LEFT),
- new Integer(AlignmentHandler.ALIGNMENT_BOTTOM) },
- {
- new Button("Bottom Center"),
- new Integer(
- AlignmentHandler.ALIGNMENT_HORIZONTAL_CENTER),
- new Integer(AlignmentHandler.ALIGNMENT_BOTTOM) },
- { new Button("Bottom Right"),
- new Integer(AlignmentHandler.ALIGNMENT_RIGHT),
- new Integer(AlignmentHandler.ALIGNMENT_BOTTOM) } };
-
- for (int i = 0; i < 9; i++) {
- HorizontalLayout celllayout = new HorizontalLayout();
- celllayout.addComponent((Component) cells[i][0]);
- if (i == 0) {
- celllayout.setExpandRatio((Component) cells[i][0], 1);
- }
-
- celllayout.setComponentAlignment((Component) cells[i][0],
- ((Integer) cells[i][1]).intValue(),
- ((Integer) cells[i][2]).intValue());
- layout.addComponent(celllayout);
- // layout.setComponentAlignment((Component)cells[i][0],
- // ((Integer)cells[i][1]).intValue(),
- // ((Integer)cells[i][2]).intValue());
- }
- } else {
- final Panel panel = new Panel("A Panel with a Layout");
- main.addComponent(panel);
-
- // panel.addComponent(new )
- }
- }
-
- void example_OrderedLayout(Window main, String param) {
- final VerticalLayout layout = new VerticalLayout();
- layout.addComponent(new TextField("Name"));
- layout.addComponent(new TextField("Street address"));
- layout.addComponent(new TextField("Postal code"));
- main.addComponent(layout);
- }
-
- void example_FormLayout(Window main, String param) {
- final FormLayout layout = new FormLayout();
- layout.addComponent(new TextField("Text Field"));
- layout.addComponent(new CheckBox("Check Box"));
- layout.addComponent(new Select("Select"));
- main.addComponent(layout);
- }
-
- void example_Form(Window main, String param) {
- if (param != null && param.equals("simple")) {
- main.addComponent(new FormExample2());
- } else if (param != null && param.equals("layout")) {
- Form form = new Form();
- form.setCaption("Form Caption");
- form
- .setDescription("This is a description of the Form that is "
- + "displayed in the upper part of the form. You normally enter some "
- + "descriptive text about the form and its use here.");
-
- // Add a field directly to the layout. This field will not be bound
- // to
- // the data source Item of the form.
- form.getLayout().addComponent(new TextField("A Field"));
-
- // Add a field and bind it to an named item property.
- form.addField("another", new TextField("Another Field"));
-
- form.setComponentError(new UserError(
- "This is the error indicator of the Form."));
-
- // Set the footer layout and add some text.
- form.setFooter(new VerticalLayout());
- form
- .getFooter()
- .addComponent(
- new Label(
- "This is the footer area of the Form. "
- + "You can use any layout here. This is nice for buttons."));
-
- // Add an Ok (commit), Reset (discard), and Cancel buttons for the
- // form.
- HorizontalLayout okbar = new HorizontalLayout();
- okbar.setHeight("25px");
- Button okbutton = new Button("OK", form, "commit");
- okbar.addComponent(okbutton);
- okbar.setExpandRatio(okbutton, 1);
- okbar.setComponentAlignment(okbutton,
- AlignmentHandler.ALIGNMENT_RIGHT,
- AlignmentHandler.ALIGNMENT_TOP);
- okbar.addComponent(new Button("Reset", form, "discard"));
- okbar.addComponent(new Button("Cancel"));
- form.getFooter().addComponent(okbar);
-
- main.addComponent(form);
- } else {
- main.addComponent(new FormExample());
- }
- }
-
- void example_ExpandLayout(Window main, String param) {
- if (param != null && param.equals("centered")) {
- Label widget = new Label("Here is text");
-
- HorizontalLayout layout = new HorizontalLayout();
- layout.addComponent(widget);
- layout.setExpandRatio(widget, 1);
- layout.setComponentAlignment(widget,
- AlignmentHandler.ALIGNMENT_HORIZONTAL_CENTER,
- AlignmentHandler.ALIGNMENT_VERTICAL_CENTER);
- layout.setWidth(100, Sizeable.UNITS_PERCENTAGE);
- layout.setHeight(100, Sizeable.UNITS_PERCENTAGE);
-
- main.setLayout(layout);
-
- return;
- } else if (param != null && param.equals("window")) {
- Window window = new Window("Progress");
- window.setHeight(100, Sizeable.UNITS_PIXELS);
- window.setWidth(200, Sizeable.UNITS_PIXELS);
- main.addWindow(window);
-
- ProgressIndicator progress = new ProgressIndicator(new Float(0.4));
- progress.addStyleName("fullwidth");
- progress.setPollingInterval(1000000);
- progress.setIndeterminate(false);
-
- HorizontalLayout layout = new HorizontalLayout();
- layout.setHeight(100, Sizeable.UNITS_PERCENTAGE);
- layout.setComponentAlignment(progress,
- HorizontalLayout.ALIGNMENT_HORIZONTAL_CENTER,
- HorizontalLayout.ALIGNMENT_VERTICAL_CENTER);
- window.setLayout(layout);
- window.addComponent(progress);
-
- return;
- } else if (param != null && param.equals("root")) {
- final Window mainwin = main;
-
- // Layout to switch to
- final VerticalLayout expand2 = new VerticalLayout();
- expand2.addComponent(new Label("I am layout too."));
-
- // Original layout
- final VerticalLayout expand1 = new VerticalLayout();
- Button switchButton = new Button("Switch to other layout");
- switchButton.addListener(new Button.ClickListener() {
- public void buttonClick(ClickEvent event) {
- mainwin.setLayout(null);
- mainwin.setLayout(expand2);
- }
- });
- expand1.addComponent(switchButton);
- main.setLayout(expand1);
-
- return;
- } else if (param != null && param.equals("size")) {
- VerticalLayout layout = new VerticalLayout();
- layout.setSizeFull();
- main.setLayout(layout);
-
- Button button = new Button("This is a button in middle of nowhere");
- layout.addComponent(button);
- layout.setComponentAlignment(button,
- VerticalLayout.ALIGNMENT_HORIZONTAL_CENTER,
- VerticalLayout.ALIGNMENT_VERTICAL_CENTER);
- layout.setExpandRatio(button, 1.0f);
- return;
- }
-
- for (int w = 0; w < 2; w++) {
- final VerticalLayout layout = new VerticalLayout();
-
- /* Set the expanding layout as the root layout of a child window. */
- final Window window = new Window("A Child Window", layout);
- main.addWindow(window);
-
- /* Add some component above the expanding one. */
- layout.addComponent(new Label("Here be some component."));
-
- /* Create the expanding component. */
- final Table table = new Table("My Ever-Expanding Table");
- /*
- * FIXME Java 5 -> 1.4 for (int i=0; i<5; i++)
- * table.addContainerProperty("col "+(i+1), Integer.class, 0); for
- * (int j=0; j<20; j++) table.addItem(new Object[]{1j,2j,3j,4j,5j},
- * j);
- */
- layout.addComponent(table);
-
- /* Designate the table to be the expanding component. */
- layout.setExpandRatio(table, 1.0f);
-
- /* Set it to use all available area. */
- table.setSizeFull();
-
- /* Add some component below the expanding one. */
- final Button button2 = new Button("Ok");
- layout.addComponent(button2);
- layout.setComponentAlignment(button2,
- AlignmentHandler.ALIGNMENT_RIGHT, 0);
- }
- }
-
- void example_TabSheet(Window main, String param) {
- if (param.equals("icon")) {
- final TabSheet tabsheet = new TabSheet();
-
- tabsheet.addTab(new Label("Contents of the first tab"),
- "First Tab", new ClassResource("images/Mercury_small.png",
- main.getApplication()));
- tabsheet.addTab(new Label("Contents of the second tab"),
- "Second Tab", new ClassResource("images/Venus_small.png",
- this));
- tabsheet.addTab(new Label("Contents of the third tab"),
- "Third tab", new ClassResource("images/Earth_small.png",
- this));
-
- main.addComponent(tabsheet);
- // main.addComponent(new Embedded("Emb", new ClassResource
- // ("images/Mercury_small.png", this)));
- } else if (param.equals("expanding")) {
- // Create the layout
- VerticalLayout expanding = new VerticalLayout();
-
- // It is important to set the expanding layout as the root layout
- // of the containing window, in this case the main window, and not
- // use addComponent(), which would place the layout inside the
- // default root layout.
- main.setLayout(expanding);
-
- // Create a tab sheet that fills the expanding layout
- final TabSheet tabsheet = new TabSheet();
- tabsheet.addTab(new Label("Contents of the first tab"),
- "First Tab", null);
- tabsheet.addTab(new Label("Contents of the second tab"),
- "Second Tab", null);
- tabsheet.addTab(new Label("Contents of the third tab"),
- "Third tab", null);
-
- // Set the tabsheet to scale to full size inside its container
- tabsheet.setWidth(100, Sizeable.UNITS_PERCENTAGE);
- tabsheet.setHeight(100, Sizeable.UNITS_PERCENTAGE);
-
- // Add the tab sheet to the layout as usual
- expanding.addComponent(tabsheet);
-
- // Set the tab sheet to be the expanding component
- expanding.setExpandRatio(tabsheet, 1);
- } else if (param.equals("ordered")) {
- // Create the layout
- VerticalLayout layout = new VerticalLayout();
-
- // It is important to set the expanding layout as the root layout
- // of the containing window, in this case the main window, and not
- // use addComponent(), which would place the layout inside the
- // default root layout.
- main.setLayout(layout);
-
- // Create a tab sheet that fills the expanding layout
- final TabSheet tabsheet = new TabSheet();
- tabsheet.addTab(new Label("Contents of the first tab"),
- "First Tab", null);
- tabsheet.addTab(new Label("Contents of the second tab"),
- "Second Tab", null);
- tabsheet.addTab(new Label("Contents of the third tab"),
- "Third tab", null);
-
- // Set the tabsheet to scale to full size inside its container
- tabsheet.setWidth(100, Sizeable.UNITS_PERCENTAGE);
- // tabsheet().setHeight(100, Sizeable.UNITS_PERCENTAGE);
-
- // Add the tab sheet to the layout as usual
- layout.addComponent(tabsheet);
- } else {
- main.addComponent(new TabSheetExample());
- }
- }
-
- void example_Embedded(Window main, String param) {
- final Embedded image = new Embedded("", new ClassResource("smiley.jpg",
- this));
- image.addStyleName("omaimage");
- main.addComponent(image);
-
- final EmbeddedButton button = new EmbeddedButton(new ClassResource(
- "smiley.jpg", this));
- main.addComponent(button);
- }
-
- void example_Window(Window main, String param) {
- if (param != null) {
- if (param.equals("opener")) {
- main.addComponent(new WindowOpener("Window Opener", main));
- } else if (param.equals("multiple")) {
- /* Create a new window. */
- final Window mywindow = new Window("Second Window");
- mywindow.setName("mywindow");
- mywindow.addComponent(new Label("This is a second window."));
-
- /* Add the window to the application. */
- main.getApplication().addWindow(mywindow);
-
- /* Add link to the second window in the main window. */
- main.addComponent(new Label("Second window: <a href='"
- + mywindow.getURL() + "'>middle-click to open</a>",
- Label.CONTENT_XHTML));
- main.addComponent(new Label(
- "The second window can be accessed through URL: "
- + mywindow.getURL()));
- }
- return;
- }
-
- /* Create a new window. */
- final Window mywindow = new Window("My Window");
- mywindow.setName("mywindow");
-
- /* Add some components in the window. */
- mywindow.addComponent(new Label("A text label in the window."));
- final Button okbutton = new Button("OK");
- mywindow.addComponent(okbutton);
-
- /* Set window size. */
- mywindow.setHeight("200px");
- mywindow.setWidth("400px");
-
- /* Set window position. */
- mywindow.setPositionX(200);
- mywindow.setPositionY(50);
-
- /* Add the window to the Application object. */
- main.addWindow(mywindow);
-
- }
-
- void example_ClassResource(Window main, String param) {
- final DateField df = new DateField();
- main.addComponent(df);
- df.setIcon(new ClassResource("smiley.jpg", main.getApplication()));
- main.addComponent(new Embedded("This is Embedded", new ClassResource(
- "smiley.jpg", main.getApplication())));
- }
-
- void example_ProgressIndicator(final Window main, String param) {
- if (param != null) {
- if (param.equals("thread")) {
-
- // Create the indicator
- final ProgressIndicator indicator = new ProgressIndicator(
- new Float(0.0));
- main.addComponent(indicator);
-
- // Set polling frequency to 0.5 seconds.
- indicator.setPollingInterval(1000);
-
- // indicator.addStyleName("invisible");
- final Label text = new Label("-- Not running --");
- main.addComponent(text);
-
- // Add a button to start the progress
- final Button button = new Button("Click to start");
- main.addComponent(button);
-
- // Another thread to do some work
- class WorkThread extends Thread {
- public void run() {
- double current = 0.0;
- while (true) {
- // Do some "heavy work"
- try {
- sleep(50); // Sleep for 50 milliseconds
- } catch (InterruptedException e) {
- }
-
- // Grow the progress value until it reaches 1.0.
- current += 0.01;
- if (current > 1.0) {
- indicator.setValue(new Float(1.0));
- } else {
- indicator.setValue(new Float(current));
- }
-
- // After the progress is full for a while, stop.
- if (current > 1.2) {
- // Restore the state to initial.
- indicator.setValue(new Float(0.0));
- button.setVisible(true);
- break;
- }
- }
- }
- }
-
- // Clicking the button creates and runs a work thread
- button.addListener(new Button.ClickListener() {
- public void buttonClick(ClickEvent event) {
- final WorkThread thread = new WorkThread();
- thread.start();
-
- // The button hides until the work is done.
- button.setVisible(false);
- }
- });
- } else if (param.equals("window")) {
- // Create a table in the main window to hold items added in the
- // second window
- final Table table = new Table();
- table.setPageLength(5);
- table.setWidth(100, Sizeable.UNITS_PERCENTAGE);
- table.addContainerProperty("Name", String.class, "");
- main.addComponent(table);
-
- // Create the second window
- final Window adderWindow = new Window("Add Items");
- adderWindow.setName("win-adder");
- main.getApplication().addWindow(adderWindow);
-
- // Create selection component to add items to the table
- final NativeSelect select = new NativeSelect(
- "Select item to add");
- select.setImmediate(true);
- adderWindow.addComponent(select);
-
- // Add some items to the selection
- String items[] = new String[] { "-- Select --", "Mercury",
- "Venus", "Earth", "Mars", "Jupiter", "Saturn",
- "Uranus", "Neptune" };
- for (int i = 0; i < items.length; i++) {
- select.addItem(items[i]);
- }
- select.setNullSelectionItemId(items[0]);
-
- // When an item is selected in the second window, add
- // table in the main window
- select.addListener(new ValueChangeListener() {
- public void valueChange(ValueChangeEvent event) {
- // If the selected value is something else but null
- // selection item.
- if (select.getValue() != null) {
- // Add the selected item to the table in the main
- // window
- table.addItem(new Object[] { select.getValue() },
- new Integer(table.size()));
- }
- }
- });
-
- // Link to open the selection window
- Link link = new Link("Click to open second window",
- new ExternalResource(adderWindow.getURL()), "_new", 50,
- 200, Link.TARGET_BORDER_DEFAULT);
- main.addComponent(link);
-
- // Enable polling to update the main window
- ProgressIndicator poller = new ProgressIndicator();
- poller.addStyleName("invisible");
- main.addComponent(poller);
- } else if (param.equals("centered")) {
- /*
- * GridLayout grid = new GridLayout(3,3); main.setLayout(grid);
- * grid().setWidth(100, Sizeable.UNITS_PERCENTAGE);
- *
- * ExpandLayout layout2 = new
- * ExpandLayout(OrderedLayout.ORIENTATION_HORIZONTAL);
- * layout2().setWidth(50, Sizeable.UNITS_PERCENTAGE);
- *
- * ProgressIndicator poller = new ProgressIndicator(new
- * Float(0.4)); poller.setPollingInterval(1000000);
- * poller.setIndeterminate(false); layout2.addComponent(poller);
- *
- * grid.addComponent(layout2, 1, 1);
- */
-
- // ExpandLayout layout2 = new
- // ExpandLayout(OrderedLayout.ORIENTATION_HORIZONTAL);
- /*
- * ProgressIndicator poller = new ProgressIndicator(new
- * Float(0.4)); poller.setPollingInterval(1000000);
- * poller.setIndeterminate(false);
- */
- /*
- * layout2.addComponent(poller); layout2().setWidth(50,
- * Sizeable.UNITS_PERCENTAGE);
- */
-
- // layout.setComponentAlignment(poller,
- // AlignmentHandler.ALIGNMENT_HORIZONTAL_CENTER,
- // AlignmentHandler.ALIGNMENT_VERTICAL_CENTER);
- /*
- * GridLayout grid = new GridLayout(1,1);
- * grid.addComponent(layout2, 0, 0); grid().setWidth(100,
- * Sizeable.UNITS_PERCENTAGE);
- */
-
- /*
- * GridLayout layout = new GridLayout(1,1);
- * //OrderedLayout.ORIENTATION_HORIZONTAL);
- * layout.addComponent(poller); //layout.expand(poller);
- * layout.setComponentAlignment(poller,
- * AlignmentHandler.ALIGNMENT_HORIZONTAL_CENTER,
- * AlignmentHandler.ALIGNMENT_VERTICAL_CENTER);
- * layout().setWidth(100, Sizeable.UNITS_PERCENTAGE);
- * layout().setHeight(100, Sizeable.UNITS_PERCENTAGE);
- */
-
- }
- } else {
- ProgressIndicator poller = new ProgressIndicator(new Float(0.0));
- poller.setPollingInterval(1000000);
- poller.setIndeterminate(true);
- main.addComponent(poller);
- }
- }
-
- void example_CustomLayout(final Window main, String param) {
- Window sub = new Window("Login");
- sub.setModal(true);
- main.addWindow(sub);
-
- // Create the custom layout and set it as the root layout of
- // the containing window.
- final CustomLayout custom = new CustomLayout("layoutname");
- sub.setLayout(custom);
-
- // Create components and bind them to the location tags
- // in the custom layout.
- TextField username = new TextField();
- custom.addComponent(username, "username");
-
- TextField password = new TextField();
- custom.addComponent(password, "password");
-
- final Button ok = new Button("Login");
- custom.addComponent(ok, "okbutton");
-
- final Button deny = new Button("No can do!");
-
- Button.ClickListener listener = new Button.ClickListener() {
- public void buttonClick(ClickEvent event) {
- // Switch between ok and deny
- if (custom.getComponent("okbutton") == ok) {
- System.out.println("Changing to deny button.");
- custom.addComponent(deny, "okbutton");
- } else {
- System.out.println("Changing to ok button.");
- custom.addComponent(ok, "okbutton");
- }
- }
- };
-
- ok.addListener(listener);
- deny.addListener(listener);
- }
-
- void example_Spacing(final Window main, String param) {
- VerticalLayout containinglayout = new VerticalLayout();
- main.setLayout(containinglayout);
-
- GridLayout grid = new GridLayout(4, 3);
- grid.addStyleName("spacingexample");
- containinglayout.addComponent(grid);
- grid.addComponent(new Label(""), 0, 0);
- grid.addComponent(new Label(""), 1, 0);
-
- grid.addComponent(new Label("No spacing:"), 0, 1);
- HorizontalLayout layout1 = new HorizontalLayout();
- grid.addComponent(layout1, 1, 1);
- layout1.addStyleName("spacingexample");
- layout1.addComponent(new Button("Component 1"));
- layout1.addComponent(new Button("Component 2"));
- layout1.addComponent(new Button("Component 3"));
-
- grid.addComponent(new Label("Horizontal spacing:"), 0, 2);
- HorizontalLayout layout2 = new HorizontalLayout();
- grid.addComponent(layout2, 1, 2);
- layout2.addStyleName("spacingexample");
- layout2.setSpacing(true);
- layout2.addComponent(new Button("Component 1"));
- layout2.addComponent(new Button("Component 2"));
- layout2.addComponent(new Button("Component 3"));
-
- grid.addComponent(new Label("No spacing:"), 2, 0);
- VerticalLayout layout3 = new VerticalLayout();
- grid.addComponent(layout3, 2, 1, 2, 2);
- layout3.addStyleName("spacingexample");
- layout3.addComponent(new Button("Component 1"));
- layout3.addComponent(new Button("Component 2"));
- layout3.addComponent(new Button("Component 3"));
-
- grid.addComponent(new Label("Vertical spacing:"), 3, 0);
- VerticalLayout layout4 = new VerticalLayout();
- grid.addComponent(layout4, 3, 1, 3, 2);
- layout4.addStyleName("spacingexample");
- layout4.setSpacing(true);
- layout4.addComponent(new Button("Component 1"));
- layout4.addComponent(new Button("Component 2"));
- layout4.addComponent(new Button("Component 3"));
- }
-
- void example_Margin(final Window main, String param) {
- HorizontalLayout hor = new HorizontalLayout();
- main.setLayout(hor);
-
- VerticalLayout containinglayout = new VerticalLayout();
- hor.addComponent(containinglayout);
-
- VerticalLayout layout1 = new VerticalLayout();
- containinglayout.addComponent(new Label("Regular layout margins:"));
- containinglayout.addComponent(layout1);
- layout1.addStyleName("marginexample1");
- layout1.addComponent(new Button("Component 1"));
- layout1.addComponent(new Button("Component 2"));
- layout1.addComponent(new Button("Component 3"));
-
- // Create a layout
- VerticalLayout layout2 = new VerticalLayout();
- containinglayout.addComponent(new Label(
- "Layout with a special margin element:"));
- containinglayout.addComponent(layout2);
-
- // Set style name for the layout to allow styling it
- layout2.addStyleName("marginexample2");
-
- // Have margin on all sides around the layout
- layout2.setMargin(true);
-
- // Put something inside the layout
- layout2.addComponent(new Button("Component 1"));
- layout2.addComponent(new Button("Component 2"));
- layout2.addComponent(new Button("Component 3"));
- }
-
- void example_ClientInfo(final Window main, String param) {
- // Get the client identification string
- WebApplicationContext context2 = (WebApplicationContext) getContext();
- String browserApplication = context2.getBrowser()
- .getBrowserApplication();
-
- // Add a browser-dependent style name for the main window
- if (browserApplication.indexOf("Firefox/2") != -1) {
- main.addStyleName("firefox2");
- }
-
- // Display the client identification string
- main.addComponent(new Label(browserApplication));
- }
-
- void example_FillInForm(final Window main, String param) {
- if (param.equals("templates")) {
- // Create a custom layout from the fill-in-form.html template.
- CustomLayout fillinlayout = new CustomLayout("fill-in-form");
-
- // The style will set the display to be "inline".
- fillinlayout.addStyleName("fillinlayout");
-
- // Create the fields that occur in the text.
- TextField field1 = new TextField();
- TextField field2 = new TextField();
- fillinlayout.addComponent(field1, "q1");
- fillinlayout.addComponent(field2, "q2");
-
- main.addComponent(fillinlayout);
- } else {
- String fillintext = "The <q1> is mightier than <q2>.";
- int pos = 0;
- while (pos < fillintext.length()) {
- int nexttag = fillintext.indexOf("<", pos);
- if (nexttag == -1) {
-
- }
- }
- }
- }
-
- void example_Notification(final Window main, String param) {
- //final Window sub1 = new Window("");
- //main.addWindow(sub1);
- if (param.equals("example")) {
- main.showNotification("This is the caption",
- "This is the description");
- return;
- } else if (param.equals("type")) {
- main.showNotification("This is a warning",
- "<br/>This is the <i>last</i> warning",
- Window.Notification.TYPE_WARNING_MESSAGE);
- return;
- } else if (param.equals("pos")) {
- // Create a notification with the default settings for a warning.
- Window.Notification notif = new Window.Notification(
- "Be warned!", "This message lurks in the top-left corner!",
- Window.Notification.TYPE_WARNING_MESSAGE);
-
- // Set the position.
- notif.setPosition(Window.Notification.POSITION_TOP_LEFT);
-
- // Let it stay there until the user clicks it
- notif.setDelayMsec(-1);
-
- // Show it in the main window.
- main.showNotification(notif);
- return;
- }
-
- main.setLayout(new HorizontalLayout());
-
- final Integer type_humanized = Window.Notification.TYPE_HUMANIZED_MESSAGE;
- final Integer type_warning = Window.Notification.TYPE_WARNING_MESSAGE;
- final Integer type_error = Window.Notification.TYPE_ERROR_MESSAGE;
- final Integer type_tray = Window.Notification.TYPE_TRAY_NOTIFICATION;
- final NativeSelect types = new NativeSelect();
- main.addComponent(types);
- types.addItem(type_humanized);
- types.addItem(type_warning);
- types.addItem(type_error);
- types.addItem(type_tray);
- types.setItemCaption(type_humanized, "Humanized");
- types.setItemCaption(type_warning, "Warning");
- types.setItemCaption(type_error, "Error");
- types.setItemCaption(type_tray, "Tray");
-
- Button show = new Button("Show Notification");
- main.addComponent(show);
-
- show.addListener(new Button.ClickListener() {
- public void buttonClick(ClickEvent event) {
- String caption = "";
- String description = "";
- switch(((Integer)types.getValue()).intValue()) {
- case Window.Notification.TYPE_HUMANIZED_MESSAGE:
- caption = "Humanized message";
- description = "<br/>For minimal annoyance";
- break;
- case Window.Notification.TYPE_WARNING_MESSAGE:
- caption = "Warning message";
- description = "<br/>For notifications of medium importance";
- break;
- case Window.Notification.TYPE_ERROR_MESSAGE:
- caption = "Error message";
- description = "<br/>For important notifications";
- break;
- case Window.Notification.TYPE_TRAY_NOTIFICATION:
- caption = "Tray notification";
- description = "<br/>Stays up longer - but away";
- }
- // main.showNotification("The default notification");
- Window.Notification notif = new Window.Notification(
- caption, description, (Integer)types.getValue());
- //notif.setPosition(Window.Notification.POSITION_TOP_LEFT);
- notif.setDelayMsec(-1);
- main.showNotification(notif);
- }
- });
-
- // Notification notif = new Notification("Title");
- }
-
- void example_Print(final Window main, String param) {
- if (param != null && param.equals("simple")) {
- main
- .addComponent(new Label(
- "<input type='button' onClick='print()' value='Click to Print'/>",
- Label.CONTENT_XHTML));
- return;
- }
-
- // A button to open the printer-friendly page.
- Button printButton = new Button("Click to Print");
- main.addComponent(printButton);
- printButton.addListener(new Button.ClickListener() {
- public void buttonClick(ClickEvent event) {
- // Create a window that contains stuff you want to print.
- Window printWindow = new Window("Window to Print");
-
- // Have some content to print.
- printWindow.addComponent(new Label(
- "Here's some dynamic content."));
-
- // To execute the print() JavaScript, we need to run it
- // from a custom layout.
- CustomLayout scriptLayout = new CustomLayout("printpage");
- printWindow.addComponent(scriptLayout);
-
- // Add the printing window as an application-level window.
- main.getApplication().addWindow(printWindow);
-
- // Open the printing window as a new browser window
- main.open(new ExternalResource(printWindow.getURL()), "_new");
- }
- });
-
- // main.addComponent(new
- // Label("<p>Print this!</p>\n<script type='text/javascript'>print();</script>",
- // Label.CONTENT_XHTML));
- }
-
- void example_RichTextArea(final Window main, String param) {
- main.setLayout(new HorizontalLayout());
-
- // Create a rich text area
- final RichTextArea rtarea = new RichTextArea();
- rtarea.addStyleName("richtextexample");
- // rtarea.setCaption("My Rich Text Area");
-
- // Set initial content as HTML
- rtarea
- .setValue("<h1>Hello</h1>\n<p>This rich text area contains some text.</p>");
-
- // Show the text edited in the rich text area as HTML.
- final Button show = new Button("Show HTML");
- final Label html = new Label((String) rtarea.getValue());
- show.addListener(new Button.ClickListener() {
- public void buttonClick(ClickEvent event) {
- html.setValue(rtarea.getValue());
- }
- });
-
- Panel rtPanel = new Panel("Rich Text Area");
- rtPanel.addComponent(rtarea);
- rtPanel.addComponent(show);
-
- Panel valuePanel = new Panel("Value");
- valuePanel.addComponent(html);
-
- main.addComponent(rtPanel);
- main.addComponent(valuePanel);
- }
-
- void example_QueryContainer(final Window main, String param) {
- try {
- // Create a database connection
- Class.forName("org.hsqldb.jdbcDriver");
- final Connection connection = DriverManager.getConnection(
- "jdbc:hsqldb:mem:qcexample", "sa", "");
-
- // Create an example table and put some data in it.
- Statement st = connection.createStatement();
- st
- .executeQuery("CREATE TABLE Prisoners (id INTEGER, name VARCHAR)");
- st.close();
- for (int i = 0; i < 100; i++) {
- st = connection.createStatement();
- st.executeQuery("INSERT INTO Prisoners (id, name) VALUES (" + i
- + ",'I am number " + (i + 1) + "')");
- st.close();
- }
-
- // Query the database
- final QueryContainer qc = new QueryContainer(
- "SELECT id,name FROM Prisoners", connection);
-
- // Create a component for selecting a query result item.
- Select select = new Select("Select an item");
-
- // The items shown in the selection component are obtained from the
- // query.
- select.setContainerDataSource(qc);
-
- // The item captions are obtained from a field in the query result.
- select.setItemCaptionMode(Select.ITEM_CAPTION_MODE_PROPERTY);
-
- // Set the name of the field from which the item captions are
- // obtained.
- select.setItemCaptionPropertyId("name");
-
- // When selection changes, display the selected item.
- select.setImmediate(true);
- final Label selection = new Label("Currently selected: -");
- select.addListener(new ValueChangeListener() {
- public void valueChange(ValueChangeEvent event) {
- // Get the item id of the currently selected item
- Integer itemId = (Integer) event.getProperty().getValue();
-
- // Use the item ID to get the actual row from the query
- // result.
- Item qrItem = qc.getItem(itemId);
-
- // Display the item ID
- selection.setValue("Currently selected: result row "
- + itemId.intValue() + " (id="
- + qrItem.getItemProperty("id") + ", " + "name="
- + qrItem.getItemProperty("name") + ")");
- }
- });
-
- main.addComponent(select);
- main.addComponent(selection);
- } catch (SQLException e) {
- e.printStackTrace();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- }
-
- void example_MenuBar(final Window main, String param) {
- // Create a menu bar
- final MenuBar menubar = new MenuBar();
- main.addComponent(menubar);
-
- // A feedback component
- final Label selection = new Label("");
- main.addComponent(selection);
-
- // Define a common menu command for all the menu items.
- MenuBar.Command mycommand = new MenuBar.Command() {
- public void menuSelected(MenuItem selectedItem) {
- selection.setValue("Ordered a " + selectedItem.getText()
- + " from menu.");
- }
- };
-
- // Put some items in the menu hierarchically
- MenuBar.MenuItem beverages = menubar.addItem("Beverages", null, null);
- MenuBar.MenuItem hot_beverages = beverages.addItem("Hot", null, null);
- hot_beverages.addItem("Tea", null, mycommand);
- hot_beverages.addItem("Coffee", null, mycommand);
- MenuBar.MenuItem cold_beverages = beverages.addItem("Cold", null, null);
- cold_beverages.addItem("Milk", null, mycommand);
-
- // Another top-level item
- MenuBar.MenuItem snacks = menubar.addItem("Snacks", null, null);
- snacks.addItem("Weisswurst", null, mycommand);
- snacks.addItem("Salami", null, mycommand);
-
- // Yet another top-level item
- MenuBar.MenuItem services = menubar.addItem("Services", null, null);
- services.addItem("Car Service", null, mycommand);
- }
+ Window main = new Window("Application window");
+
+ TheButton butts1;
+ TheButtons butts2;
+ TheButtons2 butts3;
+
+ Label mylabel1;
+ Label mylabel2;
+ Label mylabel3;
+
+ StreamResource strres;
+ VerticalLayout ol;
+ int getwincount = 0;
+
+ @Override
+ public void init() {
+ setTheme("tests-book");
+
+ setMainWindow(main);
+
+ // Demo the use of parameter and URI handlers
+ main.addParameterHandler(new MyParameterHandler());
+ main.addURIHandler(new MyURIHandler());
+
+ MyDynamicResource myresource = new MyDynamicResource();
+ main.addParameterHandler(myresource);
+ main.addURIHandler(myresource);
+
+ main.addURIHandler(new BookTestURIHandler());
+ }
+
+ class MyParameterHandler implements ParameterHandler {
+ public void handleParameters(Map parameters) {
+ // Print out the parameters to standard output
+ for (Iterator it = parameters.keySet().iterator(); it.hasNext();) {
+ String key = (String) it.next();
+ String value = ((String[]) parameters.get(key))[0];
+ System.out.println("Key: " + key + ", value: " + value);
+ }
+ }
+ }
+
+ class MyURIHandler implements URIHandler {
+ public DownloadStream handleURI(URL context, String relativeUri) {
+ System.out.println("Context: " + context.toString()
+ + ", relative: " + relativeUri);
+ return null; // Let the Application provide the response
+ }
+ }
+
+ class BookTestURIHandler implements URIHandler {
+ public DownloadStream handleURI(URL context, String relativeUri) {
+ String example;
+ String param = null;
+
+ final int slashPos = relativeUri.indexOf("/");
+ if (slashPos > 0) {
+ example = relativeUri.substring(0, slashPos);
+ param = relativeUri.substring(slashPos + 1);
+ } else {
+ example = relativeUri;
+ }
+
+ /* Remove existing components and windows. */
+ main.removeAllComponents();
+ final Set childwindows = main.getChildWindows();
+ for (final Iterator cwi = childwindows.iterator(); cwi.hasNext();) {
+ final Window child = (Window) cwi.next();
+ main.removeWindow(child);
+ }
+
+ // The index is listed inside a grid layout
+ main.setLayout(new VerticalLayout());
+ GridLayout grid = new GridLayout(4, 4);
+ grid.addStyleName("index");
+ main.addComponent(grid);
+
+ if (example.equals("index")) {
+ final String examples[] = { "defaultbutton", "label",
+ "labelcontent", "tree", "embedded", "textfield",
+ "textfieldvalidation", "datefield", "button",
+ "select/select", "select/native", "select/optiongroup",
+ "select/twincol", "filterselect", "validator", "table",
+ "table/select", "table/component", "table/paging",
+ "table/editable", "upload", "link", "gridlayout",
+ "orderedlayout", "formlayout", "form", "form/simple",
+ "form/layout", "panel", "expandlayout",
+ "expandlayout/root", "tabsheet", "alignment",
+ "alignment/grid", "window", "window/opener",
+ "window/multiple", "classresource", "usererror",
+ "progress/window", "progress/thread", "progress",
+ "customlayout", "spacing", "margin", "clientinfo",
+ "fillinform/templates", "notification", "print",
+ "richtextfield", "querycontainer", "menubar" };
+ for (int i = 0; i < examples.length; i++) {
+ grid.addComponent(new Label("<a href='"
+ + context.toString() + examples[i] + "'>"
+ + examples[i] + "</a>", Label.CONTENT_XHTML));
+ }
+ return null;
+ }
+
+ if (example.equals("defaultbutton")) {
+ example_defaultButton(main, param);
+ } else if (example.equals("label")) {
+ example_Label(main, param);
+ } else if (example.equals("labelcontent")) {
+ example_LabelContent(main, param);
+ } else if (example.equals("tree")) {
+ example_Tree(main, param);
+ } else if (example.equals("embedded")) {
+ example_Embedded(main, param);
+ } else if (example.equals("textfield")) {
+ example_TextField(main, param);
+ } else if (example.equals("textfieldvalidation")) {
+ example_TextFieldValidation(main, param);
+ } else if (example.equals("usererror")) {
+ example_UserError(main, param);
+ } else if (example.equals("datefield")) {
+ example_DateField(main, param);
+ } else if (example.equals("button")) {
+ example_Button(main, param);
+ } else if (example.equals("checkbox")) {
+ example_CheckBox(main, param);
+ } else if (example.equals("select")) {
+ example_Select(main, param);
+ } else if (example.equals("filterselect")) {
+ example_FilterSelect(main, param);
+ } else if (example.equals("validator")) {
+ example_Validator(main, param);
+ } else if (example.equals("table")) {
+ example_Table(main, param);
+ } else if (example.equals("upload")) {
+ example_Upload(main, param);
+ } else if (example.equals("link")) {
+ example_Link(main, param);
+ } else if (example.equals("gridlayout")) {
+ example_GridLayout(main, param);
+ } else if (example.equals("orderedlayout")) {
+ example_OrderedLayout(main, param);
+ } else if (example.equals("formlayout")) {
+ example_FormLayout(main, param);
+ } else if (example.equals("form")) {
+ example_Form(main, param);
+ } else if (example.equals("tabsheet")) {
+ example_TabSheet(main, param);
+ } else if (example.equals("panel")) {
+ example_Panel(main, param);
+ } else if (example.equals("expandlayout")) {
+ example_ExpandLayout(main, param);
+ } else if (example.equals("alignment")) {
+ example_Alignment(main, param);
+ } else if (example.equals("window")) {
+ example_Window(main, param);
+ } else if (example.equals("classresource")) {
+ example_ClassResource(main, param);
+ } else if (example.equals("progress")) {
+ example_ProgressIndicator(main, param);
+ } else if (example.equals("customlayout")) {
+ example_CustomLayout(main, param);
+ } else if (example.equals("spacing")) {
+ example_Spacing(main, param);
+ } else if (example.equals("margin")) {
+ example_Margin(main, param);
+ } else if (example.equals("clientinfo")) {
+ example_ClientInfo(main, param);
+ } else if (example.equals("fillinform")) {
+ example_FillInForm(main, param);
+ } else if (example.equals("notification")) {
+ example_Notification(main, param);
+ } else if (example.equals("print")) {
+ example_Print(main, param);
+ } else if (example.equals("richtextfield")) {
+ example_RichTextArea(main, param);
+ } else if (example.equals("querycontainer")) {
+ example_QueryContainer(main, param);
+ } else if (example.equals("menubar")) {
+ example_MenuBar(main, param);
+ } else {
+ ; // main.addComponent(new
+ // Label("Unknown test '"+example+"'."));
+ }
+
+ return null;
+ }
+ }
+
+ /*
+ * public Window getWindow(String name) { Window superwin =
+ * super.getWindow(name); if (superwin != null) return superwin;
+ *
+ * main.addComponent(new Label("Request 2 for window '"+name+"'.")); if
+ * (name.equals("panel")) { Window window = new Window("Other Window " +
+ * getwincount++); example_Panel(window, null); return window; } return
+ * null; }
+ */
+ public void handleButton(Button.ClickEvent event) {
+ ol.addStyleName("myLayout2");
+ }
+
+ void example_defaultButton(Window main, String param) {
+ main.addComponent(new DefaultButtonExample());
+ }
+
+ void example_Label(Window main, String param) {
+ /* Some container for the Label. */
+ final Panel panel = new Panel("Panel Containing a Label");
+ main.addComponent(panel);
+
+ panel.addComponent(new Label(
+ "This is a Label inside a Panel. There is enough "
+ + "text in the label to make the text wrap if it "
+ + "exceeds the width of the panel."));
+ }
+
+ void example_LabelContent(Window main, String param) {
+ final GridLayout labelgrid = new GridLayout(2, 1);
+ labelgrid.addStyleName("labelgrid");
+ labelgrid.addComponent(new Label("CONTENT_DEFAULT"));
+ labelgrid.addComponent(new Label(
+ "This is a label in default mode: <plain text>",
+ Label.CONTENT_DEFAULT));
+ labelgrid.addComponent(new Label("CONTENT_PREFORMATTED"));
+ labelgrid
+ .addComponent(new Label(
+ "This is a preformatted label.\nThe newline character \\n breaks the line.",
+ Label.CONTENT_PREFORMATTED));
+ labelgrid.addComponent(new Label("CONTENT_RAW"));
+ labelgrid
+ .addComponent(new Label(
+ "This is a label in raw mode.<br>It can contain, for example, unbalanced markup.",
+ Label.CONTENT_RAW));
+ labelgrid.addComponent(new Label("CONTENT_TEXT"));
+ labelgrid.addComponent(new Label(
+ "This is a label in (plain) text mode", Label.CONTENT_TEXT));
+ labelgrid.addComponent(new Label("CONTENT_XHTML"));
+ labelgrid.addComponent(new Label(
+ "<i>This</i> is an <b>XHTML<b> formatted label",
+ Label.CONTENT_XHTML));
+ labelgrid.addComponent(new Label("CONTENT_XML"));
+ labelgrid.addComponent(new Label(
+ "This is an <myelement>XML</myelement> formatted label",
+ Label.CONTENT_XML));
+ main.addComponent(labelgrid);
+
+ final ClassResource labelimage = new ClassResource("smiley.jpg", this);
+ main.addComponent(new Label("Here we have an image <img src=\""
+ + getRelativeLocation(labelimage) + "\"/> within some text.",
+ Label.CONTENT_XHTML));
+ }
+
+ void example_Tree(Window main, String param) {
+ final Object[][] planets = new Object[][] {
+ new Object[] { "Mercury" },
+ new Object[] { "Venus" },
+ new Object[] { "Earth", "The Moon" },
+ new Object[] { "Mars", "Phobos", "Deimos" },
+ new Object[] { "Jupiter", "Io", "Europa", "Ganymedes",
+ "Callisto" },
+ new Object[] { "Saturn", "Titan", "Tethys", "Dione", "Rhea",
+ "Iapetus" },
+ new Object[] { "Uranus", "Miranda", "Ariel", "Umbriel",
+ "Titania", "Oberon" },
+ new Object[] { "Neptune", "Triton", "Proteus", "Nereid",
+ "Larissa" } };
+
+ final Tree tree = new Tree();
+
+ // Add planets as root items in the tree.
+ for (int i = 0; i < planets.length; i++) {
+ final String planet = (String) (planets[i][0]);
+ tree.addItem(planet);
+
+ if (planets[i].length == 1) {
+ // The planet has no moons so make it a leaf.
+ tree.setChildrenAllowed(planet, false);
+ } else {
+ // Add children (moons) under the planets.
+ for (int j = 1; j < planets[i].length; j++) {
+ final String moon = (String) planets[i][j];
+
+ // Add the item as a regular item.
+ tree.addItem(moon);
+
+ // Set it to be a child.
+ tree.setParent(moon, planet);
+
+ // Make the moons look like leaves.
+ tree.setChildrenAllowed(moon, false);
+ }
+
+ // Expand the subtree.
+ tree.expandItemsRecursively(planet);
+ }
+ }
+
+ // Horizontal layout with the tree on the left and a details panel on
+ // the right.
+ final HorizontalLayout horlayout = new HorizontalLayout();
+ horlayout.addStyleName("treeexample");
+ horlayout.setSizeFull();
+
+ final Panel treepanel = new Panel("The Planets and Major Moons");
+ treepanel.addComponent(tree);
+ horlayout.addComponent(treepanel);
+
+ final Panel detailspanel = new Panel("Details");
+ horlayout.addComponent(detailspanel);
+ horlayout.setExpandRatio(detailspanel, 1);
+
+ final VerticalLayout detailslayout = new VerticalLayout();
+ detailspanel.setLayout(detailslayout);
+
+ // Allow null selection - this is the default actually.
+ tree.setNullSelectionAllowed(true);
+
+ // When a tree item (planet or moon) is clicked, open the item in
+ // Details view.
+ tree.setImmediate(true);
+ tree.addListener(new ValueChangeListener() {
+ String lastselected = null;
+
+ public void valueChange(ValueChangeEvent event) {
+ String planet = (String) tree.getValue();
+
+ // Reselect a selected item if it is unselected by clicking it.
+ if (planet == null) {
+ planet = lastselected;
+ tree.setValue(planet);
+ }
+ lastselected = planet;
+
+ detailspanel.setCaption("Details on " + planet);
+ detailslayout.removeAllComponents();
+
+ // Put some stuff in the Details view.
+ detailslayout.addComponent(new Label("Where is the cat?"));
+ detailslayout.addComponent(new Label("The cat is in " + planet
+ + "."));
+
+ }
+ });
+
+ main.setLayout(horlayout);
+ }
+
+ void example_Select(Window main, String param) {
+ final HorizontalLayout layout = new HorizontalLayout();
+ layout.addStyleName("aligntop");
+
+ if (param.equals("twincol")) {
+ final SelectExample select1 = new SelectExample(this, param,
+ "Select some items", true);
+ layout.addComponent(select1);
+ } else if (param.equals("filter")) {
+ final SelectExample select1 = new SelectExample(this, param,
+ "Enter containing substring", false);
+ layout.addComponent(select1);
+ } else {
+ final SelectExample select1 = new SelectExample(this, param,
+ "Single Selection Mode", false);
+ final SelectExample select2 = new SelectExample(this, param,
+ "Multiple Selection Mode", true);
+ layout.addComponent(select1);
+ layout.addComponent(select2);
+ }
+ main.addComponent(layout);
+ }
+
+ void example_FilterSelect(Window main, String param) {
+ final Select select = new Select("Enter containing substring");
+ main.addComponent(select);
+
+ select
+ .setFilteringMode(AbstractSelect.Filtering.FILTERINGMODE_CONTAINS);
+
+ /* Fill the component with some items. */
+ final String[] planets = new String[] { "Mercury", "Venus", "Earth",
+ "Mars", "Jupiter", "Saturn", "Uranus", "Neptune" };
+
+ for (int i = 0; i < planets.length; i++) {
+ for (int j = 0; j < planets.length; j++) {
+ select.addItem(planets[j] + " to " + planets[i]);
+ }
+ }
+ }
+
+ void example_TextField(Window main, String param) {
+ /* Add a single-line text field. */
+ final TextField subject = new TextField("Subject");
+ subject.setColumns(40);
+ main.addComponent(subject);
+
+ /* Add a multi-line text field. */
+ final TextField message = new TextField("Message");
+ message.setRows(7);
+ message.setColumns(40);
+ main.addComponent(message);
+ }
+
+ void example_TextFieldValidation(Window main, String param) {
+ // Create a text field with a label
+ final TextField username = new TextField("Username");
+ main.addComponent(username);
+
+ // Set visible length to 16 characters
+ username.setColumns(16);
+
+ // Set content length to minimum of 6 and maximum of 16 characters.
+ // The string also may not be null.
+ username.addValidator(new StringLengthValidator(
+ "Must be 6 to 16 characters long", 6, 16, false));
+
+ // Setting component immediate causes a ValueChangeEvent to occur
+ // when the TextField loses focus.
+ username.setImmediate(true);
+
+ // Listen for ValueChangeEvents and handle them
+ username.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ // Get the source of the event
+ final TextField username = (TextField) (event.getProperty());
+
+ try {
+ // Validate the field value.
+ username.validate();
+ } catch (final Validator.InvalidValueException e) {
+ // The value was not ok. The error was set.
+ }
+ }
+ });
+ }
+
+ void example_UserError(final Window main, String param) {
+ if (param != null) {
+ if (param.equals("form")) {
+
+ final FormLayout layout = new FormLayout();
+ main.addComponent(layout);
+
+ final TextField textfield = new TextField("Enter code");
+ layout.addComponent(textfield);
+ textfield.setComponentError(null);
+
+ final Button button = new Button("Ok!");
+ layout.addComponent(button);
+
+ button.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ if (((String) textfield.getValue()).length() == 0) {
+ textfield.setComponentError(new UserError(
+ "Must be letters and numbers."));
+ } else {
+ textfield.setComponentError(null);
+ }
+ }
+ });
+ }
+ } else {
+ main.setLayout(new HorizontalLayout());
+
+ // Create a field.
+ final TextField textfield = new TextField("Enter code");
+ main.addComponent(textfield);
+
+ // Let the component error be initially clear. (It actually is by
+ // default.)
+ textfield.setComponentError(null);
+
+ // Have a button right of the field (and align it properly).
+ final Button button = new Button("Ok!");
+ main.addComponent(button);
+ ((HorizontalLayout) main.getLayout()).setComponentAlignment(button,
+ HorizontalLayout.ALIGNMENT_LEFT,
+ HorizontalLayout.ALIGNMENT_BOTTOM);
+
+ // Handle button clicks
+ button.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ // If the field value is bad, set its error.
+ // (Here the content must be only alphanumeric characters.)
+ if (!((String) textfield.getValue()).matches("^\\w*$")) {
+ // Put the component in error state and set the error
+ // message.
+ textfield.setComponentError(new UserError(
+ "Must be letters and numbers"));
+ } else {
+ // Otherwise clear it.
+ textfield.setComponentError(null);
+ }
+ }
+ });
+ }
+ }
+
+ void example_DateField(Window main, String param) {
+ HorizontalLayout layout = new HorizontalLayout();
+
+ /* Create a DateField with the calendar style. */
+ final DateField popupdate = new PopupDateField("Popup calendar field");
+
+ /* Set resolution of the date/time display. */
+ popupdate.setResolution(DateField.RESOLUTION_MIN);
+
+ /* Set the date and time to present. */
+ popupdate.setValue(new java.util.Date());
+
+ /* Create a DateField with the calendar style. */
+ final DateField inlinedate = new InlineDateField(
+ "Inline calendar field");
+
+ /* Set locale of the DateField to American English. */
+ inlinedate.setLocale(new Locale("en", "US"));
+
+ /* Set the date and time to present. */
+ inlinedate.setValue(new java.util.Date());
+
+ /* Set resolution of the date/time display. */
+ inlinedate.setResolution(DateField.RESOLUTION_MIN);
+
+ layout.addComponent(popupdate);
+ layout.addComponent(inlinedate);
+ layout.setSpacing(true);
+ main.addComponent(layout);
+ }
+
+ void example_Validator(Window main, String param) {
+ if (param != null && param.equals("required")) {
+ Form form = new Form();
+ form.setCaption("My Form");
+ form.setRequired(true);
+ main.addComponent(form);
+
+ TextField text = new TextField("This is a required text field");
+ text.setRequired(true);
+ text.setImmediate(true);
+ form.getLayout().addComponent(text);
+ return;
+ }
+ main.addComponent(new SSNField());
+ }
+
+ class PagingTable extends Table {
+ @Override
+ public String getTag() {
+ return "pagingtable";
+ }
+ }
+
+ void example_Table(Window main, String param) {
+ if (param != null) {
+ if (param.equals("select")) {
+ main.addComponent(new TableExample2());
+ } else if (param.equals("component")) {
+ main.addComponent(new TableExample3());
+ } else if (param.equals("editable")) {
+ main.addComponent(new TableEditable());
+ } else if (param.equals("bean")) {
+ main.addComponent(new TableEditableBean());
+ } else if (param.equals("long")) {
+ main.addComponent(new TableExample());
+ } else if (param.equals("cellstyle")) {
+ main.addComponent(new TableCellStyle());
+ } else if (param.equals("huge")) {
+ main.addComponent(new TableHuge());
+ } else if (param.equals("paging")) {
+ PagingTable table = new PagingTable();
+ table.addContainerProperty("Column 1", String.class, null);
+ for (int i = 0; i < 100; i++) {
+ table.addItem(new Object[] { "Item " + i }, new Integer(i));
+ }
+ main.addComponent(table);
+ }
+ } else {
+ main.addComponent(new TableExample1());
+ }
+ }
+
+ void example_Upload(Window main, String param) {
+ main.addComponent(new MyUploader());
+ }
+
+ void example_Link(Window main, String param) {
+
+ /* Create a link that opens the popup window. */
+ final Link alink = new Link();
+
+ /* Set the resource to be opened in the window. */
+ alink.setResource(new ExternalResource("http://www.itmill.com/"));
+
+ main.addComponent(alink);
+
+ final ClassResource mydocument = new ClassResource("mydocument.pdf",
+ this);
+ main.addComponent(new Link("The document (pdf)", mydocument));
+ main.addComponent(new Link("link to a resource", new ExternalResource(
+ "http://www.itmill.com/")));
+ }
+
+ void example_Button(Window main, String param) {
+ if (param != null) {
+ if (param.equals("buttons")) {
+ main.addComponent(new TheButton());
+ }
+ return;
+ }
+
+ // butts1 = new TheButton ();
+ // main.addComponent(butts1);
+
+ // butts2 = new TheButtons (main);
+ // butts3 = new TheButtons2 (main);
+
+ // Button checkbox = new Button ("This is a checkbox");
+
+ // main.addComponent(checkbox);
+ final Button button = new Button("My Button");
+ main.addComponent(button);
+ }
+
+ void example_CheckBox(Window main, String param) {
+ /* A check box with default state (not checked, i.e., false). */
+ final CheckBox checkbox1 = new CheckBox("My CheckBox");
+ checkbox1.addStyleName("mybox");
+ main.addComponent(checkbox1);
+
+ /* Another check box with explicitly set checked state. */
+ final CheckBox checkbox2 = new CheckBox("Checked CheckBox");
+ /*
+ * @TODO: Build fails here, why? checkbox2.setValue(true);
+ */
+ main.addComponent(checkbox2);
+
+ /*
+ * Make some application logic. We use anynymous listener classes here.
+ * The above references were defined as "final" to allow accessing them
+ * from inside anonymous classes.
+ */
+ checkbox1.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ /* Copy the value to the other checkbox. */
+ checkbox2.setValue(checkbox1.getValue());
+ }
+ });
+ checkbox2.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ /* Copy the value to the other checkbox. */
+ checkbox1.setValue(checkbox2.getValue());
+ }
+ });
+ }
+
+ void example_Panel(Window main, String param) {
+ // Create a panel with a caption.
+ final Panel panel = new Panel("Contact Information");
+
+ // Create a layout inside the panel
+ final FormLayout form = new FormLayout();
+
+ // Set the layout as the root layout of the panel
+ panel.setLayout(form);
+
+ // Add some components
+ form.addComponent(new TextField("Name"));
+ form.addComponent(new TextField("Email"));
+
+ // Add the panel to the main window
+ final ClassResource icon = new ClassResource("smiley.jpg", main
+ .getApplication());
+ form.addComponent(new Embedded("Image", icon));
+ panel.setIcon(icon);
+ panel.addComponent(form);
+ main.addComponent(panel);
+ }
+
+ void example_GridLayout(Window main, String param) {
+ if (param.equals("embedded")) {
+ final GridLayout grid = new GridLayout(3, 3);
+ for (int i = 0; i < 3 * 3; i++) {
+ ClassResource img = new ClassResource("smiley.jpg", main
+ .getApplication());
+ Embedded embedded = new Embedded("", img);
+ grid.addComponent(embedded);
+ }
+ main.addComponent(grid);
+ return;
+ }
+ /* Create a 4 by 4 grid layout. */
+ final GridLayout grid = new GridLayout(4, 4);
+ grid.addStyleName("example-gridlayout");
+
+ /* Fill out the first row using the cursor. */
+ grid.addComponent(new Button("R/C 1"));
+ for (int i = 0; i < 3; i++) {
+ grid.addComponent(new Button("Col " + (grid.getCursorX() + 1)));
+ }
+
+ /* Fill out the first column using coordinates. */
+ for (int i = 1; i < 4; i++) {
+ grid.addComponent(new Button("Row " + i), 0, i);
+ }
+
+ /* Add some components of various shapes. */
+ grid.addComponent(new Button("3x1 button"), 1, 1, 3, 1);
+ grid.addComponent(new Label("1x2 cell"), 1, 2, 1, 3);
+ final InlineDateField date = new InlineDateField("A 2x2 date field");
+ date.setResolution(DateField.RESOLUTION_DAY);
+ grid.addComponent(date, 2, 2, 3, 3);
+
+ main.addComponent(grid);
+ }
+
+ void example_Alignment(Window main, String param) {
+ if (param.equals("grid")) {
+ /* Create a 3 by 3 grid layout. */
+ final GridLayout layout = new GridLayout(3, 3);
+ // OrderedLayout layout = new
+ // OrderedLayout(OrderedLayout.ORIENTATION_VERTICAL);
+ main.setLayout(layout);
+ layout.addStyleName("example-alignment");
+
+ layout.setWidth(400, Sizeable.UNITS_PIXELS);
+ layout.setHeight(400, Sizeable.UNITS_PIXELS);
+
+ /* Define cells and their layouts to create. */
+
+ Object cells[][] = {
+ { new Button("Top Left"),
+ new Integer(AlignmentHandler.ALIGNMENT_LEFT),
+ new Integer(AlignmentHandler.ALIGNMENT_TOP) },
+ {
+ new Label("Top Center"),
+ new Integer(
+ AlignmentHandler.ALIGNMENT_HORIZONTAL_CENTER),
+ new Integer(AlignmentHandler.ALIGNMENT_TOP) },
+ { new Label("Top Right"),
+ new Integer(AlignmentHandler.ALIGNMENT_RIGHT),
+ new Integer(AlignmentHandler.ALIGNMENT_TOP) },
+ {
+ new Button("Center Left"),
+ new Integer(AlignmentHandler.ALIGNMENT_LEFT),
+ new Integer(
+ AlignmentHandler.ALIGNMENT_VERTICAL_CENTER) },
+ {
+ new Button("Center Center"),
+ new Integer(
+ AlignmentHandler.ALIGNMENT_HORIZONTAL_CENTER),
+ new Integer(
+ AlignmentHandler.ALIGNMENT_VERTICAL_CENTER) },
+ {
+ new Button("Center Right"),
+ new Integer(AlignmentHandler.ALIGNMENT_RIGHT),
+ new Integer(
+ AlignmentHandler.ALIGNMENT_VERTICAL_CENTER) },
+ { new Button("Bottom Left"),
+ new Integer(AlignmentHandler.ALIGNMENT_LEFT),
+ new Integer(AlignmentHandler.ALIGNMENT_BOTTOM) },
+ {
+ new Button("Bottom Center"),
+ new Integer(
+ AlignmentHandler.ALIGNMENT_HORIZONTAL_CENTER),
+ new Integer(AlignmentHandler.ALIGNMENT_BOTTOM) },
+ { new Button("Bottom Right"),
+ new Integer(AlignmentHandler.ALIGNMENT_RIGHT),
+ new Integer(AlignmentHandler.ALIGNMENT_BOTTOM) } };
+
+ for (int i = 0; i < 9; i++) {
+ HorizontalLayout celllayout = new HorizontalLayout();
+ celllayout.addComponent((Component) cells[i][0]);
+ if (i == 0) {
+ celllayout.setExpandRatio((Component) cells[i][0], 1);
+ }
+
+ celllayout.setComponentAlignment((Component) cells[i][0],
+ ((Integer) cells[i][1]).intValue(),
+ ((Integer) cells[i][2]).intValue());
+ layout.addComponent(celllayout);
+ // layout.setComponentAlignment((Component)cells[i][0],
+ // ((Integer)cells[i][1]).intValue(),
+ // ((Integer)cells[i][2]).intValue());
+ }
+ } else {
+ final Panel panel = new Panel("A Panel with a Layout");
+ main.addComponent(panel);
+
+ // panel.addComponent(new )
+ }
+ }
+
+ void example_OrderedLayout(Window main, String param) {
+ final VerticalLayout layout = new VerticalLayout();
+ layout.addComponent(new TextField("Name"));
+ layout.addComponent(new TextField("Street address"));
+ layout.addComponent(new TextField("Postal code"));
+ main.addComponent(layout);
+ }
+
+ void example_FormLayout(Window main, String param) {
+ final FormLayout layout = new FormLayout();
+ layout.addComponent(new TextField("Text Field"));
+ layout.addComponent(new CheckBox("Check Box"));
+ layout.addComponent(new Select("Select"));
+ main.addComponent(layout);
+ }
+
+ void example_Form(Window main, String param) {
+ if (param != null && param.equals("simple")) {
+ main.addComponent(new FormExample2());
+ } else if (param != null && param.equals("layout")) {
+ Form form = new Form();
+ form.setCaption("Form Caption");
+ form
+ .setDescription("This is a description of the Form that is "
+ + "displayed in the upper part of the form. You normally enter some "
+ + "descriptive text about the form and its use here.");
+
+ // Add a field directly to the layout. This field will not be bound
+ // to
+ // the data source Item of the form.
+ form.getLayout().addComponent(new TextField("A Field"));
+
+ // Add a field and bind it to an named item property.
+ form.addField("another", new TextField("Another Field"));
+
+ form.setComponentError(new UserError(
+ "This is the error indicator of the Form."));
+
+ // Set the footer layout and add some text.
+ form.setFooter(new VerticalLayout());
+ form
+ .getFooter()
+ .addComponent(
+ new Label(
+ "This is the footer area of the Form. "
+ + "You can use any layout here. This is nice for buttons."));
+
+ // Add an Ok (commit), Reset (discard), and Cancel buttons for the
+ // form.
+ HorizontalLayout okbar = new HorizontalLayout();
+ okbar.setHeight("25px");
+ Button okbutton = new Button("OK", form, "commit");
+ okbar.addComponent(okbutton);
+ okbar.setExpandRatio(okbutton, 1);
+ okbar.setComponentAlignment(okbutton,
+ AlignmentHandler.ALIGNMENT_RIGHT,
+ AlignmentHandler.ALIGNMENT_TOP);
+ okbar.addComponent(new Button("Reset", form, "discard"));
+ okbar.addComponent(new Button("Cancel"));
+ form.getFooter().addComponent(okbar);
+
+ main.addComponent(form);
+ } else {
+ main.addComponent(new FormExample());
+ }
+ }
+
+ void example_ExpandLayout(Window main, String param) {
+ if (param != null && param.equals("centered")) {
+ Label widget = new Label("Here is text");
+
+ HorizontalLayout layout = new HorizontalLayout();
+ layout.addComponent(widget);
+ layout.setExpandRatio(widget, 1);
+ layout.setComponentAlignment(widget,
+ AlignmentHandler.ALIGNMENT_HORIZONTAL_CENTER,
+ AlignmentHandler.ALIGNMENT_VERTICAL_CENTER);
+ layout.setWidth(100, Sizeable.UNITS_PERCENTAGE);
+ layout.setHeight(100, Sizeable.UNITS_PERCENTAGE);
+
+ main.setLayout(layout);
+
+ return;
+ } else if (param != null && param.equals("window")) {
+ Window window = new Window("Progress");
+ window.setHeight(100, Sizeable.UNITS_PIXELS);
+ window.setWidth(200, Sizeable.UNITS_PIXELS);
+ main.addWindow(window);
+
+ ProgressIndicator progress = new ProgressIndicator(new Float(0.4));
+ progress.addStyleName("fullwidth");
+ progress.setPollingInterval(1000000);
+ progress.setIndeterminate(false);
+
+ HorizontalLayout layout = new HorizontalLayout();
+ layout.setHeight(100, Sizeable.UNITS_PERCENTAGE);
+ layout.setComponentAlignment(progress,
+ HorizontalLayout.ALIGNMENT_HORIZONTAL_CENTER,
+ HorizontalLayout.ALIGNMENT_VERTICAL_CENTER);
+ window.setLayout(layout);
+ window.addComponent(progress);
+
+ return;
+ } else if (param != null && param.equals("root")) {
+ final Window mainwin = main;
+
+ // Layout to switch to
+ final VerticalLayout expand2 = new VerticalLayout();
+ expand2.addComponent(new Label("I am layout too."));
+
+ // Original layout
+ final VerticalLayout expand1 = new VerticalLayout();
+ Button switchButton = new Button("Switch to other layout");
+ switchButton.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ mainwin.setLayout(null);
+ mainwin.setLayout(expand2);
+ }
+ });
+ expand1.addComponent(switchButton);
+ main.setLayout(expand1);
+
+ return;
+ } else if (param != null && param.equals("size")) {
+ VerticalLayout layout = new VerticalLayout();
+ layout.setSizeFull();
+ main.setLayout(layout);
+
+ Button button = new Button("This is a button in middle of nowhere");
+ layout.addComponent(button);
+ layout.setComponentAlignment(button,
+ VerticalLayout.ALIGNMENT_HORIZONTAL_CENTER,
+ VerticalLayout.ALIGNMENT_VERTICAL_CENTER);
+ layout.setExpandRatio(button, 1.0f);
+ return;
+ }
+
+ for (int w = 0; w < 2; w++) {
+ final VerticalLayout layout = new VerticalLayout();
+
+ /* Set the expanding layout as the root layout of a child window. */
+ final Window window = new Window("A Child Window", layout);
+ main.addWindow(window);
+
+ /* Add some component above the expanding one. */
+ layout.addComponent(new Label("Here be some component."));
+
+ /* Create the expanding component. */
+ final Table table = new Table("My Ever-Expanding Table");
+ /*
+ * FIXME Java 5 -> 1.4 for (int i=0; i<5; i++)
+ * table.addContainerProperty("col "+(i+1), Integer.class, 0); for
+ * (int j=0; j<20; j++) table.addItem(new Object[]{1j,2j,3j,4j,5j},
+ * j);
+ */
+ layout.addComponent(table);
+
+ /* Designate the table to be the expanding component. */
+ layout.setExpandRatio(table, 1.0f);
+
+ /* Set it to use all available area. */
+ table.setSizeFull();
+
+ /* Add some component below the expanding one. */
+ final Button button2 = new Button("Ok");
+ layout.addComponent(button2);
+ layout.setComponentAlignment(button2,
+ AlignmentHandler.ALIGNMENT_RIGHT, 0);
+ }
+ }
+
+ void example_TabSheet(Window main, String param) {
+ if (param.equals("icon")) {
+ final TabSheet tabsheet = new TabSheet();
+
+ tabsheet.addTab(new Label("Contents of the first tab"),
+ "First Tab", new ClassResource("images/Mercury_small.png",
+ main.getApplication()));
+ tabsheet.addTab(new Label("Contents of the second tab"),
+ "Second Tab", new ClassResource("images/Venus_small.png",
+ this));
+ tabsheet.addTab(new Label("Contents of the third tab"),
+ "Third tab", new ClassResource("images/Earth_small.png",
+ this));
+
+ main.addComponent(tabsheet);
+ // main.addComponent(new Embedded("Emb", new ClassResource
+ // ("images/Mercury_small.png", this)));
+ } else if (param.equals("expanding")) {
+ // Create the layout
+ VerticalLayout expanding = new VerticalLayout();
+
+ // It is important to set the expanding layout as the root layout
+ // of the containing window, in this case the main window, and not
+ // use addComponent(), which would place the layout inside the
+ // default root layout.
+ main.setLayout(expanding);
+
+ // Create a tab sheet that fills the expanding layout
+ final TabSheet tabsheet = new TabSheet();
+ tabsheet.addTab(new Label("Contents of the first tab"),
+ "First Tab", null);
+ tabsheet.addTab(new Label("Contents of the second tab"),
+ "Second Tab", null);
+ tabsheet.addTab(new Label("Contents of the third tab"),
+ "Third tab", null);
+
+ // Set the tabsheet to scale to full size inside its container
+ tabsheet.setWidth(100, Sizeable.UNITS_PERCENTAGE);
+ tabsheet.setHeight(100, Sizeable.UNITS_PERCENTAGE);
+
+ // Add the tab sheet to the layout as usual
+ expanding.addComponent(tabsheet);
+
+ // Set the tab sheet to be the expanding component
+ expanding.setExpandRatio(tabsheet, 1);
+ } else if (param.equals("ordered")) {
+ // Create the layout
+ VerticalLayout layout = new VerticalLayout();
+
+ // It is important to set the expanding layout as the root layout
+ // of the containing window, in this case the main window, and not
+ // use addComponent(), which would place the layout inside the
+ // default root layout.
+ main.setLayout(layout);
+
+ // Create a tab sheet that fills the expanding layout
+ final TabSheet tabsheet = new TabSheet();
+ tabsheet.addTab(new Label("Contents of the first tab"),
+ "First Tab", null);
+ tabsheet.addTab(new Label("Contents of the second tab"),
+ "Second Tab", null);
+ tabsheet.addTab(new Label("Contents of the third tab"),
+ "Third tab", null);
+
+ // Set the tabsheet to scale to full size inside its container
+ tabsheet.setWidth(100, Sizeable.UNITS_PERCENTAGE);
+ // tabsheet().setHeight(100, Sizeable.UNITS_PERCENTAGE);
+
+ // Add the tab sheet to the layout as usual
+ layout.addComponent(tabsheet);
+ } else {
+ main.addComponent(new TabSheetExample());
+ }
+ }
+
+ void example_Embedded(Window main, String param) {
+ final Embedded image = new Embedded("", new ClassResource("smiley.jpg",
+ this));
+ image.addStyleName("omaimage");
+ main.addComponent(image);
+
+ final EmbeddedButton button = new EmbeddedButton(new ClassResource(
+ "smiley.jpg", this));
+ main.addComponent(button);
+ }
+
+ void example_Window(Window main, String param) {
+ if (param != null) {
+ if (param.equals("opener")) {
+ main.addComponent(new WindowOpener("Window Opener", main));
+ } else if (param.equals("multiple")) {
+ /* Create a new window. */
+ final Window mywindow = new Window("Second Window");
+ mywindow.setName("mywindow");
+ mywindow.addComponent(new Label("This is a second window."));
+
+ /* Add the window to the application. */
+ main.getApplication().addWindow(mywindow);
+
+ /* Add link to the second window in the main window. */
+ main.addComponent(new Label("Second window: <a href='"
+ + mywindow.getURL() + "'>middle-click to open</a>",
+ Label.CONTENT_XHTML));
+ main.addComponent(new Label(
+ "The second window can be accessed through URL: "
+ + mywindow.getURL()));
+ }
+ return;
+ }
+
+ /* Create a new window. */
+ final Window mywindow = new Window("My Window");
+ mywindow.setName("mywindow");
+
+ /* Add some components in the window. */
+ mywindow.addComponent(new Label("A text label in the window."));
+ final Button okbutton = new Button("OK");
+ mywindow.addComponent(okbutton);
+
+ /* Set window size. */
+ mywindow.setHeight("200px");
+ mywindow.setWidth("400px");
+
+ /* Set window position. */
+ mywindow.setPositionX(200);
+ mywindow.setPositionY(50);
+
+ /* Add the window to the Application object. */
+ main.addWindow(mywindow);
+
+ }
+
+ void example_ClassResource(Window main, String param) {
+ final DateField df = new DateField();
+ main.addComponent(df);
+ df.setIcon(new ClassResource("smiley.jpg", main.getApplication()));
+ main.addComponent(new Embedded("This is Embedded", new ClassResource(
+ "smiley.jpg", main.getApplication())));
+ }
+
+ void example_ProgressIndicator(final Window main, String param) {
+ if (param != null) {
+ if (param.equals("thread")) {
+
+ // Create the indicator
+ final ProgressIndicator indicator = new ProgressIndicator(
+ new Float(0.0));
+ main.addComponent(indicator);
+
+ // Set polling frequency to 0.5 seconds.
+ indicator.setPollingInterval(1000);
+
+ // indicator.addStyleName("invisible");
+ final Label text = new Label("-- Not running --");
+ main.addComponent(text);
+
+ // Add a button to start the progress
+ final Button button = new Button("Click to start");
+ main.addComponent(button);
+
+ // Another thread to do some work
+ class WorkThread extends Thread {
+ @Override
+ public void run() {
+ double current = 0.0;
+ while (true) {
+ // Do some "heavy work"
+ try {
+ sleep(50); // Sleep for 50 milliseconds
+ } catch (InterruptedException e) {
+ }
+
+ // Grow the progress value until it reaches 1.0.
+ current += 0.01;
+ if (current > 1.0) {
+ indicator.setValue(new Float(1.0));
+ } else {
+ indicator.setValue(new Float(current));
+ }
+
+ // After the progress is full for a while, stop.
+ if (current > 1.2) {
+ // Restore the state to initial.
+ indicator.setValue(new Float(0.0));
+ button.setVisible(true);
+ break;
+ }
+ }
+ }
+ }
+
+ // Clicking the button creates and runs a work thread
+ button.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ final WorkThread thread = new WorkThread();
+ thread.start();
+
+ // The button hides until the work is done.
+ button.setVisible(false);
+ }
+ });
+ } else if (param.equals("window")) {
+ // Create a table in the main window to hold items added in the
+ // second window
+ final Table table = new Table();
+ table.setPageLength(5);
+ table.setWidth(100, Sizeable.UNITS_PERCENTAGE);
+ table.addContainerProperty("Name", String.class, "");
+ main.addComponent(table);
+
+ // Create the second window
+ final Window adderWindow = new Window("Add Items");
+ adderWindow.setName("win-adder");
+ main.getApplication().addWindow(adderWindow);
+
+ // Create selection component to add items to the table
+ final NativeSelect select = new NativeSelect(
+ "Select item to add");
+ select.setImmediate(true);
+ adderWindow.addComponent(select);
+
+ // Add some items to the selection
+ String items[] = new String[] { "-- Select --", "Mercury",
+ "Venus", "Earth", "Mars", "Jupiter", "Saturn",
+ "Uranus", "Neptune" };
+ for (int i = 0; i < items.length; i++) {
+ select.addItem(items[i]);
+ }
+ select.setNullSelectionItemId(items[0]);
+
+ // When an item is selected in the second window, add
+ // table in the main window
+ select.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ // If the selected value is something else but null
+ // selection item.
+ if (select.getValue() != null) {
+ // Add the selected item to the table in the main
+ // window
+ table.addItem(new Object[] { select.getValue() },
+ new Integer(table.size()));
+ }
+ }
+ });
+
+ // Link to open the selection window
+ Link link = new Link("Click to open second window",
+ new ExternalResource(adderWindow.getURL()), "_new", 50,
+ 200, Link.TARGET_BORDER_DEFAULT);
+ main.addComponent(link);
+
+ // Enable polling to update the main window
+ ProgressIndicator poller = new ProgressIndicator();
+ poller.addStyleName("invisible");
+ main.addComponent(poller);
+ } else if (param.equals("centered")) {
+ /*
+ * GridLayout grid = new GridLayout(3,3); main.setLayout(grid);
+ * grid().setWidth(100, Sizeable.UNITS_PERCENTAGE);
+ *
+ * ExpandLayout layout2 = new
+ * ExpandLayout(OrderedLayout.ORIENTATION_HORIZONTAL);
+ * layout2().setWidth(50, Sizeable.UNITS_PERCENTAGE);
+ *
+ * ProgressIndicator poller = new ProgressIndicator(new
+ * Float(0.4)); poller.setPollingInterval(1000000);
+ * poller.setIndeterminate(false); layout2.addComponent(poller);
+ *
+ * grid.addComponent(layout2, 1, 1);
+ */
+
+ // ExpandLayout layout2 = new
+ // ExpandLayout(OrderedLayout.ORIENTATION_HORIZONTAL);
+ /*
+ * ProgressIndicator poller = new ProgressIndicator(new
+ * Float(0.4)); poller.setPollingInterval(1000000);
+ * poller.setIndeterminate(false);
+ */
+ /*
+ * layout2.addComponent(poller); layout2().setWidth(50,
+ * Sizeable.UNITS_PERCENTAGE);
+ */
+
+ // layout.setComponentAlignment(poller,
+ // AlignmentHandler.ALIGNMENT_HORIZONTAL_CENTER,
+ // AlignmentHandler.ALIGNMENT_VERTICAL_CENTER);
+ /*
+ * GridLayout grid = new GridLayout(1,1);
+ * grid.addComponent(layout2, 0, 0); grid().setWidth(100,
+ * Sizeable.UNITS_PERCENTAGE);
+ */
+
+ /*
+ * GridLayout layout = new GridLayout(1,1);
+ * //OrderedLayout.ORIENTATION_HORIZONTAL);
+ * layout.addComponent(poller); //layout.expand(poller);
+ * layout.setComponentAlignment(poller,
+ * AlignmentHandler.ALIGNMENT_HORIZONTAL_CENTER,
+ * AlignmentHandler.ALIGNMENT_VERTICAL_CENTER);
+ * layout().setWidth(100, Sizeable.UNITS_PERCENTAGE);
+ * layout().setHeight(100, Sizeable.UNITS_PERCENTAGE);
+ */
+
+ }
+ } else {
+ ProgressIndicator poller = new ProgressIndicator(new Float(0.0));
+ poller.setPollingInterval(1000000);
+ poller.setIndeterminate(true);
+ main.addComponent(poller);
+ }
+ }
+
+ void example_CustomLayout(final Window main, String param) {
+ Window sub = new Window("Login");
+ sub.setModal(true);
+ main.addWindow(sub);
+
+ // Create the custom layout and set it as the root layout of
+ // the containing window.
+ final CustomLayout custom = new CustomLayout("layoutname");
+ sub.setLayout(custom);
+
+ // Create components and bind them to the location tags
+ // in the custom layout.
+ TextField username = new TextField();
+ custom.addComponent(username, "username");
+
+ TextField password = new TextField();
+ custom.addComponent(password, "password");
+
+ final Button ok = new Button("Login");
+ custom.addComponent(ok, "okbutton");
+
+ final Button deny = new Button("No can do!");
+
+ Button.ClickListener listener = new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ // Switch between ok and deny
+ if (custom.getComponent("okbutton") == ok) {
+ System.out.println("Changing to deny button.");
+ custom.addComponent(deny, "okbutton");
+ } else {
+ System.out.println("Changing to ok button.");
+ custom.addComponent(ok, "okbutton");
+ }
+ }
+ };
+
+ ok.addListener(listener);
+ deny.addListener(listener);
+ }
+
+ void example_Spacing(final Window main, String param) {
+ VerticalLayout containinglayout = new VerticalLayout();
+ main.setLayout(containinglayout);
+
+ GridLayout grid = new GridLayout(4, 3);
+ grid.addStyleName("spacingexample");
+ containinglayout.addComponent(grid);
+ grid.addComponent(new Label(""), 0, 0);
+ grid.addComponent(new Label(""), 1, 0);
+
+ grid.addComponent(new Label("No spacing:"), 0, 1);
+ HorizontalLayout layout1 = new HorizontalLayout();
+ grid.addComponent(layout1, 1, 1);
+ layout1.addStyleName("spacingexample");
+ layout1.addComponent(new Button("Component 1"));
+ layout1.addComponent(new Button("Component 2"));
+ layout1.addComponent(new Button("Component 3"));
+
+ grid.addComponent(new Label("Horizontal spacing:"), 0, 2);
+ HorizontalLayout layout2 = new HorizontalLayout();
+ grid.addComponent(layout2, 1, 2);
+ layout2.addStyleName("spacingexample");
+ layout2.setSpacing(true);
+ layout2.addComponent(new Button("Component 1"));
+ layout2.addComponent(new Button("Component 2"));
+ layout2.addComponent(new Button("Component 3"));
+
+ grid.addComponent(new Label("No spacing:"), 2, 0);
+ VerticalLayout layout3 = new VerticalLayout();
+ grid.addComponent(layout3, 2, 1, 2, 2);
+ layout3.addStyleName("spacingexample");
+ layout3.addComponent(new Button("Component 1"));
+ layout3.addComponent(new Button("Component 2"));
+ layout3.addComponent(new Button("Component 3"));
+
+ grid.addComponent(new Label("Vertical spacing:"), 3, 0);
+ VerticalLayout layout4 = new VerticalLayout();
+ grid.addComponent(layout4, 3, 1, 3, 2);
+ layout4.addStyleName("spacingexample");
+ layout4.setSpacing(true);
+ layout4.addComponent(new Button("Component 1"));
+ layout4.addComponent(new Button("Component 2"));
+ layout4.addComponent(new Button("Component 3"));
+ }
+
+ void example_Margin(final Window main, String param) {
+ HorizontalLayout hor = new HorizontalLayout();
+ main.setLayout(hor);
+
+ VerticalLayout containinglayout = new VerticalLayout();
+ hor.addComponent(containinglayout);
+
+ VerticalLayout layout1 = new VerticalLayout();
+ containinglayout.addComponent(new Label("Regular layout margins:"));
+ containinglayout.addComponent(layout1);
+ layout1.addStyleName("marginexample1");
+ layout1.addComponent(new Button("Component 1"));
+ layout1.addComponent(new Button("Component 2"));
+ layout1.addComponent(new Button("Component 3"));
+
+ // Create a layout
+ VerticalLayout layout2 = new VerticalLayout();
+ containinglayout.addComponent(new Label(
+ "Layout with a special margin element:"));
+ containinglayout.addComponent(layout2);
+
+ // Set style name for the layout to allow styling it
+ layout2.addStyleName("marginexample2");
+
+ // Have margin on all sides around the layout
+ layout2.setMargin(true);
+
+ // Put something inside the layout
+ layout2.addComponent(new Button("Component 1"));
+ layout2.addComponent(new Button("Component 2"));
+ layout2.addComponent(new Button("Component 3"));
+ }
+
+ void example_ClientInfo(final Window main, String param) {
+ // Get the client identification string
+ WebApplicationContext context2 = (WebApplicationContext) getContext();
+ String browserApplication = context2.getBrowser()
+ .getBrowserApplication();
+
+ // Add a browser-dependent style name for the main window
+ if (browserApplication.indexOf("Firefox/2") != -1) {
+ main.addStyleName("firefox2");
+ }
+
+ // Display the client identification string
+ main.addComponent(new Label(browserApplication));
+ }
+
+ void example_FillInForm(final Window main, String param) {
+ if (param.equals("templates")) {
+ // Create a custom layout from the fill-in-form.html template.
+ CustomLayout fillinlayout = new CustomLayout("fill-in-form");
+
+ // The style will set the display to be "inline".
+ fillinlayout.addStyleName("fillinlayout");
+
+ // Create the fields that occur in the text.
+ TextField field1 = new TextField();
+ TextField field2 = new TextField();
+ fillinlayout.addComponent(field1, "q1");
+ fillinlayout.addComponent(field2, "q2");
+
+ main.addComponent(fillinlayout);
+ } else {
+ String fillintext = "The <q1> is mightier than <q2>.";
+ int pos = 0;
+ while (pos < fillintext.length()) {
+ int nexttag = fillintext.indexOf("<", pos);
+ if (nexttag == -1) {
+
+ }
+ }
+ }
+ }
+
+ void example_Notification(final Window main, String param) {
+ // final Window sub1 = new Window("");
+ // main.addWindow(sub1);
+ if (param.equals("example")) {
+ main.showNotification("This is the caption",
+ "This is the description");
+ return;
+ } else if (param.equals("type")) {
+ main.showNotification("This is a warning",
+ "<br/>This is the <i>last</i> warning",
+ Window.Notification.TYPE_WARNING_MESSAGE);
+ return;
+ } else if (param.equals("pos")) {
+ // Create a notification with the default settings for a warning.
+ Window.Notification notif = new Window.Notification("Be warned!",
+ "This message lurks in the top-left corner!",
+ Window.Notification.TYPE_WARNING_MESSAGE);
+
+ // Set the position.
+ notif.setPosition(Window.Notification.POSITION_TOP_LEFT);
+
+ // Let it stay there until the user clicks it
+ notif.setDelayMsec(-1);
+
+ // Show it in the main window.
+ main.showNotification(notif);
+ return;
+ }
+
+ main.setLayout(new HorizontalLayout());
+
+ final Integer type_humanized = Window.Notification.TYPE_HUMANIZED_MESSAGE;
+ final Integer type_warning = Window.Notification.TYPE_WARNING_MESSAGE;
+ final Integer type_error = Window.Notification.TYPE_ERROR_MESSAGE;
+ final Integer type_tray = Window.Notification.TYPE_TRAY_NOTIFICATION;
+ final NativeSelect types = new NativeSelect();
+ main.addComponent(types);
+ types.addItem(type_humanized);
+ types.addItem(type_warning);
+ types.addItem(type_error);
+ types.addItem(type_tray);
+ types.setItemCaption(type_humanized, "Humanized");
+ types.setItemCaption(type_warning, "Warning");
+ types.setItemCaption(type_error, "Error");
+ types.setItemCaption(type_tray, "Tray");
+
+ Button show = new Button("Show Notification");
+ main.addComponent(show);
+
+ show.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ String caption = "";
+ String description = "";
+ switch (((Integer) types.getValue()).intValue()) {
+ case Window.Notification.TYPE_HUMANIZED_MESSAGE:
+ caption = "Humanized message";
+ description = "<br/>For minimal annoyance";
+ break;
+ case Window.Notification.TYPE_WARNING_MESSAGE:
+ caption = "Warning message";
+ description = "<br/>For notifications of medium importance";
+ break;
+ case Window.Notification.TYPE_ERROR_MESSAGE:
+ caption = "Error message";
+ description = "<br/>For important notifications";
+ break;
+ case Window.Notification.TYPE_TRAY_NOTIFICATION:
+ caption = "Tray notification";
+ description = "<br/>Stays up longer - but away";
+ }
+ // main.showNotification("The default notification");
+ Window.Notification notif = new Window.Notification(caption,
+ description, (Integer) types.getValue());
+ // notif.setPosition(Window.Notification.POSITION_TOP_LEFT);
+ notif.setDelayMsec(-1);
+ main.showNotification(notif);
+ }
+ });
+
+ // Notification notif = new Notification("Title");
+ }
+
+ void example_Print(final Window main, String param) {
+ if (param != null && param.equals("simple")) {
+ main
+ .addComponent(new Label(
+ "<input type='button' onClick='print()' value='Click to Print'/>",
+ Label.CONTENT_XHTML));
+ return;
+ }
+
+ // A button to open the printer-friendly page.
+ Button printButton = new Button("Click to Print");
+ main.addComponent(printButton);
+ printButton.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ // Create a window that contains stuff you want to print.
+ Window printWindow = new Window("Window to Print");
+
+ // Have some content to print.
+ printWindow.addComponent(new Label(
+ "Here's some dynamic content."));
+
+ // To execute the print() JavaScript, we need to run it
+ // from a custom layout.
+ CustomLayout scriptLayout = new CustomLayout("printpage");
+ printWindow.addComponent(scriptLayout);
+
+ // Add the printing window as an application-level window.
+ main.getApplication().addWindow(printWindow);
+
+ // Open the printing window as a new browser window
+ main.open(new ExternalResource(printWindow.getURL()), "_new");
+ }
+ });
+
+ // main.addComponent(new
+ // Label("<p>Print this!</p>\n<script type='text/javascript'>print();</script>",
+ // Label.CONTENT_XHTML));
+ }
+
+ void example_RichTextArea(final Window main, String param) {
+ main.setLayout(new HorizontalLayout());
+
+ // Create a rich text area
+ final RichTextArea rtarea = new RichTextArea();
+ rtarea.addStyleName("richtextexample");
+ // rtarea.setCaption("My Rich Text Area");
+
+ // Set initial content as HTML
+ rtarea
+ .setValue("<h1>Hello</h1>\n<p>This rich text area contains some text.</p>");
+
+ // Show the text edited in the rich text area as HTML.
+ final Button show = new Button("Show HTML");
+ final Label html = new Label((String) rtarea.getValue());
+ show.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ html.setValue(rtarea.getValue());
+ }
+ });
+
+ Panel rtPanel = new Panel("Rich Text Area");
+ rtPanel.addComponent(rtarea);
+ rtPanel.addComponent(show);
+
+ Panel valuePanel = new Panel("Value");
+ valuePanel.addComponent(html);
+
+ main.addComponent(rtPanel);
+ main.addComponent(valuePanel);
+ }
+
+ void example_QueryContainer(final Window main, String param) {
+ try {
+ // Create a database connection
+ Class.forName("org.hsqldb.jdbcDriver");
+ final Connection connection = DriverManager.getConnection(
+ "jdbc:hsqldb:mem:qcexample", "sa", "");
+
+ // Create an example table and put some data in it.
+ Statement st = connection.createStatement();
+ st
+ .executeQuery("CREATE TABLE Prisoners (id INTEGER, name VARCHAR)");
+ st.close();
+ for (int i = 0; i < 100; i++) {
+ st = connection.createStatement();
+ st.executeQuery("INSERT INTO Prisoners (id, name) VALUES (" + i
+ + ",'I am number " + (i + 1) + "')");
+ st.close();
+ }
+
+ // Query the database
+ final QueryContainer qc = new QueryContainer(
+ "SELECT id,name FROM Prisoners", connection);
+
+ // Create a component for selecting a query result item.
+ Select select = new Select("Select an item");
+
+ // The items shown in the selection component are obtained from the
+ // query.
+ select.setContainerDataSource(qc);
+
+ // The item captions are obtained from a field in the query result.
+ select.setItemCaptionMode(Select.ITEM_CAPTION_MODE_PROPERTY);
+
+ // Set the name of the field from which the item captions are
+ // obtained.
+ select.setItemCaptionPropertyId("name");
+
+ // When selection changes, display the selected item.
+ select.setImmediate(true);
+ final Label selection = new Label("Currently selected: -");
+ select.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ // Get the item id of the currently selected item
+ Integer itemId = (Integer) event.getProperty().getValue();
+
+ // Use the item ID to get the actual row from the query
+ // result.
+ Item qrItem = qc.getItem(itemId);
+
+ // Display the item ID
+ selection.setValue("Currently selected: result row "
+ + itemId.intValue() + " (id="
+ + qrItem.getItemProperty("id") + ", " + "name="
+ + qrItem.getItemProperty("name") + ")");
+ }
+ });
+
+ main.addComponent(select);
+ main.addComponent(selection);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+
+ void example_MenuBar(final Window main, String param) {
+ // Create a menu bar
+ final MenuBar menubar = new MenuBar();
+ main.addComponent(menubar);
+
+ // A feedback component
+ final Label selection = new Label("");
+ main.addComponent(selection);
+
+ // Define a common menu command for all the menu items.
+ MenuBar.Command mycommand = new MenuBar.Command() {
+ public void menuSelected(MenuItem selectedItem) {
+ selection.setValue("Ordered a " + selectedItem.getText()
+ + " from menu.");
+ }
+ };
+
+ // Put some items in the menu hierarchically
+ MenuBar.MenuItem beverages = menubar.addItem("Beverages", null, null);
+ MenuBar.MenuItem hot_beverages = beverages.addItem("Hot", null, null);
+ hot_beverages.addItem("Tea", null, mycommand);
+ hot_beverages.addItem("Coffee", null, mycommand);
+ MenuBar.MenuItem cold_beverages = beverages.addItem("Cold", null, null);
+ cold_beverages.addItem("Milk", null, mycommand);
+
+ // Another top-level item
+ MenuBar.MenuItem snacks = menubar.addItem("Snacks", null, null);
+ snacks.addItem("Weisswurst", null, mycommand);
+ snacks.addItem("Salami", null, mycommand);
+
+ // Yet another top-level item
+ MenuBar.MenuItem services = menubar.addItem("Services", null, null);
+ services.addItem("Car Service", null, mycommand);
+ }
}
diff --git a/src/com/itmill/toolkit/tests/book/DefaultButtonExample.java b/src/com/itmill/toolkit/tests/book/DefaultButtonExample.java
index 012070d277..1f340ce4d5 100644
--- a/src/com/itmill/toolkit/tests/book/DefaultButtonExample.java
+++ b/src/com/itmill/toolkit/tests/book/DefaultButtonExample.java
@@ -10,94 +10,85 @@ import com.itmill.toolkit.event.Action.Handler;
import com.itmill.toolkit.ui.Button;
import com.itmill.toolkit.ui.CustomComponent;
import com.itmill.toolkit.ui.FormLayout;
+import com.itmill.toolkit.ui.HorizontalLayout;
import com.itmill.toolkit.ui.Label;
-import com.itmill.toolkit.ui.OrderedLayout;
import com.itmill.toolkit.ui.Panel;
import com.itmill.toolkit.ui.TextField;
-import com.itmill.toolkit.ui.Window;
public class DefaultButtonExample extends CustomComponent implements Handler {
- // Define and create user interface components
- Panel panel = new Panel("Login");
- OrderedLayout formlayout = new FormLayout();
- TextField username = new TextField("Username");
- TextField password = new TextField("Password");
- OrderedLayout buttons = new FormLayout();
+ // Define and create user interface components
+ Panel panel = new Panel("Login");
+ FormLayout formlayout = new FormLayout();
+ TextField username = new TextField("Username");
+ TextField password = new TextField("Password");
+ HorizontalLayout buttons = new HorizontalLayout();
- // Create buttons and define their listener methods. Here we use
- // parameterless
- // methods so that we can use same methods for both click events and
- // keyboard actions.
- Button ok = new Button("OK", this, "okHandler");
- Button cancel = new Button("Cancel", this, "cancelHandler");
+ // Create buttons and define their listener methods.
+ Button ok = new Button("OK", this, "okHandler");
+ Button cancel = new Button("Cancel", this, "cancelHandler");
- // Have the unmodified Enter key cause an event
- Action action_ok = new ShortcutAction("Default key",
- ShortcutAction.KeyCode.ENTER, null);
+ // Have the unmodified Enter key cause an event
+ Action action_ok = new ShortcutAction("Default key",
+ ShortcutAction.KeyCode.ENTER, null);
- // Have the C key modified with Alt cause an event
- Action action_cancel = new ShortcutAction("Alt+C",
- ShortcutAction.KeyCode.C,
- new int[] { ShortcutAction.ModifierKey.ALT });
+ // Have the C key modified with Alt cause an event
+ Action action_cancel = new ShortcutAction("Alt+C",
+ ShortcutAction.KeyCode.C,
+ new int[] { ShortcutAction.ModifierKey.ALT });
- Window window = null;
+ public DefaultButtonExample() {
+ // Set up the user interface
+ setCompositionRoot(panel);
+ panel.addComponent(formlayout);
+ formlayout.addComponent(username);
+ formlayout.addComponent(password);
+ formlayout.addComponent(buttons);
+ buttons.addComponent(ok);
+ buttons.addComponent(cancel);
- public DefaultButtonExample(Window win) {
- // Set up the user interface
- setCompositionRoot(panel);
- panel.addComponent(formlayout);
- formlayout.setOrientation(OrderedLayout.ORIENTATION_VERTICAL);
- formlayout.addComponent(username);
- formlayout.addComponent(password);
- formlayout.addComponent(buttons);
- buttons.setOrientation(OrderedLayout.ORIENTATION_HORIZONTAL);
- buttons.addComponent(ok);
- buttons.addComponent(cancel);
+ // Set focus to username
+ username.focus();
- // Set focus to username
- username.focus();
+ // Set this object as the action handler
+ System.out.println("adding ah");
+ panel.addActionHandler(this);
- // Set this object as the action handler
- System.out.println("adding ah");
- win.addActionHandler(this);
- window = win;
+ System.out.println("start done.");
+ }
- System.out.println("start done.");
- }
+ /**
+ * Retrieve actions for a specific component. This method will be called for
+ * each object that has a handler; in this example just for login panel. The
+ * returned action list might as well be static list.
+ */
+ public Action[] getActions(Object target, Object sender) {
+ System.out.println("getActions()");
+ return new Action[] { action_ok, action_cancel };
+ }
- /**
- * Retrieve actions for a specific component. This method will be called for
- * each object that has a handler; in this example the Ok and Cancel
- * buttons.
- */
- public Action[] getActions(Object target, Object sender) {
- System.out.println("getActions()");
- return new Action[] { action_ok, action_cancel };
- }
+ /**
+ * Handle actions received from keyboard. This simply directs the actions to
+ * the same listener methods that are called with ButtonClick events.
+ */
+ public void handleAction(Action action, Object sender, Object target) {
+ if (action == action_ok) {
+ okHandler();
+ }
+ if (action == action_cancel) {
+ cancelHandler();
+ }
+ }
- /**
- * Handle actions received from keyboard. This simply directs the actions to
- * the same listener methods that are called with ButtonClick events.
- */
- public void handleAction(Action action, Object sender, Object target) {
- if (action == action_ok) {
- okHandler();
- }
- if (action == action_cancel) {
- cancelHandler();
- }
- }
+ public void okHandler() {
+ // Do something: report the click
+ formlayout.addComponent(new Label("OK clicked. " + "User="
+ + username.getValue() + ", password=" + password.getValue()));
+ //
+ }
- public void okHandler() {
- // Do something: report the click
- formlayout.addComponent(new Label("OK clicked. " + "User="
- + username.getValue() + ", password=" + password.getValue()));
- //
- }
-
- public void cancelHandler() {
- // Do something: report the click
- formlayout.addComponent(new Label("Cancel clicked. User="
- + username.getValue() + ", password=" + password.getValue()));
- }
+ public void cancelHandler() {
+ // Do something: report the click
+ formlayout.addComponent(new Label("Cancel clicked. User="
+ + username.getValue() + ", password=" + password.getValue()));
+ }
}
diff --git a/src/com/itmill/toolkit/tests/components/MultipleDebugIds.java b/src/com/itmill/toolkit/tests/components/MultipleDebugIds.java
new file mode 100644
index 0000000000..db5ba15111
--- /dev/null
+++ b/src/com/itmill/toolkit/tests/components/MultipleDebugIds.java
@@ -0,0 +1,35 @@
+package com.itmill.toolkit.tests.components;
+
+import com.itmill.toolkit.ui.Button;
+import com.itmill.toolkit.ui.TextField;
+
+public class MultipleDebugIds extends TestBase {
+
+ @Override
+ protected String getDescription() {
+ return "An exception should be thrown if the same debugId is assigned to several components";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 2796;
+ }
+
+ @Override
+ protected void setup() {
+ TextField textField = new TextField();
+ TextField textField2 = new TextField();
+ Button button = new Button();
+ Button button2 = new Button();
+ textField.setDebugId("textfield");
+ button.setDebugId("button");
+ textField2.setDebugId("textfield2");
+ button2.setDebugId("textfield");
+
+ addComponent(textField);
+ addComponent(textField2);
+ addComponent(button);
+ addComponent(button2);
+ }
+
+}
diff --git a/src/com/itmill/toolkit/tests/components/form/FormRenderingFlicker.java b/src/com/itmill/toolkit/tests/components/form/FormRenderingFlicker.java
new file mode 100644
index 0000000000..f670aa7d23
--- /dev/null
+++ b/src/com/itmill/toolkit/tests/components/form/FormRenderingFlicker.java
@@ -0,0 +1,65 @@
+package com.itmill.toolkit.tests.components.form;
+
+import com.itmill.toolkit.data.Item;
+import com.itmill.toolkit.event.ItemClickEvent;
+import com.itmill.toolkit.event.ItemClickEvent.ItemClickListener;
+import com.itmill.toolkit.tests.components.TestBase;
+import com.itmill.toolkit.ui.Form;
+import com.itmill.toolkit.ui.Panel;
+import com.itmill.toolkit.ui.Table;
+import com.itmill.toolkit.ui.VerticalLayout;
+
+public class FormRenderingFlicker extends TestBase {
+
+ private VerticalLayout tableLayout;
+ private Table table;
+ private Panel tablePanel;
+ private Form form;
+
+ @Override
+ protected String getDescription() {
+ return "Clicking on an item in the table will replace the panel (surrounding the table) with a form. This should not cause the table rows to move downwards or cause any other visible flicker";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 2816;
+ }
+
+ @Override
+ protected void setup() {
+ createTableLayout();
+ form = new Form();
+
+ tablePanel = new Panel();
+ tablePanel.setLayout(tableLayout);
+
+ addComponent(tablePanel);
+ }
+
+ private void createTableLayout() {
+ tableLayout = new VerticalLayout();
+ table = new Table();
+ table.addContainerProperty("name", String.class, "");
+ table.addContainerProperty("age", String.class, "");
+ for (int i = 0; i < 100; i++) {
+ table.addItem(new Object[] { "Name " + i, String.valueOf(i) },
+ new Object());
+ }
+ table.setImmediate(true);
+ table.addListener(new ItemClickListener() {
+
+ public void itemClick(ItemClickEvent event) {
+ clicked(event.getItem());
+ }
+
+ });
+
+ tableLayout.addComponent(table);
+ }
+
+ protected void clicked(Item item) {
+ getLayout().replaceComponent(tablePanel, form);
+ }
+
+}
diff --git a/src/com/itmill/toolkit/tests/components/table/ColumnExpandRatio.java b/src/com/itmill/toolkit/tests/components/table/ColumnExpandRatio.java
new file mode 100644
index 0000000000..94c2c5c4fc
--- /dev/null
+++ b/src/com/itmill/toolkit/tests/components/table/ColumnExpandRatio.java
@@ -0,0 +1,70 @@
+package com.itmill.toolkit.tests.components.table;
+
+import com.itmill.toolkit.data.Item;
+import com.itmill.toolkit.data.util.IndexedContainer;
+import com.itmill.toolkit.tests.components.TestBase;
+import com.itmill.toolkit.ui.Label;
+import com.itmill.toolkit.ui.Table;
+
+public class ColumnExpandRatio extends TestBase {
+
+ @Override
+ protected String getDescription() {
+ return "Column expand ratios can be used to adjust the way "
+ + "how excess horizontal space is divided among columns.";
+
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 2806;
+ }
+
+ private static final int ROWS = 100;
+
+ @Override
+ public void setup() {
+ Table table1 = initTable();
+ addComponent(new Label("Plain table"));
+ addComponent(table1);
+
+ }
+
+ private Table initTable() {
+ Table table = new Table();
+ table.setWidth("100%");
+
+ IndexedContainer idx = new IndexedContainer();
+ idx.addContainerProperty("firstname", String.class, null);
+ idx.addContainerProperty("lastname", String.class, null);
+ Item i = idx.addItem(1);
+ i.getItemProperty("firstname").setValue("John");
+ i.getItemProperty("lastname").setValue("Johnson");
+
+ i = idx.addItem(2);
+ i.getItemProperty("firstname").setValue("Jane");
+ i.getItemProperty("lastname").setValue("Janeine");
+
+ for (int index = 3; index < ROWS; index++) {
+ i = idx.addItem(index);
+ i.getItemProperty("firstname").setValue("Jane");
+ i.getItemProperty("lastname").setValue("Janeine");
+ }
+
+ idx.addContainerProperty("fixed 50px column", String.class, "");
+
+ idx.addContainerProperty("Expanded with 2", String.class, "foobar");
+
+ table.setContainerDataSource(idx);
+
+ table.setColumnHeader("firstname", "FirstName");
+ table.setColumnHeader("lastname", "LastName (1)");
+
+ table.setColumnWidth("fixed 50px column", 50);
+ table.setColumnExpandRatio("Expanded with 2", 2);
+ table.setColumnExpandRatio("lastname", 1);
+
+ return table;
+ }
+
+}
diff --git a/src/com/itmill/toolkit/tests/components/table/ColumnWidths.java b/src/com/itmill/toolkit/tests/components/table/ColumnWidths.java
new file mode 100644
index 0000000000..af03414db5
--- /dev/null
+++ b/src/com/itmill/toolkit/tests/components/table/ColumnWidths.java
@@ -0,0 +1,68 @@
+package com.itmill.toolkit.tests.components.table;
+
+import com.itmill.toolkit.data.Item;
+import com.itmill.toolkit.data.util.IndexedContainer;
+import com.itmill.toolkit.tests.components.TestBase;
+import com.itmill.toolkit.ui.Label;
+import com.itmill.toolkit.ui.Table;
+
+public class ColumnWidths extends TestBase {
+
+ @Override
+ protected String getDescription() {
+ return "On window resize undefined "
+ + "columns (by server or user (dragged)) columns "
+ + "must consume the excess space. Space is divided "
+ + "by default according to natural widths of columns."
+ + " Lastname should get 1/3 of excess spsace, the las column 2/3.";
+
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 2804;
+ }
+
+ private static final int ROWS = 100;
+
+ @Override
+ public void setup() {
+ Table table1 = initTable();
+ addComponent(new Label("Plain table"));
+ addComponent(table1);
+
+ }
+
+ private Table initTable() {
+ Table table = new Table();
+ table.setWidth("100%");
+
+ IndexedContainer idx = new IndexedContainer();
+ idx.addContainerProperty("firstname", String.class, null);
+ idx.addContainerProperty("lastname", String.class, null);
+ Item i = idx.addItem(1);
+ i.getItemProperty("firstname").setValue("John");
+ i.getItemProperty("lastname").setValue("Johnson");
+ i = idx.addItem(2);
+ i.getItemProperty("firstname").setValue("Jane");
+ i.getItemProperty("lastname").setValue("Janeine");
+
+ for (int index = 3; index < ROWS; index++) {
+ i = idx.addItem(index);
+ i.getItemProperty("firstname").setValue("Jane");
+ i.getItemProperty("lastname").setValue("Janeine");
+ }
+
+ idx.addContainerProperty("150pxfixedCol", String.class, "foobar");
+
+ table.setContainerDataSource(idx);
+
+ table.setColumnHeader("firstname", "FirstName");
+ table.setColumnHeader("lastname", "LastName");
+
+ table.setColumnWidth("150pxfixedCol", 150);
+
+ return table;
+ }
+
+}
diff --git a/src/com/itmill/toolkit/tests/components/table/PropertyValueChange.java b/src/com/itmill/toolkit/tests/components/table/PropertyValueChange.java
new file mode 100644
index 0000000000..d767808e50
--- /dev/null
+++ b/src/com/itmill/toolkit/tests/components/table/PropertyValueChange.java
@@ -0,0 +1,158 @@
+package com.itmill.toolkit.tests.components.table;
+
+import com.itmill.toolkit.data.Container;
+import com.itmill.toolkit.data.Property;
+import com.itmill.toolkit.data.Property.ValueChangeEvent;
+import com.itmill.toolkit.data.Property.ValueChangeListener;
+import com.itmill.toolkit.data.util.IndexedContainer;
+import com.itmill.toolkit.tests.components.TestBase;
+import com.itmill.toolkit.ui.BaseFieldFactory;
+import com.itmill.toolkit.ui.Button;
+import com.itmill.toolkit.ui.ComboBox;
+import com.itmill.toolkit.ui.Component;
+import com.itmill.toolkit.ui.Field;
+import com.itmill.toolkit.ui.FieldFactory;
+import com.itmill.toolkit.ui.Label;
+import com.itmill.toolkit.ui.Table;
+import com.itmill.toolkit.ui.AbstractSelect.NewItemHandler;
+import com.itmill.toolkit.ui.Table.ColumnGenerator;
+
+public class PropertyValueChange extends TestBase {
+
+ @Override
+ protected String getDescription() {
+ return "Property value change should only update absolutely "
+ + "needed cells. Tables have common datasource. The first is "
+ + "editable, second one has data in disabled fields, the lastone "
+ + "is plain table that directly shows data. Use first table and "
+ + "combobox/sync button to send changed values to server and evaluate "
+ + "given uidl responses.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 2823;
+ }
+
+ private IndexedContainer container;
+
+ // Also use column generator in test, to ensure it is possible to build
+ // columns that update automatically.
+ ColumnGenerator multiplier = new ColumnGenerator() {
+ private int getMultipliedValue(Property p) {
+ int i = ((Integer) p.getValue()).intValue();
+ return i * 3;
+ }
+
+ public Component generateCell(Table source, Object itemId,
+ Object columnId) {
+ final Label l = new Label();
+ final Property integer = source.getContainerProperty(itemId,
+ "integer");
+ l.setValue(getMultipliedValue(integer));
+
+ // we must hook value change listener to ensure updates in all use
+ // cases (eg. edit mode)
+ if (integer instanceof Property.ValueChangeNotifier) {
+ Property.ValueChangeNotifier notifier = (Property.ValueChangeNotifier) integer;
+ notifier.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ l.setValue(getMultipliedValue(integer));
+ }
+ });
+ }
+ return l;
+ }
+ };
+
+ FieldFactory ff = new MyFieldFactory();
+
+ @Override
+ public void setup() {
+ container = new IndexedContainer();
+
+ container.addContainerProperty("text", String.class, "sampletext");
+ container.addContainerProperty("integer", Integer.class, 5);
+
+ container.addItem();
+ container.addItem();
+
+ Table t1 = new Table(
+ "Editable table with bells and wistles. See description.");
+ t1.setDescription("Opening combobox should never fire table"
+ + " refresh (for this table). Update from textfield "
+ + "(integer) may be sent to server however. The readonly table"
+ + " my refresh, but not this one.");
+ t1.setPageLength(0);
+ t1.setContainerDataSource(container);
+ t1.addGeneratedColumn("integer x 3", multiplier);
+ t1.setFieldFactory(ff);
+ t1.setEditable(true);
+ t1.setDebugId("editortable");
+
+ Table t2 = new Table(
+ "A clone of table1, but disabled. Properties are in components.");
+ t2
+ .setDescription("This table is in editable mode."
+ + " Updates to common datasource should not affect redraw for this "
+ + "table. Only the components inside table should get updated.");
+ t2.setFieldFactory(ff);
+ t2.setEditable(true);
+ t2.setEnabled(false);
+ t2.setContainerDataSource(container);
+ t2.addGeneratedColumn("integer x 3", multiplier);
+ t2.setPageLength(0);
+ t2.setDebugId("disabled table");
+
+ Table reader = new Table("Reader table");
+ reader
+ .setDescription("This table should be redrawn on container changes as container data is "
+ + "displayed directly in cells.");
+ reader.setContainerDataSource(container);
+ reader.addGeneratedColumn("integer x 3", multiplier);
+ reader.setPageLength(0);
+ reader.setDebugId("reader table");
+
+ getLayout().addComponent(t1);
+ getLayout().addComponent(t2);
+ getLayout().addComponent(reader);
+ getLayout().addComponent(new Button("Sync!"));
+
+ }
+}
+
+class MyFieldFactory extends BaseFieldFactory {
+
+ IndexedContainer texts = new IndexedContainer();
+
+ public MyFieldFactory() {
+ texts.addItem("sampletext");
+ texts.addItem("foo");
+ texts.addItem("bar");
+ for (int i = 0; i < 100; i++) {
+ texts.addItem("foo" + 1);
+ }
+
+ }
+
+ @Override
+ public Field createField(Container container, Object itemId,
+ Object propertyId, Component uiContext) {
+ if (propertyId.equals("text")) {
+ // replace text fields with comboboxes
+ final ComboBox cb = new ComboBox() {
+ };
+ cb.setContainerDataSource(texts);
+ cb.setNewItemsAllowed(true);
+ cb.setNewItemHandler(new NewItemHandler() {
+ public void addNewItem(String newItemCaption) {
+ texts.addItem(newItemCaption);
+ cb.setValue(newItemCaption);
+ }
+ });
+ return cb;
+ }
+
+ return super.createField(container, itemId, propertyId, uiContext);
+ }
+}
diff --git a/src/com/itmill/toolkit/tests/components/table/RowAdditionTest.java b/src/com/itmill/toolkit/tests/components/table/RowAdditionTest.java
new file mode 100644
index 0000000000..b01abd62c0
--- /dev/null
+++ b/src/com/itmill/toolkit/tests/components/table/RowAdditionTest.java
@@ -0,0 +1,59 @@
+package com.itmill.toolkit.tests.components.table;
+
+import com.itmill.toolkit.data.Item;
+import com.itmill.toolkit.data.util.IndexedContainer;
+import com.itmill.toolkit.tests.components.TestBase;
+import com.itmill.toolkit.ui.Button;
+import com.itmill.toolkit.ui.HorizontalLayout;
+import com.itmill.toolkit.ui.Table;
+import com.itmill.toolkit.ui.Button.ClickEvent;
+
+public class RowAdditionTest extends TestBase {
+
+ @Override
+ protected String getDescription() {
+ return "Adding a row should refresh client area only if newly added row is in the rendered area.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return new Integer(2799);
+ }
+
+ @Override
+ protected void setup() {
+ final Table table = new Table();
+ final IndexedContainer container = (IndexedContainer) table
+ .getContainerDataSource();
+ table.addContainerProperty("column1", String.class, "test");
+
+ for (int i = 0; i < 100; ++i) {
+ table.addItem();
+ }
+
+ HorizontalLayout hl = new HorizontalLayout();
+ hl.addComponent(new Button("Add first", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ Item item = container.addItemAt(0, new Object());
+ item.getItemProperty("column1").setValue("0");
+ }
+ }));
+ hl.addComponent(new Button("Add at position 50",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ Item item = container.addItemAt(50, new Object());
+ item.getItemProperty("column1").setValue("50");
+ }
+ }));
+ hl.addComponent(new Button("Add at position 100",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ Item item = container.addItemAt(100, new Object());
+ item.getItemProperty("column1").setValue("100");
+ }
+ }));
+
+ getLayout().addComponent(table);
+ getLayout().addComponent(hl);
+ }
+}
diff --git a/src/com/itmill/toolkit/tests/components/table/TableRowHeight2.java b/src/com/itmill/toolkit/tests/components/table/TableRowHeight2.java
index 39f6a51c49..f02a110bab 100644
--- a/src/com/itmill/toolkit/tests/components/table/TableRowHeight2.java
+++ b/src/com/itmill/toolkit/tests/components/table/TableRowHeight2.java
@@ -35,11 +35,13 @@ public class TableRowHeight2 extends TestBase {
Item item = table.addItem(new Object());
Button b = new Button();
+ b.setWidth("100%");
+ b.setStyleName(Button.STYLE_LINK);
+ b.addStyleName("nowraplink");
b
.setCaption("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi ullamcorper, elit quis elementum iaculis, dui est rutrum risus, at cursus sem leo eget arcu. Proin vel eros ut tortor luctus pretium. Nulla facilisi. Donec in dui. Proin ac diam vitae massa tempus faucibus. Fusce eu risus. Nunc ac risus. Cras libero.");
- b.setStyleName(Button.STYLE_LINK);
item.getItemProperty("title").setValue(b);
Button c = new Button("test");
diff --git a/src/com/itmill/toolkit/tests/components/table/TableRowHeight3.java b/src/com/itmill/toolkit/tests/components/table/TableRowHeight3.java
new file mode 100644
index 0000000000..56f4289605
--- /dev/null
+++ b/src/com/itmill/toolkit/tests/components/table/TableRowHeight3.java
@@ -0,0 +1,61 @@
+package com.itmill.toolkit.tests.components.table;
+
+import com.itmill.toolkit.data.Item;
+import com.itmill.toolkit.tests.components.TestBase;
+import com.itmill.toolkit.ui.Button;
+import com.itmill.toolkit.ui.HorizontalLayout;
+import com.itmill.toolkit.ui.Table;
+
+public class TableRowHeight3 extends TestBase {
+
+ @Override
+ protected String getDescription() {
+ return "All rows should be visible and the table height should match the height of the rows (no vertical scrollbar)";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 2747;
+ }
+
+ @Override
+ protected void setup() {
+ setTheme("tests-tickets");
+ HorizontalLayout vl = new HorizontalLayout();
+ vl.setSizeFull();
+
+ Table table = new Table();
+ table.setWidth("320px");
+ table.setPageLength(0);
+ table.setColumnWidth("title", 200);
+ table.setColumnWidth("test", 98);
+ table.addContainerProperty("title", Button.class, "");
+ table.addContainerProperty("test", Button.class, "");
+ for (int i = 0; i < 6; i++) {
+ Item item = table.addItem(new Object());
+
+ Button b = new Button();
+ b.setWidth("100%");
+ b.setStyleName(Button.STYLE_LINK);
+ b.addStyleName("nowraplink");
+ if (i < 2) {
+ b
+ .setCaption("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi ullamcorper, elit quis elementum iaculis, dui est rutrum risus, at cursus sem leo eget arcu. Proin vel eros ut tortor luctus pretium. Nulla facilisi. Donec in dui. Proin ac diam vitae massa tempus faucibus. Fusce eu risus. Nunc ac risus. Cras libero.");
+ } else if (2 <= i && i < 4) {
+ b.setCaption("One line");
+ } else {
+ b.setCaption("This button caption should use up two lines");
+ }
+ item.getItemProperty("title").setValue(b);
+
+ Button c = new Button("test");
+ item.getItemProperty("test").setValue(c);
+ }
+
+ vl.addComponent(table);
+
+ addComponent(vl);
+
+ }
+
+}
diff --git a/src/com/itmill/toolkit/tests/components/window/WindowResizeListener.java b/src/com/itmill/toolkit/tests/components/window/WindowResizeListener.java
new file mode 100644
index 0000000000..63956d524f
--- /dev/null
+++ b/src/com/itmill/toolkit/tests/components/window/WindowResizeListener.java
@@ -0,0 +1,99 @@
+package com.itmill.toolkit.tests.components.window;
+
+import com.itmill.toolkit.terminal.Sizeable;
+import com.itmill.toolkit.tests.components.TestBase;
+import com.itmill.toolkit.ui.Button;
+import com.itmill.toolkit.ui.CheckBox;
+import com.itmill.toolkit.ui.Label;
+import com.itmill.toolkit.ui.Layout;
+import com.itmill.toolkit.ui.Window;
+import com.itmill.toolkit.ui.Button.ClickEvent;
+import com.itmill.toolkit.ui.Window.ResizeEvent;
+import com.itmill.toolkit.ui.Window.ResizeListener;
+
+public class WindowResizeListener extends TestBase {
+
+ @Override
+ protected String getDescription() {
+ return "Size changes from windows (both sub "
+ + "and browsers level) should get back to server."
+ + " If size changes, a separate server side event should occur.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return null;
+ }
+
+ Window subwin = new ResizeListenerWindow();
+
+ @Override
+ protected void setup() {
+
+ final Label l = new Label();
+ getLayout().addComponent(l);
+
+ getMainWindow().addListener(new ResizeListener() {
+ public void windowResized(ResizeEvent e) {
+ l.setValue("Current main window size: "
+ + getMainWindow().getWidth() + " x "
+ + getMainWindow().getHeight());
+ }
+ });
+
+ CheckBox subwindow = new CheckBox("show subwindow");
+ subwindow.setImmediate(true);
+ subwindow.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ if (event.getButton().booleanValue()) {
+ getMainWindow().addWindow(subwin);
+ } else {
+ getMainWindow().removeWindow(subwin);
+ }
+ }
+ });
+ getLayout().addComponent(subwindow);
+
+ CheckBox immediate = new CheckBox("immediate");
+ immediate.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ boolean booleanValue = event.getButton().booleanValue();
+ getMainWindow().setImmediate(booleanValue);
+ subwin.setImmediate(booleanValue);
+ }
+ });
+ immediate.setImmediate(true);
+ getLayout().addComponent(immediate);
+
+ getLayout().addComponent(new Button("Sync"));
+
+ }
+}
+
+class ResizeListenerWindow extends Window {
+ Label sizeLabel = new Label();
+
+ public ResizeListenerWindow() {
+ super("Subwindow");
+ setWidth("400px");
+
+ Layout hl = getLayout();
+ hl.addComponent(new Label("Current size: "));
+ hl.addComponent(sizeLabel);
+
+ addListener(new ResizeListener() {
+ public void windowResized(ResizeEvent e) {
+ updateLabel();
+ }
+ });
+
+ updateLabel();
+ }
+
+ public void updateLabel() {
+ sizeLabel
+ .setValue(getWidth() + Sizeable.UNIT_SYMBOLS[getWidthUnits()]
+ + " x " + getHeight()
+ + Sizeable.UNIT_SYMBOLS[getHeightUnits()]);
+ }
+}
diff --git a/src/com/itmill/toolkit/tests/containers/BeanItemContainerFilteringTest.java b/src/com/itmill/toolkit/tests/containers/BeanItemContainerFilteringTest.java
new file mode 100644
index 0000000000..be3f8b1861
--- /dev/null
+++ b/src/com/itmill/toolkit/tests/containers/BeanItemContainerFilteringTest.java
@@ -0,0 +1,172 @@
+package com.itmill.toolkit.tests.containers;
+
+import com.itmill.toolkit.data.Item;
+import com.itmill.toolkit.data.util.BeanItemContainer;
+import com.itmill.toolkit.terminal.Sizeable;
+import com.itmill.toolkit.tests.components.TestBase;
+import com.itmill.toolkit.ui.Button;
+import com.itmill.toolkit.ui.CheckBox;
+import com.itmill.toolkit.ui.Label;
+import com.itmill.toolkit.ui.Table;
+import com.itmill.toolkit.ui.TextField;
+import com.itmill.toolkit.ui.VerticalLayout;
+import com.itmill.toolkit.ui.Button.ClickEvent;
+
+public class BeanItemContainerFilteringTest extends TestBase {
+
+ private Table table;
+ private BeanItemContainer<TestBean> container;
+ private TextField filterString;
+ private TextField position;
+ private int nextToAdd = 1;
+ private Label nextLabel;
+
+ protected static class TestBean {
+ private String id;
+ private String value;
+
+ public TestBean() {
+ }
+
+ public TestBean(String id, String value) {
+ setId(id);
+ setValue(value);
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Test adding items in a filtered BeanItemContainer.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return new Integer(1061);
+ }
+
+ @Override
+ protected void setup() {
+ table = new Table();
+ try {
+ container = new BeanItemContainer<TestBean>(TestBean.class);
+ table.setContainerDataSource(container);
+
+ table.setWidth(300, Sizeable.UNITS_PIXELS);
+ table.setSelectable(true);
+ table.setMultiSelect(false);
+ table.setEditable(true);
+ table.setImmediate(true);
+ // table.addContainerProperty("column1", String.class, "test");
+
+ for (int i = 0; i < 25; ++i) {
+ container.addItem(new TestBean("Item " + i, "Value for " + i));
+ }
+
+ VerticalLayout vl = new VerticalLayout();
+
+ // activate & deactivate filtering
+ filterString = new TextField("Filter string:", "1");
+ vl.addComponent(filterString);
+
+ final CheckBox cb = new CheckBox("Filter on value",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ container.removeAllContainerFilters();
+ if (((CheckBox) event.getSource()).booleanValue()) {
+ container.addContainerFilter("value",
+ filterString.getValue().toString(),
+ false, false);
+ }
+ }
+ });
+ cb.setImmediate(true);
+ vl.addComponent(cb);
+
+ nextLabel = new Label();
+ nextLabel.setCaption("Next id: " + nextToAdd);
+ vl.addComponent(nextLabel);
+
+ // addItemAt(idx), addItemAfter(selection), addItem()
+
+ final Button addItemButton = new Button("addItem()",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ container.addItem(new TestBean("addItem() "
+ + nextToAdd, "value " + nextToAdd));
+ nextToAdd++;
+ nextLabel.setCaption("Next id: " + nextToAdd);
+ }
+ });
+ addItemButton.setImmediate(true);
+ vl.addComponent(addItemButton);
+
+ final Button addItemAfterButton = new Button("addItemAfter()",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ Object selection = table.getValue();
+ if (selection == null) {
+ return;
+ }
+ TestBean bean = new TestBean("addItemAfter() "
+ + nextToAdd, "value " + nextToAdd);
+ Item item = container.addItemAfter(selection, bean);
+ if (item == null) {
+ getMainWindow().showNotification(
+ "Adding item after " + selection
+ + " failed");
+ }
+ nextToAdd++;
+ nextLabel.setCaption("Next id: " + nextToAdd);
+ }
+ });
+ addItemAfterButton.setImmediate(true);
+ vl.addComponent(addItemAfterButton);
+
+ position = new TextField("Position:", "0");
+ vl.addComponent(position);
+
+ final Button addItemAtButton = new Button("addItemAt()",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ int index = Integer.parseInt(position.getValue()
+ .toString());
+ TestBean bean = new TestBean("addItemAt() "
+ + nextToAdd, "value " + nextToAdd);
+ Item item = container.addItemAt(index, bean);
+ if (item == null) {
+ getMainWindow().showNotification(
+ "Adding item at index "
+ + position.getValue()
+ + " failed");
+ }
+ nextToAdd++;
+ nextLabel.setCaption("Next id: " + nextToAdd);
+ }
+ });
+ addItemAtButton.setImmediate(true);
+ vl.addComponent(addItemAtButton);
+
+ getLayout().addComponent(table);
+ getLayout().addComponent(vl);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+}
diff --git a/src/com/itmill/toolkit/tests/containers/BeanItemContainerTest.java b/src/com/itmill/toolkit/tests/containers/BeanItemContainerTest.java
new file mode 100644
index 0000000000..bbfc72fb02
--- /dev/null
+++ b/src/com/itmill/toolkit/tests/containers/BeanItemContainerTest.java
@@ -0,0 +1,75 @@
+package com.itmill.toolkit.tests.containers;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+import com.itmill.toolkit.data.util.BeanItemContainer;
+
+public class BeanItemContainerTest {
+
+ /**
+ * Test class for BeanItemContainer
+ *
+ * @throws IllegalAccessException
+ * @throws InstantiationException
+ */
+ public static void main(String[] args) throws InstantiationException,
+ IllegalAccessException {
+ BeanItemContainer<Hello> c = new BeanItemContainer<Hello>(Hello.class);
+ c.addItem(new Hello());
+
+ Collection<Hello> col = new LinkedList<Hello>();
+ for (int i = 0; i < 100; i++) {
+ col.add(new Hello());
+ }
+ col.add(new Hello2());
+
+ c = new BeanItemContainer<Hello>(col);
+
+ System.out.println(c + " contains " + c.size() + " objects");
+
+ // test that subclass properties are handled correctly
+ System.out.println(c + " item 0 second = "
+ + c.getContainerProperty(c.getIdByIndex(0), "second"));
+ System.out.println(c + " item 100 second = "
+ + c.getContainerProperty(c.getIdByIndex(100), "second"));
+
+ }
+
+ public static class Hello {
+
+ public String first;
+ public String second;
+
+ public Hello() {
+ first = "f";
+ second = "l";
+ }
+
+ public String getFirst() {
+ return first;
+ }
+
+ public void setFirst(String first) {
+ this.first = first;
+ }
+
+ public String getSecond() {
+ return second;
+ }
+
+ public void setSecond(String second) {
+ this.second = second;
+ }
+
+ }
+
+ public static class Hello2 extends Hello {
+
+ @Override
+ public String getSecond() {
+ return "second";
+ }
+
+ }
+}
diff --git a/src/com/itmill/toolkit/tests/containers/IndexedContainerFilteringTest.java b/src/com/itmill/toolkit/tests/containers/IndexedContainerFilteringTest.java
new file mode 100644
index 0000000000..00cb1e3355
--- /dev/null
+++ b/src/com/itmill/toolkit/tests/containers/IndexedContainerFilteringTest.java
@@ -0,0 +1,139 @@
+package com.itmill.toolkit.tests.containers;
+
+import com.itmill.toolkit.data.Item;
+import com.itmill.toolkit.data.util.IndexedContainer;
+import com.itmill.toolkit.terminal.Sizeable;
+import com.itmill.toolkit.tests.components.TestBase;
+import com.itmill.toolkit.ui.Button;
+import com.itmill.toolkit.ui.CheckBox;
+import com.itmill.toolkit.ui.Label;
+import com.itmill.toolkit.ui.Table;
+import com.itmill.toolkit.ui.TextField;
+import com.itmill.toolkit.ui.VerticalLayout;
+import com.itmill.toolkit.ui.Button.ClickEvent;
+
+public class IndexedContainerFilteringTest extends TestBase {
+
+ private Table table;
+ private IndexedContainer container;
+ private TextField filterString;
+ private TextField position;
+ private int nextToAdd = 1;
+ private Label nextLabel;
+
+ @Override
+ protected String getDescription() {
+ return "Adding items to a filtered IndexedContainer inserts the items at the wrong location.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return new Integer(2809);
+ }
+
+ @Override
+ protected void setup() {
+ table = new Table();
+ container = (IndexedContainer) table.getContainerDataSource();
+
+ table.setWidth(300, Sizeable.UNITS_PIXELS);
+ table.setSelectable(true);
+ table.setMultiSelect(false);
+ table.addContainerProperty("column1", String.class, "test");
+
+ for (int i = 0; i < 25; ++i) {
+ table.addItem(new Object[] { "Item " + i }, "Item " + i);
+ }
+
+ VerticalLayout vl = new VerticalLayout();
+
+ // activate & deactivate filtering
+ filterString = new TextField("Filter string:", "1");
+ vl.addComponent(filterString);
+
+ final CheckBox cb = new CheckBox("Filter", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ container.removeAllContainerFilters();
+ if (((CheckBox) event.getSource()).booleanValue()) {
+ container.addContainerFilter("column1", filterString
+ .getValue().toString(), false, false);
+ }
+ }
+ });
+ cb.setImmediate(true);
+ vl.addComponent(cb);
+
+ nextLabel = new Label();
+ nextLabel.setCaption("Next id: " + nextToAdd);
+ vl.addComponent(nextLabel);
+
+ // addItemAt(idx), addItemAfter(selection), addItem()
+
+ final Button addItemButton = new Button("addItem()",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ Item item = container.addItem("addItem() " + nextToAdd);
+ if (item != null) {
+ item.getItemProperty("column1").setValue(
+ "addItem() " + nextToAdd);
+ }
+ nextToAdd++;
+ nextLabel.setCaption("Next id: " + nextToAdd);
+ }
+ });
+ addItemButton.setImmediate(true);
+ vl.addComponent(addItemButton);
+
+ final Button addItemAfterButton = new Button("addItemAfter()",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ Object selection = table.getValue();
+ if (selection == null) {
+ return;
+ }
+ String id = "addItemAfter() " + nextToAdd;
+ Item item = container.addItemAfter(selection, id);
+ if (item != null) {
+ item.getItemProperty("column1").setValue(id);
+ table.setValue(id);
+ } else {
+ getMainWindow().showNotification(
+ "Adding item after " + selection
+ + " failed");
+ }
+ nextToAdd++;
+ nextLabel.setCaption("Next id: " + nextToAdd);
+ }
+ });
+ addItemAfterButton.setImmediate(true);
+ vl.addComponent(addItemAfterButton);
+
+ position = new TextField("Position:", "0");
+ vl.addComponent(position);
+
+ final Button addItemAtButton = new Button("addItemAt()",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ int index = Integer.parseInt(position.getValue()
+ .toString());
+ String id = "addItemAt() " + nextToAdd;
+ Item item = container.addItemAt(index, id);
+ if (item != null) {
+ item.getItemProperty("column1").setValue(id);
+ table.setValue(id);
+ } else {
+ getMainWindow().showNotification(
+ "Adding item at index "
+ + position.getValue() + " failed");
+ }
+ nextToAdd++;
+ nextLabel.setCaption("Next id: " + nextToAdd);
+ }
+ });
+ addItemAtButton.setImmediate(true);
+ vl.addComponent(addItemAtButton);
+
+ getLayout().addComponent(table);
+ getLayout().addComponent(vl);
+ }
+}
diff --git a/src/com/itmill/toolkit/tests/tickets/Ticket2742.java b/src/com/itmill/toolkit/tests/tickets/Ticket2742.java
new file mode 100644
index 0000000000..77ab797035
--- /dev/null
+++ b/src/com/itmill/toolkit/tests/tickets/Ticket2742.java
@@ -0,0 +1,42 @@
+/**
+ *
+ */
+package com.itmill.toolkit.tests.tickets;
+
+import com.itmill.toolkit.Application;
+import com.itmill.toolkit.ui.HorizontalLayout;
+import com.itmill.toolkit.ui.NativeSelect;
+import com.itmill.toolkit.ui.Window;
+
+/**
+ * @author Risto Yrjänä / IT Mill Ltd.
+ *
+ */
+public class Ticket2742 extends Application {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.itmill.toolkit.Application#init()
+ */
+ @Override
+ public void init() {
+ Window mainWindow = new Window();
+ setMainWindow(mainWindow);
+
+ String shortString = "Short";
+ String longString = "Very, very long";
+
+ HorizontalLayout hl = new HorizontalLayout();
+
+ for (int i = 0; i < 2; i++) {
+ NativeSelect ns = new NativeSelect(shortString);
+ ns.addItem(longString);
+ ns.setNullSelectionAllowed(false);
+ ns.select(longString);
+ hl.addComponent(ns);
+ }
+ mainWindow.addComponent(hl);
+ }
+
+} \ No newline at end of file
diff --git a/src/com/itmill/toolkit/tests/validation/TestValidators.java b/src/com/itmill/toolkit/tests/validation/TestValidators.java
new file mode 100644
index 0000000000..2a75bdd406
--- /dev/null
+++ b/src/com/itmill/toolkit/tests/validation/TestValidators.java
@@ -0,0 +1,163 @@
+package com.itmill.toolkit.tests.validation;
+
+import com.itmill.toolkit.data.Validator;
+import com.itmill.toolkit.data.validator.AbstractStringValidator;
+import com.itmill.toolkit.data.validator.CompositeValidator;
+import com.itmill.toolkit.data.validator.DoubleValidator;
+import com.itmill.toolkit.data.validator.EmailValidator;
+import com.itmill.toolkit.data.validator.IntegerValidator;
+import com.itmill.toolkit.data.validator.RegexpValidator;
+import com.itmill.toolkit.data.validator.StringLengthValidator;
+import com.itmill.toolkit.tests.components.TestBase;
+import com.itmill.toolkit.ui.Button;
+import com.itmill.toolkit.ui.Form;
+import com.itmill.toolkit.ui.TextField;
+import com.itmill.toolkit.ui.VerticalLayout;
+import com.itmill.toolkit.ui.Button.ClickEvent;
+import com.itmill.toolkit.ui.Button.ClickListener;
+import com.itmill.toolkit.ui.Window.Notification;
+
+public class TestValidators extends TestBase {
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 680;
+ }
+
+ @Override
+ protected String getDescription() {
+ return "This test verifies that various validators work correctly";
+ }
+
+ @Override
+ public void setup() {
+ final Form form = new Form(new VerticalLayout());
+
+ // simple validators
+
+ TextField tf = new TextField("A field, must contain 1-2 chars");
+ tf
+ .addValidator(new StringLengthValidator("Invalid length", 1, 2,
+ false));
+ tf.setRequired(true);
+ tf.setValue("ab");
+ form.addField("a", tf);
+
+ tf = new TextField("A field, must contain an integer");
+ tf.addValidator(new IntegerValidator("Invalid integer {0}"));
+ tf.setRequired(true);
+ tf.setValue("123");
+ form.addField("b", tf);
+
+ tf = new TextField("A field, must contain an integer or be empty");
+ tf.addValidator(new IntegerValidator("Invalid integer {0}"));
+ tf.setValue("-321");
+ form.addField("c", tf);
+
+ tf = new TextField(
+ "A field, must contain a floating point number or be empty");
+ tf.addValidator(new DoubleValidator("Invalid double {0}"));
+ tf.setValue("-123.45e6");
+ form.addField("d", tf);
+
+ tf = new TextField(
+ "A field, must contain an e-mail address or be empty");
+ tf.addValidator(new EmailValidator("Invalid e-mail address {0}"));
+ tf.setValue("a.b@example.com");
+ form.addField("e", tf);
+
+ // regular expressions
+
+ tf = new TextField("A field, must match the regular expression a.*b.*c");
+ tf.addValidator(new RegexpValidator("a.*b.*c",
+ "{0} does not match the regular expression"));
+ tf.setValue("aagsabeqgc");
+ form.addField("f", tf);
+
+ tf = new TextField(
+ "A field, must contain the regular expression a.*b.*c");
+ tf.addValidator(new RegexpValidator("a.*b.*c", false,
+ "{0} does not contain the regular expression"));
+ tf.setValue("aagsabeqgc");
+ form.addField("g", tf);
+
+ tf = new TextField(
+ "A field, must match the regular expression ^a.*b.*c$");
+ tf.addValidator(new RegexpValidator("^a.*b.*c$", false,
+ "{0} does not match the regular expression with ^ and $"));
+ tf.setValue("aagsabeqgc");
+ form.addField("h", tf);
+
+ tf = new TextField(
+ "A field, must contain the regular expression ^a.*b.*c$");
+ tf.addValidator(new RegexpValidator("^a.*b.*c$", false,
+ "{0} does not contain the regular expression with ^ and $"));
+ tf.setValue("aagsabeqgc");
+ form.addField("i", tf);
+
+ // TODO CompositeValidator
+ tf = new TextField(
+ "A field, must be a floating point number with 4-5 chars");
+ CompositeValidator cv = new CompositeValidator(
+ CompositeValidator.MODE_AND,
+ "The field must contain a floating point number with 4-5 characters");
+ cv
+ .addValidator(new StringLengthValidator(
+ "String length of '{0}' should be 4-5 characters", 4,
+ 5, false));
+ cv.addValidator(new DoubleValidator(
+ "{0} must be a floating point number"));
+ tf.addValidator(cv);
+ tf.setValue("12.34");
+ form.addField("j", tf);
+
+ // Postal code that must be 5 digits (10000-99999).
+ tf = new TextField("Postal Code");
+ tf.setColumns(5);
+
+ // Create the validator - this would be even easier with RegexpValidator
+ Validator postalCodeValidator = new AbstractStringValidator(
+ "Postal code must be a number 10000-99999.") {
+ @Override
+ protected boolean isValidString(String value) {
+ return value.matches("[1-9][0-9]{4}");
+ }
+ };
+ tf.addValidator(postalCodeValidator);
+ tf.setValue("12345");
+ form.addField("k", tf);
+
+ Button b = new Button("Commit", new ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ try {
+ form.commit();
+ if (form.isValid()) {
+ getMainWindow().showNotification(
+ "OK! Form validated and no error was thrown",
+ Notification.TYPE_HUMANIZED_MESSAGE);
+ } else {
+ getMainWindow().showNotification(
+ "Form is invalid but no exception was thrown",
+ Notification.TYPE_ERROR_MESSAGE);
+ }
+ } catch (Exception e) {
+ if (form.isValid()) {
+ getMainWindow().showNotification(
+ "Form is valid but an exception was thrown",
+ Notification.TYPE_ERROR_MESSAGE);
+ } else {
+ getMainWindow().showNotification(
+ "OK! Error was thrown for an invalid input",
+ Notification.TYPE_HUMANIZED_MESSAGE);
+
+ }
+ }
+ }
+
+ });
+
+ addComponent(form);
+ addComponent(b);
+ }
+}
diff --git a/src/com/itmill/toolkit/ui/ComboBox.java b/src/com/itmill/toolkit/ui/ComboBox.java
index f29b51b7d9..1c251ef0a0 100644
--- a/src/com/itmill/toolkit/ui/ComboBox.java
+++ b/src/com/itmill/toolkit/ui/ComboBox.java
@@ -7,6 +7,8 @@ package com.itmill.toolkit.ui;
import java.util.Collection;
import com.itmill.toolkit.data.Container;
+import com.itmill.toolkit.terminal.PaintException;
+import com.itmill.toolkit.terminal.PaintTarget;
/**
* A filtering dropdown single-select. Suitable for newItemsAllowed, but it's
@@ -18,7 +20,7 @@ import com.itmill.toolkit.data.Container;
*/
public class ComboBox extends Select {
- private String emptyText = null;
+ private String inputPrompt = null;
public ComboBox() {
setMultiSelect(false);
@@ -51,21 +53,32 @@ public class ComboBox extends Select {
super.setMultiSelect(multiSelect);
}
- /*- TODO enable and test this - client impl exists
- public String getEmptyText() {
- return emptyText;
+ /**
+ * Gets the current input prompt.
+ *
+ * @see #setInputPrompt(String)
+ * @return the current input prompt, or null if not enabled
+ */
+ public String getInputPrompt() {
+ return inputPrompt;
}
- public void setEmptyText(String emptyText) {
- this.emptyText = emptyText;
+ /**
+ * Sets the input prompt - a textual prompt that is displayed when the
+ * select would otherwise be empty, to prompt the user for input.
+ *
+ * @param inputPrompt
+ * the desired input prompt, or null to disable
+ */
+ public void setInputPrompt(String inputPrompt) {
+ this.inputPrompt = inputPrompt;
}
public void paintContent(PaintTarget target) throws PaintException {
- if (emptyText != null) {
- target.addAttribute("emptytext", emptyText);
+ if (inputPrompt != null) {
+ target.addAttribute("prompt", inputPrompt);
}
super.paintContent(target);
}
- -*/
}
diff --git a/src/com/itmill/toolkit/ui/DateField.java b/src/com/itmill/toolkit/ui/DateField.java
index aaa53e3ee1..96ddc08b9e 100644
--- a/src/com/itmill/toolkit/ui/DateField.java
+++ b/src/com/itmill/toolkit/ui/DateField.java
@@ -107,6 +107,12 @@ public class DateField extends AbstractField {
*/
private String dateFormat;
+ /**
+ * Read-only content of an ITextualDate field - null for other types of date
+ * fields.
+ */
+ private String dateString;
+
/* Constructors */
/**
@@ -258,13 +264,23 @@ public class DateField extends AbstractField {
|| variables.containsKey("day")
|| variables.containsKey("hour")
|| variables.containsKey("min")
- || variables.containsKey("sec") || variables
- .containsKey("msec"))) {
+ || variables.containsKey("sec")
+ || variables.containsKey("msec") || variables
+ .containsKey("dateString"))) {
// Old and new dates
final Date oldDate = (Date) getValue();
+ final String oldDateString = dateString;
Date newDate = null;
+ // this enables analyzing invalid input on the server
+ Object o = variables.get("dateString");
+ if (o != null) {
+ dateString = o.toString();
+ } else {
+ dateString = null;
+ }
+
// Gets the new date in parts
// Null values are converted to negative values.
int year = variables.containsKey("year") ? (variables.get("year") == null ? -1
@@ -326,10 +342,39 @@ public class DateField extends AbstractField {
&& (newDate == null || !newDate.equals(oldDate))) {
setValue(newDate, true); // Don't require a repaint, client
// updates itself
+ } else if (dateString != null && !"".equals(dateString)
+ && !dateString.equals(oldDateString)) {
+ setValue(handleUnparsableDateString(dateString));
}
}
}
+ /**
+ * This method is called to handle the date string from the client if the
+ * client could not parse it as a Date.
+ *
+ * By default, null is returned. If an exception is thrown, the current
+ * value will not be modified.
+ *
+ * This can be overridden to handle conversions or to throw an exception, or
+ * to fire an event.
+ *
+ * The default behavior is likely to change in the next major version of the
+ * toolkit - a Property.ConversionException will be thrown.
+ *
+ * @param dateString
+ * @return parsed Date
+ * @throws Property.ConversionException
+ * to keep the old value and indicate an error
+ */
+ protected Date handleUnparsableDateString(String dateString)
+ throws Property.ConversionException {
+ // TODO in the next major version, this should throw an exception to be
+ // consistent with other fields
+ // throw new Property.ConversionException();
+ return null;
+ }
+
/* Property features */
/*
diff --git a/src/com/itmill/toolkit/ui/Layout.java b/src/com/itmill/toolkit/ui/Layout.java
index 06d9b2b3bf..78de97eaa8 100644
--- a/src/com/itmill/toolkit/ui/Layout.java
+++ b/src/com/itmill/toolkit/ui/Layout.java
@@ -145,44 +145,59 @@ public interface Layout extends ComponentContainer {
}
/**
- * This type of layout can set spacing between its components on of off.
+ * This type of layout supports automatic addition of space between its
+ * components.
*
- * TODO refine javadocs
*/
public interface SpacingHandler {
/**
* Enable spacing between child components within this layout.
*
* <p>
- * <strong>NOTE:</strong> This will only affect spaces between
- * components, not also all around spacing of the layout (i.e. do not
- * mix this with HTML Table elements cellspacing-attribute). Use
- * {@link #setMargin(boolean)} to add extra space around the layout.
+ * <strong>NOTE:</strong> This will only affect the space between
+ * components, not the space around all the components in the layout
+ * (i.e. do not confuse this with the cellspacing attribute of a HTML
+ * Table). Use {@link #setMargin(boolean)} to add space around the
+ * layout.
+ * </p>
+ *
+ * <p>
+ * See the reference manual for more information about CSS rules for
+ * defining the amount of spacing to use.
* </p>
*
* @param enabled
+ * true if spacing should be turned on, false if it should be
+ * turned off
*/
public void setSpacing(boolean enabled);
/**
*
- * @return true if spacing, layout leaves space between components
+ * @return true if spacing between child components within this layout
+ * is enabled, false otherwise
*/
public boolean isSpacingEnabled();
}
/**
- * This type of layout can enable margins.
+ * This type of layout supports automatic addition of margins (space around
+ * its components).
*/
public interface MarginHandler {
/**
* Enable margins for this layout.
*
* <p>
- * <strong>NOTE:</strong> This will only affect margins for the layout,
- * not spacing between components inside the layout. Use
- * {@link #setSpacing(boolean)} to add space between components in the
- * layout.
+ * <strong>NOTE:</strong> This will only affect the space around the
+ * components in the layout, not space between the components in the
+ * layout. Use {@link #setSpacing(boolean)} to add space between the
+ * components in the layout.
+ * </p>
+ *
+ * <p>
+ * See the reference manual for more information about CSS rules for
+ * defining the size of the margin.
* </p>
*
* @param marginInfo
diff --git a/src/com/itmill/toolkit/ui/ProgressIndicator.java b/src/com/itmill/toolkit/ui/ProgressIndicator.java
index ea788ac0b2..fc5b308b64 100644
--- a/src/com/itmill/toolkit/ui/ProgressIndicator.java
+++ b/src/com/itmill/toolkit/ui/ProgressIndicator.java
@@ -133,7 +133,7 @@ public class ProgressIndicator extends AbstractField implements Property,
@Override
public Object getValue() {
if (dataSource == null) {
- throw new IllegalStateException("Datasource must be se");
+ throw new IllegalStateException("Datasource must be set");
}
return dataSource.getValue();
}
@@ -149,7 +149,7 @@ public class ProgressIndicator extends AbstractField implements Property,
@Override
public void setValue(Object newValue) {
if (dataSource == null) {
- throw new IllegalStateException("Datasource must be se");
+ throw new IllegalStateException("Datasource must be set");
}
dataSource.setValue(newValue);
}
@@ -160,7 +160,7 @@ public class ProgressIndicator extends AbstractField implements Property,
@Override
public String toString() {
if (dataSource == null) {
- throw new IllegalStateException("Datasource must be se");
+ throw new IllegalStateException("Datasource must be set");
}
return dataSource.toString();
}
@@ -171,7 +171,7 @@ public class ProgressIndicator extends AbstractField implements Property,
@Override
public Class getType() {
if (dataSource == null) {
- throw new IllegalStateException("Datasource must be se");
+ throw new IllegalStateException("Datasource must be set");
}
return dataSource.getType();
}
diff --git a/src/com/itmill/toolkit/ui/RichTextArea.java b/src/com/itmill/toolkit/ui/RichTextArea.java
index 213eb2635b..fad763819d 100644
--- a/src/com/itmill/toolkit/ui/RichTextArea.java
+++ b/src/com/itmill/toolkit/ui/RichTextArea.java
@@ -8,7 +8,7 @@ import com.itmill.toolkit.terminal.PaintException;
import com.itmill.toolkit.terminal.PaintTarget;
/**
- * A simple RichTextEditor to edit HTML format text.
+ * A simple RichTextArea to edit HTML format text.
*
* Note, that using {@link TextField#setMaxLength(int)} method in
* {@link RichTextArea} may produce unexpected results as formatting is counted
@@ -22,4 +22,13 @@ public class RichTextArea extends TextField {
super.paintContent(target);
}
+ /**
+ * RichTextArea does not support input prompt.
+ */
+ @Override
+ public void setInputPrompt(String inputPrompt) {
+ throw new UnsupportedOperationException(
+ "RichTextArea does not support inputPrompt");
+ }
+
}
diff --git a/src/com/itmill/toolkit/ui/Slider.java b/src/com/itmill/toolkit/ui/Slider.java
index aaefc21163..0fb3496404 100644
--- a/src/com/itmill/toolkit/ui/Slider.java
+++ b/src/com/itmill/toolkit/ui/Slider.java
@@ -10,7 +10,9 @@ import com.itmill.toolkit.terminal.PaintException;
import com.itmill.toolkit.terminal.PaintTarget;
/**
- * TODO comment
+ * A component for selecting a numerical value within a range. A Slider
+ * can have the appearance of a scroll bar or e.g. look like an Adobe Photoshop
+ * style of a slider.
*
* Example code: <code>
* class MyPlayer extends CustomComponent implements ValueChangeListener {
@@ -42,6 +44,7 @@ import com.itmill.toolkit.terminal.PaintTarget;
*
* </code>
*
+ * @author IT Mill Ltd.
*/
public class Slider extends AbstractField {
diff --git a/src/com/itmill/toolkit/ui/Table.java b/src/com/itmill/toolkit/ui/Table.java
index 2b528780ca..1ad0eda6ad 100644
--- a/src/com/itmill/toolkit/ui/Table.java
+++ b/src/com/itmill/toolkit/ui/Table.java
@@ -23,6 +23,7 @@ import com.itmill.toolkit.data.util.ContainerOrderedWrapper;
import com.itmill.toolkit.data.util.IndexedContainer;
import com.itmill.toolkit.event.Action;
import com.itmill.toolkit.event.ItemClickEvent;
+import com.itmill.toolkit.event.Action.Handler;
import com.itmill.toolkit.event.ItemClickEvent.ItemClickListener;
import com.itmill.toolkit.event.ItemClickEvent.ItemClickSource;
import com.itmill.toolkit.terminal.KeyMapper;
@@ -165,37 +166,38 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Holds visible column propertyIds - in order.
*/
- private LinkedList visibleColumns = new LinkedList();
+ private LinkedList<Object> visibleColumns = new LinkedList<Object>();
/**
* Holds propertyIds of currently collapsed columns.
*/
- private final HashSet collapsedColumns = new HashSet();
+ private final HashSet<Object> collapsedColumns = new HashSet<Object>();
/**
* Holds headers for visible columns (by propertyId).
*/
- private final HashMap columnHeaders = new HashMap();
+ private final HashMap<Object, String> columnHeaders = new HashMap<Object, String>();
/**
* Holds icons for visible columns (by propertyId).
*/
- private final HashMap columnIcons = new HashMap();
+ private final HashMap<Object, Resource> columnIcons = new HashMap<Object, Resource>();
/**
* Holds alignments for visible columns (by propertyId).
*/
- private HashMap columnAlignments = new HashMap();
+ private HashMap<Object, String> columnAlignments = new HashMap<Object, String>();
/**
- * Holds column widths in pixels for visible columns (by propertyId).
+ * Holds column widths in pixels (Integer) or expand ratios (Float) for
+ * visible columns (by propertyId).
*/
- private final HashMap columnWidths = new HashMap();
+ private final HashMap<Object, Object> columnWidths = new HashMap<Object, Object>();
/**
* Holds column generators
*/
- private final HashMap columnGenerators = new LinkedHashMap();
+ private final HashMap<Object, ColumnGenerator> columnGenerators = new LinkedHashMap<Object, ColumnGenerator>();
/**
* Holds value of property pageLength. 0 disables paging.
@@ -239,17 +241,17 @@ public class Table extends AbstractSelect implements Action.Container,
* Note: This should be set or list. IdentityHashMap used due very heavy
* hashCode in indexed container
*/
- private HashSet listenedProperties = null;
+ private HashSet<Property> listenedProperties = null;
/**
* Set of visible components - the is used for needsRepaint calculation.
*/
- private HashSet visibleComponents = null;
+ private HashSet<Component> visibleComponents = null;
/**
* List of action handlers.
*/
- private LinkedList actionHandlers = null;
+ private LinkedList<Handler> actionHandlers = null;
/**
* Action mapper.
@@ -403,7 +405,7 @@ public class Table extends AbstractSelect implements Action.Container,
// If this is called before the constructor is finished, it might be
// uninitialized
- final LinkedList newVC = new LinkedList();
+ final LinkedList<Object> newVC = new LinkedList<Object>();
for (int i = 0; i < visibleColumns.length; i++) {
newVC.add(visibleColumns[i]);
}
@@ -412,7 +414,7 @@ public class Table extends AbstractSelect implements Action.Container,
if (this.visibleColumns != null) {
boolean disabledHere = disableContentRefreshing();
try {
- for (final Iterator i = this.visibleColumns.iterator(); i
+ for (final Iterator<Object> i = this.visibleColumns.iterator(); i
.hasNext();) {
final Object col = i.next();
if (!newVC.contains(col)) {
@@ -455,8 +457,9 @@ public class Table extends AbstractSelect implements Action.Container,
}
final String[] headers = new String[visibleColumns.size()];
int i = 0;
- for (final Iterator it = visibleColumns.iterator(); it.hasNext(); i++) {
- headers[i] = (String) columnHeaders.get(it.next());
+ for (final Iterator<Object> it = visibleColumns.iterator(); it
+ .hasNext(); i++) {
+ headers[i] = columnHeaders.get(it.next());
}
return headers;
}
@@ -486,7 +489,8 @@ public class Table extends AbstractSelect implements Action.Container,
this.columnHeaders.clear();
int i = 0;
- for (final Iterator it = visibleColumns.iterator(); it.hasNext()
+ for (final Iterator<Object> it = visibleColumns.iterator(); it
+ .hasNext()
&& i < columnHeaders.length; i++) {
this.columnHeaders.put(it.next(), columnHeaders[i]);
}
@@ -515,8 +519,9 @@ public class Table extends AbstractSelect implements Action.Container,
}
final Resource[] icons = new Resource[visibleColumns.size()];
int i = 0;
- for (final Iterator it = visibleColumns.iterator(); it.hasNext(); i++) {
- icons[i] = (Resource) columnIcons.get(it.next());
+ for (final Iterator<Object> it = visibleColumns.iterator(); it
+ .hasNext(); i++) {
+ icons[i] = columnIcons.get(it.next());
}
return icons;
@@ -546,7 +551,8 @@ public class Table extends AbstractSelect implements Action.Container,
this.columnIcons.clear();
int i = 0;
- for (final Iterator it = visibleColumns.iterator(); it.hasNext()
+ for (final Iterator<Object> it = visibleColumns.iterator(); it
+ .hasNext()
&& i < columnIcons.length; i++) {
this.columnIcons.put(it.next(), columnIcons[i]);
}
@@ -580,7 +586,8 @@ public class Table extends AbstractSelect implements Action.Container,
}
final String[] alignments = new String[visibleColumns.size()];
int i = 0;
- for (final Iterator it = visibleColumns.iterator(); it.hasNext(); i++) {
+ for (final Iterator<Object> it = visibleColumns.iterator(); it
+ .hasNext(); i++) {
alignments[i++] = getColumnAlignment(it.next());
}
@@ -623,9 +630,10 @@ public class Table extends AbstractSelect implements Action.Container,
}
// Resets the alignments
- final HashMap newCA = new HashMap();
+ final HashMap<Object, String> newCA = new HashMap<Object, String>();
int i = 0;
- for (final Iterator it = visibleColumns.iterator(); it.hasNext()
+ for (final Iterator<Object> it = visibleColumns.iterator(); it
+ .hasNext()
&& i < columnAlignments.length; i++) {
newCA.put(it.next(), columnAlignments[i]);
}
@@ -641,6 +649,10 @@ public class Table extends AbstractSelect implements Action.Container,
* small or very big values. Setting width to -1 (default) means that theme
* will make decision of width.
*
+ *<p>
+ * Column can either have a fixed width or expand ratio. The latter one set
+ * is used. See @link {@link #setColumnExpandRatio(Object, float)}.
+ *
* @param columnId
* colunmns property id
* @param width
@@ -648,20 +660,78 @@ public class Table extends AbstractSelect implements Action.Container,
* @since 4.0.3
*/
public void setColumnWidth(Object columnId, int width) {
- columnWidths.put(columnId, new Integer(width));
+ if (width < 0) {
+ columnWidths.remove(columnId);
+ } else {
+ columnWidths.put(columnId, new Integer(width));
+ }
+ }
+
+ /**
+ * Sets the column expand ratio for given column.
+ * <p>
+ * Expand ratios can be defined to customize the way how excess space is
+ * divided among columns. Table can have excess space if it has its width
+ * defined and there is horizontally more space than columns consume
+ * naturally. Excess space is the space that is not used by columns with
+ * explicit width (see {@link #setColumnWidth(Object, int)}) or with natural
+ * width (no width nor expand ratio).
+ *
+ * <p>
+ * By default (without expand ratios) the excess space is divided
+ * proportionally to columns natural widths.
+ *
+ * <p>
+ * Only expand ratios of visible columns are used in final calculations.
+ *
+ * <p>
+ * Column can either have a fixed width or expand ratio. The latter one set
+ * is used.
+ *
+ * <p>
+ * A column with expand ratio is considered to be minimum width by default
+ * (if no excess space exists). The minimum width is defined by terminal
+ * implementation.
+ *
+ * <p>
+ * If terminal implementation supports re-sizeable columns the column
+ * becomes fixed width column if users resizes the column.
+ *
+ * @param columnId
+ * colunmns property id
+ * @param expandRatio
+ * the expandRatio used to divide excess space for this column
+ */
+ public void setColumnExpandRatio(Object columnId, float expandRatio) {
+ if (expandRatio < 0) {
+ columnWidths.remove(columnId);
+ } else {
+ columnWidths.put(columnId, new Float(expandRatio));
+ }
+ }
+
+ public float getColumnExpandRatio(Object propertyId) {
+ final Object width = columnWidths.get(propertyId);
+ if (width == null || !(width instanceof Float)) {
+ return -1;
+ }
+ final Float value = (Float) width;
+ return value.floatValue();
+
}
/**
- * Gets the width of column
+ * Gets the pixel width of column
*
* @param propertyId
* @return width of colun or -1 when value not set
*/
public int getColumnWidth(Object propertyId) {
- final Integer value = (Integer) columnWidths.get(propertyId);
- if (value == null) {
+ final Object width = columnWidths.get(propertyId);
+ if (width == null || !(width instanceof Integer)) {
return -1;
}
+ final Integer value = (Integer) width;
return value.intValue();
}
@@ -771,7 +841,7 @@ public class Table extends AbstractSelect implements Action.Container,
* set, or if the column is not visible.
*/
public Resource getColumnIcon(Object propertyId) {
- return (Resource) columnIcons.get(propertyId);
+ return columnIcons.get(propertyId);
}
/**
@@ -810,7 +880,7 @@ public class Table extends AbstractSelect implements Action.Container,
return null;
}
- String header = (String) columnHeaders.get(propertyId);
+ String header = columnHeaders.get(propertyId);
if ((header == null && getColumnHeaderMode() == COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID)
|| getColumnHeaderMode() == COLUMN_HEADER_MODE_ID) {
header = propertyId.toString();
@@ -847,7 +917,7 @@ public class Table extends AbstractSelect implements Action.Container,
* @return the specified column's alignment if it as one; null otherwise.
*/
public String getColumnAlignment(Object propertyId) {
- final String a = (String) columnAlignments.get(propertyId);
+ final String a = columnAlignments.get(propertyId);
return a == null ? ALIGN_LEFT : a;
}
@@ -982,7 +1052,7 @@ public class Table extends AbstractSelect implements Action.Container,
if (columnOrder == null || !isColumnReorderingAllowed()) {
return;
}
- final LinkedList newOrder = new LinkedList();
+ final LinkedList<Object> newOrder = new LinkedList<Object>();
for (int i = 0; i < columnOrder.length; i++) {
if (columnOrder[i] != null
&& visibleColumns.contains(columnOrder[i])) {
@@ -990,7 +1060,8 @@ public class Table extends AbstractSelect implements Action.Container,
newOrder.add(columnOrder[i]);
}
}
- for (final Iterator it = visibleColumns.iterator(); it.hasNext();) {
+ for (final Iterator<Object> it = visibleColumns.iterator(); it
+ .hasNext();) {
final Object columnId = it.next();
if (!newOrder.contains(columnId)) {
newOrder.add(columnId);
@@ -1189,12 +1260,12 @@ public class Table extends AbstractSelect implements Action.Container,
if (isContentRefreshesEnabled) {
- HashSet oldListenedProperties = listenedProperties;
- HashSet oldVisibleComponents = visibleComponents;
+ HashSet<Property> oldListenedProperties = listenedProperties;
+ HashSet<Component> oldVisibleComponents = visibleComponents;
// initialize the listener collections
- listenedProperties = new HashSet();
- visibleComponents = new HashSet();
+ listenedProperties = new HashSet<Property>();
+ visibleComponents = new HashSet<Component>();
// Collects the basic facts about the table page
final Object[] colids = getVisibleColumns();
@@ -1299,14 +1370,6 @@ public class Table extends AbstractSelect implements Action.Container,
// check in current pageBuffer already has row
int index = firstIndex + i;
if (p != null || isGenerated) {
- if (p instanceof Property.ValueChangeNotifier) {
- if (oldListenedProperties == null
- || !oldListenedProperties.contains(p)) {
- ((Property.ValueChangeNotifier) p)
- .addListener(this);
- }
- listenedProperties.add(p);
- }
if (index < firstIndexNotInCache
&& index >= pageBufferFirstIndex) {
// we have data already in our cache,
@@ -1317,7 +1380,7 @@ public class Table extends AbstractSelect implements Action.Container,
value = pageBuffer[CELL_FIRSTCOL + j][indexInOldBuffer];
} else {
if (isGenerated) {
- ColumnGenerator cg = (ColumnGenerator) columnGenerators
+ ColumnGenerator cg = columnGenerators
.get(colids[j]);
value = cg
.generateCell(this, id, colids[j]);
@@ -1326,6 +1389,32 @@ public class Table extends AbstractSelect implements Action.Container,
value = p.getValue();
} else if (p != null) {
value = getPropertyValue(id, colids[j], p);
+ /*
+ * If returned value is Component (via
+ * fieldfactory or overridden
+ * getPropertyValue) we excpect it to listen
+ * property value changes. Otherwise if
+ * property emits value change events, table
+ * will start to listen them and refresh
+ * content when needed.
+ */
+ if (!(value instanceof Component)
+ && p instanceof Property.ValueChangeNotifier) {
+ // only add listener to property once
+ if (oldListenedProperties == null
+ || !oldListenedProperties
+ .contains(p)) {
+ ((Property.ValueChangeNotifier) p)
+ .addListener(this);
+ }
+ /*
+ * register listened properties, so we
+ * can do proper cleanup to free memory.
+ * Essential if table has loads of data
+ * and it is used for a long time.
+ */
+ listenedProperties.add(p);
+ }
} else {
value = getPropertyValue(id, colids[j],
null);
@@ -1338,7 +1427,7 @@ public class Table extends AbstractSelect implements Action.Container,
|| !oldVisibleComponents.contains(value)) {
((Component) value).setParent(this);
}
- visibleComponents.add(value);
+ visibleComponents.add((Component) value);
}
cells[CELL_FIRSTCOL + j][i] = value;
}
@@ -1384,11 +1473,12 @@ public class Table extends AbstractSelect implements Action.Container,
* set of components that where attached in last render
*/
private void unregisterPropertiesAndComponents(
- HashSet oldListenedProperties, HashSet oldVisibleComponents) {
+ HashSet<Property> oldListenedProperties,
+ HashSet<Component> oldVisibleComponents) {
if (oldVisibleComponents != null) {
- for (final Iterator i = oldVisibleComponents.iterator(); i
+ for (final Iterator<Component> i = oldVisibleComponents.iterator(); i
.hasNext();) {
- Component c = (Component) i.next();
+ Component c = i.next();
if (!visibleComponents.contains(c)) {
c.setParent(null);
}
@@ -1396,7 +1486,7 @@ public class Table extends AbstractSelect implements Action.Container,
}
if (oldListenedProperties != null) {
- for (final Iterator i = oldListenedProperties.iterator(); i
+ for (final Iterator<Property> i = oldListenedProperties.iterator(); i
.hasNext();) {
Property.ValueChangeNotifier o = (ValueChangeNotifier) i.next();
if (!listenedProperties.contains(o)) {
@@ -1484,8 +1574,8 @@ public class Table extends AbstractSelect implements Action.Container,
throws UnsupportedOperationException {
// remove generated columns from the list of columns being assigned
- final LinkedList availableCols = new LinkedList();
- for (Iterator it = visibleColumns.iterator(); it.hasNext();) {
+ final LinkedList<Object> availableCols = new LinkedList<Object>();
+ for (Iterator<Object> it = visibleColumns.iterator(); it.hasNext();) {
Object id = it.next();
if (!columnGenerators.containsKey(id)) {
availableCols.add(id);
@@ -1571,7 +1661,7 @@ public class Table extends AbstractSelect implements Action.Container,
}
// columnGenerators 'override' properties, don't add the same id twice
- Collection col = new LinkedList();
+ Collection<Object> col = new LinkedList<Object>();
for (Iterator it = getContainerPropertyIds().iterator(); it.hasNext();) {
Object id = it.next();
if (columnGenerators == null || !columnGenerators.containsKey(id)) {
@@ -1672,10 +1762,9 @@ public class Table extends AbstractSelect implements Action.Container,
final Action action = (Action) actionMapper.get(st.nextToken());
if (action != null && containsId(itemId)
&& actionHandlers != null) {
- for (final Iterator i = actionHandlers.iterator(); i
+ for (final Iterator<Handler> i = actionHandlers.iterator(); i
.hasNext();) {
- ((Action.Handler) i.next()).handleAction(action, this,
- itemId);
+ (i.next()).handleAction(action, this, itemId);
}
}
}
@@ -1713,7 +1802,7 @@ public class Table extends AbstractSelect implements Action.Container,
try {
final Object[] ids = (Object[]) variables
.get("collapsedcolumns");
- for (final Iterator it = visibleColumns.iterator(); it
+ for (final Iterator<Object> it = visibleColumns.iterator(); it
.hasNext();) {
setColumnCollapsed(it.next(), false);
}
@@ -1767,8 +1856,11 @@ public class Table extends AbstractSelect implements Action.Container,
}
MouseEventDetails evt = MouseEventDetails
.deSerialize((String) variables.get("clickEvent"));
- fireEvent(new ItemClickEvent(this, getItem(itemId), itemId,
- propertyId, evt));
+ Item item = getItem(itemId);
+ if (item != null) {
+ fireEvent(new ItemClickEvent(this, item, itemId,
+ propertyId, evt));
+ }
}
}
}
@@ -1848,7 +1940,7 @@ public class Table extends AbstractSelect implements Action.Container,
}
// selection support
- LinkedList selectedKeys = new LinkedList();
+ LinkedList<String> selectedKeys = new LinkedList<String>();
if (isMultiSelect()) {
// only paint selections that are currently visible in the client
HashSet sel = new HashSet((Set) getValue());
@@ -1900,8 +1992,9 @@ public class Table extends AbstractSelect implements Action.Container,
// Visible column order
final Collection sortables = getSortableContainerPropertyIds();
- final ArrayList visibleColOrder = new ArrayList();
- for (final Iterator it = visibleColumns.iterator(); it.hasNext();) {
+ final ArrayList<String> visibleColOrder = new ArrayList<String>();
+ for (final Iterator<Object> it = visibleColumns.iterator(); it
+ .hasNext();) {
final Object columnId = it.next();
if (!isColumnCollapsed(columnId)) {
visibleColOrder.add(columnIdMap.key(columnId));
@@ -1910,11 +2003,12 @@ public class Table extends AbstractSelect implements Action.Container,
target.addAttribute("vcolorder", visibleColOrder.toArray());
// Rows
- final Set actionSet = new LinkedHashSet();
+ final Set<Action> actionSet = new LinkedHashSet<Action>();
final boolean selectable = isSelectable();
final boolean[] iscomponent = new boolean[visibleColumns.size()];
int iscomponentIndex = 0;
- for (final Iterator it = visibleColumns.iterator(); it.hasNext()
+ for (final Iterator<Object> it = visibleColumns.iterator(); it
+ .hasNext()
&& iscomponentIndex < iscomponent.length;) {
final Object columnId = it.next();
if (columnGenerators.containsKey(columnId)) {
@@ -1975,11 +2069,10 @@ public class Table extends AbstractSelect implements Action.Container,
// Actions
if (actionHandlers != null) {
- final ArrayList keys = new ArrayList();
- for (final Iterator ahi = actionHandlers.iterator(); ahi
+ final ArrayList<String> keys = new ArrayList<String>();
+ for (final Iterator<Handler> ahi = actionHandlers.iterator(); ahi
.hasNext();) {
- final Action[] aa = ((Action.Handler) ahi.next())
- .getActions(itemId, this);
+ final Action[] aa = (ahi.next()).getActions(itemId, this);
if (aa != null) {
for (int ai = 0; ai < aa.length; ai++) {
final String key = actionMapper.key(aa[ai]);
@@ -2005,7 +2098,8 @@ public class Table extends AbstractSelect implements Action.Container,
// cells
int currentColumn = 0;
- for (final Iterator it = visibleColumns.iterator(); it.hasNext(); currentColumn++) {
+ for (final Iterator<Object> it = visibleColumns.iterator(); it
+ .hasNext(); currentColumn++) {
final Object columnId = it.next();
if (columnId == null || isColumnCollapsed(columnId)) {
continue;
@@ -2046,7 +2140,7 @@ public class Table extends AbstractSelect implements Action.Container,
// The select variable is only enabled if selectable
if (selectable && selectedKeys.size() > 0) {
- target.addVariable(this, "selected", (String[]) selectedKeys
+ target.addVariable(this, "selected", selectedKeys
.toArray(new String[selectedKeys.size()]));
}
@@ -2074,8 +2168,8 @@ public class Table extends AbstractSelect implements Action.Container,
if (!actionSet.isEmpty()) {
target.addVariable(this, "action", "");
target.startTag("actions");
- for (final Iterator it = actionSet.iterator(); it.hasNext();) {
- final Action a = (Action) it.next();
+ for (final Iterator<Action> it = actionSet.iterator(); it.hasNext();) {
+ final Action a = it.next();
target.startTag("action");
if (a.getCaption() != null) {
target.addAttribute("caption", a.getCaption());
@@ -2091,7 +2185,8 @@ public class Table extends AbstractSelect implements Action.Container,
if (columnReorderingAllowed) {
final String[] colorder = new String[visibleColumns.size()];
int i = 0;
- for (final Iterator it = visibleColumns.iterator(); it.hasNext()
+ for (final Iterator<Object> it = visibleColumns.iterator(); it
+ .hasNext()
&& i < colorder.length;) {
colorder[i++] = columnIdMap.key(it.next());
}
@@ -2099,8 +2194,9 @@ public class Table extends AbstractSelect implements Action.Container,
}
// Available columns
if (columnCollapsingAllowed) {
- final HashSet ccs = new HashSet();
- for (final Iterator i = visibleColumns.iterator(); i.hasNext();) {
+ final HashSet<Object> ccs = new HashSet<Object>();
+ for (final Iterator<Object> i = visibleColumns.iterator(); i
+ .hasNext();) {
final Object o = i.next();
if (isColumnCollapsed(o)) {
ccs.add(o);
@@ -2108,7 +2204,8 @@ public class Table extends AbstractSelect implements Action.Container,
}
final String[] collapsedkeys = new String[ccs.size()];
int nextColumn = 0;
- for (final Iterator it = visibleColumns.iterator(); it.hasNext()
+ for (final Iterator<Object> it = visibleColumns.iterator(); it
+ .hasNext()
&& nextColumn < collapsedkeys.length;) {
final Object columnId = it.next();
if (isColumnCollapsed(columnId)) {
@@ -2119,7 +2216,8 @@ public class Table extends AbstractSelect implements Action.Container,
}
target.startTag("visiblecolumns");
int i = 0;
- for (final Iterator it = visibleColumns.iterator(); it.hasNext(); i++) {
+ for (final Iterator<Object> it = visibleColumns.iterator(); it
+ .hasNext(); i++) {
final Object columnId = it.next();
if (columnId != null) {
target.startTag("column");
@@ -2140,11 +2238,15 @@ public class Table extends AbstractSelect implements Action.Container,
if (!ALIGN_LEFT.equals(getColumnAlignment(columnId))) {
target.addAttribute("align", getColumnAlignment(columnId));
}
- if (getColumnWidth(columnId) > -1) {
- target.addAttribute("width", String
- .valueOf(getColumnWidth(columnId)));
+ if (columnWidths.containsKey(columnId)) {
+ if (getColumnWidth(columnId) > -1) {
+ target.addAttribute("width", String
+ .valueOf(getColumnWidth(columnId)));
+ } else {
+ target.addAttribute("er",
+ getColumnExpandRatio(columnId));
+ }
}
-
target.endTag("column");
}
}
@@ -2236,7 +2338,7 @@ public class Table extends AbstractSelect implements Action.Container,
if (actionHandler != null) {
if (actionHandlers == null) {
- actionHandlers = new LinkedList();
+ actionHandlers = new LinkedList<Handler>();
actionMapper = new KeyMapper();
}
@@ -2310,8 +2412,9 @@ public class Table extends AbstractSelect implements Action.Container,
refreshRenderedCells();
if (visibleComponents != null) {
- for (final Iterator i = visibleComponents.iterator(); i.hasNext();) {
- ((Component) i.next()).attach();
+ for (final Iterator<Component> i = visibleComponents.iterator(); i
+ .hasNext();) {
+ i.next().attach();
}
}
}
@@ -2326,8 +2429,9 @@ public class Table extends AbstractSelect implements Action.Container,
super.detach();
if (visibleComponents != null) {
- for (final Iterator i = visibleComponents.iterator(); i.hasNext();) {
- ((Component) i.next()).detach();
+ for (final Iterator<Component> i = visibleComponents.iterator(); i
+ .hasNext();) {
+ i.next().detach();
}
}
}
@@ -2527,7 +2631,7 @@ public class Table extends AbstractSelect implements Action.Container,
@Override
public Collection getVisibleItemIds() {
- final LinkedList visible = new LinkedList();
+ final LinkedList<Object> visible = new LinkedList<Object>();
final Object[][] cells = getVisibleCells();
for (int i = 0; i < cells[CELL_ITEMID].length; i++) {
@@ -2548,9 +2652,13 @@ public class Table extends AbstractSelect implements Action.Container,
super.containerItemSetChange(event);
if (event instanceof IndexedContainer.ItemSetChangeEvent) {
IndexedContainer.ItemSetChangeEvent evt = (IndexedContainer.ItemSetChangeEvent) event;
+ // if the event is not a global one and the added item is outside
+ // the visible/buffered area, no need to do anything
if (evt.getAddedItemIndex() != -1
- && firstToBeRenderedInClient <= evt.getAddedItemIndex()
- && lastToBeRenderedInClient >= evt.getAddedItemIndex()) {
+ && (firstToBeRenderedInClient >= 0)
+ && (lastToBeRenderedInClient >= 0)
+ && (firstToBeRenderedInClient > evt.getAddedItemIndex() || lastToBeRenderedInClient < evt
+ .getAddedItemIndex())) {
return;
}
}
@@ -3058,9 +3166,9 @@ public class Table extends AbstractSelect implements Action.Container,
public void requestRepaintAll() {
requestRepaint();
if (visibleComponents != null) {
- for (Iterator childIterator = visibleComponents.iterator(); childIterator
- .hasNext();) {
- Component c = (Component) childIterator.next();
+ for (Iterator<Component> childIterator = visibleComponents
+ .iterator(); childIterator.hasNext();) {
+ Component c = childIterator.next();
if (c instanceof Form) {
// Form has children in layout, but is not
// ComponentContainer
diff --git a/src/com/itmill/toolkit/ui/TextField.java b/src/com/itmill/toolkit/ui/TextField.java
index dd8596f087..e5572f0b9f 100644
--- a/src/com/itmill/toolkit/ui/TextField.java
+++ b/src/com/itmill/toolkit/ui/TextField.java
@@ -73,6 +73,8 @@ public class TextField extends AbstractField {
*/
private boolean nullSettingAllowed = false;
+ private String inputPrompt = null;
+
/**
* Maximum character count in text field.
*/
@@ -159,6 +161,10 @@ public class TextField extends AbstractField {
target.addAttribute("maxLength", getMaxLength());
}
+ if (inputPrompt != null) {
+ target.addAttribute("prompt", inputPrompt);
+ }
+
// Adds the number of column and rows
final int c = getColumns();
final int r = getRows();
@@ -409,7 +415,7 @@ public class TextField extends AbstractField {
*
* <p>
* If this property is true, writing null-representation string to text
- * field allways sets the field value to real null. If this property is
+ * field always sets the field value to real null. If this property is
* false, null setting is not made, but the null values are maintained.
* Maintenance of null-values is made by only converting the textfield
* contents to real null, if the text field matches the null-string
@@ -420,7 +426,7 @@ public class TextField extends AbstractField {
* By default this setting is false
* </p>
*
- * @return boolean Should the null-string represenation be allways converted
+ * @return boolean Should the null-string represenation be always converted
* to null-values.
* @see TextField#getNullRepresentation()
*/
@@ -454,7 +460,7 @@ public class TextField extends AbstractField {
*
* <p>
* If this property is true, writing null-representation string to text
- * field allways sets the field value to real null. If this property is
+ * field always sets the field value to real null. If this property is
* false, null setting is not made, but the null values are maintained.
* Maintenance of null-values is made by only converting the textfield
* contents to real null, if the text field matches the null-string
@@ -466,7 +472,7 @@ public class TextField extends AbstractField {
* </p>
*
* @param nullSettingAllowed
- * Should the null-string represenation be allways converted to
+ * Should the null-string represenation be always converted to
* null-values.
* @see TextField#getNullRepresentation()
*/
@@ -475,6 +481,26 @@ public class TextField extends AbstractField {
}
/**
+ * Gets the current input prompt.
+ *
+ * @see #setInputPrompt(String)
+ * @return the current input prompt, or null if not enabled
+ */
+ public String getInputPrompt() {
+ return inputPrompt;
+ }
+
+ /**
+ * Sets the input prompt - a textual prompt that is displayed when the field
+ * would otherwise be empty, to prompt the user for input.
+ *
+ * @param inputPrompt
+ */
+ public void setInputPrompt(String inputPrompt) {
+ this.inputPrompt = inputPrompt;
+ }
+
+ /**
* Gets the value formatter of TextField.
*
* @return the Format used to format the value.
diff --git a/src/com/itmill/toolkit/ui/Tree.java b/src/com/itmill/toolkit/ui/Tree.java
index 010e481896..20c7e03961 100644
--- a/src/com/itmill/toolkit/ui/Tree.java
+++ b/src/com/itmill/toolkit/ui/Tree.java
@@ -18,6 +18,7 @@ import java.util.Stack;
import java.util.StringTokenizer;
import com.itmill.toolkit.data.Container;
+import com.itmill.toolkit.data.Item;
import com.itmill.toolkit.data.util.ContainerHierarchicalWrapper;
import com.itmill.toolkit.data.util.IndexedContainer;
import com.itmill.toolkit.event.Action;
@@ -31,8 +32,8 @@ import com.itmill.toolkit.terminal.Resource;
import com.itmill.toolkit.terminal.gwt.client.MouseEventDetails;
/**
- * MenuTree component. MenuTree can be used to select an item (or multiple
- * items) from a hierarchical set of items.
+ * Tree component. A Tree can be used to select an item (or multiple items) from
+ * a hierarchical set of items.
*
* @author IT Mill Ltd.
* @version
@@ -71,7 +72,7 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
/**
* List of action handlers.
*/
- private LinkedList actionHandlers = null;
+ private LinkedList<Action.Handler> actionHandlers = null;
/**
* Action mapper.
@@ -342,7 +343,10 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
Object id = itemIdMapper.get(key);
MouseEventDetails details = MouseEventDetails
.deSerialize((String) variables.get("clickEvent"));
- fireEvent(new ItemClickEvent(this, getItem(id), id, null, details));
+ Item item = getItem(id);
+ if (item != null) {
+ fireEvent(new ItemClickEvent(this, item, id, null, details));
+ }
}
if (!isSelectable() && variables.containsKey("selected")) {
@@ -392,10 +396,9 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
final Action action = (Action) actionMapper.get(st.nextToken());
if (action != null && containsId(itemId)
&& actionHandlers != null) {
- for (final Iterator i = actionHandlers.iterator(); i
- .hasNext();) {
- ((Action.Handler) i.next()).handleAction(action, this,
- itemId);
+ for (final Iterator<Action.Handler> i = actionHandlers
+ .iterator(); i.hasNext();) {
+ i.next().handleAction(action, this, itemId);
}
}
}
@@ -444,7 +447,7 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
}
// Initialize variables
- final Set actionSet = new LinkedHashSet();
+ final Set<Action> actionSet = new LinkedHashSet<Action>();
String[] selectedKeys;
if (isMultiSelect()) {
selectedKeys = new String[((Set) getValue()).size()];
@@ -455,7 +458,7 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
final LinkedList expandedKeys = new LinkedList();
// Iterates through hierarchical tree using a stack of iterators
- final Stack iteratorStack = new Stack();
+ final Stack<Iterator> iteratorStack = new Stack<Iterator>();
Collection ids;
if (partialUpdate) {
ids = getChildren(expandedItemId);
@@ -470,7 +473,7 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
while (!iteratorStack.isEmpty()) {
// Gets the iterator for current tree level
- final Iterator i = (Iterator) iteratorStack.peek();
+ final Iterator i = iteratorStack.peek();
// If the level is finished, back to previous tree level
if (!i.hasNext()) {
@@ -523,11 +526,11 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
// Actions
if (actionHandlers != null) {
- final ArrayList keys = new ArrayList();
- for (final Iterator ahi = actionHandlers.iterator(); ahi
- .hasNext();) {
- final Action[] aa = ((Action.Handler) ahi.next())
- .getActions(itemId, this);
+ final ArrayList<String> keys = new ArrayList<String>();
+ final Iterator<Action.Handler> ahi = actionHandlers
+ .iterator();
+ while (ahi.hasNext()) {
+ final Action[] aa = ahi.next().getActions(itemId, this);
if (aa != null) {
for (int ai = 0; ai < aa.length; ai++) {
final String akey = actionMapper.key(aa[ai]);
@@ -557,8 +560,9 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
if (!actionSet.isEmpty()) {
target.addVariable(this, "action", "");
target.startTag("actions");
- for (final Iterator i = actionSet.iterator(); i.hasNext();) {
- final Action a = (Action) i.next();
+ final Iterator<Action> i = actionSet.iterator();
+ while (i.hasNext()) {
+ final Action a = i.next();
target.startTag("action");
if (a.getCaption() != null) {
target.addAttribute("caption", a.getCaption());
@@ -573,6 +577,10 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
}
if (partialUpdate) {
+ // update tree-level selection information in case some selected
+ // node(s) were collapsed
+ target.addVariable(this, "selected", selectedKeys);
+
partialUpdate = false;
} else {
// Selected
@@ -895,7 +903,7 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
if (actionHandler != null) {
if (actionHandlers == null) {
- actionHandlers = new LinkedList();
+ actionHandlers = new LinkedList<Action.Handler>();
actionMapper = new KeyMapper();
}
@@ -937,7 +945,7 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
final LinkedList visible = new LinkedList();
// Iterates trough hierarchical tree using a stack of iterators
- final Stack iteratorStack = new Stack();
+ final Stack<Iterator> iteratorStack = new Stack<Iterator>();
final Collection ids = rootItemIds();
if (ids != null) {
iteratorStack.push(ids.iterator());
@@ -945,7 +953,7 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
while (!iteratorStack.isEmpty()) {
// Gets the iterator for current tree level
- final Iterator i = (Iterator) iteratorStack.peek();
+ final Iterator i = iteratorStack.peek();
// If the level is finished, back to previous tree level
if (!i.hasNext()) {
diff --git a/src/com/itmill/toolkit/ui/Window.java b/src/com/itmill/toolkit/ui/Window.java
index 2f8d3bcad2..530bd8441d 100644
--- a/src/com/itmill/toolkit/ui/Window.java
+++ b/src/com/itmill/toolkit/ui/Window.java
@@ -859,6 +859,21 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
*/
@Override
public void changeVariables(Object source, Map variables) {
+
+ boolean sizeHasChanged = false;
+ // size is handled in super class, but resize events only in windows ->
+ // so detect if size change occurs before super.changeVariables()
+ if (variables.containsKey("height")
+ && (getHeightUnits() != UNITS_PIXELS || (Integer) variables
+ .get("height") != getHeight())) {
+ sizeHasChanged = true;
+ }
+ if (variables.containsKey("width")
+ && (getWidthUnits() != UNITS_PIXELS || (Integer) variables
+ .get("width") != getWidth())) {
+ sizeHasChanged = true;
+ }
+
super.changeVariables(source, variables);
// Positioning
@@ -880,6 +895,12 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
close();
}
}
+
+ // fire event if size has really changed
+ if (sizeHasChanged) {
+ fireResize();
+ }
+
}
/**
@@ -1030,6 +1051,83 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
fireEvent(new Window.CloseEvent(this));
}
+ /**
+ * Method for the resize event.
+ */
+ private static final Method WINDOW_RESIZE_METHOD;
+ static {
+ try {
+ WINDOW_RESIZE_METHOD = ResizeListener.class.getDeclaredMethod(
+ "windowResized", new Class[] { ResizeEvent.class });
+ } catch (final java.lang.NoSuchMethodException e) {
+ // This should never happen
+ throw new java.lang.RuntimeException(
+ "Internal error, window resized method not found");
+ }
+ }
+
+ /**
+ * Resize events are fired whenever the client-side fires a resize-event
+ * (e.g. the browser window is resized). The frequency may vary across
+ * browsers.
+ */
+ public class ResizeEvent extends Component.Event {
+
+ // Generated serial
+ private static final long serialVersionUID = 8569831802323447687L;
+
+ /**
+ *
+ * @param source
+ */
+ public ResizeEvent(Component source) {
+ super(source);
+ }
+
+ /**
+ * Get the window form which this event originated
+ *
+ * @return the window
+ */
+ public Window getWindow() {
+ return (Window) getSource();
+ }
+ }
+
+ /**
+ * Listener for window resize events.
+ *
+ * @see com.itmill.toolkit.ui.Window.ResizeEvent
+ */
+ public interface ResizeListener {
+ public void windowResized(ResizeEvent e);
+ }
+
+ /**
+ * Add a resize listener.
+ *
+ * @param listener
+ */
+ public void addListener(ResizeListener listener) {
+ addListener(ResizeEvent.class, listener, WINDOW_RESIZE_METHOD);
+ }
+
+ /**
+ * Remove a resize listener.
+ *
+ * @param listener
+ */
+ public void removeListener(ResizeListener listener) {
+ removeListener(ResizeEvent.class, this);
+ }
+
+ /**
+ * Fire the resize event.
+ */
+ protected void fireResize() {
+ fireEvent(new ResizeEvent(this));
+ }
+
private void attachWindow(Window w) {
subwindows.add(w);
w.setParent(this);
diff --git a/tests/com/itmill/toolkit/tests/sampler/SamplerSmokeTest.java b/tests/com/itmill/toolkit/tests/sampler/SamplerSmokeTest.java
new file mode 100644
index 0000000000..125423633a
--- /dev/null
+++ b/tests/com/itmill/toolkit/tests/sampler/SamplerSmokeTest.java
@@ -0,0 +1,32 @@
+package com.itmill.toolkit.tests.sampler;
+
+import com.itmill.testingtools.runner.TestRunner;
+
+public class SamplerSmokeTest extends TestRunner {
+
+ public void testNew() throws Exception {
+ selenium.open("/sampler?restartApplication");
+ waitForITMillToolkit();
+ selenium
+ .click("itmilltoolkit=sampler::/IVerticalLayout[0]/ChildComponentContainer[1]/ISplitPanelHorizontal[0]/IPanel[0]/IGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[1]/IButton[0]");
+ waitForITMillToolkit();
+ assertEquals(
+ "Tooltips",
+ selenium
+ .getText("itmilltoolkit=sampler::/IVerticalLayout[0]/ChildComponentContainer[1]/ISplitPanelHorizontal[0]/IHorizontalLayout[0]/ChildComponentContainer[0]/IVerticalLayout[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]"));
+ selenium
+ .click("itmilltoolkit=sampler::/IVerticalLayout[0]/ChildComponentContainer[1]/ISplitPanelHorizontal[0]/IHorizontalLayout[0]/ChildComponentContainer[0]/IVerticalLayout[0]/ChildComponentContainer[1]/IVerticalLayout[0]/ChildComponentContainer[3]/IButton[0]");
+ waitForITMillToolkit();
+ selenium
+ .click("itmilltoolkit=sampler::/IVerticalLayout[0]/ChildComponentContainer[1]/ISplitPanelHorizontal[0]/IHorizontalLayout[0]/ChildComponentContainer[0]/IVerticalLayout[0]/ChildComponentContainer[1]/IVerticalLayout[0]/ChildComponentContainer[3]/IButton[0]");
+ waitForITMillToolkit();
+ selenium
+ .click("itmilltoolkit=sampler::/IVerticalLayout[0]/ChildComponentContainer[1]/ISplitPanelHorizontal[0]/IHorizontalLayout[0]/ChildComponentContainer[0]/IVerticalLayout[0]/ChildComponentContainer[0]/IVerticalLayout[0]/ChildComponentContainer[0]/IHorizontalLayout[0]/ChildComponentContainer[2]/IActiveLink[0]/domChild[0]/domChild[0]");
+ waitForITMillToolkit();
+ verifyTrue(selenium
+ .isTextPresent("'m terribly sorry, but it seems the source could not be found.\nPlease try adding the source folder to the classpath for your server, or tell the administrator to do so!"));
+ waitForITMillToolkit();
+ selenium.click("PID141_window_close");
+ waitForITMillToolkit();
+ }
+}
diff --git a/tests/com/itmill/toolkit/tests/sampler/SamplerSmokeTest2.java b/tests/com/itmill/toolkit/tests/sampler/SamplerSmokeTest2.java
new file mode 100644
index 0000000000..3a6b3d8191
--- /dev/null
+++ b/tests/com/itmill/toolkit/tests/sampler/SamplerSmokeTest2.java
@@ -0,0 +1,57 @@
+package com.itmill.toolkit.tests.sampler;
+
+import com.itmill.testingtools.runner.TestRunner;
+
+public class SamplerSmokeTest2 extends TestRunner {
+
+ public void testNew() throws Exception {
+ selenium.open("/sampler?restartApplication");
+ waitForITMillToolkit();
+ selenium
+ .click("itmilltoolkit=sampler::/IVerticalLayout[0]/ChildComponentContainer[1]/ISplitPanelHorizontal[0]/IPanel[0]/IGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[16]/IButton[0]");
+ waitForITMillToolkit();
+ selenium
+ .click("itmilltoolkit=sampler::/IVerticalLayout[0]/ChildComponentContainer[0]/IHorizontalLayout[0]/ChildComponentContainer[6]/IHorizontalLayout[0]/ChildComponentContainer[1]/IButton[0]");
+ waitForITMillToolkit();
+ selenium
+ .type(
+ "itmilltoolkit=sampler::/IVerticalLayout[0]/ChildComponentContainer[1]/ISplitPanelHorizontal[0]/IHorizontalLayout[0]/ChildComponentContainer[0]/IVerticalLayout[0]/ChildComponentContainer[1]/IVerticalLayout[0]/ChildComponentContainer[0]/IForm[0]/IFormLayout[0]/IFormLayout$IFormLayoutTable[0]/ITextField[0]",
+ "Peter");
+ waitForITMillToolkit();
+ selenium
+ .type(
+ "itmilltoolkit=sampler::/IVerticalLayout[0]/ChildComponentContainer[1]/ISplitPanelHorizontal[0]/IHorizontalLayout[0]/ChildComponentContainer[0]/IVerticalLayout[0]/ChildComponentContainer[1]/IVerticalLayout[0]/ChildComponentContainer[0]/IForm[0]/IFormLayout[0]/IFormLayout$IFormLayoutTable[0]/ITextField[1]",
+ "Person");
+ waitForITMillToolkit();
+ selenium
+ .type(
+ "itmilltoolkit=sampler::/IVerticalLayout[0]/ChildComponentContainer[1]/ISplitPanelHorizontal[0]/IHorizontalLayout[0]/ChildComponentContainer[0]/IVerticalLayout[0]/ChildComponentContainer[1]/IVerticalLayout[0]/ChildComponentContainer[0]/IForm[0]/IFormLayout[0]/IFormLayout$IFormLayoutTable[0]/IFilterSelect[0]/domChild[1]",
+ "finland");
+ waitForITMillToolkit();
+ selenium
+ .type(
+ "itmilltoolkit=sampler::/IVerticalLayout[0]/ChildComponentContainer[1]/ISplitPanelHorizontal[0]/IHorizontalLayout[0]/ChildComponentContainer[0]/IVerticalLayout[0]/ChildComponentContainer[1]/IVerticalLayout[0]/ChildComponentContainer[0]/IForm[0]/IFormLayout[0]/IFormLayout$IFormLayoutTable[0]/IPasswordField[0]",
+ "mypass");
+ waitForITMillToolkit();
+ selenium
+ .click("itmilltoolkit=sampler::/IVerticalLayout[0]/ChildComponentContainer[1]/ISplitPanelHorizontal[0]/IHorizontalLayout[0]/ChildComponentContainer[0]/IVerticalLayout[0]/ChildComponentContainer[1]/IVerticalLayout[0]/ChildComponentContainer[0]/IForm[0]/IFormLayout[0]/IFormLayout$IFormLayoutTable[0]/IPopupCalendar[0]/domChild[1]");
+ waitForITMillToolkit();
+ selenium
+ .click("//table[@id='PID_TOOLKIT_POPUPCAL']/tbody/tr[4]/td[2]/span");
+ waitForITMillToolkit();
+ selenium
+ .type(
+ "itmilltoolkit=sampler::/IVerticalLayout[0]/ChildComponentContainer[1]/ISplitPanelHorizontal[0]/IHorizontalLayout[0]/ChildComponentContainer[0]/IVerticalLayout[0]/ChildComponentContainer[1]/IVerticalLayout[0]/ChildComponentContainer[0]/IForm[0]/IFormLayout[0]/IFormLayout$IFormLayoutTable[0]/ITextField[2]",
+ "45");
+ waitForITMillToolkit();
+ selenium
+ .click("itmilltoolkit=sampler::/IVerticalLayout[0]/ChildComponentContainer[1]/ISplitPanelHorizontal[0]/IHorizontalLayout[0]/ChildComponentContainer[0]/IVerticalLayout[0]/ChildComponentContainer[1]/IVerticalLayout[0]/ChildComponentContainer[0]/IForm[0]/IFormLayout[0]/IFormLayout$IFormLayoutTable[0]/IHorizontalLayout[0]/ChildComponentContainer[1]/IButton[0]");
+ waitForITMillToolkit();
+ selenium
+ .click("itmilltoolkit=sampler::/IVerticalLayout[0]/ChildComponentContainer[1]/ISplitPanelHorizontal[0]/IHorizontalLayout[0]/ChildComponentContainer[0]/IVerticalLayout[0]/ChildComponentContainer[1]/IVerticalLayout[0]/ChildComponentContainer[1]/IButton[0]");
+ waitForITMillToolkit();
+ verifyTrue(selenium
+ .isTextPresent("First name: Peter\nLast name: Person\nCountry:"));
+ verifyTrue(selenium.isTextPresent("Shoe size: 45\nPassword: mypass"));
+ }
+}