You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by se...@apache.org on 2015/07/27 19:27:43 UTC

[7/7] incubator-ignite git commit: IGNITE-1155 Extract ignite-schema-import-ui module.

IGNITE-1155 Extract ignite-schema-import-ui module.


Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/e8d71b55
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/e8d71b55
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/e8d71b55

Branch: refs/heads/ignite-1155
Commit: e8d71b5523f8898d7a67a07f1b311c6f4cb19186
Parents: d5925e6
Author: sevdokimov <se...@gridgain.com>
Authored: Mon Jul 27 20:26:19 2015 +0300
Committer: sevdokimov <se...@gridgain.com>
Committed: Mon Jul 27 20:26:19 2015 +0300

----------------------------------------------------------------------
 modules/schema-import-ui/pom.xml                |  110 ++
 .../main/java/media/data_connection_48x48.png   |  Bin 0 -> 4443 bytes
 .../src/main/java/media/error_48x48.png         |  Bin 0 -> 4349 bytes
 .../src/main/java/media/ignite_128x128.png      |  Bin 0 -> 4917 bytes
 .../src/main/java/media/ignite_16x16.png        |  Bin 0 -> 608 bytes
 .../src/main/java/media/ignite_24x24.png        |  Bin 0 -> 930 bytes
 .../src/main/java/media/ignite_32x32.png        |  Bin 0 -> 1203 bytes
 .../src/main/java/media/ignite_48x48.png        |  Bin 0 -> 1868 bytes
 .../src/main/java/media/ignite_64x64.png        |  Bin 0 -> 2453 bytes
 .../src/main/java/media/information_48x48.png   |  Bin 0 -> 4102 bytes
 .../src/main/java/media/question_48x48.png      |  Bin 0 -> 3857 bytes
 .../src/main/java/media/sign_warning_48x48.png  |  Bin 0 -> 2988 bytes
 .../src/main/java/media/style.css               |  134 ++
 .../src/main/java/media/text_tree_48x48.png     |  Bin 0 -> 2567 bytes
 .../ignite/schema/ui/ConfirmCallable.java       |  103 +
 .../org/apache/ignite/schema/ui/Controls.java   |  692 +++++++
 .../org/apache/ignite/schema/ui/GridPaneEx.java |  177 ++
 .../apache/ignite/schema/ui/JavaFxUtils.java    |  122 ++
 .../org/apache/ignite/schema/ui/MessageBox.java |  261 +++
 .../apache/ignite/schema/ui/ModalDialog.java    |   50 +
 .../ignite/schema/ui/SchemaImportApp.java       | 1768 ++++++++++++++++++
 .../ignite/schema/ui/TextColumnValidator.java   |   32 +
 .../schema/test/AbstractSchemaImportTest.java   |  132 ++
 .../test/generator/CodeGeneratorTest.java       |   70 +
 .../schema/test/generator/XmlGeneratorTest.java |   50 +
 .../apache/ignite/schema/test/model/Objects.txt |  502 +++++
 .../ignite/schema/test/model/ObjectsKey.txt     |   96 +
 .../ignite/schema/test/model/Primitives.txt     |  506 +++++
 .../ignite/schema/test/model/PrimitivesKey.txt  |   96 +
 .../schema/test/model/ignite-type-metadata.xml  |  362 ++++
 .../test/parser/DbMetadataParserTest.java       |  118 ++
 .../testsuites/IgniteSchemaImportTestSuite.java |   41 +
 modules/schema-import/pom.xml                   |   34 -
 .../main/java/media/data_connection_48x48.png   |  Bin 4443 -> 0 bytes
 .../src/main/java/media/error_48x48.png         |  Bin 4349 -> 0 bytes
 .../src/main/java/media/ignite_128x128.png      |  Bin 4917 -> 0 bytes
 .../src/main/java/media/ignite_16x16.png        |  Bin 608 -> 0 bytes
 .../src/main/java/media/ignite_24x24.png        |  Bin 930 -> 0 bytes
 .../src/main/java/media/ignite_32x32.png        |  Bin 1203 -> 0 bytes
 .../src/main/java/media/ignite_48x48.png        |  Bin 1868 -> 0 bytes
 .../src/main/java/media/ignite_64x64.png        |  Bin 2453 -> 0 bytes
 .../src/main/java/media/information_48x48.png   |  Bin 4102 -> 0 bytes
 .../src/main/java/media/question_48x48.png      |  Bin 3857 -> 0 bytes
 .../src/main/java/media/sign_warning_48x48.png  |  Bin 2988 -> 0 bytes
 .../schema-import/src/main/java/media/style.css |  134 --
 .../src/main/java/media/text_tree_48x48.png     |  Bin 2567 -> 0 bytes
 .../ignite/schema/generator/CodeGenerator.java  |   17 +-
 .../schema/generator/ConfirmOverride.java       |   42 +
 .../ignite/schema/generator/XmlGenerator.java   |   13 +-
 .../ignite/schema/model/PojoDescriptor.java     |   34 +-
 .../apache/ignite/schema/model/PojoField.java   |   62 +-
 .../schema/parser/DatabaseMetadataParser.java   |    5 +-
 .../ignite/schema/ui/ConfirmCallable.java       |   81 -
 .../org/apache/ignite/schema/ui/Controls.java   |  643 -------
 .../org/apache/ignite/schema/ui/GridPaneEx.java |  177 --
 .../org/apache/ignite/schema/ui/MessageBox.java |  261 ---
 .../apache/ignite/schema/ui/ModalDialog.java    |   50 -
 .../ignite/schema/ui/SchemaImportApp.java       | 1764 -----------------
 .../ignite/schema/ui/TextColumnValidator.java   |   32 -
 .../ignite/schema/utils/ChangeListener.java     |   30 +
 .../apache/ignite/schema/utils/Property.java    |   84 +
 .../schema/test/AbstractSchemaImportTest.java   |  134 --
 .../test/generator/CodeGeneratorTest.java       |   70 -
 .../schema/test/generator/XmlGeneratorTest.java |   50 -
 .../apache/ignite/schema/test/model/Objects.txt |  502 -----
 .../ignite/schema/test/model/ObjectsKey.txt     |   96 -
 .../ignite/schema/test/model/Primitives.txt     |  506 -----
 .../ignite/schema/test/model/PrimitivesKey.txt  |   96 -
 .../schema/test/model/ignite-type-metadata.xml  |  362 ----
 .../test/parser/DbMetadataParserTest.java       |  118 --
 .../testsuites/IgniteSchemaImportTestSuite.java |   41 -
 71 files changed, 5639 insertions(+), 5221 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/pom.xml
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/pom.xml b/modules/schema-import-ui/pom.xml
new file mode 100644
index 0000000..c56d050
--- /dev/null
+++ b/modules/schema-import-ui/pom.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+    POM file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ignite</groupId>
+        <artifactId>ignite-parent</artifactId>
+        <version>1</version>
+        <relativePath>../../parent</relativePath>
+    </parent>
+
+    <artifactId>ignite-schema-import-ui</artifactId>
+    <version>1.4.1-SNAPSHOT</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-schema-import</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <version>1.3.175</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/java</directory>
+                <excludes>
+                    <exclude>**/*.java</exclude>
+                </excludes>
+            </resource>
+        </resources>
+
+        <testResources>
+            <testResource>
+                <directory>src/test/java</directory>
+                <excludes>
+                    <exclude>**/*.java</exclude>
+                </excludes>
+            </testResource>
+        </testResources>
+
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <mainClass>org.apache.ignite.schema.ui.SchemaImportApp</mainClass>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>schema-import</id>
+            <activation>
+                <file>
+                    <exists>${java.home}/lib/jfxrt.jar</exists>
+                </file>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>javafx</groupId>
+                    <artifactId>jfxrt</artifactId>
+                    <version>${java.version}</version>
+                    <scope>system</scope>
+                    <systemPath>${java.home}/lib/jfxrt.jar</systemPath>
+                </dependency>
+            </dependencies>
+        </profile>
+    </profiles>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/media/data_connection_48x48.png
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/media/data_connection_48x48.png b/modules/schema-import-ui/src/main/java/media/data_connection_48x48.png
new file mode 100644
index 0000000..475f219
Binary files /dev/null and b/modules/schema-import-ui/src/main/java/media/data_connection_48x48.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/media/error_48x48.png
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/media/error_48x48.png b/modules/schema-import-ui/src/main/java/media/error_48x48.png
new file mode 100644
index 0000000..e341b8a
Binary files /dev/null and b/modules/schema-import-ui/src/main/java/media/error_48x48.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/media/ignite_128x128.png
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/media/ignite_128x128.png b/modules/schema-import-ui/src/main/java/media/ignite_128x128.png
new file mode 100644
index 0000000..d99a83c
Binary files /dev/null and b/modules/schema-import-ui/src/main/java/media/ignite_128x128.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/media/ignite_16x16.png
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/media/ignite_16x16.png b/modules/schema-import-ui/src/main/java/media/ignite_16x16.png
new file mode 100644
index 0000000..3e07d33
Binary files /dev/null and b/modules/schema-import-ui/src/main/java/media/ignite_16x16.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/media/ignite_24x24.png
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/media/ignite_24x24.png b/modules/schema-import-ui/src/main/java/media/ignite_24x24.png
new file mode 100644
index 0000000..8da5c97
Binary files /dev/null and b/modules/schema-import-ui/src/main/java/media/ignite_24x24.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/media/ignite_32x32.png
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/media/ignite_32x32.png b/modules/schema-import-ui/src/main/java/media/ignite_32x32.png
new file mode 100644
index 0000000..c6c6819
Binary files /dev/null and b/modules/schema-import-ui/src/main/java/media/ignite_32x32.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/media/ignite_48x48.png
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/media/ignite_48x48.png b/modules/schema-import-ui/src/main/java/media/ignite_48x48.png
new file mode 100644
index 0000000..5b684cc
Binary files /dev/null and b/modules/schema-import-ui/src/main/java/media/ignite_48x48.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/media/ignite_64x64.png
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/media/ignite_64x64.png b/modules/schema-import-ui/src/main/java/media/ignite_64x64.png
new file mode 100644
index 0000000..c1d348b
Binary files /dev/null and b/modules/schema-import-ui/src/main/java/media/ignite_64x64.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/media/information_48x48.png
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/media/information_48x48.png b/modules/schema-import-ui/src/main/java/media/information_48x48.png
new file mode 100644
index 0000000..8712a1b
Binary files /dev/null and b/modules/schema-import-ui/src/main/java/media/information_48x48.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/media/question_48x48.png
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/media/question_48x48.png b/modules/schema-import-ui/src/main/java/media/question_48x48.png
new file mode 100644
index 0000000..84683f9
Binary files /dev/null and b/modules/schema-import-ui/src/main/java/media/question_48x48.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/media/sign_warning_48x48.png
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/media/sign_warning_48x48.png b/modules/schema-import-ui/src/main/java/media/sign_warning_48x48.png
new file mode 100644
index 0000000..5e7cccd
Binary files /dev/null and b/modules/schema-import-ui/src/main/java/media/sign_warning_48x48.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/media/style.css
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/media/style.css b/modules/schema-import-ui/src/main/java/media/style.css
new file mode 100644
index 0000000..6eee5f9
--- /dev/null
+++ b/modules/schema-import-ui/src/main/java/media/style.css
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.root {
+    -fx-background-color: eeeeee;
+}
+
+.button {
+    -fx-font-size: 14;
+    -fx-focus-color: gray;
+}
+
+.label {
+    -fx-font-size: 14;
+}
+
+.check-box {
+    -fx-font-size: 14;
+    -fx-focus-color: gray;
+}
+
+.combo-box-base  {
+    -fx-font-size: 14;
+    -fx-focus-color: gray;
+}
+
+.combo-box-popup .list-view {
+    -fx-font-size : 14;
+}
+
+.text-area {
+    -fx-font-size: 14;
+    -fx-background-color: transparent, transparent, transparent;
+}
+
+.text-area .scroll-pane {
+    -fx-background-color: transparent;
+}
+
+.text-area .scroll-pane .viewport{
+    -fx-background-color: transparent;
+}
+
+.text-area .scroll-pane .content{
+    -fx-background-color: transparent;
+}
+
+.text-area .scroll-bar:vertical:disabled {
+    -fx-opacity: 0;
+}
+
+.text-field {
+    -fx-font-size: 14;
+    -fx-background-color: -fx-text-box-border, -fx-control-inner-background, -fx-control-inner-background;
+}
+
+.text-field:focused {
+    -fx-background-color: -fx-text-box-border, -fx-control-inner-background, -fx-control-inner-background;
+}
+
+.table-view {
+    -fx-focus-color: gray;
+    -fx-font-size: 14;
+}
+
+.table-view .table-row-cell:selected {
+    -fx-background-color: -fx-table-cell-border-color, -fx-cell-hover-color;
+    -fx-background-insets: 0, 0 0 1 0;
+}
+
+.table-view:focused .table-row-cell:selected {
+     -fx-background-color: -fx-focus-color, -fx-cell-focus-inner-border, -fx-selection-bar;
+}
+
+.table-row-cell:empty {
+    -fx-background-color: white;
+}
+
+.table-row-cell:empty .table-cell {
+    -fx-border-width: 0px;
+}
+
+.tooltip {
+    -fx-font-size: 14;
+    -fx-background-radius: 0 0 0 0;
+}
+
+.page-corner {
+    -fx-shape: " ";
+}
+
+.progress-indicator {
+    -fx-progress-color: gray
+}
+
+.split-pane {
+    -fx-background-color: -fx-box-border, eeeeee;
+}
+
+.titled-pane {
+    -fx-font-size: 14;
+}
+
+.titled-pane:focused {
+    -fx-text-fill: -fx-text-base-color;
+}
+
+.titled-pane:focused > .title {
+    -fx-color: eeeeee;
+}
+
+.titled-pane:focused > .title > .arrow-button .arrow {
+    -fx-background-color: black;
+}
+
+#banner {
+   -fx-font-size: 20px;
+   -fx-font-weight: bold;
+   -fx-background-color: white
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/media/text_tree_48x48.png
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/media/text_tree_48x48.png b/modules/schema-import-ui/src/main/java/media/text_tree_48x48.png
new file mode 100644
index 0000000..6ca9e65
Binary files /dev/null and b/modules/schema-import-ui/src/main/java/media/text_tree_48x48.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/ConfirmCallable.java
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/ConfirmCallable.java b/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/ConfirmCallable.java
new file mode 100644
index 0000000..92340d0
--- /dev/null
+++ b/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/ConfirmCallable.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.ui;
+
+import javafx.application.*;
+import javafx.stage.*;
+import org.apache.ignite.schema.generator.*;
+
+import java.util.concurrent.*;
+
+import static org.apache.ignite.schema.ui.MessageBox.Result.*;
+
+/**
+ * Callable to ask user for confirmation from non EDT thread.
+ */
+public class ConfirmCallable implements Callable<MessageBox.Result>, ConfirmOverride {
+    /** Owner window. */
+    private final Stage owner;
+
+    /** Message template. */
+    private final String template;
+
+    /** Message to show in confirmation dialog. */
+    private String msg;
+
+    /** User choice. */
+    private MessageBox.Result choice = NO;
+
+    /**
+     * @param owner Owner window.
+     * @param template Message template.
+     */
+    public ConfirmCallable(Stage owner, String template) {
+        this.owner = owner;
+        this.template = template;
+    }
+
+    /** {@inheritDoc} */
+    @Override public MessageBox.Result call() throws Exception {
+        choice = MessageBox.applyToAllChoiceDialog(owner, String.format(template, msg));
+
+        return choice;
+    }
+
+    /**
+     * Execute confirmation in EDT thread.
+     *
+     * @return Confirm result.
+     */
+    public ConfirmOverride.Result confirm(String msg) {
+        this.msg = msg;
+
+        if (choice == YES_TO_ALL)
+            return Result.OVERRIDE;
+
+        if (choice == NO_TO_ALL)
+            return Result.NO;
+
+        FutureTask<MessageBox.Result> fut = new FutureTask<>(this);
+
+        Platform.runLater(fut);
+
+        MessageBox.Result res;
+
+        try {
+            res = fut.get();
+        }
+        catch (Exception ignored) {
+            return Result.NO;
+        }
+
+        switch (res) {
+            case CANCEL:
+                return Result.CANCEL;
+
+            case NO:
+            case NO_TO_ALL:
+                return Result.NO;
+
+            case YES:
+            case YES_TO_ALL:
+                return Result.OVERRIDE;
+
+            default:
+                throw new RuntimeException("Unknown result: " + res);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/Controls.java
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/Controls.java b/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/Controls.java
new file mode 100644
index 0000000..075a84b
--- /dev/null
+++ b/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/Controls.java
@@ -0,0 +1,692 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.ui;
+
+import com.sun.javafx.scene.control.skin.*;
+import javafx.application.*;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.*;
+import javafx.collections.*;
+import javafx.event.*;
+import javafx.geometry.*;
+import javafx.scene.*;
+import javafx.scene.control.*;
+import javafx.scene.control.cell.*;
+import javafx.scene.image.*;
+import javafx.scene.input.*;
+import javafx.scene.layout.*;
+import javafx.scene.text.*;
+import javafx.util.*;
+import javafx.util.converter.*;
+import org.apache.ignite.schema.utils.*;
+
+import java.lang.reflect.*;
+
+/**
+ * Utility class to create controls.
+ */
+public class Controls {
+    /** */
+    public static final Insets DFLT_PADDING = new Insets(10, 10, 10, 10);
+
+    /**
+     * Create scene with predefined style.
+     *
+     * @param root The root node of the scene graph.
+     * @return New {@code Scene} instance.
+     */
+    public static Scene scene(Parent root) {
+        Scene scene = new Scene(root);
+
+        scene.getStylesheets().add("media/style.css");
+
+        return scene;
+    }
+
+    /**
+     * Create grid pane with default padding.
+     *
+     * @param top Top padding
+     * @param right Right padding.
+     * @param bottom Bottom padding.
+     * @param left Left padding.
+     * @return New {@code GridPaneEx} instance.
+     */
+    public static GridPaneEx paneEx(double top, double right, double bottom, double left) {
+        GridPaneEx paneEx = new GridPaneEx();
+
+        paneEx.setPadding(new Insets(top, right, bottom, left));
+
+        return paneEx;
+    }
+
+    /**
+     * Create new {@code HBox} with default padding.
+     *
+     * @param spacing Amount of horizontal space between each child.
+     * @param dfltPadding If {@code true} than set default padding for pane.
+     * @return New {@code HBox} instance.
+     */
+    public static HBox hBox(int spacing, boolean dfltPadding) {
+        HBox hb = new HBox(spacing);
+
+        if (dfltPadding)
+            hb.setPadding(DFLT_PADDING);
+
+        return hb;
+    }
+
+    /**
+     * Create new {@code HBox} with default padding and add controls.
+     *
+     * @param spacing Amount of horizontal space between each child.
+     * @param dfltPadding If {@code true} than set default padding for pane.
+     * @param controls Controls to add.
+     * @return New {@code HBox} instance.
+     */
+    public static HBox hBox(int spacing, boolean dfltPadding, Node... controls) {
+        HBox hb = hBox(spacing, dfltPadding);
+
+        hb.getChildren().addAll(controls);
+
+        return hb;
+    }
+
+    /**
+     * Create new {@code VBox} with default padding.
+     *
+     * @param spacing Amount of horizontal space between each child.
+     * @return New {@code VBox} instance.
+     */
+    public static VBox vBox(int spacing) {
+        VBox vb = new VBox(spacing);
+
+        vb.setPadding(DFLT_PADDING);
+
+        return vb;
+    }
+
+    /**
+     * Create new {@code VBox} with default padding and add controls.
+     *
+     * @param spacing Amount of horizontal space between each child.
+     * @param controls Controls to add.
+     * @return New {@code VBox} instance.
+     */
+    public static VBox vBox(int spacing, Node... controls) {
+        VBox vb = vBox(spacing);
+
+        vb.getChildren().addAll(controls);
+
+        return vb;
+    }
+
+    /**
+     * Create stack pane.
+     *
+     * @param controls Controls to add.
+     * @return New {@code StackPane} instance.
+     */
+    public static StackPane stackPane(Node... controls) {
+        StackPane sp = new StackPane();
+
+        sp.getChildren().addAll(controls);
+
+        return sp;
+    }
+
+    /**
+     * Create border pane.
+     *
+     * @param top Optional top control.
+     * @param center Optional center control.
+     * @param bottom Optional bottom control.
+     * @param left Optional left control.
+     * @param right Optional right control.
+     * @return New {@code BorderPane} instance.
+     */
+    public static BorderPane borderPane(Node top, Node center, Node bottom, Node left, Node right) {
+        BorderPane bp = new BorderPane();
+
+        bp.setTop(top);
+        bp.setCenter(center);
+        bp.setBottom(bottom);
+        bp.setLeft(left);
+        bp.setRight(right);
+
+        return bp;
+    }
+
+    /**
+     * Sets control tooltip if needed.
+     *
+     * @param ctrl Target control.
+     * @param tip Tooltip text.
+     * @return Control itself for method chaining.
+     */
+    public static <T extends Control> T tooltip(T ctrl, String tip) {
+        if (!tip.isEmpty())
+            ctrl.setTooltip(new Tooltip(tip));
+
+        return ctrl;
+    }
+
+    /**
+     * Create label.
+     *
+     * @param text Label text.
+     * @return New {@code Label} instance.
+     */
+    public static Label label(String text) {
+        return new Label(text);
+    }
+
+    /**
+     * Create button with text only.
+     *
+     * @param text Button text.
+     * @param tip Tooltip text.
+     * @param onAct Button action.
+     * @return New {@code Button} instance.
+     */
+    public static Button button(String text, String tip, EventHandler<ActionEvent> onAct) {
+        Button btn = new Button(text);
+
+        btn.setOnAction(onAct);
+
+        tooltip(btn, tip);
+
+        return btn;
+    }
+
+    /**
+     * Create button with icon only.
+     *
+     * @param icon Button icon.
+     * @param tip Tooltip text.
+     * @param onAct Button action.
+     * @return New {@code Button} instance.
+     */
+    public static Button button(ImageView icon, String tip, EventHandler<ActionEvent> onAct) {
+        Button btn = new Button();
+
+        btn.setGraphic(icon);
+        btn.setOnAction(onAct);
+
+        tooltip(btn, tip);
+
+        return btn;
+    }
+
+    /**
+     * Create pane with buttons.
+     *
+     * @param alignment Alignment of buttons.
+     * @param dfltPadding If {@code true} than set default padding for pane.
+     * @param btns Buttons that will be added to pane.
+     * @return New {@code HBox} instance with buttons.
+     */
+    public static Pane buttonsPane(Pos alignment, boolean dfltPadding, Button... btns) {
+        HBox hb = hBox(10, dfltPadding, btns);
+
+        hb.setAlignment(alignment);
+
+        return hb;
+    }
+
+    /**
+     * Create checkbox.
+     *
+     * @param text Checkbox text.
+     * @param tip Tooltip tex.
+     * @param sel Checkbox selected state.
+     * @return New {@code Checkbox} instance.
+     */
+    public static CheckBox checkBox(String text, String tip, boolean sel) {
+        CheckBox ch = new CheckBox(text);
+
+        ch.setSelected(sel);
+
+        tooltip(ch, tip);
+
+        return ch;
+    }
+
+    /**
+     * Create text field.
+     *
+     * @param tip Tooltip text.
+     * @return New {@code TextField} instance.
+     */
+    public static TextField textField(String tip) {
+        TextField tf = new TextField();
+
+        tooltip(tf, tip);
+
+        return tf;
+    }
+
+    /**
+     * Create static text.
+     *
+     * @param text Text to show.
+     * @param wrap Text wrapping width.
+     * @return New {@code Text} instance.
+     */
+    public static Text text(String text, int wrap) {
+        Text t = new Text(text);
+
+        t.setFont(new Font(14));
+
+        if (wrap > 0)
+            t.setWrappingWidth(wrap);
+
+        return t;
+    }
+
+    /**
+     * Create password field.
+     *
+     * @param tip Tooltip text.
+     * @return New {@code PasswordField} instance.
+     */
+    public static PasswordField passwordField(String tip) {
+        PasswordField pf = new PasswordField();
+
+        tooltip(pf, tip);
+
+        return pf;
+    }
+
+    /**
+     * Create combo box.
+     *
+     * @param tip Tooltip text.
+     * @param items Combo box items.
+     * @return New {@code ComboBox} instance.
+     */
+    public static <T> ComboBox<T> comboBox(String tip, T... items) {
+        ComboBox<T> cb = new ComboBox<>(FXCollections.observableArrayList(items));
+
+        cb.setMaxWidth(Double.MAX_VALUE);
+        cb.getSelectionModel().select(0);
+
+        tooltip(cb, tip);
+
+        return cb;
+    }
+
+    /**
+     * Create split pane for provided nodes.
+     *
+     * @param node1 First node.
+     * @param node2 Second node.
+     * @param pos Initial divider position.
+     * @return New {@code SplitPane} instance.
+     */
+    public static SplitPane splitPane(Node node1, Node node2, double pos) {
+        SplitPane sp = new SplitPane();
+
+        sp.setOrientation(Orientation.VERTICAL);
+        sp.getItems().addAll(node1, node2);
+        sp.setDividerPosition(0, pos);
+
+        return sp;
+    }
+
+    /**
+     * Create titled pane.
+     *
+     * @param title Title.
+     * @param node Node.
+     * @return New {@code TitledPane} instance.
+     */
+    public static TitledPane titledPane(String title, Node node) {
+        TitledPane tp = new TitledPane(title, node);
+
+        tp.setExpanded(false);
+
+        return tp;
+    }
+
+    /**
+     * Create table column.
+     *
+     * @param colName Column name to display.
+     * @param propName Property name column is bound to.
+     * @param tip Column tooltip text.
+     * @param minWidth The minimum width column is permitted to be resized to.
+     * @param maxWidth The maximum width column is permitted to be resized to.
+     * @param editable {@code true} if column is editable.
+     * @return New {@code TableColumn} instance.
+     */
+    private static <S, T> TableColumn<S, T> tableColumn(String colName, String propName, String tip,
+        int minWidth, int maxWidth, boolean editable) {
+        TableColumn<S, T> col = new TableColumn<>();
+
+        col.setGraphic(tooltip(new Label(colName), tip));
+
+        col.setSortable(false);
+
+        if (minWidth > 0)
+            col.setMinWidth(minWidth);
+
+        if (maxWidth > 0)
+            col.setMaxWidth(maxWidth);
+
+        col.setCellValueFactory(new MyPropertyValueFactory<S, T>(propName));
+
+        col.setEditable(editable);
+
+        return col;
+    }
+
+    /** */
+    private static class MyPropertyValueFactory<S, T> implements Callback<TableColumn.CellDataFeatures<S, T>,
+        ObservableValue<T>> {
+        /** */
+        private final String name;
+
+        /**
+         * @param name Name.
+         */
+        public MyPropertyValueFactory(String name) {
+            this.name = name;
+        }
+
+        /** {@inheritDoc} */
+        @Override public ObservableValue<T> call(TableColumn.CellDataFeatures<S, T> features) {
+            Object val = features.getValue();
+
+            if (val == null)
+                return null;
+
+            Property prop;
+
+            try {
+                Method getter = val.getClass().getMethod(name + "Property");
+
+                getter.setAccessible(true);
+
+                prop = (Property)getter.invoke(val);
+
+                Type type = ((ParameterizedType)getter.getGenericReturnType()).getActualTypeArguments()[0];
+
+                if (type == Boolean.class)
+                    return (ObservableValue<T>)JavaFxUtils.booleanProperty(prop);
+
+                if (type == String.class)
+                    return (ObservableValue<T>)JavaFxUtils.stringProperty(prop);
+
+                throw new RuntimeException("Unknown field type: " + type);
+            }
+            catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Create table column.
+     *
+     * @param colName Column name to display.
+     * @param propName Property name column is bound to.
+     * @param tip Column tooltip text.
+     * @return New {@code TableColumn} instance.
+     */
+    public static <S, T> TableColumn<S, T> tableColumn(String colName, String propName, String tip) {
+        return tableColumn(colName, propName, tip, 100, 0, false);
+    }
+
+    /**
+     * Create table column.
+     *
+     * @param colName Column name to display.
+     * @param propName Property name column is bound to.
+     * @param tip Column tooltip text.
+     * @param cellFactory Custom cell factory.
+     * @return New {@code TableColumn} instance.
+     */
+    public static <S, T> TableColumn<S, T> customColumn(String colName, String propName, String tip,
+        Callback<TableColumn<S, T>, TableCell<S, T>> cellFactory) {
+        TableColumn<S, T> col = tableColumn(colName, propName, tip, 100, 0, true);
+
+        col.setCellFactory(cellFactory);
+
+        return col;
+    }
+
+    /**
+     * Create editable boolean table column.
+     *
+     * @param colName Column name to display.
+     * @param propName Property name column is bound to.
+     * @param tip Column tooltip text.
+     * @return New {@code TableColumn} instance.
+     */
+    public static <S> TableColumn<S, Boolean> booleanColumn(String colName, String propName, String tip) {
+        TableColumn<S, Boolean> col = tableColumn(colName, propName, tip, 50, 50, true);
+
+        col.setCellFactory(CheckBoxTableCellEx.<S>cellFactory());
+
+        return col;
+
+    }
+
+    /**
+     * Create editable text table column.
+     *
+     * @param colName Column name to display.
+     * @param propName Property name column is bound to.
+     * @param tip Column tooltip text.
+     * @return New {@code TableColumn} instance.
+     */
+    public static <S> TableColumn<S, String> textColumn(String colName, String propName, String tip,
+        TextColumnValidator<S> validator) {
+        TableColumn<S, String> col = tableColumn(colName, propName, tip, 100, 0, true);
+
+        col.setCellFactory(TextFieldTableCellEx.cellFactory(validator));
+
+        return col;
+    }
+
+    /**
+     * Create table view.
+     *
+     * @param placeholder Text to show if table model is empty.
+     * @param cols Columns to add.
+     * @return New {@code TableView} instance.
+     */
+    public static <S> TableView<S> tableView(String placeholder, TableColumn<S, ?>... cols) {
+        TableView<S> tbl = new TableView<>();
+
+        tbl.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
+        tbl.setEditable(true);
+        tbl.setMinHeight(70);
+        tbl.setPlaceholder(text(placeholder, 0));
+
+        tbl.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
+
+        tbl.getColumns().addAll(cols);
+
+        return tbl;
+    }
+
+    /**
+     * Create progress indicator.
+     *
+     * @param sz Indicator diameter.
+     * @return New {@code ProgressIndicator} instance.
+     */
+    public static ProgressIndicator progressIndicator(int sz) {
+        ProgressIndicator pi = new ProgressIndicator();
+
+        pi.setMaxWidth(sz);
+        pi.setMaxHeight(sz);
+
+        return pi;
+    }
+
+    /**
+     * Create image view.
+     *
+     * @param imgFileName Image filename.
+     * @return New {@code ImageView} instance.
+     */
+    public static ImageView imageView(String imgFileName, int sz) {
+        return new ImageView(image(imgFileName, sz));
+    }
+
+    /**
+     * Gets image by its filename.
+     *
+     * @param imgFileName Image filename.
+     * @return Loaded image.
+     */
+    public static Image image(String imgFileName, int sz) {
+        return new Image(Controls.class.getClassLoader()
+            .getResourceAsStream(String.format("media/%1$s_%2$dx%2$d.png", imgFileName, sz)));
+    }
+
+    /**
+     * Customized checkbox.
+     */
+    private static class CheckBoxTableCellEx<S> extends CheckBoxTableCell<S, Boolean> {
+        /** Creates a ComboBox cell factory for use in TableColumn controls. */
+        public static <S> Callback<TableColumn<S, Boolean>, TableCell<S, Boolean>> cellFactory() {
+            return new Callback<TableColumn<S, Boolean>, TableCell<S, Boolean>>() {
+                @Override public TableCell<S, Boolean> call(TableColumn<S, Boolean> col) {
+                    return new CheckBoxTableCellEx<>();
+                }
+            };
+        }
+
+        /**
+         * Default constructor.
+         */
+        private CheckBoxTableCellEx() {
+            setAlignment(Pos.CENTER);
+        }
+    }
+
+    /**
+     * Special table text field cell that commit its content on focus lost.
+     */
+    private static class TextFieldTableCellEx<S> extends TextFieldTableCell<S, String> {
+        /** */
+        private final TextColumnValidator<S> validator;
+        /** */
+        private String curTxt = "";
+
+        /** Row value. */
+        private S rowVal;
+
+        /** Create cell factory. */
+        public static <S> Callback<TableColumn<S, String>, TableCell<S, String>>
+        cellFactory(final TextColumnValidator<S> validator) {
+            return new Callback<TableColumn<S, String>, TableCell<S, String>>() {
+                @Override public TableCell<S, String> call(TableColumn<S, String> col) {
+                    return new TextFieldTableCellEx<>(validator);
+                }
+            };
+        }
+
+        /**
+         * Text field cell constructor.
+         *
+         * @param validator Input text validator.
+         */
+        private TextFieldTableCellEx(TextColumnValidator<S> validator) {
+            super(new DefaultStringConverter());
+
+            this.validator = validator;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void startEdit() {
+            String item = getItem();
+
+            if (item == null || item.isEmpty())
+                return;
+
+            super.startEdit();
+
+            rowVal = getTableView().getSelectionModel().getSelectedItem();
+
+            Node g = getGraphic();
+
+            if (g != null) {
+                final TextField tf = (TextField)g;
+
+                curTxt = tf.getText();
+
+                tf.textProperty().addListener(new ChangeListener<String>() {
+                    @Override public void changed(ObservableValue<? extends String> val, String oldVal, String newVal) {
+                        curTxt = newVal;
+                    }
+                });
+
+                tf.setOnKeyPressed(new EventHandler<KeyEvent>() {
+                    @Override public void handle(KeyEvent evt) {
+                        if (KeyCode.ENTER == evt.getCode() || KeyCode.ESCAPE == evt.getCode())
+                            cancelEdit();
+                    }
+                });
+
+                tf.setOnKeyReleased(new EventHandler<KeyEvent>() {
+                    @Override public void handle(KeyEvent evt) {
+                        // No-op to overwrite JavaFX implementation.
+                    }
+                });
+
+                // Special hack for editable TextFieldTableCell.
+                // Cancel edit when focus lost from text field, but do not cancel if focus lost to VirtualFlow.
+                tf.focusedProperty().addListener(new ChangeListener<Boolean>() {
+                    @Override public void changed(ObservableValue<? extends Boolean> val, Boolean oldVal, Boolean newVal) {
+                        Node fo = getScene().getFocusOwner();
+
+                        if (!newVal) {
+                            if (fo instanceof VirtualFlow) {
+                                if (fo.getParent().getParent() != getTableView())
+                                    cancelEdit();
+                            }
+                            else
+                                cancelEdit();
+                        }
+                    }
+                });
+
+                Platform.runLater(new Runnable() {
+                    @Override public void run() {
+                        tf.requestFocus();
+                    }
+                });
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public void cancelEdit() {
+            boolean editing = isEditing();
+
+            super.cancelEdit();
+
+            if (editing && validator.valid(rowVal, curTxt))
+                updateItem(curTxt, false);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/GridPaneEx.java
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/GridPaneEx.java b/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/GridPaneEx.java
new file mode 100644
index 0000000..be1aae9
--- /dev/null
+++ b/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/GridPaneEx.java
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.ui;
+
+import javafx.geometry.*;
+import javafx.scene.*;
+import javafx.scene.control.*;
+import javafx.scene.layout.*;
+
+/**
+ * Utility extension of {@code GridPane}.
+ */
+public class GridPaneEx extends GridPane {
+    /** Current column. */
+    private int col;
+
+    /** Current row. */
+    private int row;
+
+    /**
+     * Create pane.
+     */
+    public GridPaneEx() {
+        setAlignment(Pos.TOP_LEFT);
+        setHgap(5);
+        setVgap(10);
+    }
+
+    /**
+     * Add default column.
+     */
+    public void addColumn() {
+        getColumnConstraints().add(new ColumnConstraints());
+    }
+
+    /**
+     * Add column with constraints and horizontal grow priority for the column.
+     *
+     * @param min Column minimum size.
+     * @param pref Column preferred size.
+     * @param max Column max size.
+     * @param hgrow Column horizontal grow priority.
+     */
+    public void addColumn(double min, double pref, double max, Priority hgrow) {
+        ColumnConstraints cc = new ColumnConstraints(min, pref, max);
+
+        cc.setHgrow(hgrow);
+
+        getColumnConstraints().add(cc);
+    }
+
+    /**
+     * Add default row.
+     */
+    public void addRow() {
+        getRowConstraints().add(new RowConstraints());
+    }
+
+    /**
+     * Add default rows.
+     *
+     * @param n Number of rows to add.
+     */
+    public void addRows(int n) {
+        for (int i = 0; i < n; i++)
+            addRow();
+    }
+
+    /**
+     * Add row with constraints and vertical grow priority for the row.
+     *
+     * @param min Row minimum size.
+     * @param pref Row preferred size.
+     * @param max Row max size.
+     * @param vgrow Row vertical grow priority.
+     */
+    public void addRow(double min, double pref, double max, Priority vgrow) {
+        RowConstraints rc = new RowConstraints(min, pref, max);
+
+        rc.setVgrow(vgrow);
+
+        getRowConstraints().add(rc);
+    }
+
+    /**
+     * Wrap to next row.
+     */
+    public void wrap() {
+        col = 0;
+
+        row++;
+    }
+
+    /**
+     * Skip columns.
+     *
+     * @param span How many columns should be skipped.
+     */
+    public void skip(int span) {
+        add(new Label(""), span);
+    }
+
+    /**
+     * Move to next column.
+     */
+    private void nextCol(int span) {
+        col += span;
+
+        if (col >= getColumnConstraints().size())
+            wrap();
+    }
+
+    /**
+     * Add control to grid pane.
+     *
+     * @param ctrl Control to add.
+     * @param span How many columns control should take.
+     * @return Added control.
+     */
+    public <T extends Node> T add(T ctrl, int span) {
+        add(ctrl, col, row, span, 1);
+
+        nextCol(span);
+
+        return ctrl;
+    }
+
+    /**
+     * Add control to grid pane.
+     *
+     * @param ctrl Control to add.
+     * @return Added control.
+     */
+    public <T extends Node> T add(T ctrl) {
+        return add(ctrl, 1);
+    }
+
+    /**
+     * Add control with label.
+     *
+     * @param text Label text.
+     * @param ctrl Control to add.
+     * @param span How many columns control should take.
+     * @return Added control.
+     */
+    public <T extends Node> T addLabeled(String text, T ctrl, int span) {
+        add(new Label(text));
+
+        return add(ctrl, span);
+    }
+
+    /**
+     * Add control with label.
+     *
+     * @param text Label text.
+     * @param ctrl Control to add.
+     * @return Added control.
+     */
+    public <T extends Node> T addLabeled(String text, T ctrl) {
+        return addLabeled(text, ctrl, 1);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/JavaFxUtils.java
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/JavaFxUtils.java b/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/JavaFxUtils.java
new file mode 100644
index 0000000..579b649
--- /dev/null
+++ b/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/JavaFxUtils.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.ui;
+
+import javafx.beans.property.*;
+import javafx.beans.value.*;
+
+/**
+ *
+ */
+public class JavaFxUtils {
+    /**
+     * @param prop Property.
+     */
+    public static BooleanProperty booleanProperty(org.apache.ignite.schema.utils.Property<Boolean> prop) {
+        BooleanProperty res = (BooleanProperty)prop.fxProperty();
+
+        if (res == null) {
+            res = new SimpleBooleanProperty(prop.get());
+
+            new Bridge<>(res, prop);
+
+            prop.fxProperty(res);
+        }
+
+        return res;
+    }
+
+    /**
+     * @param prop Property.
+     */
+    public static StringProperty stringProperty(org.apache.ignite.schema.utils.Property<String> prop) {
+        StringProperty res = (StringProperty)prop.fxProperty();
+
+        if (res == null) {
+            res = new SimpleStringProperty(prop.get());
+
+            new Bridge<>(res, prop);
+
+            prop.fxProperty(res);
+        }
+
+        return res;
+    }
+
+    /**
+     *
+     * @param <T>
+     */
+    private static class Bridge<T> implements org.apache.ignite.schema.utils.ChangeListener<T>, ChangeListener<T> {
+        /** */
+        private final Property<T> fxProp;
+
+        /** */
+        private final org.apache.ignite.schema.utils.Property<T> igniteProp;
+
+        /**
+         * @param fxProp Fx property.
+         * @param igniteProp Ignite property.
+         */
+        public Bridge(Property<T> fxProp, org.apache.ignite.schema.utils.Property<T> igniteProp) {
+            this.fxProp = fxProp;
+            this.igniteProp = igniteProp;
+
+            fxProp.addListener(this);
+            igniteProp.addListener(this);
+        }
+
+        /** */
+        private boolean notificationInProgress;
+
+        /** {@inheritDoc} */
+        @Override public void changed(org.apache.ignite.schema.utils.Property<? extends T> prop, T oldVal, T newVal) {
+            if (notificationInProgress)
+                return;
+
+            notificationInProgress = true;
+
+            try {
+                assert prop == igniteProp;
+
+                fxProp.setValue(newVal);
+            }
+            finally {
+                notificationInProgress = false;
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public void changed(ObservableValue<? extends T> prop, T oldVal, T newVal) {
+            if (notificationInProgress)
+                return;
+
+            notificationInProgress = true;
+
+            try {
+                assert prop == fxProp;
+
+                igniteProp.set(newVal);
+            }
+            finally {
+                notificationInProgress = false;
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/MessageBox.java
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/MessageBox.java b/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/MessageBox.java
new file mode 100644
index 0000000..7daf69f
--- /dev/null
+++ b/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/MessageBox.java
@@ -0,0 +1,261 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.ui;
+
+import javafx.beans.value.*;
+import javafx.event.*;
+import javafx.geometry.*;
+import javafx.scene.control.*;
+import javafx.scene.layout.*;
+import javafx.stage.*;
+
+import java.util.logging.*;
+
+import static org.apache.ignite.schema.ui.Controls.*;
+
+/**
+ * Message box functionality.
+ */
+public class MessageBox extends ModalDialog {
+    /** Logger. */
+    private static final Logger log = Logger.getLogger(MessageBox.class.getName());
+
+    /** Message box type. */
+    private enum MessageType {
+        /** Information. */
+        INFO,
+        /** Warning. */
+        WARN,
+        /** Error. */
+        ERROR,
+        /** Confirm. */
+        CONFIRM,
+        /** Confirm with cancel option. */
+        CANCELLABLE_CONFIRM
+    }
+
+    /** Message box type. */
+    public enum Result {
+        /** Return value if YES is chosen. */
+        YES,
+        /** Return value if YES_TO_ALL is chosen. */
+        YES_TO_ALL,
+        /** Return value if NO is chosen. */
+        NO,
+        /** Return value if NO_TO_ALL is chosen. */
+        NO_TO_ALL,
+        /** Return value if CANCEL is chosen. */
+        CANCEL
+    }
+
+    /** Dialog result. */
+    private Result res = Result.CANCEL;
+
+    /**
+     * Create message box.
+     *
+     * @param owner Owner window.
+     * @param type Message box type.
+     * @param msg Message to show.
+     * @param applyToAll {@code true} if &quot;Apply to all&quot; check box should be displayed.
+     */
+    private MessageBox(Stage owner, MessageType type, String msg, final boolean applyToAll) {
+        super(owner, 480, 180);
+
+        String title;
+        String iconFile;
+
+        switch (type) {
+            case WARN:
+                title = "Warning";
+                iconFile = "sign_warning";
+                break;
+
+            case ERROR:
+                title = "Error";
+                iconFile = "error";
+                break;
+
+            case CONFIRM:
+            case CANCELLABLE_CONFIRM:
+                title = "Confirmation";
+                iconFile = "question";
+                break;
+
+            default:
+                title = "Information";
+                iconFile = "information";
+                break;
+        }
+
+        setTitle(title);
+        initStyle(StageStyle.UTILITY);
+        initModality(Modality.APPLICATION_MODAL);
+        initOwner(owner);
+        setResizable(false);
+
+        GridPaneEx contentPnl = paneEx(10, 10, 0, 10);
+
+        contentPnl.addColumn();
+        contentPnl.addColumn(100, 100, Double.MAX_VALUE, Priority.ALWAYS);
+
+        contentPnl.add(hBox(0, true, imageView(iconFile, 48)));
+
+        final TextArea ta = new TextArea(msg);
+        ta.setEditable(false);
+        ta.setWrapText(true);
+        ta.setFocusTraversable(false);
+
+        contentPnl.add(ta);
+
+        // Workaround for vertical scrollbar.
+        if (msg.length() < 100 && msg.split("\r\n|\r|\n").length < 4)
+            showingProperty().addListener(new ChangeListener<Boolean>() {
+                @Override public void changed(ObservableValue<? extends Boolean> val, Boolean oldVal, Boolean newVal) {
+                    if (newVal) {
+                        ScrollBar scrollBar = (ScrollBar)ta.lookup(".scroll-bar:vertical");
+
+                        if (scrollBar != null)
+                            scrollBar.setDisable(true);
+                    }
+                }
+            });
+
+        final CheckBox applyToAllCh = checkBox("Apply to all", "", false);
+
+        if (applyToAll) {
+            contentPnl.skip(1);
+            contentPnl.add(applyToAllCh);
+        }
+
+        HBox btns = hBox(10, true);
+        btns.setAlignment(Pos.CENTER);
+
+        if (MessageType.CONFIRM == type || MessageType.CANCELLABLE_CONFIRM == type) {
+            res = Result.NO;
+
+            btns.getChildren().addAll(
+                button("Yes", "Approve the request", new EventHandler<ActionEvent>() {
+                    @Override public void handle(ActionEvent e) {
+                        res = applyToAll && applyToAllCh.isSelected() ? Result.YES_TO_ALL : Result.YES;
+
+                        close();
+                    }
+                }),
+                button("No", "Reject the request", new EventHandler<ActionEvent>() {
+                    @Override public void handle(ActionEvent e) {
+                        res = applyToAll && applyToAllCh.isSelected() ? Result.NO_TO_ALL : Result.NO;
+
+                        close();
+                    }
+                }));
+
+            if (MessageType.CANCELLABLE_CONFIRM == type)
+                btns.getChildren().addAll(
+                    button("Cancel", "Cancel the request", new EventHandler<ActionEvent>() {
+                        @Override public void handle(ActionEvent e) {
+                            res = Result.CANCEL;
+
+                            close();
+                        }
+                    }));
+        }
+        else
+            btns.getChildren().add(button("OK", "Close dialog", new EventHandler<ActionEvent>() {
+                @Override public void handle(ActionEvent e) {
+                    close();
+                }
+            }));
+
+        setScene(scene(borderPane(null, contentPnl, btns, null, null)));
+    }
+
+    /**
+     * Show message in modal dialog.
+     *
+     * @param owner Owner window.
+     * @param type Message box type.
+     * @param msg Message to show.
+     * @param applyToAll {@code true} if &quot;Apply to all&quot; check box should be displayed.
+     * @return Option selected by the user.
+     */
+    private static Result showDialog(Stage owner, MessageType type, String msg, boolean applyToAll) {
+        MessageBox dlg = new MessageBox(owner, type, msg, applyToAll);
+
+        dlg.showModal();
+
+        return dlg.res;
+    }
+
+    /**
+     * Show confirmation dialog.
+     *
+     * @param owner Owner window.
+     * @param msg Message to show.
+     * @return {@code true} If user confirm.
+     */
+    public static boolean confirmDialog(Stage owner, String msg) {
+        return showDialog(owner, MessageType.CONFIRM, msg, false) == Result.YES;
+    }
+
+    /**
+     * Show confirmation dialog.
+     *
+     * @param owner Owner window.
+     * @param msg Message to show.
+     * @return User confirmation result.
+     */
+    public static Result applyToAllChoiceDialog(Stage owner, String msg) {
+        return showDialog(owner, MessageType.CANCELLABLE_CONFIRM, msg, true);
+    }
+
+    /**
+     * Show information dialog.
+     *
+     * @param owner Owner window.
+     * @param msg Message to show.
+     */
+    public static void informationDialog(Stage owner, String msg) {
+        showDialog(owner, MessageType.INFO, msg, false);
+    }
+
+    /**
+     * Show warning dialog.
+     *
+     * @param owner Owner window.
+     * @param msg Message to show.
+     */
+    public static void warningDialog(Stage owner, String msg) {
+        showDialog(owner, MessageType.WARN, msg, false);
+    }
+
+    /**
+     * Show error dialog.
+     *
+     * @param owner Owner window.
+     * @param msg Error message to show.
+     * @param e Optional exception to show.
+     */
+    public static void errorDialog(Stage owner, String msg, Throwable e) {
+        log.log(Level.SEVERE, msg, e);
+
+        String exMsg = e != null ? (e.getMessage() != null ? e.getMessage() : e.getClass().getName()) : null;
+
+        showDialog(owner, MessageType.ERROR, exMsg != null ? msg + "\n" + exMsg : msg, false);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e8d71b55/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/ModalDialog.java
----------------------------------------------------------------------
diff --git a/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/ModalDialog.java b/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/ModalDialog.java
new file mode 100644
index 0000000..6d0acb7
--- /dev/null
+++ b/modules/schema-import-ui/src/main/java/org/apache/ignite/schema/ui/ModalDialog.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.ui;
+
+import javafx.stage.*;
+
+/**
+ * Abstract base modal dialog.
+ */
+public abstract class ModalDialog extends Stage {
+    /** Owner window. */
+    protected final Stage owner;
+
+    /**
+     * @param owner Owner window.
+     * @param width Window width.
+     * @param height Window height.
+     */
+    protected ModalDialog(Stage owner, int width, int height) {
+        this.owner = owner;
+
+        this.setWidth(width);
+        this.setHeight(height);
+    }
+
+    /**
+     * Show modal dialog.
+     */
+    protected void showModal() {
+        setX(owner.getX() + owner.getWidth() / 2 - getWidth() / 2);
+        setY(owner.getY() + owner.getHeight() / 2 - getHeight() / 2);
+
+        showAndWait();
+    }
+}