You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2019/12/26 11:50:09 UTC

[cayenne] branch master updated: CAY-2645 Modeler: DbImport tree highlight improvement

This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git


The following commit(s) were added to refs/heads/master by this push:
     new e6ef379  CAY-2645 Modeler: DbImport tree highlight improvement
e6ef379 is described below

commit e6ef379824a82ae44221316f34a3e8cf6778ecef
Author: Nikita Timofeev <st...@gmail.com>
AuthorDate: Thu Dec 26 14:50:02 2019 +0300

    CAY-2645 Modeler: DbImport tree highlight improvement
---
 RELEASE-NOTES.txt                                  |   1 +
 .../cayenne/modeler/action/LoadDbSchemaAction.java |  11 +-
 .../modeler/dialog/db/load/DbImportTreeNode.java   |  19 +-
 .../modeler/editor/dbimport/ColorTreeRenderer.java | 159 ----------
 .../editor/dbimport/DbImportNodeHandler.java       | 350 ---------------------
 .../modeler/editor/dbimport/DbImportTree.java      |  12 +-
 .../modeler/editor/dbimport/DbImportView.java      |   1 +
 .../editor/dbimport/DraggableTreePanel.java        |   1 +
 .../modeler/editor/dbimport/tree/CatalogNode.java  |  52 +++
 .../editor/dbimport/tree/CatalogProcedureNode.java |  43 +++
 .../editor/dbimport/tree/CatalogTableNode.java     |  43 +++
 .../editor/dbimport/tree/ColorTreeRenderer.java    | 265 ++++++++++++++++
 .../modeler/editor/dbimport/tree/ColumnNode.java   | 109 +++++++
 .../cayenne/modeler/editor/dbimport/tree/Node.java |  42 +++
 .../modeler/editor/dbimport/tree/ObjectType.java   |  29 ++
 .../editor/dbimport/tree/ProcedureNode.java        | 100 ++++++
 .../modeler/editor/dbimport/tree/SchemaNode.java   |  70 +++++
 .../editor/dbimport/tree/SchemaProcedureNode.java  |  49 +++
 .../editor/dbimport/tree/SchemaTableNode.java      |  49 +++
 .../modeler/editor/dbimport/tree/Status.java       |  38 +++
 .../modeler/editor/dbimport/tree/TableNode.java    | 100 ++++++
 .../modeler/editor/dbimport/tree/BaseNodeTest.java | 243 ++++++++++++++
 .../editor/dbimport/tree/CatalogNodeTest.java      |  51 +++
 .../editor/dbimport/tree/ColumnNodeTest.java       | 215 +++++++++++++
 .../editor/dbimport/tree/SchemaNodeTest.java       |  58 ++++
 .../dbimport/tree/SchemaProcedureNodeTest.java     | 109 +++++++
 .../editor/dbimport/tree/SchemaTableNodeTest.java  | 109 +++++++
 27 files changed, 1800 insertions(+), 528 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index e940654..60e568f 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -54,6 +54,7 @@ CAY-2604 Specialization of property API for PK
 CAY-2610 Align methods in ObjectSelect and SQLSelect
 CAY-2611 Exclude system catalogs and schemas when run dbImport without config
 CAY-2612 Modeler: add lazy-loading to dbImport tab
+CAY-2645 Modeler: DbImport tree highlight improvement
 
 Bug Fixes:
 
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/LoadDbSchemaAction.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/LoadDbSchemaAction.java
index 871a502..1d3975c 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/LoadDbSchemaAction.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/LoadDbSchemaAction.java
@@ -41,6 +41,8 @@ import org.apache.cayenne.modeler.editor.dbimport.PrintTablesBiFunction;
 import org.apache.cayenne.modeler.pref.DBConnectionInfo;
 import org.apache.cayenne.modeler.pref.DataMapDefaults;
 import org.apache.cayenne.modeler.util.CayenneAction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import static org.apache.cayenne.modeler.pref.DBConnectionInfo.DB_ADAPTER_PROPERTY;
 import static org.apache.cayenne.modeler.pref.DBConnectionInfo.JDBC_DRIVER_PROPERTY;
