Change-Id: I6ef85a35077e6278831b968595c068898cee2770tags/7.6.0.beta2
@@ -0,0 +1,131 @@ | |||
--- | |||
title: Installing Commercial Vaadin Add-on Licence | |||
order: 5 | |||
layout: page | |||
--- | |||
[[addons.cval]] | |||
= Installing Commercial Vaadin Add-on Licence | |||
The commercial Vaadin add-ons require installing a license key before using | |||
them. The license keys are development licenses and checked during widget set | |||
compilation, or in Vaadin TestBench when executing tests, so you do not need | |||
them when deploying the application. | |||
[[addons.cval.obtaining]] | |||
== Obtaining License Keys | |||
You can purchase add-ons or obtain a free trial key from the Vaadin website. You | |||
need to register in the website to obtain a key. | |||
You can get license keys from | |||
link:https://vaadin.com/pro/licenses[vaadin.com/pro/licenses], where you can | |||
navigate by selecting in the Vaadin website "My Account > Licenses" or directly | |||
[menuchoice]#Licenses# if you are a Pro Tools subscriber. | |||
[[figure.addons.cval.obtaining]] | |||
.Obtaining CVAL License | |||
image::img/cval-pro-licenses-3.png[] | |||
Click on a license key to obtain the purchased or trial key. | |||
[[figure.addons.cval.obtaining]] | |||
.Obtaining CVAL License Key | |||
image::img/cval-pro-licenses-code.png[] | |||
[[addons.cval.installing]] | |||
== Installing License Key in License File | |||
To install the license key in a development workstation, you can copy and paste | |||
it verbatim to a file in your home directory. | |||
License for each product has a separate license file as follows: | |||
Vaadin Charts:: [filename]#.vaadin.charts.developer.license# | |||
Vaadin Spreadsheet:: [filename]#.vaadin.spreadsheet.developer.license# | |||
Vaadin TestBench:: [filename]#.vaadin.testbench.developer.license# | |||
Vaadin TouchKit:: [filename]#.vaadin.touchkit.developer.license# | |||
For example, in Linux and OS X: | |||
[subs="normal"] | |||
---- | |||
[prompt]#$# [command]#echo# "[replaceable]#L1cen5e-c0de#" > [parameter]#~/.vaadin.[replaceable]+++#+++<product>+++#+++.developer.license# | |||
---- | |||
[[addons.cval.systemproperty]] | |||
== Passing License Key as System Property | |||
You can also pass the key as a system property to the widget set compiler, | |||
usually with a [literal]#++-D++# option. For example, on the command-line: | |||
[subs="normal"] | |||
---- | |||
[prompt]#$# [command]#java# -D[parameter]#vaadin.[replaceable]+++#+++<product>+++#+++.developer.license#=[replaceable]#L1cen5e-c0de# ... | |||
---- | |||
ifdef::web[] | |||
See link:https://vaadin.com/directory/help/installing-cval-license[the CVAL | |||
license key installation instructions] for more details. | |||
endif::web[] | |||
[[addons.cval.systemproperty.environments]] | |||
=== Passing License Key in Different Environments | |||
How you actually pass the parameter to the widget set compiler depends on the | |||
development environment and the build system that you use to compile the widget | |||
set. Below are listed a few typical environments: | |||
Eclipse IDE:: To install the license key for all projects, select "Window > Preferences" and | |||
navigate to the "Java > Installed JREs" section. Select the JRE version that you | |||
use for the application and click [guibutton]#Edit#. In the [guilabel]#Default | |||
VM arguments#, give the [parameter]#-D# expression as shown above. | |||
Apache Ant:: If compiling the project with Apache Ant, you could set the key in the Ant | |||
script as follows: | |||
+ | |||
[subs="normal"] | |||
---- | |||
<sysproperty key="vaadin.[replaceable]#<product>#.developer.license" | |||
value="**L1cen5e-c0de**"/> | |||
---- | |||
+ | |||
However, you should never store license keys in a source repository, so if the | |||
Ant script is stored in a source repository, you should pass the license key to | |||
Ant as a property that you then use in the script for the value argument of the | |||
[literal]#++<sysproperty>++# as follows: | |||
+ | |||
[subs="normal"] | |||
---- | |||
<sysproperty key="vaadin.[replaceable]#<product>#.developer.license" | |||
value="**${vaadin.[replaceable]#<product>#.developer.license}**"/> | |||
---- | |||
+ | |||
When invoking Ant from the command-line, you can pass the property with a | |||
[parameter]#-D# parameter to Ant. | |||
Apache Maven:: If building the project with Apache Maven, you can pass the license key with a | |||
[literal]#++-D++# parameter to Maven: | |||
+ | |||
[subs="normal"] | |||
---- | |||
[prompt]#$# [command]#mvn# -D[parameter]#vaadin.[replaceable]+++#+++<product>+++#+++.developer.license#=[replaceable]#L1cen5e-c0de# package | |||
---- | |||
Continuous Integration Systems:: In CIS systems, you can pass the license key to build runners as a system | |||
property in the build configuration. However, this only passes it to a runner. | |||
As described above, Ant does not pass it to sub-processes implicitly, so you | |||
need to forward it explicitly as described earlier. | |||
@@ -0,0 +1,61 @@ | |||
--- | |||
title: Downloading Add-ons from Vaadin Directory | |||
order: 2 | |||
layout: page | |||
--- | |||
[[addons.downloading]] | |||
= Downloading Add-ons from Vaadin Directory | |||
If you are not using Maven or a Maven-compatible dependency manager such as Ivy, | |||
or want to manage for your libraries manually, you can download add-on packages | |||
from the details page of an add-on in Vaadin Directory. | |||
. Select the version; some add-ons have several versions available. The latest is | |||
shown by default, but you can choose another the version to download from the | |||
dropdown menu in the header of the details page. | |||
. Click [guibutton]#Download Now# and save the JAR or Zip file on your computer. | |||
. If the add-on is packaged in a Zip package, unzip the package and follow any | |||
instructions provided inside the package. Typically, you just need to copy a JAR | |||
file to your web project under the [filename]#WEB-INF/lib# directory. | |||
+ | |||
Note that some add-ons may require other libraries. You can resolve such | |||
dependencies manually, but we recommend using a dependency manager such as Ivy | |||
or Maven in your project. | |||
. Update and recompile your project. In Eclipse, select the project and press F5. | |||
. You may need to compile the client-side implementations of the add-on | |||
components, that is, a __widget set__. This is the case for majority of add-ons, | |||
except for pure server-side, theme, or data binding add-ons. Compiling the | |||
widget set depends on the build environment. See <<addons.downloading.ant>>, or | |||
later in this chapter for instructions for compiling the widget set with Eclipse | |||
and | |||
Maven.+ | |||
//// | |||
See <xref linkend="addons.compiling"/> for | |||
instructions. | |||
//// | |||
. Update the project in your development web server and possibly restart the | |||
server. | |||
[[addons.downloading.ant]] | |||
== Compiling Widget Sets with an Ant Script | |||
If you need to compile the widget set with an Ant script, you can find a script | |||
template package at the link:http://vaadin.com/download/[Vaadin download page]. | |||
You can copy the files in the package to your project and, once configured, use | |||
it by running Ant in the directory. | |||
If you are using an IDE such as Eclipse, __always__ remember to refresh the | |||
project to synchronize it with the filesystem after compiling the widget set | |||
outside the IDE. | |||
@@ -0,0 +1,107 @@ | |||
--- | |||
title: Installing Add-ons in Eclipse with Ivy | |||
order: 3 | |||
layout: page | |||
--- | |||
[[addons.eclipse]] | |||
= Installing Add-ons in Eclipse with Ivy | |||
The Vaadin Plugin for Eclipse uses Apache Ivy to resolve dependencies. The | |||
dependencies should be listed in the [filename]#ivy.xml# file in the project | |||
root. The Vaadin Directory allows dowloading add-ons from a Maven repository, | |||
which can be accessed also by Ivy. | |||
You can also use Ivy to resolve dependencies in an Ant script. | |||
. Open the add-on page in Vaadin Directory. | |||
. Select the version. The latest is shown by default, but you can choose another | |||
the version from the dropdown menu in the header of the add-on details page. | |||
. Click the [guilabel]#Maven/Ivy# to display the Ivy dependency declaration, as | |||
illustrated in Figure <<figure.addons.eclipse.ivybutton>>. If the add-on is | |||
available with multiple licenses, you will be prompted to select a license for | |||
the dependency. | |||
+ | |||
[[figure.addons.eclipse.ivybutton]] | |||
.Ivy Dependency Declaration | |||
image::img/directory-ivy-dependency.png[] | |||
. Open the [filename]#ivysettings.xml# in your Eclipse project either in the XML | |||
or Ivy Editor (either double-click the file or right-click it and select "Open | |||
With > Ivy Editor"). | |||
+ | |||
Check that the settings file has the [literal]#++<ibiblio>++# entry given in the | |||
Directory page. It should be, if the file was created by the Vaadin project | |||
wizard in Eclipse. If not, copy it there. | |||
+ | |||
---- | |||
<chain name="default"> | |||
... | |||
<ibiblio name="vaadin-addons" | |||
usepoms="true" | |||
m2compatible="true" | |||
root="http://maven.vaadin.com/vaadin-addons"/> | |||
... | |||
</chain> | |||
---- | |||
+ | |||
If you get Vaadin addons from another repository, such as the local repository | |||
if you have compiled them yourself, you need to define a resolver for the | |||
repository in the settings file. | |||
. Open the [filename]#ivy.xml# in your Eclipse project and copy the Ivy dependency | |||
to inside the [literal]#++dependencies++# element. It should be as follows: | |||
+ | |||
[subs="normal"] | |||
---- | |||
<dependencies> | |||
... | |||
<dependency org="**com.vaadin.addon**" | |||
name="**vaadin-charts**" | |||
rev="**1.0.0**"/> | |||
</dependencies> | |||
---- | |||
+ | |||
You can specify either a fixed version number or a dynamic revision tag, such as | |||
[literal]#++latest.release++#. You can find more information about the | |||
link:http://ant.apache.org/ivy/history/2.1.0/ivyfile/dependency.html[dependency | |||
declarations] in Ivy documentation. | |||
+ | |||
If the [filename]#ivy.xml# does not have a [literal]#++<configurations | |||
defaultconfmapping="default->default">++# defined, you also need to have | |||
[literal]#++conf="default->default"++# in the dependency to resolve transient | |||
dependencies correctly. | |||
+ | |||
IvyIDE immediately resolves the dependencies when you save the file. | |||
. Compile the add-on widget set | |||
//// | |||
, as described in <xref | |||
linkend="addons.compiling.eclipse"/>. | |||
//// | |||
by clicking the [guilabel]#Compile Vaadin widgets# button in the toolbar. | |||
+ | |||
[[figure.addons.eclipse.toolbar]] | |||
.Compiling Widget Set in Eclipse | |||
image::img/widgetset-compiling-toolbar-hi.png[] | |||
If you experience problems with Ivy, first check all the dependency parameters. | |||
IvyDE can sometimes cause unexpected problems. You can clear the Ivy dependency | |||
cache by right-clicking the project and selecting "Ivy > Clean all caches". To | |||
refresh Ivy configuration, select "Ivy > Refresh". To try resolving again Ivy, | |||
select "Ivy > Resolve". | |||
@@ -0,0 +1,170 @@ | |||
--- | |||
title: Using Add-ons in a Maven Project | |||
order: 4 | |||
layout: page | |||
--- | |||
[[addons.maven]] | |||
= Using Add-ons in a Maven Project | |||
((("Maven", "using add-ons", id="term.addons.maven", range="startofrange"))) | |||
To use add-ons in a Maven project, you simply have to add them as dependencies | |||
in the project POM. Most add-ons include a widget set, which are compiled to the | |||
project widget set. | |||
Creating, compiling, and packaging a Vaadin project with Maven was described in | |||
<<dummy/../../../framework/getting-started/getting-started-maven#getting-started.maven,"Using | |||
Vaadin with Maven">>. | |||
[[addons.maven.dependency]] | |||
== Adding a Dependency | |||
Vaadin Directory provides a Maven repository for all the add-ons in the | |||
Directory. | |||
. Open the add-on page in Vaadin Directory. | |||
. Select the version. The latest is shown by default, but you can choose another | |||
the version from the dropdown menu in the header of the add-on details page. | |||
. Click the [guilabel]#Maven/Ivy# to display the Maven dependency declaration, as | |||
illustrated in Figure <<figure.addons.maven.pombutton>>. If the add-on is | |||
available with multiple licenses, you will be prompted to select a license for | |||
the dependency. | |||
+ | |||
[[figure.addons.maven.pombutton]] | |||
.Maven POM Definitions | |||
image::img/directory-maven-pom.png[] | |||
. Copy the [literal]#++dependency++# declaration to the [filename]#pom.xml# file | |||
in your project, under the [literal]#++dependencies++# element. | |||
+ | |||
[subs="normal"] | |||
---- | |||
... | |||
<dependencies> | |||
... | |||
<dependency> | |||
<groupId>**com.vaadin.addon**</groupId> | |||
<artifactId>**vaadin-charts**</artifactId> | |||
<version>**1.0.0**</version> | |||
</dependency> | |||
</dependencies> | |||
---- | |||
+ | |||
You can use an exact version number, as is done in the example above, or | |||
[literal]#++LATEST++# to always use the latest version of the add-on. | |||
+ | |||
The POM excerpt given in Directory includes also a repository definition, but if | |||
you have used the [literal]#++vaadin-archetype-application++# to create your | |||
project, it already includes the definition. | |||
. Compile the widget set as described in the following section. | |||
[[addons.maven.compiling]] | |||
== Compiling the Project Widget Set | |||
If you have used the [literal]#++vaadin-archetype-application++# to create the | |||
project, the [filename]#pom.xml# includes all necessary declarations to compile | |||
the widget set. The widget set compilation occurs in standard Maven build phase, | |||
such as with [parameter]#package# or [parameter]#install# goal. | |||
[subs="normal"] | |||
---- | |||
[prompt]#$# [command]#mvn# [parameter]#package# | |||
---- | |||
Then, just deploy the WAR to your application server. | |||
[[addons.maven.compiling.recompiling]] | |||
=== Recompiling the Widget Set | |||
The Vaadin plugin for Maven tries to avoid recompiling the widget set unless | |||
necessary, which sometimes means that it is not compiled even when it should. | |||
Running the [literal]#++clean++# goal usually helps, but causes a full | |||
recompilation. You can compile the widget set manually by running the | |||
[parameter]#vaadin:compile# goal. | |||
[subs="normal"] | |||
---- | |||
[prompt]#$# [command]#mvn# [parameter]#vaadin:compile# | |||
---- | |||
Note that this does not update the project widget set by searching new widget | |||
sets from the class path. It must be updated if you add or remove add-ons, for | |||
example. You can do that by running the [literal]#++vaadin:update-widgetset++# | |||
goal in the project directory. | |||
[subs="normal"] | |||
---- | |||
[prompt]#$# [command]#mvn# [parameter]#vaadin:update-widgetset# | |||
... | |||
[INFO] auto discovered modules [your.company.gwt.ProjectNameWidgetSet] | |||
[INFO] Updating widgetset your.company.gwt.ProjectNameWidgetSet | |||
[ERROR] 27.10.2011 19:22:34 com.vaadin.terminal.gwt.widgetsetutils.ClassPathExplorer getAvailableWidgetSets | |||
[ERROR] INFO: Widgetsets found from classpath: | |||
... | |||
---- | |||
Do not mind the "ERROR" labels, they are just an issue with the Vaadin Plugin | |||
for Maven. | |||
After running the update, you need to run the [literal]#++vaadin:compile++# goal | |||
to actually compile the widget set. | |||
[[addons.maven.widgetset]] | |||
== Enabling Widget Set Compilation | |||
If you are not using a POM created with the proper Vaadin archetype, you may | |||
need to enable widget set compilation manually. The simplest way to do that is | |||
to copy the definitions from a POM created with the archetype. Specifically, you | |||
need to copy the [literal]#++plugin++# definitions. You also need the Vaadin | |||
dependencies. | |||
You need to create an empty widget set definition file, which the widget set | |||
compilation will populate with widget sets found from the class path. Create a | |||
[filename]#src/main/java/com/example/AppWidgetSet.gwt.xml# file (in the project | |||
package) with an empty [literal]#++<module>++# element as follows: | |||
---- | |||
<module> | |||
</module> | |||
---- | |||
[[addons.maven.widgetset.web]] | |||
=== Enabling the Widget Set in the UI | |||
If you have previously used the default widget set in the project, you need to | |||
enable the project widget set in the [filename]#web.xml# deployment descriptor. | |||
Edit the [filename]#src/main/webapp/WEB-INF/web.xml# file and add or modify the | |||
[literal]#++widgetset++# parameter for the servlet as follows. | |||
[subs="normal"] | |||
---- | |||
<servlet> | |||
... | |||
<init-param> | |||
<description>Widget Set to Use</description> | |||
<param-name>widgetset</param-name> | |||
<param-value>**com.example.AppWidgetSet**</param-value> | |||
</init-param> | |||
</servlet> | |||
---- | |||
The parameter is the class name of the widget set, that is, without the | |||
[filename]#.gwt.xml# extension and with the Java dot notation for class names | |||
that include the package name. | |||
(((range="endofrange", startref="term.addons.maven"))) | |||
@@ -0,0 +1,37 @@ | |||
--- | |||
title: Overview | |||
order: 1 | |||
layout: page | |||
--- | |||
[[addons.overview]] | |||
= Overview | |||
In addition to the components, layouts, themes, and data sources built in into | |||
the core Vaadin library, many others are available as add-ons. | |||
link:http://vaadin.com/directory/[Vaadin Directory] provides a rich collection | |||
of add-ons for Vaadin, and you may find others from independent sources. Add-ons | |||
are also one way to share your own components between projects. | |||
Installation of add-ons from Vaadin Directory is simple, just adding an Ivy or | |||
Maven dependency, or downloading the JAR package and and dropping it in the web | |||
library folder of the project. Most add-ons include a widget set, which you need | |||
to compile, but it's usually just a click of a button or a single command. | |||
After trying out an add-on, you can give some feedback to the author of the | |||
add-on by rating the add-on with one to five stars and optionally leaving a | |||
comment. Most add-ons also have a discussion forum thread for user feedback and | |||
questions. | |||
Add-ons available from Vaadin Directory are distributed under different | |||
licenses, of which some are commercial. While the add-ons can be downloaded | |||
directly, you should note their license and other terms and conditions. Many are | |||
offered under a dual licensing agreement so that they can be used in open source | |||
projects for free, and many have a trial period for closed-source development. | |||
Commercial Vaadin add-ons distributed under the CVAL license require installing | |||
a license key as instructed in | |||
<<dummy/../../../framework/addons/addons-cval#addons.cval,"Installing Commercial | |||
Vaadin Add-on Licence">>. | |||
@@ -0,0 +1,57 @@ | |||
--- | |||
title: Troubleshooting | |||
order: 6 | |||
layout: page | |||
--- | |||
[[addons.troubleshooting]] | |||
= Troubleshooting | |||
If you experience problems with using add-ons, you can try the following: | |||
* Check the [filename]#.gwt.xml# descriptor file under the the project root | |||
package. For example, if the project root package is | |||
[filename]#com.example.myproject#, the widget set definition file is typically | |||
at [filename]#com/example/project/AppWidgetset.gwt.xml#. The location is not | |||
fixed and it can be elsewhere, as long as references to it match. See | |||
<<dummy/../../../framework/clientside/clientside-module#clientside.module,"Client-Side | |||
Module Descriptor">> for details on the contents of the client-side module | |||
descriptor, which is used to define a widget set. | |||
* Check the [filename]#WEB-INF/web.xml# deployment descriptor and see that the | |||
servlet for your UI has a widget set parameter, such as the following: | |||
+ | |||
---- | |||
<init-param> | |||
<description>UI widgetset</description> | |||
<param-name>widgetset</param-name> | |||
<param-value>com.example.project.AppWidgetSet</param-value> | |||
</init-param> | |||
---- | |||
+ | |||
Check that the widget set class corresponds with the [filename]#.gwt.xml# file | |||
in the source tree. | |||
* See the [filename]#VAADIN/widgetsets# directory and check that the widget set | |||
appears there. You can remove it and recompile the widget set to see that the | |||
compilation works properly. | |||
* Use the [guilabel]#Net# tab in Firebug to check that the widget set (and theme) | |||
is loaded properly. | |||
* Use the ?debug parameter for the application to open the debug window and check | |||
if there is any version conflict between the widget set and the Vaadin library, | |||
or the themes. See | |||
<<dummy/../../../framework/advanced/advanced-debug#advanced.debug,"Debug Mode | |||
and Window">> for details. | |||
* Refresh and recompile the project. In Eclipse, select the project and press F5, | |||
stop the server, clean the server temporary directories, and restart it. | |||
* Check the Error Log view in Eclipse (or in the IDE you use). | |||
@@ -0,0 +1,19 @@ | |||
[[addons]] | |||
== Using Vaadin Add-ons | |||
This chapter describes the installation of add-on components, themes, | |||
containers, and other tools from the Vaadin Directory and the use of commercial | |||
add-ons offered by Vaadin. | |||
include::addons-overview.asciidoc[leveloffset=+2] | |||
include::addons-downloading.asciidoc[leveloffset=+2] | |||
include::addons-eclipse.asciidoc[leveloffset=+2] | |||
include::addons-maven.asciidoc[leveloffset=+2] | |||
include::addons-cval.asciidoc[leveloffset=+2] | |||
include::addons-troubleshooting.asciidoc[leveloffset=+2] |
@@ -0,0 +1,176 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<!-- Created with Inkscape (http://www.inkscape.org/) --> | |||
<svg | |||
xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
xmlns:cc="http://creativecommons.org/ns#" | |||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" | |||
xmlns:xlink="http://www.w3.org/1999/xlink" | |||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
width="210mm" | |||
height="297mm" | |||
id="svg1901" | |||
sodipodi:version="0.32" | |||
inkscape:version="0.46" | |||
sodipodi:docname="widgetset-compiling-toolbar.svg" | |||
sodipodi:docbase="/home/tsoots/ohj/translations/po" | |||
inkscape:output_extension="org.inkscape.output.svg.inkscape"> | |||
<defs | |||
id="defs1903"> | |||
<inkscape:perspective | |||
sodipodi:type="inkscape:persp3d" | |||
inkscape:vp_x="0 : 526.18109 : 1" | |||
inkscape:vp_y="0 : 1000 : 0" | |||
inkscape:vp_z="744.09448 : 526.18109 : 1" | |||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1" | |||
id="perspective7" /> | |||
<inkscape:perspective | |||
id="perspective2499" | |||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1" | |||
inkscape:vp_z="744.09448 : 526.18109 : 1" | |||
inkscape:vp_y="0 : 1000 : 0" | |||
inkscape:vp_x="0 : 526.18109 : 1" | |||
sodipodi:type="inkscape:persp3d" /> | |||
<linearGradient | |||
y2="471.38400" | |||
y1="45.132561" | |||
xlink:href="#linearGradient7601" | |||
x2="1370.5586" | |||
x1="-526.86133" | |||
spreadMethod="reflect" | |||
inkscape:collect="always" | |||
id="linearGradient10877" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="matrix(8.892150e-2,0.000000,0.000000,0.155616,635.7169,9.380527)" /> | |||
<linearGradient | |||
y2="471.38400" | |||
y1="45.132561" | |||
xlink:href="#linearGradient7601" | |||
x2="1370.5586" | |||
x1="-526.86133" | |||
spreadMethod="reflect" | |||
inkscape:collect="always" | |||
id="linearGradient10869" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="matrix(0.323979,0.000000,0.000000,0.566975,399.6324,14.15086)" /> | |||
<linearGradient | |||
y2="471.38400" | |||
y1="45.132561" | |||
xlink:href="#linearGradient7601" | |||
x2="1370.5586" | |||
x1="-526.86133" | |||
spreadMethod="reflect" | |||
inkscape:collect="always" | |||
id="linearGradient7607" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="matrix(0.755921,0,0,1.32289,-36,0)" /> | |||
<linearGradient | |||
inkscape:collect="always" | |||
id="linearGradient7601"> | |||
<stop | |||
style="stop-color:#000000;stop-opacity:1;" | |||
offset="0" | |||
id="stop7603" /> | |||
<stop | |||
style="stop-color:#000000;stop-opacity:0;" | |||
offset="1" | |||
id="stop7605" /> | |||
</linearGradient> | |||
<inkscape:perspective | |||
id="perspective13602" | |||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1" | |||
inkscape:vp_z="744.09448 : 526.18109 : 1" | |||
inkscape:vp_y="0 : 1000 : 0" | |||
inkscape:vp_x="0 : 526.18109 : 1" | |||
sodipodi:type="inkscape:persp3d" /> | |||
<inkscape:perspective | |||
id="perspective2529" | |||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1" | |||
inkscape:vp_z="744.09448 : 526.18109 : 1" | |||
inkscape:vp_y="0 : 1000 : 0" | |||
inkscape:vp_x="0 : 526.18109 : 1" | |||
sodipodi:type="inkscape:persp3d" /> | |||
</defs> | |||
<sodipodi:namedview | |||
id="base" | |||
pagecolor="#ffffff" | |||
bordercolor="#666666" | |||
borderopacity="1.0" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:zoom="2.8" | |||
inkscape:cx="295.42901" | |||
inkscape:cy="873.26277" | |||
inkscape:document-units="px" | |||
inkscape:current-layer="layer1" | |||
gridtolerance="10000" | |||
inkscape:window-width="1333" | |||
inkscape:window-height="739" | |||
inkscape:window-x="1493" | |||
inkscape:window-y="131" | |||
showgrid="false" /> | |||
<metadata | |||
id="metadata1906"> | |||
<rdf:RDF> | |||
<cc:Work | |||
rdf:about=""> | |||
<dc:format>image/svg+xml</dc:format> | |||
<dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
</cc:Work> | |||
</rdf:RDF> | |||
</metadata> | |||
<g | |||
inkscape:label="Taso 1" | |||
inkscape:groupmode="layer" | |||
id="layer1" | |||
style="opacity:1"> | |||
<image | |||
y="116.93364" | |||
x="125.21431" | |||
id="image2501" | |||
height="48" | |||
width="281" | |||
sodipodi:absref="/home/magi/itmill/book-7/manual/img/addons/widgetset-compiling-toolbar.png" | |||
xlink:href="/home/magi/itmill/book-7/manual/img/addons/widgetset-compiling-toolbar.png" /> | |||
<rect | |||
style="opacity:1;fill:#eeeff2;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.0999999;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.29999998;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |||
id="rect2535" | |||
width="24.496172" | |||
height="16.667501" | |||
x="204.80843" | |||
y="122.51678" /> | |||
<image | |||
y="122.34544" | |||
x="208.74406" | |||
id="image2531" | |||
height="17.262691" | |||
width="17.262691" | |||
sodipodi:absref="//home/magi/itmill/book-7/manual/img/addons/compile-widgetset-16.png" | |||
xlink:href="/home/magi/itmill/book-7/manual/img/addons/compile-widgetset-16.png" | |||
style="fill:#eeeff2;fill-opacity:1" /> | |||
<g | |||
style="display:inline" | |||
inkscape:label="Layer 1" | |||
id="g13611" | |||
transform="matrix(2.4577007e-2,0,0,2.4577007e-2,218.45402,137.72183)"> | |||
<g | |||
id="g1317"> | |||
<path | |||
style="fill:url(#linearGradient7607);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" | |||
id="path6080" | |||
d="M 70.29035,24.82601 L 70.29035,627.16976 L 105.72785,627.16976 L 105.72785,591.73226 L 141.16535,591.73226 L 141.16535,556.32601 L 176.5716,556.32601 L 176.5716,520.88851 L 212.0091,520.88851 L 247.4466,520.88851 L 247.4466,591.73226 L 282.8841,591.73226 L 282.8841,662.60726 L 318.3216,662.60726 L 318.3216,733.48226 L 353.7591,733.48226 L 353.7591,768.91976 L 424.60285,768.91976 L 424.60285,733.48226 L 460.04035,733.48226 L 460.04035,662.60726 L 424.60285,662.60726 L 424.60285,591.73226 L 389.1966,591.73226 L 389.1966,520.88851 L 353.7591,520.88851 L 353.7591,450.01351 L 495.47785,450.01351 L 495.47785,414.57601 L 460.04035,414.57601 L 460.04035,379.13851 L 424.60285,379.13851 L 424.60285,343.70101 L 389.1966,343.70101 L 389.1966,308.29476 L 353.7591,308.29476 L 353.7591,272.85726 L 318.3216,272.85726 L 318.3216,237.41976 L 282.8841,237.41976 L 282.8841,201.98226 L 247.4466,201.98226 L 247.4466,166.54476 L 212.0091,166.54476 L 212.0091,131.10726 L 176.5716,131.10726 L 176.5716,95.669761 L 141.16535,95.669761 L 141.16535,60.26351 L 105.72785,60.26351 L 105.72785,24.82601 L 70.29035,24.82601 z" /> | |||
<path | |||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | |||
id="rect1430" | |||
d="M 35.4375,24.8125 L 35.4375,627.15625 L 70.875,627.15625 L 70.875,591.71875 L 106.3125,591.71875 L 106.3125,556.3125 L 70.875,556.3125 L 70.875,95.65625 L 106.3125,95.65625 L 106.3125,60.25 L 70.875,60.25 L 70.875,24.8125 L 35.4375,24.8125 z M 106.3125,95.65625 L 106.3125,131.09375 L 141.71875,131.09375 L 141.71875,95.65625 L 106.3125,95.65625 z M 141.71875,131.09375 L 141.71875,166.53125 L 177.15625,166.53125 L 177.15625,131.09375 L 141.71875,131.09375 z M 177.15625,166.53125 L 177.15625,201.96875 L 212.59375,201.96875 L 212.59375,166.53125 L 177.15625,166.53125 z M 212.59375,201.96875 L 212.59375,237.40625 L 248.03125,237.40625 L 248.03125,201.96875 L 212.59375,201.96875 z M 248.03125,237.40625 L 248.03125,272.84375 L 283.46875,272.84375 L 283.46875,237.40625 L 248.03125,237.40625 z M 283.46875,272.84375 L 283.46875,308.28125 L 318.90625,308.28125 L 318.90625,272.84375 L 283.46875,272.84375 z M 318.90625,308.28125 L 318.90625,343.6875 L 354.34375,343.6875 L 354.34375,308.28125 L 318.90625,308.28125 z M 354.34375,343.6875 L 354.34375,379.125 L 389.75,379.125 L 389.75,343.6875 L 354.34375,343.6875 z M 389.75,379.125 L 389.75,414.5625 L 283.46875,414.5625 L 283.46875,450 L 283.46875,520.875 L 318.90625,520.875 L 318.90625,450 L 460.625,450 L 460.625,414.5625 L 425.1875,414.5625 L 425.1875,379.125 L 389.75,379.125 z M 318.90625,520.875 L 318.90625,591.71875 L 354.34375,591.71875 L 354.34375,520.875 L 318.90625,520.875 z M 354.34375,591.71875 L 354.34375,662.59375 L 389.75,662.59375 L 389.75,591.71875 L 354.34375,591.71875 z M 389.75,662.59375 L 389.75,733.46875 L 425.1875,733.46875 L 425.1875,662.59375 L 389.75,662.59375 z M 389.75,733.46875 L 318.90625,733.46875 L 318.90625,768.90625 L 389.75,768.90625 L 389.75,733.46875 z M 318.90625,733.46875 L 318.90625,662.59375 L 283.46875,662.59375 L 283.46875,733.46875 L 318.90625,733.46875 z M 283.46875,662.59375 L 283.46875,591.71875 L 248.03125,591.71875 L 248.03125,662.59375 L 283.46875,662.59375 z M 248.03125,591.71875 L 248.03125,520.875 L 212.59375,520.875 L 212.59375,591.71875 L 248.03125,591.71875 z M 212.59375,520.875 L 212.59375,450 L 177.15625,450 L 177.15625,485.4375 L 141.71875,485.4375 L 141.71875,520.875 L 177.15625,520.875 L 212.59375,520.875 z M 141.71875,520.875 L 106.3125,520.875 L 106.3125,556.3125 L 141.71875,556.3125 L 141.71875,520.875 z" /> | |||
<path | |||
style="fill:#ffffff;fill-opacity:1;stroke:none" | |||
id="rect3779" | |||
d="M 70.875,95.65625 L 70.875,556.3125 L 106.3125,556.3125 L 106.3125,520.875 L 141.71875,520.875 L 141.71875,485.4375 L 177.15625,485.4375 L 177.15625,450 L 212.59375,450 L 212.59375,520.875 L 248.03125,520.875 L 248.03125,591.71875 L 283.46875,591.71875 L 283.46875,662.59375 L 318.90625,662.59375 L 318.90625,733.46875 L 354.34375,733.46875 L 389.75,733.46875 L 389.75,662.59375 L 354.34375,662.59375 L 354.34375,591.71875 L 318.90625,591.71875 L 318.90625,520.875 L 283.46875,520.875 L 283.46875,414.5625 L 318.90625,414.5625 L 354.34375,414.5625 L 389.75,414.5625 L 389.75,379.125 L 354.34375,379.125 L 354.34375,343.6875 L 318.90625,343.6875 L 318.90625,308.28125 L 283.46875,308.28125 L 283.46875,272.84375 L 248.03125,272.84375 L 248.03125,237.40625 L 212.59375,237.40625 L 212.59375,201.96875 L 177.15625,201.96875 L 177.15625,166.53125 L 141.71875,166.53125 L 141.71875,131.09375 L 106.3125,131.09375 L 106.3125,95.65625 L 70.875,95.65625 z" /> | |||
</g> | |||
</g> | |||
</g> | |||
</svg> |
@@ -0,0 +1,298 @@ | |||
--- | |||
title: Advanced Application Architectures | |||
order: 10 | |||
layout: page | |||
--- | |||
[[advanced.architecture]] | |||
= Advanced Application Architectures | |||
In this section, we continue from the basic application architectures described | |||
in | |||
<<dummy/../../../framework/application/application-architecture#application.architecture,"Building | |||
the UI">> and discuss some of the more advanced patterns that are often used in | |||
Vaadin applications. | |||
[[advanced.architecture.layering]] | |||
== Layered Architectures | |||
Layered architectures, where each layer has a clearly distinct responsibility, | |||
are probably the most common architectures. Typically, applications follow at | |||
least a three-layer architecture: | |||
* User interface (or presentation) layer | |||
* Domain layer | |||
* Data store layer | |||
Such an architecture starts from a __domain model__, which defines the data | |||
model and the "business logic" of the application, typically as beans or POJOs. | |||
A user interface is built on top of the domain model, in our context with the | |||
Vaadin Framework. The Vaadin user interface could be bound directly to the data | |||
model through the Vaadin Data Model, described in | |||
<<dummy/../../../framework/datamodel/datamodel-overview.asciidoc#datamodel.overview,"Binding | |||
Components to Data">>. Beneath the domain model lies a data store, such as a | |||
relational database. The dependencies between the layers are restricted so that | |||
a higher layer may depend on a lower one, but never the other way around. | |||
[[figure.advanced.architecture.layering]] | |||
.Three-Layer Architecture | |||
image::img/three-layer-architecture-hi.png[] | |||
An __application layer__ (or __service layer__) is often distinguished from the | |||
domain layer, offering the domain logic as a service, which can be used by the | |||
user interface layer, as well as for other uses. In Java EE development, | |||
Enterprise JavaBeans (EJBs) are typically used for building this layer. | |||
An __infrastructure layer__ (or __data access layer__) is often distinguished | |||
from the data store layer, with a purpose to abstract the data store. For | |||
example, it could involve a persistence solution such as JPA and an EJB | |||
container. This layer becomes relevant with Vaadin when binding Vaadin | |||
components to data with the JPAContainer, as described in | |||
<<dummy/../../../framework/jpacontainer/jpacontainer-overview.asciidoc#jpacontainer.overview,"Vaadin | |||
JPAContainer">>. | |||
[[advanced.architecture.mvp]] | |||
== Model-View-Presenter Pattern | |||
The Model-View-Presenter (MVP) pattern is one of the most common patterns in | |||
developing large applications with Vaadin. It is similar to the older | |||
Model-View-Controller (MVC) pattern, which is not as meaningful in Vaadin | |||
development. Instead of an implementation-aware controller, there is an | |||
implementation-agnostic presenter that operates the view through an interface. | |||
The view does not interact directly with the model. This isolates the view | |||
implementation better than in MVC and allows easier unit testing of the | |||
presenter and model. | |||
[[figure.advanced.architecture.mvp]] | |||
.Model-View-Presenter Pattern | |||
image::img/mvp-pattern-hi.png[] | |||
<<figure.advanced.architecture.mvp>> illustrates the MVP pattern with a simple | |||
calculator. The domain model is realized in the [classname]#Calculator# class, | |||
which includes a data model and some model logic operations. The | |||
[classname]#CalculatorViewImpl# is a Vaadin implementation of the view, defined | |||
in the [interfacename]#CalculatorView# interface. The | |||
[classname]#CalculatorPresenter# handles the user interface logic. User | |||
interaction events received in the view are translated into | |||
implementation-independent events for the presenter to handle (the view | |||
implementation could also just call the presenter). | |||
Let us first look how the model and view are bound together by the presenter in | |||
the following example: | |||
[source, java] | |||
---- | |||
// Create the model and the Vaadin view implementation | |||
CalculatorModel model = new CalculatorModel(); | |||
CalculatorViewImpl view = new CalculatorViewImpl(); | |||
// The presenter binds the model and view together | |||
new CalculatorPresenter(model, view); | |||
// The view implementation is a Vaadin component | |||
layout.addComponent(view); | |||
---- | |||
You could add the view anywhere in a Vaadin application, as it is a composite | |||
component. | |||
[[advanced.architecture.mvp.model]] | |||
=== The Model | |||
Our business model is quite simple, with one value and a number of operations | |||
for manipulating it. | |||
[source, java] | |||
---- | |||
/** The model **/ | |||
class CalculatorModel { | |||
private double value = 0.0; | |||
public void clear() { | |||
value = 0.0; | |||
} | |||
public void add(double arg) { | |||
value += arg; | |||
} | |||
public void multiply(double arg) { | |||
value *= arg; | |||
} | |||
public void divide(double arg) { | |||
if (arg != 0.0) | |||
value /= arg; | |||
} | |||
public double getValue() { | |||
return value; | |||
} | |||
public void setValue(double value) { | |||
this.value = value; | |||
} | |||
} | |||
---- | |||
[[advanced.architecture.mvp.view]] | |||
=== The View | |||
The purpose of the view in MVP is to display data and receive user interaction. | |||
It relays the user interaction to the presenter in an fashion that is | |||
independent of the view implementation, that is, no Vaadin events. It is defined | |||
as a UI framework interface that can have multiple implementations. | |||
[source, java] | |||
---- | |||
interface CalculatorView { | |||
public void setDisplay(double value); | |||
interface CalculatorViewListener { | |||
void buttonClick(char operation); | |||
} | |||
public void addListener(CalculatorViewListener listener); | |||
} | |||
---- | |||
The are design alternatives for the view. It could receive the listener in its | |||
constructor, or it could just know the presenter. Here, we forward button clicks | |||
as an implementation-independent event. | |||
As we are using Vaadin, we make a Vaadin implementation of the interface as | |||
follows: | |||
[source, java] | |||
---- | |||
class CalculatorViewImpl extends CustomComponent | |||
implements CalculatorView, ClickListener { | |||
private Label display = new Label("0.0"); | |||
public CalculatorViewImpl() { | |||
GridLayout layout = new GridLayout(4, 5); | |||
// Create a result label that spans over all | |||
// the 4 columns in the first row | |||
layout.addComponent(display, 0, 0, 3, 0); | |||
// The operations for the calculator in the order | |||
// they appear on the screen (left to right, top | |||
// to bottom) | |||
String[] operations = new String[] { | |||
"7", "8", "9", "/", "4", "5", "6", | |||
"*", "1", "2", "3", "-", "0", "=", "C", "+" }; | |||
// Add buttons and have them send click events | |||
// to this class | |||
for (String caption: operations) | |||
layout.addComponent(new Button(caption, this)); | |||
setCompositionRoot(layout); | |||
} | |||
public void setDisplay(double value) { | |||
display.setValue(Double.toString(value)); | |||
} | |||
/* Only the presenter registers one listener... */ | |||
List<CalculatorViewListener> listeners = | |||
new ArrayList<CalculatorViewListener>(); | |||
public void addListener(CalculatorViewListener listener) { | |||
listeners.add(listener); | |||
} | |||
/** Relay button clicks to the presenter with an | |||
* implementation-independent event */ | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
for (CalculatorViewListener listener: listeners) | |||
listener.buttonClick(event.getButton() | |||
.getCaption().charAt(0)); | |||
} | |||
} | |||
---- | |||
[[advanced.architecture.mvp.presenter]] | |||
=== The Presenter | |||
The presenter in MVP is a middle-man that handles all user interaction logic, | |||
but in an implementation-independent way, so that it doesn't actually know | |||
anything about Vaadin. It shows data in the view and receives user interaction | |||
back from it. | |||
[source, java] | |||
---- | |||
class CalculatorPresenter | |||
implements CalculatorView.CalculatorViewListener { | |||
CalculatorModel model; | |||
CalculatorView view; | |||
private double current = 0.0; | |||
private char lastOperationRequested = 'C'; | |||
public CalculatorPresenter(CalculatorModel model, | |||
CalculatorView view) { | |||
this.model = model; | |||
this.view = view; | |||
view.setDisplay(current); | |||
view.addListener(this); | |||
} | |||
@Override | |||
public void buttonClick(char operation) { | |||
// Handle digit input | |||
if ('0' <= operation && operation <= '9') { | |||
current = current * 10 | |||
+ Double.parseDouble("" + operation); | |||
view.setDisplay(current); | |||
return; | |||
} | |||
// Execute the previously input operation | |||
switch (lastOperationRequested) { | |||
case '+': | |||
model.add(current); | |||
break; | |||
case '-': | |||
model.add(-current); | |||
break; | |||
case '/': | |||
model.divide(current); | |||
break; | |||
case '*': | |||
model.multiply(current); | |||
break; | |||
case 'C': | |||
model.setValue(current); | |||
break; | |||
} // '=' is implicit | |||
lastOperationRequested = operation; | |||
current = 0.0; | |||
if (operation == 'C') | |||
model.clear(); | |||
view.setDisplay(model.getValue()); | |||
} | |||
} | |||
---- | |||
In the above example, we held some state information in the presenter. | |||
Alternatively, we could have had an intermediate controller between the | |||
presenter and the model to handle the low-level button logic. | |||
@@ -0,0 +1,208 @@ | |||
--- | |||
title: Debug Mode and Window | |||
order: 3 | |||
layout: page | |||
--- | |||
[[advanced.debug]] | |||
= Debug Mode and Window | |||
Vaadin applications can be run in two modes: __debug mode__ and __production | |||
mode__. The debug mode, which is on by default, enables a number of built-in | |||
debug features for Vaadin developers: | |||
* Debug Window | |||
* Display debug information in the Debug Window and server console | |||
* On-the-fly compilation of Sass themes | |||
[[advanced.debug.mode]] | |||
== Enabling the Debug Mode | |||
The debug mode is enabled and production mode disabled by default in the UI | |||
templates created with the Eclipse plugin or the Maven archetypes. The debug | |||
mode can be enabled by giving a [parameter]#productionMode=false# parameter to | |||
the Vaadin servlet configuration: | |||
[subs="normal"] | |||
---- | |||
@VaadinServletConfiguration( | |||
productionMode = **false**, | |||
ui = **MyprojectUI.class**) | |||
---- | |||
Or with a context parameter in the [filename]#web.xml# deployment descriptor: | |||
[subs="normal"] | |||
---- | |||
<context-param> | |||
<description>Vaadin production mode</description> | |||
<param-name>productionMode</param-name> | |||
<param-value>**false**</param-value> | |||
</context-param> | |||
---- | |||
Enabling the production mode disables the debug features, thereby preventing | |||
users from easily inspecting the inner workings of the application from the | |||
browser. | |||
[[advanced.debug.open]] | |||
== Opening the Debug Window | |||
Running an application in the debug mode enables the client-side Debug Window in | |||
the browser. You can open the Debug Window by adding " ?debug" parameter to the | |||
URL of the UI, for example, http://localhost:8080/myapp/?debug. The Debug Window | |||
has buttons for controlling the debugging features and a scrollable log of debug | |||
messages. | |||
[[]] | |||
.Debug Window | |||
image::img/debug-window-annotated-hi.png[] | |||
The functionalities are described in detail in the subsequent sections. You can | |||
move the window by dragging it from the title bar and resize it from the | |||
corners. The [guibutton]#Minimize# button minimizes the debug window in the | |||
corner of the browser window, and the [guibutton]#Close# button closes it. | |||
If you use the Firebug plugin for Firefox or the Developer Tools console in | |||
Chrome, the log messages will also be printed to the Firebug console. In such a | |||
case, you may want to enable client-side debugging without showing the Debug | |||
Window with " ?debug=quiet" in the URL. In the quiet debug mode, log messages | |||
will only be printed to the console of the browser debugger. | |||
[[advanced.debug.log]] | |||
== Debug Message Log | |||
The debug message log displays client-side debug messages, with time counter in | |||
milliseconds. The control buttons allow you to clear the log, reset the timer, | |||
and lock scrolling. | |||
[[]] | |||
.Debug Message Log | |||
image::img/debug-log-hi.png[] | |||
[[advanced.debug.log.custom]] | |||
=== Logging to Debug Window | |||
You can take advantage of the debug mode when developing client-side components, | |||
by using the standard Java [classname]#Logger# to write messages to the log. The | |||
messages will be written to the debug window and Firebug console. No messages | |||
are written if the debug window is not open or if the application is running in | |||
production mode. | |||
[[advanced.debug.info]] | |||
== General Information | |||
The [guilabel]#General information about the application(s)# tab displays | |||
various information about the UI, such as version numbers of the client and | |||
servlet engine, and the theme. If they do not match, you may need to compile the | |||
widget set or theme. | |||
[[]] | |||
.General Information | |||
image::img/debug-info.png[] | |||
[[advanced.debug.hierarchy]] | |||
== Inspecting Component Hierarchy | |||
The [guilabel]#Component Hierarchy# tab has several sub-modes that allow | |||
debugging the component tree in various ways. | |||
[[advanced.debug.hierarchy.tree]] | |||
=== Connector Hierarchy Tree | |||
The [guibutton]#Show the connector hierarchy tree# button displays the | |||
client-side connector hierarchy. As explained in | |||
<<dummy/../../../framework/gwt/gwt-overview.asciidoc#gwt.overview,"Integrating | |||
with the Server-Side">>, client-side widgets are managed by connectors that | |||
handle communication with the server-side component counterparts. The connector | |||
hierarchy therefore corresponds with the server-side component tree, but the | |||
client-side widget tree and HTML DOM tree have more complexity. | |||
[[]] | |||
.Connector Hierarchy Tree | |||
image::img/debug-hierarchy-tree.png[] | |||
Clicking on a connector highlights the widget in the UI. | |||
[[advanced.debug.hierarchy.inspect]] | |||
=== Inspecting a Component | |||
The [guibutton]#Select a component in the page to inspect it# button lets you | |||
select a component in the UI by clicking it and display its client-side | |||
properties. | |||
To view the HTML structure and CSS styles in more detail, you can use Firebug in | |||
Firefox, or the Developer Tools in Chrome, as described in | |||
<<dummy/../../../framework/getting-started/getting-started-environment#getting-started.environment.firefox,"Firefox | |||
and Firebug">>. Firefox also has a built-in feature for inspecting HTML and CSS. | |||
[[advanced.debug.hierarchy.analyze]] | |||
=== Analyzing Layout Problems | |||
The [guilabel]#Check layouts for potential problems# button analyzes the | |||
currently visible UI and makes a report of possible layout related problems. All | |||
detected layout problems are displayed in the log and also printed to the | |||
console. | |||
[[]] | |||
.Debug Window Showing the Result of Layout Analysis. | |||
image::img/debug-window-analyze-layouts.png[] | |||
Clicking on a reported problem highlights the component with the problem in the | |||
UI. | |||
The most common layout problem is caused by placing a component that has a | |||
relative size inside a container (layout) that has undefined size in the | |||
particular direction (height or width). For example, adding a | |||
[classname]#Button# with 100% width inside a [classname]#VerticalLayout# with | |||
undefined width. In such a case, the error would look as shown in | |||
<<dummy/../../../framework//-overview.asciidoc#figure.advanced.debug.hierarchy.analyze,"">>. | |||
[classname]#CustomLayout# components can not be analyzed in the same way as | |||
other layouts. For custom layouts, the button analyzes all contained | |||
relative-sized components and checks if any relative dimension is calculated to | |||
zero so that the component will be invisible. The error log will display a | |||
warning for each of these invisible components. It would not be meaningful to | |||
emphasize the component itself as it is not visible, so when you select such an | |||
error, the parent layout of the component is emphasized if possible. | |||
[[advanced.debug.hierarchy.used]] | |||
=== Displaying Used Connectors | |||
The last button, [guibutton]#Show used connectors and how to optimize widget | |||
set#, displays a list of all currently visible connectors. It also generates a | |||
connector bundle loader factory, which you can use to optimize the widget set so | |||
that it only contains the widgets actually used in the UI. Note, however, that | |||
it only lists the connectors visible in the current UI state, and you usually | |||
have more connectors than that. | |||
[[advanced.debug.communication]] | |||
== Communication Log | |||
The [guilabel]#Communication# tab displays all server requests. You can unfold | |||
the requests to view details, such as the connectors involved. Clicking on a | |||
connector highlights the corresponding element in the UI. | |||
You can use Firebug or Developer Tools in Firefox or Chrome, respectively, to | |||
get more detailed information about the requests and responses. | |||
[[advanced.debug.devmodes]] | |||
== Debug Modes | |||
The [guilabel]#Menu# tab in the window opens a sub-menu to select various | |||
settings. Here you can also launch the GWT SuperDevMode, as described in | |||
<<dummy/../../../framework/clientside/clientside-debugging#clientside.debugging,"Debugging | |||
Client-Side Code">>. | |||
@@ -0,0 +1,567 @@ | |||
--- | |||
title: Drag and Drop | |||
order: 12 | |||
layout: page | |||
--- | |||
[[advanced.dragndrop]] | |||
= Drag and Drop | |||
((("Drag and Drop", id="term.advanced.dragndrop", range="startofrange"))) | |||
Dragging an object from one location to another by grabbing it with mouse, | |||
holding the mouse button pressed, and then releasing the button to "drop" it to | |||
the other location is a common way to move, copy, or associate objects. For | |||
example, most operating systems allow dragging and dropping files between | |||
folders or dragging a document on a program to open it. In Vaadin, it is | |||
possible to drag and drop components and parts of certain components. | |||
Dragged objects, or __transferables__, are essentially data objects. You can | |||
drag and drop rows in [classname]#Table# and nodes in [classname]#Tree# | |||
components, either within or between the components. You can also drag entire | |||
components by wrapping them inside [classname]#DragAndDropWrapper#. | |||
Dragging starts from a __drag source__, which defines the transferable. | |||
Transferables implement the [classname]#Transferable# interfaces. For trees and | |||
tables, which are bound to [classname]#Container# data sources, a node or row | |||
transferable is a reference to an [classname]#Item# in the Vaadin Data Model. | |||
Dragged components are referenced with a [classname]#WrapperTransferable#. | |||
Starting dragging does not require any client-server communication, you only | |||
need to enable dragging. All drag and drop logic occurs in two operations: | |||
determining ( __accepting__) where dropping is allowed and actually dropping. | |||
Drops can be done on a __drop target__, which implements the | |||
[classname]#DropTarget# interface. Three components implement the interface: | |||
[classname]#Tree#, [classname]#Table#, and [classname]#DragAndDropWrapper#. | |||
These accept and drop operations need to be provided in a __drop handler__. | |||
Essentially all you need to do to enable drag and drop is to enable dragging in | |||
the drag source and implement the [methodname]#getAcceptCriterion()# and | |||
[methodname]#drop()# methods in the [classname]#DropHandler# interface. | |||
The client-server architecture of Vaadin causes special requirements for the | |||
drag and drop functionality. The logic for determining where a dragged object | |||
can be dropped, that is, __accepting__ a drop, should normally be done on the | |||
client-side, in the browser. Server communications are too slow to have much of | |||
such logic on the server-side. The drag and drop feature therefore offers a | |||
number of ways to avoid the server communications to ensure a good user | |||
experience. | |||
[[advanced.dragndrop.drophandler]] | |||
== Handling Drops | |||
Most of the user-defined drag and drop logic occurs in a __drop handler__, which | |||
is provided by implementing the [methodname]#drop()# method in the | |||
[classname]#DropHandler# interface. A closely related definition is the drop | |||
accept criterion, which is defined in the [methodname]#getAcceptCriterion()# | |||
method in the same interface. It is described in | |||
<<advanced.dragndrop.acceptcriteria>> later. | |||
The [methodname]#drop()# method gets a [classname]#DragAndDropEvent# as its | |||
parameters. The event object provides references to two important object: | |||
[classname]#Transferable# and [classname]#TargetDetails#. | |||
A [classname]#Transferable# contains a reference to the object (component or | |||
data item) that is being dragged. A tree or table item is represented as a | |||
[classname]#TreeTransferable# or [classname]#TableTransferable# object, which | |||
carries the item identifier of the dragged tree or table item. These special | |||
transferables, which are bound to some data in a container, are | |||
[classname]#DataBoundTransferable#. Dragged components are represented as | |||
[classname]#WrapperTransferable# objects, as the components are wrapped in a | |||
[classname]#DragAndDropWrapper#. | |||
The [classname]#TargetDetails# object provides information about the exact | |||
location where the transferable object is being dropped. The exact class of the | |||
details object depends on the drop target and you need to cast it to the proper | |||
subclass to get more detailed information. If the target is selection component, | |||
essentially a tree or a table, the [classname]#AbstractSelectTargetDetails# | |||
object tells the item on which the drop is being made. For trees, the | |||
[classname]#TreeTargetDetails# gives some more details. For wrapped components, | |||
the information is provided in a [classname]#WrapperDropDetails# object. In | |||
addition to the target item or component, the details objects provide a __drop | |||
location__. For selection components, the location can be obtained with the | |||
[methodname]#getDropLocation()# and for wrapped components with | |||
[methodname]#verticalDropLocation()# and [methodname]#horizontalDropLocation()#. | |||
The locations are specified as either [classname]#VerticalDropLocation# or | |||
[classname]#HorizontalDropLocation# objects. The drop location objects specify | |||
whether the transferable is being dropped above, below, or directly on (at the | |||
middle of) a component or item. | |||
Dropping on a [classname]#Tree#, [classname]#Table#, and a wrapped component is | |||
explained further in the following sections. | |||
[[advanced.dragndrop.treedrop]] | |||
== Dropping Items On a [classname]#Tree# | |||
You can drag items from, to, or within a [classname]#Tree#. Making tree a drag | |||
source requires simply setting the drag mode with [methodname]#setDragMode()#. | |||
[classname]#Tree# currently supports only one drag mode, | |||
[literal]#++TreeDragMode.NODE++#, which allows dragging single tree nodes. While | |||
dragging, the dragged node is referenced with a [classname]#TreeTransferable# | |||
object, which is a [classname]#DataBoundTransferable#. The tree node is | |||
identified by the item ID of the container item. | |||
When a transferable is dropped on a tree, the drop location is stored in a | |||
[classname]#TreeTargetDetails# object, which identifies the target location by | |||
item ID of the tree node on which the drop is made. You can get the item ID with | |||
[methodname]#getItemIdOver()# method in | |||
[classname]#AbstractSelectTargetDetails#, which the | |||
[classname]#TreeTargetDetails# inherits. A drop can occur directly on or above | |||
or below a node; the exact location is a [classname]#VerticalDropLocation#, | |||
which you can get with the [methodname]#getDropLocation()# method. | |||
In the example below, we have a [classname]#Tree# and we allow reordering the | |||
tree items by drag and drop. | |||
[source, java] | |||
---- | |||
final Tree tree = new Tree("Inventory"); | |||
tree.setContainerDataSource(TreeExample.createTreeContent()); | |||
layout.addComponent(tree); | |||
// Expand all items | |||
for (Iterator<?> it = tree.rootItemIds().iterator(); it.hasNext();) | |||
tree.expandItemsRecursively(it.next()); | |||
// Set the tree in drag source mode | |||
tree.setDragMode(TreeDragMode.NODE); | |||
// Allow the tree to receive drag drops and handle them | |||
tree.setDropHandler(new DropHandler() { | |||
public AcceptCriterion getAcceptCriterion() { | |||
return AcceptAll.get(); | |||
} | |||
public void drop(DragAndDropEvent event) { | |||
// Wrapper for the object that is dragged | |||
Transferable t = event.getTransferable(); | |||
// Make sure the drag source is the same tree | |||
if (t.getSourceComponent() != tree) | |||
return; | |||
TreeTargetDetails target = (TreeTargetDetails) | |||
event.getTargetDetails(); | |||
// Get ids of the dragged item and the target item | |||
Object sourceItemId = t.getData("itemId"); | |||
Object targetItemId = target.getItemIdOver(); | |||
// On which side of the target the item was dropped | |||
VerticalDropLocation location = target.getDropLocation(); | |||
HierarchicalContainer container = (HierarchicalContainer) | |||
tree.getContainerDataSource(); | |||
// Drop right on an item -> make it a child | |||
if (location == VerticalDropLocation.MIDDLE) | |||
tree.setParent(sourceItemId, targetItemId); | |||
// Drop at the top of a subtree -> make it previous | |||
else if (location == VerticalDropLocation.TOP) { | |||
Object parentId = container.getParent(targetItemId); | |||
container.setParent(sourceItemId, parentId); | |||
container.moveAfterSibling(sourceItemId, targetItemId); | |||
container.moveAfterSibling(targetItemId, sourceItemId); | |||
} | |||
// Drop below another item -> make it next | |||
else if (location == VerticalDropLocation.BOTTOM) { | |||
Object parentId = container.getParent(targetItemId); | |||
container.setParent(sourceItemId, parentId); | |||
container.moveAfterSibling(sourceItemId, targetItemId); | |||
} | |||
} | |||
}); | |||
---- | |||
[[advanced.dragndrop.treedrop.criteria]] | |||
=== Accept Criteria for Trees | |||
[classname]#Tree# defines some specialized accept criteria for trees. | |||
[classname]#TargetInSubtree#(client-side):: Accepts if the target item is in the specified sub-tree. The sub-tree is specified by the item ID of the root of the sub-tree in the constructor. The second constructor includes a depth parameter, which specifies how deep from the given root node are drops accepted. Value [literal]#++-1++# means infinite, that is, the entire sub-tree, and is therefore the same as the simpler constructor. | |||
[classname]#TargetItemAllowsChildren#(client-side):: Accepts a drop if the tree has [methodname]#setChildrenAllowed()# enabled for the target item. The criterion does not require parameters, so the class is a singleton and can be acquired with [methodname]#Tree.TargetItemAllowsChildren.get()#. For example, the following composite criterion accepts drops only on nodes that allow children, but between all nodes: | |||
+ | |||
[source, java] | |||
---- | |||
return new Or (Tree.TargetItemAllowsChildren.get(), new Not(VerticalLocationIs.MIDDLE)); | |||
---- | |||
[classname]#TreeDropCriterion#(server-side):: Accepts drops on only some items, which as specified by a set of item IDs. You must extend the abstract class and implement the [methodname]#getAllowedItemIds()# to return the set. While the criterion is server-side, it is lazy-loading, so that the list of accepted target nodes is loaded only once from the server for each drag operation. See <<advanced.dragndrop.acceptcriteria>> for an example. | |||
In addition, the accept criteria defined in [classname]#AbstractSelect# are | |||
available for a [classname]#Tree#, as listed in | |||
<<advanced.dragndrop.acceptcriteria>>. | |||
[[advanced.dragndrop.tabledrop]] | |||
== Dropping Items On a [classname]#Table# | |||
You can drag items from, to, or within a [classname]#Table#. Making table a drag | |||
source requires simply setting the drag mode with [methodname]#setDragMode()#. | |||
[classname]#Table# supports dragging both single rows, with | |||
[literal]#++TableDragMode.ROW++#, and multiple rows, with | |||
[literal]#++TableDragMode.MULTIROW++#. While dragging, the dragged node or nodes | |||
are referenced with a [classname]#TreeTransferable# object, which is a | |||
[classname]#DataBoundTransferable#. Tree nodes are identified by the item IDs of | |||
the container items. | |||
When a transferable is dropped on a table, the drop location is stored in a | |||
[classname]#AbstractSelectTargetDetails# object, which identifies the target row | |||
by its item ID. You can get the item ID with [methodname]#getItemIdOver()# | |||
method. A drop can occur directly on or above or below a row; the exact location | |||
is a [classname]#VerticalDropLocation#, which you can get with the | |||
[methodname]#getDropLocation()# method from the details object. | |||
[[advanced.dragndrop.tabledrop.criteria]] | |||
=== Accept Criteria for Tables | |||
[classname]#Table# defines one specialized accept criterion for tables. | |||
[classname]#TableDropCriterion#(server-side):: Accepts drops only on (or above or below) items that are specified by a set of item IDs. You must extend the abstract class and implement the [methodname]#getAllowedItemIds()# to return the set. While the criterion is server-side, it is lazy-loading, so that the list of accepted target items is loaded only once from the server for each drag operation. | |||
[[advanced.dragndrop.acceptcriteria]] | |||
== Accepting Drops | |||
((("Drag and Drop", "Accept Criteria", id="term.advanced.dragndrop.acceptcriteria", range="startofrange"))) | |||
You can not drop the objects you are dragging around just anywhere. Before a | |||
drop is possible, the specific drop location on which the mouse hovers must be | |||
__accepted__. Hovering a dragged object over an accepted location displays an | |||
__accept indicator__, which allows the user to position the drop properly. As | |||
such checks have to be done all the time when the mouse pointer moves around the | |||
drop targets, it is not feasible to send the accept requests to the server-side, | |||
so drops on a target are normally accepted by a client-side __accept | |||
criterion__. | |||
A drop handler must define the criterion on the objects which it accepts to be | |||
dropped on the target. The criterion needs to be provided in the | |||
[classname]#getAcceptCriterion()# method of the [classname]#DropHandler# | |||
interface. A criterion is represented in an [classname]#AcceptCriterion# object, | |||
which can be a composite of multiple criteria that are evaluated using logical | |||
operations. There are two basic types of criteria: __client-side__ and | |||
__server-side criteria__. The various built-in criteria allow accepting drops | |||
based on the identity of the source and target components, and on the __data | |||
flavor__ of the dragged objects. | |||
To allow dropping any transferable objects, you can return a universal accept | |||
criterion, which you can get with [methodname]#AcceptAll.get()#. | |||
[source, java] | |||
---- | |||
tree.setDropHandler(new DropHandler() { | |||
public AcceptCriterion getAcceptCriterion() { | |||
return AcceptAll.get(); | |||
} | |||
... | |||
---- | |||
[[advanced.dragndrop.acceptcriteria.client-side]] | |||
=== Client-Side Criteria | |||
The __client-side criteria__, which inherit the | |||
[classname]#ClientSideCriterion#, are verified on the client-side, so server | |||
requests are not needed for verifying whether each component on which the mouse | |||
pointer hovers would accept a certain object. | |||
The following client-side criteria are define in | |||
[package]#com.vaadin.event.dd.acceptcriterion#: | |||
[classname]#AcceptAll#:: Accepts all transferables and targets. | |||
[classname]#And#:: Performs the logical AND operation on two or more client-side criteria; accepts the transferable if all the given sub-criteria accept it. | |||
[classname]#ContainsDataFlavour#:: The transferable must contain the defined data flavour. | |||
[classname]#Not#:: Performs the logical NOT operation on a client-side criterion; accepts the transferable if and only if the sub-criterion does not accept it. | |||
[classname]#Or#:: Performs the logical OR operation on two or more client-side criteria; accepts the transferable if any of the given sub-criteria accepts it. | |||
[classname]#SourceIs#:: Accepts all transferables from any of the given source components | |||
[classname]#SourceIsTarget#:: Accepts the transferable only if the source component is the same as the target. This criterion is useful for ensuring that items are dragged only within a tree or a table, and not from outside it. | |||
[classname]#TargetDetailIs#:: Accepts any transferable if the target detail, such as the item of a tree node or table row, is of the given data flavor and has the given value. | |||
In addition, target components such as [classname]#Tree# and [classname]#Table# | |||
define some component-specific client-side accept criteria. See | |||
<<advanced.dragndrop.treedrop>> for more details. | |||
[classname]#AbstractSelect# defines the following criteria for all selection | |||
components, including [classname]#Tree# and [classname]#Table#. | |||
[classname]#AcceptItem#:: Accepts only specific items from a specific selection component. The selection component, which must inherit [classname]#AbstractSelect#, is given as the first parameter for the constructor. It is followed by a list of allowed item identifiers in the drag source. | |||
[classname]#AcceptItem.ALL#:: Accepts all transferables as long as they are items. | |||
[classname]#TargetItemIs#:: Accepts all drops on the specified target items. The constructor requires the target component ( [classname]#AbstractSelect#) followed by a list of allowed item identifiers. | |||
[classname]#VerticalLocationIs.MIDDLE#,[classname]#TOP#, and[classname]#BOTTOM#:: The three static criteria accepts drops on, above, or below an item. For example, you could accept drops only in between items with the following: | |||
[source, java] | |||
---- | |||
public AcceptCriterion getAcceptCriterion() { | |||
return new Not(VerticalLocationIs.MIDDLE); | |||
} | |||
---- | |||
[[advanced.dragndrop.acceptcriteria.server-side]] | |||
=== Server-Side Criteria | |||
The __server-side criteria__ are verified on the server-side with the | |||
[methodname]#accept()# method of the [classname]#ServerSideCriterion# class. | |||
This allows fully programmable logic for accepting drops, but the negative side | |||
is that it causes a very large amount of server requests. A request is made for | |||
every target position on which the pointer hovers. This problem is eased in many | |||
cases by the component-specific lazy loading criteria | |||
[classname]#TableDropCriterion# and [classname]#TreeDropCriterion#. They do the | |||
server visit once for each drag and drop operation and return all accepted rows | |||
or nodes for current [classname]#Transferable# at once. | |||
The [methodname]#accept()# method gets the drag event as a parameter so it can | |||
perform its logic much like in [methodname]#drop()#. | |||
[source, java] | |||
---- | |||
public AcceptCriterion getAcceptCriterion() { | |||
// Server-side accept criterion that allows drops on any other | |||
// location except on nodes that may not have children | |||
ServerSideCriterion criterion = new ServerSideCriterion() { | |||
public boolean accept(DragAndDropEvent dragEvent) { | |||
TreeTargetDetails target = (TreeTargetDetails) | |||
dragEvent.getTargetDetails(); | |||
// The tree item on which the load hovers | |||
Object targetItemId = target.getItemIdOver(); | |||
// On which side of the target the item is hovered | |||
VerticalDropLocation location = target.getDropLocation(); | |||
if (location == VerticalDropLocation.MIDDLE) | |||
if (! tree.areChildrenAllowed(targetItemId)) | |||
return false; // Not accepted | |||
return true; // Accept everything else | |||
} | |||
}; | |||
return criterion; | |||
} | |||
---- | |||
The server-side criteria base class [classname]#ServerSideCriterion# provides a | |||
generic [methodname]#accept()# method. The more specific | |||
[classname]#TableDropCriterion# and [classname]#TreeDropCriterion# are | |||
conveniency extensions that allow definiting allowed drop targets as a set of | |||
items. They also provide some optimization by lazy loading, which reduces server | |||
communications significantly. | |||
[source, java] | |||
---- | |||
public AcceptCriterion getAcceptCriterion() { | |||
// Server-side accept criterion that allows drops on any | |||
// other tree node except on node that may not have children | |||
TreeDropCriterion criterion = new TreeDropCriterion() { | |||
@Override | |||
protected Set<Object> getAllowedItemIds( | |||
DragAndDropEvent dragEvent, Tree tree) { | |||
HashSet<Object> allowed = new HashSet<Object>(); | |||
for (Iterator<Object> i = | |||
tree.getItemIds().iterator(); i.hasNext();) { | |||
Object itemId = i.next(); | |||
if (tree.hasChildren(itemId)) | |||
allowed.add(itemId); | |||
} | |||
return allowed; | |||
} | |||
}; | |||
return criterion; | |||
} | |||
---- | |||
[[advanced.dragndrop.acceptcriteria.indicators]] | |||
=== Accept Indicators | |||
When a dragged object hovers on a drop target, an __accept indicator__ is | |||
displayed to show whether or not the location is accepted. For | |||
[parameter]#MIDDLE# location, the indicator is a box around the target (tree | |||
node, table row, or component). For vertical drop locations, the accepted | |||
locations are shown as horizontal lines, and for horizontal drop locations as | |||
vertical lines. | |||
For [classname]#DragAndDropWrapper# drop targets, you can disable the accept | |||
indicators or __drag hints__ with the [parameter]#no-vertical-drag-hints#, | |||
[parameter]#no-horizontal-drag-hints#, and [parameter]#no-box-drag-hints# | |||
styles. You need to add the styles to the __layout that contains__ the wrapper, | |||
not to the wrapper itself. | |||
[source, java] | |||
---- | |||
// Have a wrapper | |||
DragAndDropWrapper wrapper = new DragAndDropWrapper(c); | |||
layout.addComponent(wrapper); | |||
// Disable the hints | |||
layout.addStyleName("no-vertical-drag-hints"); | |||
layout.addStyleName("no-horizontal-drag-hints"); | |||
layout.addStyleName("no-box-drag-hints"); | |||
---- | |||
(((range="endofrange", startref="term.advanced.dragndrop.acceptcriteria"))) | |||
[[advanced.dragndrop.dragging]] | |||
== Dragging Components | |||
Dragging a component requires wrapping the source component within a | |||
[classname]#DragAndDropWrapper#. You can then allow dragging by putting the | |||
wrapper (and the component) in drag mode with [methodname]#setDragStartMode()#. | |||
The method supports two drag modes: [parameter]#DragStartMode.WRAPPER# and | |||
[parameter]#DragStartMode.COMPONENT#, which defines whether the entire wrapper | |||
is shown as the drag image while dragging or just the wrapped component. | |||
[source, java] | |||
---- | |||
// Have a component to drag | |||
final Button button = new Button("An Absolute Button"); | |||
// Put the component in a D&D wrapper and allow dragging it | |||
final DragAndDropWrapper buttonWrap = new DragAndDropWrapper(button); | |||
buttonWrap.setDragStartMode(DragStartMode.COMPONENT); | |||
// Set the wrapper to wrap tightly around the component | |||
buttonWrap.setSizeUndefined(); | |||
// Add the wrapper, not the component, to the layout | |||
layout.addComponent(buttonWrap, "left: 50px; top: 50px;"); | |||
---- | |||
The default height of [classname]#DragAndDropWrapper# is undefined, but the | |||
default width is 100%. If you want to ensure that the wrapper fits tightly | |||
around the wrapped component, you should call [methodname]#setSizeUndefined()# | |||
for the wrapper. Doing so, you should make sure that the wrapped component does | |||
not have a relative size, which would cause a paradox. | |||
Dragged components are referenced in the [classname]#WrapperTransferable#. You | |||
can get the reference to the dragged component with | |||
[methodname]#getDraggedComponent()#. The method will return [literal]#++null++# | |||
if the transferable is not a component. Also HTML 5 drags (see later) are held | |||
in wrapper transferables. | |||
[[advanced.dragndrop.drop-on-component]] | |||
== Dropping on a Component | |||
Drops on a component are enabled by wrapping the component in a | |||
[classname]#DragAndDropWrapper#. The wrapper is an ordinary component; the | |||
constructor takes the wrapped component as a parameter. You just need to define | |||
the [classname]#DropHandler# for the wrapper with | |||
[methodname]#setDropHandler()#. | |||
In the following example, we allow moving components in an absolute layout. | |||
Details on the drop handler are given later. | |||
[source, java] | |||
---- | |||
// A layout that allows moving its contained components | |||
// by dragging and dropping them | |||
final AbsoluteLayout absLayout = new AbsoluteLayout(); | |||
absLayout.setWidth("100%"); | |||
absLayout.setHeight("400px"); | |||
... put some (wrapped) components in the layout ... | |||
// Wrap the layout to allow handling drops | |||
DragAndDropWrapper layoutWrapper = | |||
new DragAndDropWrapper(absLayout); | |||
// Handle moving components within the AbsoluteLayout | |||
layoutWrapper.setDropHandler(new DropHandler() { | |||
public AcceptCriterion getAcceptCriterion() { | |||
return AcceptAll.get(); | |||
} | |||
public void drop(DragAndDropEvent event) { | |||
... | |||
} | |||
}); | |||
---- | |||
[[advanced.dragndrop.drop-on-component.details]] | |||
=== Target Details for Wrapped Components | |||
The drop handler receives the drop target details in a | |||
[classname]#WrapperTargetDetails# object, which implements the | |||
[classname]#TargetDetails# interface. | |||
[source, java] | |||
---- | |||
public void drop(DragAndDropEvent event) { | |||
WrapperTransferable t = | |||
(WrapperTransferable) event.getTransferable(); | |||
WrapperTargetDetails details = | |||
(WrapperTargetDetails) event.getTargetDetails(); | |||
---- | |||
The wrapper target details include a [classname]#MouseEventDetails# object, | |||
which you can get with [methodname]#getMouseEvent()#. You can use it to get the | |||
mouse coordinates for the position where the mouse button was released and the | |||
drag ended. Similarly, you can find out the drag start position from the | |||
transferable object (if it is a [classname]#WrapperTransferable#) with | |||
[methodname]#getMouseDownEvent()#. | |||
[source, java] | |||
---- | |||
// Calculate the drag coordinate difference | |||
int xChange = details.getMouseEvent().getClientX() | |||
- t.getMouseDownEvent().getClientX(); | |||
int yChange = details.getMouseEvent().getClientY() | |||
- t.getMouseDownEvent().getClientY(); | |||
// Move the component in the absolute layout | |||
ComponentPosition pos = | |||
absLayout.getPosition(t.getSourceComponent()); | |||
pos.setLeftValue(pos.getLeftValue() + xChange); | |||
pos.setTopValue(pos.getTopValue() + yChange); | |||
---- | |||
You can get the absolute x and y coordinates of the target wrapper with | |||
[methodname]#getAbsoluteLeft()# and [methodname]#getAbsoluteTop()#, which allows | |||
you to translate the absolute mouse coordinates to coordinates relative to the | |||
wrapper. Notice that the coordinates are really the position of the wrapper, not | |||
the wrapped component; the wrapper reserves some space for the accept | |||
indicators. | |||
The [methodname]#verticalDropLocation()# and | |||
[methodname]#horizontalDropLocation()# return the more detailed drop location in | |||
the target. | |||
[[advanced.dragndrop.external]] | |||
== Dragging Files from Outside the Browser | |||
The [classname]#DragAndDropWrapper# allows dragging files from outside the | |||
browser and dropping them on a component wrapped in the wrapper. Dropped files | |||
are automatically uploaded to the application and can be acquired from the | |||
wrapper with [methodname]#getFiles()#. The files are represented as | |||
[classname]#Html5File# objects as defined in the inner class. You can define an | |||
upload [classname]#Receiver# to receive the content of a file to an | |||
[classname]#OutputStream#. | |||
Dragging and dropping files to browser is supported in HTML 5 and requires a | |||
compatible browser, such as Mozilla Firefox 3.6 or newer. | |||
(((range="endofrange", startref="term.advanced.dragndrop"))) | |||
@@ -0,0 +1,460 @@ | |||
--- | |||
title: Embedding UIs in Web Pages | |||
order: 2 | |||
layout: page | |||
--- | |||
[[advanced.embedding]] | |||
= Embedding UIs in Web Pages | |||
Many web sites are not all Vaadin, but Vaadin UIs are used only for specific | |||
functionalities. In practice, many web applications are a mixture of dynamic web | |||
pages, such as JSP, and Vaadin UIs embedded in such pages. | |||
Embedding Vaadin UIs in web pages is easy and there are several different ways | |||
to embed them. One is to have a [literal]#++<div>++# placeholder for the UI and | |||
load the Vaadin Client-Side Engine with some simple JavaScript code. Another | |||
method is even easier, which is to simply use the [literal]#++<iframe>++# | |||
element. Both of these methods have advantages and disadvantages. One | |||
disadvantage of the [literal]#++<iframe>++# method is that the size of the | |||
[literal]#++<iframe>++# element is not flexible according to the content while | |||
the [literal]#++<div>++# method allows such flexibility. The following sections | |||
look closer into these two embedding methods. | |||
[[advanced.embedding.div]] | |||
== Embedding Inside a [literal]#++div++# Element | |||
You can embed one or more Vaadin UIs inside a web page with a method that is | |||
equivalent to loading the initial page content from the Vaadin servlet in a | |||
non-embedded UI. Normally, the [classname]#VaadinServlet# generates an initial | |||
page that contains the correct parameters for the specific UI. You can easily | |||
configure it to load multiple Vaadin UIs in the same page. They can have | |||
different widget sets and different themes. | |||
Embedding an UI requires the following basic tasks: | |||
* Set up the page header | |||
* Include a GWT history frame in the page | |||
* Call the [filename]#vaadinBootstrap.js# file | |||
* Define the [literal]#++<div>++# element for the UI | |||
* Configure and initialize the UI | |||
Notice that you can view the loader page for the UI easily by opening the UI in | |||
a web browser and viewing the HTML source code of the page. You could just copy | |||
and paste the embedding code from the page, but some modifications and | |||
additional settings are required, mainly related to the URLs that have to be | |||
made relative to the page instead of the servlet URL. | |||
ifdef::web[] | |||
[[advanced.embedding.div.head]] | |||
=== The Head Matter | |||
The HTML page in which the Vaadin UI is embedded should be a valid HTML 5 | |||
document. The content of the head element is largely up to you. The character | |||
encoding must be UTF-8. Some meta declarations are necessary for compatibility. | |||
You can also set the page favicon in the head element. | |||
[subs="normal"] | |||
---- | |||
<!DOCTYPE html> | |||
<html> | |||
<head> | |||
<meta http-equiv="Content-Type" | |||
content="text/html; charset=UTF-8" /> | |||
<meta http-equiv="X-UA-Compatible" | |||
content="IE=9;chrome=1" /> | |||
<title>[replaceable]#This is my Embedding Page#</title> | |||
<!-- Set up the favicon from the Vaadin theme --> | |||
<link rel="shortcut icon" type="image/vnd.microsoft.icon" | |||
href="/VAADIN/themes/[replaceable]#reindeer#/favicon.ico" /> | |||
<link rel="icon" type="image/vnd.microsoft.icon" | |||
href="/VAADIN/themes/[replaceable]#reindeer#/favicon.ico" /> | |||
</head> | |||
---- | |||
endif::web[] | |||
ifdef::web[] | |||
[[advanced.embedding.div.body]] | |||
=== The Body Matter | |||
The page content must include some Vaadin-related definitions before you can | |||
embed Vaadin UIs in it. | |||
The [filename]#vaadinBootstrap.js# script makes definitions for starting up the | |||
UI. It must be called before initializing the UI. The source path must be | |||
relative to the path of the embedding page. | |||
[subs="normal"] | |||
---- | |||
<body> | |||
<script type="text/javascript" | |||
src="[replaceable]#./#VAADIN/vaadinBootstrap.js"></script> | |||
---- | |||
The bootstrap script is served by the Vaadin servlet from inside the | |||
[filename]#vaadin-server# JAR. | |||
Vaadin, or more precisely GWT, requires an invisible history frame, which is | |||
used for tracking the page or fragment history in the browser. | |||
[source, html] | |||
---- | |||
<iframe tabindex="-1" id="__gwt_historyFrame" | |||
style="position: absolute; width: 0; height: 0; | |||
border: 0; overflow: hidden" | |||
src="javascript:false"></iframe> | |||
---- | |||
endif::web[] | |||
ifdef::web[] | |||
[[advanced.embedding.div.div]] | |||
=== UI Placeholder Element | |||
A Vaadin UI is embedded in a placeholder [literal]#++<div>++# element. It should | |||
have the following features: | |||
* The [literal]#++<div>++# element must have an [literal]#++id++# attribute, which must be a unique ID in the page, normally something that identifies the servlet of the UI uniquely. | |||
* It must have at least the [literal]#++v-app++# style class. | |||
* it should have a nested [literal]#++<div>++# element with [literal]#++v-app-loading++# style class. This is a placeholder for the loading indicator that is displayed while the UI is being loaded. | |||
* It should also contain a [literal]#++<noscript>++# element that is shown if the browser does not support JavaScript or it has been disabled. The content of the element should instruct the use to enable JavaScript in the browser. | |||
The placeholder element can include style settings, typically a width and | |||
height. If the sizes are not defined, the UI will have an undefined size in the | |||
particular dimension, which must be in accordance with the sizing of the UI | |||
components. | |||
For example: | |||
[subs="normal"] | |||
---- | |||
<div style="[replaceable]#width: 300px; border: 2px solid green;#" | |||
id="helloworldui" class="v-app"> | |||
<div class="v-app-loading"></div> | |||
<noscript>[replaceable]#You have to enable javascript in your browser to# | |||
[replaceable]#use an application built with Vaadin.#</noscript> | |||
</div> | |||
---- | |||
endif::web[] | |||
ifdef::web[] | |||
[[advanced.embedding.div.init]] | |||
=== Initializing the UI | |||
The UI is loaded by calling the [literal]#++initApplication()++# method for the | |||
[literal]#++vaadin++# object defined in the bootstrap script. Before calling it, | |||
you should check that the bootstrap script was loaded properly. | |||
[subs="normal"] | |||
---- | |||
<script type="text/javascript">//<![CDATA[ | |||
if (!window.vaadin) | |||
alert("[replaceable]#Failed to load the bootstrap JavaScript:#"+ | |||
"[replaceable]#VAADIN/vaadinBootstrap.js#"); | |||
---- | |||
The [literal]#++initApplication()++# takes two parameters. The first parameter | |||
is the UI identifier, exactly as given as the [literal]#++id++# attribute of the | |||
placeholder element. The second parameter is an associative map that contains | |||
parameters for the UI. | |||
The map must contain the following items: | |||
[parameter]#browserDetailsUrl#:: This should be the URL path (relative to the embedding page) to the Vaadin | |||
servlet of the UI. It is used by the bootstrap to communicate browser details. A | |||
trailing slash may be needed in some cases. | |||
+ | |||
Notice that this parameter is not included in the loader page generated by the | |||
servlet, because in that case, it can default to the current URL. | |||
[parameter]#serviceUrl#:: This is used for server requests after initial loading and should be same as for | |||
[parameter]#browserDetailsUrl#. The two parameters are redundant and either may | |||
be removed in | |||
future.+ | |||
//Bug | |||
#10122 | |||
[parameter]#widgetset#:: This should be the exact class name of the widget set for the UI, that is, without the [filename]#.gwt.xml# file name extension. If the UI has no custom widget set, you can use the [classname]#com.vaadin.DefaultWidgetSet#. | |||
[parameter]#theme#:: Name of the theme, such as one of the built-in themes ( [literal]#++reindeer++#, [literal]#++runo++#, or [literal]#++chameleon++#) or a custom theme. It must exist under the [filename]#VAADIN/themes# folder. | |||
[parameter]#versionInfo#:: This parameter is itself an associative map that can contain two parameters: [parameter]#vaadinVersion# contains the version number of the Vaadin version used by the application. The [parameter]#applicationVersion# parameter contains the version of the particular application. The contained parameters are optional, but the [parameter]#versionInfo# parameter itself is not. | |||
[parameter]#vaadinDir#:: Relative path to the [filename]#VAADIN# directory. It is relative to the URL of the embedding page. | |||
[parameter]#heartbeatInterval#:: The [parameter]#hearbeatInterval# parameter defines the frequency of the keep-alive hearbeat for the UI in seconds, as described in <<dummy/../../../framework/application/application-lifecycle#application.lifecycle.ui-expiration,"UI Expiration">>. | |||
[parameter]#debug#:: The parameter defines whether the debug window, as described in <<dummy/../../../framework/advanced/advanced-debug#advanced.debug,"Debug Mode and Window">>, is enabled. | |||
[parameter]#standalone#:: This parameter should be [parameter]#false# when embedding. The parameter defines whether the UI is rendered on its own in the browser window or in some context. A standalone UI may do things that might interfere with other parts of the page, such as change the page title and request focus when it is loaded. When embedding, the UI is not standalone. | |||
[parameter]#authErrMsg#,[parameter]#comErrMsg#, and[parameter]#sessExpMsg#:: These three parameters define the client-side error messages for authentication error, communication error, and session expiration, respectively. The parameters are associative maps themselves and must contain two key-value pairs: [parameter]#message#, which should contain the error text in HTML, and [parameter]#caption#, which should be the error caption. | |||
For example: | |||
[subs="normal"] | |||
---- | |||
vaadin.initApplication("[replaceable]#helloworldui#", { | |||
"browserDetailsUrl": "[replaceable]#helloworld#/", | |||
"serviceUrl": "[replaceable]#helloworld#/", | |||
"widgetset": "[replaceable]#com.example.MyWidgetSet#", | |||
"theme": "[replaceable]#mytheme#", | |||
"versionInfo": {"vaadinVersion": "[replaceable]#7.0.0#"}, | |||
"vaadinDir": "[replaceable]#VAADIN/#", | |||
"heartbeatInterval": [replaceable]#300#, | |||
"debug": [replaceable]#true#, | |||
"standalone": false, | |||
"authErrMsg": { | |||
"message": "[replaceable]#Take note of any unsaved data, "+ "and <u>click here<\/u> to continue.#", | |||
"caption": "Authentication problem" | |||
}, | |||
"comErrMsg": { | |||
"message": "[replaceable]#Take note of any unsaved data, "+ "and <u>click here<\/u> to continue.#", | |||
"caption": "Communication problem" | |||
}, | |||
"sessExpMsg": { | |||
"message": "[replaceable]#Take note of any unsaved data, "+ "and <u>click here<\/u> to continue.#", | |||
"caption": "Session Expired" | |||
} | |||
});//]]> | |||
</script> | |||
---- | |||
Notice that many of the parameters are normally deployment parameters, specified | |||
in the deployment descriptor, as described in | |||
<<dummy/../../../framework/application/application-environment#application.environment.parameters,"Other | |||
Servlet Configuration Parameters">>. | |||
endif::web[] | |||
ifdef::web[] | |||
[[advanced.embedding.div.summary]] | |||
=== Summary of Div Embedding | |||
Below is a complete example of embedding an UI in a [literal]#++<div>++# | |||
element. | |||
[source, html] | |||
---- | |||
<?xml version="1.0" encoding="UTF-8" ?> | |||
<!DOCTYPE html> | |||
<html> | |||
<head> | |||
<meta http-equiv="Content-Type" | |||
content="text/html; charset=UTF-8" /> | |||
<meta http-equiv="X-UA-Compatible" | |||
content="IE=9;chrome=1" /> | |||
<title>Embedding a Vaadin Application in HTML Page</title> | |||
<!-- Set up the favicon from the Vaadin theme --> | |||
<link rel="shortcut icon" type="image/vnd.microsoft.icon" | |||
href="/VAADIN/themes/reindeer/favicon.ico" /> | |||
<link rel="icon" type="image/vnd.microsoft.icon" | |||
href="/VAADIN/themes/reindeer/favicon.ico" /> | |||
</head> | |||
<body> | |||
<!-- Loads the Vaadin widget set, etc. --> | |||
<script type="text/javascript" | |||
src="VAADIN/vaadinBootstrap.js"></script> | |||
<!-- GWT requires an invisible history frame. It is --> | |||
<!-- needed for page/fragment history in the browser. --> | |||
<iframe tabindex="-1" id="__gwt_historyFrame" | |||
style="position: absolute; width: 0; height: 0; | |||
border: 0; overflow: hidden" | |||
src="javascript:false"></iframe> | |||
<h1>Embedding a Vaadin UI</h1> | |||
<p>This is a static web page that contains an embedded Vaadin | |||
application. It's here:</p> | |||
<!-- So here comes the div element in which the Vaadin --> | |||
<!-- application is embedded. --> | |||
<div style="width: 300px; border: 2px solid green;" | |||
id="helloworld" class="v-app"> | |||
<!-- Optional placeholder for the loading indicator --> | |||
<div class=" v-app-loading"></div> | |||
<!-- Alternative fallback text --> | |||
<noscript>You have to enable javascript in your browser to | |||
use an application built with Vaadin.</noscript> | |||
</div> | |||
<script type="text/javascript">//<![CDATA[ | |||
if (!window.vaadin) | |||
alert("Failed to load the bootstrap JavaScript: "+ | |||
"VAADIN/vaadinBootstrap.js"); | |||
/* The UI Configuration */ | |||
vaadin.initApplication("helloworld", { | |||
"browserDetailsUrl": "helloworld/", | |||
"serviceUrl": "helloworld/", | |||
"widgetset": "com.example.MyWidgetSet", | |||
"theme": "mytheme", | |||
"versionInfo": {"vaadinVersion": "7.0.0"}, | |||
"vaadinDir": "VAADIN/", | |||
"heartbeatInterval": 300, | |||
"debug": true, | |||
"standalone": false, | |||
"authErrMsg": { | |||
"message": "Take note of any unsaved data, "+ | |||
"and <u>click here<\/u> to continue.", | |||
"caption": "Authentication problem" | |||
}, | |||
"comErrMsg": { | |||
"message": "Take note of any unsaved data, "+ | |||
"and <u>click here<\/u> to continue.", | |||
"caption": "Communication problem" | |||
}, | |||
"sessExpMsg": { | |||
"message": "Take note of any unsaved data, "+ | |||
"and <u>click here<\/u> to continue.", | |||
"caption": "Session Expired" | |||
} | |||
});//]] > | |||
</script> | |||
<p>Please view the page source to see how embedding works.</p> | |||
</body> | |||
</html> | |||
---- | |||
endif::web[] | |||
[[advanced.embedding.iframe]] | |||
== Embedding Inside an [literal]#++iframe++# Element | |||
Embedding a Vaadin UI inside an [literal]#++<iframe>++# element is even easier | |||
than the method described above, as it does not require definition of any Vaadin | |||
specific definitions. | |||
You can embed an UI with an element such as the following: | |||
[subs="normal"] | |||
---- | |||
<iframe src="[replaceable]#/myapp/myui#"></iframe> | |||
---- | |||
The [literal]#++<iframe>++# elements have several downsides for embedding. One | |||
is that their size of is not flexible depending on the content of the frame, but | |||
the content must be flexible to accommodate in the frame. You can set the size | |||
of an [literal]#++<iframe>++# element with [literal]#++height++# and | |||
[literal]#++width++# attributes. Other issues arise from themeing and | |||
communication with the frame content and the rest of the page. | |||
Below is a complete example of using the [literal]#++<iframe>++# to embed two | |||
applications in a web page. | |||
[source, html] | |||
---- | |||
<!DOCTYPE html> | |||
<html> | |||
<head> | |||
<title>Embedding in IFrame</title> | |||
</head> | |||
<body style="background: #d0ffd0;"> | |||
<h1>This is a HTML page</h1> | |||
<p>Below are two Vaadin applications embedded inside | |||
a table:</p> | |||
<table align="center" border="3"> | |||
<tr> | |||
<th>The Calculator</th> | |||
<th>The Color Picker</th> | |||
</tr> | |||
<tr valign="top"> | |||
<td> | |||
<iframe src="/vaadin-examples/Calc" height="200" | |||
width="150" frameborder="0"></iframe> | |||
</td> | |||
<td> | |||
<iframe src="/vaadin-examples/colorpicker" | |||
height="330" width="400" | |||
frameborder="0"></iframe> | |||
</td> | |||
</tr> | |||
</table> | |||
</body> | |||
</html> | |||
---- | |||
The page will look as shown in <<figure.embedding.iframe>> below. | |||
[[figure.embedding.iframe]] | |||
.Vaadin Applications Embedded Inside IFrames | |||
image::img/embedding3.png[] | |||
You can embed almost anything in an iframe, which essentially acts as a browser | |||
window. However, this creates various problems. The iframe must have a fixed | |||
size, inheritance of CSS from the embedding page is not possible, and neither is | |||
interaction with JavaScript, which makes mashups impossible, and so on. Even | |||
bookmarking with URI fragments will not work. | |||
Note also that websites can forbid iframe embedding by specifying an | |||
[literal]#++X-Frame-Options: SAMEORIGIN++# header in the HTTP response. | |||
ifdef::web[] | |||
[[advanced.embedding.xs]] | |||
== Cross-Site Embedding with the Vaadin XS Add-on | |||
__The XS add-on is currently not available for Vaadin 7.__ | |||
In the previous sections, we described the two basic methods for embedding | |||
Vaadin applications: in a [literal]#++<div>++# element and in an | |||
[literal]#++<iframe>++#. One problem with div embedding is that it does not work | |||
between different Internet domains, which is a problem if you want to have your | |||
website running in one server and your Vaadin application in another. The | |||
security model in browsers effectively prevents such cross-site embedding of | |||
Ajax applications by enforcing the __same origin policy__ for XmlHttpRequest | |||
calls, even if the server is running in the same domain but different port. | |||
While iframe is more permissive, allowing embedding almost anything in anywhere, | |||
it has many disadvantanges, as described earlier. | |||
The Vaadin XS (Cross-Site) add-on works around the limitation in div embedding | |||
by using JSONP-style communication instead of the standard XmlHttpRequests. | |||
Embedding is done simply with: | |||
[source, html] | |||
---- | |||
<script src="http://demo.vaadin.com/xsembed/getEmbedJs" | |||
type="text/javascript"></script> | |||
---- | |||
This includes an automatically generated embedding script in the page, thereby | |||
making embedding effortless. | |||
This assumes that the main layout of the application has undefined height. If | |||
the height is 100%, you have to wrap it inside an element with a defined height. | |||
For example: | |||
[source, html] | |||
---- | |||
<div style="height: 500px;"> | |||
<script src="http://demo.vaadin.com/xsembed/getEmbedJs" | |||
type="text/javascript"></script> | |||
</div> | |||
---- | |||
It is possible to restrict where the application can be embedded by using a | |||
whitelist. The add-on also encrypts the client-server communication, which is | |||
more important for embedded applications than usual. | |||
You can get the Vaadin XS add-on from Vaadin Directory. It is provided as a Zip | |||
package. Download and extract the installation package to a local folder. | |||
Instructions for installation and further information is given in the | |||
[filename]#README.html# file in the package. | |||
Some restrictions apply. You can have only one embedded application in one page. | |||
Also, some third-party libraries may interfere with the communication. Other | |||
notes are given in the README. | |||
endif::web[] | |||
@@ -0,0 +1,71 @@ | |||
--- | |||
title: Google App Engine Integration | |||
order: 7 | |||
layout: page | |||
--- | |||
[[advanced.gae]] | |||
= Google App Engine Integration | |||
__This section is not yet fully updated to Vaadin 7.__ | |||
Vaadin includes support to run Vaadin applications in the Google App Engine | |||
(GAE). The most essential requirement for GAE is the ability to serialize the | |||
application state. Vaadin applications are serializable through the | |||
[classname]#java.io.Serializable# interface. | |||
To run as a GAE application, an application must use | |||
[classname]#GAEVaadinServlet# instead of [classname]#VaadinServlet#, and of | |||
course implement the [classname]#java.io.Serializable# interface for all | |||
persistent classes. You also need to enable session support in | |||
[filename]#appengine-web.xml# with: | |||
[source, xml] | |||
---- | |||
<sessions-enabled>true</sessions-enabled> | |||
---- | |||
The Vaadin Project wizard can create the configuration files needed for GAE | |||
deployment. See | |||
<<dummy/../../../framework/getting-started/getting-started-first-project#getting-started.first-project.creation,"Creating | |||
the Project">>. When the Google App Engine deployment configuration is selected, | |||
the wizard will create the project structure following the GAE Servlet | |||
convention instead of the regular Servlet convention. The main differences are: | |||
* Source directory: [filename]#src/main/java# | |||
* Output directory: [filename]#war/WEB-INF/classes# | |||
* Content directory: [filename]#war# | |||
== Rules and Limitations | |||
Running Vaadin applications in Google App Engine has the following rules and | |||
limitations: | |||
* Avoid using the session for storage, usual App Engine limitations apply (no | |||
synchronization, that is, it is unreliable). | |||
* Vaadin uses memcache for mutex, the key is of the form | |||
[parameter]#_vmutex<sessionid>#. | |||
* The Vaadin [classname]#WebApplicationContext# class is serialized separately | |||
into memcache and datastore; the memcache key is [parameter]#_vac<sessionid># | |||
and the datastore entity kind is [parameter]#_vac# with identifiers of the type | |||
[parameter]#_vac<sessionid>#. | |||
* __Do not__ update the application state when serving an | |||
[classname]#ConnectorResource# (such as [classname]#ClassResource#. | |||
[methodname]#getStream()#). | |||
* __Avoid__ (or be very careful when) updating application state in a | |||
[classname]#TransactionListener# - it is called even when the application is not | |||
locked and won't be serialized (such as with [classname]#ConnectorResource#), | |||
and changes can therefore be lost (it should be safe to update things that can | |||
be safely discarded later, that is, valid only for the current request). | |||
* The application remains locked during uploads - a progress bar is not possible. | |||
@@ -0,0 +1,234 @@ | |||
--- | |||
title: Accessing Session-Global Data | |||
order: 15 | |||
layout: page | |||
--- | |||
[[advanced.global]] | |||
= Accessing Session-Global Data | |||
__This section is mostly up-to-date with Vaadin 7, but has some information | |||
which still needs to be updated.__ | |||
Applications typically need to access some objects from practically all user | |||
interface code, such as a user object, a business data model, or a database | |||
connection. This data is typically initialized and managed in the UI class of | |||
the application, or in the session or servlet. | |||
For example, you could hold it in the UI class as follows: | |||
[source, java] | |||
---- | |||
class MyUI extends UI { | |||
UserData userData; | |||
public void init() { | |||
userData = new UserData(); | |||
} | |||
public UserData getUserData() { | |||
return userData; | |||
} | |||
} | |||
---- | |||
Vaadin offers two ways to access the UI object: with [methodname]#getUI()# | |||
method from any component and the global [methodname]#UI.getCurrent()# method. | |||
The [methodname]#getUI()# works as follows: | |||
[source, java] | |||
---- | |||
data = ((MyUI)component.getUI()).getUserData(); | |||
---- | |||
This does not, however work in many cases, because it requires that the | |||
components are attached to the UI. That is not the case most of the time when | |||
the UI is still being built, such as in constructors. | |||
[source, java] | |||
---- | |||
class MyComponent extends CustomComponent { | |||
public MyComponent() { | |||
// This fails with NullPointerException | |||
Label label = new Label("Country: " + | |||
getUI().getLocale().getCountry()); | |||
setCompositionRoot(label); | |||
} | |||
} | |||
---- | |||
The global access methods for the currently served servlet, session, and UI | |||
allow an easy way to access the data: | |||
[source, java] | |||
---- | |||
data = ((MyUI) UI.getCurrent()).getUserData(); | |||
---- | |||
[[advanced.global.passing.problem]] | |||
== The Problem | |||
The basic problem in accessing session-global data is that the | |||
[methodname]#getUI()# method works only after the component has been attached to | |||
the application. Before that, it returns [parameter]#null#. This is the case in | |||
constructors of components, such as a [classname]#CustomComponent#: | |||
Using a static variable or a singleton implemented with such to give a global | |||
access to user session data is not possible, because static variables are global | |||
in the entire web application, not just the user session. This can be handy for | |||
communicating data between the concurrent sessions, but creates a problem within | |||
a session. | |||
The data would be shared by all users and be reinitialized every time a new user | |||
opens the application. | |||
[[advanced.global.passing.solutions-overview]] | |||
== Overview of Solutions | |||
To get the application object or any other global data, you have the following | |||
solutions: | |||
* Pass a reference to the global data as a parameter | |||
* Initialize components in [methodname]#attach()# method | |||
* Initialize components in the [methodname]#enter()# method of the navigation view | |||
(if using navigation) | |||
* Store a reference to global data using the __ThreadLocal Pattern__ | |||
Each solution is described in the following sections. | |||
[[advanced.global.passing]] | |||
== Passing References Around | |||
You can pass references to objects as parameters. This is the normal way in | |||
object-oriented programming. | |||
[source, java] | |||
---- | |||
class MyApplication extends Application { | |||
UserData userData; | |||
public void init() { | |||
Window mainWindow = new Window("My Window"); | |||
setMainWindow(mainWindow); | |||
userData = new UserData(); | |||
mainWindow.addComponent(new MyComponent(this)); | |||
} | |||
public UserData getUserData() { | |||
return userData; | |||
} | |||
} | |||
class MyComponent extends CustomComponent { | |||
public MyComponent(MyApplication app) { | |||
Label label = new Label("Name: " + | |||
app.getUserData().getName()); | |||
setCompositionRoot(label); | |||
} | |||
} | |||
---- | |||
If you need the reference in other methods, you either have to pass it again as | |||
a parameter or store it in a member variable. | |||
The problem with this solution is that practically all constructors in the | |||
application need to get a reference to the application object, and passing it | |||
further around in the classes is another hard task. | |||
[[advanced.global.attach]] | |||
== Overriding [methodname]#attach()# | |||
The [methodname]#attach()# method is called when the component is attached to | |||
the UI through containment hierarchy. The [methodname]#getUI()# method always | |||
works. | |||
[source, java] | |||
---- | |||
class MyComponent extends CustomComponent { | |||
public MyComponent() { | |||
// Must set a dummy root in constructor | |||
setCompositionRoot(new Label("")); | |||
} | |||
@Override | |||
public void attach() { | |||
Label label = new Label("Name: " + | |||
((MyUI)component.getUI()) | |||
.getUserData().getName()); | |||
setCompositionRoot(label); | |||
} | |||
} | |||
---- | |||
While this solution works, it is slightly messy. You may need to do some | |||
initialization in the constructor, but any construction requiring the global | |||
data must be done in the [methodname]#attach()# method. Especially, | |||
[classname]#CustomComponent# requires that the | |||
[methodname]#setCompositionRoot()# method is called in the constructor. If you | |||
can't create the actual composition root component in the constructor, you need | |||
to use a temporary dummy root, as is done in the example above. | |||
Using [methodname]#getUI()# also needs casting if you want to use methods | |||
defined in your UI class. | |||
[[advanced.global.threadlocal]] | |||
== ThreadLocal Pattern | |||
((("ThreadLocal pattern", id="term.advanced.global.threadlocal", range="startofrange"))) | |||
Vaadin uses the ThreadLocal pattern for allowing global access to the | |||
[classname]#UI#, and [classname]#Page# objects of the currently processed server | |||
request with a static [methodname]#getCurrent()# method in all the respective | |||
classes. This section explains why the pattern is used in Vaadin and how it | |||
works. You may also need to reimplement the pattern for some purpose. | |||
The ThreadLocal pattern gives a solution to the global access problem by solving | |||
two sub-problems of static variables. | |||
As the first problem, assume that the servlet container processes requests for | |||
many users (sessions) sequentially. If a static variable is set in a request | |||
belonging one user, it could be read or re-set by the next incoming request | |||
belonging to another user. This can be solved by setting the global reference at | |||
the beginning of each HTTP request to point to data of the current user, as | |||
illustrated in Figure <<figure.advanced.global.threadlocal.sequentiality>>. | |||
[[figure.advanced.global.threadlocal.sequentiality]] | |||
.Switching a static (or ThreadLocal) reference during sequential processing of requests | |||
image::img/threadlocal-sequentiality-hi.png[] | |||
The second problem is that servlet containers typically do thread pooling with | |||
multiple worker threads that process requests. Therefore, setting a static | |||
reference would change it in all threads running concurrently, possibly just | |||
when another thread is processing a request for another user. The solution is to | |||
store the reference in a thread-local variable instead of a static. You can do | |||
so by using the [classname]#ThreadLocal# class in Java for the switch reference. | |||
[[figure.advanced.global.threadlocal.concurrency]] | |||
.Switching [classname]#ThreadLocal# references during concurrent processing of requests | |||
image::img/threadlocal-concurrency-hi.png[] | |||
(((range="endofrange", startref="term.advanced.global.threadlocal"))) | |||
@@ -0,0 +1,109 @@ | |||
--- | |||
title: JavaScript Interaction | |||
order: 14 | |||
layout: page | |||
--- | |||
[[advanced.javascript]] | |||
= JavaScript Interaction | |||
Vaadin supports two-direction JavaScript calls from and to the server-side. This | |||
allows interfacing with JavaScript code without writing client-side integration | |||
code. | |||
[[advanced.javascript.calling]] | |||
== Calling JavaScript | |||
You can make JavaScript calls from the server-side with the | |||
[methodname]#execute()# method in the [classname]#JavaScript# class. You can get | |||
a [classname]#JavaScript# instance from the current [classname]#Page# object | |||
with [methodname]#getJavaScript()#.//TODO Check that the API is | |||
so. | |||
[source, java] | |||
---- | |||
// Execute JavaScript in the currently processed page | |||
Page.getCurrent().getJavaScript().execute("alert('Hello')"); | |||
---- | |||
The [classname]#JavaScript# class itself has a static shorthand method | |||
[methodname]#getCurrent()# to get the instance for the currently processed page. | |||
[source, java] | |||
---- | |||
// Shorthand | |||
JavaScript.getCurrent().execute("alert('Hello')"); | |||
---- | |||
The JavaScript is executed after the server request that is currently processed | |||
returns. If multiple JavaScript calls are made during the processing of the | |||
request, they are all executed sequentially after the request is done. Hence, | |||
the JavaScript execution does not pause the execution of the server-side | |||
application and you can not return values from the JavaScript. | |||
[[advanced.javascript.callback]] | |||
== Handling JavaScript Function Callbacks | |||
You can make calls with JavaScript from the client-side to the server-side. This | |||
requires that you register JavaScript call-back methods from the server-side. | |||
You need to implement and register a [classname]#JavaScriptFunction# with | |||
[methodname]#addFunction()# in the current [classname]#JavaScript# object. A | |||
function requires a name, with an optional package path, which are given to the | |||
[methodname]#addFunction()#. You only need to implement the [methodname]#call()# | |||
method to handle calls from the client-side JavaScript. | |||
[source, java] | |||
---- | |||
JavaScript.getCurrent().addFunction("com.example.foo.myfunc", | |||
new JavaScriptFunction() { | |||
@Override | |||
public void call(JsonArray arguments) { | |||
Notification.show("Received call"); | |||
} | |||
}); | |||
Link link = new Link("Send Message", new ExternalResource( | |||
"javascript:com.example.foo.myfunc()")); | |||
---- | |||
Parameters passed to the JavaScript method on the client-side are provided in a | |||
[classname]#JSONArray# passed to the [methodname]#call()# method. The parameter | |||
values can be acquired with the [methodname]#get()# method by the index of the | |||
parameter, or any of the type-casting getters. The getter must match the type of | |||
the passed parameter, or an exception is thrown. | |||
[source, java] | |||
---- | |||
JavaScript.getCurrent().addFunction("com.example.foo.myfunc", | |||
new JavaScriptFunction() { | |||
@Override | |||
public void call(JsonArray arguments) { | |||
try { | |||
String message = arguments.getString(0); | |||
int value = arguments.getInt(1); | |||
Notification.show("Message: " + message + | |||
", value: " + value); | |||
} catch (Exception e) { | |||
Notification.show("Error: " + e.getMessage()); | |||
} | |||
} | |||
}); | |||
Link link = new Link("Send Message", new ExternalResource( | |||
"javascript:com.example.foo.myfunc(prompt('Message'), 42)")); | |||
---- | |||
The function callback mechanism is the same as the RPC mechanism used with | |||
JavaScript component integration, as described in | |||
<<dummy/../../../framework/gwt/gwt-javascript#gwt.javascript.rpc,"RPC from | |||
JavaScript to Server-Side">>. | |||
@@ -0,0 +1,137 @@ | |||
--- | |||
title: Logging | |||
order: 13 | |||
layout: page | |||
--- | |||
[[advanced.logging]] | |||
= Logging | |||
(((, id="term.advanced.logging", range="startofrange"))) | |||
You can do logging in Vaadin application using the standard | |||
[package]#java.util.logging# facilities. Configuring logging is as easy as | |||
putting a file named [filename]#logging.properties# in the default package of | |||
your Vaadin application ( [filename]#src# in an Eclipse project or | |||
[filename]#src/main/java# or [filename]#src/main/resources# in a Maven project). | |||
This file is read by the [classname]#Logger# class when a new instance of it is | |||
initialize. | |||
[[advanced.logging.tomcat]] | |||
== Logging in Apache Tomcat | |||
For logging Vaadin applications deployed in Apache Tomcat, you do not need to do | |||
anything special to log to the same place as Tomcat itself. If you need to write | |||
the Vaadin application related messages elsewhere, just add a custom | |||
[filename]#logging.properties# file to the default package of your Vaadin | |||
application. | |||
If you would like to pipe the log messages through another logging solution, see | |||
<<advanced.logging.slf4j>> below. | |||
[[advanced.logging.liferay]] | |||
== Logging in Liferay | |||
Liferay mutes logging through [package]#java.util.logging# by default. In order | |||
to enable logging, you need to add a [filename]#logging.properties# file of your | |||
own to the default package of your Vaadin application. This file should define | |||
at least one destination where to save the log messages. | |||
You can also log through SLF4J, which is used in and bundled with Liferay. | |||
Follow the instructions in <<advanced.logging.slf4j>>. | |||
[[advanced.logging.slf4j]] | |||
== Piping to Log4j using SLF4J | |||
((("Log4j"))) | |||
((("SLF4J"))) | |||
Piping output from [package]#java.util.logging# to Log4j is easy with SLF4J ( | |||
http://slf4j.org/). The basic way to go about this is to add the SLF4J JAR file | |||
as well as the [filename]#jul-to-slf4j.jar# file, which implements the bridge | |||
from [package]#java.util.logging#, to SLF4J. You will also need to add a third | |||
logging implementation JAR file, that is, [filename]#slf4j-log4j12-x.x.x.jar#, | |||
to log the actual messages using Log4j. For more info on this, please visit the | |||
SLF4J site. | |||
In order to get the [package]#java.util.logging# to SLF4J bridge installed, you | |||
need to add the following snippet of code to your [classname]#UI# class at the | |||
very top://TODO: Sure it's UI class and not the | |||
servlet? | |||
[source, java] | |||
---- | |||
static { | |||
SLF4JBridgeHandler.install(); | |||
} | |||
---- | |||
This will make sure that the bridge handler is installed and working before | |||
Vaadin starts to process any logging calls. | |||
[WARNING] | |||
.Please note! | |||
==== | |||
This can seriously impact on the cost of disabled logging statements (60-fold | |||
increase) and a measurable impact on enabled log statements (20% overall | |||
increase). However, Vaadin doesn't log very much, so the effect on performance | |||
will be negligible. | |||
==== | |||
[[advanced.logging.core]] | |||
== Using Logger | |||
You can do logging with a simple pattern where you register a static logger | |||
instance in each class that needs logging, and use this logger wherever logging | |||
is needed in the class. For example: | |||
[source, java] | |||
---- | |||
public class MyClass { | |||
private final static Logger logger = | |||
Logger.getLogger(MyClass.class.getName()); | |||
public void myMethod() { | |||
try { | |||
// do something that might fail | |||
} catch (Exception e) { | |||
logger.log(Level.SEVERE, "FAILED CATASTROPHICALLY!", e); | |||
} | |||
} | |||
} | |||
---- | |||
((("static"))) | |||
((("memory | |||
leak"))) | |||
((("PermGen"))) | |||
Having a [literal]#++static++# logger instance for each class needing logging | |||
saves a bit of memory and time compared to having a logger for every logging | |||
class instance. However, it could cause the application to leak PermGen memory | |||
with some application servers when redeploying the application. The problem is | |||
that the [classname]#Logger# may maintain hard references to its instances. As | |||
the [classname]#Logger# class is loaded with a classloader shared between | |||
different web applications, references to classes loaded with a per-application | |||
classloader would prevent garbage-collecting the classes after redeploying, | |||
hence leaking memory. As the size of the PermGen memory where class object are | |||
stored is fixed, the leakage will lead to a server crash after many | |||
redeployments. The issue depends on the way how the server manages classloaders, | |||
on the hardness of the back-references, and may also be different between Java 6 | |||
and 7. So, if you experience PermGen issues, or want to play it on the safe | |||
side, you should consider using non-static [classname]#Logger# instances.//As | |||
discussed in Forum thread 1175841 | |||
(24.2.2012). | |||
(((range="endofrange", startref="term.advanced.logging"))) | |||
@@ -0,0 +1,289 @@ | |||
--- | |||
title: Navigating in an Application | |||
order: 9 | |||
layout: page | |||
--- | |||
[[advanced.navigator]] | |||
= Navigating in an Application | |||
Plain Vaadin applications do not have normal web page navigation as they usually | |||
run on a single page, as all Ajax applications do. Quite commonly, however, | |||
applications have different views between which the user should be able to | |||
navigate. The [classname]#Navigator# in Vaadin can be used for most cases of | |||
navigation. Views managed by the navigator automatically get a distinct URI | |||
fragment, which can be used to be able to bookmark the views and their states | |||
and to go back and forward in the browser history. | |||
[[advanced.navigator.navigating]] | |||
== Setting Up for Navigation | |||
The [classname]#Navigator# class manages a collection of __views__ that | |||
implement the [interfacename]#View# interface. The views can be either | |||
registered beforehand or acquired from a __view provider__. When registering, | |||
the views must have a name identifier and be added to a navigator with | |||
[methodname]#addView()#. You can register new views at any point. Once | |||
registered, you can navigate to them with [methodname]#navigateTo()#. | |||
[classname]#Navigator# manages navigation in a component container, which can be | |||
either a [interfacename]#ComponentContainer# (most layouts) or a | |||
[interfacename]#SingleComponentContainer# ( [classname]#UI#, [classname]#Panel#, | |||
or [classname]#Window#). The component container is managed through a | |||
[interfacename]#ViewDisplay#. Two view displays are defined: | |||
[classname]#ComponentContainerViewDisplay# and | |||
[classname]#SingleComponentContainerViewDisplay#, for the respective component | |||
container types. Normally, you can let the navigator create the view display | |||
internally, as we do in the example below, but you can also create it yourself | |||
to customize it. | |||
Let us consider the following UI with two views: start and main. Here, we define | |||
their names with enums to be typesafe. We manage the navigation with the UI | |||
class itself, which is a [interfacename]#SingleComponentContainer#. | |||
[source, java] | |||
---- | |||
public class NavigatorUI extends UI { | |||
Navigator navigator; | |||
protected static final String MAINVIEW = "main"; | |||
@Override | |||
protected void init(VaadinRequest request) { | |||
getPage().setTitle("Navigation Example"); | |||
// Create a navigator to control the views | |||
navigator = new Navigator(this, this); | |||
// Create and register the views | |||
navigator.addView("", new StartView()); | |||
navigator.addView(MAINVIEW, new MainView()); | |||
} | |||
} | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.navigator.basic[on-line example, window="_blank"]. | |||
The [classname]#Navigator# automatically sets the URI fragment of the | |||
application URL. It also registers a [interfacename]#URIFragmentChangedListener# | |||
in the page | |||
ifdef::web[] | |||
(see <<dummy/../../../framework/advanced/advanced-urifu#advanced.urifu,"Managing | |||
URI | |||
Fragments">>) | |||
endif::web[] | |||
to show the view identified by the URI fragment if entered or navigated to in | |||
the browser. This also enables browser navigation history in the application. | |||
[[advanced.navigator.navigating.viewprovider]] | |||
=== View Providers | |||
You can create new views dynamically using a __view provider__ that implements | |||
the [interfacename]#ViewProvider# interface. A provider is registered in | |||
[classname]#Navigator# with [methodname]#addProvider()#. | |||
The [methodname]#ClassBasedViewProvider# is a view provider that can dynamically | |||
create new instances of a specified view class based on the view name. | |||
The [methodname]#StaticViewProvider# returns an existing view instance based on | |||
the view name. The [methodname]#addView()# in [classname]#Navigator# is actually | |||
just a shorthand for creating a static view provider for each registered view. | |||
[[advanced.navigator.navigating.viewchangelistener]] | |||
=== View Change Listeners | |||
You can handle view changes also by implementing a | |||
[interfacename]#ViewChangeListener# and adding it to a [classname]#Navigator#. | |||
When a view change occurs, a listener receives a [classname]#ViewChangeEvent# | |||
object, which has references to the old and the activated view, the name of the | |||
activated view, as well as the fragment parameters. | |||
[[advanced.navigator.view]] | |||
== Implementing a View | |||
Views can be any objects that implement the [interfacename]#View# interface. | |||
When the [methodname]#navigateTo()# is called for the navigator, or the | |||
application is opened with the URI fragment associated with the view, the | |||
navigator switches to the view and calls its [methodname]#enter()# method. | |||
To continue with the example, consider the following simple start view that just | |||
lets the user to navigate to the main view. It only pops up a notification when | |||
the user navigates to it and displays the navigation button. | |||
[source, java] | |||
---- | |||
/** A start view for navigating to the main view */ | |||
public class StartView extends VerticalLayout implements View { | |||
public StartView() { | |||
setSizeFull(); | |||
Button button = new Button("Go to Main View", | |||
new Button.ClickListener() { | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
navigator.navigateTo(MAINVIEW); | |||
} | |||
}); | |||
addComponent(button); | |||
setComponentAlignment(button, Alignment.MIDDLE_CENTER); | |||
} | |||
@Override | |||
public void enter(ViewChangeEvent event) { | |||
Notification.show("Welcome to the Animal Farm"); | |||
} | |||
} | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.navigator.basic[on-line example, window="_blank"]. | |||
You can initialize the view content in the constructor, as was done in the | |||
example above, or in the [methodname]#enter()# method. The advantage with the | |||
latter method is that the view is attached to the view container as well as to | |||
the UI at that time, which is not the case in the constructor. | |||
[[advanced.navigator.urifragment]] | |||
== Handling URI Fragment Path | |||
URI fragment part of a URL is the part after a hash [literal]#++#++# character. | |||
Is used for within-UI URLs, because it is the only part of the URL that can be | |||
changed with JavaScript from within a page without reloading the page. The URLs | |||
with URI fragments can be used for hyperlinking and bookmarking, as well as | |||
browser history, just like any other URLs. In addition, an exclamation mark | |||
[literal]#++#!++# after the hash marks that the page is a stateful AJAX page, | |||
which can be crawled by search engines. Crawling requires that the application | |||
also responds to special URLs to get the searchable content. URI fragments are | |||
managed by [classname]#Page#, which provides a low-level API. | |||
URI fragments can be used with [classname]#Navigator# in two ways: for | |||
navigating to a view and to a state within a view. The URI fragment accepted by | |||
[methodname]#navigateTo()# can have the view name at the root, followed by | |||
fragment parameters after a slash (" [literal]#++/++#"). These parameters are | |||
passed to the [methodname]#enter()# method in the [interfacename]#View#. | |||
In the following example, we implement within-view navigation. Here we use the | |||
following declarative design for the view: | |||
[source, html] | |||
---- | |||
<v-vertical-layout size-full> | |||
<v-horizontal-layout size-full :expand> | |||
<v-panel caption="List of Equals" height-full width-auto> | |||
<v-vertical-layout _id="menuContent" width-auto margin/> | |||
</v-panel> | |||
<v-panel _id="equalPanel" caption="An Equal" size-full :expand/> | |||
</v-horizontal-layout> | |||
<v-button _id="logout">Logout</v-button> | |||
</v-vertical-layout> | |||
---- | |||
The view's logic code would be as follows: | |||
[source, java] | |||
---- | |||
/** Main view with a menu (with declarative layout design) */ | |||
@DesignRoot | |||
public class MainView extends VerticalLayout implements View { | |||
// Menu navigation button listener | |||
class ButtonListener implements Button.ClickListener { | |||
String menuitem; | |||
public ButtonListener(String menuitem) { | |||
this.menuitem = menuitem; | |||
} | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
// Navigate to a specific state | |||
navigator.navigateTo(MAINVIEW + "/" + menuitem); | |||
} | |||
} | |||
VerticalLayout menuContent; | |||
Panel equalPanel; | |||
Button logout; | |||
public MainView() { | |||
Design.read(this); | |||
menuContent.addComponent(new Button("Pig", | |||
new ButtonListener("pig"))); | |||
menuContent.addComponent(new Button("Cat", | |||
new ButtonListener("cat"))); | |||
menuContent.addComponent(new Button("Dog", | |||
new ButtonListener("dog"))); | |||
menuContent.addComponent(new Button("Reindeer", | |||
new ButtonListener("reindeer"))); | |||
menuContent.addComponent(new Button("Penguin", | |||
new ButtonListener("penguin"))); | |||
menuContent.addComponent(new Button("Sheep", | |||
new ButtonListener("sheep"))); | |||
// Allow going back to the start | |||
logout.addClickListener(event -> // Java 8 | |||
navigator.navigateTo("")); | |||
} | |||
@DesignRoot | |||
class AnimalViewer extends VerticalLayout { | |||
Label watching; | |||
Embedded pic; | |||
Label back; | |||
public AnimalViewer(String animal) { | |||
Design.read(this); | |||
watching.setValue("You are currently watching a " + | |||
animal); | |||
pic.setSource(new ThemeResource( | |||
"img/" + animal + "-128px.png")); | |||
back.setValue("and " + animal + | |||
" is watching you back"); | |||
} | |||
} | |||
@Override | |||
public void enter(ViewChangeEvent event) { | |||
if (event.getParameters() == null | |||
|| event.getParameters().isEmpty()) { | |||
equalPanel.setContent( | |||
new Label("Nothing to see here, " + | |||
"just pass along.")); | |||
return; | |||
} else | |||
equalPanel.setContent(new AnimalViewer( | |||
event.getParameters())); | |||
} | |||
} | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.navigator.basic[on-line example, window="_blank"]. | |||
The animal sub-view would have the following declarative design: | |||
[source, html] | |||
---- | |||
<v-vertical-layout size-full> | |||
<v-label _id="watching" size-auto :middle :center/> | |||
<v-embedded _id="pic" :middle :center :expand/> | |||
<v-label _id="back" size-auto :middle :center/> | |||
</v-vertical-layout> | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.navigator.basic[on-line example, window="_blank"]. | |||
The main view is shown in <<figure.advanced.navigator.mainview>>. At this point, | |||
the URL would be [literal]#++http://localhost:8080/myapp#!main/reindeer++#. | |||
[[figure.advanced.navigator.mainview]] | |||
.Navigator Main View | |||
image::img/navigator-mainview.png[] | |||
@@ -0,0 +1,181 @@ | |||
--- | |||
title: Printing | |||
order: 6 | |||
layout: page | |||
--- | |||
[[advanced.printing]] | |||
= Printing | |||
((("printing", id="term.advanced.printing", range="startofrange"))) | |||
Vaadin does not have any special support for printing. There are two basic ways | |||
to print - in a printer controlled by the application server or by the user from | |||
the web browser. Printing in the application server is largely independent of | |||
the UI, you just have to take care that printing commands do not block server | |||
requests, possibly by running the print commands in another thread. | |||
((("[methodname]#print()#", id="term.advanced.printing.print", | |||
range="startofrange"))) | |||
((("JavaScript", "[methodname]#print()#", | |||
id="term.advanced.printing.JavaScript.print", | |||
range="startofrange"))) | |||
For client-side printing, most browsers support printing the web page. You can | |||
either print the current or a special print page that you open. The page can be | |||
styled for printing with special CSS rules, and you can hide unwanted elements. | |||
You can also print other than Vaadin UI content, such as HTML or PDF. | |||
[[advanced.printing.browserwindow]] | |||
== Printing the Browser Window | |||
Vaadin does not have special support for launching the printing in browser, but | |||
you can easily use the JavaScript [methodname]#print()# method that opens the | |||
print window of the browser. | |||
((("JavaScript", "[methodname]#execute()#"))) | |||
[source, java] | |||
---- | |||
Button print = new Button("Print This Page"); | |||
print.addClickListener(new Button.ClickListener() { | |||
public void buttonClick(ClickEvent event) { | |||
// Print the current page | |||
JavaScript.getCurrent().execute("print();"); | |||
} | |||
}); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.printing.this[on-line example, window="_blank"]. | |||
The button in the above example would print the current page, including the | |||
button itself. You can hide such elements in CSS, as well as otherwise style the | |||
page for printing. Style definitions for printing are defined inside a | |||
[literal]#++@media print {}++# block in CSS. | |||
[[advanced.printing.opening]] | |||
== Opening a Print Window | |||
You can open a browser window with a special UI for print content and | |||
automatically launch printing the content. | |||
[source, java] | |||
---- | |||
public static class PrintUI extends UI { | |||
@Override | |||
protected void init(VaadinRequest request) { | |||
// Have some content to print | |||
setContent(new Label( | |||
"<h1>Here's some dynamic content</h1>\n" + | |||
"<p>This is to be printed.</p>", | |||
ContentMode.HTML)); | |||
// Print automatically when the window opens | |||
JavaScript.getCurrent().execute( | |||
"setTimeout(function() {" + | |||
" print(); self.close();}, 0);"); | |||
} | |||
} | |||
... | |||
// Create an opener extension | |||
BrowserWindowOpener opener = | |||
new BrowserWindowOpener(PrintUI.class); | |||
opener.setFeatures("height=200,width=400,resizable"); | |||
// A button to open the printer-friendly page. | |||
Button print = new Button("Click to Print"); | |||
opener.extend(print); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.printing.open[on-line example, window="_blank"]. | |||
How the browser opens the window, as an actual (popup) window or just a tab, | |||
depends on the browser. After printing, we automatically close the window with | |||
JavaScript [methodname]#close()# call. | |||
(((range="endofrange", startref="term.advanced.printing.print"))) | |||
(((range="endofrange", startref="term.advanced.printing.JavaScript.print"))) | |||
[[advanced.printing.pdf]] | |||
== Printing PDF | |||
((("PDF"))) | |||
To print content as PDF, you need to provide the downloadable content as a | |||
static or a dynamic resource, such as a [classname]#StreamResource#. | |||
You can let the user open the resource using a [classname]#Link# component, or | |||
some other component with a [classname]#PopupWindowOpener# extension. When such | |||
a link or opener is clicked, the browser opens the PDF in the browser, in an | |||
external viewer (such as Adobe Reader), or lets the user save the document. | |||
It is crucial to notice that clicking a [classname]#Link# or a | |||
[classname]#PopupWindowOpener# is a client-side operation. If you get the | |||
content of the dynamic PDF from the same UI state, you can not have the link or | |||
opener enabled, as then clicking it would not get the current UI content. | |||
Instead, you have to create the resource object before the link or opener are | |||
clicked. This usually requires a two-step operation, or having the print | |||
operation available in another view. | |||
[source, java] | |||
---- | |||
// A user interface for a (trivial) data model from which | |||
// the PDF is generated. | |||
final TextField name = new TextField("Name"); | |||
name.setValue("Slartibartfast"); | |||
// This has to be clicked first to create the stream resource | |||
final Button ok = new Button("OK"); | |||
// This actually opens the stream resource | |||
final Button print = new Button("Open PDF"); | |||
print.setEnabled(false); | |||
ok.addClickListener(new ClickListener() { | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
// Create the PDF source and pass the data model to it | |||
StreamSource source = | |||
new MyPdfSource((String) name.getValue()); | |||
// Create the stream resource and give it a file name | |||
String filename = "pdf_printing_example.pdf"; | |||
StreamResource resource = | |||
new StreamResource(source, filename); | |||
// These settings are not usually necessary. MIME type | |||
// is detected automatically from the file name, but | |||
// setting it explicitly may be necessary if the file | |||
// suffix is not ".pdf". | |||
resource.setMIMEType("application/pdf"); | |||
resource.getStream().setParameter( | |||
"Content-Disposition", | |||
"attachment; filename="+filename); | |||
// Extend the print button with an opener | |||
// for the PDF resource | |||
BrowserWindowOpener opener = | |||
new BrowserWindowOpener(resource); | |||
opener.extend(print); | |||
name.setEnabled(false); | |||
ok.setEnabled(false); | |||
print.setEnabled(true); | |||
} | |||
}); | |||
layout.addComponent(name); | |||
layout.addComponent(ok); | |||
layout.addComponent(print); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.printing.pdfgeneration[on-line example, window="_blank"]. | |||
(((range="endofrange", startref="term.advanced.printing"))) | |||
@@ -0,0 +1,417 @@ | |||
--- | |||
title: Server Push | |||
order: 16 | |||
layout: page | |||
--- | |||
[[advanced.push]] | |||
= Server Push | |||
When you need to update a UI from another UI, possibly of another user, or from | |||
a background thread running in the server, you usually want to have the update | |||
show immediately, not when the browser happens to make the next server request. | |||
For this purpose, you can use __server push__ that sends the data to the browser | |||
immediately. Push is based on a client-server connection, usually a WebSocket | |||
connection, that the client establishes and the server can then use to send | |||
updates to the client. | |||
The server-client communication is done by default with a WebSocket connection | |||
if the browser and the server support it. If not, Vaadin will fall back to a | |||
method supported by the browser. Vaadin Push uses a custom build of the | |||
link:https://github.com/Atmosphere/atmosphere[Atmosphere framework] for | |||
client-server communication. | |||
[[advanced.push.installation]] | |||
== Installing the Push Support | |||
The server push support in Vaadin requires the separate Vaadin Push library. It | |||
is included in the installation package as [filename]#vaadin-push.jar#. | |||
[[advanced.push.installation.ivy]] | |||
=== Retrieving with Ivy | |||
With Ivy, you can get it with the following declaration in the | |||
[filename]#ivy.xml#: | |||
[source, xml] | |||
---- | |||
<dependency org="com.vaadin" name="vaadin-push" | |||
rev="&vaadin.version;" conf="default->default"/> | |||
---- | |||
In some servers, you may need to exlude a [literal]#++sl4j++# dependency as | |||
follows: | |||
[source, xml] | |||
---- | |||
<dependency org="com.vaadin" name="vaadin-push" | |||
rev="&vaadin.version;" conf="default->default"> | |||
<exclude org="org.slf4j" name="slf4j-api"/> | |||
</dependency> | |||
---- | |||
Pay note that the Atmosphere library is a bundle, so if you retrieve the | |||
libraries with Ant, for example, you need to retrieve | |||
[literal]#++type="jar,bundle"++#. | |||
[[advanced.push.installation.maven]] | |||
=== Retrieving with Maven | |||
In Maven, you can get the push library with the following dependency in the POM: | |||
[source, xml] | |||
---- | |||
<dependency> | |||
<groupId>com.vaadin</groupId> | |||
<artifactId>vaadin-push</artifactId> | |||
<version>${vaadin.version}</version> | |||
</dependency> | |||
---- | |||
[[advanced.push.enabling]] | |||
== Enabling Push for a UI | |||
To enable server push, you need to define the push mode either in the deployment | |||
descriptor or with the [classname]#@Push# annotation for the UI. | |||
[[advanced.push.enabling.pushmode]] | |||
=== Push Modes | |||
You can use server push in two modes: [literal]#++automatic++# and | |||
[literal]#++manual++#. The automatic mode pushes changes to the browser | |||
automatically after access() finishes. With the manual mode, you can do the push | |||
explicitly with [methodname]#push()#, which allows more flexibility. | |||
[[advanced.push.enabling.pushmode]] | |||
=== The [classname]#@Push# annotation | |||
You can enable server push for a UI with the [classname]#@Push# annotation as | |||
follows. It defaults to automatic mode ( [parameter]#PushMode.AUTOMATIC#). | |||
[source, java] | |||
---- | |||
@Push | |||
public class PushyUI extends UI { | |||
---- | |||
To enable manual mode, you need to give the [parameter]#PushMode.MANUAL# | |||
parameter as follows: | |||
[source, java] | |||
---- | |||
@Push(PushMode.MANUAL) | |||
public class PushyUI extends UI { | |||
---- | |||
[[advanced.push.enabling.servlet]] | |||
=== Servlet Configuration | |||
You can enable the server push and define the push mode also in the servlet | |||
configuration with the [parameter]#pushmode# parameter for the servlet in the | |||
[filename]#web.xml# deployment descriptor. If you use a Servlet 3.0 compatible | |||
server, you also want to enable asynchronous processing with the | |||
[literal]#++async-supported++# parameter. Note the use of Servlet 3.0 schema in | |||
the deployment descriptor. | |||
[subs="normal"] | |||
---- | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<web-app | |||
id="WebApp_ID" version="**3.0**" | |||
xmlns="**http://java.sun.com/xml/ns/javaee**" | |||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
xsi:schemaLocation="**http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd**"> | |||
<servlet> | |||
<servlet-name>Pushy UI</servlet-name> | |||
<servlet-class> | |||
com.vaadin.server.VaadinServlet</servlet-class> | |||
<init-param> | |||
<param-name>UI</param-name> | |||
<param-value>**com.example.my.PushyUI**</param-value> | |||
</init-param> | |||
<!-- Enable server push --> | |||
<init-param> | |||
<param-name>pushmode</param-name> | |||
<param-value>**automatic**</param-value> | |||
</init-param> | |||
<async-supported>**true**</async-supported> | |||
</servlet> | |||
</web-app> | |||
---- | |||
[[advanced.push.running]] | |||
== Accessing UI from Another Thread | |||
Making changes to a [classname]#UI# object from another thread and pushing them | |||
to the browser requires locking the user session when accessing the UI. | |||
Otherwise, the UI update done from another thread could conflict with a regular | |||
event-driven update and cause either data corruption or deadlocks. Because of | |||
this, you may only access an UI using the [methodname]#access()# method, which | |||
locks the session to prevent conflicts. It takes a [interfacename]#Runnable# | |||
which it executes as its parameter. | |||
For example: | |||
[source, java] | |||
---- | |||
ui.access(new Runnable() { | |||
@Override | |||
public void run() { | |||
series.add(new DataSeriesItem(x, y)); | |||
} | |||
}); | |||
---- | |||
In Java 8, where a parameterless lambda expression creates a runnable, you could | |||
simply write: | |||
[source, java] | |||
---- | |||
ui.access(() -> | |||
series.add(new DataSeriesItem(x, y))); | |||
---- | |||
If the push mode is [literal]#++manual++#, you need to push the pending UI | |||
changes to the browser explicitly with the [methodname]#push()# method. | |||
[source, java] | |||
---- | |||
ui.access(new Runnable() { | |||
@Override | |||
public void run() { | |||
series.add(new DataSeriesItem(x, y)); | |||
ui.push(); | |||
} | |||
}); | |||
---- | |||
Below is a complete example of a case where we make UI changes from another | |||
thread. | |||
[source, java] | |||
---- | |||
public class PushyUI extends UI { | |||
Chart chart = new Chart(ChartType.AREASPLINE); | |||
DataSeries series = new DataSeries(); | |||
@Override | |||
protected void init(VaadinRequest request) { | |||
chart.setSizeFull(); | |||
setContent(chart); | |||
// Prepare the data display | |||
Configuration conf = chart.getConfiguration(); | |||
conf.setTitle("Hot New Data"); | |||
conf.setSeries(series); | |||
// Start the data feed thread | |||
new FeederThread().start(); | |||
} | |||
class FeederThread extends Thread { | |||
int count = 0; | |||
@Override | |||
public void run() { | |||
try { | |||
// Update the data for a while | |||
while (count < 100) { | |||
Thread.sleep(1000); | |||
access(new Runnable() { | |||
@Override | |||
public void run() { | |||
double y = Math.random(); | |||
series.add( | |||
new DataSeriesItem(count++, y), | |||
true, count > 10); | |||
} | |||
}); | |||
} | |||
// Inform that we have stopped running | |||
access(new Runnable() { | |||
@Override | |||
public void run() { | |||
setContent(new Label("Done!")); | |||
} | |||
}); | |||
} catch (InterruptedException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
} | |||
} | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.push.simple[on-line example, window="_blank"]. | |||
When sharing data between UIs or user sessions, you need to consider the | |||
message-passing mechanism more carefully, as explained next. | |||
[[advanced.push.pusharound]] | |||
== Broadcasting to Other Users | |||
Broadcasting messages to be pushed to UIs in other user sessions requires having | |||
some sort of message-passing mechanism that sends the messages to all UIs that | |||
register as recipients. As processing server requests for different UIs is done | |||
concurrently in different threads of the application server, locking the threads | |||
properly is very important to avoid deadlock situations. | |||
[[advanced.push.pusharound.broadcaster]] | |||
=== The Broadcaster | |||
The standard pattern for sending messages to other users is to use a | |||
__broadcaster__ singleton that registers the UIs and broadcasts messages to them | |||
safely. To avoid deadlocks, it is recommended that the messages should be sent | |||
through a message queue in a separate thread. Using a Java | |||
[classname]#ExecutorService# running in a single thread is usually the easiest | |||
and safest way. | |||
[source, java] | |||
---- | |||
public class Broadcaster implements Serializable { | |||
static ExecutorService executorService = | |||
Executors.newSingleThreadExecutor(); | |||
public interface BroadcastListener { | |||
void receiveBroadcast(String message); | |||
} | |||
private static LinkedList<BroadcastListener> listeners = | |||
new LinkedList<BroadcastListener>(); | |||
public static synchronized void register( | |||
BroadcastListener listener) { | |||
listeners.add(listener); | |||
} | |||
public static synchronized void unregister( | |||
BroadcastListener listener) { | |||
listeners.remove(listener); | |||
} | |||
public static synchronized void broadcast( | |||
final String message) { | |||
for (final BroadcastListener listener: listeners) | |||
executorService.execute(new Runnable() { | |||
@Override | |||
public void run() { | |||
listener.receiveBroadcast(message); | |||
} | |||
}); | |||
} | |||
} | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.push.pusharound[on-line example, window="_blank"]. | |||
In Java 8, you could use lambda expressions for the listeners instead of the | |||
interface, and a parameterless expression to create the runnable: | |||
[source, java] | |||
---- | |||
for (final Consumer<String> listener: listeners) | |||
executorService.execute(() -> | |||
listener.accept(message)); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.push.pusharound[on-line example, window="_blank"]. | |||
[[advanced.push.pusharound.receiving]] | |||
=== Receiving Broadcasts | |||
The receivers need to implement the receiver interface and register to the | |||
broadcaster to receive the broadcasts. A listener should be unregistered when | |||
the UI expires. When updating the UI in a receiver, it should be done safely as | |||
described earlier, by executing the update through the [methodname]#access()# | |||
method of the UI. | |||
[source, java] | |||
---- | |||
@Push | |||
public class PushAroundUI extends UI | |||
implements Broadcaster.BroadcastListener { | |||
VerticalLayout messages = new VerticalLayout(); | |||
@Override | |||
protected void init(VaadinRequest request) { | |||
... build the UI ... | |||
// Register to receive broadcasts | |||
Broadcaster.register(this); | |||
} | |||
// Must also unregister when the UI expires | |||
@Override | |||
public void detach() { | |||
Broadcaster.unregister(this); | |||
super.detach(); | |||
} | |||
@Override | |||
public void receiveBroadcast(final String message) { | |||
// Must lock the session to execute logic safely | |||
access(new Runnable() { | |||
@Override | |||
public void run() { | |||
// Show it somehow | |||
messages.addComponent(new Label(message)); | |||
} | |||
}); | |||
} | |||
} | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.push.pusharound[on-line example, window="_blank"]. | |||
[[advanced.push.pusharound.sending]] | |||
=== Sending Broadcasts | |||
To send broadcasts with a broadcaster singleton, such as the one described | |||
above, you would only need to call the [methodname]#broadcast()# method as | |||
follows. | |||
[source, java] | |||
---- | |||
final TextField input = new TextField(); | |||
sendBar.addComponent(input); | |||
Button send = new Button("Send"); | |||
send.addClickListener(new ClickListener() { | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
// Broadcast the message | |||
Broadcaster.broadcast(input.getValue()); | |||
input.setValue(""); | |||
} | |||
}); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.push.pusharound[on-line example, window="_blank"]. | |||
@@ -0,0 +1,96 @@ | |||
--- | |||
title: Request Handlers | |||
order: 4 | |||
layout: page | |||
--- | |||
[[advanced.requesthandler]] | |||
= Request Handlers | |||
Request handlers are useful for catching request parameters or generating | |||
dynamic content, such as HTML, images, PDF, or other content. You can provide | |||
HTTP content also with stream resources, as described in | |||
<<dummy/../../../framework/application/application-resources#application.resources.stream,"Stream | |||
Resources">>. The stream resources, however, are only usable from within a | |||
Vaadin application, such as in an [classname]#Image# component. Request handlers | |||
allow responding to HTTP requests made with the application URL, including GET | |||
or POST parameters. You could also use a separate servlet to generate dynamic | |||
content, but a request handler is associated with the user session and it can | |||
easily access data associated with the session and the user. | |||
To handle requests, you need to implement the [interfacename]#RequestHandler# | |||
interface. The [methodname]#handleRequest()# method gets the session, request, | |||
and response objects as parameters. | |||
If the handler writes a response, it must return [literal]#++true++#. This stops | |||
running other possible request handlers. Otherwise, it should return | |||
[literal]#++false++# so that another handler could return a response. | |||
Eventually, if no other handler writes a response, a UI will be created and | |||
initialized. | |||
In the following example, we catch requests for a sub-path in the URL for the | |||
servlet and write a plain text response. The servlet path consists of the | |||
context path and the servlet (sub-)path. Any additional path is passed to the | |||
request handler in the [parameter]#pathInfo# of the request. For example, if the | |||
full path is [filename]#/myapp/myui/rhexample#, the path info will be | |||
[filename]#/rhexample#. Also, request parameters are available. | |||
[source, java] | |||
---- | |||
// A request handler for generating some content | |||
VaadinSession.getCurrent().addRequestHandler( | |||
new RequestHandler() { | |||
@Override | |||
public boolean handleRequest(VaadinSession session, | |||
VaadinRequest request, | |||
VaadinResponse response) | |||
throws IOException { | |||
if ("/rhexample".equals(request.getPathInfo())) { | |||
// Generate a plain text document | |||
response.setContentType("text/plain"); | |||
response.getWriter().append( | |||
"Here's some dynamically generated content.\n"); | |||
response.getWriter().format(Locale.ENGLISH, | |||
"Time: %Tc\n", new Date()); | |||
// Use shared session data | |||
response.getWriter().format("Session data: %s\n", | |||
session.getAttribute("mydata")); | |||
return true; // We wrote a response | |||
} else | |||
return false; // No response was written | |||
} | |||
}); | |||
---- | |||
A request handler can be used by embedding it in a page or opening a new page | |||
with a link or a button. In the following example, we pass some data to the | |||
handler through a session attribute. | |||
[source, java] | |||
---- | |||
// Input some shared data in the session | |||
TextField dataInput = new TextField("Some data"); | |||
dataInput.addValueChangeListener(event -> | |||
VaadinSession.getCurrent().setAttribute("mydata", | |||
event.getProperty().getValue())); | |||
dataInput.setValue("Here's some"); | |||
// Determine the base path for the servlet | |||
String servletPath = VaadinServlet.getCurrent() | |||
.getServletContext().getContextPath() | |||
+ "/book"; // Servlet | |||
// Display the page in a pop-up window | |||
Link open = new Link("Click to Show the Page", | |||
new ExternalResource(servletPath + "/rhexample"), | |||
"_blank", 500, 350, BorderStyle.DEFAULT); | |||
layout.addComponents(dataInput, open); | |||
---- | |||
@@ -0,0 +1,56 @@ | |||
--- | |||
title: Common Security Issues | |||
order: 8 | |||
layout: page | |||
--- | |||
[[advanced.security]] | |||
= Common Security Issues | |||
[[advanced.security.sanitizing]] | |||
== Sanitizing User Input to Prevent Cross-Site Scripting | |||
You can put raw HTML content in many components, such as the [classname]#Label# | |||
and [classname]#CustomLayout#, as well as in tooltips and notifications. In such | |||
cases, you should make sure that if the content has any possibility to come from | |||
user input, you must make sure that the content is safe before displaying it. | |||
Otherwise, a malicious user can easily make a | |||
link:http://en.wikipedia.org/wiki/Cross-site_scripting[cross-site scripting | |||
attack] by injecting offensive JavaScript code in such components. See other | |||
sources for more information about cross-site scripting. | |||
Offensive code can easily be injected with [literal]#++<script>++# markup or in | |||
tag attributes as events, such as | |||
[parameter]#onLoad#.//// | |||
TODO Consider an example, Alice, Bob, | |||
etc. | |||
//// | |||
Cross-site scripting vulnerabilities are browser dependent, depending on the | |||
situations in which different browsers execute scripting markup. | |||
Therefore, if the content created by one user is shown to other users, the | |||
content must be sanitized. There is no generic way to sanitize user input, as | |||
different applications can allow different kinds of input. Pruning (X)HTML tags | |||
out is somewhat simple, but some applications may need to allow (X)HTML content. | |||
It is therefore the responsibility of the application to sanitize the input. | |||
Character encoding can make sanitization more difficult, as offensive tags can | |||
be encoded so that they are not recognized by a sanitizer. This can be done, for | |||
example, with HTML character entities and with variable-width encodings such as | |||
UTF-8 or various CJK encodings, by abusing multiple representations of a | |||
character. Most trivially, you could input [literal]#++<++# and [literal]#++>++# | |||
with [literal]#++<++# and [literal]#++>++#, respectively. The input could | |||
also be malformed and the sanitizer must be able to interpret it exactly as the | |||
browser would, and different browsers can interpret malformed HTML and | |||
variable-width character encodings differently. | |||
Notice that the problem applies also to user input from a | |||
[classname]#RichTextArea# is transmitted as HTML from the browser to server-side | |||
and is not sanitized. As the entire purpose of the [classname]#RichTextArea# | |||
component is to allow input of formatted text, you can not just remove all HTML | |||
tags. Also many attributes, such as [parameter]#style#, should pass through the | |||
sanitization. | |||
@@ -0,0 +1,292 @@ | |||
--- | |||
title: Shortcut Keys | |||
order: 5 | |||
layout: page | |||
--- | |||
[[advanced.shortcuts]] | |||
= Shortcut Keys | |||
Vaadin provides simple ways to define shortcut keys for field components, as | |||
well as to a default button, and a lower-level generic shortcut API based on | |||
actions. | |||
A __shortcut__ is an action that is executed when a key or key combination is | |||
pressed within a specific scope in the UI. The scope can be the entire | |||
[classname]#UI# or a [classname]#Window# inside it. | |||
[[advanced.shortcuts.defaultbutton]] | |||
== Shortcut Keys for Default Buttons | |||
You can add a __click shortcut__ to a button to set it as "default" button; | |||
pressing the defined key, typically Enter, in any component in the scope | |||
(sub-window or UI) causes a click event for the button to be fired. | |||
You can define a click shortcut with the [methodname]#setClickShortcut()# | |||
shorthand method: | |||
[source, java] | |||
---- | |||
// Have an OK button and set it as the default button | |||
Button ok = new Button("OK"); | |||
ok.setClickShortcut(KeyCode.ENTER); | |||
ok.addStyleName(ValoTheme.BUTTON_PRIMARY); | |||
---- | |||
The [methodname]#setClickShortcut()# is a shorthand method to create, add, and | |||
manage a [classname]#ClickShortcut#, rather than to add it with | |||
[methodname]#addShortcutListener()#. | |||
Themes offer special button styles to show that a button is special. In the Valo | |||
theme, you can use the [literal]#++BUTTON_PRIMARY++# style name. The result can | |||
be seen in <<figure.advanced.shortcuts.defaultbutton>>. | |||
[[figure.advanced.shortcuts.defaultbutton]] | |||
.Default Button with Click Shortcut | |||
image::img/shortcut-defaultbutton.png[] | |||
[[advanced.shortcuts.focus]] | |||
== Field Focus Shortcuts | |||
You can define a shortcut key that sets the focus to a field component (any | |||
component that inherits [classname]#AbstractField#) by adding a | |||
[classname]#FocusShortcut# as a shortcut listener to the field. | |||
The constructor of the [classname]#FocusShortcut# takes the field component as | |||
its first parameter, followed by the key code, and an optional list of modifier | |||
keys, as listed in <<advanced.shortcuts.keycodes>>. | |||
[source, java] | |||
---- | |||
// A field with Alt+N bound to it | |||
TextField name = new TextField("Name (Alt+N)"); | |||
name.addShortcutListener( | |||
new AbstractField.FocusShortcut(name, KeyCode.N, | |||
ModifierKey.ALT)); | |||
layout.addComponent(name); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.shortcut.focus[on-line example, window="_blank"]. | |||
You can also specify the shortcut by a shorthand notation, where the shortcut | |||
key is indicated with an ampersand ( [literal]#++&++#). | |||
[source, java] | |||
---- | |||
// A field with Alt+A bound to it, using shorthand notation | |||
TextField address = new TextField("Address (Alt+A)"); | |||
address.addShortcutListener( | |||
new AbstractField.FocusShortcut(address, "&Address")); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.shortcut.focus[on-line example, window="_blank"]. | |||
This is especially useful for internationalization, so that you can determine | |||
the shortcut key from the localized string. | |||
[[advanced.shortcuts.actions]] | |||
== Generic Shortcut Actions | |||
Shortcut keys can be defined as __actions__ using the | |||
[classname]#ShortcutAction# class. It extends the generic [classname]#Action# | |||
class that is used for example in [classname]#Tree# and [classname]#Table# for | |||
context menus. Currently, the only classes that accept | |||
[classname]#ShortcutAction#s are [classname]#Window# and [classname]#Panel#. | |||
To handle key presses, you need to define an action handler by implementing the | |||
[classname]#Handler# interface. The interface has two methods that you need to | |||
implement: [methodname]#getActions()# and [methodname]#handleAction()#. | |||
The [methodname]#getActions()# method must return an array of | |||
[classname]#Action# objects for the component, specified with the second | |||
parameter for the method, the [parameter]#sender# of an action. For a keyboard | |||
shortcut, you use a [classname]#ShortcutAction#. The implementation of the | |||
method could be following: | |||
[source, java] | |||
---- | |||
// 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 }); | |||
Action[] actions = new Action[] {action_cancel, action_ok}; | |||
public Action[] getActions(Object target, Object sender) { | |||
if (sender == myPanel) | |||
return actions; | |||
return null; | |||
} | |||
---- | |||
The returned [classname]#Action# array may be static or you can create it | |||
dynamically for different senders according to your needs. | |||
The constructor of [classname]#ShortcutAction# takes a symbolic caption for the | |||
action; this is largely irrelevant for shortcut actions in their current | |||
implementation, but might be used later if implementors use them both in menus | |||
and as shortcut actions. The second parameter is the key code and the third a | |||
list of modifier keys, which are listed in <<advanced.shortcuts.keycodes>>. | |||
The following example demonstrates the definition of a default button for a user | |||
interface, as well as a normal shortcut key, AltC for clicking the | |||
[guibutton]#Cancel# button. | |||
[source, java] | |||
---- | |||
public class DefaultButtonExample extends CustomComponent | |||
implements Handler { | |||
// 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. | |||
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 C key modified with Alt cause an event | |||
Action action_cancel = new ShortcutAction("Alt+C", | |||
ShortcutAction.KeyCode.C, | |||
new int[] { ShortcutAction.ModifierKey.ALT }); | |||
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); | |||
// Set focus to username | |||
username.focus(); | |||
// Set this object as the action handler | |||
panel.addActionHandler(this); | |||
} | |||
/** | |||
* 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 }; | |||
} | |||
/** | |||
* 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 cancelHandler() { | |||
// Do something: report the click | |||
formlayout.addComponent(new Label("Cancel clicked. User=" | |||
+ username.getValue() + ", password=" | |||
+ password.getValue())); | |||
} | |||
} | |||
---- | |||
Notice that the keyboard actions can currently be attached only to | |||
[classname]#Panel#s and [classname]#Window#s. This can cause problems if you | |||
have components that require a certain key. For example, multi-line | |||
[classname]#TextField# requires the Enter key. There is currently no way to | |||
filter the shortcut actions out while the focus is inside some specific | |||
component, so you need to avoid such conflicts. | |||
[[advanced.shortcuts.keycodes]] | |||
== Supported Key Codes and Modifier Keys | |||
The shortcut key definitions require a key code to identify the pressed key and | |||
modifier keys, such as Shift, Alt, or Ctrl, to specify a key combination. | |||
The key codes are defined in the [classname]#ShortcutAction.KeyCode# interface | |||
and are: | |||
Keys [parameter]#A#to[parameter]#Z#:: Normal letter keys | |||
[parameter]#F1#to[parameter]#F12#:: Function keys | |||
[parameter]#BACKSPACE#,[parameter]#DELETE#,[parameter]#ENTER#,[parameter]#ESCAPE#,[parameter]#INSERT#,[parameter]#TAB#:: Control keys | |||
[parameter]#NUM0#to[parameter]#NUM9#:: Number pad keys | |||
[parameter]#ARROW_DOWN#,[parameter]#ARROW_UP#,[parameter]#ARROW_LEFT#,[parameter]#ARROW_RIGHT#:: Arrow keys | |||
[parameter]#HOME#,[parameter]#END#,[parameter]#PAGE_UP#,[parameter]#PAGE_DOWN#:: Other movement keys | |||
Modifier keys are defined in [classname]#ShortcutAction.ModifierKey# and are: | |||
[parameter]#ModifierKey.ALT#:: Alt key | |||
[parameter]#ModifierKey.CTRL#:: Ctrl key | |||
[parameter]#ModifierKey.SHIFT#:: Shift key | |||
All constructors and methods accepting modifier keys take them as a variable | |||
argument list following the key code, separated with commas. For example, the | |||
following defines a CtrlShiftN key combination for a shortcut. | |||
[source, java] | |||
---- | |||
TextField name = new TextField("Name (Ctrl+Shift+N)"); | |||
name.addShortcutListener( | |||
new AbstractField.FocusShortcut(name, KeyCode.N, | |||
ModifierKey.CTRL, | |||
ModifierKey.SHIFT)); | |||
---- | |||
=== Supported Key Combinations | |||
The actual possible key combinations vary greatly between browsers, as most | |||
browsers have a number of built-in shortcut keys, which can not be used in web | |||
applications. For example, Mozilla Firefox allows binding almost any key | |||
combination, while Opera does not even allow binding Alt shortcuts. Other | |||
browsers are generally in between these two. Also, the operating system can | |||
reserve some key combinations and some computer manufacturers define their own | |||
system key combinations. | |||
@@ -0,0 +1,696 @@ | |||
--- | |||
title: Vaadin Spring Add-on | |||
order: 18 | |||
layout: page | |||
--- | |||
[[advanced.spring]] | |||
= Vaadin Spring Add-on | |||
((("Vaadin Spring", id="term.advanced.spring.springlong", range="startofrange"))) | |||
((("Spring", id="term.advanced.spring.spring", range="startofrange"))) | |||
Vaadin Spring and Vaadin Spring Boot add-ons make it easier to use Spring in | |||
Vaadin applications. Vaadin Spring enables Spring dependency injection with | |||
custom UI and view providers, and provides three custom scopes: | |||
[classname]#UIScope#, [classname]#ViewScope#, and | |||
[classname]#VaadinSessionScope#. | |||
API documentation for add-ons is available at: | |||
* Vaadin Spring API at link:https://vaadin.com/api/vaadin-spring[vaadin.com/api/vaadin-spring] | |||
* Vaadin Spring Boot API at link:https://vaadin.com/api/vaadin-spring-boot[vaadin.com/api/vaadin-spring-boot] | |||
To learn more about Vaadin Spring, the | |||
link:https://vaadin.com/wiki/-/wiki/Main/Vaadin+Spring[Vaadin Spring Tutorial] | |||
gives a hands-on introduction. The source code of the Spring Tutorial demo is | |||
available for browsing or cloning at | |||
link:https://github.com/Vaadin/spring-tutorial[github.com/Vaadin/spring-tutorial]. | |||
[[advanced.spring.spring]] | |||
== Spring Overview | |||
__Spring Framework__ is a Java application framework that provides many useful | |||
services for building applications, such as authentication, authorization, data | |||
access, messaging, testing, and so forth. In the Spring core, one of the central | |||
features is dependency injection, which accomplishes inversion of control for | |||
dependency management in managed beans. Other Spring features rely on it | |||
extensively. As such, Spring offers capabilities similar to CDI, but with | |||
integration with other Spring services. Spring is well-suited for applications | |||
where Vaadin provides the UI layer and Spring is used for other aspects of the | |||
application logic. | |||
__Spring Boot__ is a Spring application development tool that allows creating | |||
Spring applications easily. __Vaadin Spring Boot__ builds on Spring Boot to | |||
allow creating Vaadin Spring applications easily. It starts up a servlet, | |||
handles the configuration of the application context, registers a UI provider, | |||
and so forth. | |||
Regarding general Spring topics, we recommend the following Spring | |||
documentation: | |||
ifdef::web[] | |||
* link:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/[Spring | |||
Framework Reference Documentation]. | |||
* link:http://projects.spring.io/spring-framework/[Spring Project] | |||
* link:https://vaadin.com/wiki/-/wiki/Main/Vaadin+Spring[Vaadin Spring Tutorial] | |||
endif::web[] | |||
[[advanced.spring.spring.injection]] | |||
=== Dependency Injection | |||
__Dependency injection__ is a way to pass dependencies (service objects) to | |||
dependent objects (clients) by injecting them in member variables or initializer | |||
parameters, instead of managing the lifecycle in the clients or passing them | |||
explicitly as parameters. In Spring, injection of a service object to a client | |||
is configured with the [classname]#@Autowired# annotation. | |||
For a very typical example in a web application, you could have a user data | |||
object associated with a user session: | |||
[source, java] | |||
---- | |||
@SpringComponent | |||
@VaadinSessionScope | |||
public class User implements Serializable { | |||
private String name; | |||
public void setName(String name) {this.name = name;} | |||
public String getName() {return name;} | |||
} | |||
---- | |||
The [classname]#@SpringComponent# annotation allows for automatic detection of | |||
managed beans by Spring. (The annotation is exactly the same as the regular | |||
Spring [classname]#@Component#, but has been given an alias, because Vaadin has | |||
a [interfacename]#Component# interface, which can cause trouble.) | |||
Now, if we have a UI view that depends on user data, we could inject the data in | |||
the client as follows: | |||
[source, java] | |||
---- | |||
public class MainView extends CustomComponent implements View { | |||
User user; | |||
Label greeting = new Label(); | |||
@Autowired | |||
public MainView(User user) { | |||
this.user = user; | |||
... | |||
} | |||
... | |||
@Override | |||
public void enter(ViewChangeEvent event) { | |||
// Then you can use the injected data | |||
// for some purpose | |||
greeting.setValue("Hello, " + user.getName()); | |||
} | |||
} | |||
---- | |||
Here, we injected the user object in the constructor. The user object would be | |||
created automatically when the view is created, with all such references | |||
referring to the same shared instance in the scope of the Vaadin user session. | |||
[[advanced.spring.spring.contexts]] | |||
=== Contexts and Scopes | |||
__Contexts__ in Spring are services that manage the lifecycle of objects and | |||
handle their injection. Generally speaking, a context is a situation in which an | |||
instance is used with a unique identity. Such objects are essentially | |||
"singletons" in the context. While conventional singletons are application-wide, | |||
objects managed by a Spring container can be "singletons" in a more narrow | |||
__scope__: a user session, a particular UI instance associated with the session, | |||
a view within the UI, or even just a single request. Such a context defines the | |||
lifecycle of the object: its creation, use, and finally its destruction. | |||
Earlier, we introduced a user class defined as session-scoped: | |||
[source, java] | |||
---- | |||
@SpringComponent | |||
@VaadinSessionScope | |||
public class User { | |||
---- | |||
Now, when you need to refer to the user, you can use Spring injection to inject | |||
the session-scoped "singleton" to a member variable or a constructor parameter; | |||
the former in the following: | |||
[source, java] | |||
---- | |||
public class MainView extends CustomComponent implements View { | |||
@Autowired | |||
User user; | |||
Label greeting = new Label(); | |||
... | |||
@Override | |||
public void enter(ViewChangeEvent event) { | |||
greeting.setValue("Hello, " + user.getName()); | |||
} | |||
} | |||
---- | |||
[[advanced.spring.boot]] | |||
== Quick Start with Vaadin Spring Boot | |||
The Vaadin Spring Boot is an add-on that allows for easily creating a project | |||
that uses Vaadin Spring. It is meant to be used together with Spring Boot, which | |||
enables general Spring functionalities in a web application. | |||
You can use the Spring Initializr at | |||
link:https://start.spring.io/[start.spring.io] website to generate a project, | |||
which you can then download as a package and import in your IDE. The generated | |||
project is a Spring application stub; you need to add at least Vaadin | |||
dependencies ( [literal]#++vaadin-spring-boot++#, [literal]#++vaadin-themes++#, | |||
and [literal]#++vaadin-client-compiled++#) and a UI class to the generated | |||
project, as well as a theme, and so forth. | |||
See the link:https://vaadin.com/wiki/-/wiki/Main/Vaadin+Spring[Vaadin Spring | |||
Tutorial] for detailed instructions for using Spring Boot. | |||
[[advanced.spring.installation]] | |||
== Installing Vaadin Spring Add-on | |||
Vaadin Spring requires a Java EE 7 compatible servlet container, such as | |||
Glassfish or Apache TomEE Web Profile, as mentioned for the reference toolchain | |||
in | |||
<<dummy/../../../framework/getting-started/getting-started-environment#getting-started.environment,"Setting | |||
up the Development Environment">>. | |||
To install the Vaadin Spring and/or Vaadin Spring Boot add-ons, either define | |||
them as an Ivy or Maven dependency or download from the Vaadin Directory add-on | |||
page at <<,vaadin.com/directory#addon/vaadin-spring>> or | |||
<<,vaadin.com/directory#addon/vaadin-spring-boot>>. See | |||
<<dummy/../../../framework/addons/addons-overview.asciidoc#addons.overview,"Using | |||
Vaadin Add-ons">> for general instructions for installing and using Vaadin | |||
add-ons. | |||
The Ivy dependency is as follows: | |||
[subs="normal"] | |||
---- | |||
<dependency org="com.vaadin" name="vaadin-spring" | |||
rev="[replaceable]#latest.release#"/> | |||
---- | |||
The Maven dependency is as follows: | |||
[subs="normal"] | |||
---- | |||
<dependency> | |||
<groupId>com.vaadin</groupId> | |||
<artifactId>vaadin-spring</artifactId> | |||
<version>[replaceable]#LATEST#</version> | |||
</dependency> | |||
---- | |||
[[advanced.spring.peparing]] | |||
== Preparing Application for Spring | |||
A Vaadin application that uses Spring must have a file named | |||
[filename]#applicationContext.xml# in the [filename]#WEB-INF# directory. | |||
[subs="normal"] | |||
---- | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<beans xmlns="http://www.springframework.org/schema/beans" | |||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
xmlns:context="http://www.springframework.org/schema/context" | |||
xsi:schemaLocation=" | |||
http://www.springframework.org/schema/beans | |||
http://www.springframework.org/schema/beans/spring-beans.xsd | |||
http://www.springframework.org/schema/context | |||
http://www.springframework.org/schema/context/spring-context-4.1.xsd"> | |||
//Configuration object | |||
<bean class="[replaceable]#com.example.myapp.MySpringUI.MyConfiguration#" /> | |||
//Location for automatically scanned beans | |||
<context:component-scan | |||
base-package="[replaceable]#com.example.myapp.domain#" /> | |||
</beans> | |||
---- | |||
The application should not have a servlet extending [classname]#VaadinServlet#, | |||
as Vaadin servlet has its own [classname]#VaadinSpringServlet# that is deployed | |||
automatically. If you need multiple servlets or need to customize the Vaadin | |||
Spring servlet, see <<advanced.spring.deployment>>. | |||
You can configure managed beans explicitly in the file, or configure them to be | |||
scanned using the annotations, which is the preferred way described in this | |||
section. | |||
[[advanced.spring.springui]] | |||
== Injecting a UI with [classname]#@SpringUI# | |||
((("[classname]#@SpringUI#", id="term.advanced.spring.springui", range="startofrange"))) | |||
Vaadin Spring offers an easier way to instantiate UIs and to define the URL | |||
mapping for them than the usual ways described in | |||
<<dummy/../../../framework/application/application-environment#application.environment,"Deploying | |||
an Application">>. It is also needed for enabling Spring features in the UI. To | |||
define a UI class that should be instantiated for a given URL, you simply need | |||
to annotate the class with [classname]#@SpringUI#. It takes an optional path as | |||
parameter. | |||
[source, java] | |||
---- | |||
@SpringUI(path="/myniceui") | |||
@Theme("valo") | |||
public class MyNiceUI extends UI { | |||
... | |||
---- | |||
The path in the URL for accessing the UI consists of the context path of the | |||
application and the UI path, for example, [literal]#++/myapp/myniceui++#. Giving | |||
empty UI path maps the UI to the root of the application context, for example, | |||
[literal]#++/myapp++#. | |||
[source, java] | |||
---- | |||
@SpringUI | |||
---- | |||
See <<advanced.spring.deployment>> for how to handle servlet URL mapping of | |||
Spring UIs when working with multiple servlets in the same web application. | |||
(((range="endofrange", startref="term.advanced.spring.springui"))) | |||
[[advanced.spring.scopes]] | |||
== Scopes | |||
((("Spring", "scopes", id="term.advanced.spring.scopes", range="startofrange"))) | |||
As in programming languages, where a variable name refers to a unique object | |||
within the scope of the variable, an object has unique identity within a scope | |||
in Spring. However, instead of identifying the objects by variable names, they | |||
are identified by their type (object class) and any qualifiers they may have. | |||
The scope of an object can be defined with an annotation to the class as | |||
follows: | |||
[source, java] | |||
---- | |||
@VaadinSessionScope | |||
public class User { | |||
... | |||
---- | |||
Defining a scope in Spring is normally done with the [classname]#@Scope# | |||
annotation. For example, [literal]#++@Scope("prototype")++# creates a new | |||
instance every time one is requested/auto-wired. Such standard scopes can be | |||
used with some limitations. For example, Spring session and request scopes do | |||
not work in background threads and with certain push transport modes. | |||
Vaadin Spring provides three scopes useful in Vaadin applications: a session | |||
scope, a UI scope, a view scope, all defined in the | |||
[package]#com.vaadin.spring.annotation# package. | |||
[[advanced.spring.scopes.session]] | |||
=== [classname]#@VaadinSessionScope# | |||
The session scope is the broadest of the custom scopes defined in Vaadin Spring. | |||
Objects in the Vaadin session scope are unique in a user session, and shared | |||
between all UIs open in the session. This is the most basic scope in Vaadin | |||
applications, useful for accessing data for the user associated with the | |||
session. It is also useful when updating UIs from a background thread, as in | |||
those cases the UI access is locked on the session and also data should be in | |||
that scope. | |||
[[advanced.spring.scopes.ui]] | |||
=== [classname]#@UIScope# | |||
UI-scoped beans are uniquely identified within a UI instance, that is, a browser | |||
window or tab. The lifecycle of UI-scoped beans is bound between to the | |||
initialization and closing of a UI. Whenever you inject a bean, as long as you | |||
are within the same UI, you will get the same instance. | |||
Annotating a Spring view (annotated with [classname]#@SpringView# as described | |||
later) also as [classname]#@UIScoped# makes the view retain the same instance | |||
when the user navigates away and back to the view. | |||
[[advanced.spring.scopes.view]] | |||
=== [classname]#@ViewScope# | |||
The annotation enables the view scope in a bean. The lifecycle of such a bean | |||
starts when the user navigates to a view referring to the object and ends when | |||
the user navigates out of the view (or when the UI is closed or expires). | |||
Views themselves are by default view-scoped, so a new instance is created every | |||
time the user navigates to the view. | |||
(((range="endofrange", startref="term.advanced.spring.scopes"))) | |||
ifdef::web[] | |||
[[advanced.spring.navigation]] | |||
== View Navigation | |||
Vaadin Spring extends the navigation framework in Vaadin, described in | |||
<<dummy/../../../framework/advanced/advanced-navigator#advanced.navigator,"Navigating | |||
in an Application">>. It manages Spring views with a special view provider and | |||
enables view scoping. | |||
[[advanced.spring.navigation.ui]] | |||
=== Preparing the UI | |||
You can define navigation for any single-component container, as described in | |||
<<dummy/../../../framework/advanced/advanced-navigator#advanced.navigator.navigating,"Setting | |||
Up for Navigation">>, but typically you set up navigation for the entire UI | |||
content. To use Vaadin Spring views, you need to inject a | |||
[classname]#SpringViewProvider# in the UI and add it as a provider for the | |||
navigator. | |||
[source, java] | |||
---- | |||
@SpringUI(path="/myspringui") | |||
public class MySpringUI extends UI { | |||
@Autowired | |||
SpringViewProvider viewProvider; | |||
@Override | |||
protected void init(VaadinRequest request) { | |||
Navigator navigator = new Navigator(this, this); | |||
navigator.addProvider(viewProvider); | |||
// Navigate to start view | |||
navigator.navigateTo(""); | |||
} | |||
} | |||
---- | |||
[[advanced.spring.navigation.view]] | |||
=== The View | |||
A view managed by Vaadin Spring only needs to have the [classname]#@SpringView# | |||
annotation, which registers the view in the [classname]#SpringViewProvider#. The | |||
annotation is also necessary to enable Spring features in the view, such as | |||
injection. | |||
[source, java] | |||
---- | |||
@SpringView(name=MainView.NAME) | |||
public class MainView extends CustomComponent implements View { | |||
public static final String NAME = "main"; | |||
... | |||
---- | |||
The annotation can have the following optional paramers: | |||
name (optional):: Specifies the path by which the view can be accessed programmatically and by the | |||
URI fragment. | |||
+ | |||
[source, java] | |||
---- | |||
@SpringView(name="main") | |||
---- | |||
+ | |||
If the view name is not given, it is derived from the class name by removing a | |||
possible "View" suffix, making it lower case, and using a dash ("-") to separate | |||
words originally denoted by capital letters. Thereby, a view class such as | |||
[classname]#MyFunnyView# would have name " [literal]#++my-funny++#". | |||
+ | |||
It is a recommended pattern to have the view name in a static member constant in | |||
the view class, as was done in the example previously, so that the name can be | |||
referred to safely. | |||
supportsParameters:: Specifies whether view parameters can be passed to the view as a suffix to the | |||
name in the navigation state, that is, in the form of | |||
[literal]#++viewname+viewparameters++#. The view name is merely a prefix and | |||
there is no separator nor format for the parameters, but those are left for the | |||
view to handle. The parameter support mode is disabled by default. | |||
+ | |||
[source, java] | |||
---- | |||
@SpringView(name="myview", supportsParameters=true) | |||
---- | |||
+ | |||
You could then navigate to the state with a URI fragment such as | |||
[literal]#++#!myview/someparameter++# or programmatically with: | |||
+ | |||
[source, java] | |||
---- | |||
getUI().getNavigator().navigateTo("myview/someparameter"); | |||
---- | |||
+ | |||
The [methodname]#enter()# method of the view gets the URI fragment as parameter | |||
as is and can interpret it in any application-defined way. | |||
+ | |||
Note that in this mode, matching a navigation state to a view is done by the | |||
prefix of the fragment! Thereby, no other views may start with the name of the | |||
view as prefix. For example, if the view name is " [literal]#++main++#", you | |||
must not have a view named " [literal]#++maintenance++#". | |||
uis:: If the application has multiple UIs that use [classname]#SpringViewProvider#, | |||
you can use this parameter to specify which UIs can show the view. | |||
+ | |||
[source, java] | |||
---- | |||
@SpringView(name="myview", uis={MySpringUI.class}) | |||
---- | |||
+ | |||
If the list contains [parameter]#UI.class#, the view is available to all UIs. | |||
+ | |||
[source, java] | |||
---- | |||
@SpringView(name="myview", uis={UI.class}) | |||
---- | |||
In the following, we have a login view that accesses a session-scoped user | |||
object. Here, we use a constant to define the view name, so that we can use the | |||
constant when navigating to it. | |||
[source, java] | |||
---- | |||
@SpringView(name=LoginView.NAME) | |||
public class LoginView extends CustomComponent | |||
implements View { | |||
public final static String NAME = ""; | |||
// Here we inject to the constructor and actually do | |||
// not store the injected object to use it later | |||
@Autowired | |||
public LoginView(User user) { | |||
VerticalLayout layout = new VerticalLayout(); | |||
// An input field for editing injected data | |||
BeanItem<User> item = new BeanItem<User>(user); | |||
TextField username = new TextField("User name", | |||
item.getItemProperty("name")); | |||
username.setNullRepresentation(""); | |||
layout.addComponent(username); | |||
// Login button (authentication omitted) / Java 8 | |||
layout.addComponent(new Button("Login", e -> | |||
getUI().getNavigator(). | |||
navigateTo(MainView.VIEWNAME))); | |||
setCompositionRoot(layout); | |||
} | |||
@Override | |||
public void enter(ViewChangeEvent event) {} | |||
} | |||
---- | |||
You could now navigate to the view from any other view in the UI with: | |||
[source, java] | |||
---- | |||
getUI().getNavigator().navigateTo(LoginView.VIEWNAME); | |||
---- | |||
endif::web[] | |||
[[advanced.spring.accesscontrol]] | |||
== Access Control | |||
Access control for views can be implemented by registering beans implementing | |||
[interfacename]#ViewAccessControl# or | |||
[interfacename]#ViewInstanceAccessControl#, which can restrict access to the | |||
view either before or after a view instance is created. | |||
Integration with authorization solutions, such as Spring Security, is provided | |||
by additional unofficial add-ons on top of Vaadin Spring. | |||
[[advanced.spring.accesscontrol.accessdenied]] | |||
=== Access Denied View | |||
By default, the view provider acts as if a denied view didn't exist. You can set | |||
up an "Access Denied" view that is shown if the access is denied with | |||
[methodname]#setAccessDeniedView()# in [classname]#SpringViewProvider#. | |||
[source, java] | |||
---- | |||
@Autowired | |||
SpringViewProvider viewProvider; | |||
@Override | |||
protected void init(VaadinRequest request) { | |||
Navigator navigator = new Navigator(this, this); | |||
navigator.addProvider(viewProvider); | |||
// Set up access denied view | |||
viewProvider.setAccessDeniedViewClass( | |||
MyAccessDeniedView.class); | |||
---- | |||
[[advanced.spring.deployment]] | |||
== Deploying Spring UIs and Servlets | |||
Vaadin Spring hooks into Vaadin framework by using a special | |||
[classname]#VaadinSpringServlet#. As described earlier, you do not need to map | |||
an URL path to a UI, as it is handled by Vaadin Spring. However, in the | |||
following, we go through some cases where you need to customize the servlet or | |||
use Spring with non-Spring servlets and UIs in a web application. | |||
[[advanced.spring.servlets.custom]] | |||
=== Custom Servlets | |||
When customizing the Vaadin servlet, as outlined in | |||
<<dummy/../../../framework/application/application-lifecycle#application.lifecycle.servlet-service,"Vaadin | |||
Servlet, Portlet, and Service">>, you simply need to extend | |||
[classname]#com.vaadin.spring.internal.VaadinSpringServlet# instead of | |||
[classname]#com.vaadin.servlet.VaadinServlet#. | |||
[subs="normal"] | |||
---- | |||
@WebServlet(value = "[replaceable]#/*#", asyncSupported = true) | |||
public class [replaceable]#MySpringServlet# extends SpringVaadinServlet { | |||
} | |||
---- | |||
The custom servlet must not have [classname]#@VaadinServletConfiguration#, as | |||
you would normally with a Vaadin servlet, as described in | |||
<<dummy/../../../framework/application/application-environment#application.environment,"Deploying | |||
an Application">>. | |||
[[advanced.spring.deployment.urlmapping]] | |||
=== Defining Servlet Root | |||
Spring UIs are managed by a Spring servlet ( [classname]#VaadinSpringServlet#), | |||
which is by default mapped to the root of the application context. For example, | |||
if the name of a Spring UI is " [literal]#++my-spring-ui++#" and application | |||
context is [literal]#++/myproject++#, the UI would by default have URL " | |||
[literal]#++/myproject/my-spring-ui++#". If you do not want to have the servlet | |||
mapped to context root, you can use a [classname]#@WebServlet# annotation for | |||
the servlet or a [filename]#web.xml# definition to map all Spring UIs to a | |||
sub-path. | |||
For example, if we have a root UI and another: | |||
[subs="normal"] | |||
---- | |||
@SpringUI(path=[replaceable]#""#) // At Spring servlet root | |||
public class [replaceable]#MySpringRootUI# extends UI {...} | |||
@SpringUI("[replaceable]#another#") | |||
public class [replaceable]#AnotherUI# extends UI {...} | |||
---- | |||
Then define a path for the servlet by defining a custom servlet: | |||
[subs="normal"] | |||
---- | |||
@WebServlet(value = "[replaceable]#/myspringuis/*#", asyncSupported = true) | |||
public class [replaceable]#MySpringServlet# extends SpringVaadinServlet { | |||
} | |||
---- | |||
These two UIs would have URLs /myproject/myspringuis and | |||
/myproject/myspringuis/another, respectively. | |||
You can also map the Spring servlet to another URL in servlet definition in | |||
[filename]#web.xml#, as described the following. | |||
[[advanced.spring.servlets.mixing]] | |||
=== Mixing With Other Servlets | |||
The [classname]#VaadinSpringServlet# is normally used as the default servlet, | |||
but if you have other servlets in the application, such as for non-Spring UIs, | |||
you need to define the Spring servlet explicitly in the [filename]#web.xml#. You | |||
can map the servlet to any URL path, but perhaps typically, you define it as the | |||
default servlet as follows, and map the other servlets to other URL paths: | |||
[subs="normal"] | |||
---- | |||
<web-app> | |||
... | |||
<servlet> | |||
<servlet-name>Default</servlet-name> | |||
<servlet-class> | |||
com.vaadin.spring.internal.VaadinSpringServlet | |||
</servlet-class> | |||
</servlet> | |||
<servlet-mapping> | |||
<servlet-name>Default</servlet-name> | |||
<url-pattern>[replaceable]#/myspringuis/*#</url-pattern> | |||
</servlet-mapping> | |||
<servlet-mapping> | |||
<servlet-name>Default</servlet-name> | |||
<url-pattern>/VAADIN/*</url-pattern> | |||
</servlet-mapping> | |||
</web-app> | |||
---- | |||
With such a setting, paths to Spring UIs would have base path | |||
[filename]#/myapp/myspringuis#, to which the (optional) UI path would be | |||
appended. The [filename]#/VAADIN/*# only needs to be mapped to the servlet if | |||
there are no other Vaadin servlets. | |||
(((range="endofrange", startref="term.advanced.spring.springlong"))) | |||
(((range="endofrange", startref="term.advanced.spring.spring"))) | |||
@@ -0,0 +1,191 @@ | |||
--- | |||
title: Managing URI Fragments | |||
order: 11 | |||
layout: page | |||
--- | |||
[[advanced.urifu]] | |||
= Managing URI Fragments | |||
A major issue in AJAX applications is that as they run in a single web page, | |||
bookmarking the application URL (or more generally the __URI__) can only | |||
bookmark the application, not an application state. This is a problem for many | |||
applications, such as product catalogs and discussion forums, in which it would | |||
be good to provide links to specific products or messages. Consequently, as | |||
browsers remember the browsing history by URI, the history and the | |||
[guibutton]#Back# button do not normally work. The solution is to use the | |||
__fragment identifier__ part of the URI, which is separated from the primary | |||
part (address + path + optional query parameters) of the URI with the hash (#) | |||
character. For example: | |||
---- | |||
http://example.com/path#myfragment | |||
---- | |||
The exact syntax of the fragment identifier part is defined in RFC 3986 | |||
(Internet standard STD 66) that defines the URI syntax. A fragment may only | |||
contain the regular URI __path characters__ (see the standard) and additionally | |||
the slash and the question mark. | |||
Vaadin offers two ways to enable the use of URI fragments: the high-level | |||
[classname]#Navigator# utility described in | |||
<<dummy/../../../framework/advanced/advanced-navigator#advanced.navigator,"Navigating | |||
in an Application">> and the low-level API described here. | |||
[[advanced.urifu.setting]] | |||
== Setting the URI Fragment | |||
You can set the current fragment identifier with the | |||
[methodname]#setUriFragment()# method in the [classname]#Page# object. | |||
[source, java] | |||
---- | |||
Page.getCurrent().setUriFragment("mars"); | |||
---- | |||
Setting the URI fragment causes an [interfacename]#UriFragmentChangeEvent#, | |||
which is processed in the same server request. As with UI rendering, the URI | |||
fragment is changed in the browser after the currently processed server request | |||
returns the response. | |||
Prefixing the fragment identifier with an exclamation mark enables the web | |||
crawler support described in <<advanced.urifu.crawling>>. | |||
[[advanced.urifu.reading]] | |||
== Reading the URI Fragment | |||
The current URI fragment can be acquired with the [methodname]#getUriFragment()# | |||
method from the current [classname]#Page# object. The fragment is known when the | |||
[methodname]#init()# method of the UI is called. | |||
[source, java] | |||
---- | |||
// Read initial URI fragment to create UI content | |||
String fragment = getPage().getUriFragment(); | |||
enter(fragment); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.urifragment.basic[on-line example, window="_blank"]. | |||
To enable reusing the same code when the URI fragment is changed, as described | |||
next, it is usually best to build the relevant part of the UI in a separate | |||
method. In the above example, we called an [methodname]#enter()# method, in a | |||
way that is similar to handling view changes with [classname]#Navigator#. | |||
[[advanced.urifu.listening]] | |||
== Listening for URI Fragment Changes | |||
After the UI has been initialized, changes in the URI fragment can be handled | |||
with a [interfacename]#UriFragmentChangeListener#. The listeners are called when | |||
the URI fragment changes, but not when the UI is initialized, where the current | |||
fragment is available from the page object as described earlier. | |||
For example, we could define the listener as follows in the [methodname]#init()# | |||
method of a UI class: | |||
[source, java] | |||
---- | |||
public class MyUI extends UI { | |||
@Override | |||
protected void init(VaadinRequest request) { | |||
getPage().addUriFragmentChangedListener( | |||
new UriFragmentChangedListener() { | |||
public void uriFragmentChanged( | |||
UriFragmentChangedEvent source) { | |||
enter(source.getUriFragment()); | |||
} | |||
}); | |||
// Read the initial URI fragment | |||
enter(getPage().getUriFragment()); | |||
} | |||
void enter(String fragment) { | |||
... initialize the UI ... | |||
} | |||
} | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.urifragment.basic[on-line example, window="_blank"]. | |||
<<figure.advanced.urifu>> shows an application that allows specifying the menu | |||
selection with a URI fragment and correspondingly sets the fragment when the | |||
user selects a menu item. | |||
[[figure.advanced.urifu]] | |||
.Application State Management with URI Fragment Utility | |||
image::img/urifu-1.png[] | |||
[[advanced.urifu.crawling]] | |||
== Supporting Web Crawling | |||
Stateful AJAX applications can not normally be crawled by a search engine, as | |||
they run in a single page and a crawler can not navigate the states even if URI | |||
fragments are enabled. The Google search engine and crawler | |||
link:http://googlewebmastercentral.blogspot.fi/2009/10/proposal-for-making-ajax-crawlable.html[support | |||
a convention] where the fragment identifiers are prefixed with exclamation mark, | |||
such as [literal]#++#!myfragment++#. The servlet needs to have a separate | |||
searchable content page accessible with the same URL, but with a | |||
[literal]#++_escaped_fragment_++# parameter. For example, for | |||
[literal]#++/myapp/myui#!myfragment++# it would be | |||
[literal]#++/myapp/myui?_escaped_fragment_=myfragment++#. | |||
You can provide the crawl content by overriding the [methodname]#service()# | |||
method in a custom servlet class. For regular requests, you should call the | |||
super implementation in the [classname]#VaadinServlet# class. | |||
[source, java] | |||
---- | |||
public class MyCustomServlet extends VaadinServlet | |||
@Override | |||
protected void service(HttpServletRequest request, | |||
HttpServletResponse response) | |||
throws ServletException, IOException { | |||
String fragment = request | |||
.getParameter("_escaped_fragment_"); | |||
if (fragment != null) { | |||
response.setContentType("text/html"); | |||
Writer writer = response.getWriter(); | |||
writer.append("<html><body>"+ | |||
"<p>Here is some crawlable "+ | |||
"content about " + fragment + "</p>"); | |||
// A list of all crawlable pages | |||
String items[] = {"mercury", "venus", | |||
"earth", "mars"}; | |||
writer.append("<p>Index of all content:</p><ul>"); | |||
for (String item: items) { | |||
String url = request.getContextPath() + | |||
request.getServletPath() + | |||
request.getPathInfo() + "#!" + item; | |||
writer.append("<li><a href='" + url + "'>" + | |||
item + "</a></li>"); | |||
} | |||
writer.append("</ul></body>"); | |||
} else | |||
super.service(request, response); | |||
} | |||
} | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#advanced.urifragment.basic[on-line example, window="_blank"]. | |||
The crawlable content does not need to be human readable. It can provide an | |||
index of links to other application states, as we did in the example above. The | |||
links should use the " [literal]#++#!++#" notation, but can not be relative to | |||
avoid having the [literal]#++_escaped_fragment_++# parameter. | |||
You need to use the custom servlet class in the [filename]#web.xml# deployment | |||
descriptor instead of the normal [classname]#VaadinServlet# class, as described | |||
in | |||
<<dummy/../../../framework/application/application-environment#application.environment.web-xml,"Using | |||
a web.xml Deployment Descriptor">>. | |||
@@ -0,0 +1,180 @@ | |||
--- | |||
title: Handling Browser Windows | |||
order: 1 | |||
layout: page | |||
--- | |||
[[advanced.windows]] | |||
= Handling Browser Windows | |||
The UI of a Vaadin application runs in a web page displayed in a browser window | |||
or tab. An application can be used from multiple UIs in different windows or | |||
tabs, either opened by the user using an URL or by the Vaadin application. | |||
In addition to native browser windows, Vaadin has a [classname]#Window# | |||
component, which is a floating panel or __sub-window__ inside a page, as | |||
described in | |||
<<dummy/../../../framework/layout/layout-sub-window#layout.sub-window,"Sub-Windows">>. | |||
* __Native popup windows__. An application can open popup windows for sub-tasks. | |||
* __Page-based browsing__. The application can allow the user to open certain content to different windows. For example, in a messaging application, it can be useful to open different messages to different windows so that the user can browse through them while writing a new message. | |||
* __Bookmarking__. Bookmarks in the web browser can provide an entry-point to some content provided by an application. | |||
* __Embedding UIs__. UIs can be embedded in web pages, thus making it possible to provide different views to an application from different pages or even from the same page, while keeping the same session. See <<dummy/../../../framework/advanced/advanced-embedding#advanced.embedding,"Embedding UIs in Web Pages">>. | |||
Use of multiple windows in an application may require defining and providing | |||
different UIs for the different windows. The UIs of an application share the | |||
same user session, that is, the [classname]#VaadinSession# object, as described | |||
in | |||
<<dummy/../../../framework/application/application-lifecycle#application.lifecycle.session,"User | |||
Session">>. Each UI is identified by a URL that is used to access it, which | |||
makes it possible to bookmark application UIs. UI instances can even be created | |||
dynamically based on the URLs or other request parameters, such as browser | |||
information, as described in | |||
<<dummy/../../../framework/application/application-lifecycle#application.lifecycle.ui,"Loading | |||
a UI">>. | |||
Because of the special nature of AJAX applications, use of multiple windows uses | |||
require some | |||
caveats.//// | |||
TODO Re-enable We will go through them later in <xref | |||
linkend="advanced.windows.caveats"/>. | |||
//// | |||
[[advanced.windows.popup]] | |||
== Opening Popup Windows | |||
((("popup windows"))) | |||
((("windows", "popup"))) | |||
Popup windows are native browser windows or tabs opened by user interaction with | |||
an existing window. Due to browser security reasons, it is made incovenient for | |||
a web page to open popup windows using JavaScript commands. At the least, the | |||
browser will ask for a permission to open the popup, if it is possible at all. | |||
This limitation can be circumvented by letting the browser open the new window | |||
or tab directly by its URL when the user clicks some target. This is realized in | |||
Vaadin with the [classname]#BrowserWindowOpener# component extension, which | |||
causes the browser to open a window or tab when the component is clicked. | |||
[[advanced.windows.popup.ui]] | |||
=== The Popup Window UI | |||
A popup Window displays an [classname]#UI#. The UI of a popup window is defined | |||
just like a main UI in a Vaadin application, and it can have a theme, title, and | |||
so forth. | |||
For example: | |||
[source, java] | |||
---- | |||
@Theme("book-examples") | |||
public static class MyPopupUI extends UI { | |||
@Override | |||
protected void init(VaadinRequest request) { | |||
getPage().setTitle("Popup Window"); | |||
// Have some content for it | |||
VerticalLayout content = new VerticalLayout(); | |||
Label label = | |||
new Label("I just popped up to say hi!"); | |||
label.setSizeUndefined(); | |||
content.addComponent(label); | |||
content.setComponentAlignment(label, | |||
Alignment.MIDDLE_CENTER); | |||
content.setSizeFull(); | |||
setContent(content); | |||
} | |||
} | |||
---- | |||
[[advanced.windows.popup.popping]] | |||
=== Popping It Up | |||
A popup window is opened using the [classname]#BrowserWindowOpener# extension, | |||
which you can attach to any component. The constructor of the extension takes | |||
the class object of the UI class to be opened as a parameter. | |||
You can configure the features of the popup window with | |||
[methodname]#setFeatures()#. It takes as its parameter a comma-separated list of | |||
window features, as defined in the HTML specification. | |||
status=[parameter]#0|1#:: Whether the status bar at the bottom of the window should be enabled. | |||
[parameter]##:: | |||
scrollbars:: Enables scrollbars in the window if the document area is bigger than the view area of the window. | |||
resizable:: Allows the user to resize the browser window (no effect for tabs). | |||
menubar:: Enables the browser menu bar. | |||
location:: Enables the location bar. | |||
toolbar:: Enables the browser toolbar. | |||
height=[parameter]#value#:: Specifies the height of the window in pixels. | |||
width=[parameter]#value#:: Specifies the width of the window in pixels. | |||
For example: | |||
[source, java] | |||
---- | |||
// Create an opener extension | |||
BrowserWindowOpener opener = | |||
new BrowserWindowOpener(MyPopupUI.class); | |||
opener.setFeatures("height=200,width=300,resizable"); | |||
// Attach it to a button | |||
Button button = new Button("Pop It Up"); | |||
opener.extend(button); | |||
---- | |||
The resulting popup window, which appears when the button is clicked, is shown | |||
in <<figure.advanced.windows.popup.popping>>. | |||
[[figure.advanced.windows.popup.popping]] | |||
.A Popup Window | |||
image::img/windows-popup.png[] | |||
[[advanced.windows.popup.target]] | |||
=== Popup Window Name (Target) | |||
The target name is one of the default HTML target names ( [parameter]#_new#, | |||
[parameter]#_blank#, [parameter]#_top#, etc.) or a custom target name. How the | |||
window is exactly opened depends on the browser. Browsers that support tabbed | |||
browsing can open the window in another tab, depending on the browser settings. | |||
[[advanced.windows.popup.url]] | |||
=== URL and Session | |||
The URL path for a popup window UI is by default determined from the UI class | |||
name, by prefixig it with " [literal]#++popup/++#". For example, for the example | |||
UI giver earlier, the URL would be | |||
[literal]#++/book-examples/book/popup/MyPopupUI++#. | |||
[[advanced.windows.popup-closing]] | |||
== Closing Popup Windows | |||
Besides closing popup windows from a native window close button, you can close | |||
them programmatically by calling the JavaScript [methodname]#close()# method as | |||
follows. | |||
[source, java] | |||
---- | |||
public class MyPopup extends UI { | |||
@Override | |||
protected void init(VaadinRequest request) { | |||
setContent(new Button("Close Window", event -> {// Java 8 | |||
// Close the popup | |||
JavaScript.eval("close()"); | |||
// Detach the UI from the session | |||
getUI().close(); | |||
})); | |||
} | |||
} | |||
---- | |||
@@ -0,0 +1,41 @@ | |||
[[advanced]] | |||
== Advanced Web Application Topics | |||
This chapter covers various features and topics often needed in applications. | |||
include::advanced-windows.asciidoc[leveloffset=+2] | |||
include::advanced-embedding.asciidoc[leveloffset=+2] | |||
include::advanced-debug.asciidoc[leveloffset=+2] | |||
include::advanced-requesthandler.asciidoc[leveloffset=+2] | |||
include::advanced-shortcuts.asciidoc[leveloffset=+2] | |||
include::advanced-printing.asciidoc[leveloffset=+2] | |||
include::advanced-gae.asciidoc[leveloffset=+2] | |||
include::advanced-security.asciidoc[leveloffset=+2] | |||
include::advanced-navigator.asciidoc[leveloffset=+2] | |||
include::advanced-architecture.asciidoc[leveloffset=+2] | |||
include::advanced-urifu.asciidoc[leveloffset=+2] | |||
include::advanced-dragndrop.asciidoc[leveloffset=+2] | |||
include::advanced-logging.asciidoc[leveloffset=+2] | |||
include::advanced-javascript.asciidoc[leveloffset=+2] | |||
include::advanced-global.asciidoc[leveloffset=+2] | |||
include::advanced-push.asciidoc[leveloffset=+2] | |||
include::advanced-cdi.asciidoc[leveloffset=+2] | |||
include::advanced-spring.asciidoc[leveloffset=+2] |
@@ -0,0 +1,424 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<!-- Created with Inkscape (http://www.inkscape.org/) --> | |||
<svg | |||
xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
xmlns:cc="http://creativecommons.org/ns#" | |||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" | |||
xmlns:xlink="http://www.w3.org/1999/xlink" | |||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
width="210mm" | |||
height="297mm" | |||
id="svg1901" | |||
sodipodi:version="0.32" | |||
inkscape:version="0.48.3.1 r9886" | |||
sodipodi:docname="debug-log.svg" | |||
inkscape:output_extension="org.inkscape.output.svg.inkscape" | |||
enable-background="new" | |||
version="1.1"> | |||
<sodipodi:namedview | |||
id="base" | |||
pagecolor="#ffffff" | |||
bordercolor="#666666" | |||
borderopacity="1.0" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:zoom="1.979899" | |||
inkscape:cx="461.10259" | |||
inkscape:cy="887.71455" | |||
inkscape:document-units="px" | |||
inkscape:current-layer="layer1" | |||
gridtolerance="10000" | |||
inkscape:window-width="1680" | |||
inkscape:window-height="1026" | |||
inkscape:window-x="236" | |||
inkscape:window-y="0" | |||
showgrid="true" | |||
inkscape:window-maximized="0" | |||
inkscape:snap-bbox="true" | |||
showguides="true" | |||
inkscape:guide-bbox="true"> | |||
<inkscape:grid | |||
type="xygrid" | |||
id="grid3942" | |||
empspacing="5" | |||
visible="true" | |||
enabled="true" | |||
snapvisiblegridlinesonly="true" | |||
spacingx="5px" | |||
spacingy="5px" /> | |||
<sodipodi:guide | |||
orientation="1,0" | |||
position="330,1000" | |||
id="guide4118" /> | |||
</sodipodi:namedview> | |||
<defs | |||
id="defs1903"> | |||
<linearGradient | |||
id="linearGradient4123"> | |||
<stop | |||
style="stop-color:#ffffff;stop-opacity:0;" | |||
offset="0" | |||
id="stop4125" /> | |||
<stop | |||
id="stop4131" | |||
offset="0.25" | |||
style="stop-color:#ffffff;stop-opacity:0.70161289;" /> | |||
<stop | |||
style="stop-color:#ffffff;stop-opacity:0.87903225;" | |||
offset="0.75" | |||
id="stop4133" /> | |||
<stop | |||
style="stop-color:#ffffff;stop-opacity:0;" | |||
offset="1" | |||
id="stop4127" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient3944" | |||
inkscape:collect="always"> | |||
<stop | |||
id="stop3946" | |||
offset="0" | |||
style="stop-color:#ff1515;stop-opacity:1;" /> | |||
<stop | |||
id="stop3948" | |||
offset="1" | |||
style="stop-color:#ff1515;stop-opacity:0;" /> | |||
</linearGradient> | |||
<marker | |||
style="overflow:visible;" | |||
id="Arrow2Mend" | |||
refX="0.0" | |||
refY="0.0" | |||
orient="auto" | |||
inkscape:stockid="Arrow2Mend"> | |||
<path | |||
transform="scale(0.6) rotate(180) translate(0,0)" | |||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " | |||
style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;" | |||
id="path3196" /> | |||
</marker> | |||
<inkscape:perspective | |||
id="perspective7" | |||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1" | |||
inkscape:vp_z="744.09448 : 526.18109 : 1" | |||
inkscape:vp_y="0 : 1000 : 0" | |||
inkscape:vp_x="0 : 526.18109 : 1" | |||
sodipodi:type="inkscape:persp3d" /> | |||
<inkscape:perspective | |||
sodipodi:type="inkscape:persp3d" | |||
inkscape:vp_x="0 : 526.18109 : 1" | |||
inkscape:vp_y="0 : 1000 : 0" | |||
inkscape:vp_z="744.09448 : 526.18109 : 1" | |||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1" | |||
id="perspective2464" /> | |||
<filter | |||
inkscape:label="filter1" | |||
id="filter2470"> | |||
<feGaussianBlur | |||
id="feGaussianBlur2472" | |||
stdDeviation="3.6554687499999998" | |||
result="result0" /> | |||
<feFlood | |||
id="feFlood3438" | |||
in="SourceGraphic" | |||
flood-opacity="0.49289099526066349" | |||
flood-color="rgb(139,139,139)" | |||
result="result1" /> | |||
<feBlend | |||
blend="normal" | |||
id="feBlend3440" | |||
in="result0" | |||
mode="normal" | |||
in2="result1" /> | |||
</filter> | |||
<linearGradient | |||
gradientUnits="userSpaceOnUse" | |||
y2="66.994687" | |||
x2="345.28571" | |||
y1="66.994687" | |||
x1="228.07906" | |||
id="linearGradient3950" | |||
xlink:href="#linearGradient3944" | |||
inkscape:collect="always" /> | |||
<marker | |||
style="overflow:visible;" | |||
id="Arrow2MendL" | |||
refX="0.0" | |||
refY="0.0" | |||
orient="auto" | |||
inkscape:stockid="Arrow2MendL"> | |||
<path | |||
transform="scale(0.6) rotate(180) translate(0,0)" | |||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " | |||
style="stroke-linejoin:round;font-size:12.0;fill-rule:evenodd;stroke:url(#linearGradient3950);stroke-width:0.62500000;fill:url(#linearGradient3950)" | |||
id="path3967" /> | |||
</marker> | |||
<clipPath | |||
clipPathUnits="userSpaceOnUse" | |||
id="clipPath3442"> | |||
<rect | |||
y="105.21935" | |||
x="162.85715" | |||
height="82.142815" | |||
width="175.71426" | |||
id="rect3444" | |||
style="opacity:1;fill:#545454;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.29999998;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | |||
</clipPath> | |||
<marker | |||
id="marker52016" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker52016-3" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010-5" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012-6" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014-4" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker52016-5" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010-1" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012-3" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014-2" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker52016-0" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010-4" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012-9" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014-3" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker52016-03" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010-17" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012-8" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014-9" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker52016-1" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010-2" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012-0" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014-8" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker52016-038" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010-49" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012-7" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014-6" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker52016-9" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010-47" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012-2" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014-7" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
</defs> | |||
<metadata | |||
id="metadata1906"> | |||
<rdf:RDF> | |||
<cc:Work | |||
rdf:about=""> | |||
<dc:format>image/svg+xml</dc:format> | |||
<dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
<dc:title></dc:title> | |||
</cc:Work> | |||
</rdf:RDF> | |||
</metadata> | |||
<g | |||
style="opacity:1" | |||
id="layer1" | |||
inkscape:groupmode="layer" | |||
inkscape:label="Taso 1"> | |||
<image | |||
y="177.36218" | |||
x="75" | |||
id="image3126" | |||
xlink:href="file:///home/magi/itmill/book-7/manual/img/debug/debug-window.png" | |||
height="186.25829" | |||
width="375" /> | |||
<path | |||
style="fill:none;stroke:#f39300;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#marker52016)" | |||
d="m 165,127.36218 -67.272842,0 0,64.74746" | |||
id="path4833-3-7-55" | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="ccc" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text2421-3" | |||
y="132.63379" | |||
x="174.136" | |||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
y="132.63379" | |||
x="174.136" | |||
id="tspan2423-6" | |||
sodipodi:role="line">Clear Log</tspan></text> | |||
<path | |||
style="fill:none;stroke:#f39300;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#marker52016)" | |||
d="m 165,152.36218 -43.28302,0 0,40" | |||
id="path4833-3-7-55-6" | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="ccc" /> | |||
<path | |||
style="fill:none;stroke:#f39300;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#marker52016)" | |||
d="m 165,177.36218 -20,0 0,15" | |||
id="path4833-3-7-55-6-2" | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="ccc" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text2421-3-3" | |||
y="158.80699" | |||
x="173.56" | |||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
y="158.80699" | |||
x="173.56" | |||
id="tspan2423-6-9" | |||
sodipodi:role="line">Reset Timer</tspan></text> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text2421-3-3-2" | |||
y="183.89645" | |||
x="174.226" | |||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
y="183.89645" | |||
x="174.226" | |||
id="tspan2423-6-9-6" | |||
sodipodi:role="line">Scroll Lock</tspan></text> | |||
</g> | |||
</svg> |
@@ -0,0 +1,608 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<!-- Created with Inkscape (http://www.inkscape.org/) --> | |||
<svg | |||
xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
xmlns:cc="http://creativecommons.org/ns#" | |||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" | |||
xmlns:xlink="http://www.w3.org/1999/xlink" | |||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
width="210mm" | |||
height="297mm" | |||
id="svg1901" | |||
sodipodi:version="0.32" | |||
inkscape:version="0.48.3.1 r9886" | |||
sodipodi:docname="debug-window-annotated.svg" | |||
inkscape:output_extension="org.inkscape.output.svg.inkscape" | |||
enable-background="new" | |||
version="1.1"> | |||
<sodipodi:namedview | |||
id="base" | |||
pagecolor="#ffffff" | |||
bordercolor="#666666" | |||
borderopacity="1.0" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:zoom="1.4" | |||
inkscape:cx="219.4901" | |||
inkscape:cy="836.30592" | |||
inkscape:document-units="px" | |||
inkscape:current-layer="layer1" | |||
gridtolerance="10000" | |||
inkscape:window-width="1680" | |||
inkscape:window-height="1026" | |||
inkscape:window-x="236" | |||
inkscape:window-y="0" | |||
showgrid="true" | |||
inkscape:window-maximized="0" | |||
inkscape:snap-bbox="true" | |||
showguides="true" | |||
inkscape:guide-bbox="true"> | |||
<inkscape:grid | |||
type="xygrid" | |||
id="grid3942" | |||
empspacing="5" | |||
visible="true" | |||
enabled="true" | |||
snapvisiblegridlinesonly="true" | |||
spacingx="5px" | |||
spacingy="5px" /> | |||
<sodipodi:guide | |||
orientation="1,0" | |||
position="330,1000" | |||
id="guide4118" /> | |||
</sodipodi:namedview> | |||
<defs | |||
id="defs1903"> | |||
<linearGradient | |||
id="linearGradient5902"> | |||
<stop | |||
style="stop-color:#2d2d2d;stop-opacity:1;" | |||
offset="0" | |||
id="stop5904" /> | |||
<stop | |||
style="stop-color:#2d2d2d;stop-opacity:0;" | |||
offset="1" | |||
id="stop5906" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient4123"> | |||
<stop | |||
style="stop-color:#ffffff;stop-opacity:0;" | |||
offset="0" | |||
id="stop4125" /> | |||
<stop | |||
id="stop4131" | |||
offset="0.25" | |||
style="stop-color:#ffffff;stop-opacity:0.70161289;" /> | |||
<stop | |||
style="stop-color:#ffffff;stop-opacity:0.87903225;" | |||
offset="0.75" | |||
id="stop4133" /> | |||
<stop | |||
style="stop-color:#ffffff;stop-opacity:0;" | |||
offset="1" | |||
id="stop4127" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient3944" | |||
inkscape:collect="always"> | |||
<stop | |||
id="stop3946" | |||
offset="0" | |||
style="stop-color:#ff1515;stop-opacity:1;" /> | |||
<stop | |||
id="stop3948" | |||
offset="1" | |||
style="stop-color:#ff1515;stop-opacity:0;" /> | |||
</linearGradient> | |||
<marker | |||
style="overflow:visible;" | |||
id="Arrow2Mend" | |||
refX="0.0" | |||
refY="0.0" | |||
orient="auto" | |||
inkscape:stockid="Arrow2Mend"> | |||
<path | |||
transform="scale(0.6) rotate(180) translate(0,0)" | |||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " | |||
style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;" | |||
id="path3196" /> | |||
</marker> | |||
<inkscape:perspective | |||
id="perspective7" | |||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1" | |||
inkscape:vp_z="744.09448 : 526.18109 : 1" | |||
inkscape:vp_y="0 : 1000 : 0" | |||
inkscape:vp_x="0 : 526.18109 : 1" | |||
sodipodi:type="inkscape:persp3d" /> | |||
<inkscape:perspective | |||
sodipodi:type="inkscape:persp3d" | |||
inkscape:vp_x="0 : 526.18109 : 1" | |||
inkscape:vp_y="0 : 1000 : 0" | |||
inkscape:vp_z="744.09448 : 526.18109 : 1" | |||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1" | |||
id="perspective2464" /> | |||
<filter | |||
inkscape:label="filter1" | |||
id="filter2470"> | |||
<feGaussianBlur | |||
id="feGaussianBlur2472" | |||
stdDeviation="3.6554687499999998" | |||
result="result0" /> | |||
<feFlood | |||
id="feFlood3438" | |||
in="SourceGraphic" | |||
flood-opacity="0.49289099526066349" | |||
flood-color="rgb(139,139,139)" | |||
result="result1" /> | |||
<feBlend | |||
blend="normal" | |||
id="feBlend3440" | |||
in="result0" | |||
mode="normal" | |||
in2="result1" /> | |||
</filter> | |||
<linearGradient | |||
gradientUnits="userSpaceOnUse" | |||
y2="66.994687" | |||
x2="345.28571" | |||
y1="66.994687" | |||
x1="228.07906" | |||
id="linearGradient3950" | |||
xlink:href="#linearGradient3944" | |||
inkscape:collect="always" /> | |||
<marker | |||
style="overflow:visible;" | |||
id="Arrow2MendL" | |||
refX="0.0" | |||
refY="0.0" | |||
orient="auto" | |||
inkscape:stockid="Arrow2MendL"> | |||
<path | |||
transform="scale(0.6) rotate(180) translate(0,0)" | |||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " | |||
style="stroke-linejoin:round;font-size:12.0;fill-rule:evenodd;stroke:url(#linearGradient3950);stroke-width:0.62500000;fill:url(#linearGradient3950)" | |||
id="path3967" /> | |||
</marker> | |||
<clipPath | |||
clipPathUnits="userSpaceOnUse" | |||
id="clipPath3442"> | |||
<rect | |||
y="105.21935" | |||
x="162.85715" | |||
height="82.142815" | |||
width="175.71426" | |||
id="rect3444" | |||
style="opacity:1;fill:#545454;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.29999998;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | |||
</clipPath> | |||
<marker | |||
id="marker52016" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker52016-3" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010-5" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012-6" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014-4" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker52016-5" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010-1" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012-3" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014-2" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker52016-0" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010-4" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012-9" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014-3" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker52016-03" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010-17" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012-8" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014-9" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker52016-1" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010-2" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012-0" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014-8" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker52016-038" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010-49" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012-7" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014-6" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker52016-9" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010-47" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012-2" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014-7" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<linearGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient5902" | |||
id="linearGradient5908" | |||
x1="260" | |||
y1="362.36218" | |||
x2="260" | |||
y2="202.36218" | |||
gradientUnits="userSpaceOnUse" /> | |||
<linearGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient5902" | |||
id="linearGradient5950" | |||
gradientUnits="userSpaceOnUse" | |||
x1="260" | |||
y1="362.36218" | |||
x2="260" | |||
y2="202.36218" | |||
gradientTransform="translate(130,0)" /> | |||
<filter | |||
id="filter5952" | |||
inkscape:menu-tooltip="Make the lightest parts of the object progressively transparent" | |||
inkscape:menu="Transparency utilities" | |||
inkscape:label="Light eraser" | |||
height="1" | |||
width="1" | |||
y="0" | |||
x="0" | |||
color-interpolation-filters="sRGB"> | |||
<feColorMatrix | |||
id="feColorMatrix5954" | |||
result="result14" | |||
type="luminanceToAlpha" | |||
in="SourceGraphic" /> | |||
<feComposite | |||
id="feComposite5956" | |||
in2="result14" | |||
in="SourceGraphic" | |||
result="fbSourceGraphic" | |||
operator="out" /> | |||
<feBlend | |||
id="feBlend5958" | |||
in2="fbSourceGraphic" | |||
mode="normal" | |||
result="result15" /> | |||
</filter> | |||
<marker | |||
id="marker52016-35" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010-7" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012-20" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014-76" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker52016-7" | |||
orient="auto" | |||
markerHeight="5.7450786" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g52010-6" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path52012-4" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path52014-48" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
</defs> | |||
<metadata | |||
id="metadata1906"> | |||
<rdf:RDF> | |||
<cc:Work | |||
rdf:about=""> | |||
<dc:format>image/svg+xml</dc:format> | |||
<dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
</cc:Work> | |||
</rdf:RDF> | |||
</metadata> | |||
<g | |||
style="opacity:1" | |||
id="layer1" | |||
inkscape:groupmode="layer" | |||
inkscape:label="Taso 1"> | |||
<image | |||
y="177.36218" | |||
x="75" | |||
id="image3126" | |||
xlink:href="file:///home/magi/itmill/book-7/manual/img/debug/debug-window.png" | |||
height="186.25829" | |||
width="375" /> | |||
<path | |||
style="fill:none;stroke:#f39300;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#marker52016)" | |||
d="m 310,2.3621826 -15.71428,0 0,169.9999974" | |||
id="path4833-3-7-55-7" | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="ccc" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text2421-3-8" | |||
y="7.633739" | |||
x="313.54199" | |||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
y="7.633739" | |||
x="313.54199" | |||
id="tspan2423-6-2" | |||
sodipodi:role="line">Debug message log</tspan></text> | |||
<path | |||
style="fill:none;stroke:#f39300;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#marker52016)" | |||
d="m 335,27.362183 -17.23225,0 0,144.999997" | |||
id="path4833-3-7-55-7-3" | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="ccc" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text2421-3-8-9" | |||
y="33.57235" | |||
x="339.04599" | |||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
y="33.57235" | |||
x="339.04599" | |||
id="tspan2423-6-2-5" | |||
sodipodi:role="line">General info</tspan></text> | |||
<path | |||
style="fill:none;stroke:#f39300;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#marker52016)" | |||
d="m 355,52.36218 -14.36865,0 0,120" | |||
id="path4833-3-7-55-7-3-6" | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="ccc" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text2421-3-8-9-8" | |||
y="57.392303" | |||
x="359.13599" | |||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
y="57.392303" | |||
x="359.13599" | |||
id="tspan2423-6-2-5-5" | |||
sodipodi:role="line">Component hierarchy</tspan></text> | |||
<path | |||
style="fill:none;stroke:#f39300;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#marker52016)" | |||
d="m 380,77.36218 -16.76778,0 0,95" | |||
id="path4833-3-7-55-7-3-6-5" | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="ccc" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text2421-3-8-9-4" | |||
y="83.878448" | |||
x="384.04599" | |||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
y="83.878448" | |||
x="384.04599" | |||
id="tspan2423-6-2-5-2" | |||
sodipodi:role="line">Communication</tspan></text> | |||
<path | |||
style="fill:none;stroke:#f39300;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#marker52016)" | |||
d="m 403.91437,102.36218 -16.76778,0 0,70" | |||
id="path4833-3-7-55-7-3-6-5-8" | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="ccc" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text2421-3-8-9-4-1" | |||
y="109.05702" | |||
x="409.13599" | |||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
y="109.05702" | |||
x="409.13599" | |||
id="tspan2423-6-2-5-2-6" | |||
sodipodi:role="line">Menu</tspan></text> | |||
<path | |||
style="fill:none;stroke:#f39300;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#marker52016)" | |||
d="m 425,127.36218 -14.49492,0 0,45" | |||
id="path4833-3-7-55-7-3-6-5-8-9" | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="ccc" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text2421-3-8-9-4-1-2" | |||
y="133.71503" | |||
x="428.59601" | |||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
y="133.71503" | |||
x="428.59601" | |||
id="tspan2423-6-2-5-2-6-6" | |||
sodipodi:role="line">Minimize</tspan></text> | |||
<path | |||
style="fill:none;stroke:#f39300;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#marker52016)" | |||
d="m 445,152.36218 -11.60713,0 0,20" | |||
id="path4833-3-7-55-7-3-6-5-8-9-6" | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="ccc" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text2421-3-8-9-4-1-2-9" | |||
y="159.07217" | |||
x="448.59601" | |||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
y="159.07217" | |||
x="448.59601" | |||
id="tspan2423-6-2-5-2-6-6-0" | |||
sodipodi:role="line">Close</tspan></text> | |||
<rect | |||
style="fill:#ffffff;fill-opacity:0.63793105;stroke:none" | |||
id="rect6062" | |||
width="345" | |||
height="120" | |||
x="85" | |||
y="222.36218" | |||
ry="3.7880721" /> | |||
<rect | |||
style="fill:#ffffff;fill-opacity:0.67672414;stroke:none" | |||
id="rect6062-9" | |||
width="125" | |||
height="15" | |||
x="85" | |||
y="202.36218" | |||
ry="3.7880721" /> | |||
</g> | |||
</svg> |
@@ -0,0 +1,832 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<!-- Created with Inkscape (http://www.inkscape.org/) --> | |||
<svg | |||
xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
xmlns:cc="http://creativecommons.org/ns#" | |||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" | |||
xmlns:xlink="http://www.w3.org/1999/xlink" | |||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
version="1.1" | |||
sodipodi:modified="true" | |||
inkscape:output_extension="org.inkscape.output.svg.inkscape" | |||
sodipodi:docname="mvp-pattern.svg" | |||
inkscape:version="0.48.2 r9819" | |||
sodipodi:version="0.32" | |||
id="svg1901" | |||
height="297mm" | |||
width="210mm"> | |||
<sodipodi:namedview | |||
id="base" | |||
pagecolor="#ffffff" | |||
bordercolor="#666666" | |||
borderopacity="1.0" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:zoom="2" | |||
inkscape:cx="296.58974" | |||
inkscape:cy="799.23501" | |||
inkscape:document-units="px" | |||
inkscape:current-layer="g6951-6" | |||
gridtolerance="10000" | |||
inkscape:window-width="1680" | |||
inkscape:window-height="1027" | |||
inkscape:window-x="-4" | |||
inkscape:window-y="-4" | |||
showgrid="true" | |||
showguides="true" | |||
inkscape:connector-spacing="10" | |||
inkscape:guide-bbox="true" | |||
inkscape:window-maximized="1"> | |||
<inkscape:grid | |||
spacingy="5px" | |||
spacingx="5px" | |||
snapvisiblegridlinesonly="true" | |||
enabled="true" | |||
visible="true" | |||
empspacing="5" | |||
id="grid3123" | |||
type="xygrid" /> | |||
</sodipodi:namedview> | |||
<defs | |||
id="defs1903"> | |||
<marker | |||
style="overflow:visible" | |||
id="DotS" | |||
refX="0.0" | |||
refY="0.0" | |||
orient="auto" | |||
inkscape:stockid="DotS"> | |||
<path | |||
transform="scale(0.2) translate(7.4, 1)" | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;marker-end:none" | |||
d="M -2.5,-1.0 C -2.5,1.7600000 -4.7400000,4.0 -7.5,4.0 C -10.260000,4.0 -12.5,1.7600000 -12.5,-1.0 C -12.5,-3.7600000 -10.260000,-6.0 -7.5,-6.0 C -4.7400000,-6.0 -2.5,-3.7600000 -2.5,-1.0 z " | |||
id="path4833" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="DotM" | |||
refX="0.0" | |||
refY="0.0" | |||
orient="auto" | |||
inkscape:stockid="DotM"> | |||
<path | |||
transform="scale(0.4) translate(7.4, 1)" | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;marker-end:none" | |||
d="M -2.5,-1.0 C -2.5,1.7600000 -4.7400000,4.0 -7.5,4.0 C -10.260000,4.0 -12.5,1.7600000 -12.5,-1.0 C -12.5,-3.7600000 -10.260000,-6.0 -7.5,-6.0 C -4.7400000,-6.0 -2.5,-3.7600000 -2.5,-1.0 z " | |||
id="path4830" /> | |||
</marker> | |||
<marker | |||
markerWidth="4.6297355" | |||
markerHeight="5.7450781" | |||
orient="auto" | |||
id="marker44971"> | |||
<g | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)" | |||
id="g18059"> | |||
<path | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1" | |||
d="M 370,508.65625 C 369.13933,508.715 368.39056,509.27755 368.09375,510.09375 C 367.82399,510.83551 368.03605,511.62868 368.53125,512.21875 L 366.78125,512.21875 C 366.73884,512.21408 366.69882,512.22093 366.65625,512.21875 L 366.65625,516.59375 L 366.78125,516.59375 L 368.53125,516.59375 C 367.85229,517.45345 367.83424,518.70924 368.625,519.5 C 369.47591,520.35091 370.89909,520.35091 371.75,519.5 L 375.09375,516.125 C 375.12672,516.09552 375.15802,516.06422 375.1875,516.03125 C 375.21972,516.01191 375.25101,515.99105 375.28125,515.96875 C 375.28162,515.96839 375.49976,515.68796 375.5,515.6875 C 375.50005,515.68741 375.49338,515.64282 375.5,515.625 C 375.5011,515.62203 375.53002,515.62832 375.53125,515.625 C 375.57039,515.57293 375.58228,515.57321 375.625,515.5 C 375.76199,515.26524 375.79184,515.12809 375.78125,515.15625 C 375.81807,515.06473 375.79977,515.04374 375.8125,515 C 375.82311,514.98978 375.83353,514.97936 375.84375,514.96875 C 375.90379,514.74477 375.93181,514.45186 375.90625,514.1875 C 375.89266,513.98387 375.84739,513.88985 375.84375,513.875 C 375.84389,513.86458 375.84389,513.85417 375.84375,513.84375 C 375.86975,513.94071 375.85901,513.85978 375.75,513.59375 C 375.69753,513.46336 375.66014,513.37439 375.625,513.3125 C 375.57262,513.22275 375.49154,513.05015 375.28125,512.84375 L 371.75,509.3125 C 371.29355,508.82579 370.66491,508.60087 370,508.65625 z" | |||
id="path18061" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" /> | |||
<path | |||
style="fill:#d9d9cd;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | |||
d="M 366.65625,515.40625 L 371.28125,515.40625 L 369.46875,517.21875 C 369.0718,517.6157 369.0718,518.2593 369.46875,518.65625 C 369.8657,519.0532 370.5093,519.0532 370.90625,518.65625 L 374.34375,515.1875 L 374.4375,515.125 C 374.44343,515.11918 374.43171,515.09972 374.4375,515.09375 C 374.49291,515.03659 374.5526,514.97676 374.59375,514.90625 C 374.62239,514.85717 374.63663,514.80216 374.65625,514.75 C 374.66861,514.71928 374.67831,514.68783 374.6875,514.65625 C 374.71862,514.54015 374.73024,514.43132 374.71875,514.3125 C 374.71489,514.25466 374.70138,514.21285 374.6875,514.15625 C 374.6766,514.1156 374.67237,514.07059 374.65625,514.03125 C 374.63982,513.99042 374.61578,513.94505 374.59375,513.90625 C 374.5483,513.82838 374.50015,513.74899 374.4375,513.6875 L 370.90625,510.15625 C 370.69734,509.93349 370.39809,509.8184 370.09375,509.84375 C 369.69897,509.8707 369.35398,510.12813 369.21875,510.5 C 369.08351,510.87187 369.18349,511.28826 369.46875,511.5625 L 371.34375,513.40625 L 366.65625,513.40625" | |||
id="path18063" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" /> | |||
</g> | |||
</marker> | |||
<marker | |||
markerWidth="4.6297302" | |||
markerHeight="5.7450776" | |||
orient="auto" | |||
id="marker18095"> | |||
<g | |||
transform="matrix(0.5,0,0,0.5,-185.64298,-257.19655)" | |||
id="g11064"> | |||
<path | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1" | |||
d="M 370,508.65625 C 369.13933,508.715 368.39056,509.27755 368.09375,510.09375 C 367.82399,510.83551 368.03605,511.62868 368.53125,512.21875 L 366.78125,512.21875 C 366.73884,512.21408 366.69882,512.22093 366.65625,512.21875 L 366.65625,516.59375 L 366.78125,516.59375 L 368.53125,516.59375 C 367.85229,517.45345 367.83424,518.70924 368.625,519.5 C 369.47591,520.35091 370.89909,520.35091 371.75,519.5 L 375.09375,516.125 C 375.12672,516.09552 375.15802,516.06422 375.1875,516.03125 C 375.21972,516.01191 375.25101,515.99105 375.28125,515.96875 C 375.28162,515.96839 375.49976,515.68796 375.5,515.6875 C 375.50005,515.68741 375.49338,515.64282 375.5,515.625 C 375.5011,515.62203 375.53002,515.62832 375.53125,515.625 C 375.57039,515.57293 375.58228,515.57321 375.625,515.5 C 375.76199,515.26524 375.79184,515.12809 375.78125,515.15625 C 375.81807,515.06473 375.79977,515.04374 375.8125,515 C 375.82311,514.98978 375.83353,514.97936 375.84375,514.96875 C 375.90379,514.74477 375.93181,514.45186 375.90625,514.1875 C 375.89266,513.98387 375.84739,513.88985 375.84375,513.875 C 375.84389,513.86458 375.84389,513.85417 375.84375,513.84375 C 375.86975,513.94071 375.85901,513.85978 375.75,513.59375 C 375.69753,513.46336 375.66014,513.37439 375.625,513.3125 C 375.57262,513.22275 375.49154,513.05015 375.28125,512.84375 L 371.75,509.3125 C 371.29355,508.82579 370.66491,508.60087 370,508.65625 z" | |||
id="path11050" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" /> | |||
<path | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | |||
d="M 366.65625,515.40625 L 371.28125,515.40625 L 369.46875,517.21875 C 369.0718,517.6157 369.0718,518.2593 369.46875,518.65625 C 369.8657,519.0532 370.5093,519.0532 370.90625,518.65625 L 374.34375,515.1875 L 374.4375,515.125 C 374.44343,515.11918 374.43171,515.09972 374.4375,515.09375 C 374.49291,515.03659 374.5526,514.97676 374.59375,514.90625 C 374.62239,514.85717 374.63663,514.80216 374.65625,514.75 C 374.66861,514.71928 374.67831,514.68783 374.6875,514.65625 C 374.71862,514.54015 374.73024,514.43132 374.71875,514.3125 C 374.71489,514.25466 374.70138,514.21285 374.6875,514.15625 C 374.6766,514.1156 374.67237,514.07059 374.65625,514.03125 C 374.63982,513.99042 374.61578,513.94505 374.59375,513.90625 C 374.5483,513.82838 374.50015,513.74899 374.4375,513.6875 L 370.90625,510.15625 C 370.69734,509.93349 370.39809,509.8184 370.09375,509.84375 C 369.69897,509.8707 369.35398,510.12813 369.21875,510.5 C 369.08351,510.87187 369.18349,511.28826 369.46875,511.5625 L 371.34375,513.40625 L 366.65625,513.40625" | |||
id="path11035" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" /> | |||
</g> | |||
</marker> | |||
<inkscape:perspective | |||
id="perspective7604" | |||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1" | |||
inkscape:vp_z="744.09448 : 526.18109 : 1" | |||
inkscape:vp_y="0 : 1000 : 0" | |||
inkscape:vp_x="0 : 526.18109 : 1" | |||
sodipodi:type="inkscape:persp3d" /> | |||
<linearGradient | |||
id="linearGradient11516"> | |||
<stop | |||
style="stop-color:#ffffff;stop-opacity:1" | |||
offset="0" | |||
id="stop11518" /> | |||
<stop | |||
style="stop-color:#a090e7;stop-opacity:1" | |||
offset="1" | |||
id="stop11520" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient11508"> | |||
<stop | |||
style="stop-color:#ffffff;stop-opacity:1;" | |||
offset="0" | |||
id="stop11510" /> | |||
<stop | |||
style="stop-color:#e27979;stop-opacity:1" | |||
offset="1" | |||
id="stop11512" /> | |||
</linearGradient> | |||
<marker | |||
style="overflow:visible" | |||
id="DiamondL" | |||
refX="0.0" | |||
refY="0.0" | |||
orient="auto" | |||
inkscape:stockid="DiamondL"> | |||
<path | |||
transform="scale(0.8)" | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" | |||
d="M 0,-7.0710768 L -7.0710894,0 L 0,7.0710589 L 7.0710462,0 L 0,-7.0710768 z " | |||
id="path4404" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="DiamondEmpty" | |||
refX="0.0" | |||
refY="0.0" | |||
orient="auto"> | |||
<path | |||
transform="scale(1.0) translate(-5,0)" | |||
style="fill-rule:evenodd;fill:#ffffff;stroke:#000000;stroke-width:1.0pt;marker-start:none" | |||
d="M 0,-5 L -5,0 L 0,5 L 5,0 L 0,-5 z " | |||
id="path7" /> | |||
</marker> | |||
<linearGradient | |||
id="linearGradient3286"> | |||
<stop | |||
id="stop3288" | |||
offset="0" | |||
style="stop-color:#ffffff;stop-opacity:1;" /> | |||
<stop | |||
id="stop3290" | |||
offset="1" | |||
style="stop-color:#79e291;stop-opacity:1;" /> | |||
</linearGradient> | |||
<marker | |||
style="overflow:visible;" | |||
id="EmptyArrow" | |||
refX="0.0" | |||
refY="0.0" | |||
orient="auto"> | |||
<path | |||
transform="scale(1.0) rotate(180) translate(10,0)" | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" | |||
d="M 0.0,0.0 L 0.0,-5.0 L -12.5,0.0 L 0.0,5.0 L 0.0,0.0 z M -0.5,0.0 L -0.5,-4.5 L -12.0,0.0 L -0.5,4.5 L -0.5,0.0 z" | |||
id="path9" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible;" | |||
id="EmptyArrow2" | |||
refX="0.0" | |||
refY="0.0" | |||
orient="auto"> | |||
<path | |||
transform="scale(1.0) rotate(180) translate(10,0)" | |||
style="fill-rule:evenodd;fill:#ffffff;stroke:#000000;stroke-width:1.0pt;marker-start:none;" | |||
d="M 0.0,0.0 L 0.0,-5.0 L -10.0,0.0 L 0.0,5.0 L 0.0,0.0 z" | |||
id="path13" /> | |||
</marker> | |||
<linearGradient | |||
id="linearGradient19816"> | |||
<stop | |||
style="stop-color:#ffffff;stop-opacity:1;" | |||
offset="0" | |||
id="stop19818" /> | |||
<stop | |||
style="stop-color:#e7e790;stop-opacity:1;" | |||
offset="1" | |||
id="stop19820" /> | |||
</linearGradient> | |||
<marker | |||
style="overflow:visible;" | |||
id="Arrow2Lend" | |||
refX="0.0" | |||
refY="0.0" | |||
orient="auto" | |||
inkscape:stockid="Arrow2Lend"> | |||
<path | |||
transform="scale(1.1) rotate(180) translate(1,0)" | |||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " | |||
style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;" | |||
id="path16811" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible;" | |||
id="Arrow1Lend" | |||
refX="0.0" | |||
refY="0.0" | |||
orient="auto" | |||
inkscape:stockid="Arrow1Lend"> | |||
<path | |||
transform="scale(0.8) rotate(180) translate(12.5,0)" | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" | |||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " | |||
id="path16829" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleOutM" | |||
refX="0.0" | |||
refY="0.0" | |||
orient="auto" | |||
inkscape:stockid="TriangleOutM"> | |||
<path | |||
transform="scale(0.4)" | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" | |||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z " | |||
id="path16731" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleInL" | |||
refX="0.0" | |||
refY="0.0" | |||
orient="auto" | |||
inkscape:stockid="TriangleInL"> | |||
<path | |||
transform="scale(-0.8)" | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" | |||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z " | |||
id="path16743" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleOutL" | |||
refX="0.0" | |||
refY="0.0" | |||
orient="auto" | |||
inkscape:stockid="TriangleOutL"> | |||
<path | |||
transform="scale(0.8)" | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" | |||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z " | |||
id="path16734" /> | |||
</marker> | |||
<linearGradient | |||
id="linearGradient9263"> | |||
<stop | |||
id="stop9265" | |||
offset="0" | |||
style="stop-color:#000000;stop-opacity:0" /> | |||
<stop | |||
id="stop9267" | |||
offset="1" | |||
style="stop-color:#000000;stop-opacity:0;" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient7299"> | |||
<stop | |||
id="stop7301" | |||
offset="0" | |||
style="stop-color:#ffffff;stop-opacity:1" /> | |||
<stop | |||
id="stop7303" | |||
offset="1" | |||
style="stop-color:#a090e7;stop-opacity:1" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient5349"> | |||
<stop | |||
id="stop5351" | |||
offset="0" | |||
style="stop-color:#000000;stop-opacity:1;" /> | |||
<stop | |||
id="stop5353" | |||
offset="1" | |||
style="stop-color:#000000;stop-opacity:0;" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient4152"> | |||
<stop | |||
id="stop4154" | |||
offset="0" | |||
style="stop-color:#6b6bff;stop-opacity:1;" /> | |||
<stop | |||
id="stop4156" | |||
offset="1" | |||
style="stop-color:#6b6bff;stop-opacity:0;" /> | |||
</linearGradient> | |||
<linearGradient | |||
gradientUnits="userSpaceOnUse" | |||
y2="148.38934" | |||
x2="389.01985" | |||
y1="148.38934" | |||
x1="96.085953" | |||
id="linearGradient5355" | |||
xlink:href="#linearGradient5349" | |||
inkscape:collect="always" /> | |||
<radialGradient | |||
r="109.42857" | |||
fy="97.300964" | |||
fx="-147.5" | |||
cy="97.300964" | |||
cx="-147.5" | |||
gradientTransform="matrix(1.3208501,2.3843471e-3,-3.1056446e-3,0.596383,334.93437,78.721097)" | |||
gradientUnits="userSpaceOnUse" | |||
id="radialGradient11602" | |||
xlink:href="#linearGradient19816" | |||
inkscape:collect="always" /> | |||
<radialGradient | |||
r="109.42857" | |||
fy="97.300964" | |||
fx="-147.5" | |||
cy="97.300964" | |||
cx="-147.5" | |||
gradientTransform="matrix(0.9214039,2.3896193e-3,-2.166448e-3,0.5977017,541.12253,30.198804)" | |||
gradientUnits="userSpaceOnUse" | |||
id="radialGradient3268" | |||
xlink:href="#linearGradient19816" | |||
inkscape:collect="always" /> | |||
<radialGradient | |||
r="109.42857" | |||
fy="97.300964" | |||
fx="-147.5" | |||
cy="97.300964" | |||
cx="-147.5" | |||
gradientTransform="matrix(1.3208501,2.3843471e-3,-3.1056446e-3,0.596383,334.93437,78.721097)" | |||
gradientUnits="userSpaceOnUse" | |||
id="radialGradient3270" | |||
xlink:href="#linearGradient7299" | |||
inkscape:collect="always" /> | |||
<radialGradient | |||
r="109.42857" | |||
fy="97.300964" | |||
fx="-147.5" | |||
cy="97.300964" | |||
cx="-147.5" | |||
gradientTransform="matrix(1.6000725,2.3808346e-3,-3.7621654e-3,0.5955044,664.61868,-4.8275956)" | |||
gradientUnits="userSpaceOnUse" | |||
id="radialGradient3272" | |||
xlink:href="#linearGradient19816" | |||
inkscape:collect="always" /> | |||
<radialGradient | |||
r="109.42857" | |||
fy="97.300964" | |||
fx="-147.5" | |||
cy="97.300964" | |||
cx="-147.5" | |||
gradientTransform="matrix(1.3208501,2.3843471e-3,-3.1056446e-3,0.596383,334.93437,78.721097)" | |||
gradientUnits="userSpaceOnUse" | |||
id="radialGradient3274" | |||
xlink:href="#linearGradient7299" | |||
inkscape:collect="always" /> | |||
<radialGradient | |||
r="109.42857" | |||
fy="97.300964" | |||
fx="-147.5" | |||
cy="97.300964" | |||
cx="-147.5" | |||
gradientTransform="matrix(1.3208501,2.3843471e-3,-3.1056446e-3,0.596383,334.93437,78.721097)" | |||
gradientUnits="userSpaceOnUse" | |||
id="radialGradient3276" | |||
xlink:href="#linearGradient7299" | |||
inkscape:collect="always" /> | |||
<radialGradient | |||
r="109.42857" | |||
fy="97.300964" | |||
fx="-147.5" | |||
cy="97.300964" | |||
cx="-147.5" | |||
gradientTransform="matrix(1.3208501,2.3843471e-3,-3.1056446e-3,0.596383,334.93437,78.721097)" | |||
gradientUnits="userSpaceOnUse" | |||
id="radialGradient3278" | |||
xlink:href="#linearGradient7299" | |||
inkscape:collect="always" /> | |||
<radialGradient | |||
r="109.42857" | |||
fy="97.300964" | |||
fx="-147.5" | |||
cy="97.300964" | |||
cx="-147.5" | |||
gradientTransform="matrix(1.3208501,2.3843471e-3,-3.1056446e-3,0.596383,334.93437,78.721097)" | |||
gradientUnits="userSpaceOnUse" | |||
id="radialGradient3280" | |||
xlink:href="#linearGradient7299" | |||
inkscape:collect="always" /> | |||
<marker | |||
markerWidth="4.6297355" | |||
markerHeight="5.7450781" | |||
orient="auto" | |||
id="marker44971-5"> | |||
<g | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)" | |||
id="g18059-9"> | |||
<path | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
id="path18061-1" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
style="fill:#d9d9cd;fill-opacity:1;fill-rule:evenodd;stroke:none" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
id="path18063-4" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
inkscape:connector-curvature="0" /> | |||
</g> | |||
</marker> | |||
<marker | |||
markerWidth="4.6297302" | |||
markerHeight="5.7450776" | |||
orient="auto" | |||
id="marker18095-3"> | |||
<g | |||
transform="matrix(0.5,0,0,0.5,-185.64298,-257.19655)" | |||
id="g11064-5"> | |||
<path | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
id="path11050-8" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:evenodd;stroke:none" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
id="path11035-2" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
inkscape:connector-curvature="0" /> | |||
</g> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="DotSC" | |||
refX="0.0" | |||
refY="0.0" | |||
orient="auto" | |||
inkscape:stockid="DotSC"> | |||
<path | |||
transform="scale(0.2) translate(7.4, 1)" | |||
style="marker-end:none;fill-rule:evenodd;marker-start:none;stroke:#49c2f1;stroke-width:1.0pt;fill:#49c2f1" | |||
d="M -2.5,-1.0 C -2.5,1.7600000 -4.7400000,4.0 -7.5,4.0 C -10.260000,4.0 -12.5,1.7600000 -12.5,-1.0 C -12.5,-3.7600000 -10.260000,-6.0 -7.5,-6.0 C -4.7400000,-6.0 -2.5,-3.7600000 -2.5,-1.0 z " | |||
id="path5535" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="DotSC-1" | |||
refX="0" | |||
refY="0" | |||
orient="auto" | |||
inkscape:stockid="DotSC"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
transform="matrix(0.2,0,0,0.2,1.48,0.2)" | |||
style="fill:#49c2f1;fill-rule:evenodd;stroke:#49c2f1;stroke-width:1pt;marker-start:none;marker-end:none" | |||
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z" | |||
id="path5535-8" /> | |||
</marker> | |||
<marker | |||
markerWidth="4.6297302" | |||
markerHeight="5.7450776" | |||
orient="auto" | |||
id="marker18095-34"> | |||
<g | |||
transform="matrix(0.5,0,0,0.5,-185.64298,-257.19655)" | |||
id="g11064-1"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
id="path11050-84" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:evenodd;stroke:none" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
id="path11035-25" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" /> | |||
</g> | |||
</marker> | |||
</defs> | |||
<metadata | |||
id="metadata1906"> | |||
<rdf:RDF> | |||
<cc:Work | |||
rdf:about=""> | |||
<dc:format>image/svg+xml</dc:format> | |||
<dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
</cc:Work> | |||
</rdf:RDF> | |||
</metadata> | |||
<g | |||
style="opacity:1" | |||
id="layer1" | |||
inkscape:groupmode="layer" | |||
inkscape:label="Taso 1"> | |||
<g | |||
transform="matrix(1.4062095,0,0,1.4062095,-160.27559,-197.72935)" | |||
id="g6925" | |||
style="display:inline"> | |||
<rect | |||
ry="3.7880721" | |||
y="231.36011" | |||
x="167.87294" | |||
height="53.157619" | |||
width="123.88699" | |||
id="rect2549" | |||
style="fill:#d9d9cd;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | |||
<text | |||
xml:space="preserve" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
x="174.42322" | |||
y="248.96115" | |||
id="text6921"><tspan | |||
sodipodi:role="line" | |||
id="tspan6923" | |||
x="174.42322" | |||
y="248.96115">CalculatorView</tspan></text> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3155-5" | |||
y="262.29724" | |||
x="173.71204" | |||
style="font-size:9.95584228px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Italic" | |||
xml:space="preserve"><tspan | |||
id="tspan4492" | |||
y="262.29724" | |||
x="173.71204" | |||
sodipodi:role="line">setDisplay()</tspan><tspan | |||
y="274.74203" | |||
x="173.71204" | |||
sodipodi:role="line" | |||
id="tspan5929">addListener()</tspan></text> | |||
</g> | |||
<path | |||
sodipodi:type="arc" | |||
style="color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |||
id="path5742" | |||
sodipodi:cx="225" | |||
sodipodi:cy="172.36218" | |||
sodipodi:rx="10" | |||
sodipodi:ry="10" | |||
d="m 235,172.36218 a 10,10 0 1 1 0,-0.005" | |||
sodipodi:start="0" | |||
sodipodi:end="6.2827149" | |||
sodipodi:open="true" | |||
transform="translate(25,2.6171874e-6)" /> | |||
<g | |||
transform="matrix(1.4062095,0,0,1.4062095,52.743842,-199.95949)" | |||
id="g6951" | |||
style="display:inline"> | |||
<rect | |||
ry="3.7880721" | |||
y="232.76878" | |||
x="168.72035" | |||
height="71.113159" | |||
width="131.55934" | |||
id="rect6953" | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | |||
<text | |||
xml:space="preserve" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
x="175.83167" | |||
y="250.54707" | |||
id="text6955"><tspan | |||
sodipodi:role="line" | |||
id="tspan6957" | |||
x="175.83167" | |||
y="250.54707">CalculatorPresenter</tspan></text> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3155-5-4" | |||
y="263.88318" | |||
x="177.25385" | |||
style="font-size:9.95584202px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
id="tspan4492-0" | |||
y="263.88318" | |||
x="177.25385" | |||
sodipodi:role="line">buttonClick()</tspan></text> | |||
</g> | |||
<g | |||
transform="matrix(1.4062095,0,0,1.4062095,-160.02993,-59.169572)" | |||
id="g6951-6" | |||
style="display:inline"> | |||
<rect | |||
ry="3.7880721" | |||
y="232.20705" | |||
x="167.13719" | |||
height="71.113159" | |||
width="124.44804" | |||
id="rect6953-7" | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | |||
<text | |||
xml:space="preserve" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
x="172.96414" | |||
y="250.54707" | |||
id="text6955-8"><tspan | |||
sodipodi:role="line" | |||
id="tspan6957-7" | |||
x="172.96414" | |||
y="250.54707">CalculatorViewImpl</tspan></text> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3155-5-6" | |||
y="264.20798" | |||
x="174.24852" | |||
style="font-size:9.95584202px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
id="tspan4492-3" | |||
y="264.20798" | |||
x="174.24852" | |||
sodipodi:role="line">setDisplay()</tspan><tspan | |||
y="276.65277" | |||
x="174.24852" | |||
sodipodi:role="line" | |||
id="tspan5931">addListener()</tspan></text> | |||
</g> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3155" | |||
y="237.36218" | |||
x="160" | |||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
y="237.36218" | |||
x="160" | |||
id="tspan3157" | |||
sodipodi:role="line">«implements»</tspan></text> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" | |||
id="path3204" | |||
d="m 150,267.36218 0,-65" | |||
style="fill:none;stroke:#49c2f1;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#marker18095)" /> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" | |||
id="path3204-2" | |||
d="m 290,172.36218 -40,0" | |||
style="fill:none;stroke:#49c2f1;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#DotSC)" /> | |||
<g | |||
transform="matrix(1.4062095,0,0,1.4062095,54.970076,-59.169585)" | |||
id="g6951-6-1" | |||
style="display:inline"> | |||
<rect | |||
ry="3.7880721" | |||
y="232.20705" | |||
x="167.13719" | |||
height="88.891457" | |||
width="131.55936" | |||
id="rect6953-7-4" | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | |||
<text | |||
xml:space="preserve" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
x="172.96414" | |||
y="250.54707" | |||
id="text6955-8-8"><tspan | |||
sodipodi:role="line" | |||
id="tspan6957-7-3" | |||
x="172.96414" | |||
y="250.54707">Calculator</tspan></text> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3155-5-6-8" | |||
y="264.20798" | |||
x="174.24852" | |||
style="font-size:9.95584202px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
y="264.20798" | |||
x="174.24852" | |||
id="tspan3157-2-8-1" | |||
sodipodi:role="line">set/getValue()</tspan><tspan | |||
id="tspan4492-3-8" | |||
y="276.65277" | |||
x="174.24852" | |||
sodipodi:role="line">add()</tspan><tspan | |||
y="289.0976" | |||
x="174.24852" | |||
sodipodi:role="line" | |||
id="tspan5919">multiply()</tspan><tspan | |||
y="301.54239" | |||
x="174.24852" | |||
sodipodi:role="line" | |||
id="tspan5921">divide()</tspan><tspan | |||
y="313.98718" | |||
x="174.24852" | |||
sodipodi:role="line" | |||
id="tspan5923">clear()</tspan></text> | |||
</g> | |||
<path | |||
transform="translate(140,95)" | |||
sodipodi:type="arc" | |||
style="color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |||
id="path5742-1" | |||
sodipodi:cx="225" | |||
sodipodi:cy="172.36218" | |||
sodipodi:rx="10" | |||
sodipodi:ry="10" | |||
d="m 235,172.36218 a 10,10 0 1 1 0,-0.005" | |||
sodipodi:start="0" | |||
sodipodi:end="6.2827149" | |||
sodipodi:open="true" /> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" | |||
id="path3204-2-7" | |||
d="m 365,227.36218 0,40" | |||
style="fill:none;stroke:#49c2f1;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#DotSC)" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3155-50" | |||
y="162.36218" | |||
x="251" | |||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
y="162.36218" | |||
x="251" | |||
id="tspan3157-1" | |||
sodipodi:role="line">1</tspan></text> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3155-50-0" | |||
y="262.36218" | |||
x="373.69604" | |||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
y="262.36218" | |||
x="373.69604" | |||
id="tspan3157-1-5" | |||
sodipodi:role="line">1</tspan></text> | |||
<g | |||
transform="matrix(1.4062095,0,0,1.4062095,-130.27557,-232.9786)" | |||
id="g6925-1" | |||
style="display:inline"> | |||
<rect | |||
ry="3.7880721" | |||
y="231.36011" | |||
x="167.31189" | |||
height="32.000923" | |||
width="110.2254" | |||
id="rect2549-7" | |||
style="fill:#d9d9cd;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1.42226315;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | |||
<text | |||
xml:space="preserve" | |||
style="font-size:8.53357887px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
x="174.42322" | |||
y="244.69438" | |||
id="text6921-9" | |||
sodipodi:linespacing="125%"><tspan | |||
sodipodi:role="line" | |||
id="tspan6923-7" | |||
x="174.42322" | |||
y="244.69438">CalculatorViewListener</tspan></text> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3155-5-63" | |||
y="255.1859" | |||
x="175.13429" | |||
style="font-size:7.11131592px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Italic" | |||
xml:space="preserve"><tspan | |||
id="tspan4492-7" | |||
y="255.1859" | |||
x="175.13429" | |||
sodipodi:role="line">buttonClick()</tspan></text> | |||
</g> | |||
<path | |||
sodipodi:nodetypes="ccc" | |||
inkscape:connector-curvature="0" | |||
id="path3204-6" | |||
d="m 365,127.36218 0,-10 -105,0" | |||
style="fill:none;stroke:#49c2f1;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#marker18095)" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3155-9" | |||
y="112.36218" | |||
x="280" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
xml:space="preserve"><tspan | |||
y="112.36218" | |||
x="280" | |||
id="tspan3157-7" | |||
sodipodi:role="line">«implements»</tspan></text> | |||
</g> | |||
<g | |||
inkscape:label="Varjot" | |||
id="layer2" | |||
inkscape:groupmode="layer" /> | |||
</svg> |
@@ -0,0 +1,980 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<!-- Created with Inkscape (http://www.inkscape.org/) --> | |||
<svg | |||
xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
xmlns:cc="http://creativecommons.org/ns#" | |||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" | |||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
width="744.09448" | |||
height="1052.3622" | |||
id="svg2475" | |||
sodipodi:version="0.32" | |||
inkscape:version="0.48.1 r9760" | |||
sodipodi:docname="threadlocal-sequentiality.svg" | |||
inkscape:output_extension="org.inkscape.output.svg.inkscape" | |||
inkscape:export-filename="/home/magi/itmill/doc/cheatsheet/vaadin-cheatsheet.png" | |||
inkscape:export-xdpi="300.01001" | |||
inkscape:export-ydpi="300.01001" | |||
version="1.0"> | |||
<sodipodi:namedview | |||
id="base" | |||
pagecolor="#ffffff" | |||
bordercolor="#666666" | |||
borderopacity="1.0" | |||
gridtolerance="10000" | |||
guidetolerance="10" | |||
objecttolerance="10" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:zoom="2.4" | |||
inkscape:cx="374.31245" | |||
inkscape:cy="621.17988" | |||
inkscape:document-units="mm" | |||
inkscape:current-layer="layer1" | |||
showgrid="true" | |||
inkscape:window-width="1680" | |||
inkscape:window-height="1026" | |||
inkscape:window-x="232" | |||
inkscape:window-y="0" | |||
inkscape:snap-nodes="true" | |||
inkscape:snap-bbox="true" | |||
units="mm" | |||
inkscape:snap-global="false" | |||
showguides="true" | |||
inkscape:guide-bbox="true" | |||
inkscape:window-maximized="0"> | |||
<inkscape:grid | |||
dotted="false" | |||
type="xygrid" | |||
id="grid4674" | |||
visible="true" | |||
enabled="true" | |||
units="mm" | |||
empspacing="5" | |||
spacingx="1mm" | |||
spacingy="1mm" /> | |||
</sodipodi:namedview> | |||
<defs | |||
id="defs2477"> | |||
<marker | |||
style="overflow:visible" | |||
id="Arrow1Lstart" | |||
refX="0" | |||
refY="0" | |||
orient="auto" | |||
inkscape:stockid="Arrow1Lstart"> | |||
<path | |||
transform="matrix(0.8,0,0,0.8,10,0)" | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" | |||
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" | |||
id="path5210" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="DotS" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="DotS" | |||
style="overflow:visible"> | |||
<path | |||
id="path3636" | |||
d="M -2.5,-1 C -2.5,1.76 -4.74,4 -7.5,4 C -10.26,4 -12.5,1.76 -12.5,-1 C -12.5,-3.76 -10.26,-6 -7.5,-6 C -4.74,-6 -2.5,-3.76 -2.5,-1 z" | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none" | |||
transform="matrix(0.2,0,0,0.2,1.48,0.2)" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleOutS" | |||
refX="0" | |||
refY="0" | |||
orient="auto" | |||
inkscape:stockid="TriangleOutS"> | |||
<path | |||
transform="scale(0.2,0.2)" | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
id="path3717" /> | |||
</marker> | |||
<inkscape:path-effect | |||
effect="skeletal" | |||
id="path-effect2503" | |||
prop_scale="1" | |||
pattern="M 349.202,225.086 L 405.895,331.386 L 370.462,338.472 " | |||
copytype="single_stretched" /> | |||
<inkscape:path-effect | |||
effect="skeletal" | |||
id="path-effect2499" | |||
prop_scale="1" /> | |||
<inkscape:path-effect | |||
effect="skeletal" | |||
id="path-effect2497" | |||
prop_scale="1" | |||
pattern="M 432.28346,272.83462 L 403.93701,216.14171" | |||
pattern-nodetypes="cc" /> | |||
<marker | |||
inkscape:stockid="Arrow1Send" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="Arrow1Send" | |||
style="overflow:visible"> | |||
<path | |||
id="path3641" | |||
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" | |||
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="Arrow1Lend" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="Arrow1Lend" | |||
style="overflow:visible"> | |||
<path | |||
id="path3629" | |||
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" | |||
transform="matrix(-0.8,0,0,-0.8,-10,0)" /> | |||
</marker> | |||
<inkscape:perspective | |||
id="perspective3487" | |||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1" | |||
inkscape:vp_z="744.09448 : 526.18109 : 1" | |||
inkscape:vp_y="0 : 1000 : 0" | |||
inkscape:vp_x="0 : 526.18109 : 1" | |||
sodipodi:type="inkscape:persp3d" /> | |||
<marker | |||
inkscape:stockid="Arrow2Sendp" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="Arrow2Sendp" | |||
style="overflow:visible"> | |||
<path | |||
id="path28139" | |||
style="font-size:12px;fill:#f39300;fill-rule:evenodd;stroke:#f39300;stroke-width:0.625;stroke-linejoin:round" | |||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" | |||
transform="matrix(-0.3,0,0,-0.3,0.69,0)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="TriangleOutSK" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="TriangleOutSK" | |||
style="overflow:visible"> | |||
<path | |||
id="path36611" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
style="fill:#49c2f1;fill-rule:evenodd;stroke:#49c2f1;stroke-width:1pt;marker-start:none" | |||
transform="scale(0.2,0.2)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="TriangleOutSH" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="TriangleOutSH" | |||
style="overflow:visible"> | |||
<path | |||
id="path36614" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
style="fill:#49c2f1;fill-rule:evenodd;stroke:#49c2f1;stroke-width:1pt;marker-start:none" | |||
transform="scale(0.2,0.2)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="TriangleOutSA" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="TriangleOutSA" | |||
style="overflow:visible"> | |||
<path | |||
id="path36617" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
style="fill:#49c2f1;fill-rule:evenodd;stroke:#49c2f1;stroke-width:1pt;marker-start:none" | |||
transform="scale(0.2,0.2)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="TriangleOutSKF" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="TriangleOutSKF" | |||
style="overflow:visible"> | |||
<path | |||
id="path36620" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
style="fill:#49c2f1;fill-rule:evenodd;stroke:#49c2f1;stroke-width:1pt;marker-start:none" | |||
transform="scale(0.2,0.2)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="TriangleOutS9" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="TriangleOutS9" | |||
style="overflow:visible"> | |||
<path | |||
id="path36623" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
style="fill:#49c2f1;fill-rule:evenodd;stroke:#49c2f1;stroke-width:1pt;marker-start:none" | |||
transform="scale(0.2,0.2)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="Arrow2SendpA" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="Arrow2SendpA" | |||
style="overflow:visible"> | |||
<path | |||
id="path3396" | |||
style="font-size:12px;fill:#d9d9cd;fill-rule:evenodd;stroke:#d9d9cd;stroke-width:0.625;stroke-linejoin:round" | |||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" | |||
transform="matrix(-0.3,0,0,-0.3,0.69,0)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="Arrow2Sendpg" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="Arrow2Sendpg" | |||
style="overflow:visible"> | |||
<path | |||
id="path3360" | |||
style="font-size:12px;fill:#fcc988;fill-rule:evenodd;stroke:#fcc988;stroke-width:0.625;stroke-linejoin:round" | |||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" | |||
transform="matrix(-0.3,0,0,-0.3,0.69,0)" /> | |||
</marker> | |||
<filter | |||
height="1.1" | |||
width="1.1" | |||
inkscape:label="White Halo" | |||
id="filter2780"> | |||
<feMorphology | |||
result="result0" | |||
radius="3" | |||
operator="dilate" | |||
id="feMorphology2782" /> | |||
<feFlood | |||
result="result3" | |||
in="result0" | |||
flood-opacity="1" | |||
flood-color="rgb(255,255,255)" | |||
id="feFlood2786" /> | |||
<feComposite | |||
result="result4" | |||
operator="in" | |||
in2="result0" | |||
in="result3" | |||
id="feComposite2623" /> | |||
<feMerge | |||
id="feMerge2629"> | |||
<feMergeNode | |||
in="result4" | |||
id="feMergeNode2631" | |||
inkscape:collect="always" /> | |||
<feMergeNode | |||
in="SourceGraphic" | |||
id="feMergeNode2633" | |||
inkscape:collect="always" /> | |||
</feMerge> | |||
</filter> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleOutSn" | |||
refX="0" | |||
refY="0" | |||
orient="auto" | |||
inkscape:stockid="TriangleOutSn"> | |||
<path | |||
transform="scale(0.2,0.2)" | |||
style="fill:#d9d9cd;fill-rule:evenodd;stroke:#d9d9cd;stroke-width:1pt;marker-start:none" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
id="path4441" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleOutS9F" | |||
refX="0" | |||
refY="0" | |||
orient="auto" | |||
inkscape:stockid="TriangleOutS9F"> | |||
<path | |||
transform="scale(0.2,0.2)" | |||
style="fill:#d9d9cd;fill-rule:evenodd;stroke:#d9d9cd;stroke-width:1pt;marker-start:none" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
id="path4444" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleOutSI" | |||
refX="0" | |||
refY="0" | |||
orient="auto" | |||
inkscape:stockid="TriangleOutSI"> | |||
<path | |||
transform="scale(0.2,0.2)" | |||
style="fill:#d9d9cd;fill-rule:evenodd;stroke:#d9d9cd;stroke-width:1pt;marker-start:none" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
id="path4447" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleOutSO" | |||
refX="0" | |||
refY="0" | |||
orient="auto" | |||
inkscape:stockid="TriangleOutSO"> | |||
<path | |||
transform="scale(0.2,0.2)" | |||
style="fill:#d9d9cd;fill-rule:evenodd;stroke:#d9d9cd;stroke-width:1pt;marker-start:none" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
id="path4450" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleOutSW" | |||
refX="0" | |||
refY="0" | |||
orient="auto" | |||
inkscape:stockid="TriangleOutSW"> | |||
<path | |||
transform="scale(0.2,0.2)" | |||
style="fill:#d9d9cd;fill-rule:evenodd;stroke:#d9d9cd;stroke-width:1pt;marker-start:none" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
id="path4453" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleOutSB" | |||
refX="0" | |||
refY="0" | |||
orient="auto" | |||
inkscape:stockid="TriangleOutSB"> | |||
<path | |||
transform="scale(0.2,0.2)" | |||
style="fill:#d9d9cd;fill-rule:evenodd;stroke:#d9d9cd;stroke-width:1pt;marker-start:none" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
id="path4456" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleOutSZ" | |||
refX="0" | |||
refY="0" | |||
orient="auto" | |||
inkscape:stockid="TriangleOutSZ"> | |||
<path | |||
transform="scale(0.2,0.2)" | |||
style="fill:#d9d9cd;fill-rule:evenodd;stroke:#d9d9cd;stroke-width:1pt;marker-start:none" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
id="path4459" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="DotSq" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="DotSq" | |||
style="overflow:visible"> | |||
<path | |||
id="path5853" | |||
d="M -2.5,-1 C -2.5,1.76 -4.74,4 -7.5,4 C -10.26,4 -12.5,1.76 -12.5,-1 C -12.5,-3.76 -10.26,-6 -7.5,-6 C -4.74,-6 -2.5,-3.76 -2.5,-1 z" | |||
style="fill:#d9d9cd;fill-rule:evenodd;stroke:#d9d9cd;stroke-width:1pt;marker-start:none;marker-end:none" | |||
transform="matrix(0.2,0,0,0.2,1.48,0.2)" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleOutSBO" | |||
refX="0" | |||
refY="0" | |||
orient="auto" | |||
inkscape:stockid="TriangleOutSBO"> | |||
<path | |||
transform="scale(0.2,0.2)" | |||
style="fill:#49c2f1;fill-rule:evenodd;stroke:#49c2f1;stroke-width:1pt;marker-start:none" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
id="path7501" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="DotSu" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="DotSu" | |||
style="overflow:visible"> | |||
<path | |||
id="path9463" | |||
d="M -2.5,-1 C -2.5,1.76 -4.74,4 -7.5,4 C -10.26,4 -12.5,1.76 -12.5,-1 C -12.5,-3.76 -10.26,-6 -7.5,-6 C -4.74,-6 -2.5,-3.76 -2.5,-1 z" | |||
style="fill:#49c2f1;fill-rule:evenodd;stroke:#49c2f1;stroke-width:1pt;marker-start:none;marker-end:none" | |||
transform="matrix(0.2,0,0,0.2,1.48,0.2)" /> | |||
</marker> | |||
<filter | |||
id="filter10694" | |||
inkscape:label="Black Halo" | |||
width="1.1" | |||
height="1.1"> | |||
<feMorphology | |||
id="feMorphology10696" | |||
operator="dilate" | |||
radius="3" | |||
result="result0" /> | |||
<feFlood | |||
id="feFlood10698" | |||
flood-color="rgb(0,0,0)" | |||
flood-opacity="1" | |||
in="result0" | |||
result="result3" /> | |||
<feComposite | |||
id="feComposite10700" | |||
in="result3" | |||
in2="result0" | |||
operator="in" | |||
result="result4" /> | |||
<feMerge | |||
id="feMerge10702"> | |||
<feMergeNode | |||
inkscape:collect="always" | |||
id="feMergeNode10704" | |||
in="result4" /> | |||
<feMergeNode | |||
inkscape:collect="always" | |||
id="feMergeNode10706" | |||
in="SourceGraphic" /> | |||
</feMerge> | |||
</filter> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleOutSu" | |||
refX="0" | |||
refY="0" | |||
orient="auto" | |||
inkscape:stockid="TriangleOutSu"> | |||
<path | |||
transform="scale(0.2,0.2)" | |||
style="fill:#49c2f1;fill-rule:evenodd;stroke:#49c2f1;stroke-width:1pt;marker-start:none" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
id="path8127" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleOutSI8" | |||
refX="0" | |||
refY="0" | |||
orient="auto" | |||
inkscape:stockid="TriangleOutSI8"> | |||
<path | |||
transform="scale(0.2,0.2)" | |||
style="fill:#49c2f1;fill-rule:evenodd;stroke:#49c2f1;stroke-width:1pt;marker-start:none" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
id="path8130" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleOutSr" | |||
refX="0" | |||
refY="0" | |||
orient="auto" | |||
inkscape:stockid="TriangleOutSr"> | |||
<path | |||
transform="scale(0.2,0.2)" | |||
style="fill:#49c2f1;fill-rule:evenodd;stroke:#49c2f1;stroke-width:1pt;marker-start:none" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
id="path8133" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleOutSM" | |||
refX="0" | |||
refY="0" | |||
orient="auto" | |||
inkscape:stockid="TriangleOutSM"> | |||
<path | |||
transform="scale(0.2,0.2)" | |||
style="fill:#49c2f1;fill-rule:evenodd;stroke:#49c2f1;stroke-width:1pt;marker-start:none" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
id="path8136" /> | |||
</marker> | |||
<marker | |||
style="overflow:visible" | |||
id="TriangleOutSb" | |||
refX="0" | |||
refY="0" | |||
orient="auto" | |||
inkscape:stockid="TriangleOutSb"> | |||
<path | |||
transform="scale(0.2,0.2)" | |||
style="fill:#49c2f1;fill-rule:evenodd;stroke:#49c2f1;stroke-width:1pt;marker-start:none" | |||
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" | |||
id="path8139" /> | |||
</marker> | |||
<marker | |||
markerWidth="4.6297302" | |||
markerHeight="5.7450776" | |||
orient="auto" | |||
id="marker18095"> | |||
<g | |||
transform="matrix(0.5,0,0,0.5,-185.64298,-257.19655)" | |||
id="g11064"> | |||
<path | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1" | |||
d="M 370,508.65625 C 369.13933,508.715 368.39056,509.27755 368.09375,510.09375 C 367.82399,510.83551 368.03605,511.62868 368.53125,512.21875 L 366.78125,512.21875 C 366.73884,512.21408 366.69882,512.22093 366.65625,512.21875 L 366.65625,516.59375 L 366.78125,516.59375 L 368.53125,516.59375 C 367.85229,517.45345 367.83424,518.70924 368.625,519.5 C 369.47591,520.35091 370.89909,520.35091 371.75,519.5 L 375.09375,516.125 C 375.12672,516.09552 375.15802,516.06422 375.1875,516.03125 C 375.21972,516.01191 375.25101,515.99105 375.28125,515.96875 C 375.28162,515.96839 375.49976,515.68796 375.5,515.6875 C 375.50005,515.68741 375.49338,515.64282 375.5,515.625 C 375.5011,515.62203 375.53002,515.62832 375.53125,515.625 C 375.57039,515.57293 375.58228,515.57321 375.625,515.5 C 375.76199,515.26524 375.79184,515.12809 375.78125,515.15625 C 375.81807,515.06473 375.79977,515.04374 375.8125,515 C 375.82311,514.98978 375.83353,514.97936 375.84375,514.96875 C 375.90379,514.74477 375.93181,514.45186 375.90625,514.1875 C 375.89266,513.98387 375.84739,513.88985 375.84375,513.875 C 375.84389,513.86458 375.84389,513.85417 375.84375,513.84375 C 375.86975,513.94071 375.85901,513.85978 375.75,513.59375 C 375.69753,513.46336 375.66014,513.37439 375.625,513.3125 C 375.57262,513.22275 375.49154,513.05015 375.28125,512.84375 L 371.75,509.3125 C 371.29355,508.82579 370.66491,508.60087 370,508.65625 z" | |||
id="path11050" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" /> | |||
<path | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | |||
d="M 366.65625,515.40625 L 371.28125,515.40625 L 369.46875,517.21875 C 369.0718,517.6157 369.0718,518.2593 369.46875,518.65625 C 369.8657,519.0532 370.5093,519.0532 370.90625,518.65625 L 374.34375,515.1875 L 374.4375,515.125 C 374.44343,515.11918 374.43171,515.09972 374.4375,515.09375 C 374.49291,515.03659 374.5526,514.97676 374.59375,514.90625 C 374.62239,514.85717 374.63663,514.80216 374.65625,514.75 C 374.66861,514.71928 374.67831,514.68783 374.6875,514.65625 C 374.71862,514.54015 374.73024,514.43132 374.71875,514.3125 C 374.71489,514.25466 374.70138,514.21285 374.6875,514.15625 C 374.6766,514.1156 374.67237,514.07059 374.65625,514.03125 C 374.63982,513.99042 374.61578,513.94505 374.59375,513.90625 C 374.5483,513.82838 374.50015,513.74899 374.4375,513.6875 L 370.90625,510.15625 C 370.69734,509.93349 370.39809,509.8184 370.09375,509.84375 C 369.69897,509.8707 369.35398,510.12813 369.21875,510.5 C 369.08351,510.87187 369.18349,511.28826 369.46875,511.5625 L 371.34375,513.40625 L 366.65625,513.40625" | |||
id="path11035" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" /> | |||
</g> | |||
</marker> | |||
<marker | |||
markerWidth="4.6297355" | |||
markerHeight="5.7450781" | |||
orient="auto" | |||
id="marker44971"> | |||
<g | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)" | |||
id="g18059"> | |||
<path | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1" | |||
d="M 370,508.65625 C 369.13933,508.715 368.39056,509.27755 368.09375,510.09375 C 367.82399,510.83551 368.03605,511.62868 368.53125,512.21875 L 366.78125,512.21875 C 366.73884,512.21408 366.69882,512.22093 366.65625,512.21875 L 366.65625,516.59375 L 366.78125,516.59375 L 368.53125,516.59375 C 367.85229,517.45345 367.83424,518.70924 368.625,519.5 C 369.47591,520.35091 370.89909,520.35091 371.75,519.5 L 375.09375,516.125 C 375.12672,516.09552 375.15802,516.06422 375.1875,516.03125 C 375.21972,516.01191 375.25101,515.99105 375.28125,515.96875 C 375.28162,515.96839 375.49976,515.68796 375.5,515.6875 C 375.50005,515.68741 375.49338,515.64282 375.5,515.625 C 375.5011,515.62203 375.53002,515.62832 375.53125,515.625 C 375.57039,515.57293 375.58228,515.57321 375.625,515.5 C 375.76199,515.26524 375.79184,515.12809 375.78125,515.15625 C 375.81807,515.06473 375.79977,515.04374 375.8125,515 C 375.82311,514.98978 375.83353,514.97936 375.84375,514.96875 C 375.90379,514.74477 375.93181,514.45186 375.90625,514.1875 C 375.89266,513.98387 375.84739,513.88985 375.84375,513.875 C 375.84389,513.86458 375.84389,513.85417 375.84375,513.84375 C 375.86975,513.94071 375.85901,513.85978 375.75,513.59375 C 375.69753,513.46336 375.66014,513.37439 375.625,513.3125 C 375.57262,513.22275 375.49154,513.05015 375.28125,512.84375 L 371.75,509.3125 C 371.29355,508.82579 370.66491,508.60087 370,508.65625 z" | |||
id="path18061" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" /> | |||
<path | |||
style="fill:#d9d9cd;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | |||
d="M 366.65625,515.40625 L 371.28125,515.40625 L 369.46875,517.21875 C 369.0718,517.6157 369.0718,518.2593 369.46875,518.65625 C 369.8657,519.0532 370.5093,519.0532 370.90625,518.65625 L 374.34375,515.1875 L 374.4375,515.125 C 374.44343,515.11918 374.43171,515.09972 374.4375,515.09375 C 374.49291,515.03659 374.5526,514.97676 374.59375,514.90625 C 374.62239,514.85717 374.63663,514.80216 374.65625,514.75 C 374.66861,514.71928 374.67831,514.68783 374.6875,514.65625 C 374.71862,514.54015 374.73024,514.43132 374.71875,514.3125 C 374.71489,514.25466 374.70138,514.21285 374.6875,514.15625 C 374.6766,514.1156 374.67237,514.07059 374.65625,514.03125 C 374.63982,513.99042 374.61578,513.94505 374.59375,513.90625 C 374.5483,513.82838 374.50015,513.74899 374.4375,513.6875 L 370.90625,510.15625 C 370.69734,509.93349 370.39809,509.8184 370.09375,509.84375 C 369.69897,509.8707 369.35398,510.12813 369.21875,510.5 C 369.08351,510.87187 369.18349,511.28826 369.46875,511.5625 L 371.34375,513.40625 L 366.65625,513.40625" | |||
id="path18063" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" /> | |||
</g> | |||
</marker> | |||
<marker | |||
markerWidth="4.6297302" | |||
markerHeight="5.7450786" | |||
orient="auto" | |||
id="marker52016"> | |||
<g | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)" | |||
id="g52010"> | |||
<path | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1" | |||
d="M 370,508.65625 C 369.13933,508.715 368.39056,509.27755 368.09375,510.09375 C 367.82399,510.83551 368.03605,511.62868 368.53125,512.21875 L 366.78125,512.21875 C 366.73884,512.21408 366.69882,512.22093 366.65625,512.21875 L 366.65625,516.59375 L 366.78125,516.59375 L 368.53125,516.59375 C 367.85229,517.45345 367.83424,518.70924 368.625,519.5 C 369.47591,520.35091 370.89909,520.35091 371.75,519.5 L 375.09375,516.125 C 375.12672,516.09552 375.15802,516.06422 375.1875,516.03125 C 375.21972,516.01191 375.25101,515.99105 375.28125,515.96875 C 375.28162,515.96839 375.49976,515.68796 375.5,515.6875 C 375.50005,515.68741 375.49338,515.64282 375.5,515.625 C 375.5011,515.62203 375.53002,515.62832 375.53125,515.625 C 375.57039,515.57293 375.58228,515.57321 375.625,515.5 C 375.76199,515.26524 375.79184,515.12809 375.78125,515.15625 C 375.81807,515.06473 375.79977,515.04374 375.8125,515 C 375.82311,514.98978 375.83353,514.97936 375.84375,514.96875 C 375.90379,514.74477 375.93181,514.45186 375.90625,514.1875 C 375.89266,513.98387 375.84739,513.88985 375.84375,513.875 C 375.84389,513.86458 375.84389,513.85417 375.84375,513.84375 C 375.86975,513.94071 375.85901,513.85978 375.75,513.59375 C 375.69753,513.46336 375.66014,513.37439 375.625,513.3125 C 375.57262,513.22275 375.49154,513.05015 375.28125,512.84375 L 371.75,509.3125 C 371.29355,508.82579 370.66491,508.60087 370,508.65625 z" | |||
id="path52012" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" /> | |||
<path | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | |||
d="M 366.65625,515.40625 L 371.28125,515.40625 L 369.46875,517.21875 C 369.0718,517.6157 369.0718,518.2593 369.46875,518.65625 C 369.8657,519.0532 370.5093,519.0532 370.90625,518.65625 L 374.34375,515.1875 L 374.4375,515.125 C 374.44343,515.11918 374.43171,515.09972 374.4375,515.09375 C 374.49291,515.03659 374.5526,514.97676 374.59375,514.90625 C 374.62239,514.85717 374.63663,514.80216 374.65625,514.75 C 374.66861,514.71928 374.67831,514.68783 374.6875,514.65625 C 374.71862,514.54015 374.73024,514.43132 374.71875,514.3125 C 374.71489,514.25466 374.70138,514.21285 374.6875,514.15625 C 374.6766,514.1156 374.67237,514.07059 374.65625,514.03125 C 374.63982,513.99042 374.61578,513.94505 374.59375,513.90625 C 374.5483,513.82838 374.50015,513.74899 374.4375,513.6875 L 370.90625,510.15625 C 370.69734,509.93349 370.39809,509.8184 370.09375,509.84375 C 369.69897,509.8707 369.35398,510.12813 369.21875,510.5 C 369.08351,510.87187 369.18349,511.28826 369.46875,511.5625 L 371.34375,513.40625 L 366.65625,513.40625" | |||
id="path52014" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" /> | |||
</g> | |||
</marker> | |||
<marker | |||
markerWidth="4.6297255" | |||
markerHeight="5.745079" | |||
orient="auto" | |||
id="marker64887"> | |||
<g | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)" | |||
id="g64855"> | |||
<path | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1" | |||
d="M 370,508.65625 C 369.13933,508.715 368.39056,509.27755 368.09375,510.09375 C 367.82399,510.83551 368.03605,511.62868 368.53125,512.21875 L 366.78125,512.21875 C 366.73884,512.21408 366.69882,512.22093 366.65625,512.21875 L 366.65625,516.59375 L 366.78125,516.59375 L 368.53125,516.59375 C 367.85229,517.45345 367.83424,518.70924 368.625,519.5 C 369.47591,520.35091 370.89909,520.35091 371.75,519.5 L 375.09375,516.125 C 375.12672,516.09552 375.15802,516.06422 375.1875,516.03125 C 375.21972,516.01191 375.25101,515.99105 375.28125,515.96875 C 375.28162,515.96839 375.49976,515.68796 375.5,515.6875 C 375.50005,515.68741 375.49338,515.64282 375.5,515.625 C 375.5011,515.62203 375.53002,515.62832 375.53125,515.625 C 375.57039,515.57293 375.58228,515.57321 375.625,515.5 C 375.76199,515.26524 375.79184,515.12809 375.78125,515.15625 C 375.81807,515.06473 375.79977,515.04374 375.8125,515 C 375.82311,514.98978 375.83353,514.97936 375.84375,514.96875 C 375.90379,514.74477 375.93181,514.45186 375.90625,514.1875 C 375.89266,513.98387 375.84739,513.88985 375.84375,513.875 C 375.84389,513.86458 375.84389,513.85417 375.84375,513.84375 C 375.86975,513.94071 375.85901,513.85978 375.75,513.59375 C 375.69753,513.46336 375.66014,513.37439 375.625,513.3125 C 375.57262,513.22275 375.49154,513.05015 375.28125,512.84375 L 371.75,509.3125 C 371.29355,508.82579 370.66491,508.60087 370,508.65625 z" | |||
id="path64857" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" /> | |||
<path | |||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | |||
d="M 366.65625,515.40625 L 371.28125,515.40625 L 369.46875,517.21875 C 369.0718,517.6157 369.0718,518.2593 369.46875,518.65625 C 369.8657,519.0532 370.5093,519.0532 370.90625,518.65625 L 374.34375,515.1875 L 374.4375,515.125 C 374.44343,515.11918 374.43171,515.09972 374.4375,515.09375 C 374.49291,515.03659 374.5526,514.97676 374.59375,514.90625 C 374.62239,514.85717 374.63663,514.80216 374.65625,514.75 C 374.66861,514.71928 374.67831,514.68783 374.6875,514.65625 C 374.71862,514.54015 374.73024,514.43132 374.71875,514.3125 C 374.71489,514.25466 374.70138,514.21285 374.6875,514.15625 C 374.6766,514.1156 374.67237,514.07059 374.65625,514.03125 C 374.63982,513.99042 374.61578,513.94505 374.59375,513.90625 C 374.5483,513.82838 374.50015,513.74899 374.4375,513.6875 L 370.90625,510.15625 C 370.69734,509.93349 370.39809,509.8184 370.09375,509.84375 C 369.69897,509.8707 369.35398,510.12813 369.21875,510.5 C 369.08351,510.87187 369.18349,511.28826 369.46875,511.5625 L 371.34375,513.40625 L 366.65625,513.40625" | |||
id="path64859" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" /> | |||
</g> | |||
</marker> | |||
<marker | |||
markerWidth="4.6297302" | |||
markerHeight="5.745079" | |||
orient="auto" | |||
id="marker4057"> | |||
<g | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)" | |||
id="g51986"> | |||
<path | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1" | |||
d="M 370,508.65625 C 369.13933,508.715 368.39056,509.27755 368.09375,510.09375 C 367.82399,510.83551 368.03605,511.62868 368.53125,512.21875 L 366.78125,512.21875 C 366.73884,512.21408 366.69882,512.22093 366.65625,512.21875 L 366.65625,516.59375 L 366.78125,516.59375 L 368.53125,516.59375 C 367.85229,517.45345 367.83424,518.70924 368.625,519.5 C 369.47591,520.35091 370.89909,520.35091 371.75,519.5 L 375.09375,516.125 C 375.12672,516.09552 375.15802,516.06422 375.1875,516.03125 C 375.21972,516.01191 375.25101,515.99105 375.28125,515.96875 C 375.28162,515.96839 375.49976,515.68796 375.5,515.6875 C 375.50005,515.68741 375.49338,515.64282 375.5,515.625 C 375.5011,515.62203 375.53002,515.62832 375.53125,515.625 C 375.57039,515.57293 375.58228,515.57321 375.625,515.5 C 375.76199,515.26524 375.79184,515.12809 375.78125,515.15625 C 375.81807,515.06473 375.79977,515.04374 375.8125,515 C 375.82311,514.98978 375.83353,514.97936 375.84375,514.96875 C 375.90379,514.74477 375.93181,514.45186 375.90625,514.1875 C 375.89266,513.98387 375.84739,513.88985 375.84375,513.875 C 375.84389,513.86458 375.84389,513.85417 375.84375,513.84375 C 375.86975,513.94071 375.85901,513.85978 375.75,513.59375 C 375.69753,513.46336 375.66014,513.37439 375.625,513.3125 C 375.57262,513.22275 375.49154,513.05015 375.28125,512.84375 L 371.75,509.3125 C 371.29355,508.82579 370.66491,508.60087 370,508.65625 z" | |||
id="path51988" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" /> | |||
<path | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | |||
d="M 366.65625,515.40625 L 371.28125,515.40625 L 369.46875,517.21875 C 369.0718,517.6157 369.0718,518.2593 369.46875,518.65625 C 369.8657,519.0532 370.5093,519.0532 370.90625,518.65625 L 374.34375,515.1875 L 374.4375,515.125 C 374.44343,515.11918 374.43171,515.09972 374.4375,515.09375 C 374.49291,515.03659 374.5526,514.97676 374.59375,514.90625 C 374.62239,514.85717 374.63663,514.80216 374.65625,514.75 C 374.66861,514.71928 374.67831,514.68783 374.6875,514.65625 C 374.71862,514.54015 374.73024,514.43132 374.71875,514.3125 C 374.71489,514.25466 374.70138,514.21285 374.6875,514.15625 C 374.6766,514.1156 374.67237,514.07059 374.65625,514.03125 C 374.63982,513.99042 374.61578,513.94505 374.59375,513.90625 C 374.5483,513.82838 374.50015,513.74899 374.4375,513.6875 L 370.90625,510.15625 C 370.69734,509.93349 370.39809,509.8184 370.09375,509.84375 C 369.69897,509.8707 369.35398,510.12813 369.21875,510.5 C 369.08351,510.87187 369.18349,511.28826 369.46875,511.5625 L 371.34375,513.40625 L 366.65625,513.40625" | |||
id="path51990" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" /> | |||
</g> | |||
</marker> | |||
<marker | |||
markerWidth="4.0334239" | |||
markerHeight="4.5568175" | |||
orient="auto" | |||
id="marker72805"> | |||
<path | |||
style="fill:#f39300;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | |||
d="M -2.0167119,0.50456824 L 0.29578813,0.50456824 L -0.61046187,1.4108182 C -0.80893187,1.6092982 -0.80893187,1.9310982 -0.61046187,2.1295682 C -0.41198187,2.3280482 -0.090181874,2.3280482 0.10828813,2.1295682 L 1.8270381,0.39519824 L 1.8739181,0.36394824 C 1.8768781,0.36103824 1.8710181,0.35130824 1.8739181,0.34831824 C 1.9016181,0.31973824 1.9314681,0.28982824 1.9520381,0.25456824 C 1.9663581,0.23002824 1.9734781,0.20252824 1.9832881,0.17644824 C 1.9894681,0.16108824 1.9943181,0.14535824 1.9989181,0.12956824 C 2.0144781,0.07151824 2.0202881,0.01710824 2.0145381,-0.04230176 C 2.0126081,-0.07122176 2.0058581,-0.09213176 1.9989181,-0.12043176 C 1.9934681,-0.14075176 1.9913481,-0.16326176 1.9832881,-0.18293176 C 1.9750781,-0.20334176 1.9630581,-0.22603176 1.9520381,-0.24543176 C 1.9293181,-0.28436176 1.9052381,-0.32406176 1.8739181,-0.35480176 L 0.10828813,-2.1204318 C 0.003838126,-2.2318118 -0.14579187,-2.2893518 -0.29796187,-2.2766818 C -0.49535187,-2.2632018 -0.66784187,-2.1344918 -0.73546187,-1.9485518 C -0.80308187,-1.7626218 -0.75309187,-1.5544218 -0.61046187,-1.4173018 L 0.32703813,-0.49543176 L -2.0167119,-0.49543176" | |||
id="path18057" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" /> | |||
</marker> | |||
<marker | |||
markerWidth="4.0334177" | |||
markerHeight="4.5568123" | |||
orient="auto" | |||
id="marker72808"> | |||
<path | |||
style="fill:#d9d9cd;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | |||
d="M -2.016709,0.50457301 L 0.29579105,0.50457301 L -0.61045895,1.410823 C -0.80893895,1.609293 -0.80893895,1.931093 -0.61045895,2.129573 C -0.41198895,2.328043 -0.090188953,2.328043 0.10829105,2.129573 L 1.827041,0.39519301 L 1.873911,0.36394301 C 1.876881,0.36103301 1.871021,0.35130301 1.873911,0.34832301 C 1.901621,0.31974301 1.931461,0.28982301 1.952041,0.25457301 C 1.966361,0.23003301 1.973481,0.20252301 1.983291,0.17644301 C 1.989471,0.16108301 1.994321,0.14536301 1.998911,0.12957301 C 2.014471,0.071523013 2.020281,0.017103013 2.014541,-0.042306987 C 2.012611,-0.071226987 2.005851,-0.092126987 1.998911,-0.12042699 C 1.993461,-0.14075699 1.991351,-0.16325699 1.983291,-0.18292699 C 1.975071,-0.20334699 1.963051,-0.22602699 1.952041,-0.24542699 C 1.929311,-0.28436699 1.905241,-0.32405699 1.873911,-0.35480699 L 0.10829105,-2.120427 C 0.003831047,-2.231807 -0.14578895,-2.289357 -0.29795895,-2.276677 C -0.49534895,-2.263207 -0.66784895,-2.134487 -0.73545895,-1.948557 C -0.80307895,-1.762617 -0.75308895,-1.554427 -0.61045895,-1.417307 L 0.32704105,-0.49542699 L -2.016709,-0.49542699" | |||
id="path72801" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="DotSuN" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="DotSuN" | |||
style="overflow:visible"> | |||
<path | |||
id="path81580" | |||
d="M -2.5,-1 C -2.5,1.76 -4.74,4 -7.5,4 C -10.26,4 -12.5,1.76 -12.5,-1 C -12.5,-3.76 -10.26,-6 -7.5,-6 C -4.74,-6 -2.5,-3.76 -2.5,-1 z" | |||
style="fill:#f39300;fill-rule:evenodd;stroke:#f39300;stroke-width:1pt;marker-start:none;marker-end:none" | |||
transform="matrix(0.2,0,0,0.2,1.48,0.2)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="DotSqO" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="DotSqO" | |||
style="overflow:visible"> | |||
<path | |||
id="path13615" | |||
d="M -2.5,-1 C -2.5,1.76 -4.74,4 -7.5,4 C -10.26,4 -12.5,1.76 -12.5,-1 C -12.5,-3.76 -10.26,-6 -7.5,-6 C -4.74,-6 -2.5,-3.76 -2.5,-1 z" | |||
style="marker-end:none;fill-rule:evenodd;marker-start:none;stroke:#f39300;stroke-width:1pt;fill:#f39300" | |||
transform="matrix(0.2,0,0,0.2,1.48,0.2)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="DotSqOt" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="DotSqOt" | |||
style="overflow:visible"> | |||
<path | |||
id="path13992" | |||
d="M -2.5,-1 C -2.5,1.76 -4.74,4 -7.5,4 C -10.26,4 -12.5,1.76 -12.5,-1 C -12.5,-3.76 -10.26,-6 -7.5,-6 C -4.74,-6 -2.5,-3.76 -2.5,-1 z" | |||
style="marker-end:none;fill-rule:evenodd;marker-start:none;stroke:#49c2f1;stroke-width:1pt;fill:#49c2f1" | |||
transform="matrix(0.2,0,0,0.2,1.48,0.2)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="DotSqOth" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="DotSqOth" | |||
style="overflow:visible"> | |||
<path | |||
id="path14421" | |||
d="M -2.5,-1 C -2.5,1.76 -4.74,4 -7.5,4 C -10.26,4 -12.5,1.76 -12.5,-1 C -12.5,-3.76 -10.26,-6 -7.5,-6 C -4.74,-6 -2.5,-3.76 -2.5,-1 z" | |||
style="marker-end:none;fill-rule:evenodd;marker-start:none;stroke:#d9d9cd;stroke-width:1pt;fill:#d9d9cd" | |||
transform="matrix(0.2,0,0,0.2,1.48,0.2)" /> | |||
</marker> | |||
</defs> | |||
<metadata | |||
id="metadata2480"> | |||
<rdf:RDF> | |||
<cc:Work | |||
rdf:about=""> | |||
<dc:format>image/svg+xml</dc:format> | |||
<dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
</cc:Work> | |||
</rdf:RDF> | |||
</metadata> | |||
<g | |||
inkscape:label="Layer 1" | |||
inkscape:groupmode="layer" | |||
id="layer1"> | |||
<flowRoot | |||
xml:space="preserve" | |||
id="flowRoot2485" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold"><flowRegion | |||
id="flowRegion2487"><rect | |||
id="rect2489" | |||
width="184.28572" | |||
height="120" | |||
x="262.85715" | |||
y="238.07646" | |||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" /></flowRegion><flowPara | |||
id="flowPara2491" /></flowRoot> <g | |||
id="g3178" | |||
transform="translate(-3.5714286,23.214286)" /> | |||
<flowRoot | |||
xml:space="preserve" | |||
id="flowRoot8724" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light"><flowRegion | |||
id="flowRegion8726"><rect | |||
id="rect8728" | |||
width="29.904507" | |||
height="22.868153" | |||
x="39.286312" | |||
y="752.14441" | |||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" /></flowRegion><flowPara | |||
id="flowPara8730" /></flowRoot> <g | |||
id="g18053" | |||
transform="matrix(0.5,0,0,0.5,103.34299,0.7940752)" /> | |||
<path | |||
inkscape:connector-type="polyline" | |||
id="path2544" | |||
d="m 577.33419,399.27065 -417.68723,0" | |||
style="fill:none;stroke:#000000;stroke-width:3.54330707;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none;display:inline" | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
inkscape:connector-type="polyline" | |||
id="path7078" | |||
d="m 578.16752,344.99696 -418.93723,0" | |||
style="fill:none;stroke:#000000;stroke-width:3.54330707;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none;display:inline" | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" /> | |||
<g | |||
id="g7090" | |||
transform="translate(205.28678,114.29679)"> | |||
<rect | |||
ry="3.7880721" | |||
y="237.40155" | |||
x="14.173247" | |||
height="35.433075" | |||
width="72.269569" | |||
id="rect7092" | |||
style="opacity:1;fill:#49c2f1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | |||
<flowRoot | |||
xml:space="preserve" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
id="flowRoot14290" | |||
transform="translate(19.422623,251.0954)"><flowRegion | |||
id="flowRegion14292" /><flowPara | |||
id="flowPara14294">User B</flowPara><flowPara | |||
id="flowPara14296">Request</flowPara></flowRoot> </g> | |||
<g | |||
id="g7100" | |||
transform="translate(160.20793,143.48504)"> | |||
<rect | |||
style="opacity:1;fill:#f39300;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |||
id="rect7102" | |||
width="87.798714" | |||
height="35.93816" | |||
x="172.42705" | |||
y="208.55002" | |||
ry="3.7880721" /> | |||
<flowRoot | |||
xml:space="preserve" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
id="flowRoot7104" | |||
transform="translate(178.96771,222.54606)"><flowRegion | |||
id="flowRegion7106" /><flowPara | |||
id="flowPara14282">User A</flowPara><flowPara | |||
id="flowPara14286">Request</flowPara></flowRoot> </g> | |||
<g | |||
id="g12724" | |||
transform="translate(160.8144,287.6179)"> | |||
<rect | |||
ry="3.7880721" | |||
y="181.8969" | |||
x="234.86888" | |||
height="35.43306" | |||
width="74.409447" | |||
id="rect12726" | |||
style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#49c2f1;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | |||
<flowRoot | |||
xml:space="preserve" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
id="flowRoot12728" | |||
transform="translate(272.73415,204.25271)"><flowRegion | |||
id="flowRegion12730" /><flowPara | |||
id="flowPara12732">Data B</flowPara></flowRoot> </g> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
style="fill:none;stroke:#d9d9cd;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:url(#marker44971);display:inline" | |||
d="m 164.52619,370.82623 24.11062,-0.6048" | |||
id="path8430" | |||
inkscape:connector-type="polyline" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
style="fill:none;stroke:#d9d9cd;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:url(#marker44971);display:inline" | |||
d="m 547.05718,370.82623 24.11062,-0.6048" | |||
id="path13507" | |||
inkscape:connector-type="polyline" | |||
inkscape:connector-curvature="0" /> | |||
<g | |||
id="g13489" | |||
transform="translate(98.710324,234.60224)"> | |||
<flowRoot | |||
xml:space="preserve" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
id="flowRoot13493" | |||
transform="translate(162.53473,193.13766)"><flowRegion | |||
id="flowRegion13495" /><flowPara | |||
id="flowPara13497">Switchable</flowPara><flowPara | |||
id="flowPara13502">Reference</flowPara></flowRoot> <rect | |||
ry="3.7880721" | |||
y="181.8969" | |||
x="234.86888" | |||
height="35.43306" | |||
width="74.409447" | |||
id="rect13491" | |||
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#d9d9cd;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | |||
</g> | |||
<path | |||
style="fill:none;stroke:#f39300;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:url(#DotSqO);display:inline" | |||
d="m 356.13661,451.61897 -9.65403,15.6042" | |||
id="path13881" | |||
inkscape:connector-type="polyline" | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
style="fill:none;stroke:#d9d9cd;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:url(#DotSqOth);display:inline" | |||
d="m 373.0034,423.38453 -0.004,-10.08184" | |||
id="path6576" | |||
inkscape:connector-type="polyline" | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" /> | |||
<g | |||
id="g3696" | |||
transform="translate(38.81777,286.95927)"> | |||
<rect | |||
ry="3.7880721" | |||
y="181.8969" | |||
x="234.86888" | |||
height="35.43306" | |||
width="74.409447" | |||
id="rect3698" | |||
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#f39300;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | |||
<flowRoot | |||
xml:space="preserve" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
id="flowRoot3700" | |||
transform="translate(272.73415,204.25271)"><flowRegion | |||
id="flowRegion3702" /><flowPara | |||
id="flowPara3704">Data A</flowPara></flowRoot> </g> | |||
<path | |||
style="fill:none;stroke:#49c2f1;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:url(#DotSqOt);display:inline" | |||
d="m 388.14963,451.57598 8.51687,14.46247" | |||
id="path13883" | |||
inkscape:connector-type="polyline" | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
style="fill:none;stroke:#49c2f1;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:url(#DotSqOt);display:inline" | |||
d="m 515.13539,381.83876 -0.64979,22.7958" | |||
id="path14262" | |||
inkscape:connector-type="polyline" | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
style="fill:none;stroke:#49c2f1;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:url(#DotSqOt);display:inline" | |||
d="m 289.76931,384.93236 0.16044,20.12321" | |||
id="path14264" | |||
inkscape:connector-type="polyline" | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" /> | |||
<g | |||
id="g14298" | |||
transform="translate(431.12012,114.29679)"> | |||
<rect | |||
ry="3.7880721" | |||
y="237.40155" | |||
x="14.173247" | |||
height="35.433075" | |||
width="72.269569" | |||
id="rect14300" | |||
style="opacity:1;fill:#49c2f1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | |||
<flowRoot | |||
xml:space="preserve" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
id="flowRoot14302" | |||
transform="translate(19.422623,251.0954)"><flowRegion | |||
id="flowRegion14304" /><flowPara | |||
id="flowPara14306">User B</flowPara><flowPara | |||
id="flowPara14308">Request</flowPara></flowRoot> </g> | |||
<path | |||
style="fill:none;stroke:#f39300;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:url(#DotSqO);display:inline" | |||
d="m 372.90447,387.62702 0.0947,18.52085" | |||
id="path14310" | |||
inkscape:connector-type="polyline" | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
style="fill:none;stroke:#d9d9cd;stroke-width:4.00039387;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none;display:inline" | |||
d="M 356.03507,451.60786 372.9481,423.86787" | |||
id="path2540" | |||
inkscape:connector-type="polyline" | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" /> | |||
<flowRoot | |||
xml:space="preserve" | |||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
id="flowRoot7955" | |||
transform="translate(444.56871,337.39513)"><flowRegion | |||
id="flowRegion7957" /><flowPara | |||
id="flowPara7959">transactionStart()</flowPara></flowRoot> <path | |||
style="fill:none;stroke:#f39300;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none;display:inline" | |||
d="m 418.39227,384.45566 0.0947,8.20888" | |||
id="path7961" | |||
inkscape:connector-type="polyline" | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
style="fill:none;stroke:#f39300;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none;display:inline" | |||
d="m 334.74425,384.69509 0.0947,8.20888" | |||
id="path8736" | |||
inkscape:connector-type="polyline" | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
style="fill:none;stroke:#49c2f1;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none;display:inline" | |||
d="m 221.54764,384.9544 0.16044,8.04347" | |||
id="path8738" | |||
inkscape:connector-type="polyline" | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
style="fill:none;stroke:#49c2f1;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none;display:inline" | |||
d="m 447.2753,384.39663 0.16044,8.04347" | |||
id="path9513" | |||
inkscape:connector-type="polyline" | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
style="fill:none;stroke:#000000;stroke-width:1.77165353;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none;display:inline" | |||
d="m 421.96015,389.14884 25.24637,-48.15665" | |||
id="path9515" | |||
inkscape:connector-type="polyline" | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" /> | |||
<flowRoot | |||
xml:space="preserve" | |||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica LT Std;-inkscape-font-specification:Helvetica LT Std Light" | |||
id="flowRoot9517" | |||
transform="translate(304.44491,338.82052)"><flowRegion | |||
id="flowRegion9519" /><flowPara | |||
id="flowPara9521">transactionEnd()</flowPara></flowRoot> <path | |||
style="fill:none;stroke:#000000;stroke-width:1.77165353;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none;display:inline" | |||
d="M 329.87681,389.77384 311.37319,340.78385" | |||
id="path9523" | |||
inkscape:connector-type="polyline" | |||
sodipodi:nodetypes="cc" | |||
inkscape:connector-curvature="0" /> | |||
</g> | |||
</svg> |
@@ -0,0 +1,258 @@ | |||
--- | |||
title: Building the UI | |||
order: 2 | |||
layout: page | |||
--- | |||
[[application.architecture]] | |||
= Building the UI | |||
Vaadin user interfaces are built hierarchically from components, so that the | |||
leaf components are contained within layout components and other component | |||
containers. Building the hierarchy starts from the top (or bottom - whichever | |||
way you like to think about it), from the [classname]#UI# class of the | |||
application. You normally set a layout component as the content of the UI and | |||
fill it with other components. | |||
[source, java] | |||
---- | |||
public class MyHierarchicalUI extends UI { | |||
@Override | |||
protected void init(VaadinRequest request) { | |||
// The root of the component hierarchy | |||
VerticalLayout content = new VerticalLayout(); | |||
content.setSizeFull(); // Use entire window | |||
setContent(content); // Attach to the UI | |||
// Add some component | |||
content.addComponent(new Label("Hello!")); | |||
// Layout inside layout | |||
HorizontalLayout hor = new HorizontalLayout(); | |||
hor.setSizeFull(); // Use all available space | |||
// Couple of horizontally laid out components | |||
Tree tree = new Tree("My Tree", | |||
TreeExample.createTreeContent()); | |||
hor.addComponent(tree); | |||
Table table = new Table("My Table", | |||
TableExample.generateContent()); | |||
table.setSizeFull(); | |||
hor.addComponent(table); | |||
hor.setExpandRatio(table, 1); // Expand to fill | |||
content.addComponent(hor); | |||
content.setExpandRatio(hor, 1); // Expand to fill | |||
} | |||
} | |||
---- | |||
The component hierarchy could be illustrated with a tree as follows: | |||
---- | |||
UI | |||
`-- VerticalLayout | |||
|-- Label | |||
`-- HorizontalLayout | |||
|-- Tree | |||
`-- Table | |||
---- | |||
The result is shown in <<figure.application.architecture.example>>. | |||
[[figure.application.architecture.example]] | |||
.Simple Hierarchical UI | |||
image::img/ui-architecture-hierarchical.png[] | |||
Instead of building the layout in Java, you can also use a declarative design, | |||
as described later in | |||
<<dummy/../../../framework/application/application-declarative#application.declarative,"Designing | |||
UIs Declaratively">>. The examples given for the declarative layouts give | |||
exactly the same UI layout as built from the components above. | |||
The built-in components are described in | |||
<<dummy/../../../framework/components/components-overview.asciidoc#components.overview,"User | |||
Interface Components">> and the layout components in | |||
<<dummy/../../../framework/layout/layout-overview.asciidoc#layout.overview,"Managing | |||
Layout">>. | |||
The example application described above just is, it does not do anything. User | |||
interaction is handled with event listeners, as described a bit later in | |||
<<dummy/../../../framework/application/application-events#application.events,"Handling | |||
Events with Listeners">>. | |||
[[application.architecture.architecture]] | |||
== Application Architecture | |||
Once your application grows beyond a dozen or so lines, which is usually quite | |||
soon, you need to start considering the application architecture more closely. | |||
You are free to use any object-oriented techniques available in Java to organize | |||
your code in methods, classes, packages, and libraries. An architecture defines | |||
how these modules communicate together and what sort of dependencies they have | |||
between them. It also defines the scope of the application. The scope of this | |||
book, however, only gives a possibility to mention some of the most common | |||
architectural patterns in Vaadin applications. | |||
The subsequent sections describe some basic application patterns. For more | |||
information about common architectures, see | |||
<<dummy/../../../framework/advanced/advanced-architecture#advanced.architecture,"Advanced | |||
Application Architectures">>, which discusses layered architectures, the | |||
Model-View-Presenter (MVP) pattern, and so forth. | |||
ifdef::web[] | |||
The | |||
<<dummy/../../../framework/advanced/advanced-global#advanced.global,"Accessing | |||
Session-Global Data">> discusses the problem of passing essentially global | |||
references around, a common problem which is also visited in | |||
<<application.architecture.accessing>>. | |||
endif::web[] | |||
[[application.architecture.composition]] | |||
== Compositing Components | |||
User interfaces typically contain many user interface components in a layout | |||
hierarchy. Vaadin provides many layout components for laying contained | |||
components vertically, horizontally, in a grid, and in many other ways. You can | |||
extend layout components to create composite components. | |||
[source, java] | |||
---- | |||
class MyView extends VerticalLayout { | |||
TextField entry = new TextField("Enter this"); | |||
Label display = new Label("See this"); | |||
Button click = new Button("Click This"); | |||
public MyView() { | |||
addComponent(entry); | |||
addComponent(display); | |||
addComponent(click); | |||
// Configure it a bit | |||
setSizeFull(); | |||
addStyleName("myview"); | |||
} | |||
} | |||
// Use it | |||
Layout myview = new MyView(); | |||
---- | |||
This composition pattern is especially supported for creating forms, as | |||
described in | |||
<<dummy/../../../framework/datamodel/datamodel-itembinding#datamodel.itembinding.formclass,"Binding | |||
Member Fields">>. | |||
While extending layouts is an easy way to make component composition, it is a | |||
good practice to encapsulate implementation details, such as the exact layout | |||
component used. Otherwise, the users of such a composite could begin to rely on | |||
such implementation details, which would make changes harder. For this purpose, | |||
Vaadin has a special [classname]#CustomComponent# wrapper, which hides the | |||
content representation. | |||
[source, java] | |||
---- | |||
class MyView extends CustomComponent { | |||
TextField entry = new TextField("Enter this"); | |||
Label display = new Label("See this"); | |||
Button click = new Button("Click This"); | |||
public MyView() { | |||
Layout layout = new VerticalLayout(); | |||
layout.addComponent(entry); | |||
layout.addComponent(display); | |||
layout.addComponent(click); | |||
setCompositionRoot(layout); | |||
setSizeFull(); | |||
} | |||
} | |||
// Use it | |||
MyView myview = new MyView(); | |||
---- | |||
For a more detailed description of the [classname]#CustomComponent#, see | |||
<<dummy/../../../framework/components/components-customcomponent#components.customcomponent,"Composition | |||
with CustomComponent">>. | |||
[[application.architecture.navigation]] | |||
== View Navigation | |||
While the most simple applications have just a single __view__ (or __screen__), | |||
perhaps most have many. Even in a single view, you often want to have sub-views, | |||
for example to display different content. | |||
<<figure.application.architecture.navigation>> illustrates a typical navigation | |||
between different top-level views of an application, and a main view with | |||
sub-views. | |||
[[figure.application.architecture.navigation]] | |||
.Navigation Between Views | |||
image::img/view-navigation-hi.png[] | |||
The [classname]#Navigator# described in | |||
<<dummy/../../../framework/advanced/advanced-navigator#advanced.navigator,"Navigating | |||
in an Application">> is a view manager that provides a flexible way to navigate | |||
between views and sub-views, while managing the URI fragment in the page URL to | |||
allow bookmarking, linking, and going back in browser history. | |||
Often Vaadin application views are part of something bigger. In such cases, you | |||
may need to integrate the Vaadin applications with the other website. You can | |||
use the embedding techniques described in | |||
<<dummy/../../../framework/advanced/advanced-embedding#advanced.embedding,"Embedding | |||
UIs in Web Pages">>. | |||
[[application.architecture.accessing]] | |||
== Accessing UI, Page, Session, and Service | |||
You can get the UI and the page to which a component is attached to with | |||
[methodname]#getUI()# and [methodname]#getPage()#. | |||
However, the values are [literal]#++null++# until the component is attached to | |||
the UI, and typically, when you need it in constructors, it is not. It is | |||
therefore preferable to access the current UI, page, session, and service | |||
objects from anywhere in the application using the static | |||
[methodname]#getCurrent()# methods in the respective [classname]#UI#, | |||
[classname]#Page#, [classname]#VaadinSession#, and [classname]#VaadinService# | |||
classes. | |||
[source, java] | |||
---- | |||
// Set the default locale of the UI | |||
UI.getCurrent().setLocale(new Locale("en")); | |||
// Set the page title (window or tab caption) | |||
Page.getCurrent().setTitle("My Page"); | |||
// Set a session attribute | |||
VaadinSession.getCurrent().setAttribute("myattrib", "hello"); | |||
// Access the HTTP service parameters | |||
File baseDir = VaadinService.getCurrent().getBaseDirectory(); | |||
---- | |||
You can get the page and the session also from a [classname]#UI# with | |||
[methodname]#getPage()# and [methodname]#getSession()# and the service from | |||
[classname]#VaadinSession# with [methodname]#getService()#. | |||
The static methods use the built-in ThreadLocal support in the classes. | |||
ifdef::web[] | |||
The pattern is described in | |||
<<dummy/../../../framework/advanced/advanced-global#advanced.global.threadlocal,"ThreadLocal | |||
Pattern">>. | |||
endif::web[] | |||
@@ -0,0 +1,398 @@ | |||
--- | |||
title: Designing UIs Declaratively | |||
order: 3 | |||
layout: page | |||
--- | |||
[[application.declarative]] | |||
= Designing UIs Declaratively | |||
Declarative definition of composites and even entire UIs makes it easy for | |||
developers and especially graphical designers to work on visual designs without | |||
any coding. Designs can be modified even while the application is running, as | |||
can be the associated themes. A design is a representation of a component | |||
hierarcy, which can be accessed from Java code to implement dynamic UI logic, as | |||
well as data binding. | |||
For example, considering the following layout in Java: | |||
[source, java] | |||
---- | |||
VerticalLayout vertical = new VerticalLayout (); | |||
vertical.addComponent(new TextField("Name")); | |||
vertical.addComponent(new TextField("Street address")); | |||
vertical.addComponent(new TextField("Postal code")); | |||
layout.addComponent(vertical); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#layout.orderedlayout.basic[on-line example, window="_blank"]. | |||
You could define it declaractively with the following equivalent design: | |||
[source, html] | |||
---- | |||
<v-vertical-layout> | |||
<v-text-field caption="Name"/> | |||
<v-text-field caption="Street address"/> | |||
<v-text-field caption="Postal code"/> | |||
</v-vertical-layout> | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#layout.orderedlayout.basic[on-line example, window="_blank"]. | |||
Declarative designs can be crafted by hand, but are most conveniently created | |||
with the Vaadin Designer. | |||
In the following, we first go through the syntax of the declarative design | |||
files, and then see how to use them in applications by binding them to data and | |||
handling user interaction events. | |||
[[application.declarative.syntax]] | |||
== Declarative Syntax | |||
A design is an HTML document with custom elements for representing components | |||
and their configuration. A design has a single root component inside the HTML | |||
body element. Enclosing [literal]#++<html>++#, [literal]#++<head>++#, | |||
[literal]#++<body>++# are optional, but necessary if you need to make namespace | |||
definitions for custom components. Other regular HTML elements may not be used | |||
in the file, except inside components that specifically accept HTML content. | |||
In a design, each nested element corresponds to a Vaadin component in a | |||
component tree. Components can have explicitly given IDs to enable binding them | |||
to variables in the Java code, as well as optional attributes. | |||
[source, html] | |||
---- | |||
<!DOCTYPE html> | |||
<html> | |||
<body> | |||
<v-vertical-layout size-full> | |||
<!-- Label with HTML content --> | |||
<v-label><b>Hello!</b> - How are you?</v-label> | |||
<v-horizontal-layout size-full :expand> | |||
<v-tree _id="mytree" caption="My Tree" | |||
width-auto height-full/> | |||
<v-table _id="mytable" caption="My Table" | |||
size-full :expand/> | |||
</v-horizontal-layout> | |||
</v-vertical-layout> | |||
</body> | |||
</html> | |||
---- | |||
The DOCTYPE is not required, neither is the [literal]#++<html>++#, or | |||
[literal]#++<body>++# elements. Nevertheless, there may only be one design root | |||
element. | |||
The above design defines the same UI layout as done earlier with Java code, and | |||
illustrated in | |||
<<dummy/../../../framework/application/application-architecture#figure.application.architecture.example,"Simple | |||
Hierarchical UI">>. | |||
[[application.declarative.elements]] | |||
== Component Elements | |||
HTML elements of the declarative syntax are directly mapped to Vaadin components | |||
according to their Java class names. The tag of a component element has a | |||
namespace prefix separated by a dash. Vaadin core components, which are defined | |||
in the [package]#com.vaadin.ui# package, have [literal]#++v-++# prefix. The rest | |||
of an element tag is determined from the Java class name of the component, by | |||
making it lower-case, while adding a dash ( [literal]#++-++#) before every | |||
previously upper-case letter as a word separator. For example, | |||
[classname]#ComboBox# component has declarative element tag | |||
[literal]#++<v-combo-box>++#. | |||
[[application.declarative.elements.prefix]] | |||
=== Component Prefix to Package Mapping | |||
You can use any components in a design: components extending Vaadin components, | |||
composite components, and add-on components. To do so, you need to define a | |||
mapping from an element prefix to the Java package of the component. The prefix | |||
is used as a sort of a namespace. | |||
The mappings are defined in [literal]#++<meta name="package-mapping" ...>++# | |||
elements in the HTML head. A [parameter]#content# attribute defines a mapping, | |||
in notation with a prefix separated from the corresponding Java package name | |||
with a colon, such as " [literal]#++my:com.example.myapp++#". | |||
For example, consider that you have the following composite class | |||
[classname]#com.example.myapp.ExampleComponent#: | |||
[source, java] | |||
---- | |||
package com.example.myapp; | |||
public class ExampleComponent extends CustomComponent { | |||
public ExampleComponent() { | |||
setCompositionRoot(new Label("I am an example.")); | |||
} | |||
} | |||
---- | |||
You would make the package prefix mapping and then use the component as follows: | |||
[subs="normal"] | |||
---- | |||
<!DOCTYPE html> | |||
<html> | |||
<head> | |||
**<meta name="package-mapping" content="my:com.example.myapp" />** | |||
</head> | |||
<body> | |||
<v-vertical-layout> | |||
<v-label><b>Hello!</b> - How are you?</v-label> | |||
<!-- Use it here --> | |||
**<my-example-component/>** | |||
</v-vertical-layout> | |||
</body> | |||
</html> | |||
---- | |||
[[application.declarative.elements.inline]] | |||
=== Inline Content and Data | |||
The element content can be used for certain default attributes, such as a button | |||
caption. For example: | |||
[source, html] | |||
---- | |||
<v-button><b>OK</b></v-button> | |||
---- | |||
Some components, such as selection components, allow defining inline data within | |||
the element. For example: | |||
[source, html] | |||
---- | |||
<v-native-select> | |||
<option>Mercury</option> | |||
<option>Venus</option> | |||
<option selected>Earth</option> | |||
</v-native-select> | |||
---- | |||
The declarative syntax of each component type is described in the JavaDoc API | |||
documentation of Vaadin. | |||
[[application.declarative.attributes]] | |||
== Component Attributes | |||
[[application.declarative.attributes.mapping]] | |||
=== Attribute-to-Property Mapping | |||
Component properties are directly mapped to the attributes of the HTML elements | |||
according to the names of the properties. Attributes are written in lower-case | |||
letters and dash is used for word separation instead of upper-case letters in | |||
the Java methods, so that [literal]#++input-prompt++# attribute is equivalent to | |||
[methodname]#setInputPrompt()#. | |||
For example, the __caption__ property, which you can set with | |||
[methodname]#setCaption()#, is represented as [literal]#++caption++# attribute. | |||
You can find the component properties by the setter methods in the | |||
link:https://vaadin.com/api/[JavaDoc API documentation] of the component | |||
classes. | |||
[source, html] | |||
---- | |||
<v-text-field caption="Name" input-prompt="Enter Name"/> | |||
---- | |||
[[application.declarative.attributes.parameters]] | |||
=== Attribute Values | |||
Attribute parameters must be enclosed in quotes and the value given as a string | |||
must be convertible to the type of the property (string, integer, boolean, or | |||
enumeration). Object types are not supported. | |||
Some attribute names are given by a shorthand. For example, | |||
[parameter]#alternateText# property of the [classname]#Image# component, which | |||
you would set with [methodname]#setAlternateText()#, is given as the | |||
[literal]#++alt++# attribute. | |||
Boolean values must be either " [literal]#++true++#" or " [literal]#++false++#". | |||
The value can be omitted, in which case [literal]#++true++# is assumed. For | |||
example, the [literal]#++enabled++# attribute is boolean and has default value " | |||
[literal]#++true++#", so [literal]#++enabled="true"++# and | |||
[literal]#++enabled++# and equivalent. | |||
[source, html] | |||
---- | |||
<v-button enabled="false">OK</v-button> | |||
---- | |||
[[application.declarative.attributes.parent]] | |||
=== Parent Component Settings | |||
Certain settings, such as a component's alignment in a layout, are not done in | |||
the component itself, but in the layout. Attributes prefixed with colon ( | |||
[literal]#++:++#) are passed to the containing component, with the component as | |||
a target parameter. For example, [literal]#++:expand="1"++# given for a | |||
component [parameter]#c# is equivalent to calling [methodname]#setExpandRatio(c, | |||
1)# for the containing layout. | |||
[subs="normal"] | |||
---- | |||
<v-vertical-layout size-full> | |||
<!-- Align right in the containing layout --> | |||
<v-label width-auto **:right**>Hello!</v-label> | |||
<!-- Expands to take up all remaining vertical space --> | |||
<v-horizontal-layout size-full **:expand**> | |||
<!-- Automatic width - shrinks horizontally --> | |||
<v-tree width-auto height-full/> | |||
<!-- Expands horizontally to take remaining space --> | |||
<v-table size-full **:expand**/> | |||
</v-horizontal-layout> | |||
</v-vertical-layout> | |||
---- | |||
Again, compare the above declaration to the Java code given in | |||
<<dummy/../../../framework/application/application-architecture#application.architecture,"Building | |||
the UI">>. | |||
[[application.declarative.identifiers]] | |||
== Component Identifiers | |||
Components can be identified by either an identifier or a caption. There are two | |||
types of identifiers: page-global and local. This allows accessing them from | |||
Java code and binding them to components, as described later in | |||
<<application.declarative.composite>>. | |||
The [literal]#++id++# attribute can be used to define a page-global identifier, | |||
which must be unique within the page. Another design or UI shown simultaneously | |||
in the same page may not have components sharing the same ID. Using global | |||
identifiers is therefore not recommended, except in special cases where | |||
uniqueness is ensured. | |||
The [literal]#++_id++# attribute defines a local identifier used only within the | |||
design. This is the recommended way to identifying components. | |||
[source, html] | |||
---- | |||
<v-tree _id="mytree" caption="My Tree"/> | |||
---- | |||
[[application.declarative.composite]] | |||
== Using Designs in Code | |||
The main use of declarative designs is in building application views, sub-views, | |||
dialogs, and forms through composition. The two main tasks are filling the | |||
designs with application data and handling user interaction events. | |||
[[application.declarative.composite.designroot]] | |||
=== Binding to a Design Root | |||
You can bind any component container as the root component of a design with the | |||
[classname]#@DesignRoot# annotation. The class must match or extend the class of | |||
the root element in the design. | |||
The member variables are automatically initialized from the design according to | |||
the component identifiers (see <<application.declarative.identifiers>>), which | |||
must match the variable names. | |||
For example, the following class could be used to bind the design given earlier. | |||
[source, java] | |||
---- | |||
@DesignRoot | |||
public class MyViewDesign extends VerticalLayout { | |||
Tree mytree; | |||
Table mytable; | |||
public MyViewDesign() { | |||
Design.read("MyDeclarativeUI.html", this); | |||
// Show some (example) data | |||
mytree.setContainerDataSource( | |||
TreeExample.createTreeContent()); | |||
mytable.setContainerDataSource( | |||
TableExample.generateContent()); | |||
// Some interaction | |||
mytree.addItemClickListener(event -> // Java 8 | |||
Notification.show("Selected " + | |||
event.getItemId())); | |||
} | |||
} | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.declarative.designroot[on-line example, window="_blank"]. | |||
The design root class must match or extend the root element class of the design. | |||
For example, earlier we had [literal]#++<v-vertical-layout>++# element in the | |||
HTML file, which can be bound to a class extending [classname]#VerticalLayout#. | |||
[[application.declarative.composite.using]] | |||
=== Using a Design | |||
The fact that a component is defined declaratively is not visible in its API, so | |||
you can create and use such it just like any other component. | |||
For example, to use the previously defined design root component as the content | |||
of the entire UI: | |||
[source, java] | |||
---- | |||
public class DeclarativeViewUI extends UI { | |||
@Override | |||
protected void init(VaadinRequest request) { | |||
setContent(new MyViewDesign()); | |||
} | |||
} | |||
---- | |||
[[application.declarative.composite.viewnavigation]] | |||
=== Designs in View Navigation | |||
To use a design in view navigation, as described in | |||
<<dummy/../../../framework/advanced/advanced-navigator#advanced.navigator,"Navigating | |||
in an Application">>, you just need to implement the [interfacename]#View# | |||
interface. | |||
[source, java] | |||
---- | |||
@DesignRoot | |||
public class MainView extends VerticalLayout | |||
implements View { | |||
public MainView() { | |||
Design.read(this); | |||
... | |||
} | |||
... | |||
} | |||
... | |||
// Use the view by precreating it | |||
navigator.addView(MAINVIEW, new MainView()); | |||
---- | |||
See | |||
<<dummy/../../../framework/advanced/advanced-navigator#advanced.navigator.urifragment,"Handling | |||
URI Fragment Path">> for a complete example. | |||
@@ -0,0 +1,502 @@ | |||
--- | |||
title: Deploying an Application | |||
order: 9 | |||
layout: page | |||
--- | |||
[[application.environment]] | |||
= Deploying an Application | |||
Vaadin applications are deployed as __Java web applications__, which can contain | |||
a number of servlets, each of which can be a Vaadin application or some other | |||
servlet, and static resources such as HTML files. Such a web application is | |||
normally packaged as a WAR (Web application ARchive) file, which can be deployed | |||
to a Java application server (or a servlet container to be exact). A WAR file, | |||
which has the [filename]#.war# extension, is a subtype of JAR (Java ARchive), | |||
and like a regular JAR, is a ZIP-compressed file with a special content | |||
structure. | |||
For a detailed tutorial on how web applications are packaged, please refer to | |||
any Java book that discusses Java Servlets. | |||
In the Java Servlet parlance, a "web application" means a collection of Java | |||
servlets or portlets, JSP and static HTML pages, and various other resources | |||
that form an application. Such a Java web application is typically packaged as a | |||
WAR package for deployment. Server-side Vaadin UIs run as servlets within such a | |||
Java web application. There exists also other kinds of web applications. To | |||
avoid confusion with the general meaning of "web application", we often refer to | |||
Java web applications with the slight misnomer "WAR" in this book.//TODO Vaadin | |||
7: What is the relationship between servlet and | |||
application? | |||
[[application.environment.war-eclipse]] | |||
== Creating Deployable WAR in Eclipse | |||
To deploy an application to a web server, you need to create a WAR package. Here | |||
we give the instructions for Eclipse. | |||
. Select "File > Export" and then "Web > WAR File". Or, right-click the project in | |||
the Project Explorer and select "Web > WAR File". | |||
. Select the [guilabel]#Web project# to export. Enter [guilabel]#Destination# file | |||
name ( [filename]#.war#). | |||
. Make any other settings in the dialog, and click [guibutton]#Finish#. | |||
[[application.environment.war]] | |||
== Web Application Contents | |||
The following files are required in a web application in order to run it. | |||
[filename]#WEB-INF/web.xml# (optional with Servlet 3.0):: This is the web application descriptor that defines how the application is | |||
organized, that is, what servlets and such it has. You can refer to any Java | |||
book about the contents of this file. It is not needed if you define the Vaadin | |||
servlet with the [literal]#++@WebServlet++# annotation in Servlet API 3.0. | |||
[filename]#WEB-INF/lib/*.jar# :: These are the Vaadin libraries and their dependencies. They can be found in the | |||
installation package or as loaded by a dependency management system such as | |||
Maven or Ivy. | |||
Your UI classes:: You must include your UI classes either in a JAR file in [filename]#WEB-INF/lib# | |||
or as classes in [filename]#WEB-INF/classes# | |||
Your own theme files (OPTIONAL):: If your application uses a special theme (look and feel), you must include it in | |||
[filename]#VAADIN/themes/themename# directory. | |||
Widget sets (OPTIONAL):: If your application uses a project-specific widget set, it must be compiled in | |||
the [filename]#VAADIN/widgetset/# directory. | |||
[[application.environment.webservlet]] | |||
== Web Servlet Class | |||
When using the Servlet 3.0 API, you normally declare the Vaadin servlet classes | |||
with the [literal]#++@WebServlet++# annotation. The Vaadin UI associated with | |||
the servlet and other Vaadin-specific parameters are declared with a separate | |||
[literal]#++@VaadinServletConfiguration++# annotation. | |||
[subs="normal"] | |||
---- | |||
@WebServlet(value = "**/++*++**", | |||
asyncSupported = true) | |||
@VaadinServletConfiguration( | |||
productionMode = **false**, | |||
ui = **MyProjectUI**.class) | |||
public class **MyProjectServlet** extends VaadinServlet { | |||
} | |||
---- | |||
The Vaadin Plugin for Eclipse creates the servlet class as a static inner class | |||
of the UI class. Normally, you may want to have it as a separate regular class. | |||
The [parameter]#value# parameter is the URL pattern for mapping request URLs to | |||
the servlet, as described in <<application.environment.servlet-mapping>>. The | |||
[parameter]#ui# parameter is the UI class. Production mode is disabled by | |||
default, which enabled on-the-fly theme compilation, debug window, and other | |||
such development features. See the subsequent sections for details on the | |||
different servlet and Vaadin configuration parameters. | |||
You can also use a [filename]#web.xml# deployment descriptor in Servlet 3.0 | |||
projects. | |||
[[application.environment.web-xml]] | |||
== Using a [filename]#web.xml# Deployment Descriptor | |||
A deployment descriptor is an XML file with the name [filename]#web.xml# in the | |||
[filename]#WEB-INF# sub-directory of a web application. It is a standard | |||
component in Java EE describing how a web application should be deployed. The | |||
descriptor is not required with Servlet API 3.0, where you can also define | |||
servlets with the [classname]#@WebServlet# annotation as decribed earlier, as | |||
web fragments, or programmatically. You can use both a [filename]#web.xml# and | |||
WebServlet in the same application. Settings in the [filename]#web.xml# override | |||
the ones given in annotations. | |||
The following example shows the basic contents of a deployment descriptor for a | |||
Servlet 2.4 application. You simply specify the UI class with the | |||
[parameter]#UI# parameter for the [classname]#com.vaadin.server.VaadinServlet#. | |||
The servlet is then mapped to a URL path in a standard way for Java Servlets. | |||
[subs="normal"] | |||
---- | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<web-app | |||
id="WebApp_ID" version="2.4" | |||
xmlns="http://java.sun.com/xml/ns/j2ee" | |||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee | |||
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> | |||
<servlet> | |||
<servlet-name>**myservlet**</servlet-name> | |||
<servlet-class> | |||
com.vaadin.server.VaadinServlet | |||
</servlet-class> | |||
<init-param> | |||
<param-name>UI</param-name> | |||
<param-value>**com.ex.myprj.MyUI**</param-value> | |||
</init-param> | |||
<!-- If not using the default widget set--> | |||
<init-param> | |||
<param-name>widgetset</param-name> | |||
<param-value>**com.ex.myprj.MyWidgetSet**</param-value> | |||
</init-param> | |||
</servlet> | |||
<servlet-mapping> | |||
<servlet-name>**myservlet**</servlet-name> | |||
<url-pattern>/*</url-pattern> | |||
</servlet-mapping> | |||
</web-app> | |||
---- | |||
The descriptor defines a servlet with the name [filename]#myservlet#. The | |||
servlet class, [classname]#com.vaadin.server.VaadinServlet#, is provided by | |||
Vaadin framework and is normally the same for all Vaadin projects. For some | |||
purposes, you may need to use a custom servlet class that extends the | |||
[classname]#VaadinServlet#. The class name must include the full package path. | |||
[[application.environment.web-xml.servlet]] | |||
=== Servlet API Version | |||
The descriptor example given above was for Servlet 2.4. For a later version, | |||
such as Servlet 3.0, you should use: | |||
[subs="normal"] | |||
---- | |||
<web-app | |||
id="WebApp_ID" version="**3.0**" | |||
xmlns="http://java.sun.com/xml/ns/j2ee" | |||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
xsi:schemaLocation="**http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd**"> | |||
---- | |||
Servlet 3.0 support is useful for at least server push. | |||
[[application.environment.web-xml.widgetset]] | |||
=== Widget Set | |||
If the UI uses add-on components or custom widgets, it needs a custom widget | |||
set, which can be specified with the [parameter]#widgetset# parameter for the | |||
servlet. Alternatively, you can defined it with the [classname]#@WidgetSet# | |||
annotation for the UI class. The parameter is a class name with the same path | |||
but without the [filename]#.gwt.xml# extension as the widget set definition | |||
file. If the parameter is not given, the | |||
[classname]#com.vaadin.DefaultWidgetSet# is used, which contains all the widgets | |||
for the built-in Vaadin components. | |||
Unless using the default widget set (which is included in the | |||
[filename]#vaadin-client-compiled# JAR), the widget set must be compiled, as | |||
described in | |||
<<dummy/../../../framework/addons/addons-overview.asciidoc#addons.overview,"Using | |||
Vaadin Add-ons">> or | |||
<<dummy/../../../framework/clientside/clientside-compiling#clientside.compiling,"Compiling | |||
a Client-Side Module">>, and properly deployed with the application. | |||
[[application.environment.servlet-mapping]] | |||
== Servlet Mapping with URL Patterns | |||
The servlet needs to be mapped to an URL path, which requests it is to handle. | |||
With [classname]#@WebServlet# annotation for the servlet class: | |||
[subs="normal"] | |||
---- | |||
@WebServlet(value = "**/++*++**", asyncSupported = true) | |||
---- | |||
In a [filename]#web.xml#: | |||
[subs="normal"] | |||
---- | |||
<servlet-mapping> | |||
<servlet-name>**myservlet**</servlet-name> | |||
<url-pattern>/*</url-pattern> | |||
</servlet-mapping> | |||
---- | |||
The URL pattern is defined in the above examples as [literal]#++/*++#. This | |||
matches any URL under the project context. We defined above the project context | |||
as [literal]#++myproject++# so the URL for the page of the UI will be | |||
http://localhost:8080/myproject/. | |||
[[application.environment.servlet-mapping.sub-paths]] | |||
=== Mapping Sub-Paths | |||
If an application has multiple UIs or servlets, they have to be given different | |||
paths in the URL, matched by a different URL pattern. Also, you may need to have | |||
statically served content under some path. Having an URL pattern | |||
[literal]#++/myui/*++# would match a URL such as | |||
http://localhost:8080/myproject/myui/. Notice that the slash and the asterisk | |||
__must__ be included at the end of the pattern. In such case, you also need to | |||
map URLs with [literal]#++/VAADIN/*++# to a servlet (unless you are serving it | |||
statically as noted below). | |||
With a [classname]#@WebServlet# annotation for a servlet class, you can define | |||
multiple mappings as a list enclosed in curly braces as follows: | |||
[subs="normal"] | |||
---- | |||
@WebServlet(value = {"**/myui/++*++**", "/VAADIN/*"}, | |||
asyncSupported = true) | |||
---- | |||
In a [filename]#web.xml#: | |||
[subs="normal"] | |||
---- | |||
... | |||
<servlet-mapping> | |||
<servlet-name>**myservlet**</servlet-name> | |||
<url-pattern>**/myui/++*++**</url-pattern> | |||
</servlet-mapping> | |||
<servlet-mapping> | |||
<servlet-name>**myservlet**</servlet-name> | |||
<url-pattern>/VAADIN/*</url-pattern> | |||
</servlet-mapping> | |||
---- | |||
If you have multiple servlets, you should specify only one | |||
[literal]#++/VAADIN/*++# mapping.It does not matter which servlet you map the | |||
pattern to, as long as it is a Vaadin servlet. | |||
You do not have to provide the above [literal]#++/VAADIN/*++# mapping if you | |||
serve both the widget sets and (custom and default) themes statically in the | |||
[filename]#/VAADIN# directory in the web application. The mapping simply allows | |||
serving them dynamically from the Vaadin JAR. Serving them statically is | |||
recommended for production environments as it is faster. If you serve the | |||
content from within the same web application, you may not have the root pattern | |||
[literal]#++/*++# for the Vaadin servlet, as then all the requests would be | |||
mapped to the servlet. | |||
[[application.environment.parameters]] | |||
== Other Servlet Configuration Parameters | |||
The servlet class or deployment descriptor can have many parameters and options | |||
that control the execution of a servlet. You can find complete documentation of | |||
the basic servlet parameters in the appropriate | |||
link:http://wiki.apache.org/tomcat/Specifications[Java Servlet Specification]. | |||
//// | |||
JCP or Oracle don't seem to have a proper index | |||
URL. | |||
//// | |||
[classname]#@VaadinServletConfiguration# accepts a number of special parameters, | |||
as described below. | |||
In a [filename]#web.xml#, you can set most parameters either as a | |||
[literal]#++<context-param>++# for the entire web application, in which case | |||
they apply to all Vaadin servlets, or as an [literal]#++<init-param>++# for an | |||
individual servlet. If both are defined, servlet parameters override context | |||
parameters. | |||
[[application.environment.parameters.production-mode]] | |||
=== Production Mode | |||
By default, Vaadin applications run in __debug mode__ (or __development mode__), | |||
which should be used during development. This enables various debugging | |||
features. For production use, you should have the | |||
[literal]#++productionMode=true++# setting in the | |||
[classname]#@VaadinServletConfiguration#, or in [filename]#web.xml#: | |||
---- | |||
<context-param> | |||
<param-name>productionMode</param-name> | |||
<param-value>true</param-value> | |||
<description>Vaadin production mode</description> | |||
</context-param> | |||
---- | |||
The parameter and the debug and production modes are described in more detail in | |||
<<dummy/../../../framework/advanced/advanced-debug#advanced.debug,"Debug Mode | |||
and Window">>. | |||
[[application.environment.parameters.uiprovider]] | |||
=== Custom UI Provider | |||
Vaadin normally uses the [classname]#DefaultUIProvider# for creating | |||
[classname]#UI# class instances. If you need to use a custom UI provider, you | |||
can define its class with the [parameter]#UIProvider# parameter. The provider is | |||
registered in the [classname]#VaadinSession#. | |||
In a [filename]#web.xml#: | |||
[subs="normal"] | |||
---- | |||
<servlet> | |||
... | |||
<init-param> | |||
<param-name>UIProvider</param-name> | |||
<param-value>**com.ex.my.MyUIProvider**</param-value> | |||
</init-param> | |||
---- | |||
The parameter is logically associated with a particular servlet, but can be | |||
defined in the context as well. | |||
[[application.environment.parameters.heartbeat]] | |||
=== UI Heartbeat | |||
Vaadin monitors UIs by using a heartbeat, as explained in | |||
<<dummy/../../../framework/application/application-lifecycle#application.lifecycle.ui-expiration,"UI | |||
Expiration">>. If the user closes the browser window of a Vaadin application or | |||
navigates to another page, the Client-Side Engine running in the page stops | |||
sending heartbeat to the server, and the server eventually cleans up the | |||
[classname]#UI# instance. | |||
The interval of the heartbeat requests can be specified in seconds with the | |||
[parameter]#heartbeatInterval# parameter either as a context parameter for the | |||
entire web application or an init parameter for the individual servlet. The | |||
default value is 300 seconds (5 minutes). | |||
In a [filename]#web.xml#: | |||
---- | |||
<context-param> | |||
<param-name>heartbeatInterval</param-name> | |||
<param-value>300</param-value> | |||
</context-param> | |||
---- | |||
[[application.environment.parameters.session-timeout]] | |||
=== Session Timeout After User Inactivity | |||
In normal servlet operation, the session timeout defines the allowed time of | |||
inactivity after which the server should clean up the session. The inactivity is | |||
measured from the last server request. Different servlet containers use varying | |||
defaults for timeouts, such as 30 minutes for Apache Tomcat. You can set the | |||
timeout under [literal]#++<web-app>++# with: | |||
In a [filename]#web.xml#: | |||
((("session-timeout"))) | |||
---- | |||
<session-config> | |||
<session-timeout>30</session-timeout> | |||
</session-config> | |||
---- | |||
((("Out of | |||
Sync"))) | |||
The session timeout should be longer than the heartbeat interval or otherwise | |||
sessions are closed before the heartbeat can keep them alive. As the session | |||
expiration leaves the UIs in a state where they assume that the session still | |||
exists, this would cause an Out Of Sync error notification in the browser. | |||
((("closeIdleSessions"))) | |||
However, having a shorter heartbeat interval than the session timeout, which is | |||
the normal case, prevents the sessions from expiring. If the | |||
[parameter]#closeIdleSessions# parameter for the servlet is enabled (disabled by | |||
default), Vaadin closes the UIs and the session after the time specified in the | |||
[parameter]#session-timeout# parameter expires after the last non-heartbeat | |||
request. | |||
In a [filename]#web.xml#: | |||
---- | |||
<servlet> | |||
... | |||
<init-param> | |||
<param-name>closeIdleSessions</param-name> | |||
<param-value>true</param-value> | |||
</init-param> | |||
---- | |||
[[application.environment.parameters.push]] | |||
=== Push Mode | |||
You can enable server push, as described in | |||
<<dummy/../../../framework/advanced/advanced-push#advanced.push,"Server Push">>, | |||
for a UI either with a [classname]#@Push# annotation for the UI or in the | |||
descriptor. The push mode is defined with a [parameter]#pushmode# parameter. The | |||
[literal]#++automatic++# mode pushes changes to the browser automatically after | |||
__access()__ finishes. With [literal]#++manual++# mode, you need to do the push | |||
explicitly with [methodname]#push()#. If you use a Servlet 3.0 compatible | |||
server, you also want to enable asynchronous processing with the | |||
[literal]#++async-supported++# parameter. | |||
In a [filename]#web.xml#: | |||
[subs="normal"] | |||
---- | |||
<servlet> | |||
... | |||
<init-param> | |||
<param-name>pushmode</param-name> | |||
<param-value>**automatic**</param-value> | |||
</init-param> | |||
<async-supported>**true**</async-supported> | |||
---- | |||
[[application.environment.parameters.xsrf]] | |||
=== Cross-Site Request Forgery Prevention | |||
Vaadin uses a protection mechanism to prevent malicious cross-site request | |||
forgery (XSRF or CSRF), also called one-click attacks or session riding, which | |||
is a security exploit for executing unauthorized commands in a web server. This | |||
protection is normally enabled. However, it prevents some forms of testing of | |||
Vaadin applications, such as with JMeter. In such cases, you can disable the | |||
protection by setting the [parameter]#disable-xsrf-protection# parameter to | |||
[literal]#++true++#. | |||
In a [filename]#web.xml#: | |||
---- | |||
<context-param> | |||
<param-name>disable-xsrf-protection</param-name> | |||
<param-value>true</param-value> | |||
</context-param> | |||
---- | |||
[[application.environment.configuration]] | |||
== Deployment Configuration | |||
The Vaadin-specific parameters defined in the deployment configuration are | |||
available from the [classname]#DeploymentConfiguration# object managed by the | |||
[classname]#VaadinSession#. | |||
[source, java] | |||
---- | |||
DeploymentConfiguration conf = | |||
getSession().getConfiguration(); | |||
// Heartbeat interval in seconds | |||
int heartbeatInterval = conf.getHeartbeatInterval(); | |||
---- | |||
Parameters defined in the Java Servlet definition, such as the session timeout, | |||
are available from the low-level [classname]#HttpSession# or | |||
[classname]#PortletSession# object, which are wrapped in a | |||
[classname]#WrappedSession# in Vaadin. You can access the low-level session | |||
wrapper with [methodname]#getSession()# of the [classname]#VaadinSession#. | |||
[source, java] | |||
---- | |||
WrappedSession session = getSession().getSession(); | |||
int sessionTimeout = session.getMaxInactiveInterval(); | |||
---- | |||
You can also access other [classname]#HttpSession# and | |||
[classname]#PortletSession# session properties through the interface, such as | |||
set and read session attributes that are shared by all servlets belonging to a | |||
particular servlet or portlet session. | |||
@@ -0,0 +1,189 @@ | |||
--- | |||
title: Handling Errors | |||
order: 6 | |||
layout: page | |||
--- | |||
[[application.errors]] | |||
= Handling Errors | |||
[[application.errors.error-indicator]] | |||
== Error Indicator and Message | |||
All components have a built-in error indicator that is turned on if validating | |||
the component fails, and can be set explicitly with | |||
[methodname]#setComponentError()#. Usually, the error indicator is placed right | |||
of the component caption. The error indicator is part of the component caption, | |||
so its placement is usually managed by the layout in which the component is | |||
contained, but some components handle it themselves. Hovering the mouse pointer | |||
over the field displays the error message. | |||
[source, java] | |||
---- | |||
textfield.setComponentError(new UserError("Bad value")); | |||
button.setComponentError(new UserError("Bad click")); | |||
---- | |||
The result is shown in <<figure.application.errors.error-indicator>>. | |||
[[figure.application.errors.error-indicator]] | |||
.Error Indicator Active | |||
image::img/errorindicator-example2.png[] | |||
ifdef::web[] | |||
[[application.errors.systemmessages]] | |||
== Customizing System Messages | |||
System messages are notifications that indicate a major invalid state that | |||
usually requires restarting the application. Session timeout is perhaps the most | |||
typical such state. | |||
System messages are strings managed in the [classname]#SystemMessages# class. | |||
sessionExpired:: ((("session", | |||
"expiration"))) | |||
((("session", | |||
"timeout"))) | |||
The Vaadin session expired. A session expires if no server requests are made | |||
during the session timeout period. The session timeout can be configured with | |||
the [parameter]#session-timeout# parameter in [filename]#web.xml#, as described | |||
in | |||
<<dummy/../../../framework/application/application-environment#application.environment.web-xml,"Using | |||
a web.xml Deployment Descriptor">>. | |||
communicationError:: An unspecified communication problem between the Vaadin Client-Side Engine and | |||
the application server. The server may be unavailable or there is some other | |||
problem. | |||
authenticationError:: This error occurs if 401 (Unauthorized) response to a request is received from | |||
the server. | |||
internalError:: A serious internal problem, possibly indicating a bug in Vaadin Client-Side | |||
Engine or in some custom client-side code. | |||
outOfSync:: The client-side state is invalid with respect to server-side state. | |||
cookiesDisabled:: Informs the user that cookies are disabled in the browser and the application | |||
does not work without them. | |||
Each message has four properties: a short caption, the actual message, a URL to | |||
which to redirect after displaying the message, and property indicating whether | |||
the notification is enabled. | |||
Additional details may be written (in English) to the debug console window | |||
described in | |||
<<dummy/../../../framework/advanced/advanced-debug#advanced.debug,"Debug Mode | |||
and Window">>. | |||
You can override the default system messages by setting the | |||
[interfacename]#SystemMessagesProvider# in the [classname]#VaadinService#. You | |||
need to implement the [methodname]#getSystemMessages()# method, which should | |||
return a [classname]#SystemMessages# object. The easiest way to customize the | |||
messages is to use a [classname]#CustomizedSystemMessages# object. | |||
You can set the system message provider in the | |||
[methodname]#servletInitialized()# method of a custom servlet class, for example | |||
as follows: | |||
[source, java] | |||
---- | |||
getService().setSystemMessagesProvider( | |||
new SystemMessagesProvider() { | |||
@Override | |||
public SystemMessages getSystemMessages( | |||
SystemMessagesInfo systemMessagesInfo) { | |||
CustomizedSystemMessages messages = | |||
new CustomizedSystemMessages(); | |||
messages.setCommunicationErrorCaption("Comm Err"); | |||
messages.setCommunicationErrorMessage("This is bad."); | |||
messages.setCommunicationErrorNotificationEnabled(true); | |||
messages.setCommunicationErrorURL("http://vaadin.com/"); | |||
return messages; | |||
} | |||
}); | |||
---- | |||
See | |||
<<dummy/../../../framework/application/application-lifecycle#application.lifecycle.servlet-service,"Vaadin | |||
Servlet, Portlet, and Service">> for information about customizing Vaadin | |||
servlets. | |||
endif::web[] | |||
ifdef::web[] | |||
[[application.errors.unchecked-exceptions]] | |||
== Handling Uncaught Exceptions | |||
Handling events can result in exceptions either in the application logic or in | |||
the framework itself, but some of them may not be caught properly by the | |||
application. Any such exceptions are eventually caught by the framework. It | |||
delegates the exceptions to the [classname]#DefaultErrorHandler#, which displays | |||
the error as a component error, that is, with a small red "!" -sign (depending | |||
on the theme). If the user hovers the mouse pointer over it, the entire | |||
backtrace of the exception is shown in a large tooltip box, as illustrated in | |||
<<figure.application.errors.unchecked-exceptions>>. | |||
[[figure.application.errors.unchecked-exceptions]] | |||
.Uncaught Exception in Component Error Indicator | |||
image::img/errorindicator-exception.png[] | |||
You can customize the default error handling by implementing a custom | |||
[interfacename]#ErrorHandler# and enabling it with | |||
[methodname]#setErrorHandler()# in any of the components in the component | |||
hierarchy, including the [classname]#UI#, or in the [classname]#VaadinSession# | |||
object. You can either implement the [interfacename]#ErrorHandler# or extend the | |||
[classname]#DefaultErrorHandler#. In the following example, we modify the | |||
behavior of the default handler. | |||
[source, java] | |||
---- | |||
// Here's some code that produces an uncaught exception | |||
final VerticalLayout layout = new VerticalLayout(); | |||
final Button button = new Button("Click Me!", | |||
new Button.ClickListener() { | |||
public void buttonClick(ClickEvent event) { | |||
((String)null).length(); // Null-pointer exception | |||
} | |||
}); | |||
layout.addComponent(button); | |||
// Configure the error handler for the UI | |||
UI.getCurrent().setErrorHandler(new DefaultErrorHandler() { | |||
@Override | |||
public void error(com.vaadin.server.ErrorEvent event) { | |||
// Find the final cause | |||
String cause = "<b>The click failed because:</b><br/>"; | |||
for (Throwable t = event.getThrowable(); t != null; | |||
t = t.getCause()) | |||
if (t.getCause() == null) // We're at final cause | |||
cause += t.getClass().getName() + "<br/>"; | |||
// Display the error message in a custom fashion | |||
layout.addComponent(new Label(cause, ContentMode.HTML)); | |||
// Do the default error handling (optional) | |||
doDefault(event); | |||
} | |||
}); | |||
---- | |||
The above example also demonstrates how to dig up the final cause from the cause | |||
stack. | |||
When extending [classname]#DefaultErrorHandler#, you can call | |||
[methodname]#doDefault()# as was done above to run the default error handling, | |||
such as set the component error for the component where the exception was | |||
thrown. See the source code of the implementation for more details. You can call | |||
[methodname]#findAbstractComponent(event)# to find the component that caused the | |||
error. If the error is not associated with a component, it returns null. | |||
endif::web[] | |||
@@ -0,0 +1,195 @@ | |||
--- | |||
title: Handling Events with Listeners | |||
order: 4 | |||
layout: page | |||
--- | |||
[[application.events]] | |||
= Handling Events with Listeners | |||
Let us put into practice what we learned of event handling in | |||
<<dummy/../../../framework/architecture/architecture-events#architecture.events,"Events | |||
and Listeners">>. You can implement listener interfaces in a regular class, but | |||
it brings the problem with differentiating between different event sources. | |||
Using anonymous class for listeners is recommended in most cases. | |||
[[application.events.anonymous]] | |||
== Using Anonymous Classes | |||
By far the easiest and the most common way to handle events in Java 6 and 7 is | |||
to use anonymous local classes. It encapsulates the handling of events to where | |||
the component is defined and does not require cumbering the managing class with | |||
interface implementations. The following example defines an anonymous class that | |||
inherits the [classname]#Button.ClickListener# interface. | |||
[source, java] | |||
---- | |||
// Have a component that fires click events | |||
final Button button = new Button("Click Me!"); | |||
// Handle the events with an anonymous class | |||
button.addClickListener(new Button.ClickListener() { | |||
public void buttonClick(ClickEvent event) { | |||
button.setCaption("You made me click!"); | |||
} | |||
}); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.eventlistener.anonymous[on-line example, window="_blank"]. | |||
Local objects referenced from within an anonymous class, such as the | |||
[classname]#Button# object in the above example, must be declared | |||
[literal]#++final++#. | |||
Most components allow passing a listener to the constructor, thereby losing a | |||
line or two. However, notice that if accessing the component that is constructed | |||
from an anonymous class, you must use a reference that is declared before the | |||
constructor is executed, for example as a member variable in the outer class. If | |||
it is declared in the same expression where the constructor is called, it | |||
doesn't yet exist. In such cases, you need to get a reference to the component | |||
from the event object. | |||
[source, java] | |||
---- | |||
final Button button = new Button("Click It!", | |||
new Button.ClickListener() { | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
event.getButton().setCaption("Done!"); | |||
} | |||
}); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.eventlistener.constructor[on-line example, window="_blank"]. | |||
[[application.events.java8]] | |||
== Handling Events in Java 8 | |||
Java 8 introduced lambda expressions, which offer a replacement for listeners. | |||
You can directly use lambda expressions in place of listeners that have only one | |||
method to implement. | |||
For example, in the following, we use a lambda expression to handle button click | |||
events in the constructor: | |||
[source, java] | |||
---- | |||
layout.addComponent(new Button("Click Me!", | |||
event -> event.getButton().setCaption("You made click!"))); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.eventlistener.java8[on-line example, window="_blank"]. | |||
Java 8 is the future that is already here, and as Vaadin API uses event | |||
listeners extensively, using lambda expressions makes UI code much more | |||
readable. | |||
Directing events to handler methods is easy with method references: | |||
[source, java] | |||
---- | |||
public class Java8Buttons extends CustomComponent { | |||
public Java8Buttons() { | |||
setCompositionRoot(new HorizontalLayout( | |||
new Button("OK", this::ok), | |||
new Button("Cancel", this::cancel))); | |||
} | |||
public void ok(ClickEvent event) { | |||
event.getButton().setCaption ("OK!"); | |||
} | |||
public void cancel(ClickEvent event) { | |||
event.getButton().setCaption ("Not OK!"); | |||
} | |||
} | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.eventlistener.java8differentiation[on-line example, window="_blank"]. | |||
[[application.events.classlistener]] | |||
== Implementing a Listener in a Regular Class | |||
The following example follows a typical pattern where you have a | |||
[classname]#Button# component and a listener that handles user interaction | |||
(clicks) communicated to the application as events. Here we define a class that | |||
listens to click events. | |||
[source, java] | |||
---- | |||
public class MyComposite extends CustomComponent | |||
implements Button.ClickListener { | |||
Button button; // Defined here for access | |||
public MyComposite() { | |||
Layout layout = new HorizontalLayout(); | |||
// Just a single component in this composition | |||
button = new Button("Do not push this"); | |||
button.addClickListener(this); | |||
layout.addComponent(button); | |||
setCompositionRoot(layout); | |||
} | |||
// The listener method implementation | |||
public void buttonClick(ClickEvent event) { | |||
button.setCaption("Do not push this again"); | |||
} | |||
} | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.eventlistener.classlistener[on-line example, window="_blank"]. | |||
[[application.events.differentiation]] | |||
== Differentiating Between Event Sources | |||
If an application receives events of the same type from multiple sources, such | |||
as multiple buttons, it has to be able to distinguish between the sources. If | |||
using a regular class listener, distinguishing between the components can be | |||
done by comparing the source of the event with each of the components. The | |||
method for identifying the source depends on the event type. | |||
[source, java] | |||
---- | |||
public class TheButtons extends CustomComponent | |||
implements Button.ClickListener { | |||
Button onebutton; | |||
Button toobutton; | |||
public TheButtons() { | |||
onebutton = new Button("Button One", this); | |||
toobutton = new Button("A Button Too", this); | |||
// Put them in some layout | |||
Layout root = new HorizontalLayout(); | |||
root.addComponent(onebutton); | |||
root.addComponent(toobutton); | |||
setCompositionRoot(root); | |||
} | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
// Differentiate targets by event source | |||
if (event.getButton() == onebutton) | |||
onebutton.setCaption ("Pushed one"); | |||
else if (event.getButton() == toobutton) | |||
toobutton.setCaption ("Pushed too"); | |||
} | |||
} | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.eventlistener.differentiation[on-line example, window="_blank"]. | |||
Other techniques exist for separating between event sources, such as using | |||
object properties, names, or captions to separate between them. Using captions | |||
or any other visible text is generally discouraged, as it may create problems | |||
for internationalization. Using other symbolic strings can also be dangerous, | |||
because the syntax of such strings is checked only at runtime. | |||
@@ -0,0 +1,502 @@ | |||
--- | |||
title: Application Lifecycle | |||
order: 8 | |||
layout: page | |||
--- | |||
[[application.lifecycle]] | |||
= Application Lifecycle | |||
In this section, we look into more technical details of application deployment, | |||
user sessions, and UI instance lifecycle. These details are not generally needed | |||
for writing Vaadin applications, but may be useful for understanding how they | |||
actually work and, especially, in what circumstances their execution ends. | |||
[[application.lifecycle.deployment]] | |||
== Deployment | |||
Before a Vaadin application can be used, it has to be deployed to a Java web | |||
server, as described in | |||
<<dummy/../../../framework/application/application-environment#application.environment,"Deploying | |||
an Application">>. Deploying reads the servlet classes annotated with the | |||
[literal]#++@WebServlet++# annotation (Servlet 3.0) or the [filename]#web.xml# | |||
deployment descriptor (Servlet 2.4) in the application to register servlets for | |||
specific URL paths and loads the classes. Deployment does not yet normally run | |||
any code in the application, although static blocks in classes are executed when | |||
they are loaded. | |||
[[application.lifecycle.deployment.redeployment]] | |||
=== Undeploying and Redeploying | |||
Applications are undeployed when the server shuts down, during redeployment, and | |||
when they are explicitly undeployed. Undeploying a server-side Vaadin | |||
application ends its execution, all application classes are unloaded, and the | |||
heap space allocated by the application is freed for garbage-collection. | |||
If any user sessions are open at this point, the client-side state of the UIs is | |||
left hanging and an Out of Sync error is displayed on the next server request. | |||
[[application.lifecycle.deployment.serialization]] | |||
=== Redeployment and Serialization | |||
Some servers, such as Tomcat, support __hot deployment__, where the classes are | |||
reloaded while preserving the memory state of the application. This is done by | |||
serializing the application state and then deserializing it after the classes | |||
are reloaded. This is, in fact, done with the basic Eclipse setup with Tomcat | |||
and if a UI is marked as [classname]#@PreserveOnRefresh#, you may actually need | |||
to give the [literal]#++?restartApplication++# URL parameter to force it to | |||
restart when you reload the page. Tools such as JRebel go even further by | |||
reloading the code in place without need for serialization. The server can also | |||
serialize the application state when shutting down and restarting, thereby | |||
preserving sessions over restarts. | |||
Serialization requires that the applications are __serializable__, that is, all | |||
classes implement the [interfacename]#Serializable# interface. All Vaadin | |||
classes do. If you extend them or implement interfaces, you can provide an | |||
optional serialization key, which is automatically generated by Eclipse if you | |||
use it. Serialization is also used for clustering and cloud computing, such as | |||
with Google App Engine. | |||
ifdef::web[] | |||
For more about that topic, see | |||
<<dummy/../../../framework/advanced/advanced-gae#advanced.gae,"Google App Engine | |||
Integration">>. | |||
endif::web[] | |||
[[application.lifecycle.servlet-service]] | |||
== Vaadin Servlet, Portlet, and Service | |||
The [classname]#VaadinServlet#, or [classname]#VaadinPortlet# in a portal, | |||
receives all server requests mapped to it by its URL, as defined in the | |||
deployment configuration, and associates them with sessions. The sessions | |||
further associate the requests with particular UIs. | |||
When servicing requests, the Vaadin servlet or portlet handles all tasks common | |||
to both servlets and portlets in a [classname]#VaadinService#. It manages | |||
sessions, gives access to the deployment configuration information, handles | |||
system messages, and does various other tasks. Any further servlet or portlet | |||
specific tasks are handled in the corresponding | |||
[classname]#VaadinServletService# or [classname]#VaadinPortletService#. The | |||
service acts as the primary low-level customization layer for processing | |||
requests. | |||
[[application.lifecycle.servlet-service.servletcustomization]] | |||
=== Customizing Vaadin Servlet | |||
Many common configuration tasks need to be done in the servlet class, which you | |||
already have if you are using the [literal]#++@WebServlet++# annotation for | |||
Servlet 3.0 to deploy the application. You can handle most customization by | |||
overriding the [methodname]#servletInitialized()# method, where the | |||
[classname]#VaadinService# object is available with [methodname]#getService()# | |||
(it would not be available in a constructor). You should always call | |||
[methodname]#super.servletInitialized()# in the beginning. | |||
[source, java] | |||
---- | |||
public class MyServlet extends VaadinServlet { | |||
@Override | |||
protected void servletInitialized() | |||
throws ServletException { | |||
super.servletInitialized(); | |||
... | |||
} | |||
} | |||
---- | |||
To add custom functionality around request handling, you can override the | |||
[methodname]#service()# method. | |||
To use the custom servlet class in a Servlet 2.4 project, you need to define it | |||
in the [filename]#web.xml# deployment descriptor instead of the regular | |||
[classname]#VaadinServlet# class, as described in | |||
<<dummy/../../../framework/application/application-environment#application.environment.web-xml,"Using | |||
a web.xml Deployment Descriptor">>. | |||
ifdef::web[] | |||
[[application.lifecycle.servlet-service.portletcustomization]] | |||
=== Customizing Vaadin Portlet | |||
__To Be Done__ | |||
endif::web[] | |||
ifdef::web[] | |||
[[application.lifecycle.servlet-service.servicecustomization]] | |||
=== Customizing Vaadin Service | |||
To customize [classname]#VaadinService#, you first need to extend the | |||
[classname]#VaadinServlet# or - [classname]#Portlet# class and override the | |||
[methodname]#createServletService()# to create a custom service object. | |||
endif::web[] | |||
[[application.lifecycle.session]] | |||
== User Session | |||
((("session"))) | |||
A user session begins when a user first makes a request to a Vaadin servlet or | |||
portlet by opening the URL for a particular [classname]#UI#. All server requests | |||
belonging to a particular UI class are processed by the | |||
[classname]#VaadinServlet# or [classname]#VaadinPortlet# class. When a new | |||
client connects, it creates a new user session, represented by an instance of | |||
[classname]#VaadinSession#. Sessions are tracked using cookies stored in the | |||
browser. | |||
You can obtain the [classname]#VaadinSession# of a [classname]#UI# with | |||
[methodname]#getSession()# or globally with | |||
[methodname]#VaadinSession.getCurrent()#. It also provides access to the | |||
lower-level session objects, [interfacename]#HttpSession# and | |||
[interfacename]#PortletSession#, through a [classname]#WrappedSession#. You can | |||
also access the deployment configuration through [classname]#VaadinSession#, as | |||
described in | |||
<<dummy/../../../framework/application/application-environment#application.environment.configuration,"Deployment | |||
Configuration">>. | |||
A session ends after the last [classname]#UI# instance expires or is closed, as | |||
described later. | |||
[[application.lifecycle.session.init]] | |||
=== Handling Session Initialization and Destruction | |||
((("[classname]#SessionInitListener#"))) | |||
((("[classname]#SessionDestroyListener#"))) | |||
((("[classname]#VaadinService#"))) | |||
You can handle session initialization and destruction by implementing a | |||
[interfacename]#SessionInitListener# or [interfacename]#SessionDestroyListener#, | |||
respectively, to the [classname]#VaadinService#. | |||
((("[methodname]#servletInitialized()#"))) | |||
((("[classname]#VaadinServlet#"))) | |||
You can do that best by extending [classname]#VaadinServlet# and overriding the | |||
[methodname]#servletInitialized()# method, as outlined in | |||
<<application.lifecycle.servlet-service>>. | |||
[source, java] | |||
---- | |||
public class MyServlet extends VaadinServlet | |||
implements SessionInitListener, SessionDestroyListener { | |||
@Override | |||
protected void servletInitialized() throws ServletException { | |||
super.servletInitialized(); | |||
getService().addSessionInitListener(this); | |||
getService().addSessionDestroyListener(this); | |||
} | |||
@Override | |||
public void sessionInit(SessionInitEvent event) | |||
throws ServiceException { | |||
// Do session start stuff here | |||
} | |||
@Override | |||
public void sessionDestroy(SessionDestroyEvent event) { | |||
// Do session end stuff here | |||
} | |||
} | |||
---- | |||
If using Servlet 2.4, you need to configure the custom servlet class in the | |||
[parameter]#servlet-class# parameter in the [filename]#web.xml# descriptor | |||
instead of the [classname]#VaadinServlet#, as described in | |||
<<dummy/../../../framework/application/application-environment#application.environment.web-xml,"Using | |||
a web.xml Deployment Descriptor">>. | |||
[[application.lifecycle.ui]] | |||
== Loading a UI | |||
((("UI", "loading"))) | |||
When a browser first accesses a URL mapped to the servlet of a particular UI | |||
class, the Vaadin servlet generates a loader page. The page loads the | |||
client-side engine (widget set), which in turn loads the UI in a separate | |||
request to the Vaadin servlet. | |||
((("[classname]#UIProvider#"))) | |||
((("[classname]#DefaultUIProvider#"))) | |||
((("[classname]#BrowserWindowOpener#"))) | |||
A [classname]#UI# instance is created when the client-side engine makes its | |||
first request. The servlet creates the UIs using a [classname]#UIProvider# | |||
registered in the [classname]#VaadinSession# instance. A session has at least a | |||
[classname]#DefaultUIProvider# for managing UIs opened by the user. If the | |||
application lets the user open popup windows with a | |||
[classname]#BrowserWindowOpener#, each of them has a dedicated special UI | |||
provider. | |||
((("[classname]#VaadinRequest#"))) | |||
((("[methodname]#init()#"))) | |||
Once a new UI is created, its [methodname]#init()# method is called. The method | |||
gets the request as a [classname]#VaadinRequest#. | |||
[[application.lifecycle.ui.loaderpage]] | |||
=== Customizing the Loader Page | |||
The HTML content of the loader page is generated as an HTML DOM object, which | |||
can be customized by implementing a [interfacename]#BootstrapListener# that | |||
modifies the DOM object. To do so, you need to extend the | |||
[classname]#VaadinServlet# and add a [interfacename]#SessionInitListener# to the | |||
service object, as outlined in <<application.lifecycle.session>>. You can then | |||
add the bootstrap listener to a session with | |||
[methodname]#addBootstrapListener()# when the session is initialized. | |||
Loading the widget set is handled in the loader page with functions defined in a | |||
separate [filename]#vaadinBootstrap.js# script. | |||
You can also use entirely custom loader code, such as in a static HTML page, as | |||
described in | |||
<<dummy/../../../framework/advanced/advanced-embedding#advanced.embedding,"Embedding | |||
UIs in Web Pages">>. | |||
[[application.lifecycle.ui.uiprovider]] | |||
=== Custom UI Providers | |||
((("[interfacename]#UIProvider#", "custom"))) | |||
You can create UI objects dynamically according to their request parameters, | |||
such as the URL path, by defining a custom [interfacename]#UIProvider#. You need | |||
to add custom UI providers to the session object which calls them. The providers | |||
are chained so that they are requested starting from the one added last, until | |||
one returns a UI (otherwise they return null). You can add a UI provider to a | |||
session most conveniently by implementing a custom servlet and adding the UI | |||
provider to sessions in a [interfacename]#SessionInitListener#. | |||
You can find an example of custom UI providers in | |||
<<dummy/../../../mobile/mobile-features#mobile.features.fallback,"Providing a | |||
Fallback UI">>. | |||
[[application.lifecycle.ui.preserving]] | |||
=== Preserving UI on Refresh | |||
((("UI", "preserving on refresh"))) | |||
((("[classname]#@PreserveOnRefresh#"))) | |||
Reloading a page in the browser normally spawns a new [classname]#UI# instance | |||
and the old UI is left hanging, until cleaned up after a while. This can be | |||
undesired as it resets the UI state for the user. To preserve the UI, you can | |||
use the [classname]#@PreserveOnRefresh# annotation for the UI class. You can | |||
also use a [classname]#UIProvider# with a custom implementation of | |||
[methodname]#isUiPreserved()#. | |||
[source, java] | |||
---- | |||
@PreserveOnRefresh | |||
public class MyUI extends UI { | |||
---- | |||
Adding the ?restartApplication parameter in the URL tells the Vaadin servlet to | |||
create a new [classname]#UI# instance when loading the page, thereby overriding | |||
the [classname]#@PreserveOnRefresh#. This is often necessary when developing | |||
such a UI in Eclipse, when you need to restart it after redeploying, because | |||
Eclipse likes to persist the application state between redeployments. If you | |||
also include a URI fragment, the parameter should be given before the fragment. | |||
[[application.lifecycle.ui-expiration]] | |||
== UI Expiration | |||
((("UI", "expiration"))) | |||
[classname]#UI# instances are cleaned up if no communication is received from | |||
them after some time. If no other server requests are made, the client-side | |||
sends keep-alive heartbeat requests. A UI is kept alive for as long as requests | |||
or heartbeats are received from it. It expires if three consecutive heartbeats | |||
are missed. | |||
The heartbeats occur at an interval of 5 minutes, which can be changed with the | |||
[parameter]#heartbeatInterval# parameter of the servlet. You can configure the | |||
parameter in [classname]#@VaadinServletConfiguration# or in [filename]#web.xml# | |||
as described in | |||
<<dummy/../../../framework/application/application-environment#application.environment.parameters,"Other | |||
Servlet Configuration Parameters">>. | |||
When the UI cleanup happens, a [classname]#DetachEvent# is sent to all | |||
[classname]#DetachListener#s added to the UI. When the [classname]#UI# is | |||
detached from the session, [methodname]#detach()# is called for it. | |||
[[application.lifecycle.ui-closing]] | |||
== Closing UIs Explicitly | |||
((("UI", "closing"))) | |||
((("[methodname]#close()#", | |||
"UI"))) | |||
You can explicitly close a UI with [methodname]#close()#. The method marks the | |||
UI to be detached from the session after processing the current request. | |||
Therefore, the method does not invalidate the UI instance immediately and the | |||
response is sent as usual. | |||
Detaching a UI does not close the page or browser window in which the UI is | |||
running and further server request will cause error. Typically, you either want | |||
to close the window, reload it, or redirect it to another URL. If the page is a | |||
regular browser window or tab, browsers generally do not allow closing them | |||
programmatically, but redirection is possible. You can redirect the window to | |||
another URL with [methodname]#setLocation()#, as is done in the examples in | |||
<<application.lifecycle.session-closing>>. You can close popup windows by making | |||
JavaScript [methodname]#close()# call for them, as described in | |||
<<dummy/../../../framework/advanced/advanced-windows#advanced.windows.popup-closing,"Closing | |||
Popup Windows">>. | |||
If you close other UI than the one associated with the current request, they | |||
will not be detached at the end of the current request, but after next request | |||
from the particular UI. You can make that occur quicker by making the UI | |||
heartbeat faster or immediately by using server push. | |||
[[application.lifecycle.session-expiration]] | |||
== Session Expiration | |||
((("session", "expiration"))) | |||
A session is kept alive by server requests caused by user interaction with the | |||
application as well as the heartbeat monitoring of the UIs. Once all UIs have | |||
expired, the session still remains. It is cleaned up from the server when the | |||
session timeout configured in the web application expires. | |||
((("closeIdleSessions"))) | |||
If there are active UIs in an application, their heartbeat keeps the session | |||
alive indefinitely. You may want to have the sessions timeout if the user is | |||
inactive long enough, which is the original purpose of the session timeout | |||
setting. ((("session", | |||
"timeout"))) | |||
((("closeIdleSessions"))) | |||
If the [parameter]#closeIdleSessions# parameter of the servlet is set to | |||
[literal]#++true++# in the [filename]#web.xml#, as described in | |||
<<dummy/../../../framework/application/application-environment#application.environment.web-xml,"Using | |||
a web.xml Deployment Descriptor">>, the session and all of its UIs are closed | |||
when the timeout specified by the [parameter]#session-timeout# parameter of the | |||
servlet expires after the last non-heartbeat request. Once the session is gone, | |||
the browser will show an Out Of Sync error on the next server request. | |||
((("redirection"))) | |||
To avoid the ugly message, you may want to set a redirect URL for the UIs | |||
ifdef::web[] | |||
, as described in | |||
<<dummy/../../../framework/application/application-errors#application.errors.systemmessages,"Customizing | |||
System | |||
Messages">> | |||
endif::web[] | |||
. | |||
The related configuration parameters are described in | |||
<<dummy/../../../framework/application/application-environment#application.environment.parameters,"Other | |||
Servlet Configuration Parameters">>. | |||
((("[interfacename]#SessionDestroyListener#"))) | |||
You can handle session expiration on the server-side with a | |||
[interfacename]#SessionDestroyListener#, as described in | |||
<<application.lifecycle.session>>. | |||
[[application.lifecycle.session-closing]] | |||
== Closing a Session | |||
((("session", "closing"))) | |||
((("[methodname]#close()#"))) | |||
You can close a session by calling [methodname]#close()# on the | |||
[classname]#VaadinSession#. It is typically used when logging a user out and the | |||
session and all the UIs belonging to the session should be closed. The session | |||
is closed immediately and any objects related to it are not available after | |||
calling the method. | |||
When closing the session from a UI, you typically want to redirect the user to | |||
another URL. | |||
((("redirection"))) | |||
((("[methodname]#setLocation()#"))) | |||
((("Page", | |||
"[methodname]#setLocation()#"))) | |||
You can do the redirect using the [methodname]#setLocation()# method in | |||
[classname]#Page#. This needs to be done before closing the session, as the UI | |||
or page are not available after that. In the following example, we display a | |||
logout button, which closes the user session. | |||
((("logout"))) | |||
[source, java] | |||
---- | |||
public class MyUI extends UI { | |||
@Override | |||
protected void init(VaadinRequest request) { | |||
setContent(new Button("Logout", event -> {// Java 8 | |||
// Redirect this page immediately | |||
getPage().setLocation("/myapp/logout.html"); | |||
// Close the session | |||
getSession().close(); | |||
})); | |||
// Notice quickly if other UIs are closed | |||
setPollInterval(3000); | |||
} | |||
} | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.lifecycle.closing[on-line example, window="_blank"]. | |||
This is not enough. When a session is closed from one UI, any other UIs attached | |||
to it are left hanging. When the client-side engine notices that a UI and the | |||
session are gone on the server-side, it displays a "Session Expired" message | |||
and, by default, reloads the UI when the message is clicked. ((("session", | |||
"expiration"))) | |||
((("redirection"))) | |||
((("system | |||
messages"))) | |||
You can customize the message and the redirect URL in the system messages | |||
ifdef::web[] | |||
, as described in | |||
<<dummy/../../../framework/application/application-errors#application.errors.systemmessages,"Customizing | |||
System | |||
Messages">> | |||
endif::web[] | |||
. | |||
((("heartbeat"))) | |||
((("UI", | |||
"heartbeat"))) | |||
((("push"))) | |||
((("server | |||
push"))) | |||
The client-side engine notices the expiration when user interaction causes a | |||
server request to be made or when the keep-alive heartbeat occurs. To make the | |||
UIs detect the situation faster, you need to make the heart beat faster, as was | |||
done in the example above. You can also use server push to close the other UIs | |||
immediately, as is done in the following example. Access to the UIs must be | |||
synchronized as described in | |||
<<dummy/../../../framework/advanced/advanced-push#advanced.push,"Server Push">>. | |||
[source, java] | |||
---- | |||
@Push | |||
public class MyPushyUI extends UI { | |||
@Override | |||
protected void init(VaadinRequest request) { | |||
setContent(new Button("Logout", event -> {// Java 8 | |||
for (UI ui: VaadinSession.getCurrent().getUIs()) | |||
ui.access(() -> { | |||
// Redirect from the page | |||
ui.getPage().setLocation("/logout.html"); | |||
}); | |||
getSession().close(); | |||
})); | |||
} | |||
} | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.lifecycle.closingall[on-line example, window="_blank"]. | |||
In the above example, we assume that all UIs in the session have push enabled | |||
and that they should be redirected; popups you might want to close instead of | |||
redirecting. It is not necessary to call [methodname]#close()# for them | |||
individually, as we close the entire session afterwards. | |||
@@ -0,0 +1,177 @@ | |||
--- | |||
title: Notifications | |||
order: 7 | |||
layout: page | |||
--- | |||
[[application.notifications]] | |||
= Notifications | |||
Notifications are error or information boxes that appear briefly, typically at | |||
the center of the screen. A notification box has a caption and an optional | |||
description and icon. The box stays on the screen either for a preset time or | |||
until the user clicks it. The notification type defines the default appearance | |||
and behaviour of a notification. | |||
There are two ways to create a notification. The easiest is to use a static | |||
shorthand [methodname]#Notification.show()# method, which takes the caption of | |||
the notification as a parameter, and an optional description and notification | |||
type, and displays it in the current page. | |||
[source, java] | |||
---- | |||
Notification.show("This is the caption", | |||
"This is the description", | |||
Notification.Type.WARNING_MESSAGE); | |||
---- | |||
[[figure.notification.example1]] | |||
.Notification | |||
image::img/notification-example2.png[] | |||
For more control, you can create a [classname]#Notification# object. Different | |||
constructors exist for taking just the caption, and optionally the description, | |||
notification type, and whether HTML is allowed or not. Notifications are shown | |||
in a [classname]#Page#, typically the current page. | |||
[source, java] | |||
---- | |||
new Notification("This is a warning", | |||
"<br/>This is the <i>last</i> warning", | |||
Notification.TYPE_WARNING_MESSAGE, true) | |||
.show(Page.getCurrent()); | |||
---- | |||
The caption and description are by default written on the same line. If you want | |||
to have a line break between them, use the HTML line break markup " | |||
[literal]#++<br/>++#" if HTML is enabled, or " [literal]#++\n++#" if not. HTML | |||
is disabled by default, but can be enabled with | |||
[methodname]#setHtmlContentAllowed(true)#. When enabled, you can use any HTML | |||
markup in the caption and description of a notification. If it is in any way | |||
possible to get the notification content from user input, you should either | |||
disallow HTML or sanitize the content carefully, as noted in | |||
<<dummy/../../../framework/advanced/advanced-security#advanced.security.sanitizing,"Sanitizing | |||
User Input to Prevent Cross-Site Scripting">>. | |||
[[figure.notification.example2]] | |||
.Notification with HTML Formatting | |||
image::img/notification-example3.png[] | |||
[[application.notifications.type]] | |||
== Notification Type | |||
The notification type defines the overall default style and behaviour of a | |||
notification. If no notification type is given, the "humanized" type is used as | |||
the default. The notification types, listed below, are defined in the | |||
[classname]#Notification.Type# class. | |||
[parameter]#TYPE_HUMANIZED_MESSAGE# image:[]:: A user-friendly message that does not annoy too much: it does not require | |||
confirmation by clicking and disappears quickly. It is centered and has a | |||
neutral gray color. | |||
[parameter]#TYPE_WARNING_MESSAGE# image:[]:: Warnings are messages of medium importance. They are displayed with colors that | |||
are neither neutral nor too distractive. A warning is displayed for 1.5 seconds, | |||
but the user can click the message box to dismiss it. The user can continue to | |||
interact with the application while the warning is displayed. | |||
[parameter]#TYPE_ERROR_MESSAGE# image:[]:: Error messages are notifications that require the highest user attention, with | |||
alert colors, and they require the user to click the message to dismiss it. The | |||
error message box does not itself include an instruction to click the message, | |||
although the close box in the upper right corner indicates it visually. Unlike | |||
with other notifications, the user can not interact with the application while | |||
the error message is displayed. | |||
[parameter]#TYPE_TRAY_NOTIFICATION# image:[]:: Tray notifications are displayed in the "system tray" area, that is, in the | |||
lower-right corner of the browser view. As they do not usually obscure any user | |||
interface, they are displayed longer than humanized or warning messages, 3 | |||
seconds by default. The user can continue to interact with the application | |||
normally while the tray notification is displayed. | |||
ifdef::web[] | |||
[[application.notifications.customization]] | |||
== Customizing Notifications | |||
All of the features of specific notification types can be controlled with the | |||
[classname]#Notification# properties. Once configured, you need to show it in | |||
the current page. | |||
[source, java] | |||
---- | |||
// Notification with default settings for a warning | |||
Notification notif = new Notification( | |||
"Warning", | |||
"<br/>Area of reindeer husbandry", | |||
Notification.TYPE_WARNING_MESSAGE); | |||
// Customize it | |||
notif.setDelayMsec(20000); | |||
notif.setPosition(Position.BOTTOM_RIGHT); | |||
notif.setStyleName("mystyle"); | |||
notif.setIcon(new ThemeResource("img/reindeer.png")); | |||
// Show it in the page | |||
notif.show(Page.getCurrent()); | |||
---- | |||
The [methodname]#setPosition()# method allows setting the positioning of the | |||
notification. The position can be specified by any of the constants defined in | |||
the [classname]#Position# enum. | |||
The [methodname]#setDelayMSec()# allows setting the time for how long the | |||
notification is displayed in milliseconds. Parameter value [literal]#++-1++# | |||
means that the message is displayed until the user clicks the message box. It | |||
also prevents interaction with other parts of the application window, which is | |||
the default behaviour for error notifications. It does not, however, add a close | |||
box that the error notification has. | |||
endif::web[] | |||
[[application.notifications.css]] | |||
== Styling with CSS | |||
[source, css] | |||
---- | |||
.v-Notification {} | |||
.popupContent {} | |||
.gwt-HTML {} | |||
h1 {} | |||
p {} | |||
---- | |||
The notification box is a floating [literal]#++div++# element under the | |||
[literal]#++body++# element of the page. It has an overall | |||
[literal]#++v-Notification++# style. The content is wrapped inside an element | |||
with [literal]#++popupContent++# style. The caption is enclosed within an | |||
[literal]#++h1++# element and the description in a [literal]#++p++# element. | |||
To customize it, add a style for the [classname]#Notification# object with | |||
[methodname]#setStyleName("mystyle")#, and make the settings in the theme, for | |||
example as follows: | |||
[source, css] | |||
---- | |||
.v-Notification.mystyle { | |||
background: #FFFF00; | |||
border: 10px solid #C00000; | |||
color: black; | |||
} | |||
---- | |||
The result is shown, with the icon set earlier in the customization example, in | |||
<<figure.application.errors.notifications.css>>. | |||
[[figure.application.errors.notifications.css]] | |||
.A Styled Notification | |||
image::img/notification-customization.png[] | |||
@@ -0,0 +1,158 @@ | |||
--- | |||
title: Overview | |||
order: 1 | |||
layout: page | |||
--- | |||
[[application.overview]] | |||
= Overview | |||
A server-side Vaadin application runs as a Java Servlet in a servlet container. | |||
The Java Servlet API is, however, hidden behind the framework. The user | |||
interface of the application is implemented as a __UI__ class, which needs to | |||
create and manage the user interface components that make up the user interface. | |||
User input is handled with event listeners, although it is also possible to bind | |||
the user interface components directly to data. The visual style of the | |||
application is defined in themes as CSS or Sass. Icons, other images, and | |||
downloadable files are handled as __resources__, which can be external or served | |||
by the application server or the application itself. | |||
[[figure.application.architecture]] | |||
.Server-Side Application Architecture | |||
image::img/application-architecture-hi.png[] | |||
<<figure.application.architecture>> illustrates the basic architecture of an | |||
application made with the Vaadin Framework, with all the major elements, which | |||
are introduced below and discussed in detail in this chapter. | |||
First of all, a Vaadin application must have one or more UI classes that extend | |||
the abstract [classname]#com.vaadin.ui.UI# class and implement the | |||
[methodname]#init()# method. A custom theme can be defined as an annotation for | |||
the UI. | |||
[source, java] | |||
---- | |||
@Theme("hellotheme") | |||
public class HelloWorld extends UI { | |||
protected void init(VaadinRequest request) { | |||
... initialization code goes here ... | |||
} | |||
} | |||
---- | |||
A UI is a viewport to a Vaadin application running in a web page. A web page can | |||
actually have multiple such UIs within it. Such situation is typical especially | |||
with portlets in a portal. An application can run in multiple browser windows, | |||
each having a distinct [classname]#UI# instance. The UIs of an application can | |||
be the same UI class or different. | |||
Vaadin framework handles servlet requests internally and associates the requests | |||
with user sessions and a UI state. Because of this, you can develop Vaadin | |||
applications much like you would develop desktop applications. | |||
The most important task in the initialization is the creation of the initial | |||
user interface. This, and the deployment of a UI as a Java Servlet in the | |||
Servlet container, as described in | |||
<<dummy/../../../framework/application/application-environment#application.environment,"Deploying | |||
an Application">>, are the minimal requirements for an application. | |||
Below is a short overview of the other basic elements of an application besides | |||
UI: | |||
UI:: A __UI__ represents an HTML fragment in which a Vaadin application runs in a web | |||
page. It typically fills the entire page, but can also be just a part of a page. | |||
You normally develop a Vaadin application by extending the [classname]#UI# class | |||
and adding content to it. A UI is essentially a viewport connected to a user | |||
session of an application, and you can have many such views, especially in a | |||
multi-window application. Normally, when the user opens a new page with the URL | |||
of the Vaadin UI, a new [classname]#UI# (and the associated [classname]#Page# | |||
object) is automatically created for it. All of them share the same user | |||
session. | |||
+ | |||
The current UI object can be accessed globally with | |||
[methodname]#UI.getCurrent()#. The static method returns the thread-local UI | |||
instance for the currently processed request | |||
ifdef::web[] | |||
(see | |||
<<dummy/../../../framework/advanced/advanced-global#advanced.global.threadlocal,"ThreadLocal | |||
Pattern">>) | |||
endif::web[] | |||
. | |||
Page:: A [classname]#UI# is associated with a [classname]#Page# object that represents | |||
the web page as well as the browser window in which the UI runs. | |||
+ | |||
The [classname]#Page# object for the currently processed request can be accessed | |||
globally from a Vaadin application with [methodname]#Page.getCurrent()#. This is | |||
equivalent to calling [methodname]#UI.getCurrent().getPage()#. | |||
Vaadin Session:: A [classname]#VaadinSession# object represents a user session with one or more | |||
UIs open in the application. A session starts when a user first opens a UI of a | |||
Vaadin application, and closes when the session expires in the server or when it | |||
is closed explicitly. | |||
User Interface Components:: The user interface consists of components that are created by the application. | |||
They are laid out hierarchically using special __layout components__, with a | |||
content root layout at the top of the hierarchy. User interaction with the | |||
components causes __events__ related to the component, which the application can | |||
handle. __Field components__ are intended for inputting values and can be | |||
directly bound to data using the Vaadin Data Model. You can make your own user | |||
interface components through either inheritance or composition. For a thorough | |||
reference of user interface components, see | |||
<<dummy/../../../framework/components/components-overview.asciidoc#components.overview,"User | |||
Interface Components">>, for layout components, see | |||
<<dummy/../../../framework/layout/layout-overview.asciidoc#layout.overview,"Managing | |||
Layout">>, and for compositing components, see | |||
<<dummy/../../../framework/components/components-customcomponent#components.customcomponent,"Composition | |||
with CustomComponent">>. | |||
Events and Listeners:: Vaadin follows an event-driven programming paradigm, in which events, and | |||
listeners that handle the events, are the basis of handling user interaction in | |||
an application (although also server push is possible as described in | |||
<<dummy/../../../framework/advanced/advanced-push#advanced.push,"Server | |||
Push">>). | |||
<<dummy/../../../framework/architecture/architecture-events#architecture.events,"Events | |||
and Listeners">> gave an introduction to events and listeners from an | |||
architectural point-of-view, while | |||
<<dummy/../../../framework/application/application-events#application.events,"Handling | |||
Events with Listeners">> later in this chapter takes a more practical view. | |||
Resources:: A user interface can display images or have links to web pages or downloadable | |||
documents. These are handled as __resources__, which can be external or provided | |||
by the web server or the application itself. | |||
<<dummy/../../../framework/application/application-resources#application.resources,"Images | |||
and Other Resources">> gives a practical overview of the different types of | |||
resources. | |||
Themes:: The presentation and logic of the user interface are separated. While the UI | |||
logic is handled as Java code, the presentation is defined in __themes__ as CSS | |||
or SCSS. Vaadin includes some built-in themes. User-defined themes can, in | |||
addition to style sheets, include HTML templates that define custom layouts and | |||
other theme resources, such as images. Themes are discussed in detail in | |||
<<dummy/../../../framework/themes/themes-overview.asciidoc#themes.overview,"Themes">>, | |||
custom layouts in | |||
<<dummy/../../../framework/layout/layout-customlayout#layout.customlayout,"Custom | |||
Layouts">>, and theme resources in | |||
<<dummy/../../../framework/application/application-resources#application.resources.theme,"Theme | |||
Resources">>. | |||
Data Binding:: Field components are essentially views to data, represented in the __Vaadin Data | |||
Model__. Using the data model, the components can get their values from and | |||
update user input to the data model directly, without the need for any control | |||
code. A field component is always bound to a __property__ and a group of fields | |||
to an __item__ that holds the properties. Items can be collected in a | |||
__container__, which can act as a data source for some components such as tables | |||
or lists. While all the components have a default data model, they can be bound | |||
to a user-defined data source. For example, you can bind a [classname]#Table# | |||
component to an SQL query response. For a complete overview of data binding in | |||
Vaadin, please refer to | |||
<<dummy/../../../framework/datamodel/datamodel-overview.asciidoc#datamodel.overview,"Binding | |||
Components to Data">>. | |||
@@ -0,0 +1,245 @@ | |||
--- | |||
title: Images and Other Resources | |||
order: 5 | |||
layout: page | |||
--- | |||
[[application.resources]] | |||
= Images and Other Resources | |||
Web applications can display various __resources__, such as images, other | |||
embedded content, or downloadable files, that the browser has to load from the | |||
server. Image resources are typically displayed with the [classname]#Image# | |||
component or as component icons. Flash animations can be displayed with | |||
[classname]#Flash#, embedded browser frames with [classname]#BrowserFrame#, and | |||
other content with the [classname]#Embedded# component, as described in | |||
<<dummy/../../../framework/components/components-embedded#components.embedded,"Embedded | |||
Resources">>. Downloadable files are usually provided by clicking a | |||
[classname]#Link#. | |||
There are several ways to how such resources can be provided by the web server. | |||
Static resources can be provided without having to ask for them from the | |||
application. For dynamic resources, the user application must be able to create | |||
them dynamically. The resource request interfaces in Vaadin allow applications | |||
to both refer to static resources as well as dynamically create them. The | |||
dynamic creation includes the [classname]#StreamResource# class and the | |||
[interfacename]#RequestHandler# described in | |||
<<dummy/../../../framework/advanced/advanced-requesthandler#advanced.requesthandler,"Request | |||
Handlers">>. | |||
Vaadin also provides low-level facilities for retrieving the URI and other | |||
parameters of a HTTP request. We will first look into how applications can | |||
provide various kinds of resources and then look into low-level interfaces for | |||
handling URIs and parameters to provide resources and functionalities. | |||
Notice that using request handlers to create "pages" is not normally meaningful | |||
in Vaadin or in AJAX applications generally. Please see | |||
<<dummy/../../../framework/architecture/architecture-technology#architecture.technology.ajax,"AJAX">> | |||
for a detailed explanation. | |||
[[application.resources.api]] | |||
== Resource Interfaces and Classes | |||
The resource classes in Vaadin are grouped under two interfaces: a generic | |||
[classname]#Resource# interface and a more specific | |||
[classname]#ConnectorResource# interface for resources provided by the servlet. | |||
[[figure.resource.classdiagram]] | |||
.Resource Interface and Class Diagram | |||
image::img/resource_classdiagram-hi.png[] | |||
[[application.resources.file]] | |||
== File Resources | |||
File resources are files stored anywhere in the file system. As such, they can | |||
not be retrieved by a regular URL from the server, but need to be requested | |||
through the Vaadin servlet. The use of file resources is typically necessary for | |||
persistent user data that is not packaged in the web application, which would | |||
not be persistent over redeployments. | |||
A file object that can be accessed as a file resource is defined with the | |||
standard [classname]#java.io.File# class. You can create the file either with an | |||
absolute or relative path, but the base path of the relative path depends on the | |||
installation of the web server. For example, with Apache Tomcat, the default | |||
current directory would be the installation path of Tomcat. | |||
In the following example, we provide an image resource from a file stored in the | |||
web application. Notice that the image is stored under the [filename]#WEB-INF# | |||
folder, which is a special folder that is never accessible using an URL, unlike | |||
the other folders of a web application. This is a security solution - another | |||
would be to store the resource elsewhere in the file system. | |||
[source, java] | |||
---- | |||
// Find the application directory | |||
String basepath = VaadinService.getCurrent() | |||
.getBaseDirectory().getAbsolutePath(); | |||
// Image as a file resource | |||
FileResource resource = new FileResource(new File(basepath + | |||
"/WEB-INF/images/image.png")); | |||
// Show the image in the application | |||
Image image = new Image("Image from file", resource); | |||
// Let the user view the file in browser or download it | |||
Link link = new Link("Link to the image file", resource); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.resources.fileresource[on-line example, window="_blank"]. | |||
The result, as well as the folder structure where the file is stored under a | |||
regular Eclipse Vaadin project, is shown in | |||
<<figure.application.resources.file>>. | |||
[[figure.application.resources.file]] | |||
.File Resource | |||
image::img/resource-fileresource.png[] | |||
[[application.resources.class]] | |||
== Class Loader Resources | |||
The [classname]#ClassResource# allows resources to be loaded from the class path | |||
using Java Class Loader. Normally, the relevant class path entry is the | |||
[filename]#WEB-INF/classes# folder under the web application, where the Java | |||
compilation should compile the Java classes and copy other files from the source | |||
tree. | |||
The one-line example below loads an image resource from the application package | |||
and displays it in an [classname]#Image# component. | |||
[source, java] | |||
---- | |||
layout.addComponent(new Image(null, | |||
new ClassResource("smiley.jpg"))); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.resources.classresource[on-line example, window="_blank"]. | |||
[[application.resources.theme]] | |||
== Theme Resources | |||
Theme resources of [classname]#ThemeResource# class are files, typically images, | |||
included in a theme. A theme is located with the path | |||
[filename]#VAADIN/themes/themename# in a web application. The name of a theme | |||
resource is given as the parameter for the constructor, with a path relative to | |||
the theme folder. | |||
[source, java] | |||
---- | |||
// A theme resource in the current theme ("mytheme") | |||
// Located in: VAADIN/themes/mytheme/img/themeimage.png | |||
ThemeResource resource = new ThemeResource("img/themeimage.png"); | |||
// Use the resource | |||
Image image = new Image("My Theme Image", resource); | |||
---- | |||
See the http://demo.vaadin.com/book-examples-vaadin7/book#application.resources.themeresource[on-line example, window="_blank"]. | |||
The result is shown in <<figure.application.resources.theme>>, also illustrating | |||
the folder structure for the theme resource file in an Eclipse project. | |||
[[figure.application.resources.theme]] | |||
.Theme Resources | |||
image::img/resource-themeimage.png[] | |||
To use theme resources, you must set the theme for the UI. See | |||
<<dummy/../../../framework/themes/themes-overview.asciidoc#themes.overview,"Themes">> | |||
for more information regarding themes. | |||
[[application.resources.stream]] | |||
== Stream Resources | |||
Stream resources allow creating dynamic resource content. Charts are typical | |||
examples of dynamic images. To define a stream resource, you need to implement | |||
the [classname]#StreamResource.StreamSource# interface and its | |||
[methodname]#getStream()# method. The method needs to return an | |||
[classname]#InputStream# from which the stream can be read. | |||
The following example demonstrates the creation of a simple image in PNG image | |||
format. | |||
[source, java] | |||
---- | |||
import java.awt.image.*; | |||
public class MyImageSource | |||
implements StreamResource.StreamSource { | |||
ByteArrayOutputStream imagebuffer = null; | |||
int reloads = 0; | |||
/* We need to implement this method that returns | |||
* the resource as a stream. */ | |||
public InputStream getStream () { | |||
/* Create an image and draw something on it. */ | |||
BufferedImage image = new BufferedImage (200, 200, | |||
BufferedImage.TYPE_INT_RGB); | |||
Graphics drawable = image.getGraphics(); | |||
drawable.setColor(Color.lightGray); | |||
drawable.fillRect(0,0,200,200); | |||
drawable.setColor(Color.yellow); | |||
drawable.fillOval(25,25,150,150); | |||
drawable.setColor(Color.blue); | |||
drawable.drawRect(0,0,199,199); | |||
drawable.setColor(Color.black); | |||
drawable.drawString("Reloads="+reloads, 75, 100); | |||
reloads++; | |||
try { | |||
/* Write the image to a buffer. */ | |||
imagebuffer = new ByteArrayOutputStream(); | |||
ImageIO.write(image, "png", imagebuffer); | |||
/* Return a stream from the buffer. */ | |||
return new ByteArrayInputStream( | |||
imagebuffer.toByteArray()); | |||
} catch (IOException e) { | |||
return null; | |||
} | |||
} | |||
} | |||
---- | |||
The content of the generated image is dynamic, as it updates the reloads counter | |||
with every call. The [classname]#ImageIO#. [methodname]#write()# method writes | |||
the image to an output stream, while we had to return an input stream, so we | |||
stored the image contents to a temporary buffer. | |||
Below we display the image with the [classname]#Image# component. | |||
[source, java] | |||
---- | |||
// Create an instance of our stream source. | |||
StreamResource.StreamSource imagesource = new MyImageSource (); | |||
// Create a resource that uses the stream source and give it a name. | |||
// The constructor will automatically register the resource in | |||
// the application. | |||
StreamResource resource = | |||
new StreamResource(imagesource, "myimage.png"); | |||
// Create an image component that gets its contents | |||
// from the resource. | |||
layout.addComponent(new Image("Image title", resource)); | |||
---- | |||
The resulting image is shown in <<figure.application.resource.stream>>. | |||
[[figure.application.resource.stream]] | |||
.A Stream Resource | |||
image::img/application_streamresource.png[] | |||
Another way to create dynamic content is a request handler, described in | |||
<<dummy/../../../framework/advanced/advanced-requesthandler#advanced.requesthandler,"Request | |||
Handlers">>. | |||
@@ -0,0 +1,25 @@ | |||
[[application]] | |||
== Writing a Server-Side Web Application | |||
This chapter provides the fundamentals of server-side web application | |||
development with Vaadin, concentrating on the basic elements of an application | |||
from a practical point-of-view. | |||
include::application-overview.asciidoc[leveloffset=+2] | |||
include::application-architecture.asciidoc[leveloffset=+2] | |||
include::application-declarative.asciidoc[leveloffset=+2] | |||
include::application-events.asciidoc[leveloffset=+2] | |||
include::application-resources.asciidoc[leveloffset=+2] | |||
include::application-errors.asciidoc[leveloffset=+2] | |||
include::application-notifications.asciidoc[leveloffset=+2] | |||
include::application-lifecycle.asciidoc[leveloffset=+2] | |||
include::application-environment.asciidoc[leveloffset=+2] |
@@ -0,0 +1,799 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<!-- Created with Inkscape (http://www.inkscape.org/) --> | |||
<svg | |||
xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
xmlns:cc="http://creativecommons.org/ns#" | |||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" | |||
xmlns:xlink="http://www.w3.org/1999/xlink" | |||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
width="210mm" | |||
height="297mm" | |||
id="svg1901" | |||
sodipodi:version="0.32" | |||
inkscape:version="0.48.2 r9819" | |||
sodipodi:docname="resource_classdiagram.svg" | |||
inkscape:output_extension="org.inkscape.output.svg.inkscape" | |||
sodipodi:modified="true" | |||
version="1.1"> | |||
<defs | |||
id="defs1903"> | |||
<marker | |||
id="marker44971" | |||
orient="auto" | |||
markerHeight="5.7450781" | |||
markerWidth="4.6297355"> | |||
<g | |||
id="g18059" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path18061" | |||
d="M 370,508.65625 C 369.13933,508.715 368.39056,509.27755 368.09375,510.09375 C 367.82399,510.83551 368.03605,511.62868 368.53125,512.21875 L 366.78125,512.21875 C 366.73884,512.21408 366.69882,512.22093 366.65625,512.21875 L 366.65625,516.59375 L 366.78125,516.59375 L 368.53125,516.59375 C 367.85229,517.45345 367.83424,518.70924 368.625,519.5 C 369.47591,520.35091 370.89909,520.35091 371.75,519.5 L 375.09375,516.125 C 375.12672,516.09552 375.15802,516.06422 375.1875,516.03125 C 375.21972,516.01191 375.25101,515.99105 375.28125,515.96875 C 375.28162,515.96839 375.49976,515.68796 375.5,515.6875 C 375.50005,515.68741 375.49338,515.64282 375.5,515.625 C 375.5011,515.62203 375.53002,515.62832 375.53125,515.625 C 375.57039,515.57293 375.58228,515.57321 375.625,515.5 C 375.76199,515.26524 375.79184,515.12809 375.78125,515.15625 C 375.81807,515.06473 375.79977,515.04374 375.8125,515 C 375.82311,514.98978 375.83353,514.97936 375.84375,514.96875 C 375.90379,514.74477 375.93181,514.45186 375.90625,514.1875 C 375.89266,513.98387 375.84739,513.88985 375.84375,513.875 C 375.84389,513.86458 375.84389,513.85417 375.84375,513.84375 C 375.86975,513.94071 375.85901,513.85978 375.75,513.59375 C 375.69753,513.46336 375.66014,513.37439 375.625,513.3125 C 375.57262,513.22275 375.49154,513.05015 375.28125,512.84375 L 371.75,509.3125 C 371.29355,508.82579 370.66491,508.60087 370,508.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1" /> | |||
<path | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path18063" | |||
d="M 366.65625,515.40625 L 371.28125,515.40625 L 369.46875,517.21875 C 369.0718,517.6157 369.0718,518.2593 369.46875,518.65625 C 369.8657,519.0532 370.5093,519.0532 370.90625,518.65625 L 374.34375,515.1875 L 374.4375,515.125 C 374.44343,515.11918 374.43171,515.09972 374.4375,515.09375 C 374.49291,515.03659 374.5526,514.97676 374.59375,514.90625 C 374.62239,514.85717 374.63663,514.80216 374.65625,514.75 C 374.66861,514.71928 374.67831,514.68783 374.6875,514.65625 C 374.71862,514.54015 374.73024,514.43132 374.71875,514.3125 C 374.71489,514.25466 374.70138,514.21285 374.6875,514.15625 C 374.6766,514.1156 374.67237,514.07059 374.65625,514.03125 C 374.63982,513.99042 374.61578,513.94505 374.59375,513.90625 C 374.5483,513.82838 374.50015,513.74899 374.4375,513.6875 L 370.90625,510.15625 C 370.69734,509.93349 370.39809,509.8184 370.09375,509.84375 C 369.69897,509.8707 369.35398,510.12813 369.21875,510.5 C 369.08351,510.87187 369.18349,511.28826 369.46875,511.5625 L 371.34375,513.40625 L 366.65625,513.40625" | |||
style="fill:#d9d9cd;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker18095" | |||
orient="auto" | |||
markerHeight="5.7450776" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g11064" | |||
transform="matrix(0.5,0,0,0.5,-185.64298,-257.19655)"> | |||
<path | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path11050" | |||
d="M 370,508.65625 C 369.13933,508.715 368.39056,509.27755 368.09375,510.09375 C 367.82399,510.83551 368.03605,511.62868 368.53125,512.21875 L 366.78125,512.21875 C 366.73884,512.21408 366.69882,512.22093 366.65625,512.21875 L 366.65625,516.59375 L 366.78125,516.59375 L 368.53125,516.59375 C 367.85229,517.45345 367.83424,518.70924 368.625,519.5 C 369.47591,520.35091 370.89909,520.35091 371.75,519.5 L 375.09375,516.125 C 375.12672,516.09552 375.15802,516.06422 375.1875,516.03125 C 375.21972,516.01191 375.25101,515.99105 375.28125,515.96875 C 375.28162,515.96839 375.49976,515.68796 375.5,515.6875 C 375.50005,515.68741 375.49338,515.64282 375.5,515.625 C 375.5011,515.62203 375.53002,515.62832 375.53125,515.625 C 375.57039,515.57293 375.58228,515.57321 375.625,515.5 C 375.76199,515.26524 375.79184,515.12809 375.78125,515.15625 C 375.81807,515.06473 375.79977,515.04374 375.8125,515 C 375.82311,514.98978 375.83353,514.97936 375.84375,514.96875 C 375.90379,514.74477 375.93181,514.45186 375.90625,514.1875 C 375.89266,513.98387 375.84739,513.88985 375.84375,513.875 C 375.84389,513.86458 375.84389,513.85417 375.84375,513.84375 C 375.86975,513.94071 375.85901,513.85978 375.75,513.59375 C 375.69753,513.46336 375.66014,513.37439 375.625,513.3125 C 375.57262,513.22275 375.49154,513.05015 375.28125,512.84375 L 371.75,509.3125 C 371.29355,508.82579 370.66491,508.60087 370,508.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1" /> | |||
<path | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path11035" | |||
d="M 366.65625,515.40625 L 371.28125,515.40625 L 369.46875,517.21875 C 369.0718,517.6157 369.0718,518.2593 369.46875,518.65625 C 369.8657,519.0532 370.5093,519.0532 370.90625,518.65625 L 374.34375,515.1875 L 374.4375,515.125 C 374.44343,515.11918 374.43171,515.09972 374.4375,515.09375 C 374.49291,515.03659 374.5526,514.97676 374.59375,514.90625 C 374.62239,514.85717 374.63663,514.80216 374.65625,514.75 C 374.66861,514.71928 374.67831,514.68783 374.6875,514.65625 C 374.71862,514.54015 374.73024,514.43132 374.71875,514.3125 C 374.71489,514.25466 374.70138,514.21285 374.6875,514.15625 C 374.6766,514.1156 374.67237,514.07059 374.65625,514.03125 C 374.63982,513.99042 374.61578,513.94505 374.59375,513.90625 C 374.5483,513.82838 374.50015,513.74899 374.4375,513.6875 L 370.90625,510.15625 C 370.69734,509.93349 370.39809,509.8184 370.09375,509.84375 C 369.69897,509.8707 369.35398,510.12813 369.21875,510.5 C 369.08351,510.87187 369.18349,511.28826 369.46875,511.5625 L 371.34375,513.40625 L 366.65625,513.40625" | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> | |||
</g> | |||
</marker> | |||
<inkscape:perspective | |||
sodipodi:type="inkscape:persp3d" | |||
inkscape:vp_x="0 : 526.18109 : 1" | |||
inkscape:vp_y="0 : 1000 : 0" | |||
inkscape:vp_z="744.09448 : 526.18109 : 1" | |||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1" | |||
id="perspective7604" /> | |||
<linearGradient | |||
id="linearGradient11516"> | |||
<stop | |||
id="stop11518" | |||
offset="0" | |||
style="stop-color:#ffffff;stop-opacity:1" /> | |||
<stop | |||
id="stop11520" | |||
offset="1" | |||
style="stop-color:#a090e7;stop-opacity:1" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient11508"> | |||
<stop | |||
id="stop11510" | |||
offset="0" | |||
style="stop-color:#ffffff;stop-opacity:1;" /> | |||
<stop | |||
id="stop11512" | |||
offset="1" | |||
style="stop-color:#e27979;stop-opacity:1" /> | |||
</linearGradient> | |||
<marker | |||
inkscape:stockid="DiamondL" | |||
orient="auto" | |||
refY="0.0" | |||
refX="0.0" | |||
id="DiamondL" | |||
style="overflow:visible"> | |||
<path | |||
id="path4404" | |||
d="M 0,-7.0710768 L -7.0710894,0 L 0,7.0710589 L 7.0710462,0 L 0,-7.0710768 z " | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" | |||
transform="scale(0.8)" /> | |||
</marker> | |||
<marker | |||
orient="auto" | |||
refY="0.0" | |||
refX="0.0" | |||
id="DiamondEmpty" | |||
style="overflow:visible"> | |||
<path | |||
id="path7" | |||
d="M 0,-5 L -5,0 L 0,5 L 5,0 L 0,-5 z " | |||
style="fill-rule:evenodd;fill:#ffffff;stroke:#000000;stroke-width:1.0pt;marker-start:none" | |||
transform="scale(1.0) translate(-5,0)" /> | |||
</marker> | |||
<linearGradient | |||
id="linearGradient3286"> | |||
<stop | |||
style="stop-color:#ffffff;stop-opacity:1;" | |||
offset="0" | |||
id="stop3288" /> | |||
<stop | |||
style="stop-color:#79e291;stop-opacity:1;" | |||
offset="1" | |||
id="stop3290" /> | |||
</linearGradient> | |||
<marker | |||
orient="auto" | |||
refY="0.0" | |||
refX="0.0" | |||
id="EmptyArrow" | |||
style="overflow:visible;"> | |||
<path | |||
id="path9" | |||
d="M 0.0,0.0 L 0.0,-5.0 L -12.5,0.0 L 0.0,5.0 L 0.0,0.0 z M -0.5,0.0 L -0.5,-4.5 L -12.0,0.0 L -0.5,4.5 L -0.5,0.0 z" | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" | |||
transform="scale(1.0) rotate(180) translate(10,0)" /> | |||
</marker> | |||
<marker | |||
orient="auto" | |||
refY="0.0" | |||
refX="0.0" | |||
id="EmptyArrow2" | |||
style="overflow:visible;"> | |||
<path | |||
id="path13" | |||
d="M 0.0,0.0 L 0.0,-5.0 L -10.0,0.0 L 0.0,5.0 L 0.0,0.0 z" | |||
style="fill-rule:evenodd;fill:#ffffff;stroke:#000000;stroke-width:1.0pt;marker-start:none;" | |||
transform="scale(1.0) rotate(180) translate(10,0)" /> | |||
</marker> | |||
<linearGradient | |||
id="linearGradient19816"> | |||
<stop | |||
id="stop19818" | |||
offset="0" | |||
style="stop-color:#ffffff;stop-opacity:1;" /> | |||
<stop | |||
id="stop19820" | |||
offset="1" | |||
style="stop-color:#e7e790;stop-opacity:1;" /> | |||
</linearGradient> | |||
<marker | |||
inkscape:stockid="Arrow2Lend" | |||
orient="auto" | |||
refY="0.0" | |||
refX="0.0" | |||
id="Arrow2Lend" | |||
style="overflow:visible;"> | |||
<path | |||
id="path16811" | |||
style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;" | |||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " | |||
transform="scale(1.1) rotate(180) translate(1,0)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="Arrow1Lend" | |||
orient="auto" | |||
refY="0.0" | |||
refX="0.0" | |||
id="Arrow1Lend" | |||
style="overflow:visible;"> | |||
<path | |||
id="path16829" | |||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" | |||
transform="scale(0.8) rotate(180) translate(12.5,0)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="TriangleOutM" | |||
orient="auto" | |||
refY="0.0" | |||
refX="0.0" | |||
id="TriangleOutM" | |||
style="overflow:visible"> | |||
<path | |||
id="path16731" | |||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z " | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" | |||
transform="scale(0.4)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="TriangleInL" | |||
orient="auto" | |||
refY="0.0" | |||
refX="0.0" | |||
id="TriangleInL" | |||
style="overflow:visible"> | |||
<path | |||
id="path16743" | |||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z " | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" | |||
transform="scale(-0.8)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="TriangleOutL" | |||
orient="auto" | |||
refY="0.0" | |||
refX="0.0" | |||
id="TriangleOutL" | |||
style="overflow:visible"> | |||
<path | |||
id="path16734" | |||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z " | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" | |||
transform="scale(0.8)" /> | |||
</marker> | |||
<linearGradient | |||
id="linearGradient9263"> | |||
<stop | |||
style="stop-color:#000000;stop-opacity:0" | |||
offset="0" | |||
id="stop9265" /> | |||
<stop | |||
style="stop-color:#000000;stop-opacity:0;" | |||
offset="1" | |||
id="stop9267" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient7299"> | |||
<stop | |||
style="stop-color:#ffffff;stop-opacity:1" | |||
offset="0" | |||
id="stop7301" /> | |||
<stop | |||
style="stop-color:#a090e7;stop-opacity:1" | |||
offset="1" | |||
id="stop7303" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient5349"> | |||
<stop | |||
style="stop-color:#000000;stop-opacity:1;" | |||
offset="0" | |||
id="stop5351" /> | |||
<stop | |||
style="stop-color:#000000;stop-opacity:0;" | |||
offset="1" | |||
id="stop5353" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient4152"> | |||
<stop | |||
style="stop-color:#6b6bff;stop-opacity:1;" | |||
offset="0" | |||
id="stop4154" /> | |||
<stop | |||
style="stop-color:#6b6bff;stop-opacity:0;" | |||
offset="1" | |||
id="stop4156" /> | |||
</linearGradient> | |||
<linearGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient5349" | |||
id="linearGradient5355" | |||
x1="96.085953" | |||
y1="148.38934" | |||
x2="389.01985" | |||
y2="148.38934" | |||
gradientUnits="userSpaceOnUse" /> | |||
<radialGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient19816" | |||
id="radialGradient11602" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="matrix(1.3208501,2.3843471e-3,-3.1056446e-3,0.596383,334.93437,78.721097)" | |||
cx="-147.5" | |||
cy="97.300964" | |||
fx="-147.5" | |||
fy="97.300964" | |||
r="109.42857" /> | |||
<radialGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient19816" | |||
id="radialGradient3268" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="matrix(0.9214039,2.3896193e-3,-2.166448e-3,0.5977017,541.12253,30.198804)" | |||
cx="-147.5" | |||
cy="97.300964" | |||
fx="-147.5" | |||
fy="97.300964" | |||
r="109.42857" /> | |||
<radialGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient7299" | |||
id="radialGradient3270" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="matrix(1.3208501,2.3843471e-3,-3.1056446e-3,0.596383,334.93437,78.721097)" | |||
cx="-147.5" | |||
cy="97.300964" | |||
fx="-147.5" | |||
fy="97.300964" | |||
r="109.42857" /> | |||
<radialGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient19816" | |||
id="radialGradient3272" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="matrix(1.6000725,2.3808346e-3,-3.7621654e-3,0.5955044,664.61868,-4.8275956)" | |||
cx="-147.5" | |||
cy="97.300964" | |||
fx="-147.5" | |||
fy="97.300964" | |||
r="109.42857" /> | |||
<radialGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient7299" | |||
id="radialGradient3274" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="matrix(1.3208501,2.3843471e-3,-3.1056446e-3,0.596383,334.93437,78.721097)" | |||
cx="-147.5" | |||
cy="97.300964" | |||
fx="-147.5" | |||
fy="97.300964" | |||
r="109.42857" /> | |||
<radialGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient7299" | |||
id="radialGradient3276" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="matrix(1.3208501,2.3843471e-3,-3.1056446e-3,0.596383,334.93437,78.721097)" | |||
cx="-147.5" | |||
cy="97.300964" | |||
fx="-147.5" | |||
fy="97.300964" | |||
r="109.42857" /> | |||
<radialGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient7299" | |||
id="radialGradient3278" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="matrix(1.3208501,2.3843471e-3,-3.1056446e-3,0.596383,334.93437,78.721097)" | |||
cx="-147.5" | |||
cy="97.300964" | |||
fx="-147.5" | |||
fy="97.300964" | |||
r="109.42857" /> | |||
<radialGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient7299" | |||
id="radialGradient3280" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="matrix(1.3208501,2.3843471e-3,-3.1056446e-3,0.596383,334.93437,78.721097)" | |||
cx="-147.5" | |||
cy="97.300964" | |||
fx="-147.5" | |||
fy="97.300964" | |||
r="109.42857" /> | |||
<marker | |||
id="marker18095-4" | |||
orient="auto" | |||
markerHeight="5.7450776" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g11064-6" | |||
transform="matrix(0.5,0,0,0.5,-185.64298,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path11050-2" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path11035-1" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker44971-5" | |||
orient="auto" | |||
markerHeight="5.7450781" | |||
markerWidth="4.6297355"> | |||
<g | |||
id="g18059-0" | |||
transform="matrix(0.5,0,0,0.5,-185.64299,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path18061-4" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path18063-9" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#d9d9cd;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker18095-0" | |||
orient="auto" | |||
markerHeight="5.7450776" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g11064-0" | |||
transform="matrix(0.5,0,0,0.5,-185.64298,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path11050-0" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path11035-16" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker18095-6" | |||
orient="auto" | |||
markerHeight="5.7450776" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g11064-7" | |||
transform="matrix(0.5,0,0,0.5,-185.64298,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path11050-20" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path11035-4" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
<marker | |||
id="marker18095-2" | |||
orient="auto" | |||
markerHeight="5.7450776" | |||
markerWidth="4.6297302"> | |||
<g | |||
id="g11064-2" | |||
transform="matrix(0.5,0,0,0.5,-185.64298,-257.19655)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="csccccccsccssssssssssssssccc" | |||
id="path11050-23" | |||
d="m 370,508.65625 c -0.86067,0.0587 -1.60944,0.6213 -1.90625,1.4375 -0.26976,0.74176 -0.0577,1.53493 0.4375,2.125 l -1.75,0 c -0.0424,-0.005 -0.0824,0.002 -0.125,0 l 0,4.375 0.125,0 1.75,0 c -0.67896,0.8597 -0.69701,2.11549 0.0937,2.90625 0.85091,0.85091 2.27409,0.85091 3.125,0 l 3.34375,-3.375 c 0.033,-0.0295 0.0643,-0.0608 0.0937,-0.0937 0.0322,-0.0193 0.0635,-0.0402 0.0937,-0.0625 3.7e-4,-3.6e-4 0.21851,-0.28079 0.21875,-0.28125 5e-5,-9e-5 -0.007,-0.0447 0,-0.0625 0.001,-0.003 0.03,0.003 0.0312,0 0.0391,-0.0521 0.051,-0.0518 0.0937,-0.125 0.13699,-0.23476 0.16684,-0.37191 0.15625,-0.34375 0.0368,-0.0915 0.0185,-0.11251 0.0312,-0.15625 0.0106,-0.0102 0.021,-0.0206 0.0312,-0.0312 0.06,-0.22398 0.0881,-0.51689 0.0625,-0.78125 -0.0136,-0.20363 -0.0589,-0.29765 -0.0625,-0.3125 1.4e-4,-0.0104 1.4e-4,-0.0208 0,-0.0312 0.026,0.097 0.0153,0.016 -0.0937,-0.25 -0.0525,-0.13039 -0.0899,-0.21936 -0.125,-0.28125 -0.0524,-0.0897 -0.13346,-0.26235 -0.34375,-0.46875 L 371.75,509.3125 c -0.45645,-0.48671 -1.08509,-0.71163 -1.75,-0.65625 z" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccscccsssssssscccsccc" | |||
id="path11035-9" | |||
d="m 366.65625,515.40625 4.625,0 -1.8125,1.8125 c -0.39695,0.39695 -0.39695,1.04055 0,1.4375 0.39695,0.39695 1.04055,0.39695 1.4375,0 l 3.4375,-3.46875 0.0937,-0.0625 c 0.006,-0.006 -0.006,-0.0253 0,-0.0312 0.0554,-0.0572 0.1151,-0.11699 0.15625,-0.1875 0.0286,-0.0491 0.0429,-0.10409 0.0625,-0.15625 0.0124,-0.0307 0.0221,-0.0622 0.0312,-0.0937 0.0311,-0.1161 0.0427,-0.22493 0.0312,-0.34375 -0.004,-0.0578 -0.0174,-0.0996 -0.0312,-0.15625 -0.0109,-0.0407 -0.0151,-0.0857 -0.0312,-0.125 -0.0164,-0.0408 -0.0405,-0.0862 -0.0625,-0.125 -0.0455,-0.0779 -0.0936,-0.15726 -0.15625,-0.21875 l -3.53125,-3.53125 c -0.20891,-0.22276 -0.50816,-0.33785 -0.8125,-0.3125 -0.39478,0.0269 -0.73977,0.28438 -0.875,0.65625 -0.13524,0.37187 -0.0353,0.78826 0.25,1.0625 l 1.875,1.84375 -4.6875,0" | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:evenodd;stroke:none" /> | |||
</g> | |||
</marker> | |||
</defs> | |||
<sodipodi:namedview | |||
id="base" | |||
pagecolor="#ffffff" | |||
bordercolor="#666666" | |||
borderopacity="1.0" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:zoom="1.8159691" | |||
inkscape:cx="336.32892" | |||
inkscape:cy="885.30635" | |||
inkscape:document-units="px" | |||
inkscape:current-layer="layer1" | |||
gridtolerance="10000" | |||
inkscape:window-width="1458" | |||
inkscape:window-height="1019" | |||
inkscape:window-x="194" | |||
inkscape:window-y="0" | |||
showgrid="true" | |||
showguides="true" | |||
inkscape:connector-spacing="10" | |||
inkscape:guide-bbox="true" | |||
inkscape:window-maximized="0"> | |||
<sodipodi:guide | |||
orientation="horizontal" | |||
position="940.71429" | |||
id="guide22848" /> | |||
<inkscape:grid | |||
type="xygrid" | |||
id="grid6196" | |||
empspacing="5" | |||
visible="true" | |||
enabled="true" | |||
snapvisiblegridlinesonly="true" | |||
spacingx="5px" | |||
spacingy="5px" /> | |||
</sodipodi:namedview> | |||
<metadata | |||
id="metadata1906"> | |||
<rdf:RDF> | |||
<cc:Work | |||
rdf:about=""> | |||
<dc:format>image/svg+xml</dc:format> | |||
<dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
</cc:Work> | |||
</rdf:RDF> | |||
</metadata> | |||
<g | |||
inkscape:label="Taso 1" | |||
inkscape:groupmode="layer" | |||
id="layer1" | |||
style="opacity:1"> | |||
<g | |||
style="display:inline" | |||
id="g2547" | |||
transform="matrix(1.4062095,0,0,1.4062095,-221.12715,-215.60428)"> | |||
<flowRoot | |||
xml:space="preserve" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
id="flowRoot2551" | |||
transform="translate(-5.2378947,106.19782)"><flowRegion | |||
id="flowRegion2553"><use | |||
transform="translate(1.467046,-91.03536)" | |||
x="0" | |||
y="0" | |||
xlink:href="#rect4654" | |||
id="use2555" | |||
width="744.09448" | |||
height="1052.3622" /></flowRegion><flowPara | |||
id="flowPara2557">Sizeable</flowPara></flowRoot> <g | |||
id="g6863" | |||
transform="translate(-46.062995,-30.433073)"> | |||
<flowRoot | |||
xml:space="preserve" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
id="flowRoot6866" | |||
transform="translate(-5.2378947,106.19782)"><flowRegion | |||
id="flowRegion6868"><use | |||
transform="translate(1.467046,-91.03536)" | |||
x="0" | |||
y="0" | |||
xlink:href="#rect4654" | |||
id="use6870" | |||
width="744.09448" | |||
height="1052.3622" /></flowRegion><flowPara | |||
id="flowPara6872">Sizeable</flowPara></flowRoot> </g> | |||
<flowRoot | |||
xml:space="preserve" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
id="flowRoot2539" | |||
transform="translate(75.734798,-715.9695)"><flowRegion | |||
id="flowRegion2541"><use | |||
transform="translate(1.467046,-91.03536)" | |||
x="0" | |||
y="0" | |||
xlink:href="#rect4654" | |||
id="use2543" | |||
width="744.09448" | |||
height="1052.3622" /></flowRegion><flowPara | |||
id="flowPara2545">VariableOwner</flowPara></flowRoot> <g | |||
style="display:inline" | |||
id="g6931" | |||
transform="translate(132.33963,-23.86934)"> | |||
<rect | |||
style="fill:#d9d9cd;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |||
id="rect6933" | |||
width="138.189" | |||
height="35.43309" | |||
x="167.13719" | |||
y="232.20705" | |||
ry="3.7880721" /> | |||
<text | |||
id="text6935" | |||
y="253.39159" | |||
x="175.51506" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
xml:space="preserve"><tspan | |||
y="253.39159" | |||
x="175.51506" | |||
id="tspan6937" | |||
sodipodi:role="line">ConnectorResource</tspan></text> | |||
</g> | |||
</g> | |||
<g | |||
style="display:inline" | |||
id="g6925" | |||
transform="matrix(1.4062095,0,0,1.4062095,-185.02991,-249.16957)"> | |||
<rect | |||
style="fill:#d9d9cd;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |||
id="rect2549" | |||
width="85.039375" | |||
height="35.433075" | |||
x="167.13719" | |||
y="232.20705" | |||
ry="3.7880721" /> | |||
<text | |||
id="text6921" | |||
y="253.39159" | |||
x="180.51506" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
xml:space="preserve"><tspan | |||
y="253.39159" | |||
x="180.51506" | |||
id="tspan6923" | |||
sodipodi:role="line">Resource</tspan></text> | |||
</g> | |||
<g | |||
style="display:inline" | |||
id="g6951" | |||
transform="matrix(1.4062095,0,0,1.4062095,-35.029907,-184.16957)"> | |||
<rect | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |||
id="rect6953" | |||
width="124.01576" | |||
height="35.43309" | |||
x="167.13719" | |||
y="232.20705" | |||
ry="3.7880721" /> | |||
<text | |||
id="text6955" | |||
y="253.39159" | |||
x="227.90504" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
xml:space="preserve"><tspan | |||
y="253.39159" | |||
x="227.90504" | |||
id="tspan6957" | |||
sodipodi:role="line">ExternalResource</tspan></text> | |||
</g> | |||
<g | |||
style="display:inline" | |||
id="g6960" | |||
transform="matrix(1.4062095,0,0,1.4062095,-35.029907,-119.16957)"> | |||
<rect | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |||
id="rect6962" | |||
width="124.01576" | |||
height="35.43309" | |||
x="167.13719" | |||
y="232.20705" | |||
ry="3.7880721" /> | |||
<text | |||
id="text6964" | |||
y="253.39159" | |||
x="228.18105" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
xml:space="preserve"><tspan | |||
y="253.39159" | |||
x="228.18105" | |||
id="tspan6966" | |||
sodipodi:role="line">ThemeResource</tspan></text> | |||
</g> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
style="fill:none;stroke:#49c2f1;stroke-width:5.48089504;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none;display:inline" | |||
d="m 199.47896,231.82376 -89.68737,0" | |||
id="path6976" | |||
inkscape:connector-type="polyline" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
style="fill:none;stroke:#49c2f1;stroke-width:5.48089504;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none;display:inline" | |||
d="m 199.47896,167.04954 -89.68737,0" | |||
id="path8919" | |||
inkscape:connector-type="polyline" | |||
inkscape:connector-curvature="0" /> | |||
<g | |||
style="display:inline" | |||
id="g8921" | |||
transform="matrix(1.4062095,0,0,1.4062095,199.97009,-249.16957)"> | |||
<rect | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |||
id="rect8923" | |||
width="124.01576" | |||
height="35.43309" | |||
x="167.13719" | |||
y="232.20705" | |||
ry="3.7880721" /> | |||
<text | |||
id="text8925" | |||
y="253.39159" | |||
x="227.90504" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
xml:space="preserve"><tspan | |||
y="253.39159" | |||
x="227.90504" | |||
id="tspan8927" | |||
sodipodi:role="line">FileResource</tspan></text> | |||
</g> | |||
<g | |||
style="display:inline" | |||
id="g8929" | |||
transform="matrix(1.4062095,0,0,1.4062095,199.97009,-184.16957)"> | |||
<rect | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |||
id="rect8931" | |||
width="124.01576" | |||
height="35.43309" | |||
x="167.13719" | |||
y="232.20705" | |||
ry="3.7880721" /> | |||
<text | |||
id="text8933" | |||
y="253.39159" | |||
x="228.18105" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
xml:space="preserve"><tspan | |||
y="253.39159" | |||
x="228.18105" | |||
id="tspan8935" | |||
sodipodi:role="line">ClassResource</tspan></text> | |||
</g> | |||
<g | |||
style="display:inline" | |||
id="g8939" | |||
transform="matrix(1.4062095,0,0,1.4062095,199.97009,-119.16957)"> | |||
<rect | |||
style="fill:#49c2f1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |||
id="rect8941" | |||
width="124.01576" | |||
height="35.43309" | |||
x="167.13719" | |||
y="232.20705" | |||
ry="3.7880721" /> | |||
<text | |||
id="text8943" | |||
y="253.39159" | |||
x="228.18105" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Helvetica Rounded LT Std;-inkscape-font-specification:Helvetica Rounded LT Std Bold" | |||
xml:space="preserve"><tspan | |||
y="253.39159" | |||
x="228.18105" | |||
id="tspan8945" | |||
sodipodi:role="line">StreamResource</tspan></text> | |||
</g> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
style="fill:none;stroke:#49c2f1;stroke-width:5.48089504;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none;display:inline" | |||
d="m 438.64529,231.82376 -24.91315,0" | |||
id="path8947" | |||
inkscape:connector-type="polyline" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
style="fill:none;stroke:#49c2f1;stroke-width:5.48089504;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none;display:inline" | |||
d="m 413.73214,102.27533 0,129.54843" | |||
id="path8949" | |||
inkscape:connector-type="polyline" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
style="fill:none;stroke:#49c2f1;stroke-width:5.48089504;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none;display:inline" | |||
d="m 438.64529,167.04954 -24.91315,0" | |||
id="path8951" | |||
inkscape:connector-type="polyline" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
style="fill:none;stroke:#49c2f1;stroke-width:5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#marker18095)" | |||
d="m 110,232.36218 c 0,-110 0,-110 0,-110" | |||
id="path6258" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
style="fill:none;stroke:#49c2f1;stroke-width:5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#marker18095)" | |||
d="m 440,102.36218 -50,0" | |||
id="path6258-6" | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cc" /> | |||
<path | |||
style="fill:none;stroke:#d9d9cd;stroke-width:5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#marker44971)" | |||
d="m 205,102.36218 -40,0" | |||
id="path6258-6-3" | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cc" /> | |||
</g> | |||
<g | |||
inkscape:groupmode="layer" | |||
id="layer2" | |||
inkscape:label="Varjot" /> | |||
</svg> |
@@ -0,0 +1,43 @@ | |||
--- | |||
title: Client-Side Engine | |||
order: 3 | |||
layout: page | |||
--- | |||
[[architecture.client-side]] | |||
= Client-Side Engine | |||
((("Client-Side | |||
Engine"))) | |||
The user interface of a server-side Vaadin application is rendered in the | |||
browser by the Vaadin Client-Side Engine. It is loaded in the browser when the | |||
page with the Vaadin UI is opened. The server-side UI components are rendered | |||
using __widgets__ (as they are called in Google Web Toolkit) on the client-side. | |||
The client-side engine is illustrated in <<figure.architecture.client-side>>. | |||
[[figure.architecture.client-side]] | |||
.Vaadin Client-Side Engine | |||
image::img/clientside-arch-hi.png[] | |||
The client-side framework includes two kinds of built-in widgets: GWT widgets | |||
and Vaadin-specific widgets. The two widget collections have significant | |||
overlap, where the Vaadin widgets provide a bit different features than the GWT | |||
widgets. In addition, many add-on widgets and their server-side counterparts | |||
exist, and you can easily download and install them, as described in | |||
<<dummy/../../../framework/addons/addons-overview.asciidoc#addons.overview,"Using | |||
Vaadin Add-ons">>. You can also develop your own widgets, as described in | |||
<<dummy/../../../framework/clientside/clientside-overview.asciidoc#clientside.overview,"Client-Side | |||
Vaadin Development">>. | |||
The rendering with widgets, as well as the communication to the server-side, is | |||
handled in the [classname]#ApplicationConnection#. Connecting the widgets with | |||
their server-side counterparts is done in __connectors__, and there is one for | |||
each widget that has a server-side counterpart. The framework handles | |||
serialization of component state transparently, and includes an RPC mechanism | |||
between the two sides. Integration of widgets with their server-side counterpart | |||
components is described in | |||
<<dummy/../../../framework/gwt/gwt-overview.asciidoc#gwt.overview,"Integrating | |||
with the Server-Side">>. | |||
@@ -0,0 +1,74 @@ | |||
--- | |||
title: Events and Listeners | |||
order: 4 | |||
layout: page | |||
--- | |||
[[architecture.events]] | |||
= Events and Listeners | |||
Vaadin offers an event-driven programming model for handling user interaction. | |||
When a user does something in the user interface, such as clicks a button or | |||
selects an item, the application needs to know about it. Many Java-based user | |||
interface frameworks follow the __Event-Listener pattern__ (also known as the | |||
Observer design pattern) to communicate user input to the application logic. So | |||
does Vaadin. The design pattern involves two kinds of elements: an object that | |||
generates ("fires" or "emits") events and a number of listeners that listen for | |||
the events. When such an event occurs, the object sends a notification about it | |||
to all the listeners. In a typical case, there is only one listener. | |||
Events can serve many kinds of purposes. In Vaadin, the usual purpose of events | |||
is handling user interaction in a user interface. Session management can require | |||
special events, such as time-out, in which case the event would actually be the | |||
lack of user interaction. Time-out is a special case of timed or scheduled | |||
events, where an event occurs at a specific date and time or when a set time has | |||
passed. | |||
To receive events of a particular type, an application must register a listener | |||
object with the event source. The listeners are registered in the components | |||
with an [methodname]#add*Listener()# method (with a method name specific to the | |||
listener). | |||
Most components that have related events define their own event class and the | |||
corresponding listener class. For example, the [classname]#Button# has | |||
[classname]#Button.ClickEvent# events, which can be listened to through the | |||
[classname]#Button.ClickListener# interface. | |||
In the following, we handle button clicks with a listener implemented as an | |||
anonymous class: | |||
[source, java] | |||
---- | |||
final Button button = new Button("Push it!"); | |||
button.addClickListener(new Button.ClickListener() { | |||
public void buttonClick(ClickEvent event) { | |||
button.setCaption("You pushed it!"); | |||
} | |||
}); | |||
---- | |||
<<figure.eventlistenerdiagram>> illustrates the case where an | |||
application-specific class inherits the [classname]#Button.ClickListener# | |||
interface to be able to listen for button click events. The application must | |||
instantiate the listener class and register it with | |||
[methodname]#addClickListener()#. It can be an anonymous class, such as the one | |||
above. When an event occurs, an event object is instantiated, in this case a | |||
[classname]#Button.ClickEvent#. The event object knows the related UI component, | |||
in this case the [classname]#Button#. | |||
[[figure.eventlistenerdiagram]] | |||
.Class Diagram of a Button Click Listener | |||
image::img/events-classdiagram-hi.png[] | |||
In the ancient times of C programming, __callback functions__ filled largely the | |||
same need as listeners do now. In object-oriented languages, we usually only | |||
have classes and methods, not functions, so the application has to give a class | |||
interface instead of a callback function pointer to the framework. | |||
<<dummy/../../../framework/application/application-events#application.events,"Handling | |||
Events with Listeners">> goes into details of handling events in practice. | |||
@@ -0,0 +1,162 @@ | |||
--- | |||
title: Overview | |||
order: 1 | |||
layout: page | |||
--- | |||
[[architecture.overview]] | |||
= Overview | |||
Vaadin provides two development models for web applications: for the client-side | |||
(the browser) and for the server-side. The server-driven development model is | |||
the more powerful one, allowing application development solely on the | |||
server-side, by utilizing an AJAX-based Vaadin Client-Side Engine that renders | |||
the user interface in the browser. The client-side model allows developing | |||
widgets and applications in Java, which are compiled to JavaScript and executed | |||
in the browser. The two models can share their UI widgets, themes, and back-end | |||
code and services, and can be mixed together easily. | |||
[[figure.architecture.detailed]] | |||
.Vaadin Runtime Architecture | |||
image::img/architecture-detailed-hi.png[] | |||
<<figure.architecture.detailed>> gives a basic illustration of the client-side | |||
and server-side communications, in a running situation where the page with the | |||
client-side code (engine or application) has been initially loaded in the | |||
browser. | |||
Vaadin Framework consists of a __server-side API__, a __client-side API__, a | |||
horde of __user interface components/widgets__ on the both sides, __themes__ for | |||
controlling the appearance, and a __data model__ that allows binding the | |||
server-side components directly to data. For client-side development, it | |||
includes the Vaadin Compiler, which allows compiling Java to JavaScript. | |||
A server-side Vaadin application runs as a servlet in a Java web server, serving | |||
HTTP requests. The [classname]#VaadinServlet# is normally used as the servlet | |||
class. The servlet receives client requests and inteprets them as events for a | |||
particular user session. Events are associated with user interface components | |||
and delivered to the event listeners defined in the application. If the UI logic | |||
makes changes to the server-side user interface components, the servlet renders | |||
them in the web browser by generating a response. The client-side engine running | |||
in the browser receives the responses and uses them to make any necessary | |||
changes to the page in the browser. | |||
The major parts of the server-driven development architecture and their function | |||
are as follows: | |||
User Interface:: Vaadin applications provide a user interface for the user to interface with the | |||
business logic and data of the application. At technical level, the UI is | |||
realized as a __UI__ class that extends [classname]#com.vaadin.ui.UI#. Its main | |||
task is to create the initial user interface out of UI components and set up | |||
event listeners to handle user input. The UI can then be loaded in the browser | |||
using an URL, or can be embedded to any HTML page. For detailed information | |||
about implementing a [classname]#UI#, see | |||
<<dummy/../../../framework/application/application-overview.asciidoc#application.overview,"Writing | |||
a Server-Side Web Application">>. | |||
+ | |||
Please note that the term "UI" is used throughout this book to refer both to the | |||
general UI concept as well as the technical UI class concept. | |||
User Interface Components/Widgets:: ((("component"))) | |||
((("widget"))) | |||
((("field"))) | |||
The user interface of a Vaadin application consists of components that are | |||
created and laid out by the application. Each server-side component has a | |||
client-side counterpart, a " __widget__", by which it is rendered in the browser | |||
and with which the user interacts. The client-side widgets can also be used by | |||
client-side applications. The server-side components relay these events to the | |||
application logic. Field components that have a value, which the user can view | |||
or edit, can be bound to a data source (see below). For a more detailed | |||
description of the UI component architecture, see | |||
<<dummy/../../../framework/components/components-overview.asciidoc#components.overview,"User | |||
Interface Components">>. | |||
Client-Side Engine:: ((("Client-Side | |||
Engine"))) | |||
((("Google Web | |||
Toolkit"))) | |||
((("HTTP"))) | |||
The Client-Side Engine of Vaadin manages the rendering of the UI in the web | |||
browser by employing various client-side __widgets__, counterparts of the | |||
server-side components. It communicates user interaction to the server-side, and | |||
then again renders the changes in the UI. The communications are made using | |||
asynchronous HTTP or HTTPS requests. See | |||
<<dummy/../../../framework/architecture/architecture-client-side#architecture.client-side,"Client-Side | |||
Engine">>. | |||
Vaadin Servlet:: ((("VaadinServlet"))) | |||
Server-side Vaadin applications work on top of the Java Servlet API (see | |||
<<dummy/../../../framework/architecture/architecture-technology#architecture.technology.servlet,"Java | |||
Servlets">>). The Vaadin servlet, or more exactly the [classname]#VaadinServlet# | |||
class, receives requests from different clients, determines which user session | |||
they belong to by tracking the sessions with cookies, and delegates the requests | |||
to their corresponding sessions. You can customize the Vaadin servlet by | |||
extending it. | |||
Themes:: ((("theme"))) | |||
((("CSS"))) | |||
((("Sass"))) | |||
((("HTML | |||
templates"))) | |||
Vaadin makes a separation between the appearance and component structure of the | |||
user interface. While the UI logic is handled as Java code, the presentation is | |||
defined in __themes__ as CSS or Sass. Vaadin provides a number of default | |||
themes. User themes can, in addition to style sheets, include HTML templates | |||
that define custom layouts and other resources, such as images and fonts. Themes | |||
are discussed in detail in | |||
<<dummy/../../../framework/themes/themes-overview.asciidoc#themes.overview,"Themes">>. | |||
Events:: ((("events"))) | |||
Interaction with user interface components creates events, which are first | |||
processed on the client-side by the widgets, then passed all the way through the | |||
HTTP server, Vaadin servlet, and the user interface components to the event | |||
listeners defined in the application. See | |||
<<dummy/../../../framework/architecture/architecture-events#architecture.events,"Events | |||
and Listeners">>. | |||
Server Push:: ((("server | |||
push"))) | |||
In addition to the event-driven programming model, Vaadin supports server push, | |||
where the UI changes are pushed directly from the server to the client without a | |||
client request or an event. This makes it possible to update UIs immediately | |||
from other threads and other UIs, without having to wait for a request. See | |||
<<dummy/../../../framework/advanced/advanced-push#advanced.push,"Server Push">>. | |||
Data Binding:: ((("Data | |||
Model"))) | |||
((("Data | |||
Binding"))) | |||
In addition to the user interface model, Vaadin provides a __data model__ for | |||
binding data presented in field components, such as text fields, check boxes and | |||
selection components, to a data source. Using the data model, the user interface | |||
components can update the application data directly, often without the need for | |||
any control code. All the field components in Vaadin use this data model | |||
internally, but any of them can be bound to a separate data source as well. | |||
((("SQL"))) | |||
For example, you can bind a table component to an SQL query response. For a | |||
complete overview of the Vaadin Data Model, please refer to | |||
<<dummy/../../../framework/datamodel/datamodel-overview.asciidoc#datamodel.overview,"Binding | |||
Components to Data">>. | |||
Client-Side Applications:: In addition to server-side web applications, Vaadin supports client-side | |||
application modules, which run in the browser. Client-side modules can use the | |||
same widgets, themes, and back-end services as server-side Vaadin applications. | |||
They are useful when you have a need for highly responsive UI logic, such as for | |||
games or for serving a large number of clients with possibly stateless | |||
server-side code, and for various other purposes, such as offering an off-line | |||
mode for server-side applications. Please see | |||
<<dummy/../../../framework/clientsideapp/clientsideapp-overview.asciidoc#clientsideapp.overview,"Client-Side | |||
Applications">> for further details. | |||
Back-end:: Vaadin is meant for building user interfaces, and it is recommended that other | |||
application layers should be kept separate from the UI. The business logic can | |||
run in the same servlet as the UI code, usually separated at least by a Java | |||
API, possibly as EJBs, or distributed to a remote back-end service. The data | |||
storage is usually distributed to a database management system, and is typically | |||
accessed through a persistence solution, such as JPA. | |||
@@ -0,0 +1,208 @@ | |||
--- | |||
title: Technological Background | |||
order: 2 | |||
layout: page | |||
--- | |||
[[architecture.technology]] | |||
= Technological Background | |||
((("Google Web | |||
Toolkit"))) | |||
((("Google Web | |||
Toolkit"))) | |||
This section provides an introduction to the various technologies and designs, | |||
which Vaadin is based on. This knowledge is not necessary for using Vaadin, but | |||
provides some background if you need to make low-level extensions to Vaadin. | |||
[[architecture.technology.html]] | |||
== HTML and JavaScript | |||
((("HTML"))) | |||
((("JavaScript"))) | |||
The World Wide Web, with all its websites and most of the web applications, is | |||
based on the use of the Hypertext Markup Language (HTML). HTML defines the | |||
structure and formatting of web pages, and allows inclusion of graphics and | |||
other resources. It is based on a hierarchy of elements marked with start and | |||
end tags, such as [literal]#++<div> ... </div>++#. Vaadin uses HTML version 5, | |||
although conservatively, to the extent supported by the major browsers, and | |||
their currently most widely used versions. | |||
((("DOM"))) | |||
JavaScript, on the other hand, is a programming language for embedding programs | |||
in HTML pages. JavaScript programs can manipulate a HTML page through the | |||
Document Object Model (DOM) of the page. They can also handle user interaction | |||
events. The Client-Side Engine of Vaadin and its client-side widgets do exactly | |||
this, although it is actually programmed in Java, which is compiled to | |||
JavaScript with the Vaadin Client Compiler. | |||
Vaadin largely hides the use of HTML, allowing you to concentrate on the UI | |||
component structure and logic. In server-side development, the UI is developed | |||
in Java using UI components and rendered by the client-side engine as HTML, but | |||
it is possible to use HTML templates for defining the layout, as well as HTML | |||
formatting in many text elements. Also when developing client-side widgets and | |||
UIs, the built-in widgets in the framework hide most of HTML DOM manipulation. | |||
[[architecture.technology.styling]] | |||
== Styling with CSS and Sass | |||
((("CSS"))) | |||
((("Sass"))) | |||
While HTML defines the content and structure of a web page, __Cascading Style | |||
Sheet__ (CSS) is a language for defining the visual style, such as colors, text | |||
sizes, and margins. CSS is based on a set of rules that are matched with the | |||
HTML structure by the browser. The properties defined in the rules determine the | |||
visual appearance of the matching HTML elements. | |||
[source, css] | |||
---- | |||
/* Define the color of labels in my view */ | |||
.myview .v-label { | |||
color: blue; | |||
} | |||
---- | |||
((("SCSS"))) | |||
((("CSS3"))) | |||
__Sass__, or __Syntactically Awesome Stylesheets__, is an extension of the CSS | |||
language, which allows the use of variables, nesting, and many other syntactic | |||
features that make the use of CSS easier and clearer. Sass has two alternative | |||
formats, SCSS, which is a superset of the syntax of CSS3, and an older indented | |||
syntax, which is more concise. The Vaadin Sass compiler supports the SCSS | |||
syntax. | |||
((("themes"))) | |||
Vaadin handles styling with __themes__ defined with CSS or Sass, and associated | |||
images, fonts, and other resources. Vaadin themes are specifically written in | |||
Sass. In development mode, Sass files are compiled automatically to CSS. For | |||
production use, you compile the Sass files to CSS with the included compiler. | |||
The use of themes is documented in detail in | |||
<<dummy/../../../framework/themes/themes-overview.asciidoc#themes.overview,"Themes">>, | |||
which also gives an introduction to CSS and Sass. | |||
[[architecture.technology.ajax]] | |||
== AJAX | |||
((("AJAX"))) | |||
((("XML"))) | |||
((("JavaScript"))) | |||
((("HTML | |||
5"))) | |||
((("CSS"))) | |||
((("DOM"))) | |||
((("XMLHttpRequest"))) | |||
AJAX, short for Asynchronous JavaScript and XML, is a technique for developing | |||
web applications with responsive user interaction, similar to traditional | |||
desktop applications. Conventional web applications, be they JavaScript-enabled | |||
or not, can get new page content from the server only by loading an entire new | |||
page. AJAX-enabled pages, on the other hand, handle the user interaction in | |||
JavaScript, send a request to the server asynchronously (without reloading the | |||
page), receive updated content in the response, and modify the page accordingly. | |||
This way, only small parts of the page data need to be loaded. This goal is | |||
archieved by the use of a certain set of technologies: HTML, CSS, DOM, | |||
JavaScript, and the XMLHttpRequest API in JavaScript. XML is just one way to | |||
serialize data between the client and the server, and in Vaadin it is serialized | |||
with the more efficient JSON. | |||
The asynchronous requests used in AJAX are made possible by the | |||
[methodname]#XMLHttpRequest# class in JavaScript. The API feature is available | |||
in all major browsers and is under way to become a W3C standard. | |||
The communication of complex data between the browser and the server requires | |||
some sort of __serialization__ (or __marshalling__) of data objects. The Vaadin | |||
servlet and the client-side engine handle the serialization of shared state | |||
objects from the server-side components to the client-side widgets, as well as | |||
serialization of RPC calls between the widgets and the server-side components. | |||
[[architecture.technology.gwt]] | |||
== Google Web Toolkit | |||
((("Google Web | |||
Toolkit"))) | |||
The client-side framework of Vaadin is based on the Google Web Toolkit (GWT). | |||
Its purpose is to make it possible to develop web user interfaces that run in | |||
the browser easily with Java instead of JavaScript. Client-side modules are | |||
developed with Java and compiled into JavaScript with the Vaadin Compiler, which | |||
is an extension of the GWT Compiler. The client-side framework also hides much | |||
of the HTML DOM manipulation and enables handling browser events in Java. | |||
GWT is essentially a client-side technology, normally used to develop user | |||
interface logic in the web browser. Pure client-side modules still need to | |||
communicate with a server using RPC calls and by serializing any data. The | |||
server-driven development mode in Vaadin effectively hides all the client-server | |||
communications and allows handling user interaction logic in a server-side | |||
application. This makes the architecture of an AJAX-based web application much | |||
simpler. Nevertheless, Vaadin also allows developing pure client-side | |||
applications, as described in | |||
<<dummy/../../../framework/clientsideapp/clientsideapp-overview.asciidoc#clientsideapp.overview,"Client-Side | |||
Applications">>. | |||
See | |||
<<dummy/../../../framework/architecture/architecture-client-side#architecture.client-side,"Client-Side | |||
Engine">> for a description of how the client-side framework based on GWT is | |||
used in the Client-Side Engine of Vaadin. | |||
<<dummy/../../../framework/clientside/clientside-overview.asciidoc#clientside.overview,"Client-Side | |||
Vaadin Development">> provides information about the client-side development, | |||
and | |||
<<dummy/../../../framework/gwt/gwt-overview.asciidoc#gwt.overview,"Integrating | |||
with the Server-Side">> about the integration of client-side widgets with the | |||
server-side components. | |||
[[architecture.technology.servlet]] | |||
== Java Servlets | |||
A Java Servlet is a class that is executed in a Java web server (a __Servlet | |||
container__) to extend the capabilities of the server. In practice, it is | |||
normally a part of a __web application__, which can contain HTML pages to | |||
provide static content, and JavaServer Pages (JSP) and Java Servlets to provide | |||
dynamic content. This is illustrated in | |||
<<figure.architecture.technology.servlet>>. | |||
[[figure.architecture.technology.servlet]] | |||
.Java Web Applications and Servlets | |||
image::img/java-servlet-hi.png[] | |||
Web applications are usually packaged and deployed to a server as __WAR__ ( | |||
__Web application ARchive__) files, which are Java JAR packages, which in turn | |||
are ZIP compressed packages. The web application is defined in a | |||
[filename]#WEB-INF/web.xml# deployment descriptor, which defines the servlet | |||
classes and also the mappings from request URL paths to the servlets. This is | |||
described in more detail in | |||
<<dummy/../../../framework/application/application-environment#application.environment.web-xml,"Using | |||
a web.xml Deployment Descriptor">>. The class path for the servlets and their | |||
dependencies includes the [filename]#WEB-INF/classes# and | |||
[filename]#WEB-INF/lib# folders. The [filename]#WEB-INF# is a special hidden | |||
folder that can not be accessed by its URL path. | |||
The servlets are Java classes that handle HTTP requests passed to them by the | |||
server through the __Java Servlet API__. They can generate HTML or other content | |||
as a response. JSP pages, on the other hand, are HTML pages, which allow | |||
including Java source code embedded in the pages. They are actually translated | |||
to Java source files by the container and then compiled to servlets. | |||
The UIs of server-side Vaadin applications run as servlets. They are wrapped | |||
inside a [classname]#VaadinServlet# servlet class, which handles session | |||
tracking and other tasks. On the initial request, it returns an HTML loader page | |||
and then mostly JSON responses to synchronize the widgets and their server-side | |||
counterparts. It also serves various resources, such as themes. The server-side | |||
UIs are implemented as classes extending the [classname]#UI# class, as described | |||
in | |||
<<dummy/../../../framework/application/application-overview.asciidoc#application.overview,"Writing | |||
a Server-Side Web Application">>. The class is given as a parameter to the | |||
Vaadin Servlet in the [filename]#web.xml# deployment descriptor. | |||
The Vaadin Client-Side Engine as well as client-side Vaadin applications are | |||
loaded to the browser as static JavaScript files. The client-side engine, or | |||
widget set in technical terms, needs to be located under the | |||
[filename]#VAADIN/widgetsets# path in the web application. The precompiled | |||
default widget set is served from the [filename]#vaadin-client-compiled# JAR by | |||
the Vaadin Servlet. | |||
@@ -0,0 +1,16 @@ | |||
[[architecture]] | |||
== Architecture | |||
In | |||
<<dummy/../../../framework/introduction/introduction-overview.asciidoc#intro.overview,"Introduction">>, | |||
we gave a short introduction to the general architecture of Vaadin. This chapter | |||
looks deeper into the architecture at a more technical level. | |||
include::architecture-overview.asciidoc[leveloffset=+2] | |||
include::architecture-technology.asciidoc[leveloffset=+2] | |||
include::architecture-client-side.asciidoc[leveloffset=+2] | |||
include::architecture-events.asciidoc[leveloffset=+2] |