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

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

commit f1f4a0e1928f3d4a14cbd28673a129f31e712b27
Author: Andrus Adamchik <[email protected]>
AuthorDate: Tue May 5 16:13:36 2026 -0400

    Modeler cleanup
    
    unifying component init sequences, fixing inheritance
---
 .../apache/cayenne/modeler/toolkit/AppPanel.java   |   2 +-
 .../apache/cayenne/modeler/toolkit/AppToolBar.java |  14 ++
 .../cayenne/modeler/toolkit/ProjectPanel.java      |   2 +-
 .../org/apache/cayenne/modeler/ui/MainFrame.java   |  10 +-
 .../org/apache/cayenne/modeler/ui/MainToolBar.java |  77 +++++----
 .../org/apache/cayenne/modeler/ui/SearchPanel.java |  41 +++--
 .../ui/about/{AboutDialog.java => AboutFrame.java} |  14 +-
 .../cayenne/modeler/ui/action/AboutAction.java     |   4 +-
 .../modeler/ui/project/editor/EditorPanelView.java |  51 +++---
 .../datadomain/DataDomainGeneratorsPanel.java      |  20 +--
 .../project/editor/datadomain/DataDomainView.java  |  35 ++---
 .../ui/project/editor/datamap/DataMapView.java     |  15 +-
 .../datamap/dbimport/DbImportResultDialog.java     |   4 +-
 .../editor/datamap/dbimport/DbImportView.java      |  41 ++---
 .../datamap/dbimport/DraggableTreePanel.java       |  20 ++-
 .../dbimport/ReverseEngineeringConfigPanel.java    | 174 ++++++++++-----------
 .../dbimport/ReverseEngineeringTreePanel.java      |  24 +--
 .../editor/datamap/main/DataMapMainView.java       |  73 ++++-----
 .../editor/datanode/DataNodeEditorPanel.java       |  40 ++---
 .../ui/project/editor/dbentity/DbEntityView.java   |  19 ++-
 .../editor/dbentity/main/DbEntityMainView.java     |  64 +++-----
 .../editor/dbentity/main/PKDBGeneratorPanel.java   |   9 +-
 .../dbentity/properties/DbAttributePanel.java      |  16 +-
 .../properties/DbEntityPropertiesView.java         |  24 +--
 .../dbentity/properties/DbRelationshipPanel.java   |  20 ++-
 .../project/editor/embeddable/EmbeddableView.java  |  16 +-
 .../attributes/EmbeddableAttributesView.java       |  17 +-
 .../ui/project/editor/objentity/ObjEntityView.java |  27 ++--
 .../callbacks/ObjEntityCallbacksView.java          |  17 +-
 .../editor/objentity/main/ObjEntityMainView.java   |  69 ++++----
 .../objentity/properties/ObjAttributePanel.java    |  38 +++--
 .../properties/ObjEntityPropertiesView.java        |  17 +-
 .../objentity/properties/ObjRelationshipPanel.java |  40 ++---
 .../editor/procedure/ProcedureQueryView.java       |   9 +-
 .../editor/procedure/ProcedureTabbedView.java      |  15 +-
 .../editor/query/ejbql/EjbqlTabbedView.java        |  14 +-
 .../query/selectquery/SelectQueryTabbedView.java   |  17 +-
 .../query/sqltemplate/SQLTemplateTabbedView.java   |  17 +-
 .../cayenne/modeler/ui/welcome/WelcomeScreen.java  |  52 ++----
 .../modeler/ui/welcome/WelcomeScreenMainPanel.java |  23 +++
 40 files changed, 619 insertions(+), 582 deletions(-)

diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/AppPanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/AppPanel.java
index 4b5203604..e81f4a05b 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/AppPanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/AppPanel.java
@@ -30,7 +30,7 @@ import javax.swing.JPanel;
  */
 public abstract class AppPanel extends JPanel {
 
-    private final Application app;
+    protected final Application app;
 
     protected AppPanel(Application app) {
         this.app = app;
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/AppToolBar.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/AppToolBar.java
new file mode 100644
index 000000000..4862a370c
--- /dev/null
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/AppToolBar.java
@@ -0,0 +1,14 @@
+package org.apache.cayenne.modeler.toolkit;
+
+import org.apache.cayenne.modeler.Application;
+
+import javax.swing.*;
+
+public class AppToolBar extends JToolBar {
+
+    protected final Application app;
+
+    protected AppToolBar(Application app) {
+        this.app = app;
+    }
+}
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/ProjectPanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/ProjectPanel.java
index b0d88eff6..aa84a82b9 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/ProjectPanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/ProjectPanel.java
@@ -29,7 +29,7 @@ import org.apache.cayenne.modeler.project.ProjectSession;
  */
 public abstract class ProjectPanel extends AppPanel {
 
-    private final ProjectSession session;
+    protected final ProjectSession session;
 
     protected ProjectPanel(ProjectSession session) {
         super(session.app());
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/MainFrame.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/MainFrame.java
index 3c15889ed..2fec3ab01 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/MainFrame.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/MainFrame.java
@@ -78,6 +78,7 @@ import java.util.List;
  */
 public class MainFrame extends AppFrame {
 
+    private static final int DEFAULT_BUTTON_WIDTH = 30;
     private static final int DEFAULT_DIVIDER_LOCATION = 400;
 
     private final GlobalActions globalActions;
@@ -386,11 +387,10 @@ public class MainFrame extends AppFrame {
 
     private void initToolbar() {
 
-        MainToolBar toolBar = new MainToolBar(globalActions);
+        MainToolBar toolBar = new MainToolBar(app());
         getContentPane().add(toolBar, BorderLayout.NORTH);
 
         // Hide some buttons when frame is too small
-        int defaultBtnWidth = toolBar.getDefaultButtonWidth();
         addComponentListener(new ComponentAdapter() {
             private final int[] empty = {};
             private final int[] all = {6, 7, 8, 9, 10, 11, 12, 13, 14};
@@ -402,13 +402,13 @@ public class MainFrame extends AppFrame {
             @Override
             public void componentResized(ComponentEvent e) {
                 int[] hidden, shown;
-                if (getSize().width < (13 * defaultBtnWidth + 300)) {
+                if (getSize().width < (13 * DEFAULT_BUTTON_WIDTH + 300)) {
                     hidden = all;
                     shown = empty;
-                } else if (getSize().width < (16 * defaultBtnWidth + 300)) {
+                } else if (getSize().width < (16 * DEFAULT_BUTTON_WIDTH + 
300)) {
                     hidden = removeAndCopy;
                     shown = undo;
-                } else if (getSize().width < (18 * defaultBtnWidth + 300)) {
+                } else if (getSize().width < (18 * DEFAULT_BUTTON_WIDTH + 
300)) {
                     hidden = remove;
                     shown = undoAndCopy;
                 } else {
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/MainToolBar.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/MainToolBar.java
index 415e5282e..a07f81ac2 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/MainToolBar.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/MainToolBar.java
@@ -1,75 +1,94 @@
 package org.apache.cayenne.modeler.ui;
 
+import org.apache.cayenne.modeler.Application;
 import org.apache.cayenne.modeler.service.action.GlobalActions;
-import org.apache.cayenne.modeler.ui.action.*;
+import org.apache.cayenne.modeler.toolkit.AppToolBar;
+import org.apache.cayenne.modeler.ui.action.CopyAction;
+import org.apache.cayenne.modeler.ui.action.CreateDataMapAction;
+import org.apache.cayenne.modeler.ui.action.CreateDbEntityAction;
+import org.apache.cayenne.modeler.ui.action.CreateEmbeddableAction;
+import org.apache.cayenne.modeler.ui.action.CreateNodeAction;
+import org.apache.cayenne.modeler.ui.action.CreateObjEntityAction;
+import org.apache.cayenne.modeler.ui.action.CreateProcedureAction;
+import org.apache.cayenne.modeler.ui.action.CreateQueryAction;
+import org.apache.cayenne.modeler.ui.action.CutAction;
+import org.apache.cayenne.modeler.ui.action.NavigateBackwardAction;
+import org.apache.cayenne.modeler.ui.action.NavigateForwardAction;
+import org.apache.cayenne.modeler.ui.action.NewProjectAction;
+import org.apache.cayenne.modeler.ui.action.OpenProjectAction;
+import org.apache.cayenne.modeler.ui.action.PasteAction;
+import org.apache.cayenne.modeler.ui.action.RedoAction;
+import org.apache.cayenne.modeler.ui.action.RemoveAction;
+import org.apache.cayenne.modeler.ui.action.SaveAction;
+import org.apache.cayenne.modeler.ui.action.UndoAction;
 
 import javax.swing.*;
 import javax.swing.border.Border;
 import java.awt.*;
 
-class MainToolBar extends JToolBar {
+class MainToolBar extends AppToolBar {
 
-    private final JButton backButton;
-    private final JButton removeButton;
+    public MainToolBar(Application app) {
+        super(app);
+        initLayout();
+    }
 
-    public MainToolBar(GlobalActions globalActions) {
+    private void initLayout() {
         setFloatable(false);
 
+        GlobalActions actions = app.getActionManager();
+
         Dimension smallBtnDim = new Dimension(30, 30);
-        backButton = 
globalActions.getAction(NavigateBackwardAction.class).buildButton(1);
+
+        JButton backButton = 
actions.getAction(NavigateBackwardAction.class).buildButton(1);
         backButton.setMinimumSize(smallBtnDim);
         backButton.setPreferredSize(smallBtnDim);
         add(backButton);
 
-        JButton forwardButton = 
globalActions.getAction(NavigateForwardAction.class).buildButton(3);
+        JButton forwardButton = 
actions.getAction(NavigateForwardAction.class).buildButton(3);
         forwardButton.setMinimumSize(smallBtnDim);
         forwardButton.setPreferredSize(smallBtnDim);
         add(forwardButton);
 
         addSeparator(new Dimension(30, 0));
 
-        add(globalActions.getAction(NewProjectAction.class).buildButton(1));
-        add(globalActions.getAction(OpenProjectAction.class).buildButton(2));
-        add(globalActions.getAction(SaveAction.class).buildButton(3));
+        add(actions.getAction(NewProjectAction.class).buildButton(1));
+        add(actions.getAction(OpenProjectAction.class).buildButton(2));
+        add(actions.getAction(SaveAction.class).buildButton(3));
 
         addSeparator();
 
-        removeButton = 
globalActions.getAction(RemoveAction.class).buildButton();
+        JButton removeButton = 
actions.getAction(RemoveAction.class).buildButton();
         add(removeButton);
 
         addSeparator();
 
-        add(globalActions.getAction(CutAction.class).buildButton(1));
-        add(globalActions.getAction(CopyAction.class).buildButton(2));
-        add(globalActions.getAction(PasteAction.class).buildButton(3));
+        add(actions.getAction(CutAction.class).buildButton(1));
+        add(actions.getAction(CopyAction.class).buildButton(2));
+        add(actions.getAction(PasteAction.class).buildButton(3));
 
         addSeparator();
 
-        add(globalActions.getAction(UndoAction.class).buildButton(1));
-        add(globalActions.getAction(RedoAction.class).buildButton(3));
+        add(actions.getAction(UndoAction.class).buildButton(1));
+        add(actions.getAction(RedoAction.class).buildButton(3));
 
         addSeparator();
 
-        add(globalActions.getAction(CreateNodeAction.class).buildButton(1));
-        add(globalActions.getAction(CreateDataMapAction.class).buildButton(3));
+        add(actions.getAction(CreateNodeAction.class).buildButton(1));
+        add(actions.getAction(CreateDataMapAction.class).buildButton(3));
 
         addSeparator();
 
-        
add(globalActions.getAction(CreateDbEntityAction.class).buildButton(1));
-        
add(globalActions.getAction(CreateProcedureAction.class).buildButton(3));
+        add(actions.getAction(CreateDbEntityAction.class).buildButton(1));
+        add(actions.getAction(CreateProcedureAction.class).buildButton(3));
 
         addSeparator();
 
-        
add(globalActions.getAction(CreateObjEntityAction.class).buildButton(1));
-        
add(globalActions.getAction(CreateEmbeddableAction.class).buildButton(2));
-        add(globalActions.getAction(CreateQueryAction.class).buildButton(3));
-
-        // is used to place search feature components the most right on a 
toolbar
-        add(new SearchPanel(globalActions.getAction(FindAction.class)));
-    }
+        add(actions.getAction(CreateObjEntityAction.class).buildButton(1));
+        add(actions.getAction(CreateEmbeddableAction.class).buildButton(2));
+        add(actions.getAction(CreateQueryAction.class).buildButton(3));
 
-    int getDefaultButtonWidth() {
-        return removeButton.getUI().getPreferredSize(backButton).width;
+        add(new SearchPanel(app));
     }
 
     @Override
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/SearchPanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/SearchPanel.java
index 4259e27cb..eb87accc7 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/SearchPanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/SearchPanel.java
@@ -1,5 +1,7 @@
 package org.apache.cayenne.modeler.ui;
 
+import org.apache.cayenne.modeler.Application;
+import org.apache.cayenne.modeler.toolkit.AppPanel;
 import org.apache.cayenne.modeler.ui.action.FindAction;
 
 import javax.swing.*;
@@ -7,21 +9,38 @@ import java.awt.*;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
 
-public class SearchPanel extends JPanel {
+public class SearchPanel extends AppPanel {
 
     private final JLabel searchLabel;
     private final JPanel box;
     private final JTextField findField;
 
-    public SearchPanel(FindAction findAction) {
-        super(new BorderLayout());
-        searchLabel = new JLabel("Search: ");
-        box = new JPanel();
+    public SearchPanel(Application app) {
+        super(app);
+
+        this.searchLabel = new JLabel("Search: ");
+        this.box = new JPanel();
+        this.findField = new JTextField(10);
+
+        initLayout();
+        initBindings();
+    }
+
+    private void initLayout() {
+        setLayout(new BorderLayout());
 
-        findField = new JTextField(10);
         findField.putClientProperty("JTextField.variant", "search");
         findField.setMaximumSize(new Dimension(100, 22));
         findField.setPreferredSize(new Dimension(100, 22));
+        searchLabel.setLabelFor(findField);
+        // is used to place label and text field one after another
+        box.setLayout(new BoxLayout(box, BoxLayout.X_AXIS));
+        box.add(searchLabel);
+        box.add(findField);
+        add(box, BorderLayout.EAST);
+    }
+
+    private void initBindings() {
         findField.addKeyListener(new KeyListener() {
             public void keyPressed(KeyEvent e) {
                 if (e.getKeyCode() != KeyEvent.VK_ENTER) {
@@ -35,7 +54,7 @@ public class SearchPanel extends JPanel {
             public void keyTyped(KeyEvent e) {
             }
         });
-        findField.setAction(findAction);
+        
findField.setAction(app().getActionManager().getAction(FindAction.class));
 
         Toolkit.getDefaultToolkit().addAWTEventListener(event -> {
             if (event instanceof KeyEvent) {
@@ -45,14 +64,6 @@ public class SearchPanel extends JPanel {
                 }
             }
         }, AWTEvent.KEY_EVENT_MASK);
-
-        searchLabel.setLabelFor(findField);
-        // is used to place label and text field one after another
-        box.setLayout(new BoxLayout(box, BoxLayout.X_AXIS));
-        box.add(searchLabel);
-        box.add(findField);
-
-        add(box, BorderLayout.EAST);
     }
 
     public void hideSearchLabel() {
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/about/AboutDialog.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/about/AboutFrame.java
similarity index 90%
rename from 
modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/about/AboutDialog.java
rename to 
modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/about/AboutFrame.java
index d849cfbea..560bf0e77 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/about/AboutDialog.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/about/AboutFrame.java
@@ -19,9 +19,7 @@
 
 package org.apache.cayenne.modeler.ui.about;
 
-import org.apache.cayenne.modeler.Application;
 import org.apache.cayenne.modeler.toolkit.icon.IconFactory;
-import org.apache.cayenne.modeler.toolkit.AppFrame;
 import org.apache.cayenne.util.LocalizedStringsHandler;
 import org.apache.cayenne.util.Util;
 
@@ -38,10 +36,7 @@ import java.time.LocalDate;
 /**
  * Displays the Cayenne license and build information.
  */
-// Implementation note - the data displayed here is
-// static and very simple, so there is no need to implement complex Scope MVC
-// triad, though it might be beneficial to use strings file
-public class AboutDialog extends AppFrame implements FocusListener, 
KeyListener, MouseListener {
+public class AboutFrame extends JFrame implements FocusListener, KeyListener, 
MouseListener {
 
     private static final String ABOUT_STRING = "(c) 2001-%d Apache Software 
Foundation and individual authors.<br><br>https://cayenne.apache.org/<br>";
 
@@ -55,8 +50,7 @@ public class AboutDialog extends AppFrame implements 
FocusListener, KeyListener,
         return logoImage;
     }
 
-    public AboutDialog(Application application) {
-        super(application);
+    public AboutFrame() {
         initLayout();
         initBindings();
         pack();
@@ -96,7 +90,7 @@ public class AboutDialog extends AppFrame implements 
FocusListener, KeyListener,
         gbc2.gridy = 2;
         gbc2.insets = new Insets(6, 12, 12, 12);
         panel.add(info, gbc2);
-        info.setText(getInfoString(app()));
+        info.setText(getInfoString());
     }
 
     private void initBindings() {
@@ -105,7 +99,7 @@ public class AboutDialog extends AppFrame implements 
FocusListener, KeyListener,
         addKeyListener(this);
     }
 
-    private static String getInfoString(Application application) {
+    private static String getInfoString() {
         if (infoString == null) {
 
             double maxMemory = (double) Runtime.getRuntime().maxMemory() / 
1024 / 1024;
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/AboutAction.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/AboutAction.java
index fcc875d94..edf208b96 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/AboutAction.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/AboutAction.java
@@ -20,7 +20,7 @@
 package org.apache.cayenne.modeler.ui.action;
 
 import org.apache.cayenne.modeler.Application;
-import org.apache.cayenne.modeler.ui.about.AboutDialog;
+import org.apache.cayenne.modeler.ui.about.AboutFrame;
 
 import java.awt.event.ActionEvent;
 
@@ -36,6 +36,6 @@ public class AboutAction extends ModelerAbstractAction {
     }
 
     public void showAboutDialog() {
-        new AboutDialog(application);
+        new AboutFrame();
     }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/EditorPanelView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/EditorPanelView.java
index f90a535fd..0e986da49 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/EditorPanelView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/EditorPanelView.java
@@ -22,6 +22,7 @@ package org.apache.cayenne.modeler.ui.project.editor;
 import org.apache.cayenne.map.QueryDescriptor;
 import org.apache.cayenne.modeler.event.display.QueryDisplayEvent;
 import org.apache.cayenne.modeler.project.ProjectSession;
+import org.apache.cayenne.modeler.toolkit.ProjectPanel;
 import org.apache.cayenne.modeler.ui.project.editor.datadomain.DataDomainView;
 import org.apache.cayenne.modeler.ui.project.editor.datamap.DataMapView;
 import 
org.apache.cayenne.modeler.ui.project.editor.datanode.DataNodeEditorPanel;
@@ -40,7 +41,7 @@ import java.awt.*;
 /**
  * Card-layout panel that shows the editor matching the currently selected 
project object.
  */
-public class EditorPanelView extends JPanel {
+public class EditorPanelView extends ProjectPanel {
 
     private static final String EMPTY_VIEW = "Empty";
     private static final String DOMAIN_VIEW = "Domain";
@@ -67,49 +68,43 @@ public class EditorPanelView extends JPanel {
     private final EjbqlTabbedView ejbqlQueryView;
 
     public EditorPanelView(ProjectSession session) {
+        super(session);
+
+        this.detailLayout = new CardLayout();
+        this.dataDomainView = new DataDomainView(session);
+        this.dataMapView = new DataMapView(session);
+        this.procedureView = new ProcedureTabbedView(session);
+        this.sqlTemplateView = new SQLTemplateTabbedView(session);
+        this.ejbqlQueryView = new EjbqlTabbedView(session);
+        this.embeddableView = new EmbeddableView(session);
+        this.objDetailView = new ObjEntityView(session);
+        this.dbDetailView = new DbEntityView(session);
+
+        initLayout();
+        initBindings();
+    }
 
-        detailLayout = new CardLayout();
+    private void initLayout() {
         setLayout(detailLayout);
 
         // some but not all panels must be wrapped in a scroll pane
         // those that are not wrapped usually have their own scrollers
         // in subpanels...
-
         add(new JPanel(), EMPTY_VIEW);
-
-        dataDomainView = new DataDomainView(session);
         add(dataDomainView, DOMAIN_VIEW);
-
-        DataNodeEditorPanel nodeEditor = new 
DataNodeEditorPanel(session.app(), session);
-        add(new JScrollPane(nodeEditor), NODE_VIEW);
-
-        dataMapView = new DataMapView(session);
+        add(new JScrollPane(new DataNodeEditorPanel(session())), NODE_VIEW);
         add(dataMapView, DATA_MAP_VIEW);
-
-        procedureView = new ProcedureTabbedView(session);
         add(procedureView, PROCEDURE_VIEW);
-
-        SelectQueryTabbedView selectQueryView = new 
SelectQueryTabbedView(session);
-        add(selectQueryView, SELECT_QUERY_VIEW);
-
-        sqlTemplateView = new SQLTemplateTabbedView(session);
+        add(new SelectQueryTabbedView(session), SELECT_QUERY_VIEW);
         add(sqlTemplateView, SQL_TEMPLATE_VIEW);
-
-        Component procedureQueryView = new ProcedureQueryView(session);
-        add(new JScrollPane(procedureQueryView), PROCEDURE_QUERY_VIEW);
-
-        ejbqlQueryView = new EjbqlTabbedView(session);
+        add(new JScrollPane(new ProcedureQueryView(session)), 
PROCEDURE_QUERY_VIEW);
         add(ejbqlQueryView, EJBQL_QUERY_VIEW);
-
-        embeddableView = new EmbeddableView(session);
         add(embeddableView, EMBEDDABLE_VIEW);
-
-        objDetailView = new ObjEntityView(session);
         add(objDetailView, OBJ_VIEW);
-
-        dbDetailView = new DbEntityView(session);
         add(dbDetailView, DB_VIEW);
+    }
 
+    private void initBindings() {
         session.addDomainDisplayListener(e -> detailLayout.show(this, 
e.getDomain() == null ? EMPTY_VIEW : DOMAIN_VIEW));
         session.addDataNodeDisplayListener(e -> detailLayout.show(this, 
e.getDataNode() == null ? EMPTY_VIEW : NODE_VIEW));
         session.addDataMapDisplayListener(e -> detailLayout.show(this, 
e.getDataMap() == null ? EMPTY_VIEW : DATA_MAP_VIEW));
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datadomain/DataDomainGeneratorsPanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datadomain/DataDomainGeneratorsPanel.java
index 26fc3fc7f..e2817eaa8 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datadomain/DataDomainGeneratorsPanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datadomain/DataDomainGeneratorsPanel.java
@@ -38,34 +38,34 @@ class DataDomainGeneratorsPanel extends JPanel {
     private final Class<?> type;
     private final String icon;
 
-    private JCheckBox checkConfig;
-    private JButton toConfigButton;
+    private final JCheckBox checkConfig;
+    private final JButton toConfigButton;
 
     DataDomainGeneratorsPanel(Application application, DataMap dataMap, String 
icon, Class<?> type) {
         this.type = type;
         this.icon = icon;
         this.dataMap = dataMap;
-        initView(application);
+        this.checkConfig = new JCheckBox();
+        this.toConfigButton = new JButton("Edit Config");
+        initLayout(application);
     }
 
-    private void initView(Application application){
+    private void initLayout(Application application) {
         setLayout(new BorderLayout());
         FormLayout layout = new FormLayout(
                 "left:pref, 4dlu, fill:70dlu, 3dlu, fill:120, 3dlu, fill:120", 
"");
         DefaultFormBuilder builder = new DefaultFormBuilder(layout);
-        this.checkConfig = new JCheckBox();
         JLabel dataMapLabel = new JLabel(dataMap.getName());
         dataMapLabel.setToolTipText(dataMap.getName());
         DataChannelMetaData metaData = application.getMetaData();
-        this.toConfigButton = new JButton("Edit Config");
-        if(metaData.get(dataMap, type) == null) {
-            if(type == ReverseEngineering.class) {
+        if (metaData.get(dataMap, type) == null) {
+            if (type == ReverseEngineering.class) {
                 checkConfig.setEnabled(false);
             }
         }
-        this.toConfigButton.setIcon(IconFactory.buildIcon(icon));
+        toConfigButton.setIcon(IconFactory.buildIcon(icon));
         builder.append(checkConfig, dataMapLabel, toConfigButton);
-        this.add(builder.getPanel(), BorderLayout.CENTER);
+        add(builder.getPanel(), BorderLayout.CENTER);
     }
 
     JCheckBox getCheckConfig() {
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datadomain/DataDomainView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datadomain/DataDomainView.java
index a1fa78a31..408169224 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datadomain/DataDomainView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datadomain/DataDomainView.java
@@ -45,33 +45,30 @@ public class DataDomainView extends ProjectTabbedPane {
 
     public DataDomainView(ProjectSession session) {
         super(session);
+        this.dbImportTab = new DataDomainDbImportTab(session);
+        this.dbImportView = new JScrollPane(dbImportTab);
+        this.cgenTab = new DataDomainCgenTab(session);
+        this.cgenView = new JScrollPane(cgenTab);
+        this.graphTab = new DataDomainGraphTab(session);
+        this.validationTab = new ValidationTab(session);
+        initLayout();
+        initBindings();
+    }
 
+    private void initLayout() {
         setTabPlacement(JTabbedPane.TOP);
-
-        // add panels to tabs
-        // note that those panels that have no internal scrollable tables
-        // must be wrapped in a scroll pane
-        JScrollPane domainView = new JScrollPane(new 
DataDomainMainView(session));
-        addTab("Main", domainView);
-
-        dbImportTab = new DataDomainDbImportTab(session);
-        dbImportView = new JScrollPane(dbImportTab);
+        addTab("Main", new JScrollPane(new DataDomainMainView(session())));
         addTab("Db Import", dbImportView);
-
-        cgenTab = new DataDomainCgenTab(session);
-        cgenView = new JScrollPane(cgenTab);
         addTab("Class Generation", cgenView);
-
-        graphTab = new DataDomainGraphTab(session);
         addTab("Graph", graphTab);
-
-        validationTab = new ValidationTab(session);
         addTab("Validation", validationTab);
+    }
 
+    private void initBindings() {
         addChangeListener(this::stateChanged);
-        session.addDomainDisplayListener(this::currentDomainChanged);
-        session.addObjEntityDisplayListener(this::onEntitySelected);
-        session.addDbEntityDisplayListener(this::onEntitySelected);
+        session().addDomainDisplayListener(this::currentDomainChanged);
+        session().addObjEntityDisplayListener(this::onEntitySelected);
+        session().addDbEntityDisplayListener(this::onEntitySelected);
     }
 
     private void onEntitySelected(ObjEntityDisplayEvent e) {
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/DataMapView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/DataMapView.java
index 6b4bbafd7..f3d5eb4d6 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/DataMapView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/DataMapView.java
@@ -32,14 +32,19 @@ public class DataMapView extends ProjectTabbedPane {
 
     public DataMapView(ProjectSession session) {
         super(session);
+        initLayout();
+        initBindings();
+    }
 
+    private void initLayout() {
         setTabPlacement(JTabbedPane.TOP);
+        addTab("DataMap", new JScrollPane(new DataMapMainView(session())));
+        addTab("DB Import", new JScrollPane(new DbImportView(session())));
+        addTab("Class Generation", new JScrollPane(new CgenPanel(app(), 
session())));
+    }
 
-        addTab("DataMap", new JScrollPane(new DataMapMainView(session)));
-        addTab("DB Import", new JScrollPane(new DbImportView(session)));
-        addTab("Class Generation", new JScrollPane(new CgenPanel(app(), 
session)));
-
-        session.addDataMapDisplayListener(this::currentDataMapChanged);
+    private void initBindings() {
+        session().addDataMapDisplayListener(this::currentDataMapChanged);
     }
 
     private void currentDataMapChanged(DataMapDisplayEvent e) {
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/DbImportResultDialog.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/DbImportResultDialog.java
index ce8e0ff39..11c26fe00 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/DbImportResultDialog.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/DbImportResultDialog.java
@@ -62,14 +62,14 @@ public class DbImportResultDialog extends AppDialog {
         this.revertButton = new JButton("Revert");
         this.okButton = new JButton("OK");
 
-        buildElements();
+        initLayout();
 
         setResizable(true);
         setPreferredSize(new Dimension(400, 400));
         pack();
     }
 
-    public void buildElements() {
+    private void initLayout() {
         buttonPanel.add(revertButton);
         buttonPanel.add(okButton);
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/DbImportView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/DbImportView.java
index d99bd7e9b..d98cb0ddc 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/DbImportView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/DbImportView.java
@@ -65,7 +65,6 @@ public class DbImportView extends ProjectPanel {
         model.setCanBeCleaned(true);
         DbImportModel draggableTreeModel = new 
DbImportModel(draggableTreeRoot);
         draggableTreeModel.setCanBeCleaned(false);
-
         draggableTree.setRootVisible(false);
         draggableTree.setShowsRootHandles(true);
         draggableTree.setModel(draggableTreeModel);
@@ -74,23 +73,29 @@ public class DbImportView extends ProjectPanel {
         reverseEngineeringTree.setShowsRootHandles(true);
 
         DbImportActions actions = new DbImportActions(app(), this, 
reverseEngineeringTree, draggableTree);
-
         this.draggableTreePanel = new DraggableTreePanel(draggableTree, 
reverseEngineeringTree, actions);
-
         draggableTree.setLoadDbSchemaAction(actions.getLoadDbSchemaAction());
-        treeToolbar = new TreeToolbarPanel(reverseEngineeringTree, actions);
-        treePanel = new ReverseEngineeringTreePanel(session, 
reverseEngineeringTree, draggableTree, actions);
+        this.treeToolbar = new TreeToolbarPanel(reverseEngineeringTree, 
actions);
+        this.treePanel = new ReverseEngineeringTreePanel(session, 
reverseEngineeringTree, draggableTree, actions);
         treePanel.setTreeToolbar(treeToolbar);
         model.setDbSchemaTree(draggableTree);
         draggableTreeModel.setDbSchemaTree(draggableTree);
-        ((ColorTreeRenderer) 
draggableTreePanel.getSourceTree().getCellRenderer()).
-                setReverseEngineeringTree(reverseEngineeringTree);
+        ((ColorTreeRenderer) 
draggableTreePanel.getSourceTree().getCellRenderer())
+                .setReverseEngineeringTree(reverseEngineeringTree);
+        this.configPanel = new ReverseEngineeringConfigPanel(session, this);
+        this.loadDbSchemaProgress = new JProgressBar();
+        this.reverseEngineeringProgress = new JProgressBar();
+        this.loadDbSchemaButton = (ModelerAbstractAction.CayenneToolbarButton)
+                actions.getLoadDbSchemaAction().buildButton(0);
+
+        initLayout(actions);
+        initBindings();
+    }
 
-        configPanel = new ReverseEngineeringConfigPanel(session, this);
+    private void initLayout(DbImportActions actions) {
         configPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
         configPanel.setVisible(false);
 
-
         FormLayout buttonPanelLayout = new FormLayout("fill:50dlu");
         DefaultFormBuilder buttonBuilder = new 
DefaultFormBuilder(buttonPanelLayout);
         buttonBuilder.append(draggableTreePanel.getMoveButton());
@@ -99,8 +104,8 @@ public class DbImportView extends ProjectPanel {
         FormLayout layout = new FormLayout("fill:160dlu:grow, 5dlu, 
fill:50dlu, 5dlu, fill:160dlu:grow");
         DefaultFormBuilder builder = new DefaultFormBuilder(layout);
         builder.append(treeToolbar, ALL_LINE_SPAN);
-        FormLayout headerLayout = new FormLayout("fill:80dlu:grow");
 
+        FormLayout headerLayout = new FormLayout("fill:80dlu:grow");
         DefaultFormBuilder reverseEngineeringHeaderBuilder = new 
DefaultFormBuilder(headerLayout);
         JLabel importLabel = new JLabel("Database Import Configuration");
         importLabel.setBorder(new EmptyBorder(0, 5, 0, 0));
@@ -111,15 +116,14 @@ public class DbImportView extends ProjectPanel {
         JLabel schemaLabel = new JLabel("Database Schema");
         schemaLabel.setBorder(new EmptyBorder(0, 5, 0, 0));
         databaseHeaderBuilder.append(schemaLabel);
-        LoadDbSchemaAction loadDbSchemaAction = 
actions.getLoadDbSchemaAction();
-        loadDbSchemaButton = (ModelerAbstractAction.CayenneToolbarButton) 
loadDbSchemaAction.buildButton(0);
+
         loadDbSchemaButton.setShowingText(false);
         loadDbSchemaButton.setText("Refresh DB Schema");
         treeToolbar.add(loadDbSchemaButton);
 
         ModelerDbImportAction dbImportAction = 
actions.getReverseEngineeringAction();
-        ModelerAbstractAction.CayenneToolbarButton reverseEngineeringButton = 
(ModelerAbstractAction.CayenneToolbarButton)
-                dbImportAction.buildButton(0);
+        ModelerAbstractAction.CayenneToolbarButton reverseEngineeringButton =
+                (ModelerAbstractAction.CayenneToolbarButton) 
dbImportAction.buildButton(0);
         reverseEngineeringButton.setShowingText(true);
         reverseEngineeringButton.setText("Run Import");
         JPanel reverseEngineeringButtonPanel = new JPanel();
@@ -130,13 +134,10 @@ public class DbImportView extends ProjectPanel {
 
         builder.append("");
         builder.append(databaseHeaderBuilder.getPanel());
-
         builder.append(treePanel);
         builder.append(buttonBuilder.getPanel());
         builder.append(draggableTreePanel);
 
-        loadDbSchemaProgress = new JProgressBar();
-        reverseEngineeringProgress = new JProgressBar();
         loadDbSchemaProgress.setIndeterminate(true);
         loadDbSchemaProgress.setVisible(false);
         reverseEngineeringProgress.setIndeterminate(true);
@@ -150,16 +151,18 @@ public class DbImportView extends ProjectPanel {
         createAdvancedOptionsHiderPanel(builder);
 
         builder.append(configPanel, ALL_LINE_SPAN);
-        this.setLayout(new BorderLayout());
+        setLayout(new BorderLayout());
         add(builder.getPanel(), BorderLayout.CENTER);
+        draggableTreePanel.getSourceTree().repaint();
+    }
 
+    private void initBindings() {
         session().addDataMapDisplayListener(e -> {
             DataMap map = e.getDataMap();
             if (map != null) {
                 initFromModel(map);
             }
         });
-        draggableTreePanel.getSourceTree().repaint();
     }
 
     private void createAdvancedOptionsHiderPanel(DefaultFormBuilder builder) {
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/DraggableTreePanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/DraggableTreePanel.java
index 6868326ec..2f210d4de 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/DraggableTreePanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/DraggableTreePanel.java
@@ -72,8 +72,8 @@ public class DraggableTreePanel extends JScrollPane {
     private final Map<Class<?>, Integer> levels;
     private final Map<Class<?>, List<Class<?>>> insertableLevels;
 
-    private ModelerAbstractAction.CayenneToolbarButton moveButton;
-    private ModelerAbstractAction.CayenneToolbarButton moveInvertButton;
+    private final ModelerAbstractAction.CayenneToolbarButton moveButton;
+    private final ModelerAbstractAction.CayenneToolbarButton moveInvertButton;
     private ImportSourceTree importSourceTree;
 
     public DraggableTreePanel(DbImportTree sourceTree, DbImportTree 
targetTree, DbImportActions actions) {
@@ -84,10 +84,10 @@ public class DraggableTreePanel extends JScrollPane {
         this.databaseStructures = new HashMap<>();
         this.levels = new HashMap<>();
         this.insertableLevels = new HashMap<>();
-
-        initLevels();
-        initElement();
-        initListeners();
+        this.moveButton = (ModelerAbstractAction.CayenneToolbarButton) 
actions.getMoveImportNodeAction().buildButton();
+        this.moveInvertButton = (ModelerAbstractAction.CayenneToolbarButton) 
actions.getMoveInvertNodeAction().buildButton();
+        initLayout();
+        initBindings();
     }
 
     public void updateTree(DataMap dataMap) {
@@ -102,7 +102,7 @@ public class DraggableTreePanel extends JScrollPane {
         }
     }
 
-    private void initListeners() {
+    private void initBindings() {
         sourceTree.addKeyListener(new SourceTreeKeyListener());
         sourceTree.setTransferHandler(new SourceTreeTransferHandler());
         sourceTree.addTreeSelectionListener(new SourceTreeSelectionListener());
@@ -123,15 +123,13 @@ public class DraggableTreePanel extends JScrollPane {
         return levels.get(selectedElement.getUserObject().getClass()) < 
SECOND_LEVEL;
     }
 
-    private void initElement() {
+    private void initLayout() {
+        initLevels();
         sourceTree.setDragEnabled(true);
         sourceTree.setCellRenderer(new ColorTreeRenderer());
         sourceTree.setDropMode(DropMode.INSERT);
-
-        moveButton = (ModelerAbstractAction.CayenneToolbarButton) 
actions.getMoveImportNodeAction().buildButton();
         moveButton.setShowingText(true);
         moveButton.setText(MOVE_BUTTON_LABEL);
-        moveInvertButton = (ModelerAbstractAction.CayenneToolbarButton) 
actions.getMoveInvertNodeAction().buildButton();
         moveInvertButton.setShowingText(true);
         moveInvertButton.setText(MOVE_INV_BUTTON_LABEL);
     }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/ReverseEngineeringConfigPanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/ReverseEngineeringConfigPanel.java
index 1f797ea50..8220d492d 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/ReverseEngineeringConfigPanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/ReverseEngineeringConfigPanel.java
@@ -23,6 +23,7 @@ import com.jgoodies.forms.builder.DefaultFormBuilder;
 import com.jgoodies.forms.layout.FormLayout;
 import org.apache.cayenne.dbsync.reverse.dbimport.ReverseEngineering;
 import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.modeler.toolkit.ProjectPanel;
 import org.apache.cayenne.modeler.toolkit.combobox.AutoCompletion;
 import org.apache.cayenne.modeler.toolkit.combobox.CMComboBox;
 import org.apache.cayenne.modeler.toolkit.text.CMUndoableTextField;
@@ -30,126 +31,95 @@ import org.apache.cayenne.modeler.project.ProjectSession;
 import org.apache.cayenne.modeler.util.NameGeneratorPreferences;
 
 import javax.swing.*;
+import java.awt.*;
 import java.util.Vector;
 
-public class ReverseEngineeringConfigPanel extends JPanel {
+public class ReverseEngineeringConfigPanel extends ProjectPanel {
 
     private static final String DATA_FIELDS_LAYOUT = "right:pref, 3dlu, 
fill:235dlu";
 
-    private JComboBox<String> strategyCombo;
-    private CMUndoableTextField meaningfulPk;
-    private CMUndoableTextField stripFromTableNames;
-    private JCheckBox skipRelationshipsLoading;
-    private JCheckBox skipPrimaryKeyLoading;
-    private JCheckBox forceDataMapCatalog;
-    private JCheckBox forceDataMapSchema;
-    private JCheckBox useJava7Types;
+    private final JComboBox<String> strategyCombo;
+    private final CMUndoableTextField meaningfulPk;
+    private final CMUndoableTextField stripFromTableNames;
+    private final JCheckBox skipRelationshipsLoading;
+    private final JCheckBox skipPrimaryKeyLoading;
+    private final JCheckBox forceDataMapCatalog;
+    private final JCheckBox forceDataMapSchema;
+    private final JCheckBox useJava7Types;
+    private final CMUndoableTextField tableTypes;
 
-    private CMUndoableTextField tableTypes;
-
-    private final ProjectSession session;
     private final DbImportView dbImportView;
 
-    ReverseEngineeringConfigPanel(ProjectSession session, DbImportView 
dbImportView) {
-        this.session = session;
-        this.dbImportView = dbImportView;
-        initFormElements();
-        initListeners();
-        buildView();
-    }
-
-    private void buildView() {
-        FormLayout panelLayout = new FormLayout(DATA_FIELDS_LAYOUT);
-        DefaultFormBuilder panelBuilder = new DefaultFormBuilder(panelLayout);
-        panelBuilder.setDefaultDialogBorder();
-
-        panelBuilder.append("Tables with Meaningful PK Pattern:", 
meaningfulPk);
-        panelBuilder.append("Strip from table names:", stripFromTableNames);
-        panelBuilder.append("Skip relationships loading:", 
skipRelationshipsLoading);
-        panelBuilder.append("Skip primary key loading:", 
skipPrimaryKeyLoading);
-        panelBuilder.append("Force datamap catalog:", forceDataMapCatalog);
-        panelBuilder.append("Force datamap schema:", forceDataMapSchema);
-        panelBuilder.append("Use java.util.Date type:", useJava7Types);
-        panelBuilder.append("Naming strategy:", strategyCombo);
-        panelBuilder.append("Table types:", tableTypes);
-
-        add(panelBuilder.getPanel());
-    }
-
-    void fillCheckboxes(ReverseEngineering reverseEngineering) {
-        
skipRelationshipsLoading.setSelected(reverseEngineering.getSkipRelationshipsLoading());
-        
skipPrimaryKeyLoading.setSelected(reverseEngineering.getSkipPrimaryKeyLoading());
-        
forceDataMapCatalog.setSelected(reverseEngineering.isForceDataMapCatalog());
-        
forceDataMapSchema.setSelected(reverseEngineering.isForceDataMapSchema());
-        useJava7Types.setSelected(reverseEngineering.isUseJava7Types());
-    }
-
-    void initializeTextFields(ReverseEngineering reverseEngineering) {
-        meaningfulPk.setText(reverseEngineering.getMeaningfulPkTables());
-        
stripFromTableNames.setText(reverseEngineering.getStripFromTableNames());
-    }
-
-    ReverseEngineering getReverseEngineeringBySelectedMap() {
-        DataMap dataMap = session.getSelectedDataMap();
-        return session.app().getMetaData().get(dataMap, 
ReverseEngineering.class);
-    }
+    public ReverseEngineeringConfigPanel(ProjectSession session, DbImportView 
dbImportView) {
+        super(session);
 
-    void initStrategy(ReverseEngineering reverseEngineering) {
-        Vector<String> arr = NameGeneratorPreferences
-                .getInstance()
-                .getLastUsedStrategies(session.app());
-        strategyCombo.setModel(new DefaultComboBoxModel<>(arr));
-        strategyCombo.setSelectedItem(reverseEngineering.getNamingStrategy());
+        this.dbImportView = dbImportView;
+        this.strategyCombo = new CMComboBox<>();
+        this.meaningfulPk = new 
CMUndoableTextField(session.app().getUndoManager());
+        this.stripFromTableNames = new 
CMUndoableTextField(session.app().getUndoManager());
+        this.tableTypes = new 
CMUndoableTextField(session.app().getUndoManager());
+        this.skipRelationshipsLoading = new JCheckBox();
+        this.skipPrimaryKeyLoading = new JCheckBox();
+        this.forceDataMapCatalog = new JCheckBox();
+        this.forceDataMapSchema = new JCheckBox();
+        this.useJava7Types = new JCheckBox();
+
+        initLayout();
+        initBindings();
     }
 
-    private void initFormElements() {
-        strategyCombo = new CMComboBox<>();
+    private void initLayout() {
         AutoCompletion.enable(strategyCombo, false, true, 
session::getSelectedDataMap);
         strategyCombo.setToolTipText("Naming strategy to use");
 
-        meaningfulPk = new CMUndoableTextField(session.app().getUndoManager());
         meaningfulPk.setToolTipText("<html>Regular expression to filter tables 
with meaningful primary keys.<br>" +
                 "Multiple expressions divided by comma can be used.<br>" +
                 "Example: <b>^table1|^table2|^prefix.*|table_name</b></html>");
-        meaningfulPk.addCommitListener(text -> {
-            if (!dbImportView.isInitFromModel()) {
-                
getReverseEngineeringBySelectedMap().setMeaningfulPkTables(text);
-                session.setDirty(true);
-            }
-        });
-
-        stripFromTableNames = new 
CMUndoableTextField(session.app().getUndoManager());
         stripFromTableNames.setToolTipText("<html>Regex that matches the part 
of the table name that needs to be stripped off " +
                 "when generating ObjEntity name</html>");
-        stripFromTableNames.addCommitListener(text -> {
-            if (!dbImportView.isInitFromModel()) {
-                
getReverseEngineeringBySelectedMap().setStripFromTableNames(text);
-                session.setDirty(true);
-            }
-        });
-
-        tableTypes = new CMUndoableTextField(session.app().getUndoManager());
         tableTypes.setToolTipText("<html>Default types to import is TABLE and 
VIEW.");
-        tableTypes.addCommitListener(this::applyTableTypes);
 
-        skipRelationshipsLoading = new JCheckBox();
         skipRelationshipsLoading.setToolTipText("<html>Whether to load 
relationships.</html>");
-        skipPrimaryKeyLoading = new JCheckBox();
         skipPrimaryKeyLoading.setToolTipText("<html>Whether to load primary 
keys.</html>");
-        forceDataMapCatalog = new JCheckBox();
         forceDataMapCatalog.setToolTipText("<html>Automatically tagging each 
DbEntity with the actual DB catalog/schema" +
                 "(default behavior) may sometimes be undesirable.<br>  If this 
is the case then setting <b>forceDataMapCatalog</b> " +
                 "to <b>true</b> will set DbEntity catalog to one in the 
DataMap.</html>");
-        forceDataMapSchema = new JCheckBox();
         forceDataMapSchema.setToolTipText("<html>Automatically tagging each 
DbEntity with the actual DB catalog/schema " +
                 "(default behavior) may sometimes be undesirable.<br> If this 
is the case then setting <b>forceDataMapSchema</b> " +
                 "to <b>true</b> will set DbEntity schema to one in the 
DataMap.</html>");
-        useJava7Types = new JCheckBox();
         useJava7Types.setToolTipText("<html>Use <b>java.util.Date</b> for all 
columns with <i>DATE/TIME/TIMESTAMP</i> types.<br>" +
                 "By default <b>java.time.*</b> types will be used.</html>");
+
+        setLayout(new BorderLayout());
+        FormLayout formLayout = new FormLayout(DATA_FIELDS_LAYOUT, "");
+        DefaultFormBuilder builder = new DefaultFormBuilder(formLayout);
+        builder.setDefaultDialogBorder();
+        builder.append("Naming Strategy:", strategyCombo);
+        builder.append("Meaningful PK:", meaningfulPk);
+        builder.append("Strip From Table Names:", stripFromTableNames);
+        builder.append("Table Types:", tableTypes);
+        builder.append("Skip Relationships:", skipRelationshipsLoading);
+        builder.append("Skip Primary Keys:", skipPrimaryKeyLoading);
+        builder.append("Force DataMap Catalog:", forceDataMapCatalog);
+        builder.append("Force DataMap Schema:", forceDataMapSchema);
+        builder.append("Use Java 7 Types:", useJava7Types);
+        add(builder.getPanel(), BorderLayout.CENTER);
     }
 
-    private void initListeners() {
+    private void initBindings() {
+        meaningfulPk.addCommitListener(text -> {
+            if (!dbImportView.isInitFromModel()) {
+                
getReverseEngineeringBySelectedMap().setMeaningfulPkTables(text);
+                session.setDirty(true);
+            }
+        });
+        stripFromTableNames.addCommitListener(text -> {
+            if (!dbImportView.isInitFromModel()) {
+                
getReverseEngineeringBySelectedMap().setStripFromTableNames(text);
+                session.setDirty(true);
+            }
+        });
+        tableTypes.addCommitListener(this::applyTableTypes);
         skipRelationshipsLoading.addActionListener(e -> {
             if (!dbImportView.isInitFromModel()) {
                 
getReverseEngineeringBySelectedMap().setSkipRelationshipsLoading(skipRelationshipsLoading.isSelected());
@@ -181,7 +151,7 @@ public class ReverseEngineeringConfigPanel extends JPanel {
             }
         });
         strategyCombo.addActionListener(e -> {
-            String strategy = (String) 
ReverseEngineeringConfigPanel.this.getStrategyCombo().getSelectedItem();
+            String strategy = (String) strategyCombo.getSelectedItem();
             checkStrategy(strategy);
             if (!dbImportView.isInitFromModel()) {
                 
getReverseEngineeringBySelectedMap().setNamingStrategy(strategy);
@@ -191,6 +161,34 @@ public class ReverseEngineeringConfigPanel extends JPanel {
         });
     }
 
+    void fillCheckboxes(ReverseEngineering reverseEngineering) {
+        
skipRelationshipsLoading.setSelected(reverseEngineering.getSkipRelationshipsLoading());
+        
skipPrimaryKeyLoading.setSelected(reverseEngineering.getSkipPrimaryKeyLoading());
+        
forceDataMapCatalog.setSelected(reverseEngineering.isForceDataMapCatalog());
+        
forceDataMapSchema.setSelected(reverseEngineering.isForceDataMapSchema());
+        useJava7Types.setSelected(reverseEngineering.isUseJava7Types());
+    }
+
+    void initializeTextFields(ReverseEngineering reverseEngineering) {
+        meaningfulPk.setText(reverseEngineering.getMeaningfulPkTables());
+        
stripFromTableNames.setText(reverseEngineering.getStripFromTableNames());
+    }
+
+    ReverseEngineering getReverseEngineeringBySelectedMap() {
+        DataMap dataMap = session.getSelectedDataMap();
+        return session.app().getMetaData().get(dataMap, 
ReverseEngineering.class);
+    }
+
+    void initStrategy(ReverseEngineering reverseEngineering) {
+        Vector<String> arr = NameGeneratorPreferences
+                .getInstance()
+                .getLastUsedStrategies(session.app());
+        strategyCombo.setModel(new DefaultComboBoxModel<>(arr));
+        strategyCombo.setSelectedItem(reverseEngineering.getNamingStrategy());
+    }
+
+
+
     private void checkStrategy(String strategy) {
         try {
             Thread.currentThread().getContextClassLoader().loadClass(strategy);
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/ReverseEngineeringTreePanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/ReverseEngineeringTreePanel.java
index c3fc2ef59..50a10ce9c 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/ReverseEngineeringTreePanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/ReverseEngineeringTreePanel.java
@@ -51,7 +51,7 @@ class ReverseEngineeringTreePanel extends JScrollPane {
     private final ProjectSession session;
     private final DbImportActions actions;
     private TreeToolbarPanel treeToolbar;
-    private Map<Class<?>, DefaultPopUpMenu> popups;
+    private final Map<Class<?>, DefaultPopUpMenu> popups;
 
     ReverseEngineeringTreePanel(ProjectSession session, DbImportTree 
reverseEngineeringTree,
                                 DbImportTree dbSchemaTree, DbImportActions 
actions) {
@@ -60,22 +60,21 @@ class ReverseEngineeringTreePanel extends JScrollPane {
         this.reverseEngineeringTree = reverseEngineeringTree;
         this.dbSchemaTree = dbSchemaTree;
         this.actions = actions;
-        reverseEngineeringTree.setEditable(true);
-        reverseEngineeringTree.setCellRenderer(new DbImportTreeCellRenderer());
-        DbImportTreeCellEditor editor = new 
DbImportTreeCellEditor(reverseEngineeringTree,
-                (DefaultTreeCellRenderer) 
reverseEngineeringTree.getCellRenderer(), actions);
-        reverseEngineeringTree.setCellEditor(editor);
-        initListeners();
-        initPopupMenus();
-        changeIcons();
+        this.popups = new HashMap<>();
+        initLayout();
+        initBindings();
     }
 
     void updateTree() {
         
reverseEngineeringTree.translateReverseEngineeringToTree(getReverseEngineeringBySelectedMap(),
 false);
     }
 
-    private void initPopupMenus() {
-        popups = new HashMap<>();
+    private void initLayout() {
+        reverseEngineeringTree.setEditable(true);
+        reverseEngineeringTree.setCellRenderer(new DbImportTreeCellRenderer());
+        DbImportTreeCellEditor editor = new 
DbImportTreeCellEditor(reverseEngineeringTree,
+                (DefaultTreeCellRenderer) 
reverseEngineeringTree.getCellRenderer(), actions);
+        reverseEngineeringTree.setCellEditor(editor);
         popups.put(Catalog.class, new CatalogPopUpMenu(actions));
         popups.put(Schema.class, new SchemaPopUpMenu(actions));
         popups.put(ReverseEngineering.class, new RootPopUpMenu(actions));
@@ -86,9 +85,10 @@ class ReverseEngineeringTreePanel extends JScrollPane {
         popups.put(ExcludeColumn.class, new DefaultPopUpMenu(actions));
         popups.put(IncludeProcedure.class, new DefaultPopUpMenu(actions));
         popups.put(ExcludeProcedure.class, new DefaultPopUpMenu(actions));
+        changeIcons();
     }
 
-    private void initListeners() {
+    private void initBindings() {
         reverseEngineeringTree.addTreeSelectionListener(e -> 
treeToolbar.lockButtons());
         reverseEngineeringTree.addMouseListener(new MouseAdapter() {
             @Override
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/main/DataMapMainView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/main/DataMapMainView.java
index 92be566ca..3ee92493e 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/main/DataMapMainView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/main/DataMapMainView.java
@@ -64,45 +64,37 @@ public class DataMapMainView extends ProjectPanel {
     private final CMUndoableTextField defaultPackage;
     private final CMUndoableTextField defaultSuperclass;
     private final JCheckBox quoteSQLIdentifiers;
-
     private final CMUndoableTextField comment;
+    private final JButton updateDefaultCatalog;
+    private final JButton updateDefaultSchema;
+    private final JButton updateDefaultPackage;
+    private final JButton updateDefaultSuperclass;
+    private final JButton updateDefaultLockType;
 
     public DataMapMainView(ProjectSession session) {
         super(session);
-
-        // create widgets
         name = new CMUndoableTextField(app().getUndoManager());
-        name.addCommitListener(this::setDataMapName);
-
         nodeSelectorLabel = new JLabel("DataNode:");
         nodeSelector = new CMUndoableComboBox<>(app().getUndoManager());
-        nodeSelector.setRenderer(Renderers.listRendererWithIcons());
-
-        JButton updateDefaultCatalog = new JButton("Update...");
         defaultCatalog = new CMUndoableTextField(app().getUndoManager());
-        defaultCatalog.addCommitListener(this::setDefaultCatalog);
-
-        JButton updateDefaultSchema = new JButton("Update...");
         defaultSchema = new CMUndoableTextField(app().getUndoManager());
-        defaultSchema.addCommitListener(this::setDefaultSchema);
-
         quoteSQLIdentifiers = new CMCheckBox(app().getUndoManager());
-
         comment = new CMUndoableTextField(app().getUndoManager());
-        comment.addCommitListener(this::updateComment);
-
-        JButton updateDefaultPackage = new JButton("Update...");
         defaultPackage = new CMUndoableTextField(app().getUndoManager());
-        defaultPackage.addCommitListener(this::setDefaultPackage);
-
-        JButton updateDefaultSuperclass = new JButton("Update...");
         defaultSuperclass = new CMUndoableTextField(app().getUndoManager());
-        defaultSuperclass.addCommitListener(this::setDefaultSuperclass);
-
-        JButton updateDefaultLockType = new JButton("Update...");
         defaultLockType = new CMCheckBox(app().getUndoManager());
+        updateDefaultCatalog = new JButton("Update...");
+        updateDefaultSchema = new JButton("Update...");
+        updateDefaultPackage = new JButton("Update...");
+        updateDefaultSuperclass = new JButton("Update...");
+        updateDefaultLockType = new JButton("Update...");
+        initLayout();
+        initBindings();
+    }
+
+    private void initLayout() {
+        nodeSelector.setRenderer(Renderers.listRendererWithIcons());
 
-        // assemble
         FormLayout layout = new FormLayout(
                 "right:70dlu, 3dlu, fill:180dlu, 3dlu, fill:120",
                 "");
@@ -117,30 +109,25 @@ public class DataMapMainView extends ProjectPanel {
         builder.appendSeparator("Entity Defaults");
         builder.append("DB Catalog:", defaultCatalog, updateDefaultCatalog);
         builder.append("DB Schema:", defaultSchema, updateDefaultSchema);
-        builder.append(
-                "Java Package:",
-                defaultPackage,
-                updateDefaultPackage);
-        builder.append(
-                "Custom Superclass:",
-                defaultSuperclass,
-                updateDefaultSuperclass);
+        builder.append("Java Package:", defaultPackage, updateDefaultPackage);
+        builder.append("Custom Superclass:", defaultSuperclass, 
updateDefaultSuperclass);
         builder.append("Optimistic Locking:", defaultLockType, 
updateDefaultLockType);
 
         builder.appendSeparator("Linked DataNode");
         builder.append(nodeSelectorLabel);
         builder.append(nodeSelector, 2);
 
-        this.setLayout(new BorderLayout());
+        setLayout(new BorderLayout());
         add(builder.getPanel(), BorderLayout.CENTER);
+    }
 
-        session().addDataMapDisplayListener(e -> {
-            DataMap map = e.getDataMap();
-            if (map != null) {
-                initFromModel(map);
-            }
-        });
-
+    private void initBindings() {
+        name.addCommitListener(this::setDataMapName);
+        defaultCatalog.addCommitListener(this::setDefaultCatalog);
+        defaultSchema.addCommitListener(this::setDefaultSchema);
+        comment.addCommitListener(this::updateComment);
+        defaultPackage.addCommitListener(this::setDefaultPackage);
+        defaultSuperclass.addCommitListener(this::setDefaultSuperclass);
         nodeSelector.addActionListener(e -> setDataNode());
         quoteSQLIdentifiers.addItemListener(e -> 
setQuoteSQLIdentifiers(quoteSQLIdentifiers.isSelected()));
         defaultLockType.addItemListener(e -> 
setDefaultLockType(defaultLockType.isSelected()
@@ -151,6 +138,12 @@ public class DataMapMainView extends ProjectPanel {
         updateDefaultPackage.addActionListener(e -> updateDefaultPackage());
         updateDefaultSuperclass.addActionListener(e -> 
updateDefaultSuperclass());
         updateDefaultLockType.addActionListener(e -> updateDefaultLockType());
+        session().addDataMapDisplayListener(e -> {
+            DataMap map = e.getDataMap();
+            if (map != null) {
+                initFromModel(map);
+            }
+        });
     }
 
     /**
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datanode/DataNodeEditorPanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datanode/DataNodeEditorPanel.java
index c57d0d4e6..4c5201998 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datanode/DataNodeEditorPanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datanode/DataNodeEditorPanel.java
@@ -28,27 +28,20 @@ import 
org.apache.cayenne.access.dbsync.ThrowOnPartialSchemaStrategy;
 import org.apache.cayenne.configuration.DataChannelDescriptor;
 import org.apache.cayenne.configuration.DataNodeDescriptor;
 import org.apache.cayenne.configuration.runtime.XMLPoolingDataSourceFactory;
-import org.apache.cayenne.modeler.Application;
 import org.apache.cayenne.modeler.dbconnector.DBConnector;
 import org.apache.cayenne.modeler.event.model.DataNodeEvent;
 import org.apache.cayenne.modeler.pref.DataNodePrefs;
+import org.apache.cayenne.modeler.project.ProjectSession;
+import org.apache.cayenne.modeler.toolkit.ProjectPanel;
 import org.apache.cayenne.modeler.toolkit.combobox.CMUndoableComboBox;
 import org.apache.cayenne.modeler.toolkit.text.CMUndoableTextField;
-import org.apache.cayenne.modeler.toolkit.AppPanel;
 import org.apache.cayenne.modeler.ui.preferences.PreferenceDialog;
-import org.apache.cayenne.modeler.project.ProjectSession;
 import 
org.apache.cayenne.modeler.ui.project.editor.datanode.custom.CustomDataSourcePanel;
 import 
org.apache.cayenne.modeler.ui.project.editor.datanode.jdbc.JDBCDataSourcePanel;
 import org.apache.cayenne.validation.ValidationException;
 
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import java.awt.BorderLayout;
-import java.awt.CardLayout;
-import java.awt.Font;
+import javax.swing.*;
+import java.awt.*;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
 import java.util.Collection;
@@ -61,7 +54,7 @@ import java.util.Map;
  * delegates to a sub-editor selected by the chosen DataSource factory 
(Cayenne JDBC
  * pooling vs custom).
  */
-public class DataNodeEditorPanel extends AppPanel {
+public class DataNodeEditorPanel extends ProjectPanel {
 
     static final String NO_LOCAL_DATA_SOURCE = "Select DataSource for Local 
Work...";
     private static final String XML_POOLING_DATA_SOURCE_FACTORY = 
XMLPoolingDataSourceFactory.class.getName();
@@ -78,7 +71,6 @@ public class DataNodeEditorPanel extends AppPanel {
             ThrowOnPartialOrCreateSchemaStrategy.class.getName()
     };
 
-    private final ProjectSession session;
     private final Runnable nodeChangeProcessor;
     private final Map<String, DataSourcePanel> datasourceEditors = new 
HashMap<>();
     private final CustomDataSourcePanel defaultSubeditor;
@@ -95,19 +87,19 @@ public class DataNodeEditorPanel extends AppPanel {
     private DataNodeDescriptor node;
     private boolean refreshing;
 
-    public DataNodeEditorPanel(Application app, ProjectSession session) {
-        super(app);
-        this.session = session;
+    public DataNodeEditorPanel(ProjectSession session) {
+        super(session);
+
         this.nodeChangeProcessor = () -> 
session.fireDataNodeEvent(DataNodeEvent.ofChange(this, node));
-        this.defaultSubeditor = new CustomDataSourcePanel(app, 
nodeChangeProcessor);
+        this.defaultSubeditor = new CustomDataSourcePanel(app(), 
nodeChangeProcessor);
 
-        this.dataNodeName = new CMUndoableTextField(app.getUndoManager());
-        this.factories = new CMUndoableComboBox<>(app.getUndoManager());
-        this.localDataSources = new CMUndoableComboBox<>(app.getUndoManager());
-        this.schemaUpdateStrategy = new 
CMUndoableComboBox<>(app.getUndoManager());
+        this.dataNodeName = new CMUndoableTextField(app().getUndoManager());
+        this.factories = new CMUndoableComboBox<>(app().getUndoManager());
+        this.localDataSources = new 
CMUndoableComboBox<>(app().getUndoManager());
+        this.schemaUpdateStrategy = new 
CMUndoableComboBox<>(app().getUndoManager());
         this.dataSourceDetailLayout = new CardLayout();
         this.dataSourceDetail = new JPanel(dataSourceDetailLayout);
-        this.customAdapter = new CMUndoableTextField(app.getUndoManager());
+        this.customAdapter = new CMUndoableTextField(app().getUndoManager());
         this.configLocalDataSources = new JButton("...");
         this.configLocalDataSources.setToolTipText("configure local 
DataSource");
 
@@ -148,12 +140,12 @@ public class DataNodeEditorPanel extends AppPanel {
     }
 
     private void initBindings() {
-        session.addDataNodeDisplayListener(e -> refreshView(e.getDataNode()));
+        session().addDataNodeDisplayListener(e -> 
refreshView(e.getDataNode()));
 
         addComponentListener(new ComponentAdapter() {
             @Override
             public void componentShown(ComponentEvent e) {
-                refreshView(node != null ? node : 
session.getSelectedDataNode());
+                refreshView(node != null ? node : 
session().getSelectedDataNode());
             }
         });
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/DbEntityView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/DbEntityView.java
index b77c403e0..f831f462e 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/DbEntityView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/DbEntityView.java
@@ -47,19 +47,22 @@ public class DbEntityView extends ProjectTabbedPane {
 
     public DbEntityView(ProjectSession session) {
         super(session);
+        this.entityPanel = new JScrollPane(new DbEntityMainView(session));
+        this.attributeRelationshipTab = new DbEntityPropertiesView(session);
+        initLayout();
+        initBindings();
+    }
 
+    private void initLayout() {
         setTabPlacement(JTabbedPane.TOP);
-
-        this.entityPanel = new JScrollPane(new DbEntityMainView(session));
         addTab("Entity", entityPanel);
-
-        this.attributeRelationshipTab = new DbEntityPropertiesView(session);
         addTab("Properties", attributeRelationshipTab);
+    }
 
-        session.addDbEntityDisplayListener(this::currentDbEntityChanged);
-        session.addDbAttributeDisplayListener(this::currentDbAttributeChanged);
-        
session.addDbRelationshipDisplayListener(this::currentDbRelationshipChanged);
-
+    private void initBindings() {
+        session().addDbEntityDisplayListener(this::currentDbEntityChanged);
+        
session().addDbAttributeDisplayListener(this::currentDbAttributeChanged);
+        
session().addDbRelationshipDisplayListener(this::currentDbRelationshipChanged);
         addChangeListener(this::stateChanged);
     }
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/main/DbEntityMainView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/main/DbEntityMainView.java
index 650df508e..21ea6e64b 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/main/DbEntityMainView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/main/DbEntityMainView.java
@@ -78,84 +78,72 @@ public class DbEntityMainView extends ProjectPanel 
implements ExistingSelectionP
 
     public DbEntityMainView(ProjectSession session) {
         super(session);
-
         toolBar = new JToolBar();
+        name = new CMUndoableTextField(app().getUndoManager());
+        catalogLabel = new JLabel("Catalog:");
+        catalog = new CMUndoableTextField(app().getUndoManager());
+        schemaLabel = new JLabel("Schema:");
+        schema = new CMUndoableTextField(app().getUndoManager());
+        qualifier = new CMUndoableTextField(app().getUndoManager());
+        comment = new CMUndoableTextField(app().getUndoManager());
+        pkGeneratorType = new JComboBox<>();
+        pkGeneratorDetailLayout = new CardLayout();
+        pkGeneratorDetail = new JPanel(pkGeneratorDetailLayout);
+        initLayout();
+        initBindings();
+    }
+
+    private void initLayout() {
         toolBar.setBorder(BorderFactory.createEmptyBorder());
         toolBar.setFloatable(false);
         GlobalActions globalActions = app().getActionManager();
-
         
toolBar.add(globalActions.getAction(CreateAttributeAction.class).buildButton(1));
         
toolBar.add(globalActions.getAction(CreateRelationshipAction.class).buildButton(3));
         toolBar.addSeparator();
-
         
toolBar.add(globalActions.getAction(CreateObjEntityFromDbAction.class).buildButton(1));
         
toolBar.add(globalActions.getAction(DbEntitySyncAction.class).buildButton(2));
         
toolBar.add(globalActions.getAction(DbEntityCounterpartAction.class).buildButton(3));
         toolBar.addSeparator();
-
         
toolBar.add(globalActions.getAction(ShowGraphEntityAction.class).buildButton());
 
-        // create widgets
-        name = new CMUndoableTextField(app().getUndoManager());
-        name.addCommitListener(this::setEntityName);
-
-        catalogLabel = new JLabel("Catalog:");
-        catalog = new CMUndoableTextField(app().getUndoManager());
-        catalog.addCommitListener(this::setCatalog);
-
-        schemaLabel = new JLabel("Schema:");
-        schema = new CMUndoableTextField(app().getUndoManager());
-        schema.addCommitListener(this::setSchema);
-
-        qualifier = new CMUndoableTextField(app().getUndoManager());
-        qualifier.addCommitListener(this::setQualifier);
-
-        comment = new CMUndoableTextField(app().getUndoManager());
-        comment.addCommitListener(this::setComment);
-
-        pkGeneratorType = new JComboBox<>();
         pkGeneratorType.setEditable(false);
         pkGeneratorType.setModel(new 
DefaultComboBoxModel<>(PK_GENERATOR_TYPES));
+        pkGeneratorDetail.add(new PKDefaultGeneratorPanel(session()), 
PK_DEFAULT_GENERATOR);
+        pkGeneratorDetail.add(new PKDBGeneratorPanel(session()), 
PK_DB_GENERATOR);
+        pkGeneratorDetail.add(new PKCustomSequenceGeneratorPanel(session()), 
PK_CUSTOM_SEQUENCE_GENERATOR);
 
-        pkGeneratorDetailLayout = new CardLayout();
-        pkGeneratorDetail = new JPanel(pkGeneratorDetailLayout);
-        pkGeneratorDetail.add(new PKDefaultGeneratorPanel(session), 
PK_DEFAULT_GENERATOR);
-        pkGeneratorDetail.add(new PKDBGeneratorPanel(session), 
PK_DB_GENERATOR);
-        pkGeneratorDetail.add(new PKCustomSequenceGeneratorPanel(session), 
PK_CUSTOM_SEQUENCE_GENERATOR);
-
-        // assemble
         FormLayout layout = new FormLayout("right:pref, 3dlu, fill:200dlu", 
"");
         DefaultFormBuilder builder = new DefaultFormBuilder(layout);
         builder.setDefaultDialogBorder();
-
         builder.appendSeparator("DbEntity Configuration");
         builder.append("DbEntity Name:", name);
         builder.append(catalogLabel, catalog);
         builder.append(schemaLabel, schema);
         builder.append("Qualifier:", qualifier);
         builder.append("Comment:", comment);
-
         builder.appendSeparator("Primary Key");
         builder.append("PK Generation Strategy:", pkGeneratorType);
 
-        JPanel mainPanel = new JPanel();
-        mainPanel.setLayout(new BorderLayout());
-
+        JPanel mainPanel = new JPanel(new BorderLayout());
         mainPanel.add(builder.getPanel(), BorderLayout.NORTH);
         mainPanel.add(pkGeneratorDetail, BorderLayout.CENTER);
 
         setLayout(new BorderLayout());
         add(toolBar, BorderLayout.NORTH);
         add(mainPanel, BorderLayout.CENTER);
+    }
 
+    private void initBindings() {
+        name.addCommitListener(this::setEntityName);
+        catalog.addCommitListener(this::setCatalog);
+        schema.addCommitListener(this::setSchema);
+        qualifier.addCommitListener(this::setQualifier);
+        comment.addCommitListener(this::setComment);
         session().addDbEntityDisplayListener(this);
-
         pkGeneratorType.addItemListener(e -> {
             pkGeneratorDetailLayout.show(pkGeneratorDetail, (String) 
pkGeneratorType.getSelectedItem());
-
             for (int i = 0; i < pkGeneratorDetail.getComponentCount(); i++) {
                 if (pkGeneratorDetail.getComponent(i).isVisible()) {
-
                     DbEntity entity = session().getSelectedDbEntity();
                     PKGeneratorPanel panel = (PKGeneratorPanel) 
pkGeneratorDetail.getComponent(i);
                     panel.onInit(entity);
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/main/PKDBGeneratorPanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/main/PKDBGeneratorPanel.java
index d9e29a857..e07d6a4db 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/main/PKDBGeneratorPanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/main/PKDBGeneratorPanel.java
@@ -36,16 +36,15 @@ import java.util.Collection;
 
 public class PKDBGeneratorPanel extends PKGeneratorPanel {
 
-    private JComboBox<Object> attributes;
+    private final JComboBox<Object> attributes;
 
     public PKDBGeneratorPanel(ProjectSession session) {
         super(session);
-        initView();
+        this.attributes = new JComboBox<>();
+        initLayout();
     }
 
-    private void initView() {
-
-        attributes = new JComboBox<>();
+    private void initLayout() {
         attributes.setEditable(false);
         attributes.setRenderer(new AttributeRenderer());
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbAttributePanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbAttributePanel.java
index 6ac9337b2..441f421f8 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbAttributePanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbAttributePanel.java
@@ -63,22 +63,22 @@ public class DbAttributePanel extends JPanel implements 
DbEntityDisplayListener,
     public DbAttributePanel(ProjectSession session, DbEntityPropertiesView 
parentPanel) {
         this.session = session;
         this.parentPanel = parentPanel;
+        this.table = new CMTable();
+        initLayout();
+        initBindings();
+    }
 
-        this.setLayout(new BorderLayout());
+    private void initLayout() {
+        setLayout(new BorderLayout());
 
         GlobalActions globalActions = session.app().getActionManager();
 
-        // Create table with two columns and no rows.
-        table = new CMTable();
         table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
         table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
         table.setDefaultRenderer(String.class, new BoardTableCellRenderer());
 
-        // TODO: There is no edit panel for DbAttributes, so for now no edit 
contextual menu and the edit button is disabled
-
         JPopupMenu popup = new JPopupMenu();
         
popup.add(globalActions.getAction(RemoveAttributeRelationshipAction.class).buildMenu());
-
         popup.addSeparator();
         
popup.add(globalActions.getAction(CutAttributeRelationshipAction.class).buildMenu());
         
popup.add(globalActions.getAction(CopyAttributeRelationshipAction.class).buildMenu());
@@ -86,13 +86,15 @@ public class DbAttributePanel extends JPanel implements 
DbEntityDisplayListener,
 
         TablePopupHandler.install(table, popup);
         add(new CMTablePanel(table), BorderLayout.CENTER);
+    }
 
+    private void initBindings() {
         session.addDbEntityDisplayListener(this);
         session.addDbAttributeListener(this);
 
         table.getSelectionModel().addListSelectionListener(this::valueChanged);
 
-        globalActions.setupCutCopyPaste(
+        session.app().getActionManager().setupCutCopyPaste(
                 table,
                 CutAttributeRelationshipAction.class,
                 CopyAttributeRelationshipAction.class);
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbEntityPropertiesView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbEntityPropertiesView.java
index db4fdfe51..7e6ecc431 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbEntityPropertiesView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbEntityPropertiesView.java
@@ -57,22 +57,23 @@ public class DbEntityPropertiesView extends ProjectPanel 
implements DbEntityDisp
 
     public DbEntityPropertiesView(ProjectSession session) {
         super(session);
+        this.editButton = new ModelerAbstractAction.CayenneToolbarButton(null, 
0);
+        this.attributePanel = new DbAttributePanel(session, this);
+        this.relationshipPanel = new DbRelationshipPanel(session, this);
+        this.splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, 
attributePanel, relationshipPanel);
+        this.toolBar = new JToolBar();
+        initLayout();
+        initBindings();
+    }
 
-        this.setLayout(new BorderLayout());
-
-        editButton = new ModelerAbstractAction.CayenneToolbarButton(null, 0);
-
-        attributePanel = new DbAttributePanel(session, this);
-        relationshipPanel = new DbRelationshipPanel(session, this);
+    private void initLayout() {
+        setLayout(new BorderLayout());
 
-        splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, attributePanel, 
relationshipPanel);
         splitPane.setOneTouchExpandable(true);
         splitPane.setResizeWeight(0.5);
-
         CMSplitPanePrefs.of(app().getPreferencesRepository(), 
"dbEntity/splitPane").bind(splitPane, -1);
-
         add(splitPane);
-        toolBar = new JToolBar();
+
         toolBar.setFloatable(false);
         GlobalActions globalActions = app().getActionManager();
 
@@ -99,6 +100,9 @@ public class DbEntityPropertiesView extends ProjectPanel 
implements DbEntityDisp
         toolBar.add(globalActions.getAction(PasteAction.class).buildButton(3));
 
         add(toolBar, BorderLayout.NORTH);
+    }
+
+    private void initBindings() {
         session().addDbEntityDisplayListener(this);
     }
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbRelationshipPanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbRelationshipPanel.java
index 18bd24286..9a187d687 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbRelationshipPanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbRelationshipPanel.java
@@ -71,23 +71,25 @@ public class DbRelationshipPanel extends JPanel implements 
DbEntityDisplayListen
     public DbRelationshipPanel(ProjectSession session, DbEntityPropertiesView 
parentPanel) {
         this.session = session;
         this.parentPanel = parentPanel;
+        this.table = new CMTable();
+        this.editMenu = new JMenuItem("Edit Relationship", 
IconFactory.buildIcon("icon-edit.png"));
+        initLayout();
+        initBindings();
+    }
 
-        this.setLayout(new BorderLayout());
+    private void initLayout() {
+        setLayout(new BorderLayout());
 
         GlobalActions globalActions = session.app().getActionManager();
 
-        table = new CMTable();
         table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
         table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
         table.setDefaultRenderer(DbEntity.class, 
Renderers.entityTableRendererWithIcons(session));
         table.setDefaultRenderer(String.class, new BoardTableCellRenderer());
 
-        editMenu = new JMenuItem("Edit Relationship", 
IconFactory.buildIcon("icon-edit.png"));
-
         JPopupMenu popup = new JPopupMenu();
         popup.add(editMenu);
         
popup.add(globalActions.getAction(RemoveAttributeRelationshipAction.class).buildMenu());
-
         popup.addSeparator();
         
popup.add(globalActions.getAction(CutAttributeRelationshipAction.class).buildMenu());
         
popup.add(globalActions.getAction(CopyAttributeRelationshipAction.class).buildMenu());
@@ -95,10 +97,12 @@ public class DbRelationshipPanel extends JPanel implements 
DbEntityDisplayListen
 
         TablePopupHandler.install(table, popup);
         add(new CMTablePanel(table), BorderLayout.CENTER);
+    }
 
-        this.session.addDbEntityDisplayListener(this);
-        this.session.addDbEntityListener(this);
-        this.session.addDbRelationshipListener(this);
+    private void initBindings() {
+        session.addDbEntityDisplayListener(this);
+        session.addDbEntityListener(this);
+        session.addDbRelationshipListener(this);
 
         editMenu.addActionListener(this::edit);
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/embeddable/EmbeddableView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/embeddable/EmbeddableView.java
index 1bed0c704..1ad6462df 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/embeddable/EmbeddableView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/embeddable/EmbeddableView.java
@@ -43,17 +43,21 @@ public class EmbeddableView extends ProjectTabbedPane {
 
     public EmbeddableView(ProjectSession session) {
         super(session);
+        embeddablePanel = new JScrollPane(new EmbeddableMainView(session));
+        attributesPanel = new EmbeddableAttributesView(session);
+        initLayout();
+        initBindings();
+    }
 
+    private void initLayout() {
         setTabPlacement(JTabbedPane.TOP);
-
-        embeddablePanel = new JScrollPane(new EmbeddableMainView(session));
         addTab("Embeddable", embeddablePanel);
-
-        attributesPanel = new EmbeddableAttributesView(session);
         addTab("Attributes", attributesPanel);
+    }
 
-        
session.addEmbeddableAttributeDisplayListener(this::currentEmbeddableAttributeChanged);
-        session.addEmbeddableDisplayListener(this::currentEmbeddableChanged);
+    private void initBindings() {
+        
session().addEmbeddableAttributeDisplayListener(this::currentEmbeddableAttributeChanged);
+        session().addEmbeddableDisplayListener(this::currentEmbeddableChanged);
         addChangeListener(this::stateChanged);
     }
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/embeddable/attributes/EmbeddableAttributesView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/embeddable/attributes/EmbeddableAttributesView.java
index 89186fb79..ad6c7bec8 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/embeddable/attributes/EmbeddableAttributesView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/embeddable/attributes/EmbeddableAttributesView.java
@@ -65,16 +65,17 @@ public class EmbeddableAttributesView extends ProjectPanel 
implements
         EmbeddableAttributeListener, EmbeddableDisplayListener, 
EmbeddableListener,
         ExistingSelectionProcessor {
 
-    private CMTable table;
+    private final CMTable table;
 
     public EmbeddableAttributesView(ProjectSession session) {
         super(session);
-        init();
-        initController();
+        this.table = new CMTable();
+        initLayout();
+        initBindings();
     }
 
-    private void init() {
-        this.setLayout(new BorderLayout());
+    private void initLayout() {
+        setLayout(new BorderLayout());
 
         JToolBar toolBar = new JToolBar();
         toolBar.setFloatable(false);
@@ -92,16 +93,12 @@ public class EmbeddableAttributesView extends ProjectPanel 
implements
 
         add(toolBar, BorderLayout.NORTH);
 
-        table = new CMTable();
         table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
         table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
 
-        // Create and install a popup
         JPopupMenu popup = new JPopupMenu();
         
popup.add(globalActions.getAction(RemoveAttributeAction.class).buildMenu());
-
         popup.addSeparator();
-
         
popup.add(globalActions.getAction(CutAttributeAction.class).buildMenu());
         
popup.add(globalActions.getAction(CopyAttributeAction.class).buildMenu());
         popup.add(globalActions.getAction(PasteAction.class).buildMenu());
@@ -110,7 +107,7 @@ public class EmbeddableAttributesView extends ProjectPanel 
implements
         add(new CMTablePanel(table), BorderLayout.CENTER);
     }
 
-    private void initController() {
+    private void initBindings() {
         session().addEmbeddableAttributeListener(this);
         session().addEmbeddableDisplayListener(this);
         session().addEmbeddableListener(this);
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/ObjEntityView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/ObjEntityView.java
index ad484aa52..9740ed6f0 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/ObjEntityView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/ObjEntityView.java
@@ -50,26 +50,25 @@ public class ObjEntityView extends ProjectTabbedPane {
 
     public ObjEntityView(ProjectSession session) {
         super(session);
+        // note that those panels that have no internal scrollable tables must 
be wrapped in a scroll pane
+        entityPanel = new JScrollPane(new ObjEntityMainView(session));
+        attributeRelationshipTab = new ObjEntityPropertiesView(session);
+        callbacksPanel = new ObjEntityCallbacksView(session);
+        initLayout();
+        initBindings();
+    }
 
+    private void initLayout() {
         setTabPlacement(JTabbedPane.TOP);
-
-        // add panels to tabs
-        // note that those panels that have no internal scrollable tables
-        // must be wrapped in a scroll pane
-
-        entityPanel = new JScrollPane(new ObjEntityMainView(session));
         addTab("Entity", entityPanel);
-
-        attributeRelationshipTab = new ObjEntityPropertiesView(session);
         addTab("Properties", attributeRelationshipTab);
-
-        callbacksPanel = new ObjEntityCallbacksView(session);
         addTab("Callbacks", callbacksPanel);
+    }
 
-        session.addObjEntityDisplayListener(this::currentObjEntityChanged);
-        
session.addObjAttributeDisplayListener(this::currentObjAttributeChanged);
-        
session.addObjRelationshipDisplayListener(this::currentObjRelationshipChanged);
-
+    private void initBindings() {
+        session().addObjEntityDisplayListener(this::currentObjEntityChanged);
+        
session().addObjAttributeDisplayListener(this::currentObjAttributeChanged);
+        
session().addObjRelationshipDisplayListener(this::currentObjRelationshipChanged);
         addChangeListener(this::stateChanged);
     }
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/callbacks/ObjEntityCallbacksView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/callbacks/ObjEntityCallbacksView.java
index 4aabea2e8..6bad8c6b9 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/callbacks/ObjEntityCallbacksView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/callbacks/ObjEntityCallbacksView.java
@@ -91,7 +91,14 @@ public class ObjEntityCallbacksView extends ProjectPanel {
 
     public ObjEntityCallbacksView(ProjectSession session) {
         super(session);
-        this.setLayout(new BorderLayout());
+        this.auxPanel = new JPanel();
+        this.popupMenu = createPopup();
+        initLayout();
+        initBindings();
+    }
+
+    private void initLayout() {
+        setLayout(new BorderLayout());
 
         JToolBar toolBar = new JToolBar();
         toolBar.setFloatable(false);
@@ -100,19 +107,15 @@ public class ObjEntityCallbacksView extends ProjectPanel {
         toolBar.add(getCopyCallbackMethodAction().buildButton(1));
         toolBar.add(getCutCallbackMethodAction().buildButton(2));
         toolBar.add(getPasteCallbackMethodAction().buildButton(3));
-
         add(toolBar, BorderLayout.NORTH);
 
-        auxPanel = new JPanel();
         auxPanel.setOpaque(false);
         auxPanel.setLayout(new BorderLayout());
-
-        popupMenu = createPopup();
-
         createTables();
-
         add(new JScrollPane(auxPanel), BorderLayout.CENTER);
+    }
 
+    private void initBindings() {
         session().addCallbackMethodListener(new CallbackMethodListener() {
 
             public void callbackMethodChanged(CallbackMethodEvent e) {
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/main/ObjEntityMainView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/main/ObjEntityMainView.java
index db06d3295..f08dc9396 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/main/ObjEntityMainView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/main/ObjEntityMainView.java
@@ -68,7 +68,7 @@ public class ObjEntityMainView extends ProjectPanel 
implements ObjEntityDisplayL
     private final CMUndoableTextField name;
     private final CMUndoableTextField className;
 
-    private final JLabel superclassLabel;
+    private JLabel superclassLabel;
     private final CMUndoableTextField superClassName;
     private final CMUndoableTextField qualifier;
     private final CMComboBox<DbEntity> dbEntityCombo;
@@ -77,17 +77,33 @@ public class ObjEntityMainView extends ProjectPanel 
implements ObjEntityDisplayL
     private final CMCheckBox optimisticLocking;
     private final CMCheckBox isAbstract;
     private final CMUndoableTextField comment;
+    // borderless clickable button used as a label; needs to be a field to 
wire its listener in initBindings()
+    private final JButton tableLabel;
 
     public ObjEntityMainView(ProjectSession session) {
         super(session);
+        name = new CMUndoableTextField(app().getUndoManager());
+        superClassName = new CMUndoableTextField(app().getUndoManager());
+        className = new CMUndoableTextField(app().getUndoManager());
+        qualifier = new CMUndoableTextField(app().getUndoManager());
+        dbEntityCombo = new CMComboBox<>();
+        superEntityCombo = new CMComboBox<>();
+        readOnly = new CMCheckBox(app().getUndoManager());
+        optimisticLocking = new CMCheckBox(app().getUndoManager());
+        isAbstract = new CMCheckBox(app().getUndoManager());
+        comment = new CMUndoableTextField(app().getUndoManager());
+        tableLabel = new JButton("Table/View:");
+        initLayout();
+        initBindings();
+    }
 
-        this.setLayout(new BorderLayout());
+    private void initLayout() {
+        setLayout(new BorderLayout());
 
         JToolBar toolBar = new JToolBar();
         toolBar.setBorder(BorderFactory.createEmptyBorder());
         toolBar.setFloatable(false);
         GlobalActions globalActions = app().getActionManager();
-
         
toolBar.add(globalActions.getAction(CreateAttributeAction.class).buildButton(1));
         
toolBar.add(globalActions.getAction(CreateRelationshipAction.class).buildButton(3));
         toolBar.addSeparator();
@@ -95,44 +111,14 @@ public class ObjEntityMainView extends ProjectPanel 
implements ObjEntityDisplayL
         
toolBar.add(globalActions.getAction(ObjEntityCounterpartAction.class).buildButton(3));
         toolBar.addSeparator();
         
toolBar.add(globalActions.getAction(ShowGraphEntityAction.class).buildButton());
-
         add(toolBar, BorderLayout.NORTH);
 
-        // create widgets
-        name = new CMUndoableTextField(app().getUndoManager());
-        name.addCommitListener(this::setEntityName);
-        superClassName = new CMUndoableTextField(app().getUndoManager());
-        superClassName.addCommitListener(this::setSuperClassName);
-        className = new CMUndoableTextField(app().getUndoManager());
-        className.addCommitListener(this::setClassName);
-        qualifier = new CMUndoableTextField(app().getUndoManager());
-        qualifier.addCommitListener(this::setQualifier);
-
-        dbEntityCombo = new CMComboBox<>();
-        superEntityCombo = new CMComboBox<>();
-
-        AutoCompletion.enable(dbEntityCombo, session()::getSelectedDataMap);
-        AutoCompletion.enable(superEntityCombo, session()::getSelectedDataMap);
-
-        readOnly = new CMCheckBox(app().getUndoManager());
-
-        optimisticLocking = new CMCheckBox(app().getUndoManager());
-
-        // borderless clickable button used as a label
-        JButton tableLabel = new JButton("Table/View:");
         tableLabel.setBorderPainted(false);
         tableLabel.setHorizontalAlignment(SwingConstants.LEFT);
         tableLabel.setFocusPainted(false);
         tableLabel.setMargin(new Insets(0, 0, 0, 0));
         tableLabel.setBorder(null);
 
-
-        isAbstract = new CMCheckBox(app().getUndoManager());
-
-        comment = new CMUndoableTextField(app().getUndoManager());
-        comment.addCommitListener(this::setComment);
-
-        // assemble
         FormLayout layout = new FormLayout("right:pref, 3dlu, fill:200dlu", 
"");
         DefaultFormBuilder builder = new DefaultFormBuilder(layout);
         builder.setDefaultDialogBorder();
@@ -143,17 +129,24 @@ public class ObjEntityMainView extends ProjectPanel 
implements ObjEntityDisplayL
         builder.append(tableLabel, dbEntityCombo);
         builder.append("Comment:", comment);
         builder.appendSeparator();
-
         builder.append("Java Class:", className);
-
         superclassLabel = builder.append("Superclass:", superClassName);
         builder.append("Qualifier:", qualifier);
         builder.append("Read-Only:", readOnly);
         builder.append("Optimistic Locking:", optimisticLocking);
 
         add(builder.getPanel(), BorderLayout.CENTER);
+    }
 
-        // initialize events processing and tracking of UI updates...
+    private void initBindings() {
+        AutoCompletion.enable(dbEntityCombo, session()::getSelectedDataMap);
+        AutoCompletion.enable(superEntityCombo, session()::getSelectedDataMap);
+
+        name.addCommitListener(this::setEntityName);
+        superClassName.addCommitListener(this::setSuperClassName);
+        className.addCommitListener(this::setClassName);
+        qualifier.addCommitListener(this::setQualifier);
+        comment.addCommitListener(this::setComment);
 
         session().addObjEntityDisplayListener(this);
 
@@ -161,8 +154,6 @@ public class ObjEntityMainView extends ProjectPanel 
implements ObjEntityDisplayL
             // Change DbEntity for current ObjEntity
             ObjEntity entity = session().getSelectedObjEntity();
             DbEntity dbEntity = (DbEntity) dbEntityCombo.getSelectedItem();
-
-
             if (dbEntity != entity.getDbEntity()) {
                 entity.setDbEntity(dbEntity);
                 
session().fireObjEntityEvent(ObjEntityEvent.ofChange(ObjEntityMainView.this, 
entity));
@@ -221,10 +212,8 @@ public class ObjEntityMainView extends ProjectPanel 
implements ObjEntityDisplayL
 
                 // fire both ObjEntityEvent and ObjEntityDisplayEvent;
                 // the latter is to update attribute and relationship display
-
                 DataChannelDescriptor domain = (DataChannelDescriptor) 
session().project().getRootNode();
                 DataMap map = session().getSelectedDataMap();
-
                 session().fireObjEntityEvent(ObjEntityEvent.ofChange(this, 
entity));
                 session().displayObjEntity(new ObjEntityDisplayEvent(this, 
domain, map, entity));
             }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjAttributePanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjAttributePanel.java
index e29977425..b1e8a0af4 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjAttributePanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjAttributePanel.java
@@ -86,17 +86,34 @@ public class ObjAttributePanel extends JPanel implements 
ObjEntityDisplayListene
     public ObjAttributePanel(ProjectSession session, ObjEntityPropertiesView 
parentPanel) {
         this.session = session;
         this.parentPanel = parentPanel;
+        this.table = new CMTable();
+        this.editMenu = new JMenuItem("Edit Attribute", 
IconFactory.buildIcon("icon-edit.png"));
+        initLayout();
+        initBindings();
+    }
 
-        this.setLayout(new BorderLayout());
+    private void initLayout() {
+        setLayout(new BorderLayout());
 
         GlobalActions globalActions = session.app().getActionManager();
 
-        table = new CMTable();
         table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
         table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
         table.setDefaultRenderer(String.class, new CellRenderer(session));
 
-        // go to SuperEntity from ObjEntity by inheritance icon
+        JPopupMenu popup = new JPopupMenu();
+        popup.add(editMenu);
+        
popup.add(globalActions.getAction(RemoveAttributeRelationshipAction.class).buildMenu());
+        popup.addSeparator();
+        
popup.add(globalActions.getAction(CutAttributeRelationshipAction.class).buildMenu());
+        
popup.add(globalActions.getAction(CopyAttributeRelationshipAction.class).buildMenu());
+        popup.add(globalActions.getAction(PasteAction.class).buildMenu());
+
+        TablePopupHandler.install(table, popup);
+        add(new CMTablePanel(table), BorderLayout.CENTER);
+    }
+
+    private void initBindings() {
         table.addMouseListener(new MouseAdapter() {
             @Override
             public void mouseReleased(MouseEvent e) {
@@ -114,28 +131,15 @@ public class ObjAttributePanel extends JPanel implements 
ObjEntityDisplayListene
             }
         });
 
-        this.editMenu = new JMenuItem("Edit Attribute", 
IconFactory.buildIcon("icon-edit.png"));
         editMenu.addActionListener(this::edit);
 
-        JPopupMenu popup = new JPopupMenu();
-        popup.add(editMenu);
-        
popup.add(globalActions.getAction(RemoveAttributeRelationshipAction.class).buildMenu());
-
-        popup.addSeparator();
-        
popup.add(globalActions.getAction(CutAttributeRelationshipAction.class).buildMenu());
-        
popup.add(globalActions.getAction(CopyAttributeRelationshipAction.class).buildMenu());
-        popup.add(globalActions.getAction(PasteAction.class).buildMenu());
-
-        TablePopupHandler.install(table, popup);
-        add(new CMTablePanel(table), BorderLayout.CENTER);
-
         session.addObjEntityDisplayListener(this);
         session.addObjEntityListener(this);
         session.addObjAttributeListener(this);
 
         table.getSelectionModel().addListSelectionListener(this::valueChanged);
 
-        globalActions.setupCutCopyPaste(
+        session.app().getActionManager().setupCutCopyPaste(
                 table,
                 CutAttributeRelationshipAction.class,
                 CopyAttributeRelationshipAction.class);
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjEntityPropertiesView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjEntityPropertiesView.java
index 5f1d4d8ee..0e8e40b60 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjEntityPropertiesView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjEntityPropertiesView.java
@@ -54,21 +54,22 @@ public class ObjEntityPropertiesView extends ProjectPanel 
implements ObjEntityDi
 
     public ObjEntityPropertiesView(ProjectSession session) {
         super(session);
-        this.setLayout(new BorderLayout());
-
         this.editButton = new ModelerAbstractAction.CayenneToolbarButton(null, 
0);
-        attributePanel = new ObjAttributePanel(session, this);
-        relationshipPanel = new ObjRelationshipPanel(session, this);
+        this.attributePanel = new ObjAttributePanel(session, this);
+        this.relationshipPanel = new ObjRelationshipPanel(session, this);
+        this.splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, 
attributePanel, relationshipPanel);
+        this.toolBar = new JToolBar();
+        initLayout();
+    }
+
+    private void initLayout() {
+        setLayout(new BorderLayout());
 
-        splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, attributePanel, 
relationshipPanel);
         splitPane.setOneTouchExpandable(true);
         splitPane.setResizeWeight(0.5);
-
         CMSplitPanePrefs.of(app().getPreferencesRepository(), 
"objEntity/splitPane").bind(splitPane, -1);
-
         add(splitPane);
 
-        toolBar = new JToolBar();
         toolBar.setFloatable(false);
         GlobalActions globalActions = app().getActionManager();
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjRelationshipPanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjRelationshipPanel.java
index 0dbd4fb05..7b2255c97 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjRelationshipPanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjRelationshipPanel.java
@@ -78,17 +78,35 @@ public class ObjRelationshipPanel extends JPanel implements 
ObjEntityDisplayList
     public ObjRelationshipPanel(ProjectSession session, 
ObjEntityPropertiesView parentPanel) {
         this.session = session;
         this.parentPanel = parentPanel;
+        this.table = new CMTable();
+        this.editMenu = new JMenuItem("Edit Relationship", 
IconFactory.buildIcon("icon-edit.png"));
+        initLayout();
+        initBindings();
+    }
 
-        this.setLayout(new BorderLayout());
+    private void initLayout() {
+        setLayout(new BorderLayout());
 
         GlobalActions globalActions = session.app().getActionManager();
 
-        table = new CMTable();
         table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
         table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
         table.setDefaultRenderer(String.class, new StringRenderer());
         table.setDefaultRenderer(ObjEntity.class, new EntityRenderer());
 
+        JPopupMenu popup = new JPopupMenu();
+        popup.add(editMenu);
+        
popup.add(globalActions.getAction(RemoveAttributeRelationshipAction.class).buildMenu());
+        popup.addSeparator();
+        
popup.add(globalActions.getAction(CutAttributeRelationshipAction.class).buildMenu());
+        
popup.add(globalActions.getAction(CopyAttributeRelationshipAction.class).buildMenu());
+        popup.add(globalActions.getAction(PasteAction.class).buildMenu());
+
+        TablePopupHandler.install(table, popup);
+        add(new CMTablePanel(table), BorderLayout.CENTER);
+    }
+
+    private void initBindings() {
         table.addMouseListener(new MouseAdapter() {
             @Override
             public void mouseReleased(MouseEvent e) {
@@ -107,28 +125,12 @@ public class ObjRelationshipPanel extends JPanel 
implements ObjEntityDisplayList
             }
         });
 
-        // Create and install a popup
-        Icon ico = IconFactory.buildIcon("icon-edit.png");
-        editMenu = new JMenuItem("Edit Relationship", ico);
-
-        JPopupMenu popup = new JPopupMenu();
-        popup.add(editMenu);
-        
popup.add(globalActions.getAction(RemoveAttributeRelationshipAction.class).buildMenu());
-
-        popup.addSeparator();
-        
popup.add(globalActions.getAction(CutAttributeRelationshipAction.class).buildMenu());
-        
popup.add(globalActions.getAction(CopyAttributeRelationshipAction.class).buildMenu());
-        popup.add(globalActions.getAction(PasteAction.class).buildMenu());
-
-        TablePopupHandler.install(table, popup);
-        add(new CMTablePanel(table), BorderLayout.CENTER);
+        editMenu.addActionListener(this::edit);
 
         session.addObjEntityDisplayListener(this);
         session.addObjEntityListener(this);
         session.addObjRelationshipListener(this);
 
-        editMenu.addActionListener(this::edit);
-
         table.getSelectionModel().addListSelectionListener(this::valueChanged);
 
         session.app().getActionManager().setupCutCopyPaste(
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/procedure/ProcedureQueryView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/procedure/ProcedureQueryView.java
index 06a73470e..fe942ad3b 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/procedure/ProcedureQueryView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/procedure/ProcedureQueryView.java
@@ -79,12 +79,11 @@ public class ProcedureQueryView extends ProjectPanel {
 
     public ProcedureQueryView(ProjectSession session) {
         super(session);
-
-        initView();
-        initController();
+        initLayout();
+        initBindings();
     }
 
-    private void initView() {
+    private void initLayout() {
         // create widgets
         name = new CMUndoableTextField(app().getUndoManager());
         name.addCommitListener(this::setQueryName);
@@ -117,7 +116,7 @@ public class ProcedureQueryView extends ProjectPanel {
         this.add(properties, BorderLayout.CENTER);
     }
 
-    private void initController() {
+    private void initBindings() {
 
         queryRoot.addActionListener(new ActionListener() {
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/procedure/ProcedureTabbedView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/procedure/ProcedureTabbedView.java
index 31df70e81..8dc5bfaa8 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/procedure/ProcedureTabbedView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/procedure/ProcedureTabbedView.java
@@ -39,14 +39,21 @@ public class ProcedureTabbedView extends ProjectTabbedPane {
 
     public ProcedureTabbedView(ProjectSession session) {
         super(session);
-        setTabPlacement(JTabbedPane.TOP);
         procedurePanel = new ProcedureTab(session);
-        addTab("Procedure", new JScrollPane(procedurePanel));
         procedureParameterPanel = new ProcedureParameterTab(session);
+        initLayout();
+        initBindings();
+    }
+
+    private void initLayout() {
+        setTabPlacement(JTabbedPane.TOP);
+        addTab("Procedure", new JScrollPane(procedurePanel));
         addTab("Parameters", procedureParameterPanel);
+    }
 
-        session.addProcedureDisplayListener(this::currentProcedureChanged);
-        
session.addProcedureParameterDisplayListener(this::currentProcedureParameterChanged);
+    private void initBindings() {
+        session().addProcedureDisplayListener(this::currentProcedureChanged);
+        
session().addProcedureParameterDisplayListener(this::currentProcedureParameterChanged);
         addChangeListener(this::stateChanged);
     }
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/query/ejbql/EjbqlTabbedView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/query/ejbql/EjbqlTabbedView.java
index ec76a636a..5eba1f394 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/query/ejbql/EjbqlTabbedView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/query/ejbql/EjbqlTabbedView.java
@@ -34,16 +34,20 @@ public class EjbqlTabbedView extends ProjectTabbedPane {
 
     public EjbqlTabbedView(ProjectSession session) {
         super(session);
+        this.mainTab = new EjbqlQueryMainTab(session);
+        this.scriptsTab = new EjbqlQueryScriptsTab(session);
+        initLayout();
+        initBindings();
+    }
 
+    private void initLayout() {
         setTabPlacement(JTabbedPane.TOP);
-
-        this.mainTab = new EjbqlQueryMainTab(session);
         addTab("General", new JScrollPane(mainTab));
-
-        this.scriptsTab = new EjbqlQueryScriptsTab(session);
         addTab("EJBQL", scriptsTab);
+    }
 
-        session.addQueryDisplayListener(e -> initFromModel());
+    private void initBindings() {
+        session().addQueryDisplayListener(e -> initFromModel());
         addChangeListener(this::stateChanged);
     }
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/query/selectquery/SelectQueryTabbedView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/query/selectquery/SelectQueryTabbedView.java
index e204233a1..409df75fd 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/query/selectquery/SelectQueryTabbedView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/query/selectquery/SelectQueryTabbedView.java
@@ -36,19 +36,22 @@ public class SelectQueryTabbedView extends 
ProjectTabbedPane {
 
     public SelectQueryTabbedView(ProjectSession session) {
         super(session);
+        this.mainTab = new SelectQueryMainTab(session);
+        this.orderingTab = new SelectQueryOrderingTab(session);
+        this.prefetchTab = new SelectQueryPrefetchTab(session);
+        initLayout();
+        initBindings();
+    }
 
+    private void initLayout() {
         setTabPlacement(JTabbedPane.TOP);
-
-        this.mainTab = new SelectQueryMainTab(session);
         addTab("General", new JScrollPane(mainTab));
-
-        this.orderingTab = new SelectQueryOrderingTab(session);
         addTab("Orderings", orderingTab);
-
-        this.prefetchTab = new SelectQueryPrefetchTab(session);
         addTab("Prefetches", prefetchTab);
+    }
 
-        session.addQueryDisplayListener(e -> initFromModel());
+    private void initBindings() {
+        session().addQueryDisplayListener(e -> initFromModel());
         addChangeListener(this::stateChanged);
     }
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/query/sqltemplate/SQLTemplateTabbedView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/query/sqltemplate/SQLTemplateTabbedView.java
index 6b2b6e5b9..31c8f458c 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/query/sqltemplate/SQLTemplateTabbedView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/query/sqltemplate/SQLTemplateTabbedView.java
@@ -36,19 +36,22 @@ public class SQLTemplateTabbedView extends 
ProjectTabbedPane {
 
     public SQLTemplateTabbedView(ProjectSession session) {
         super(session);
+        this.mainTab = new SQLTemplateMainTab(session);
+        this.scriptsTab = new SQLTemplateScriptsTab(session);
+        this.prefetchTab = new SQLTemplatePrefetchTab(session);
+        initLayout();
+        initBindings();
+    }
 
+    private void initLayout() {
         setTabPlacement(JTabbedPane.TOP);
-
-        this.mainTab = new SQLTemplateMainTab(session);
         addTab("General", new JScrollPane(mainTab));
-
-        this.scriptsTab = new SQLTemplateScriptsTab(session);
         addTab("SQL Scripts", scriptsTab);
-
-        this.prefetchTab = new SQLTemplatePrefetchTab(session);
         addTab("Prefetches", prefetchTab);
+    }
 
-        session.addQueryDisplayListener(e -> initFromModel());
+    private void initBindings() {
+        session().addQueryDisplayListener(e -> initFromModel());
         addChangeListener(this::stateChanged);
     }
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/welcome/WelcomeScreen.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/welcome/WelcomeScreen.java
index a04ab99f4..f90d346c0 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/welcome/WelcomeScreen.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/welcome/WelcomeScreen.java
@@ -38,37 +38,24 @@ import java.util.List;
  */
 public class WelcomeScreen extends JScrollPane implements 
RecentFileListListener, RecentFileListRenderer.OnFileClickListener {
 
-    private static final Color TOP_GRADIENT = new Color(153, 153, 153);
-    private static final Color BOTTOM_GRADIENT = new Color(230, 230, 230);
-
     private final Application application;
     private final GlobalActions actionManager;
 
-    private JList<String> recentProjectsList;
-    private JPanel buttonsPanel;
-    private JPanel mainPanel;
+    private final JList<String> recentProjectsList;
+    private final JPanel buttonsPanel;
+    private final JPanel mainPanel;
 
     public WelcomeScreen(Application application) {
         this.application = application;
         this.actionManager = application.getActionManager();
-        initView();
+        this.mainPanel = new WelcomeScreenMainPanel();
+        this.buttonsPanel = new 
BackgroundPanel("welcome/welcome-screen-left-bg.jpg");
+        this.recentProjectsList = new JList<>();
+
+        initLayout();
     }
 
-    /**
-     * Creates all necessary components
-     */
-    protected void initView() {
-        mainPanel = new JPanel(new GridBagLayout()) {
-            @Override
-            public void paintComponent(Graphics g) {
-                // paint gradient background
-                Graphics2D g2 = (Graphics2D) g.create();
-                Paint paint = new GradientPaint(0, 0, TOP_GRADIENT, 0, 
getHeight(), BOTTOM_GRADIENT);
-                g2.setPaint(paint);
-                g2.fillRect(0, 0, getWidth(), getHeight());
-                g2.dispose();
-            }
-        };
+    private void initLayout() {
         setBorder(BorderFactory.createEmptyBorder());
         initButtonsPane();
         initFileListPane();
@@ -78,8 +65,7 @@ public class WelcomeScreen extends JScrollPane implements 
RecentFileListListener
     private void initFileListPane() {
         JPanel fileListPanel = new 
BackgroundPanel("welcome/welcome-screen-right-bg.jpg");
 
-        final int padding = 20;
-        recentProjectsList = new JList<>();
+        int padding = 20;
         recentProjectsList.setOpaque(false);
         recentProjectsList.setLocation(padding, padding);
         recentProjectsList.setSize(
@@ -93,10 +79,9 @@ public class WelcomeScreen extends JScrollPane implements 
RecentFileListListener
     }
 
     private void initButtonsPane() {
-        final int padding = 24; // bottom padding for buttons
-        final int buttonHeight = 36;
+        int padding = 24;
+        int buttonHeight = 36;
 
-        buttonsPanel = new 
BackgroundPanel("welcome/welcome-screen-left-bg.jpg");
         int openButtonY = buttonsPanel.getHeight() - padding - buttonHeight; 
// buttons layout from bottom
         int newButtonY = openButtonY - 10 - buttonHeight; // 10px - space 
between buttons
         initButton("open", openButtonY, OpenProjectAction.class);
@@ -105,9 +90,9 @@ public class WelcomeScreen extends JScrollPane implements 
RecentFileListListener
         mainPanel.add(buttonsPanel);
     }
 
-    private void initButton(String name, int y,  Class<? extends Action> 
actionClass) {
-        ImageIcon icon = 
IconFactory.buildIcon("welcome/welcome-screen-"+name+"-btn.png");
-        ImageIcon hoverIcon = 
IconFactory.buildIcon("welcome/welcome-screen-"+name+"-btn-hover.png");
+    private void initButton(String name, int y, Class<? extends Action> 
actionClass) {
+        ImageIcon icon = IconFactory.buildIcon("welcome/welcome-screen-" + 
name + "-btn.png");
+        ImageIcon hoverIcon = IconFactory.buildIcon("welcome/welcome-screen-" 
+ name + "-btn-hover.png");
         JButton button = createButton(icon, hoverIcon);
         button.setLocation(24, y); // 24px - button left & right padding
         button.addActionListener(actionManager.getAction(actionClass));
@@ -116,14 +101,9 @@ public class WelcomeScreen extends JScrollPane implements 
RecentFileListListener
 
     @Override
     public void onFileSelect(File file) {
-        ActionEvent event = new ActionEvent(file, 0, null);
-        // Fire an action with the file as source
-        actionManager.getAction(OpenProjectAction.class).performAction(event);
+        actionManager.getAction(OpenProjectAction.class).performAction(new 
ActionEvent(file, 0, null));
     }
 
-    /**
-     * Creates welcome screen-specific button
-     */
     private JButton createButton(Icon outIcon, Icon overIcon) {
         JButton button = new JButton();
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/welcome/WelcomeScreenMainPanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/welcome/WelcomeScreenMainPanel.java
new file mode 100644
index 000000000..11d6b18ea
--- /dev/null
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/welcome/WelcomeScreenMainPanel.java
@@ -0,0 +1,23 @@
+package org.apache.cayenne.modeler.ui.welcome;
+
+import javax.swing.*;
+import java.awt.*;
+
+class WelcomeScreenMainPanel extends JPanel {
+
+    private static final Color TOP_GRADIENT = new Color(153, 153, 153);
+    private static final Color BOTTOM_GRADIENT = new Color(230, 230, 230);
+
+    public WelcomeScreenMainPanel() {
+        super(new GridBagLayout());
+    }
+
+    @Override
+    public void paintComponent(Graphics g) {
+        Graphics2D g2 = (Graphics2D) g.create();
+        Paint paint = new GradientPaint(0, 0, TOP_GRADIENT, 0, getHeight(), 
BOTTOM_GRADIENT);
+        g2.setPaint(paint);
+        g2.fillRect(0, 0, getWidth(), getHeight());
+        g2.dispose();
+    }
+}

Reply via email to