@@ -53,6 +55,8 @@ import static org.apache.cayenne.modeler.pref.DBConnectionInfo.USER_NAME_PROPERT
  */
 public class LoadDbSchemaAction extends CayenneAction {
 
+    private static final Logger LOGGER = LoggerFactory.getLogger(LoadDbSchemaAction.class);
+
     private static final String ICON_NAME = "icon-dbi-refresh.png";
     private static final String ACTION_NAME = "Refresh Db Schema";
     private DraggableTreePanel draggableTreePanel;
@@ -107,12 +111,13 @@ public class LoadDbSchemaAction extends CayenneAction {
                 } else {
                     loadDataBase(connectionInfo);
                 }
-            } catch (Exception exception) {
+            } catch (Exception ex) {
                 JOptionPane.showMessageDialog(
                         Application.getFrame(),
-                        exception.getMessage(),
-                        "Error db schema loading",
+                        ex.getMessage(),
+                        "Error loading db schema",
                         JOptionPane.ERROR_MESSAGE);
+                LOGGER.warn("Error loading db schema", ex);
             } finally {
                 rootParent.getLoadDbSchemaButton().setEnabled(true);
                 rootParent.getLoadDbSchemaProgress().setVisible(false);
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/load/DbImportTreeNode.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/load/DbImportTreeNode.java
index f634e9e..3026d04 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/load/DbImportTreeNode.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/load/DbImportTreeNode.java
@@ -32,6 +32,7 @@ import org.apache.cayenne.dbsync.reverse.dbimport.ReverseEngineering;
 import org.apache.cayenne.dbsync.reverse.dbimport.Schema;
 
 import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreeNode;
 import java.util.ArrayList;
 
 
@@ -40,7 +41,6 @@ import java.util.ArrayList;
  */
 public class DbImportTreeNode extends DefaultMutableTreeNode {
 
-    private boolean isColorized;
     private boolean isLoaded;
 
     public DbImportTreeNode() {
@@ -129,12 +129,17 @@ public class DbImportTreeNode extends DefaultMutableTreeNode {
         ArrayList<DbImportTreeNode> parents = new ArrayList<>();
         DbImportTreeNode tmpNode = this;
         while (tmpNode.getParent() != null) {
-            parents.add((DbImportTreeNode) tmpNode.getParent());
-            tmpNode = (DbImportTreeNode) tmpNode.getParent();
+            parents.add(tmpNode.getParent());
+            tmpNode = tmpNode.getParent();
         }
         return parents;
     }
 
+    @Override
+    public DbImportTreeNode getParent() {
+        return (DbImportTreeNode)super.getParent();
+    }
+
     protected String getFormattedName(String className, String nodeName) {
         if (nodeName == null) {
             return className;
@@ -195,14 +200,6 @@ public class DbImportTreeNode extends DefaultMutableTreeNode {
         return true;
     }
 
-    public boolean isColorized() {
-        return isColorized;
-    }
-
-    public void setColorized(boolean colorized) {
-        isColorized = colorized;
-    }
-
     public boolean isLoaded() {
         return isLoaded;
     }
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/ColorTreeRenderer.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/ColorTreeRenderer.java
deleted file mode 100644
index 1d8b0ad..0000000
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/ColorTreeRenderer.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*****************************************************************
- *   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
- *
- *    https://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.cayenne.modeler.editor.dbimport;
-
-import org.apache.cayenne.dbsync.reverse.dbimport.IncludeColumn;
-import org.apache.cayenne.dbsync.reverse.dbimport.IncludeProcedure;
-import org.apache.cayenne.modeler.dialog.db.load.DbImportTreeNode;
-
-import javax.swing.JTree;
-import java.awt.Color;
-import java.awt.Component;
-
-import static org.apache.cayenne.modeler.editor.dbimport.DbImportNodeHandler.LABEL_COLOR;
-import static org.apache.cayenne.modeler.editor.dbimport.DbImportNodeHandler.NON_INCLUDE_COLOR;
-
-/**
- * @since 4.1
- */
-public class ColorTreeRenderer extends DbImportTreeCellRenderer {
-
-    private DbImportNodeHandler handler;
-    private DbImportTree reverseEngineeringTree;
-
-
-    public ColorTreeRenderer() {
-        super();
-        handler = new DbImportNodeHandler();
-    }
-
-    @Override
-    public Component getTreeCellRendererComponent(JTree tree, Object value,
-                                                  boolean sel,
-                                                  boolean expanded,
-                                                  boolean leaf, int row,
-                                                  boolean hasFocus) {
-        super.getTreeCellRendererComponent(tree, value, sel,
-                expanded, leaf, row, hasFocus);
-        DbImportTree renderedTree = (DbImportTree) tree;
-        handler.setDbSchemaNode(node);
-        if (node.isLabel()) {
-            setForeground(LABEL_COLOR);
-            return this;
-        }
-        if (handler.isContainer(node) || (handler.isFirstNodeIsPrimitive(renderedTree))) {
-            handler.setHasEntitiesInEmptyContainer(false);
-        }
-        if (selected) {
-            setForeground(Color.BLACK);
-            node.setColorized(node.isColorized());
-            return this;
-        }
-        DbImportTreeNode root;
-        handler.findFirstLevelIncludeTable();
-        if (!handler.checkTreesLevels(renderedTree)) {
-            setForeground(NON_INCLUDE_COLOR);
-            node.setColorized(false);
-            return this;
-        }
-        if (reverseEngineeringTree.getSelectionPath() != null) {
-            root = reverseEngineeringTree.getSelectedNode();
-        } else {
-            root = reverseEngineeringTree.getRootNode();
-        }
-        renderedTree.getRootNode().setColorized(true);
-
-        int traverseResult = handler.traverseTree(root);
-        if (traverseResult > 0) {
-
-            if (root.getUserObject().getClass() == IncludeColumn.class) {
-                if (handler.nodesIsEqual(root)) {
-                    setForeground(handler.getColorByNodeType(root));
-                    node.setColorized(true);
-                    return this;
-                } else {
-                    setForeground(NON_INCLUDE_COLOR);
-                    node.setColorized(false);
-                    return this;
-                }
-            }
-            // Case on IncludeProcedure on zero level is selected
-            if (root.getUserObject().getClass() == IncludeProcedure.class) {
-                if (handler.nodesIsEqual(root)) {
-                    setForeground(handler.getColorByNodeType(root));
-                    node.setColorized(true);
-                    return this;
-                } else {
-                    setForeground(NON_INCLUDE_COLOR);
-                    node.setColorized(false);
-                    return this;
-                }
-            }
-            // If ReverseEngineering doesn't have catalogs or schemas on zero level
-            if (!handler.isExistCatalogsOrSchemas()) {
-                if ((root.isExcludeTable()) || (root.isExcludeProcedure() || root.isExcludeColumn())) {
-                    if (handler.nodesIsEqual(root)) {
-                        setForeground(handler.getColorByNodeType(root));
-                        node.setColorized(true);
-                        return this;
-                    }
-                    setForeground(NON_INCLUDE_COLOR);
-                    node.setColorized(false);
-                    return this;
-                }
-                if (root.equals(node)) {
-                    setForeground(handler.getColorByNodeType(root));
-                    node.setColorized(true);
-                    return this;
-                }
-            }
-            // Recursion painting, if parent is colorized
-            if (handler.isParentIncluded()) {
-                setForeground(handler.getColorByNodeType(root));
-                node.setColorized(true);
-                return this;
-            }
-        } else {
-            setForeground(NON_INCLUDE_COLOR);
-            node.setColorized(false);
-            return this;
-        }
-        if ((handler.isParentIncluded()) || (reverseEngineeringTree.getSelectionPath() != null)) {
-            setForeground(handler.getColorByNodeType(root));
-            node.setColorized(true);
-            return this;
-        } else {
-            if (!handler.isExistCatalogsOrSchemas()) {
-                setForeground(handler.getColorByNodeType(root));
-                node.setColorized(true);
-                return this;
-            }
-            setForeground(NON_INCLUDE_COLOR);
-            node.setColorized(false);
-            return this;
-        }
-
-    }
-
-    public void setReverseEngineeringTree(DbImportTree reverseEngineeringTree) {
-        this.reverseEngineeringTree = reverseEngineeringTree;
-        handler.setReverseEngineeringTree(reverseEngineeringTree);
-    }
-}
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/DbImportNodeHandler.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/DbImportNodeHandler.java
deleted file mode 100644
index 773d7a2..0000000
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/DbImportNodeHandler.java
+++ /dev/null
@@ -1,350 +0,0 @@
-/*****************************************************************
- *   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
- *
- *    https://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.cayenne.modeler.editor.dbimport;
-
-import org.apache.cayenne.dbsync.reverse.dbimport.Catalog;
-import org.apache.cayenne.dbsync.reverse.dbimport.ExcludeColumn;
-import org.apache.cayenne.dbsync.reverse.dbimport.ExcludeProcedure;
-import org.apache.cayenne.dbsync.reverse.dbimport.ExcludeTable;
-import org.apache.cayenne.dbsync.reverse.dbimport.IncludeColumn;
-import org.apache.cayenne.dbsync.reverse.dbimport.IncludeProcedure;
-import org.apache.cayenne.dbsync.reverse.dbimport.IncludeTable;
-import org.apache.cayenne.dbsync.reverse.dbimport.ReverseEngineering;
-import org.apache.cayenne.dbsync.reverse.dbimport.Schema;
-import org.apache.cayenne.modeler.dialog.db.load.DbImportTreeNode;
-
-import javax.swing.tree.TreePath;
-import java.awt.Color;
-
-/**
- * @since 4.1
- */
-class DbImportNodeHandler {
-
-    private static final Color ACCEPT_COLOR = new Color(60,179,113);
-    private static final Color EXCLUDE_COLOR = new Color(178, 0, 0);
-    static final Color NON_INCLUDE_COLOR = Color.LIGHT_GRAY;
-    static final Color LABEL_COLOR = Color.BLACK;
-    private static final int EXCLUDE_TABLE_RATE = -10000;
-
-    private boolean existFirstLevelIncludeTable;
-    private boolean existCatalogsOrSchemas;
-    private boolean hasEntitiesInEmptyContainer;
-    private DbImportTreeNode dbSchemaNode;
-    private DbImportTree reverseEngineeringTree;
-
-    private boolean namesIsEqual(DbImportTreeNode reverseEngineeringNode) {
-        if (isContainer(reverseEngineeringNode)) {
-            return dbSchemaNode.getSimpleNodeName().equals(reverseEngineeringNode.getSimpleNodeName());
-        } else {
-            return (dbSchemaNode.getSimpleNodeName().toLowerCase().matches(reverseEngineeringNode.getSimpleNodeName().toLowerCase()));
-        }
-    }
-
-    boolean isContainer(DbImportTreeNode node) {
-        return (node.getUserObject().getClass() == Schema.class) || (node.getUserObject().getClass() == Catalog.class);
-    }
-
-    private boolean isEmptyContainer(DbImportTreeNode rootNode) {
-        return ((getChildIncludeTableCount(rootNode) == 0) && (!existFirstLevelIncludeTable));
-    }
-
-    boolean isParentIncluded() {
-        return ((dbSchemaNode.getParent() != null) && (((DbImportTreeNode) dbSchemaNode.getParent()).isColorized()));
-    }
-
-    // Compare node with current rendered node
-    public boolean nodesIsEqual(DbImportTreeNode reverseEngineeringNode) {
-        TreePath[] paths = reverseEngineeringTree.getSelectionPaths();
-        for (TreePath path : paths != null ? paths : new TreePath[0]) {
-            DbImportTreeNode node = (DbImportTreeNode) path.getLastPathComponent();
-            if ((nodesClassesComparation(node.getUserObject().getClass(), dbSchemaNode.getUserObject().getClass()))
-                    && namesIsEqual(node)
-                    && (dbSchemaNode.getLevel() >= node.getLevel())
-                    && (dbSchemaNode.parentsIsEqual(node))) {
-                return true;
-            }
-        }
-        if ((nodesClassesComparation(reverseEngineeringNode.getUserObject().getClass(), dbSchemaNode.getUserObject().getClass()))
-                && namesIsEqual(reverseEngineeringNode)
-                && (dbSchemaNode.getLevel() >= reverseEngineeringNode.getLevel())
-                && (dbSchemaNode.parentsIsEqual(reverseEngineeringNode))) {
-            return true;
-        }
-        return false;
-    }
-
-    public boolean checkTreesLevels(DbImportTree dbTree) {
-        if (dbTree.getRootNode().getChildCount() == 0) {
-            return false;
-        }
-        DbImportTreeNode dbNode = (DbImportTreeNode) dbTree.getRootNode().getChildAt(0);
-        int childCount = reverseEngineeringTree.getRootNode().getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            if (((DbImportTreeNode) reverseEngineeringTree.getRootNode().getChildAt(i)).
-                    getUserObject().getClass() == Catalog.class) {
-                if (dbNode.getUserObject().getClass() == Catalog.class || dbNode.getUserObject().getClass() == IncludeTable.class) {
-                    return true;
-                } else {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    // Compare reverseEngineeringNode with node.getParent()
-    private boolean compareWithParent(DbImportTreeNode reverseEngineeringNode) {
-        if ((reverseEngineeringNode == null) || (dbSchemaNode.getParent() == null)) {
-            return false;
-        }
-        if ((((DbImportTreeNode)dbSchemaNode.getParent()).getUserObject().getClass() == reverseEngineeringNode.getUserObject().getClass())
-                && (((DbImportTreeNode)dbSchemaNode.getParent()).getSimpleNodeName().equals(reverseEngineeringNode.getSimpleNodeName()))
-                && (((DbImportTreeNode)dbSchemaNode.getParent()).getLevel() >= reverseEngineeringNode.getLevel())
-                && (((DbImportTreeNode)dbSchemaNode.getParent())).parentsIsEqual(reverseEngineeringNode)) {
-            return true;
-        }
-        return false;
-    }
-
-    // Get child IncludeTable's count in node, if exists
-    private int getChildIncludeTableCount(DbImportTreeNode parentNode) {
-        if (parentNode.isIncludeTable()) {
-            return 1;
-        }
-        int childCount = parentNode.getChildCount();
-        int result = 0;
-        for (int i = 0; i < childCount; i++) {
-            DbImportTreeNode tmpNode = (DbImportTreeNode) parentNode.getChildAt(i);
-            if (tmpNode.isIncludeTable()) {
-                result++;
-            }
-        }
-        return result;
-    }
-
-    // Find Exclude-node in configuration
-    private boolean foundExclude(DbImportTreeNode rootNode) {
-        int childCount = rootNode.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            DbImportTreeNode tmpNode = (DbImportTreeNode) rootNode.getChildAt(i);
-            if (tmpNode.getChildCount() > 0) {
-                if (tmpNode.isExcludeTable() || tmpNode.isExcludeProcedure()) {
-                    return true;
-                }
-            }
-            if (dbSchemaNode.getParent() != null) {
-                if (nodesIsEqual(tmpNode)) {
-                    if (tmpNode.isExcludeTable() || tmpNode.isExcludeProcedure()) {
-                        return true;
-                    }
-                }
-            }
-        }
-
-        return false;
-    }
-
-    /*
-    *  Recursively traverse DbImportTree,
-    *  Increment result if rendered node exists in configuration tree,
-    *  Subtract EXCLUDE_TABLE_RATE from result, if found Exclude-node for rendered node,
-    *  Return 0, if rendered node not found.
-    */
-    int traverseTree(DbImportTreeNode rootNode) {
-        hasEntitiesInEmptyContainer = false;
-        int traverseResult = 0;
-        int childCount = rootNode.getChildCount();
-        boolean hasProcedures = false;
-
-        // Case for empty reverse engineering, which has a include/exclude tables/procedures
-        if ((childCount == 0) && (nodesIsEqual(rootNode))) {
-            traverseResult++;
-        }
-
-        if (nodesIsEqual(rootNode)) {
-            traverseResult++;
-        }
-
-        ReverseEngineering reverseEngineering = reverseEngineeringTree.getReverseEngineering();
-        if ((reverseEngineering.getCatalogs().isEmpty()) && (reverseEngineering.getSchemas().isEmpty())
-                && (reverseEngineering.getIncludeTables().isEmpty())
-                && (!dbSchemaNode.isIncludeProcedure())) {
-            traverseResult++;
-        }
-
-        if (nodesIsEqual(rootNode) && isEmptyContainer(rootNode)) {
-            hasEntitiesInEmptyContainer = true;
-            if (foundExclude(rootNode)) {
-                return EXCLUDE_TABLE_RATE;
-            }
-            return 1;
-        }
-
-        if (compareWithParent(rootNode) && (!rootNode.isReverseEngineering()) &&
-                isEmptyContainer(rootNode) && (dbSchemaNode.isIncludeTable())) {
-            hasEntitiesInEmptyContainer = true;
-            if (foundExclude(rootNode)) {
-                return EXCLUDE_TABLE_RATE;
-            }
-            return 1;
-        }
-
-        if (hasEntitiesInEmptyContainer) {
-            for (int i = 0; i < childCount; i++) {
-                DbImportTreeNode tmpNode = (DbImportTreeNode) rootNode.getChildAt(i);
-                if (dbSchemaNode.isIncludeProcedure() && (nodesIsEqual(tmpNode))) {
-                    int tmpNodeChildCount = tmpNode.getChildCount();
-                    if (tmpNodeChildCount > 0) {
-                        traverseResult += traverseTree((DbImportTreeNode) rootNode.getChildAt(i));
-                    }
-                    traverseResult++;
-                    hasProcedures = true;
-                }
-            }
-            if ((!rootNode.isExcludeTable()) && (!nodesIsEqual(rootNode))
-                    && (!dbSchemaNode.isIncludeProcedure()) &&(!dbSchemaNode.isIncludeColumn())) {
-                traverseResult++;
-            } else {
-                if ((!hasProcedures) && (!dbSchemaNode.isIncludeProcedure())) {
-                    traverseResult += EXCLUDE_TABLE_RATE;
-                }
-            }
-        }
-
-        for (int i = 0; i < childCount; i++) {
-            DbImportTreeNode tmpNode = (DbImportTreeNode) rootNode.getChildAt(i);
-            if (tmpNode.getChildCount() > 0) {
-                traverseResult += traverseTree(tmpNode);
-                if (tmpNode.isExcludeTable() || tmpNode.isExcludeProcedure()) {
-                    traverseResult += EXCLUDE_TABLE_RATE;
-                }
-            } else if (compareWithParent(tmpNode) && !(existFirstLevelIncludeTable)) {
-                if (!dbSchemaNode.isIncludeProcedure()) {
-                    traverseResult++;
-                }
-            }
-            if (dbSchemaNode.getParent() != null) {
-                if (nodesIsEqual(tmpNode)) {
-                    if (tmpNode.isExcludeTable() || tmpNode.isExcludeProcedure()) {
-                        traverseResult += EXCLUDE_TABLE_RATE;
-                    }
-                    traverseResult++;
-                }
-            }
-        }
-        return traverseResult;
-    }
-
-    Color getColorByNodeType(DbImportTreeNode node) {
-        if ((reverseEngineeringTree.getSelectionPaths() != null) &&(reverseEngineeringTree.getSelectionPaths().length > 1)) {
-            for (TreePath path : reverseEngineeringTree.getSelectionPaths()) {
-                DbImportTreeNode pathNode = (DbImportTreeNode) path.getLastPathComponent();
-                if (pathNode.getSimpleNodeName().equals(dbSchemaNode.getSimpleNodeName())) {
-                    if (pathNode.isExcludeTable() || pathNode.isExcludeProcedure() || node.isExcludeColumn()) {
-                        return EXCLUDE_COLOR;
-                    } else {
-                        return ACCEPT_COLOR;
-                    }
-                }
-            }
-        }
-        if (node.isExcludeTable() || node.isExcludeProcedure() || node.isExcludeColumn()) {
-            return EXCLUDE_COLOR;
-        } else {
-            return ACCEPT_COLOR;
-        }
-    }
-
-    void findFirstLevelIncludeTable() {
-        DbImportTreeNode root = reverseEngineeringTree.getRootNode();
-        int childCount = root.getChildCount();
-        existFirstLevelIncludeTable = false;
-        existCatalogsOrSchemas = false;
-        for (int i = 0; i < childCount; i++) {
-            DbImportTreeNode tmpNode = (DbImportTreeNode) root.getChildAt(i);
-            if (tmpNode.isIncludeTable()) {
-                existFirstLevelIncludeTable = true;
-            }
-            if (isContainer(tmpNode)) {
-                existCatalogsOrSchemas = true;
-            }
-        }
-    }
-
-    // Check, is DatabaseTree started with IncludeTable or IncludeProcedure
-    boolean isFirstNodeIsPrimitive(DbImportTree tree) {
-        final int firstChildIndex = 0;
-        DbImportTreeNode root = tree.getRootNode();
-        if (root.getChildCount() == 0) {
-            return false;
-        }
-        DbImportTreeNode firstElement = (DbImportTreeNode) root.getChildAt(firstChildIndex);
-        if (firstElement.isIncludeTable() || firstElement.isIncludeProcedure()) {
-            return true;
-        }
-        return false;
-    }
-
-    public boolean nodesClassesComparation(Class firstClass, Class secondClass) {
-        if (firstClass.equals(secondClass)) {
-            return true;
-        }
-        if ((firstClass.equals(IncludeTable.class)) && (secondClass.equals(ExcludeTable.class))) {
-            return true;
-        }
-        if ((firstClass.equals(ExcludeTable.class)) && (secondClass.equals(IncludeTable.class))) {
-            return true;
-        }
-        if ((firstClass.equals(IncludeProcedure.class)) && (secondClass.equals(ExcludeProcedure.class))) {
-            return true;
-        }
-        if ((firstClass.equals(ExcludeProcedure.class)) && (secondClass.equals(IncludeProcedure.class))) {
-            return true;
-        }
-        if ((firstClass.equals(ExcludeColumn.class)) && (secondClass.equals(IncludeColumn.class))) {
-            return true;
-        }
-        if ((firstClass.equals(IncludeColumn.class)) && (secondClass.equals(ExcludeColumn.class))) {
-            return true;
-        }
-        return false;
-    }
-
-    public boolean isExistCatalogsOrSchemas() {
-        return existCatalogsOrSchemas;
-    }
-
-    public boolean getHasEntitiesInEmptyContainer() {
-        return hasEntitiesInEmptyContainer;
-    }
-
-    public void setHasEntitiesInEmptyContainer(boolean newFlag) {
-        hasEntitiesInEmptyContainer = newFlag;
-    }
-
-    public void setDbSchemaNode(DbImportTreeNode dbSchemaNode) {
-        this.dbSchemaNode = dbSchemaNode;
-    }
-
-    public void setReverseEngineeringTree(DbImportTree reverseEngineeringTree) {
-        this.reverseEngineeringTree = reverseEngineeringTree;
-    }
-}
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/DbImportTree.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/DbImportTree.java
index f5e2053..b30b945 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/DbImportTree.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/DbImportTree.java
@@ -169,10 +169,10 @@ public class DbImportTree extends JTree {
     }
 
     public DbImportTreeNode findNodeByParentsChain(DbImportTreeNode rootNode, DbImportTreeNode movedNode, int depth) {
-        String parentName = ((DbImportTreeNode) movedNode.getParent()).getSimpleNodeName();
-        if ((rootNode.parentsIsEqual(((DbImportTreeNode) movedNode.getParent())))
-                && (rootNode.getSimpleNodeName().equals(parentName))
-                && ((rootNode.isCatalog()) || (rootNode.isSchema()) || (rootNode.isIncludeTable()))) {
+        String parentName = movedNode.getParent().getSimpleNodeName();
+        if (rootNode.parentsIsEqual(movedNode.getParent())
+                && rootNode.getSimpleNodeName().equals(parentName)
+                && (rootNode.isCatalog() || rootNode.isSchema() || rootNode.isIncludeTable())) {
             return rootNode;
         }
         for (int i = 0; i < rootNode.getChildCount(); i++) {
@@ -333,8 +333,10 @@ public class DbImportTree extends JTree {
         this.addTreeExpansionListener(treeExpansionListener);
     }
 
-
     public DbImportTreeNode getSelectedNode() {
+        if(this.getSelectionPath() == null) {
+            return null;
+        }
         return (DbImportTreeNode) this.getSelectionPath().getLastPathComponent();
     }
 
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/DbImportView.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/DbImportView.java
index fc18fc2..3a7dd3d 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/DbImportView.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/DbImportView.java
@@ -38,6 +38,7 @@ import org.apache.cayenne.modeler.action.LoadDbSchemaAction;
 import org.apache.cayenne.modeler.action.ReverseEngineeringAction;
 import org.apache.cayenne.modeler.dialog.db.load.DbImportTreeNode;
 import org.apache.cayenne.modeler.dialog.db.load.TransferableNode;
+import org.apache.cayenne.modeler.editor.dbimport.tree.ColorTreeRenderer;
 import org.apache.cayenne.modeler.util.CayenneAction;
 import org.apache.cayenne.modeler.util.ModelerUtil;
 
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/DraggableTreePanel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/DraggableTreePanel.java
index 769faed..aa0a3a9 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/DraggableTreePanel.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/DraggableTreePanel.java
@@ -43,6 +43,7 @@ import org.apache.cayenne.modeler.action.dbimport.MoveInvertNodeAction;
 import org.apache.cayenne.modeler.action.dbimport.TreeManipulationAction;
 import org.apache.cayenne.modeler.dialog.db.load.DbImportTreeNode;
 import org.apache.cayenne.modeler.dialog.db.load.TransferableNode;
+import org.apache.cayenne.modeler.editor.dbimport.tree.ColorTreeRenderer;
 import org.apache.cayenne.modeler.util.CayenneAction;
 
 import javax.swing.DropMode;
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/CatalogNode.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/CatalogNode.java
new file mode 100644
index 0000000..4122858
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/CatalogNode.java
@@ -0,0 +1,52 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import org.apache.cayenne.dbsync.reverse.dbimport.Catalog;
+import org.apache.cayenne.dbsync.reverse.dbimport.ReverseEngineering;
+
+class CatalogNode extends Node<Node> {
+
+    CatalogNode(String name) {
+        super(name, null);
+    }
+
+    @Override
+    public Status getStatus(ReverseEngineering config) {
+        if(config.getCatalogs().isEmpty()) {
+            return Status.INCLUDE;
+        }
+
+        if(getCatalog(config) != null) {
+            return Status.INCLUDE;
+        }
+
+        return Status.EXCLUDE_IMPLICIT;
+    }
+
+    Catalog getCatalog(ReverseEngineering config) {
+        for(Catalog catalog : config.getCatalogs()) {
+            if(catalog.getName().equals(getName())) {
+                return catalog;
+            }
+        }
+        return null;
+    }
+}
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/CatalogProcedureNode.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/CatalogProcedureNode.java
new file mode 100644
index 0000000..19fd239
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/CatalogProcedureNode.java
@@ -0,0 +1,43 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cayenne.dbsync.reverse.dbimport.FilterContainer;
+import org.apache.cayenne.dbsync.reverse.dbimport.ReverseEngineering;
+
+class CatalogProcedureNode extends ProcedureNode<CatalogNode> {
+
+    CatalogProcedureNode(String name, CatalogNode parent) {
+        super(name, parent);
+    }
+
+    @Override
+    List<FilterContainer> getContainers(ReverseEngineering config) {
+        List<FilterContainer> containers = new ArrayList<>();
+        if(getParent() != null) {
+            containers.add(getParent().getCatalog(config));
+        }
+        containers.add(config);
+        return containers;
+    }
+}
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/CatalogTableNode.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/CatalogTableNode.java
new file mode 100644
index 0000000..55bc66a
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/CatalogTableNode.java
@@ -0,0 +1,43 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cayenne.dbsync.reverse.dbimport.FilterContainer;
+import org.apache.cayenne.dbsync.reverse.dbimport.ReverseEngineering;
+
+class CatalogTableNode extends TableNode<CatalogNode> {
+
+    CatalogTableNode(String name, CatalogNode parent) {
+        super(name, parent);
+    }
+
+    @Override
+    List<FilterContainer> getContainers(ReverseEngineering config) {
+        List<FilterContainer> containers = new ArrayList<>();
+        if(getParent() != null) {
+            containers.add(getParent().getCatalog(config));
+        }
+        containers.add(config);
+        return containers;
+    }
+}
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/ColorTreeRenderer.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/ColorTreeRenderer.java
new file mode 100644
index 0000000..eca87d6
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/ColorTreeRenderer.java
@@ -0,0 +1,265 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.swing.JTree;
+
+import org.apache.cayenne.dbsync.reverse.dbimport.Catalog;
+import org.apache.cayenne.dbsync.reverse.dbimport.ExcludeColumn;
+import org.apache.cayenne.dbsync.reverse.dbimport.ExcludeProcedure;
+import org.apache.cayenne.dbsync.reverse.dbimport.ExcludeTable;
+import org.apache.cayenne.dbsync.reverse.dbimport.FilterContainer;
+import org.apache.cayenne.dbsync.reverse.dbimport.IncludeColumn;
+import org.apache.cayenne.dbsync.reverse.dbimport.IncludeProcedure;
+import org.apache.cayenne.dbsync.reverse.dbimport.IncludeTable;
+import org.apache.cayenne.dbsync.reverse.dbimport.PatternParam;
+import org.apache.cayenne.dbsync.reverse.dbimport.ReverseEngineering;
+import org.apache.cayenne.dbsync.reverse.dbimport.Schema;
+import org.apache.cayenne.dbsync.reverse.dbimport.SchemaContainer;
+import org.apache.cayenne.modeler.dialog.db.load.DbImportTreeNode;
+import org.apache.cayenne.modeler.editor.dbimport.DbImportTree;
+import org.apache.cayenne.modeler.editor.dbimport.DbImportTreeCellRenderer;
+
+/**
+ * @since 4.1
+ */
+public class ColorTreeRenderer extends DbImportTreeCellRenderer {
+
+    private DbImportTree reverseEngineeringTree;
+
+    public ColorTreeRenderer() {
+        super();
+    }
+
+    @Override
+    public Component getTreeCellRendererComponent(JTree tree, Object value,
+                                                  boolean selected, boolean expanded,
+                                                  boolean leaf, int row, boolean hasFocus) {
+        super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
+
+        if (this.node.isLabel() || this.selected) {
+            setForeground(Color.BLACK);
+            return this;
+        }
+
+        Node<?> logicalTreeNode = getLogicalTreeNode();
+        if(logicalTreeNode == null) {
+            return this;
+        }
+
+        Status status = logicalTreeNode.getStatus(reverseEngineeringTree.getReverseEngineering());
+        ReverseEngineering mask = getMask();
+        if (mask != null) {
+            status = logicalTreeNode.getStatus(mask);
+        }
+
+        setForeground(status.getColor());
+        return this;
+    }
+
+    private ReverseEngineering merge(ReverseEngineering config, Object object) {
+        if(mergeAsFilterContainer(config, object)) {
+            return config;
+        } else if(mergeAsSchemaContainer(config, object)) {
+            return config;
+        } else if(object instanceof Catalog) {
+            config.addCatalog((Catalog)object);
+        }
+        return config;
+    }
+
+    private Object merge(Catalog catalog, Object object) {
+        if(mergeAsFilterContainer(catalog, object)) {
+            return catalog;
+        }
+        mergeAsSchemaContainer(catalog, object);
+        return catalog;
+    }
+
+    private Object merge(Schema schema, Object object) {
+        mergeAsFilterContainer(schema, object);
+        return schema;
+    }
+
+    private boolean mergeAsSchemaContainer(SchemaContainer container, Object object) {
+        if(object instanceof Schema) {
+            container.addSchema((Schema)object);
+            return true;
+        }
+        return false;
+    }
+
+    private boolean mergeAsFilterContainer(FilterContainer container, Object object) {
+        if(object instanceof IncludeTable) {
+            container.addIncludeTable((IncludeTable)object);
+            container.addIncludeProcedure(new IncludeProcedure("tmp include to disable include all behaviour"));
+            return true;
+        } else if(object instanceof ExcludeTable) {
+            container.addExcludeTable((ExcludeTable)object);
+            container.addIncludeProcedure(new IncludeProcedure("tmp include to disable include all behaviour"));
+            container.addIncludeTable(new IncludeTable("tmp include to disable include all behaviour"));
+            return true;
+        } else if(object instanceof IncludeProcedure) {
+            container.addIncludeProcedure((IncludeProcedure)object);
+            return true;
+        } else if(object instanceof ExcludeProcedure) {
+            container.addExcludeProcedure((ExcludeProcedure)object);
+            container.addIncludeProcedure(new IncludeProcedure("tmp include to disable include all behaviour"));
+            return true;
+        } else if(object instanceof IncludeColumn) {
+            container.addIncludeColumn((IncludeColumn)object);
+            return true;
+        } else if(object instanceof ExcludeColumn) {
+            container.addExcludeColumn((ExcludeColumn)object);
+            return true;
+        }
+        return false;
+    }
+
+    private IncludeTable merge(IncludeTable includeTable, Object object) {
+        if(object instanceof IncludeColumn) {
+            includeTable.addIncludeColumn((IncludeColumn)object);
+        } else if(object instanceof ExcludeColumn) {
+            includeTable.addExcludeColumn((ExcludeColumn)object);
+            includeTable.addIncludeColumn(new IncludeColumn("tmp include to disable include all behaviour"));
+        }
+        return includeTable;
+    }
+
+    private Object addToMask(Object object, DbImportTreeNode node) {
+        if(object == null) {
+            return node.getUserObject();
+        }
+        String rule = getObjectValue(node.getUserObject());
+        if(node.isCatalog()) {
+            return merge(new Catalog(rule), object);
+        } else if(node.isSchema()) {
+            return merge(new Schema(rule), object);
+        } else if(node.isIncludeTable()) {
+            return merge(new IncludeTable(rule), object);
+        } else if(node.isExcludeTable()) {
+            return new ExcludeTable(rule);
+        } else if(node.isIncludeColumn()) {
+            return new IncludeColumn(rule);
+        } else if(node.isExcludeColumn()) {
+            return new ExcludeColumn(rule);
+        } else if(node.isIncludeProcedure()) {
+            return new IncludeProcedure(rule);
+        } else if(node.isExcludeProcedure()) {
+            return new ExcludeProcedure(rule);
+        }
+
+        return object;
+    }
+
+    private ReverseEngineering getMask() {
+        DbImportTreeNode selectedNode = reverseEngineeringTree.getSelectedNode();
+        if(selectedNode == null) {
+            return null;
+        }
+
+        if(selectedNode.isReverseEngineering()) {
+            return reverseEngineeringTree.getReverseEngineering();
+        }
+
+        ReverseEngineering config = new ReverseEngineering();
+        Object configNode = null;
+        while(!selectedNode.isReverseEngineering()) {
+            configNode = addToMask(configNode, selectedNode);
+            selectedNode = selectedNode.getParent();
+        }
+        return merge(config, configNode);
+    }
+
+    private Node<?> getLogicalTreeNode() {
+        List<Object> path = new ArrayList<>();
+        DbImportTreeNode parent = node;
+        while (parent != null) {
+            path.add(parent.getUserObject());
+            parent = parent.getParent();
+        }
+        Collections.reverse(path);
+
+        Node<?> logicalParent = null;
+        for(Object object : path) {
+            logicalParent = toLogicalNode(getObjectType(object), getObjectValue(object), logicalParent);
+        }
+        return logicalParent;
+    }
+
+    private Node<?> toLogicalNode(ObjectType type, String value, Node<?> logicalParent) {
+        switch (type) {
+            case CATALOG:
+                return new CatalogNode(value);
+            case SCHEMA:
+                return new SchemaNode(value, (CatalogNode)logicalParent);
+            case TABLE:
+                if(logicalParent instanceof CatalogNode) {
+                    return new CatalogTableNode(value, (CatalogNode)logicalParent);
+                } else {
+                    return new SchemaTableNode(value, (SchemaNode)logicalParent);
+                }
+            case COLUMN:
+                return new ColumnNode(value, (TableNode<?>) logicalParent);
+            case PROCEDURE:
+                if(logicalParent instanceof CatalogNode) {
+                    return new CatalogProcedureNode(value, (CatalogNode)logicalParent);
+                } else {
+                    return new SchemaProcedureNode(value, (SchemaNode)logicalParent);
+                }
+            default:
+                return null;
+        }
+    }
+
+    private ObjectType getObjectType(Object object) {
+        if(object instanceof Catalog) {
+            return ObjectType.CATALOG;
+        } else if(object instanceof Schema) {
+            return ObjectType.SCHEMA;
+        } else if(object instanceof IncludeTable || object instanceof ExcludeTable) {
+            return ObjectType.TABLE;
+        } else if(object instanceof IncludeColumn || object instanceof ExcludeColumn) {
+            return ObjectType.COLUMN;
+        } else if(object instanceof IncludeProcedure || object instanceof ExcludeProcedure) {
+            return ObjectType.PROCEDURE;
+        }
+        return ObjectType.UNKNOWN;
+    }
+
+    private String getObjectValue(Object object) {
+        if(object instanceof FilterContainer) {
+            return ((FilterContainer) object).getName();
+        } else if(object instanceof PatternParam) {
+            return ((PatternParam) object).getPattern();
+        }
+        return "";
+    }
+
+    public void setReverseEngineeringTree(DbImportTree reverseEngineeringTree) {
+        this.reverseEngineeringTree = reverseEngineeringTree;
+    }
+
+}
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/ColumnNode.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/ColumnNode.java
new file mode 100644
index 0000000..a2ae091
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/ColumnNode.java
@@ -0,0 +1,109 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.cayenne.dbsync.reverse.dbimport.ExcludeColumn;
+import org.apache.cayenne.dbsync.reverse.dbimport.FilterContainer;
+import org.apache.cayenne.dbsync.reverse.dbimport.IncludeColumn;
+import org.apache.cayenne.dbsync.reverse.dbimport.IncludeTable;
+import org.apache.cayenne.dbsync.reverse.dbimport.ReverseEngineering;
+
+class ColumnNode extends Node<TableNode<?>> {
+
+    ColumnNode(String name, TableNode<?> parent) {
+        super(name, parent);
+    }
+
+    @Override
+    public Status getStatus(ReverseEngineering config) {
+        Status parentStatus = getParent().getStatus(config);
+        if (parentStatus != Status.INCLUDE) {
+            return parentStatus;
+        }
+
+        List<FilterContainer> containers = getParent().getContainers(config);
+        List<IncludeColumn> includeColumns = new ArrayList<>();
+        List<ExcludeColumn> excludeColumns = new ArrayList<>();
+
+        for (FilterContainer container : containers) {
+            if(container == null) {
+                continue;
+            }
+            IncludeTable table = getParent().getIncludeTable(container.getIncludeTables());
+            if (table != null) {
+                includeColumns.addAll(table.getIncludeColumns());
+                excludeColumns.addAll(table.getExcludeColumns());
+            }
+            includeColumns.addAll(container.getIncludeColumns());
+            excludeColumns.addAll(container.getExcludeColumns());
+        }
+
+        return includesColumn(includeColumns, excludeColumns);
+    }
+
+    private Status includesColumn(Collection<IncludeColumn> includeColumns, Collection<ExcludeColumn> excludeColumns) {
+        if (includeColumns.isEmpty() && excludeColumns.isEmpty()) {
+            return Status.INCLUDE;
+        }
+
+        if (!includeColumns.isEmpty()) {
+            if (getIncludeColumn(includeColumns) != null) {
+                return Status.INCLUDE;
+            }
+        }
+
+        if (!excludeColumns.isEmpty()) {
+            if (getExcludeColumn(excludeColumns) != null) {
+                return Status.EXCLUDE_EXPLICIT;
+            } else {
+                return includeColumns.isEmpty()
+                        ? Status.INCLUDE
+                        : Status.EXCLUDE_IMPLICIT;
+            }
+        }
+
+        return Status.EXCLUDE_IMPLICIT;
+    }
+
+    IncludeColumn getIncludeColumn(Collection<IncludeColumn> includeColumns) {
+        for (IncludeColumn column : includeColumns) {
+            if (getName().matches(column.getPattern())) {
+                return column;
+            }
+        }
+
+        return null;
+    }
+
+    ExcludeColumn getExcludeColumn(Collection<ExcludeColumn> excludeColumns) {
+        for (ExcludeColumn column : excludeColumns) {
+            if (getName().matches(column.getPattern())) {
+                return column;
+            }
+        }
+
+        return null;
+    }
+
+}
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/Node.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/Node.java
new file mode 100644
index 0000000..97e4d22
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/Node.java
@@ -0,0 +1,42 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import org.apache.cayenne.dbsync.reverse.dbimport.ReverseEngineering;
+
+abstract class Node<P extends Node> {
+    private final String name;
+    private final P parent;
+
+    Node(String name, P parent) {
+        this.name = name;
+        this.parent = parent;
+    }
+
+    P getParent() {
+        return parent;
+    }
+
+    String getName() {
+        return name;
+    }
+
+    public abstract Status getStatus(ReverseEngineering config);
+}
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/ObjectType.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/ObjectType.java
new file mode 100644
index 0000000..2cf014f
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/ObjectType.java
@@ -0,0 +1,29 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+enum ObjectType {
+    UNKNOWN,
+    CATALOG,
+    SCHEMA,
+    TABLE,
+    COLUMN,
+    PROCEDURE;
+}
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/ProcedureNode.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/ProcedureNode.java
new file mode 100644
index 0000000..ad9d50c
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/ProcedureNode.java
@@ -0,0 +1,100 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.cayenne.dbsync.reverse.dbimport.ExcludeProcedure;
+import org.apache.cayenne.dbsync.reverse.dbimport.FilterContainer;
+import org.apache.cayenne.dbsync.reverse.dbimport.IncludeProcedure;
+import org.apache.cayenne.dbsync.reverse.dbimport.ReverseEngineering;
+
+abstract class ProcedureNode<T extends Node> extends Node<T> {
+
+    ProcedureNode(String name, T parent) {
+        super(name, parent);
+    }
+
+    @Override
+    public Status getStatus(ReverseEngineering config) {
+        Status parentStatus = getParent().getStatus(config);
+        if(parentStatus != Status.INCLUDE) {
+            return parentStatus;
+        }
+
+        List<IncludeProcedure> includeProcedures = new ArrayList<>();
+        List<ExcludeProcedure> excludeProcedures = new ArrayList<>();
+        for(FilterContainer container : getContainers(config)) {
+            if(container == null) {
+                continue;
+            }
+            includeProcedures.addAll(container.getIncludeProcedures());
+            excludeProcedures.addAll(container.getExcludeProcedures());
+        }
+
+        return includesProcedure(includeProcedures, excludeProcedures);
+    }
+
+    abstract List<FilterContainer> getContainers(ReverseEngineering config);
+
+    private Status includesProcedure(Collection<IncludeProcedure> includeProcedures, Collection<ExcludeProcedure> excludeProcedures) {
+        if(includeProcedures.isEmpty() && excludeProcedures.isEmpty()) {
+            return Status.INCLUDE;
+        }
+
+        if(!includeProcedures.isEmpty()) {
+            if(includesProcedure(includeProcedures)) {
+                return Status.INCLUDE;
+            }
+        }
+
+        if(!excludeProcedures.isEmpty()) {
+            if(excludesProcedure(excludeProcedures)) {
+                return Status.EXCLUDE_EXPLICIT;
+            } else {
+                return includeProcedures.isEmpty()
+                        ? Status.INCLUDE
+                        : Status.EXCLUDE_IMPLICIT;
+            }
+        }
+
+        return Status.EXCLUDE_IMPLICIT;
+    }
+
+    private boolean includesProcedure(Collection<IncludeProcedure> includeProcedures) {
+        for(IncludeProcedure procedure : includeProcedures) {
+            if(getName().matches(procedure.getPattern())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean excludesProcedure(Collection<ExcludeProcedure> excludeProcedures) {
+        for(ExcludeProcedure procedure : excludeProcedures) {
+            if(getName().matches(procedure.getPattern())) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaNode.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaNode.java
new file mode 100644
index 0000000..11e95d1
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaNode.java
@@ -0,0 +1,70 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import org.apache.cayenne.dbsync.reverse.dbimport.Catalog;
+import org.apache.cayenne.dbsync.reverse.dbimport.ReverseEngineering;
+import org.apache.cayenne.dbsync.reverse.dbimport.Schema;
+import org.apache.cayenne.dbsync.reverse.dbimport.SchemaContainer;
+
+class SchemaNode extends Node<CatalogNode> {
+
+    SchemaNode(String name, CatalogNode parent) {
+        super(name, parent);
+    }
+
+    @Override
+    public Status getStatus(ReverseEngineering config) {
+        // check via parent path
+        if(getParent() != null) {
+            Status parentStatus = getParent().getStatus(config);
+            if(parentStatus != Status.INCLUDE) {
+                return parentStatus;
+            }
+
+            Catalog parentCatalog = getParent().getCatalog(config);
+            if(parentCatalog != null && includesSchema(parentCatalog) == Status.INCLUDE) {
+                return Status.INCLUDE;
+            }
+        }
+
+        // check root
+        return includesSchema(config);
+    }
+
+    Status includesSchema(SchemaContainer container) {
+        if(container.getSchemas().isEmpty()) {
+            return Status.INCLUDE;
+        }
+        if(getSchema(container) != null) {
+            return Status.INCLUDE;
+        }
+        return Status.EXCLUDE_IMPLICIT;
+    }
+
+    Schema getSchema(SchemaContainer container) {
+        for(Schema schema : container.getSchemas()) {
+            if(schema.getName().equals(getName())) {
+                return schema;
+            }
+        }
+        return null;
+    }
+}
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaProcedureNode.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaProcedureNode.java
new file mode 100644
index 0000000..00a37d6
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaProcedureNode.java
@@ -0,0 +1,49 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cayenne.dbsync.reverse.dbimport.Catalog;
+import org.apache.cayenne.dbsync.reverse.dbimport.FilterContainer;
+import org.apache.cayenne.dbsync.reverse.dbimport.ReverseEngineering;
+
+class SchemaProcedureNode extends ProcedureNode<SchemaNode> {
+
+    SchemaProcedureNode(String name, SchemaNode parent) {
+        super(name, parent);
+    }
+
+    @Override
+    List<FilterContainer> getContainers(ReverseEngineering config) {
+        List<FilterContainer> containers = new ArrayList<>();
+        if(getParent() != null && getParent().getParent() != null) {
+            Catalog catalog = getParent().getParent().getCatalog(config);
+            if(catalog != null) {
+                containers.add(getParent().getSchema(catalog));
+                containers.add(catalog);
+            }
+            containers.add(getParent().getSchema(config));
+        }
+        containers.add(config);
+        return containers;
+    }
+}
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaTableNode.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaTableNode.java
new file mode 100644
index 0000000..302772e
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaTableNode.java
@@ -0,0 +1,49 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cayenne.dbsync.reverse.dbimport.Catalog;
+import org.apache.cayenne.dbsync.reverse.dbimport.FilterContainer;
+import org.apache.cayenne.dbsync.reverse.dbimport.ReverseEngineering;
+
+class SchemaTableNode extends TableNode<SchemaNode> {
+
+    SchemaTableNode(String name, SchemaNode parent) {
+        super(name, parent);
+    }
+
+    @Override
+    List<FilterContainer> getContainers(ReverseEngineering config) {
+        List<FilterContainer> containers = new ArrayList<>();
+        if(getParent() != null && getParent().getParent() != null) {
+            Catalog catalog = getParent().getParent().getCatalog(config);
+            if(catalog != null) {
+                containers.add(getParent().getSchema(catalog));
+                containers.add(catalog);
+            }
+            containers.add(getParent().getSchema(config));
+        }
+        containers.add(config);
+        return containers;
+    }
+}
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/Status.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/Status.java
new file mode 100644
index 0000000..6e1369b
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/Status.java
@@ -0,0 +1,38 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import java.awt.Color;
+
+enum Status {
+    INCLUDE             (new Color(60,179,113)),
+    EXCLUDE_EXPLICIT    (new Color(178, 0, 0)),
+    EXCLUDE_IMPLICIT    (Color.LIGHT_GRAY);
+
+    private final Color color;
+
+    Status(Color color) {
+        this.color = color;
+    }
+
+    public Color getColor() {
+        return color;
+    }
+}
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/TableNode.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/TableNode.java
new file mode 100644
index 0000000..08652d1
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbimport/tree/TableNode.java
@@ -0,0 +1,100 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.cayenne.dbsync.reverse.dbimport.ExcludeTable;
+import org.apache.cayenne.dbsync.reverse.dbimport.FilterContainer;
+import org.apache.cayenne.dbsync.reverse.dbimport.IncludeTable;
+import org.apache.cayenne.dbsync.reverse.dbimport.ReverseEngineering;
+
+abstract class TableNode<T extends Node> extends Node<T> {
+
+    TableNode(String name, T parent) {
+        super(name, parent);
+    }
+    
+    @Override
+    public Status getStatus(ReverseEngineering config) {
+        Status parentStatus = getParent().getStatus(config);
+        if(parentStatus != Status.INCLUDE) {
+            return parentStatus;
+        }
+
+        List<IncludeTable> includeTables = new ArrayList<>();
+        List<ExcludeTable> excludeTables = new ArrayList<>();
+        for(FilterContainer container : getContainers(config)) {
+            if(container == null) {
+                continue;
+            }
+            includeTables.addAll(container.getIncludeTables());
+            excludeTables.addAll(container.getExcludeTables());
+        }
+
+        return includesTable(includeTables, excludeTables);
+    }
+    
+    abstract List<FilterContainer> getContainers(ReverseEngineering config);
+
+    Status includesTable(Collection<IncludeTable> includeTables, Collection<ExcludeTable> excludeTables) {
+        if(includeTables.isEmpty() && excludeTables.isEmpty()) {
+            return Status.INCLUDE;
+        }
+
+        if(!includeTables.isEmpty()) {
+            if(getIncludeTable(includeTables) != null) {
+                return Status.INCLUDE;
+            }
+        }
+
+        if(!excludeTables.isEmpty()) {
+            if(getExcludeTable(excludeTables) != null) {
+                return Status.EXCLUDE_EXPLICIT;
+            } else {
+                return includeTables.isEmpty()
+                        ? Status.INCLUDE
+                        : Status.EXCLUDE_IMPLICIT;
+            }
+        }
+
+        return Status.EXCLUDE_IMPLICIT;
+    }
+
+    IncludeTable getIncludeTable(Collection<IncludeTable> includeTables) {
+        for(IncludeTable table : includeTables) {
+            if(getName().matches(table.getPattern())) {
+                return table;
+            }
+        }
+        return null;
+    }
+
+    ExcludeTable getExcludeTable(Collection<ExcludeTable> excludeTables) {
+        for(ExcludeTable table : excludeTables) {
+            if(getName().matches(table.getPattern())) {
+                return table;
+            }
+        }
+        return null;
+    }
+}
diff --git a/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/BaseNodeTest.java b/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/BaseNodeTest.java
new file mode 100644
index 0000000..dfb8403
--- /dev/null
+++ b/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/BaseNodeTest.java
@@ -0,0 +1,243 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import org.apache.cayenne.dbsync.reverse.dbimport.Catalog;
+import org.apache.cayenne.dbsync.reverse.dbimport.ExcludeColumn;
+import org.apache.cayenne.dbsync.reverse.dbimport.ExcludeProcedure;
+import org.apache.cayenne.dbsync.reverse.dbimport.ExcludeTable;
+import org.apache.cayenne.dbsync.reverse.dbimport.IncludeColumn;
+import org.apache.cayenne.dbsync.reverse.dbimport.IncludeProcedure;
+import org.apache.cayenne.dbsync.reverse.dbimport.IncludeTable;
+import org.apache.cayenne.dbsync.reverse.dbimport.ReverseEngineering;
+import org.apache.cayenne.dbsync.reverse.dbimport.Schema;
+
+import static org.junit.Assert.assertEquals;
+
+class BaseNodeTest {
+
+    ReverseEngineering config;
+
+    void assertIncluded(Node<?> node) {
+        assertEquals(Status.INCLUDE, node.getStatus(config));
+    }
+
+    void assertExcludedImplicitly(Node<?> node) {
+        assertEquals(Status.EXCLUDE_IMPLICIT, node.getStatus(config));
+    }
+
+    void assertExcludedExplicitly(Node<?> node) {
+        assertEquals(Status.EXCLUDE_EXPLICIT, node.getStatus(config));
+    }
+
+    static ConfigBuilder config() {
+        return new ConfigBuilder();
+    }
+
+    static SchemaBuilder schema(String name) {
+        return new SchemaBuilder(name);
+    }
+
+    static CatalogBuilder catalog(String name) {
+        return new CatalogBuilder(name);
+    }
+
+    static IncludeTableBuilder table(String name) {
+        return new IncludeTableBuilder(name);
+    }
+
+    static class IncludeTableBuilder {
+        final IncludeTable table;
+
+        IncludeTableBuilder(String name) {
+            table = new IncludeTable(name);
+        }
+
+        IncludeTableBuilder includeColumn(String name) {
+            table.addIncludeColumn(new IncludeColumn(name));
+            return this;
+        }
+
+        IncludeTableBuilder excludeColumn(String name) {
+            table.addExcludeColumn(new ExcludeColumn(name));
+            return this;
+        }
+
+        IncludeTable build() {
+            return table;
+        }
+    }
+
+    static class SchemaBuilder {
+        Schema schema;
+
+        SchemaBuilder(String name) {
+            schema = new Schema(name);
+        }
+
+        SchemaBuilder includeTable(String name) {
+            schema.addIncludeTable(new IncludeTable(name));
+            return this;
+        }
+
+        SchemaBuilder excludeTable(String name) {
+            schema.addExcludeTable(new ExcludeTable(name));
+            return this;
+        }
+
+        SchemaBuilder includeTable(IncludeTableBuilder tableBuilder) {
+            schema.addIncludeTable(tableBuilder.build());
+            return this;
+        }
+
+        SchemaBuilder includeColumn(String name) {
+            schema.addIncludeColumn(new IncludeColumn(name));
+            return this;
+        }
+
+        SchemaBuilder excludeColumn(String name) {
+            schema.addExcludeColumn(new ExcludeColumn(name));
+            return this;
+        }
+
+        SchemaBuilder includeProcedure(String name) {
+            schema.addIncludeProcedure(new IncludeProcedure(name));
+            return this;
+        }
+
+        SchemaBuilder excludeProcedure(String name) {
+            schema.addExcludeProcedure(new ExcludeProcedure(name));
+            return this;
+        }
+
+        Schema build() {
+            return schema;
+        }
+    }
+
+    static class CatalogBuilder {
+        Catalog catalog;
+
+        protected CatalogBuilder(String name) {
+            catalog = new Catalog(name);
+        }
+
+        CatalogBuilder schema(SchemaBuilder schemaBuilder) {
+            catalog.addSchema(schemaBuilder.build());
+            return this;
+        }
+
+        CatalogBuilder includeTable(String name) {
+            catalog.addIncludeTable(new IncludeTable(name));
+            return this;
+        }
+
+        CatalogBuilder includeTable(IncludeTableBuilder tableBuilder) {
+            catalog.addIncludeTable(tableBuilder.build());
+            return this;
+        }
+
+        CatalogBuilder excludeTable(String name) {
+            catalog.addExcludeTable(new ExcludeTable(name));
+            return this;
+        }
+
+        CatalogBuilder includeColumn(String name) {
+            catalog.addIncludeColumn(new IncludeColumn(name));
+            return this;
+        }
+
+        CatalogBuilder excludeColumn(String name) {
+            catalog.addExcludeColumn(new ExcludeColumn(name));
+            return this;
+        }
+
+        CatalogBuilder includeProcedure(String name) {
+            catalog.addIncludeProcedure(new IncludeProcedure(name));
+            return this;
+        }
+
+        CatalogBuilder excludeProcedure(String name) {
+            catalog.addExcludeProcedure(new ExcludeProcedure(name));
+            return this;
+        }
+
+        Catalog build() {
+            return catalog;
+        }
+    }
+
+    static class ConfigBuilder {
+        ReverseEngineering config;
+
+        protected ConfigBuilder() {
+            config = new ReverseEngineering();
+        }
+
+        ConfigBuilder schema(SchemaBuilder schemaBuilder) {
+            config.addSchema(schemaBuilder.build());
+            return this;
+        }
+
+        ConfigBuilder catalog(CatalogBuilder catalogBuilder) {
+            config.addCatalog(catalogBuilder.build());
+            return this;
+        }
+
+        ConfigBuilder includeTable(String name) {
+            config.addIncludeTable(new IncludeTable(name));
+            return this;
+        }
+
+        ConfigBuilder includeTable(IncludeTableBuilder tableBuilder) {
+            config.addIncludeTable(tableBuilder.build());
+            return this;
+        }
+
+        ConfigBuilder excludeTable(String name) {
+            config.addExcludeTable(new ExcludeTable(name));
+            return this;
+        }
+
+        ConfigBuilder includeColumn(String name) {
+            config.addIncludeColumn(new IncludeColumn(name));
+            return this;
+        }
+
+        ConfigBuilder excludeColumn(String name) {
+            config.addExcludeColumn(new ExcludeColumn(name));
+            return this;
+        }
+
+        ConfigBuilder includeProcedure(String name) {
+            config.addIncludeProcedure(new IncludeProcedure(name));
+            return this;
+        }
+
+        ConfigBuilder excludeProcedure(String name) {
+            config.addExcludeProcedure(new ExcludeProcedure(name));
+            return this;
+        }
+
+        ReverseEngineering build() {
+            return config;
+        }
+    }
+}
diff --git a/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/CatalogNodeTest.java b/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/CatalogNodeTest.java
new file mode 100644
index 0000000..8d7fe49
--- /dev/null
+++ b/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/CatalogNodeTest.java
@@ -0,0 +1,51 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class CatalogNodeTest extends BaseNodeTest {
+
+    private CatalogNode node;
+
+    @Before
+    public void createNode() {
+        node = new CatalogNode("catalog");
+    }
+
+    @Test
+    public void testIncludeEmptyConfig() {
+        config = config().build();
+        assertIncluded(node);
+    }
+
+    @Test
+    public void testIncludeCatalog() {
+        config = config().catalog(catalog("catalog")).build();
+        assertIncluded(node);
+    }
+
+    @Test
+    public void testNoIncludeCatalog() {
+        config = config().catalog(catalog("catalog1")).build();
+        assertExcludedImplicitly(node);
+    }
+}
diff --git a/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/ColumnNodeTest.java b/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/ColumnNodeTest.java
new file mode 100644
index 0000000..0a1c4b4
--- /dev/null
+++ b/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/ColumnNodeTest.java
@@ -0,0 +1,215 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class ColumnNodeTest extends BaseNodeTest {
+
+    private ColumnNode node;
+
+    @Before
+    public void createNode() {
+        CatalogNode catalogNode = new CatalogNode("catalog");
+        SchemaNode schemaNode = new SchemaNode("schema", catalogNode);
+        SchemaTableNode tableNode = new SchemaTableNode("table1", schemaNode);
+        node = new ColumnNode("id", tableNode);
+    }
+
+    @Test
+    public void rootEmpty() {
+        config = config().build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void rootIncludeTable() {
+        config = config().includeTable("table1").build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void rootNoIncludeTable() {
+        config = config().includeTable("table2").build();
+
+        assertExcludedImplicitly(node);
+    }
+
+    @Test
+    public void rootExcludeTable() {
+        config = config().excludeTable("table1").build();
+
+        assertExcludedExplicitly(node);
+    }
+
+    @Test
+    public void rootIncludeColumn() {
+        config = config().includeColumn("id").build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void rootNoIncludeColumn() {
+        config = config().includeColumn("name").build();
+
+        assertExcludedImplicitly(node);
+    }
+
+    @Test
+    public void rootExcludeColumn() {
+        config = config().excludeColumn("id").build();
+
+        assertExcludedExplicitly(node);
+    }
+
+    @Test
+    public void schemaIncludeAll() {
+        config = config().schema(schema("schema")).build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void schemaIncludeTable() {
+        config = config().schema(schema("schema").includeTable("table1")).build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void schemaNoIncludeTable() {
+        config = config().schema(schema("schema").includeTable("table2")).build();
+
+        assertExcludedImplicitly(node);
+    }
+
+    @Test
+    public void schemaExcludeTable() {
+        config = config().schema(schema("schema").excludeTable("table1").includeTable("table2")).build();
+
+        assertExcludedExplicitly(node);
+    }
+
+
+    @Test
+    public void schemaIncludeColumn() {
+        config = config().schema(schema("schema").includeColumn("id")).build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void schemaNoIncludeColumn() {
+        config = config().schema(schema("schema").includeColumn("name")).build();
+
+        assertExcludedImplicitly(node);
+    }
+
+    @Test
+    public void schemaExcludeColumn() {
+        config = config().schema(schema("schema").excludeColumn("id").includeColumn("name")).build();
+
+        assertExcludedExplicitly(node);
+    }
+
+
+    @Test
+    public void schemaIncludeTableRootNoIncludeTable() {
+        config = config()
+                .includeTable("table2")
+                .schema(schema("schema").includeTable("table1")).build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void schemaNoIncludeTableRootNoIncludeTable() {
+        config = config()
+                .includeTable("table2")
+                .schema(schema("schema")).build();
+
+        assertExcludedImplicitly(node);
+    }
+
+    @Test
+    public void schemaIncludeColumnRootNoIncludeColumn() {
+        config = config()
+                .includeColumn("name")
+                .schema(schema("schema").includeColumn("id")).build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void schemaNoIncludeColumnRootNoIncludeColumn() {
+        config = config()
+                .includeColumn("name")
+                .schema(schema("schema")).build();
+
+        assertExcludedImplicitly(node);
+    }
+
+
+    @Test
+    public void tableIncludeAll() {
+        config = config().includeTable(table("table1")).build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void tableInclude() {
+        config = config().includeTable(table("table1").includeColumn("id")).build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void tableNoInclude() {
+        config = config().includeTable(table("table1").includeColumn("name")).build();
+
+        assertExcludedImplicitly(node);
+    }
+
+    @Test
+    public void tableExclude() {
+        config = config().includeTable(table("table1").excludeColumn("id")).build();
+
+        assertExcludedExplicitly(node);
+    }
+
+    @Test
+    public void tableNoExclude() {
+        config = config().includeTable(table("table1").excludeColumn("name")).build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void tableIncludeExclude() {
+        config = config().includeTable(table("table1").excludeColumn("name").includeColumn("id")).build();
+
+        assertIncluded(node);
+    }
+}
diff --git a/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaNodeTest.java b/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaNodeTest.java
new file mode 100644
index 0000000..e3a660d
--- /dev/null
+++ b/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaNodeTest.java
@@ -0,0 +1,58 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class SchemaNodeTest extends BaseNodeTest {
+
+    private SchemaNode node;
+
+    @Before
+    public void createNode() {
+        CatalogNode catalogNode = new CatalogNode("catalog");
+        node = new SchemaNode("schema", catalogNode);
+    }
+
+    @Test
+    public void testIncludeEmptyConfig() {
+        config = config().build();
+        assertIncluded(node);
+    }
+
+    @Test
+    public void testIncludeSchema() {
+        config = config().schema(schema("schema")).build();
+        assertIncluded(node);
+    }
+
+    @Test
+    public void testIncludeMultipleSchemas() {
+        config = config().schema(schema("schema")).schema(schema("schema1")).build();
+        assertIncluded(node);
+    }
+
+    @Test
+    public void testNoIncludeSchema() {
+        config = config().schema(schema("schema1")).build();
+        assertExcludedImplicitly(node);
+    }
+}
diff --git a/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaProcedureNodeTest.java b/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaProcedureNodeTest.java
new file mode 100644
index 0000000..a811e27
--- /dev/null
+++ b/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaProcedureNodeTest.java
@@ -0,0 +1,109 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class SchemaProcedureNodeTest extends BaseNodeTest {
+
+    private SchemaProcedureNode node;
+
+    @Before
+    public void createNode() {
+        CatalogNode catalogNode = new CatalogNode("catalog");
+        SchemaNode schemaNode = new SchemaNode("schema", catalogNode);
+        node = new SchemaProcedureNode("procedure1", schemaNode);
+    }
+
+    @Test
+    public void rootEmpty() {
+        config = config().build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void rootInclude() {
+        config = config().includeProcedure("procedure1").build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void rootNoInclude() {
+        config = config().includeProcedure("procedure2").build();
+
+        assertExcludedImplicitly(node);
+    }
+
+    @Test
+    public void rootExclude() {
+        config = config().excludeProcedure("procedure1").build();
+
+        assertExcludedExplicitly(node);
+    }
+
+    @Test
+    public void schemaIncludeAll() {
+        config = config().schema(schema("schema")).build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void schemaInclude() {
+        config = config().schema(schema("schema").includeProcedure("procedure1")).build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void schemaNoInclude() {
+        config = config().schema(schema("schema").includeProcedure("procedure2")).build();
+
+        assertExcludedImplicitly(node);
+    }
+
+    @Test
+    public void schemaExclude() {
+        config = config().schema(schema("schema").excludeProcedure("procedure1").includeProcedure("procedure2")).build();
+
+        assertExcludedExplicitly(node);
+    }
+
+    @Test
+    public void schemaIncludeRootNoInclude() {
+        config = config()
+                .includeProcedure("procedure2")
+                .schema(schema("schema").includeProcedure("procedure1")).build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void schemaNoIncludeRootNoInclude() {
+        config = config()
+                .includeProcedure("procedure2")
+                .schema(schema("schema")).build();
+
+        assertExcludedImplicitly(node);
+    }
+}
\ No newline at end of file
diff --git a/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaTableNodeTest.java b/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaTableNodeTest.java
new file mode 100644
index 0000000..dfecc5b
--- /dev/null
+++ b/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/editor/dbimport/tree/SchemaTableNodeTest.java
@@ -0,0 +1,109 @@
+/*****************************************************************
+ *   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.cayenne.modeler.editor.dbimport.tree;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class SchemaTableNodeTest extends BaseNodeTest {
+
+    private SchemaTableNode node;
+
+    @Before
+    public void createNode() {
+        CatalogNode catalogNode = new CatalogNode("catalog");
+        SchemaNode schemaNode = new SchemaNode("schema", catalogNode);
+        node = new SchemaTableNode("table1", schemaNode);
+    }
+
+    @Test
+    public void rootEmpty() {
+        config = config().build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void rootInclude() {
+        config = config().includeTable("table1").build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void rootNoInclude() {
+        config = config().includeTable("table2").build();
+
+        assertExcludedImplicitly(node);
+    }
+
+    @Test
+    public void rootExclude() {
+        config = config().excludeTable("table1").build();
+
+        assertExcludedExplicitly(node);
+    }
+
+    @Test
+    public void schemaIncludeAll() {
+        config = config().schema(schema("schema")).build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void schemaInclude() {
+        config = config().schema(schema("schema").includeTable("table1")).build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void schemaNoInclude() {
+        config = config().schema(schema("schema").includeTable("table2")).build();
+
+        assertExcludedImplicitly(node);
+    }
+
+    @Test
+    public void schemaExclude() {
+        config = config().schema(schema("schema").excludeTable("table1").includeTable("table2")).build();
+
+        assertExcludedExplicitly(node);
+    }
+
+    @Test
+    public void schemaIncludeRootNoInclude() {
+        config = config()
+                .includeTable("table2")
+                .schema(schema("schema").includeTable("table1")).build();
+
+        assertIncluded(node);
+    }
+
+    @Test
+    public void schemaNoIncludeRootNoInclude() {
+        config = config()
+                .includeTable("table2")
+                .schema(schema("schema")).build();
+
+        assertExcludedImplicitly(node);
+    }
+}
\ No newline at end of file