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


The following commit(s) were added to refs/heads/master by this push:
     new e94a5a24e Modeler Cleanup
e94a5a24e is described below

commit e94a5a24e6478c2187de11939bbdfa922d00db70
Author: Andrus Adamchik <[email protected]>
AuthorDate: Sun May 3 15:15:58 2026 -0400

    Modeler Cleanup
    
    refactoring towards MVP from MVC - controller creates the view, but view 
binds its widgets to contrller
---
 .../modeler/ui/action/DBConnectionAwareAction.java |   8 -
 .../ui/datasource/DataSourceController.java        |  59 +++----
 .../modeler/ui/datasource/DataSourceView.java      |  55 +++----
 .../ui/dbgen/DBGeneratorOptionsController.java     | 136 ++++++++--------
 .../modeler/ui/dbgen/DBGeneratorOptionsView.java   | 179 +++++++++++++--------
 .../cayenne/modeler/ui/dbgen/DBGeneratorPrefs.java |  49 +++---
 .../modeler/ui/dbgen/TableSelectorController.java  |  52 +-----
 .../modeler/ui/dbgen/TableSelectorView.java        |  83 ++++++++--
 .../ui/preferences/PreferenceDialogController.java |  40 ++---
 .../ui/preferences/PreferenceDialogView.java       |  89 +++++-----
 .../classpath/ClasspathPreferencesController.java  |  87 +++-------
 .../classpath/ClasspathPreferencesView.java        |  77 ++++++---
 .../maven/MavenDependencyDialogController.java     |  41 ++---
 .../classpath/maven/MavenDependencyDialogView.java | 100 +++++-------
 .../DBConnectionInfoEditorController.java          |  89 ----------
 .../dbconnector/DBConnectorEditorController.java   |  79 +++++++++
 ...oEditorView.java => DBConnectorEditorView.java} |  93 +++++------
 .../DBConnectorPreferencesController.java          |  69 ++++----
 .../dbconnector/DBConnectorPreferencesView.java    |  68 +++-----
 .../creator/DBConnectorCreatorController.java      |  75 ++++-----
 .../creator/DBConnectorCreatorView.java            |  47 +++---
 .../DBConnectorDuplicatorController.java           |  54 +++----
 .../duplicator/DBConnectorDuplicatorView.java      |  28 +---
 .../general/GeneralPreferencesController.java      |  63 +-------
 .../general/GeneralPreferencesView.java            |  66 ++++++--
 .../more/MorePreferencesController.java            |  16 +-
 .../ui/preferences/more/MorePreferencesView.java   |  33 ++--
 .../dbimport/action/GetDbConnectionAction.java     |   2 +-
 .../objentity/properties/ObjRelationshipPanel.java |   8 +-
 .../general/GeneralPreferencesControllerTest.java  |   9 --
 30 files changed, 859 insertions(+), 995 deletions(-)

diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/DBConnectionAwareAction.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/DBConnectionAwareAction.java
index 25196918b..833a5fdc3 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/DBConnectionAwareAction.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/DBConnectionAwareAction.java
@@ -50,14 +50,6 @@ public abstract class DBConnectionAwareAction extends 
ModelerAbstractAction {
         return connector;
     }
 
-    protected DataSourceController getDataSourceController(String title, 
String[] buttons) {
-        DataSourceController connectWizard = new 
DataSourceController(getProjectController(), title, buttons);
-        if (!connectWizard.startupAction()) {
-            return null;
-        }
-        return connectWizard;
-    }
-
     protected DataSourceController getDataSourceController(String title) {
         DataSourceController connectWizard = new 
DataSourceController(getProjectController(), title);
         if (!connectWizard.startupAction()) {
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/datasource/DataSourceController.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/datasource/DataSourceController.java
index 272b1bb3c..14dc8cc77 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/datasource/DataSourceController.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/datasource/DataSourceController.java
@@ -21,6 +21,7 @@ package org.apache.cayenne.modeler.ui.datasource;
 
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.modeler.service.classloader.ModelerClassLoader;
+import 
org.apache.cayenne.modeler.ui.preferences.dbconnector.DBConnectorEditorController;
 import org.apache.cayenne.modeler.ui.project.ProjectController;
 import org.apache.cayenne.modeler.ui.preferences.PreferenceDialogController;
 import org.apache.cayenne.modeler.mvc.ChildController;
@@ -40,14 +41,10 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
-/**
- * A subclass of ConnectionWizard that tests configured DataSource, but does 
not
- * keep an open connection.
- *
- */
 public class DataSourceController extends ChildController<ProjectController> {
 
     private final DataSourceView view;
+    private final DBConnectorEditorController editorController;
 
     private Map<String, DBConnector> connectors;
     private String dataSourceKey;
@@ -58,46 +55,32 @@ public class DataSourceController extends 
ChildController<ProjectController> {
     private boolean canceled;
 
     public DataSourceController(ProjectController parent, String title) {
-        this(parent, title, new String[]{"Continue", "Cancel"});
-    }
-
-    public DataSourceController(ProjectController parent, String title, 
String[] buttons) {
         super(parent);
 
         this.connector = new DBConnector();
-
-        this.view = new DataSourceView(this, buttons);
+        this.editorController = new DBConnectorEditorController(this);
+        this.view = new DataSourceView(
+                this,
+                getApplication().getFrameController().getView(),
+                editorController.getView());
         this.view.setTitle(title);
-
-        initBindings();
-    }
-
-    protected void initBindings() {
-        view.getDataSources().addActionListener(e -> {
-            Object sel = view.getDataSources().getSelectedItem();
-            setDataSourceKey(sel != null ? sel.toString() : null);
-        });
-
-        view.getCancelButton().addActionListener(e -> cancelAction());
-        view.getOkButton().addActionListener(e -> okAction());
-        view.getConfigButton().addActionListener(e -> 
dataSourceConfigAction());
     }
 
     private void initFavouriteDataSource() {
         String favouriteDataSource = 
GeneralPrefs.of(parent.getApplication().getPreferencesRepository()).getFavouriteDataSource();
         if (favouriteDataSource != null && 
connectors.containsKey(favouriteDataSource)) {
-            setDataSourceKey(favouriteDataSource);
-            view.getDataSources().setSelectedItem(dataSourceKey);
+            setSelectedDataSource(favouriteDataSource);
+            view.selectDataSource(dataSourceKey);
         }
     }
 
     private DBConnector getConnectionInfoFromPreferences() {
         DataMapPrefs dataMapPrefs = 
DataMapPrefs.of(parent.getApplication().getPreferencesRepository(), 
parent.getSelectedDataMap());
-        DBConnector info = dataMapPrefs.getConnector();
-        return info != null ? info : new DBConnector();
+        DBConnector connector = dataMapPrefs.getConnector();
+        return connector != null ? connector : new DBConnector();
     }
 
-    private void setDataSourceKey(final String dataSourceKey) {
+    void setSelectedDataSource(String dataSourceKey) {
         this.dataSourceKey = dataSourceKey;
 
         // update a clone object that will be used to obtain connection...
@@ -107,7 +90,7 @@ public class DataSourceController extends 
ChildController<ProjectController> {
         } else {
             connector = new DBConnector();
         }
-        view.getConnectionInfo().setConnectionInfo(connector);
+        editorController.setConnector(connector);
     }
 
     /**
@@ -126,7 +109,7 @@ public class DataSourceController extends 
ChildController<ProjectController> {
         view.pack();
         view.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
         view.setModal(true);
-        view.connectionInfo.setConnectionInfo(connector);
+        editorController.setConnector(connector);
         makeCloseableOnEscape();
         centerView();
         view.setVisible(true);
@@ -142,7 +125,7 @@ public class DataSourceController extends 
ChildController<ProjectController> {
      * Tests that the entered information is valid and can be used to open a
      * connection. Does not store the open connection.
      */
-    public void okAction() {
+    void okClicked() {
         DBConnector info = getConnector();
         ModelerClassLoader classLoader = getApplication().getClassLoader();
 
@@ -166,7 +149,7 @@ public class DataSourceController extends 
ChildController<ProjectController> {
         onClose(false);
     }
 
-    public void cancelAction() {
+    void cancelClicked() {
         onClose(true);
     }
 
@@ -182,7 +165,7 @@ public class DataSourceController extends 
ChildController<ProjectController> {
     /**
      * Opens preferences panel to allow configuration of DataSource presets.
      */
-    public void dataSourceConfigAction() {
+    void dataSourceConfigClicked() {
         DBConnectors registry = getApplication().getDbConnectors();
         Set<String> before = new HashSet<>(registry.getAll().keySet());
 
@@ -202,7 +185,7 @@ public class DataSourceController extends 
ChildController<ProjectController> {
      * Opens preferences panel to allow configuration of classpath.
      */
     public void classPathConfigAction() {
-        final PreferenceDialogController prefs = new 
PreferenceDialogController(this);
+        PreferenceDialogController prefs = new 
PreferenceDialogController(this);
         prefs.showClassPathEditorAction();
         refreshDataSources();
     }
@@ -228,7 +211,7 @@ public class DataSourceController extends 
ChildController<ProjectController> {
 
         final String[] keys = connectors.keySet().toArray(new String[0]);
         Arrays.sort(keys);
-        view.getDataSources().setModel(new DefaultComboBoxModel<>(keys));
+        view.setDataSources(keys);
 
         String key = null;
         if (dataSourceKey == null || !connectors.containsKey(dataSourceKey)) {
@@ -237,8 +220,8 @@ public class DataSourceController extends 
ChildController<ProjectController> {
             }
         }
 
-        setDataSourceKey(key != null ? key : dataSourceKey);
-        view.getDataSources().setSelectedItem(dataSourceKey);
+        setSelectedDataSource(key != null ? key : dataSourceKey);
+        view.selectDataSource(dataSourceKey);
     }
 
     protected void showNoConnectorDialog(String message) {
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/datasource/DataSourceView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/datasource/DataSourceView.java
index 9fe8de3e7..41882b0bc 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/datasource/DataSourceView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/datasource/DataSourceView.java
@@ -22,8 +22,6 @@ package org.apache.cayenne.modeler.ui.datasource;
 import com.jgoodies.forms.builder.PanelBuilder;
 import com.jgoodies.forms.layout.CellConstraints;
 import com.jgoodies.forms.layout.FormLayout;
-import 
org.apache.cayenne.modeler.ui.preferences.dbconnector.DBConnectionInfoEditorController;
-import org.apache.cayenne.modeler.mvc.RootController;
 
 import javax.swing.*;
 import java.awt.*;
@@ -31,28 +29,27 @@ import java.awt.*;
 
 public class DataSourceView extends JDialog {
 
-    private static final byte OK_BUTTON_INDEX = 0;
-    private static final byte CANCEL_BUTTON_INDEX = 1;
+    private final JComboBox<String> dataSources;
 
-    protected JComboBox<String> dataSources;
-    protected JButton configButton;
-    protected JButton okButton;
-    protected JButton cancelButton;
-    protected DBConnectionInfoEditorController connectionInfo;
+    public DataSourceView(DataSourceController controller, Frame parent, 
Component editorView) {
+        super(parent);
 
-    public DataSourceView(RootController controller, String[] labels) {
-        super(controller.getApplication().getFrameController().getView());
-        
         this.dataSources = new JComboBox<>();
-
-        this.configButton = new JButton("...");
-        this.configButton.setToolTipText("configure local DataSource");
-        this.okButton = new JButton(labels[OK_BUTTON_INDEX]);
-        this.cancelButton = new JButton(labels[CANCEL_BUTTON_INDEX]);
-        this.connectionInfo = new DBConnectionInfoEditorController(controller);
+        JButton configButton = new JButton("...");
+        configButton.setToolTipText("configure local DataSource");
+        JButton okButton = new JButton("Continue");
+        JButton cancelButton = new JButton("Cancel");
 
         getRootPane().setDefaultButton(okButton);
 
+        dataSources.addActionListener(e -> {
+            Object sel = dataSources.getSelectedItem();
+            controller.setSelectedDataSource(sel != null ? sel.toString() : 
null);
+        });
+        cancelButton.addActionListener(e -> controller.cancelClicked());
+        okButton.addActionListener(e -> controller.okClicked());
+        configButton.addActionListener(e -> 
controller.dataSourceConfigClicked());
+
         CellConstraints cc = new CellConstraints();
         PanelBuilder builder = new PanelBuilder(new FormLayout(
                 "20dlu:grow, pref, 3dlu, fill:max(150dlu;pref), 3dlu, 
fill:20dlu",
@@ -69,29 +66,17 @@ public class DataSourceView extends JDialog {
 
         getContentPane().setLayout(new BorderLayout());
         getContentPane().add(builder.getPanel(), BorderLayout.NORTH);
-        getContentPane().add(connectionInfo.getView(), BorderLayout.CENTER);
+        getContentPane().add(editorView, BorderLayout.CENTER);
         getContentPane().add(buttons, BorderLayout.SOUTH);
 
         setTitle("DB Connection Info");
     }
 
-    public JComboBox<String> getDataSources() {
-        return dataSources;
-    }
-
-    public JButton getCancelButton() {
-        return cancelButton;
-    }
-
-    public JButton getConfigButton() {
-        return configButton;
-    }
-
-    public JButton getOkButton() {
-        return okButton;
+    public void setDataSources(String[] keys) {
+        dataSources.setModel(new DefaultComboBoxModel<>(keys));
     }
 
-    public DBConnectionInfoEditorController getConnectionInfo() {
-        return connectionInfo;
+    public void selectDataSource(String key) {
+        dataSources.setSelectedItem(key);
     }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorOptionsController.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorOptionsController.java
index c1cf71e17..8500a5950 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorOptionsController.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorOptionsController.java
@@ -28,7 +28,6 @@ import 
org.apache.cayenne.modeler.ui.validation.ValidationController;
 import org.apache.cayenne.modeler.ui.datasource.DataSourceController;
 import org.apache.cayenne.modeler.mvc.ChildController;
 import org.apache.cayenne.modeler.dbconnector.DBConnector;
-import org.apache.cayenne.modeler.util.DbAdapterInfo;
 import org.apache.cayenne.validation.ValidationResult;
 
 import javax.swing.*;
@@ -44,10 +43,11 @@ import java.util.Iterator;
 
 public class DBGeneratorOptionsController extends 
ChildController<ProjectController> {
 
-    protected DBGeneratorOptionsView view;
-    private boolean updatingAdapterCombo;
+    private static final String JDBC_ADAPTER = 
"org.apache.cayenne.dba.JdbcAdapter";
 
-    protected DBConnector connectionInfo;
+    protected final DBGeneratorOptionsView view;
+
+    protected DBConnector connector;
     protected Collection<DataMap> dataMaps;
     protected DBGeneratorPrefs generatorDefaults;
     protected Collection<DbGenerator> generators;
@@ -60,17 +60,23 @@ public class DBGeneratorOptionsController extends 
ChildController<ProjectControl
 
         this.dataMaps = dataMaps;
         this.tables = new TableSelectorController(parent);
-        this.view = new DBGeneratorOptionsView(tables.getView());
-        this.connectionInfo = new DBConnector();
-        // DataSource may not be initialized, so warn connection wizard
-        this.connectionInfo.setAllowDataSourceFailure(true);
+        this.connector = new DBConnector();
+        this.connector.setAllowDataSourceFailure(true);
         this.generatorDefaults = DBGeneratorPrefs.of(
                 parent.getApplication().getPreferencesRepository(),
                 parent.getProject());
 
+        this.view = new DBGeneratorOptionsView(
+                this,
+                tables.getView(),
+                generatorDefaults.getCreateFK(),
+                generatorDefaults.getCreatePK(),
+                generatorDefaults.getCreateTables(),
+                generatorDefaults.getDropPK(),
+                generatorDefaults.getDropTables());
         this.view.setTitle(title);
-        initController();
-        connectionInfo.setDbAdapter((String) 
view.getAdapters().getSelectedItem());
+
+        connector.setDbAdapter(view.getSelectedAdapter());
 
         tables.updateTables(dataMaps);
         prepareGenerator();
@@ -84,47 +90,12 @@ public class DBGeneratorOptionsController extends 
ChildController<ProjectControl
         return view;
     }
 
-    protected void initController() {
-
-        generatorDefaults.bind(view);
-
-        DefaultComboBoxModel<String> adapterModel = new DefaultComboBoxModel<>(
-                DbAdapterInfo.getStandardAdapters());
-        view.getAdapters().setModel(adapterModel);
-        view.getAdapters().setSelectedIndex(0);
-
-        view.getAdapters().addActionListener(e -> {
-            if (updatingAdapterCombo) return;
-            Object sel = view.getAdapters().getSelectedItem();
-            
connectionInfo.setDbAdapter("org.apache.cayenne.dba.JdbcAdapter".equals(sel) ? 
null : (String) sel);
-            refreshSQLAction();
-        });
-
-        view.getCreateFK().addActionListener(e -> refreshSQLAction());
-        view.getCreatePK().addActionListener(e -> refreshSQLAction());
-        view.getCreateTables().addActionListener(e -> refreshSQLAction());
-        view.getDropPK().addActionListener(e -> refreshSQLAction());
-        view.getDropTables().addActionListener(e -> refreshSQLAction());
-
-        view.getGenerateButton().addActionListener(e -> 
generateSchemaAction());
-        view.getSaveSqlButton().addActionListener(e -> storeSQLAction());
-        view.getCancelButton().addActionListener(e -> closeAction());
-
-        // refresh SQL if different tables were selected
-        view.getTabs().addChangeListener(e -> {
-            if (view.getTabs().getSelectedIndex() == 0) {
-                // this assumes that some tables where checked/unchecked... 
not very efficient
-                refreshGeneratorAction();
-            }
-        });
-    }
-
     private void applyOptionsToGenerators() {
-        boolean createFK = view.getCreateFK().isSelected();
-        boolean createPK = view.getCreatePK().isSelected();
-        boolean createTables = view.getCreateTables().isSelected();
-        boolean dropPK = view.getDropPK().isSelected();
-        boolean dropTables = view.getDropTables().isSelected();
+        boolean createFK = view.isCreateFkSelected();
+        boolean createPK = view.isCreatePkSelected();
+        boolean createTables = view.isCreateTablesSelected();
+        boolean dropPK = view.isDropPkSelected();
+        boolean dropTables = view.isDropTablesSelected();
         for (DbGenerator generator : generators) {
             generator.setShouldCreateFKConstraints(createFK);
             generator.setShouldCreatePKSupport(createPK);
@@ -139,7 +110,7 @@ public class DBGeneratorOptionsController extends 
ChildController<ProjectControl
      */
     protected void prepareGenerator() {
         try {
-            DbAdapter adapter = 
connectionInfo.makeAdapter(getApplication().getClassLoader(), 
getApplication().getDbAdapterFactory());
+            DbAdapter adapter = 
connector.makeAdapter(getApplication().getClassLoader(), 
getApplication().getDbAdapterFactory());
             generators = new ArrayList<>();
             for (DataMap dataMap : dataMaps) {
                 this.generators.add(new DbGenerator(
@@ -177,8 +148,47 @@ public class DBGeneratorOptionsController extends 
ChildController<ProjectControl
     }
 
     protected void refreshView() {
-        view.setEnabled(connectionInfo != null);
-        view.getSql().setText(textForSQL);
+        view.setEnabled(connector != null);
+        view.setSqlPreview(textForSQL);
+    }
+
+    // ===============
+    // View callbacks
+    // ===============
+
+    void refreshSqlClicked() {
+        refreshSQLAction();
+    }
+
+    void adapterChanged(String adapter) {
+        connector.setDbAdapter(adapter);
+        refreshSQLAction();
+    }
+
+    void sqlTabSelected() {
+        // assumes that some tables were checked/unchecked... not very 
efficient
+        refreshGeneratorAction();
+    }
+
+    void generateClicked() {
+        generateSchemaAction();
+    }
+
+    void saveSqlClicked() {
+        storeSQLAction();
+    }
+
+    void cancelClicked() {
+        view.dispose();
+    }
+
+    void windowClosed() {
+        generatorDefaults.save(
+                view.isCreateFkSelected(),
+                view.isCreatePkSelected(),
+                view.isCreateTablesSelected(),
+                view.isDropPkSelected(),
+                view.isDropTablesSelected());
     }
 
     // ===============
@@ -207,18 +217,14 @@ public class DBGeneratorOptionsController extends 
ChildController<ProjectControl
      */
     public void refreshSQLAction() {
         // sync combo to reflect current connectionInfo (e.g. after 
generateSchemaAction replaces it)
-        updatingAdapterCombo = true;
-        try {
-            String adapter = connectionInfo.getDbAdapter();
-            view.getAdapters().setSelectedItem(adapter != null ? adapter : 
"org.apache.cayenne.dba.JdbcAdapter");
-        } finally {
-            updatingAdapterCombo = false;
-        }
-        connectionInfo.setDbAdapter((String) 
view.getAdapters().getSelectedItem());
+        String adapter = connector.getDbAdapter();
+        view.selectAdapter(adapter);
+        // mirror the displayed value back to the model (was: setSelectedItem 
returns "JdbcAdapter" placeholder when null)
+        connector.setDbAdapter(adapter != null ? adapter : JDBC_ADAPTER);
         prepareGenerator();
         applyOptionsToGenerators();
         createSQL();
-        view.getSql().setText(textForSQL);
+        view.setSqlPreview(textForSQL);
     }
 
     /**
@@ -231,7 +237,7 @@ public class DBGeneratorOptionsController extends 
ChildController<ProjectControl
             return;
         }
 
-        this.connectionInfo = connectWizard.getConnector();
+        this.connector = connectWizard.getConnector();
 
         refreshGeneratorAction();
 
@@ -291,8 +297,4 @@ public class DBGeneratorOptionsController extends 
ChildController<ProjectControl
             }
         }
     }
-
-    public void closeAction() {
-        view.dispose();
-    }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorOptionsView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorOptionsView.java
index f4eb97363..bdb47689a 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorOptionsView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorOptionsView.java
@@ -25,8 +25,11 @@ import java.awt.Container;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.GridLayout;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
 
 import javax.swing.Box;
+import javax.swing.DefaultComboBoxModel;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
@@ -44,60 +47,107 @@ import com.jgoodies.forms.factories.Borders;
 import com.jgoodies.forms.layout.CellConstraints;
 import com.jgoodies.forms.layout.FormLayout;
 import org.apache.cayenne.modeler.toolkit.border.TopBorder;
+import org.apache.cayenne.modeler.util.DbAdapterInfo;
 
 /**
  * Wizard for generating the database from the data map.
  */
 public class DBGeneratorOptionsView extends JDialog {
 
-    protected JTextArea sql;
-    protected JButton generateButton;
-    protected JButton cancelButton;
-    protected JButton saveSqlButton;
-    protected JCheckBox dropTables;
-    protected JCheckBox createTables;
-    protected JCheckBox createFK;
-    protected JCheckBox createPK;
-    protected JCheckBox dropPK;
-    protected Component tables;
-    protected JTabbedPane tabs;
-    protected JComboBox<String> adapters;
-
-    public DBGeneratorOptionsView(Component tables) {
-        // create widgets
-        this.generateButton = new JButton("Generate");
-        getRootPane().setDefaultButton(generateButton);
-        this.cancelButton = new JButton("Cancel");
-        this.saveSqlButton = new JButton("Save SQL");
-        this.dropTables = new JCheckBox("Drop Tables");
-        this.createTables = new JCheckBox("Create Tables");
+    private static final String JDBC_ADAPTER = 
"org.apache.cayenne.dba.JdbcAdapter";
+
+    private final JTextArea sql;
+    private final JCheckBox dropTables;
+    private final JCheckBox createTables;
+    private final JCheckBox createFK;
+    private final JCheckBox createPK;
+    private final JCheckBox dropPK;
+    private final JComboBox<String> adapters;
+
+    // True while the controller is pushing a programmatic adapter selection;
+    // suppresses the action listener so it doesn't recurse back into the 
controller.
+    private boolean updatingAdapterProgrammatically;
+
+    public DBGeneratorOptionsView(DBGeneratorOptionsController controller,
+                                  Component tablesView,
+                                  boolean createFK, boolean createPK, boolean 
createTables,
+                                  boolean dropPK, boolean dropTables) {
+
+        // create widgets — set initial state before wiring listeners so we
+        // don't fire spurious refresh events during construction.
         this.createFK = new JCheckBox("Create FK Support");
+        this.createFK.setSelected(createFK);
         this.createPK = new JCheckBox("Create Primary Key Support");
+        this.createPK.setSelected(createPK);
+        this.createTables = new JCheckBox("Create Tables");
+        this.createTables.setSelected(createTables);
         this.dropPK = new JCheckBox("Drop Primary Key Support");
-        this.tables = tables;
-        this.tabs = new JTabbedPane(SwingConstants.TOP);
+        this.dropPK.setSelected(dropPK);
+        this.dropTables = new JCheckBox("Drop Tables");
+        this.dropTables.setSelected(dropTables);
+
+        JButton generateButton = new JButton("Generate");
+        getRootPane().setDefaultButton(generateButton);
+        JButton cancelButton = new JButton("Cancel");
+        JButton saveSqlButton = new JButton("Save SQL");
+
+        JTabbedPane tabs = new JTabbedPane(SwingConstants.TOP);
         this.adapters = new JComboBox<>();
         adapters.setEditable(true);
+        adapters.setModel(new 
DefaultComboBoxModel<>(DbAdapterInfo.getStandardAdapters()));
+        adapters.setSelectedIndex(0);
+
         this.sql = new JTextArea();
         sql.setEditable(false);
         sql.setLineWrap(true);
         sql.setWrapStyleWord(true);
 
-        // assemble...
+        // wire listeners
+        this.createFK.addActionListener(e -> controller.refreshSqlClicked());
+        this.createPK.addActionListener(e -> controller.refreshSqlClicked());
+        this.createTables.addActionListener(e -> 
controller.refreshSqlClicked());
+        this.dropPK.addActionListener(e -> controller.refreshSqlClicked());
+        this.dropTables.addActionListener(e -> controller.refreshSqlClicked());
+
+        adapters.addActionListener(e -> {
+            if (updatingAdapterProgrammatically) return;
+            Object sel = adapters.getSelectedItem();
+            controller.adapterChanged(JDBC_ADAPTER.equals(sel) ? null : 
(String) sel);
+        });
+
+        generateButton.addActionListener(e -> controller.generateClicked());
+        saveSqlButton.addActionListener(e -> controller.saveSqlClicked());
+        cancelButton.addActionListener(e -> controller.cancelClicked());
+
+        // refresh SQL if different tables were selected
+        tabs.addChangeListener(e -> {
+            if (tabs.getSelectedIndex() == 0) {
+                controller.sqlTabSelected();
+            }
+        });
+
+        addWindowListener(new WindowAdapter() {
+            @Override
+            public void windowClosed(WindowEvent e) {
+                controller.windowClosed();
+            }
+        });
+
+        // assemble
         JPanel optionsPane = new JPanel(new GridLayout(3, 2));
-        optionsPane.add(dropTables);
-        optionsPane.add(createTables);
+        optionsPane.add(this.dropTables);
+        optionsPane.add(this.createTables);
         optionsPane.add(new JLabel());
-        optionsPane.add(createFK);
-        optionsPane.add(dropPK);
-        optionsPane.add(createPK);
+        optionsPane.add(this.createFK);
+        optionsPane.add(this.dropPK);
+        optionsPane.add(this.createPK);
 
         JPanel sqlTextPanel = new JPanel(new BorderLayout());
         sqlTextPanel.add(new JScrollPane(
                 sql,
                 ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED), 
BorderLayout.CENTER);
-        
+
         JPanel adapterPanel = new JPanel(new BorderLayout());
         adapterPanel.add(adapters);
 
@@ -115,7 +165,7 @@ public class DBGeneratorOptionsView extends JDialog {
 
         tabs.addTab("SQL Options", builder.getPanel());
         tabs.addTab("Tables", new JScrollPane(
-                tables,
+                tablesView,
                 ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED));
 
@@ -124,60 +174,55 @@ public class DBGeneratorOptionsView extends JDialog {
         tabs.setPreferredSize(new Dimension(450, 500));
         tabs.setFocusable(false);
 
-        JPanel buttons = new JPanel(new FlowLayout(FlowLayout.RIGHT));
-        buttons.add(saveSqlButton);
-        buttons.add(Box.createHorizontalStrut(20));
-        buttons.add(cancelButton);
-        buttons.add(generateButton);
-        buttons.setBorder(TopBorder.create());
+        JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+        buttonsPanel.add(saveSqlButton);
+        buttonsPanel.add(Box.createHorizontalStrut(20));
+        buttonsPanel.add(cancelButton);
+        buttonsPanel.add(generateButton);
+        buttonsPanel.setBorder(TopBorder.create());
 
-        Container contentPane = this.getContentPane();
+        Container contentPane = getContentPane();
         contentPane.setLayout(new BorderLayout());
         contentPane.add(tabs, BorderLayout.CENTER);
-        contentPane.add(buttons, BorderLayout.SOUTH);
+        contentPane.add(buttonsPanel, BorderLayout.SOUTH);
     }
 
-    public JButton getCancelButton() {
-        return cancelButton;
+    public void setSqlPreview(String sql) {
+        this.sql.setText(sql);
     }
 
-    public JTabbedPane getTabs() {
-        return tabs;
+    public void selectAdapter(String adapter) {
+        String display = adapter != null ? adapter : JDBC_ADAPTER;
+        updatingAdapterProgrammatically = true;
+        try {
+            adapters.setSelectedItem(display);
+        } finally {
+            updatingAdapterProgrammatically = false;
+        }
     }
 
-    public JCheckBox getCreateFK() {
-        return createFK;
+    public String getSelectedAdapter() {
+        Object sel = adapters.getSelectedItem();
+        return sel != null ? sel.toString() : null;
     }
 
-    public JCheckBox getCreatePK() {
-        return createPK;
+    public boolean isCreateFkSelected() {
+        return createFK.isSelected();
     }
 
-    public JCheckBox getCreateTables() {
-        return createTables;
+    public boolean isCreatePkSelected() {
+        return createPK.isSelected();
     }
 
-    public JCheckBox getDropPK() {
-        return dropPK;
+    public boolean isCreateTablesSelected() {
+        return createTables.isSelected();
     }
 
-    public JCheckBox getDropTables() {
-        return dropTables;
+    public boolean isDropPkSelected() {
+        return dropPK.isSelected();
     }
 
-    public JButton getGenerateButton() {
-        return generateButton;
-    }
-
-    public JButton getSaveSqlButton() {
-        return saveSqlButton;
-    }
-
-    public JTextArea getSql() {
-        return sql;
-    }
-    
-    public JComboBox<String> getAdapters() {
-        return adapters;
+    public boolean isDropTablesSelected() {
+        return dropTables.isSelected();
     }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorPrefs.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorPrefs.java
index 2d624c348..35dbb2270 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorPrefs.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorPrefs.java
@@ -22,15 +22,10 @@ import org.apache.cayenne.modeler.pref.PreferenceAdapter;
 import org.apache.cayenne.modeler.pref.PreferencesRepository;
 import org.apache.cayenne.project.Project;
 
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
 import java.util.prefs.Preferences;
 
 /**
- * Binds the DB Generator dialog's checkboxes to {@link Preferences}: seeds the
- * checkboxes from prefs on {@link #bind} and writes them back when the dialog 
window
- * closes. Holds no state of its own — the view is the source of truth while 
the dialog
- * is open.
+ * Persistence for the DB Generator dialog's checkbox options.
  */
 public class DBGeneratorPrefs implements PreferenceAdapter {
 
@@ -52,22 +47,32 @@ public class DBGeneratorPrefs implements PreferenceAdapter {
         this.prefs = prefs;
     }
 
-    public void bind(DBGeneratorOptionsView view) {
-        view.getCreateFK().setSelected(prefs.getBoolean(CREATE_FK_PROPERTY, 
true));
-        view.getCreatePK().setSelected(prefs.getBoolean(CREATE_PK_PROPERTY, 
true));
-        
view.getCreateTables().setSelected(prefs.getBoolean(CREATE_TABLES_PROPERTY, 
true));
-        view.getDropPK().setSelected(prefs.getBoolean(DROP_PK_PROPERTY, 
false));
-        
view.getDropTables().setSelected(prefs.getBoolean(DROP_TABLES_PROPERTY, false));
+    public boolean getCreateFK() {
+        return prefs.getBoolean(CREATE_FK_PROPERTY, true);
+    }
+
+    public boolean getCreatePK() {
+        return prefs.getBoolean(CREATE_PK_PROPERTY, true);
+    }
+
+    public boolean getCreateTables() {
+        return prefs.getBoolean(CREATE_TABLES_PROPERTY, true);
+    }
+
+    public boolean getDropPK() {
+        return prefs.getBoolean(DROP_PK_PROPERTY, false);
+    }
+
+    public boolean getDropTables() {
+        return prefs.getBoolean(DROP_TABLES_PROPERTY, false);
+    }
 
-        view.addWindowListener(new WindowAdapter() {
-            @Override
-            public void windowClosed(WindowEvent e) {
-                prefs.putBoolean(CREATE_FK_PROPERTY, 
view.getCreateFK().isSelected());
-                prefs.putBoolean(CREATE_PK_PROPERTY, 
view.getCreatePK().isSelected());
-                prefs.putBoolean(CREATE_TABLES_PROPERTY, 
view.getCreateTables().isSelected());
-                prefs.putBoolean(DROP_PK_PROPERTY, 
view.getDropPK().isSelected());
-                prefs.putBoolean(DROP_TABLES_PROPERTY, 
view.getDropTables().isSelected());
-            }
-        });
+    public void save(boolean createFK, boolean createPK, boolean createTables,
+                     boolean dropPK, boolean dropTables) {
+        prefs.putBoolean(CREATE_FK_PROPERTY, createFK);
+        prefs.putBoolean(CREATE_PK_PROPERTY, createPK);
+        prefs.putBoolean(CREATE_TABLES_PROPERTY, createTables);
+        prefs.putBoolean(DROP_PK_PROPERTY, dropPK);
+        prefs.putBoolean(DROP_TABLES_PROPERTY, dropTables);
     }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/TableSelectorController.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/TableSelectorController.java
index 53e325943..ae1d68b20 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/TableSelectorController.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/TableSelectorController.java
@@ -25,13 +25,11 @@ import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.DbRelationship;
 import org.apache.cayenne.modeler.ui.project.ProjectController;
 import org.apache.cayenne.modeler.mvc.ChildController;
-import org.apache.cayenne.modeler.toolkit.table.TableSizer;
 import org.apache.cayenne.project.Project;
 import org.apache.cayenne.project.validation.ProjectValidator;
 import org.apache.cayenne.validation.ValidationFailure;
 import org.apache.cayenne.validation.ValidationResult;
 
-import javax.swing.table.AbstractTableModel;
 import java.awt.*;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -41,11 +39,7 @@ import java.util.Map;
 
 public class TableSelectorController extends 
ChildController<ProjectController> {
 
-    private static final String[] COLUMN_HEADERS = {"", "Table", "Problems"};
-    private static final Class<?>[] COLUMN_CLASSES = {Boolean.class, 
String.class, String.class};
-
-    protected TableSelectorView view;
-    protected AbstractTableModel tableModel;
+    protected final TableSelectorView view;
 
     protected List<DbEntity> tables;
     protected int permanentlyExcludedCount;
@@ -55,11 +49,10 @@ public class TableSelectorController extends 
ChildController<ProjectController>
 
     public TableSelectorController(ProjectController parent) {
         super(parent);
-        this.view = new TableSelectorView();
         this.excludedTables = new HashMap<>();
         this.selectableTablesList = new ArrayList<>();
         this.validationMessages = new HashMap<>();
-        initController();
+        this.view = new TableSelectorView(this);
     }
 
     public Component getView() {
@@ -94,38 +87,12 @@ public class TableSelectorController extends 
ChildController<ProjectController>
     public void tableSelectedAction() {
         int unselectedCount = excludedTables.size() - permanentlyExcludedCount;
         if (unselectedCount == selectableTablesList.size()) {
-            view.getCheckAll().setSelected(false);
+            view.setCheckAll(false);
         } else if (unselectedCount == 0) {
-            view.getCheckAll().setSelected(true);
+            view.setCheckAll(true);
         }
     }
 
-    protected void initController() {
-        view.getCheckAll().addActionListener(e -> checkAllAction());
-
-        tableModel = new AbstractTableModel() {
-            public int getRowCount() { return tables != null ? tables.size() : 
0; }
-            public int getColumnCount() { return COLUMN_HEADERS.length; }
-            public String getColumnName(int col) { return COLUMN_HEADERS[col]; 
}
-            public Class<?> getColumnClass(int col) { return 
COLUMN_CLASSES[col]; }
-            public boolean isCellEditable(int row, int col) { return col == 0; 
}
-
-            public Object getValueAt(int row, int col) {
-                DbEntity entity = tables.get(row);
-                if (col == 0) return isIncluded(entity);
-                if (col == 1) return entity.getName();
-                return getProblem(entity);
-            }
-
-            public void setValueAt(Object value, int row, int col) {
-                if (col == 0) setIncluded(tables.get(row), (Boolean) value);
-            }
-        };
-
-        view.getTables().setModel(tableModel);
-        TableSizer.sizeColumns(view.getTables(), Boolean.TRUE, 
"XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
-    }
-
     public void updateTables(Collection<DataMap> dataMaps) {
         this.tables = new ArrayList<>();
         for (DataMap dataMap : dataMaps) {
@@ -168,14 +135,12 @@ public class TableSelectorController extends 
ChildController<ProjectController>
             }
         }
 
-        tableModel.fireTableDataChanged();
+        view.tablesChanged();
         tableSelectedAction();
     }
 
-    public void checkAllAction() {
-        boolean isCheckAllSelected = view.getCheckAll().isSelected();
-
-        if (isCheckAllSelected) {
+    void checkAllClicked(boolean isSelected) {
+        if (isSelected) {
             selectableTablesList.clear();
             selectableTablesList.addAll(tables);
             excludedTables.clear();
@@ -187,7 +152,6 @@ public class TableSelectorController extends 
ChildController<ProjectController>
             selectableTablesList.clear();
         }
 
-        tableModel.fireTableDataChanged();
+        view.tablesChanged();
     }
-
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/TableSelectorView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/TableSelectorView.java
index 6dd24eaad..bd2fc95b4 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/TableSelectorView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/TableSelectorView.java
@@ -22,21 +22,28 @@ package org.apache.cayenne.modeler.ui.dbgen;
 import com.jgoodies.forms.builder.PanelBuilder;
 import com.jgoodies.forms.layout.CellConstraints;
 import com.jgoodies.forms.layout.FormLayout;
+import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.modeler.toolkit.table.CMTable;
+import org.apache.cayenne.modeler.toolkit.table.TableSizer;
 
 import javax.swing.*;
+import javax.swing.table.AbstractTableModel;
 import java.awt.*;
 
 public class TableSelectorView extends JPanel {
 
-    private final JTable tables;
+    private static final String[] COLUMN_HEADERS = {"", "Table", "Problems"};
+    private static final Class<?>[] COLUMN_CLASSES = {Boolean.class, 
String.class, String.class};
+
     private final JCheckBox checkAll;
-    private final JLabel checkAllLabel;
+    private final TableSelectorTableModel tableModel;
 
-    public TableSelectorView() {
+    public TableSelectorView(TableSelectorController controller) {
 
         this.checkAll = new JCheckBox();
-        this.checkAllLabel = new JLabel("Check All Tables");
+        this.tableModel = new TableSelectorTableModel(controller);
+
+        JLabel checkAllLabel = new JLabel("Check All Tables");
 
         checkAll.addItemListener(event -> {
             if (checkAll.isSelected()) {
@@ -45,16 +52,19 @@ public class TableSelectorView extends JPanel {
                 checkAllLabel.setText("Check All Tables");
             }
         });
+        checkAll.addActionListener(e -> 
controller.checkAllClicked(checkAll.isSelected()));
+
+        JTable tables = new CMTable();
+        tables.setRowHeight(25);
+        tables.setRowMargin(3);
+        tables.setModel(tableModel);
+        TableSizer.sizeColumns(tables, Boolean.TRUE, "XXXXXXXXXXXXXXXX", 
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
 
         // assemble
         JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
         topPanel.add(checkAll);
         topPanel.add(checkAllLabel);
 
-        tables = new CMTable();
-        tables.setRowHeight(25);
-        tables.setRowMargin(3);
-
         CellConstraints cc = new CellConstraints();
         PanelBuilder builder = new PanelBuilder(new FormLayout(
                 "fill:min(50dlu;pref):grow",
@@ -71,11 +81,60 @@ public class TableSelectorView extends JPanel {
         add(builder.getPanel(), BorderLayout.CENTER);
     }
 
-    public JTable getTables() {
-        return tables;
+    public void tablesChanged() {
+        tableModel.fireTableDataChanged();
+    }
+
+    public void setCheckAll(boolean selected) {
+        checkAll.setSelected(selected);
     }
 
-    public JCheckBox getCheckAll() {
-        return checkAll;
+    private static class TableSelectorTableModel extends AbstractTableModel {
+
+        private final TableSelectorController controller;
+
+        TableSelectorTableModel(TableSelectorController controller) {
+            this.controller = controller;
+        }
+
+        @Override
+        public int getRowCount() {
+            return controller.getTables() != null ? 
controller.getTables().size() : 0;
+        }
+
+        @Override
+        public int getColumnCount() {
+            return COLUMN_HEADERS.length;
+        }
+
+        @Override
+        public String getColumnName(int col) {
+            return COLUMN_HEADERS[col];
+        }
+
+        @Override
+        public Class<?> getColumnClass(int col) {
+            return COLUMN_CLASSES[col];
+        }
+
+        @Override
+        public boolean isCellEditable(int row, int col) {
+            return col == 0;
+        }
+
+        @Override
+        public Object getValueAt(int row, int col) {
+            DbEntity entity = controller.getTables().get(row);
+            if (col == 0) return controller.isIncluded(entity);
+            if (col == 1) return entity.getName();
+            return controller.getProblem(entity);
+        }
+
+        @Override
+        public void setValueAt(Object value, int row, int col) {
+            if (col == 0) {
+                controller.setIncluded(controller.getTables().get(row), 
(Boolean) value);
+            }
+        }
     }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/PreferenceDialogController.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/PreferenceDialogController.java
index 1802b27e8..b99577e18 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/PreferenceDialogController.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/PreferenceDialogController.java
@@ -51,7 +51,7 @@ public class PreferenceDialogController extends 
ChildController<RootController>
     private final ClasspathPreferencesController classpathPrefsController;
     private final MorePreferencesController allPrefsController;
 
-    public PreferenceDialogController(final RootController parent) {
+    public PreferenceDialogController(RootController parent) {
         super(parent);
 
         Window parentView = parent.getView() instanceof Window
@@ -59,44 +59,35 @@ public class PreferenceDialogController extends 
ChildController<RootController>
                 : SwingUtilities.getWindowAncestor(parent.getView());
 
         this.view = (parentView instanceof Dialog)
-                ? new PreferenceDialogView((Dialog) parentView)
-                : new PreferenceDialogView((Frame) parentView);
+                ? new PreferenceDialogView(this, (Dialog) parentView)
+                : new PreferenceDialogView(this, (Frame) parentView);
 
-        JList<String> list = view.getList();
-        list.setListData(preferenceMenus);
-        list.addListSelectionListener(e -> updateSelection());
-        view.sizeListToLabels();
-
-        view.getCancelButton().addActionListener(e -> cancelAction());
-        view.getSaveButton().addActionListener(e -> savePreferencesAction());
+        view.setMenuItems(preferenceMenus);
 
         this.generalPrefsController = new GeneralPreferencesController(this);
-        view.getDetailPanel().add(generalPrefsController.getView(), 
GENERAL_KEY);
+        view.addCard(GENERAL_KEY, generalPrefsController.getView());
 
         this.dbConnectorPrefsController = new 
DBConnectorPreferencesController(this);
-        view.getDetailPanel().add(dbConnectorPrefsController.getView(), 
DB_CONNECTORS_KEY);
+        view.addCard(DB_CONNECTORS_KEY, dbConnectorPrefsController.getView());
 
         this.classpathPrefsController = new 
ClasspathPreferencesController(this);
-        view.getDetailPanel().add(classpathPrefsController.getView(), 
CLASSPATH_KEY);
+        view.addCard(CLASSPATH_KEY, classpathPrefsController.getView());
 
         this.allPrefsController = new MorePreferencesController(this);
-        view.getDetailPanel().add(allPrefsController.getView(), MORE_KEY);
+        view.addCard(MORE_KEY, allPrefsController.getView());
     }
 
-    public void updateSelection() {
-        final String selection = view.getList().getSelectedValue();
-        if (selection != null) {
-            view.getDetailLayout().show(view.getDetailPanel(), selection);
-            lastSelectedCard = selection;
-        }
+    void cardSelected(String name) {
+        lastSelectedCard = name;
+        view.showCard(name);
     }
 
-    private void cancelAction() {
+    void cancelClicked() {
         dbConnectorPrefsController.discard();
         view.dispose();
     }
 
-    private void savePreferencesAction() {
+    void saveClicked() {
         dbConnectorPrefsController.commit();
         generalPrefsController.commit();
         classpathPrefsController.commit();
@@ -131,7 +122,7 @@ public class PreferenceDialogController extends 
ChildController<RootController>
     }
 
     private void doShow(String cardKey, ChildController<?> childController) {
-        view.getDetailLayout().show(view.getDetailPanel(), GENERAL_KEY);
+        view.showCard(GENERAL_KEY);
         view.pack();
 
         centerView();
@@ -140,8 +131,7 @@ public class PreferenceDialogController extends 
ChildController<RootController>
         view.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
         view.setModalityType(Dialog.ModalityType.MODELESS);
 
-        view.getDetailLayout().show(view.getDetailPanel(), cardKey);
-        view.getList().setSelectedValue(cardKey, true);
+        view.showCard(cardKey);
         childController.getView().setEnabled(true);
         view.setVisible(true);
     }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/PreferenceDialogView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/PreferenceDialogView.java
index e8716cfd9..06343e10f 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/PreferenceDialogView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/PreferenceDialogView.java
@@ -49,25 +49,30 @@ public class PreferenceDialogView extends JDialog {
     private static final int LIST_MIN_WIDTH = 120;
     private static final int LIST_HEIGHT = 400;
 
-    protected JList<String> list;
-    protected JPanel leftContainer;
-    protected CardLayout detailLayout;
-    protected Container detailPanel;
-    protected JButton cancelButton;
-    protected JButton saveButton;
-
-    public PreferenceDialogView(Dialog parent) {
+    private final JList<String> list;
+    private final JPanel leftContainer;
+    private final CardLayout detailLayout;
+    private final Container detailPanel;
+
+    public PreferenceDialogView(PreferenceDialogController controller, Dialog 
parent) {
         super(parent);
-        init();
+        this.list = new JList<>();
+        this.detailLayout = new CardLayout();
+        this.detailPanel = new JPanel(detailLayout);
+        this.leftContainer = new JPanel(new BorderLayout());
+        init(controller);
     }
 
-    public PreferenceDialogView(Frame parent) {
+    public PreferenceDialogView(PreferenceDialogController controller, Frame 
parent) {
         super(parent);
-        init();
+        this.list = new JList<>();
+        this.detailLayout = new CardLayout();
+        this.detailPanel = new JPanel(detailLayout);
+        this.leftContainer = new JPanel(new BorderLayout());
+        init(controller);
     }
 
-    private void init() {
-        list = new JList<>();
+    private void init(PreferenceDialogController controller) {
         list.setCellRenderer(new DefaultListCellRenderer() {
             @Override
             public Component getListCellRendererComponent(JList list, Object 
value, int index, boolean isSelected, boolean cellHasFocus) {
@@ -77,14 +82,20 @@ public class PreferenceDialogView extends JDialog {
             }
         });
         list.setFont(new JLabel().getFont().deriveFont(Font.BOLD, 12));
-        detailLayout = new CardLayout();
-        detailPanel = new JPanel(detailLayout);
-        saveButton = new JButton("Save");
-        cancelButton = new JButton("Cancel");
 
-        // assemble
+        list.addListSelectionListener(e -> {
+            String selection = list.getSelectedValue();
+            if (selection != null) {
+                controller.cardSelected(selection);
+            }
+        });
+
+        JButton saveButton = new JButton("Save");
+        JButton cancelButton = new JButton("Cancel");
+
+        cancelButton.addActionListener(e -> controller.cancelClicked());
+        saveButton.addActionListener(e -> controller.saveClicked());
 
-        leftContainer = new JPanel(new BorderLayout());
         JScrollPane scrollPane = new JScrollPane(list);
         scrollPane.setBorder(BorderFactory.createEmptyBorder());
         leftContainer.add(scrollPane);
@@ -108,11 +119,21 @@ public class PreferenceDialogView extends JDialog {
         setTitle("Edit Preferences");
     }
 
-    /**
-     * Sets the left list to a fixed width that fits the longest label. This
-     * keeps labels fully visible regardless of how the user resizes the 
dialog.
-     */
-    public void sizeListToLabels() {
+    public void setMenuItems(String[] items) {
+        list.setListData(items);
+        sizeListToLabels();
+    }
+
+    public void addCard(String name, Component card) {
+        detailPanel.add(card, name);
+    }
+
+    public void showCard(String name) {
+        detailLayout.show(detailPanel, name);
+        list.setSelectedValue(name, true);
+    }
+
+    private void sizeListToLabels() {
         FontMetrics fm = list.getFontMetrics(list.getFont());
         int maxText = 0;
         for (int i = 0; i < list.getModel().getSize(); i++) {
@@ -122,24 +143,4 @@ public class PreferenceDialogView extends JDialog {
         leftContainer.setPreferredSize(new Dimension(width, LIST_HEIGHT));
         leftContainer.setMinimumSize(new Dimension(width, 0));
     }
-
-    public JList<String> getList() {
-        return list;
-    }
-
-    public Container getDetailPanel() {
-        return detailPanel;
-    }
-
-    public CardLayout getDetailLayout() {
-        return detailLayout;
-    }
-
-    public JButton getCancelButton() {
-        return cancelButton;
-    }
-
-    public JButton getSaveButton() {
-        return saveButton;
-    }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/ClasspathPreferencesController.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/ClasspathPreferencesController.java
index 01222a41a..ad5b4fb1b 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/ClasspathPreferencesController.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/ClasspathPreferencesController.java
@@ -28,7 +28,6 @@ import org.apache.cayenne.modeler.util.FileFilters;
 
 import javax.swing.*;
 import javax.swing.filechooser.FileFilter;
-import javax.swing.table.AbstractTableModel;
 import java.awt.*;
 import java.io.File;
 import java.util.ArrayList;
@@ -37,67 +36,42 @@ import java.util.List;
 public class ClasspathPreferencesController extends 
ChildController<PreferenceDialogController> {
 
     private final ClasspathPreferencesView view;
-    private final List<String> classPathEntries;
-    private final ClasspathTableModel tableModel;
+    private final List<String> entries;
 
     public ClasspathPreferencesController(PreferenceDialogController parent) {
         super(parent);
 
-        this.view = new ClasspathPreferencesView();
-        this.classPathEntries = new 
ArrayList<>(ClasspathPrefs.of(getApplication().getPreferencesRepository()).getEntries());
-        this.tableModel = new ClasspathTableModel(classPathEntries);
-
-        initBindings();
+        this.entries = new 
ArrayList<>(ClasspathPrefs.of(getApplication().getPreferencesRepository()).getEntries());
+        this.view = new ClasspathPreferencesView(this);
     }
 
+    @Override
     public Component getView() {
         return view;
     }
 
     public List<String> getEntries() {
-        return classPathEntries;
+        return entries;
     }
 
-    /**
-     * Flushes the working snapshot to {@link ClasspathPrefs} and refreshes the
-     * Modeler classloader. Called on dialog Save.
-     */
     public void commit() {
-        
ClasspathPrefs.of(getApplication().getPreferencesRepository()).setEntries(classPathEntries);
+        
ClasspathPrefs.of(getApplication().getPreferencesRepository()).setEntries(entries);
         getApplication().refreshClassLoader();
     }
 
-    protected void initBindings() {
-        view.getTable().setModel(tableModel);
-        view.getAddDirButton().addActionListener(e -> 
addClassDirectoryAction());
-        view.getAddJarButton().addActionListener(e -> addJarAction());
-        view.getAddMvnButton().addActionListener(e -> 
addMvnDependencyAction());
-        view.getDeleteEntryButton().addActionListener(e -> 
removeEntryAction());
-    }
-
-    protected void addJarAction() {
+    void addJarClicked() {
         chooseClassEntry(FileFilters.getExtensionFileFilter("jar", "JAR 
Files"), "Select JAR File.", JFileChooser.FILES_ONLY);
     }
 
-    protected void addClassDirectoryAction() {
+    void addClassDirectoryClicked() {
         chooseClassEntry(null, "Select Java Class Directory.", 
JFileChooser.DIRECTORIES_ONLY);
     }
 
-    protected void addMvnDependencyAction() {
+    void addMvnDependencyClicked() {
         MavenDependencyDialogController dialog = new 
MavenDependencyDialogController(this);
         dialog.getView().setVisible(true);
     }
 
-    protected synchronized void removeEntryAction() {
-        int selected = view.getTable().getSelectedRow();
-        if (selected < 0) {
-            return;
-        }
-
-        classPathEntries.remove(selected);
-        tableModel.fireTableRowsDeleted(selected, selected);
-    }
-
     protected void chooseClassEntry(FileFilter filter, String title, int 
selectionMode) {
         JFileChooser chooser = new JFileChooser();
         chooser.setFileSelectionMode(selectionMode);
@@ -117,45 +91,26 @@ public class ClasspathPreferencesController extends 
ChildController<PreferenceDi
             selected = chooser.getSelectedFile();
         }
 
-        addClasspathEntry(selected);
+        entryAdded(selected);
     }
 
-    public synchronized void addClasspathEntry(File selected) {
-        if (selected == null) {
-            return;
-        }
-        String path = selected.getAbsolutePath();
-        if (classPathEntries.contains(path)) {
-            return;
+    public void entryRemoved(int selectedRow) {
+        if (selectedRow >= 0) {
+            entries.remove(selectedRow);
         }
-
-        int len = classPathEntries.size();
-        classPathEntries.add(path);
-        tableModel.fireTableRowsInserted(len, len);
     }
 
-    static class ClasspathTableModel extends AbstractTableModel {
-
-        private final List<String> classPathEntries;
-
-        ClasspathTableModel(List<String> classPathEntries) {
-            this.classPathEntries = classPathEntries;
-        }
-
-        public int getColumnCount() {
-            return 1;
-        }
-
-        public int getRowCount() {
-            return classPathEntries.size();
+    public void entryAdded(File selected) {
+        if (selected == null) {
+            return;
         }
 
-        public Object getValueAt(int rowIndex, int columnIndex) {
-            return classPathEntries.get(rowIndex);
+        String path = selected.getAbsolutePath();
+        if (entries.contains(path)) {
+            return;
         }
 
-        public String getColumnName(int column) {
-            return "Custom ClassPath";
-        }
+        entries.add(path);
+        view.entryAdded();
     }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/ClasspathPreferencesView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/ClasspathPreferencesView.java
index b92d077ce..d2d94bf35 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/ClasspathPreferencesView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/ClasspathPreferencesView.java
@@ -26,31 +26,33 @@ import com.jgoodies.forms.layout.FormLayout;
 import org.apache.cayenne.modeler.toolkit.table.CMTable;
 
 import javax.swing.*;
+import javax.swing.table.AbstractTableModel;
 import java.awt.*;
 
 
 public class ClasspathPreferencesView extends JPanel {
 
-    private final JButton addJarButton;
-    private final JButton addDirButton;
-    private final JButton addMvnButton;
-    private final JButton deleteEntryButton;
-    private final JTable table;
+    private final ClasspathTableModel tableModel;
 
-    public ClasspathPreferencesView() {
+    public ClasspathPreferencesView(ClasspathPreferencesController controller) 
{
 
-        // create widgets
-        addJarButton = new JButton("Add Jar");
-        addDirButton = new JButton("Add Class Folder");
-        addMvnButton = new JButton("Get From Maven Central");
-        deleteEntryButton = new JButton("Delete");
+        this.tableModel = new ClasspathTableModel(controller);
 
-        table = new CMTable();
+        JButton addJarButton = new JButton("Add Jar");
+        JButton addDirButton = new JButton("Add Class Folder");
+        JButton addMvnButton = new JButton("Get From Maven Central");
+        JButton deleteEntryButton = new JButton("Delete");
+
+        JTable table = new CMTable();
         table.setRowMargin(3);
         table.setRowHeight(25);
         table.setTableHeader(null);
+        table.setModel(tableModel);
 
-        // assemble
+        addJarButton.addActionListener(e -> controller.addJarClicked());
+        addDirButton.addActionListener(e -> 
controller.addClassDirectoryClicked());
+        addMvnButton.addActionListener(e -> 
controller.addMvnDependencyClicked());
+        deleteEntryButton.addActionListener(e -> 
removeEntryClicked(controller, table, tableModel));
 
         DefaultFormBuilder sidebar = new DefaultFormBuilder(
                 new FormLayout("fill:min(150dlu;pref)", ""));
@@ -78,23 +80,48 @@ public class ClasspathPreferencesView extends JPanel {
         add(outer.getPanel(), BorderLayout.CENTER);
     }
 
-    public JButton getAddDirButton() {
-        return addDirButton;
-    }
+    public void entryAdded() {
+        int len = tableModel.getRowCount();
 
-    public JButton getAddJarButton() {
-        return addJarButton;
+        tableModel.fireTableRowsInserted(len, len);
     }
 
-    public JButton getAddMvnButton() {
-        return addMvnButton;
-    }
+    private void removeEntryClicked(ClasspathPreferencesController controller, 
JTable table, AbstractTableModel tableModel) {
+        int selectedRow = table.getSelectedRow();
+        if (selectedRow < 0) {
+            return;
+        }
 
-    public JButton getDeleteEntryButton() {
-        return deleteEntryButton;
+        controller.entryRemoved(selectedRow);
+        tableModel.fireTableRowsDeleted(selectedRow, selectedRow);
     }
 
-    public JTable getTable() {
-        return table;
+    private static class ClasspathTableModel extends AbstractTableModel {
+
+        private final ClasspathPreferencesController controller;
+
+        ClasspathTableModel(ClasspathPreferencesController controller) {
+            this.controller = controller;
+        }
+
+        @Override
+        public int getColumnCount() {
+            return 1;
+        }
+
+        @Override
+        public int getRowCount() {
+            return controller.getEntries().size();
+        }
+
+        @Override
+        public Object getValueAt(int rowIndex, int columnIndex) {
+            return controller.getEntries().get(rowIndex);
+        }
+
+        @Override
+        public String getColumnName(int column) {
+            return "Custom ClassPath";
+        }
     }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/maven/MavenDependencyDialogController.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/maven/MavenDependencyDialogController.java
index 1181160dd..cf8f322b3 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/maven/MavenDependencyDialogController.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/maven/MavenDependencyDialogController.java
@@ -46,61 +46,50 @@ public class MavenDependencyDialogController extends 
ChildController<ClasspathPr
     private volatile boolean closing;
 
     public MavenDependencyDialogController(ClasspathPreferencesController 
preferencesController) {
-
         super(preferencesController);
 
         Window parentView = preferencesController.getView() instanceof Window
                 ? (Window) preferencesController.getView()
                 : 
SwingUtilities.getWindowAncestor(preferencesController.getView());
-        if (parentView instanceof Dialog) {
-            view = new MavenDependencyDialogView((Dialog) parentView);
-        } else {
-            view = new MavenDependencyDialogView((Frame) parentView);
-        }
-        initBindings();
-    }
-
-    private void initBindings() {
-        view.getDownloadButton().addActionListener(e -> loadArtifact());
-        view.getCancelButton().addActionListener(e -> close());
+        this.view = (parentView instanceof Dialog)
+                ? new MavenDependencyDialogView((Dialog) parentView, this)
+                : new MavenDependencyDialogView((Frame) parentView, this);
     }
 
-    private void loadArtifact() {
+    void downloadClicked(String groupId, String artifactId, String version) {
         // url template: 
https://repo1.maven.org/maven2/org/apache/cayenne/cayenne-server/4.2.M1/cayenne-server-4.2.M1.jar
-        String groupPath = view.getGroupId().getText().replace('.', 
'/').trim();
-        String artifactIdText = view.getArtifactId().getText().trim();
-        String versionText = view.getVersion().getText().trim();
+        String groupPath = groupId.replace('.', '/');
 
         if (groupPath.isEmpty()) {
             JOptionPane.showMessageDialog(view, "Empty group Id", "Warning", 
JOptionPane.WARNING_MESSAGE);
             return;
         }
 
-        if (artifactIdText.isEmpty()) {
+        if (artifactId.isEmpty()) {
             JOptionPane.showMessageDialog(view, "Empty artifact Id", 
"Warning", JOptionPane.WARNING_MESSAGE);
             return;
         }
 
-        if (versionText.isEmpty()) {
+        if (version.isEmpty()) {
             JOptionPane.showMessageDialog(view, "Empty version", "Warning", 
JOptionPane.WARNING_MESSAGE);
             return;
         }
 
         String urlText = "https://repo1.maven.org/maven2/"; + groupPath + "/"
-                + artifactIdText + "/" + versionText + "/"
-                + artifactIdText + "-" + versionText + ".jar";
+                + artifactId + "/" + version + "/"
+                + artifactId + "-" + version + ".jar";
 
         application.getFrameController().updateStatus("Loading " + urlText);
 
         String localPath = System.getProperty("user.home") + 
"/.cayenne/modeler/"
-                + groupPath + "/" + artifactIdText + "-" + versionText + 
".jar";
+                + groupPath + "/" + artifactId + "-" + version + ".jar";
         File targetFile = new File(localPath);
 
-        view.getDownloadButton().setEnabled(false);
+        view.setDownloadEnabled(false);
         new Thread(() -> download(urlText, targetFile)).start();
     }
 
-    private void close() {
+    void cancelClicked() {
         this.closing = true;
         view.close();
     }
@@ -130,16 +119,16 @@ public class MavenDependencyDialogController extends 
ChildController<ClasspathPr
     private void finalizeDownload(File dstFile, String status, boolean 
success, boolean shouldClose) {
         SwingUtilities.invokeLater(() -> {
             if (success) {
-                parent.addClasspathEntry(dstFile);
+                parent.entryAdded(dstFile);
             } else {
                 JOptionPane.showMessageDialog(view, status, "Error", 
JOptionPane.ERROR_MESSAGE);
             }
 
-            view.getDownloadButton().setEnabled(true);
+            view.setDownloadEnabled(true);
             application.getFrameController().updateStatus(status);
 
             if (shouldClose) {
-                close();
+                cancelClicked();
             }
         });
     }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/maven/MavenDependencyDialogView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/maven/MavenDependencyDialogView.java
index 9b382b5de..7e8f25bc9 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/maven/MavenDependencyDialogView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/maven/MavenDependencyDialogView.java
@@ -30,61 +30,59 @@ import java.awt.*;
 
 public class MavenDependencyDialogView extends CMDialog {
 
-    private JButton downloadButton;
-    private JButton cancelButton;
-    private JTextField groupId;
-    private JTextField artifactId;
-    private JTextField version;
-
-    public MavenDependencyDialogView(Dialog parentDialog) {
-        super(parentDialog, "Download artifact", true);
-        this.initView();
-        this.pack();
+    private final JButton downloadButton;
+
+    public MavenDependencyDialogView(Dialog parent, 
MavenDependencyDialogController controller) {
+        super(parent, "Download artifact", true);
+        this.downloadButton = init(controller);
+        pack();
         centerWindow();
     }
 
-    public MavenDependencyDialogView(Frame parentFrame) {
-        super(parentFrame, "Download artifact", true);
-        this.initView();
-        this.pack();
+    public MavenDependencyDialogView(Frame parent, 
MavenDependencyDialogController controller) {
+        super(parent, "Download artifact", true);
+        this.downloadButton = init(controller);
+        pack();
         centerWindow();
     }
 
-    private void initView() {
+    private JButton init(MavenDependencyDialogController controller) {
         getContentPane().setLayout(new BorderLayout());
 
-        {
-            groupId = new JTextField(25);
-            artifactId = new JTextField(25);
-            version = new JTextField(25);
+        JTextField groupId = new JTextField(25);
+        JTextField artifactId = new JTextField(25);
+        JTextField version = new JTextField(25);
+
+        CellConstraints cc = new CellConstraints();
+        PanelBuilder builder = new PanelBuilder(
+                new FormLayout(
+                        "right:max(50dlu;pref), 3dlu, fill:min(100dlu;pref)",
+                        "p, 3dlu, p, 3dlu, p, 3dlu"));
+        builder.setDefaultDialogBorder();
 
-            CellConstraints cc = new CellConstraints();
-            PanelBuilder builder = new PanelBuilder(
-                    new FormLayout(
-                            "right:max(50dlu;pref), 3dlu, 
fill:min(100dlu;pref)",
-                            "p, 3dlu, p, 3dlu, p, 3dlu"
-                    ));
-            builder.setDefaultDialogBorder();
+        builder.addLabel("group id:", cc.xy(1, 1));
+        builder.add(groupId, cc.xy(3, 1));
 
-            builder.addLabel("group id:", cc.xy(1, 1));
-            builder.add(groupId, cc.xy(3, 1));
+        builder.addLabel("artifact id:", cc.xy(1, 3));
+        builder.add(artifactId, cc.xy(3, 3));
 
-            builder.addLabel("artifact id:", cc.xy(1, 3));
-            builder.add(artifactId, cc.xy(3, 3));
+        builder.addLabel("version:", cc.xy(1, 5));
+        builder.add(version, cc.xy(3, 5));
 
-            builder.addLabel("version:", cc.xy(1, 5));
-            builder.add(version, cc.xy(3, 5));
+        getContentPane().add(builder.getPanel(), BorderLayout.NORTH);
 
-            getContentPane().add(builder.getPanel(), BorderLayout.NORTH);
-        }
+        JButton download = new JButton("Download");
+        JButton cancel = new JButton("Cancel");
+        getRootPane().setDefaultButton(download);
 
-        {
-            downloadButton = new JButton("Download");
-            cancelButton = new JButton("Cancel");
-            getRootPane().setDefaultButton(downloadButton);
+        download.addActionListener(e -> controller.downloadClicked(
+                groupId.getText().trim(),
+                artifactId.getText().trim(),
+                version.getText().trim()));
+        cancel.addActionListener(e -> controller.cancelClicked());
 
-            getContentPane().add(new CMButtonPanel(cancelButton, 
downloadButton), BorderLayout.SOUTH);
-        }
+        getContentPane().add(new CMButtonPanel(cancel, download), 
BorderLayout.SOUTH);
+        return download;
     }
 
     public void close() {
@@ -92,23 +90,7 @@ public class MavenDependencyDialogView extends CMDialog {
         dispose();
     }
 
-    public JButton getCancelButton() {
-        return cancelButton;
-    }
-
-    public JButton getDownloadButton() {
-        return downloadButton;
-    }
-
-    public JTextField getArtifactId() {
-        return artifactId;
-    }
-
-    public JTextField getGroupId() {
-        return groupId;
-    }
-
-    public JTextField getVersion() {
-        return version;
+    public void setDownloadEnabled(boolean enabled) {
+        downloadButton.setEnabled(enabled);
     }
-}
\ No newline at end of file
+}
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectionInfoEditorController.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectionInfoEditorController.java
deleted file mode 100644
index 55834ce69..000000000
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectionInfoEditorController.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-
-package org.apache.cayenne.modeler.ui.preferences.dbconnector;
-
-import org.apache.cayenne.modeler.mvc.ChildController;
-import org.apache.cayenne.modeler.mvc.RootController;
-import org.apache.cayenne.modeler.dbconnector.DBConnector;
-import org.apache.cayenne.modeler.util.DbAdapterInfo;
-
-import javax.swing.*;
-import java.awt.*;
-
-/**
- * A reusable editor for DBConnectionInfo object.
- */
-public class DBConnectionInfoEditorController extends 
ChildController<RootController> {
-
-    // transient placeholder to display disabled form
-    private static final DBConnector emptyInfo = new DBConnector();
-
-    protected DBConnectionInfoEditorView view;
-    protected DBConnector connectionInfo;
-
-    public DBConnectionInfoEditorController(RootController parent) {
-        super(parent);
-
-        this.view = new DBConnectionInfoEditorView();
-        this.view.setEnabled(false);
-
-        DefaultComboBoxModel adapterModel = new 
DefaultComboBoxModel(DbAdapterInfo.getStandardAdapters());
-        view.getAdapters().setModel(adapterModel);
-        view.getAdapters().setSelectedIndex(0);
-
-        view.getUserName().addCommitListener(v -> {
-            if (connectionInfo != null) connectionInfo.setUserName(v);
-        });
-        view.getPassword().addCommitListener(v -> {
-            if (connectionInfo != null) connectionInfo.setPassword(v);
-        });
-        view.getDriver().addCommitListener(v -> {
-            if (connectionInfo != null) connectionInfo.setJdbcDriver(v);
-        });
-        view.getUrl().addCommitListener(v -> {
-            if (connectionInfo != null) connectionInfo.setUrl(v);
-        });
-
-        view.getAdapters().addActionListener(e -> {
-            if (connectionInfo != null) {
-                Object sel = view.getAdapters().getSelectedItem();
-                connectionInfo.setDbAdapter("Automatic".equals(sel) ? null : 
(String) sel);
-            }
-        });
-    }
-
-    @Override
-    public Component getView() {
-        return view;
-    }
-
-    public void setConnectionInfo(DBConnector connectionInfo) {
-        this.connectionInfo = connectionInfo;
-
-        view.setEnabled(connectionInfo != null);
-
-        DBConnector ci = connectionInfo != null ? connectionInfo : emptyInfo;
-        view.getUserName().setText(ci.getUserName());
-        view.getPassword().setText(ci.getPassword());
-        view.getDriver().setText(ci.getJdbcDriver());
-        view.getUrl().setText(ci.getUrl());
-        view.getAdapters().setSelectedItem(ci.getDbAdapter() != null ? 
ci.getDbAdapter() : "Automatic");
-    }
-}
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorEditorController.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorEditorController.java
new file mode 100644
index 000000000..031ba82f9
--- /dev/null
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorEditorController.java
@@ -0,0 +1,79 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.ui.preferences.dbconnector;
+
+import org.apache.cayenne.modeler.mvc.ChildController;
+import org.apache.cayenne.modeler.mvc.RootController;
+import org.apache.cayenne.modeler.dbconnector.DBConnector;
+
+import java.awt.Component;
+
+/**
+ * A reusable editor for DBConnectionInfo object.
+ */
+public class DBConnectorEditorController extends 
ChildController<RootController> {
+
+    private final DBConnectorEditorView view;
+    private DBConnector connector;
+
+    public DBConnectorEditorController(RootController parent) {
+        super(parent);
+        this.view = new DBConnectorEditorView(this);
+    }
+
+    @Override
+    public Component getView() {
+        return view;
+    }
+
+    public void setConnector(DBConnector connector) {
+        this.connector = connector;
+        if (connector == null) {
+            view.clear();
+        } else {
+            view.showConnector(
+                    connector.getUserName(),
+                    connector.getPassword(),
+                    connector.getJdbcDriver(),
+                    connector.getUrl(),
+                    connector.getDbAdapter());
+        }
+    }
+
+    void userNameChanged(String v) {
+        if (connector != null) connector.setUserName(v);
+    }
+
+    void passwordChanged(String v) {
+        if (connector != null) connector.setPassword(v);
+    }
+
+    void driverChanged(String v) {
+        if (connector != null) connector.setJdbcDriver(v);
+    }
+
+    void urlChanged(String v) {
+        if (connector != null) connector.setUrl(v);
+    }
+
+    void adapterChanged(String v) {
+        if (connector != null) connector.setDbAdapter(v);
+    }
+}
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectionInfoEditorView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorEditorView.java
similarity index 54%
rename from 
modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectionInfoEditorView.java
rename to 
modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorEditorView.java
index 9b22de275..64bbf9336 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectionInfoEditorView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorEditorView.java
@@ -19,37 +19,37 @@
 
 package org.apache.cayenne.modeler.ui.preferences.dbconnector;
 
-import java.awt.BorderLayout;
-import java.util.ArrayList;
-import java.util.Collection;
-
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-
 import com.jgoodies.forms.builder.DefaultFormBuilder;
 import com.jgoodies.forms.layout.FormLayout;
 import org.apache.cayenne.modeler.toolkit.text.CMPasswordField;
 import org.apache.cayenne.modeler.toolkit.text.CMTextField;
+import org.apache.cayenne.modeler.util.DbAdapterInfo;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Collection;
 
 /**
  * A generic panel for entering DataSource information.
  */
-public class DBConnectionInfoEditorView extends JPanel {
+public class DBConnectorEditorView extends JPanel {
 
-    protected JComboBox adapters;
-    protected CMTextField driver;
-    protected CMTextField url;
-    protected CMTextField userName;
-    protected CMPasswordField password;
+    private static final String AUTOMATIC = "Automatic";
 
-    protected Collection<JLabel> labels;
+    private final JComboBox<String> adapters;
+    private final CMTextField driver;
+    private final CMTextField url;
+    private final CMTextField userName;
+    private final CMPasswordField password;
 
-    protected DefaultFormBuilder builder;
+    private final Collection<JLabel> labels;
 
-    public DBConnectionInfoEditorView() {
-        adapters = new JComboBox();
+    public DBConnectorEditorView(DBConnectorEditorController controller) {
+        adapters = new JComboBox<>();
         adapters.setEditable(true);
+        adapters.setModel(new 
DefaultComboBoxModel<>(DbAdapterInfo.getStandardAdapters()));
+        adapters.setSelectedIndex(0);
 
         driver = new CMTextField();
         url = new CMTextField();
@@ -57,9 +57,18 @@ public class DBConnectionInfoEditorView extends JPanel {
         password = new CMPasswordField();
         labels = new ArrayList<>();
 
-        // assemble
+        // bindings — controller is captured by lambdas; not stored on the view
+        userName.addCommitListener(controller::userNameChanged);
+        password.addCommitListener(controller::passwordChanged);
+        driver.addCommitListener(controller::driverChanged);
+        url.addCommitListener(controller::urlChanged);
+        adapters.addActionListener(e -> {
+            Object sel = adapters.getSelectedItem();
+            controller.adapterChanged(AUTOMATIC.equals(sel) ? null : (String) 
sel);
+        });
+
         FormLayout layout = new FormLayout("right:pref, 3dlu, 
fill:160dlu:grow", "");
-        builder = new DefaultFormBuilder(layout);
+        DefaultFormBuilder builder = new DefaultFormBuilder(layout);
         builder.setDefaultDialogBorder();
 
         labels.add(builder.append("JDBC Driver:", driver));
@@ -68,44 +77,36 @@ public class DBConnectionInfoEditorView extends JPanel {
         labels.add(builder.append("Password:", password));
         labels.add(builder.append("Adapter (optional):", adapters));
 
-        this.setLayout(new BorderLayout());
-        this.add(builder.getPanel(), BorderLayout.CENTER);
+        setLayout(new BorderLayout());
+        add(builder.getPanel(), BorderLayout.CENTER);
+        setEnabled(false);
     }
 
-    public JComboBox getAdapters() {
-        return adapters;
+    public void showConnector(String userName, String password, String driver, 
String url, String adapter) {
+        this.userName.setText(userName != null ? userName : "");
+        this.password.setText(password != null ? password : "");
+        this.driver.setText(driver != null ? driver : "");
+        this.url.setText(url != null ? url : "");
+        this.adapters.setSelectedItem(adapter != null ? adapter : AUTOMATIC);
+        setEnabled(true);
     }
 
-    public CMTextField getDriver() {
-        return driver;
-    }
-
-    public CMPasswordField getPassword() {
-        return password;
-    }
-
-    public CMTextField getUrl() {
-        return url;
-    }
-
-    public CMTextField getUserName() {
-        return userName;
-    }
-
-    /**
-     * @return Builder of the view (to allow dynamic extending of the 
component)
-     */
-    public DefaultFormBuilder getBuilder() {
-        return builder;
+    public void clear() {
+        userName.setText("");
+        password.setText("");
+        driver.setText("");
+        url.setText("");
+        adapters.setSelectedItem(AUTOMATIC);
+        setEnabled(false);
     }
 
+    @Override
     public void setEnabled(boolean enabled) {
         if (isEnabled() != enabled) {
             super.setEnabled(enabled);
             for (JLabel label : labels) {
                 label.setEnabled(enabled);
             }
-
             adapters.setEnabled(enabled);
             driver.setEnabled(enabled);
             url.setEnabled(enabled);
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorPreferencesController.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorPreferencesController.java
index 738e96e9d..4d2431f7c 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorPreferencesController.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorPreferencesController.java
@@ -50,6 +50,7 @@ import java.util.stream.Collectors;
 public class DBConnectorPreferencesController extends 
ChildController<PreferenceDialogController> {
 
        private final DBConnectorPreferencesView view;
+       private final DBConnectorEditorController editorController;
        private final DBConnectors registry;
        private final Map<String, DBConnector> connectors;
        private final Set<String> toRemove;
@@ -58,7 +59,8 @@ public class DBConnectorPreferencesController extends 
ChildController<Preference
        public DBConnectorPreferencesController(PreferenceDialogController 
parent) {
                super(parent);
 
-               this.view = new DBConnectorPreferencesView(this);
+               this.editorController = new DBConnectorEditorController(this);
+               this.view = new DBConnectorPreferencesView(this, 
editorController.getView());
 
                // init view data — work on a snapshot of the live registry; 
commit/discard on Save/Revert
                this.registry = getApplication().getDbConnectors();
@@ -68,14 +70,11 @@ public class DBConnectorPreferencesController extends 
ChildController<Preference
 
                Object[] keys = connectors.keySet().toArray();
                Arrays.sort(keys);
-               DefaultComboBoxModel<Object> connectorModel = new 
DefaultComboBoxModel<>(keys);
-               view.getConnectors().setModel(connectorModel);
-
-               initBindings();
+               view.setConnectors(keys);
 
                // show first item
                if (keys.length > 0) {
-                       view.getConnectors().setSelectedIndex(0);
+                       view.selectConnector(keys[0]);
                        editConnectorAction();
                }
        }
@@ -84,18 +83,6 @@ public class DBConnectorPreferencesController extends 
ChildController<Preference
                return view;
        }
 
-       protected void initBindings() {
-               view.getAddConnector().addActionListener(e -> 
newConnectorAction());
-               view.getDuplicateConnector().addActionListener(e -> 
duplicateConnectorAction());
-               view.getRemoveConnector().addActionListener(e -> 
removeConnectorAction());
-               view.getTestConnector().addActionListener(e -> 
testConnectorAction());
-
-               view.getConnectors().addActionListener(e -> {
-                       Object sel = view.getConnectors().getSelectedItem();
-                       setConnectorName(sel != null ? sel.toString() : null);
-               });
-       }
-
        public Map<String, DBConnector> getConnectors() {
                return connectors;
        }
@@ -104,8 +91,8 @@ public class DBConnectorPreferencesController extends 
ChildController<Preference
                return connectorName;
        }
 
-       public void setConnectorName(String connectorName) {
-               this.connectorName = connectorName;
+       void connectorSelected(String name) {
+               this.connectorName = name;
                editConnectorAction();
        }
 
@@ -152,15 +139,15 @@ public class DBConnectorPreferencesController extends 
ChildController<Preference
        /**
         * Shows a dialog to create a new local DB Connector configuration.
         */
-       public void newConnectorAction() {
+       void addConnectorClicked() {
                DBConnectorCreatorController creatorWizard = new 
DBConnectorCreatorController(this);
                DBConnector connector = creatorWizard.startupAction();
 
                if (connector != null) {
                        Object[] keys = connectors.keySet().toArray();
                        Arrays.sort(keys);
-                       view.getConnectors().setModel(new 
DefaultComboBoxModel<>(keys));
-                       
view.getConnectors().setSelectedItem(creatorWizard.getName());
+                       view.setConnectors(keys);
+                       view.selectConnector(creatorWizard.getName());
                        editConnectorAction();
                }
        }
@@ -168,26 +155,26 @@ public class DBConnectorPreferencesController extends 
ChildController<Preference
        /**
         * Shows a dialog to duplicate an existing local DB Connector 
configuration.
         */
-       public void duplicateConnectorAction() {
-               Object selected = view.getConnectors().getSelectedItem();
-               if (selected != null) {
-                       DBConnectorDuplicatorController wizard = new 
DBConnectorDuplicatorController(this, selected.toString());
-                       DBConnector connector = wizard.startupAction();
-
-                       if (connector != null) {
-                               Object[] keys = connectors.keySet().toArray();
-                               Arrays.sort(keys);
-                               view.getConnectors().setModel(new 
DefaultComboBoxModel<>(keys));
-                               
view.getConnectors().setSelectedItem(wizard.getName());
-                               editConnectorAction();
-                       }
+       void duplicateConnectorClicked(String prototypeKey) {
+               if (prototypeKey == null) {
+                       return;
+               }
+               DBConnectorDuplicatorController wizard = new 
DBConnectorDuplicatorController(this, prototypeKey);
+               DBConnector connector = wizard.startupAction();
+
+               if (connector != null) {
+                       Object[] keys = connectors.keySet().toArray();
+                       Arrays.sort(keys);
+                       view.setConnectors(keys);
+                       view.selectConnector(wizard.getName());
+                       editConnectorAction();
                }
        }
 
        /**
         * Removes current DB Connector.
         */
-       public void removeConnectorAction() {
+       void removeConnectorClicked() {
                String key = getConnectorName();
                if (key != null) {
                        connectors.remove(key);
@@ -195,7 +182,7 @@ public class DBConnectorPreferencesController extends 
ChildController<Preference
 
                        Object[] keys = connectors.keySet().toArray();
                        Arrays.sort(keys);
-                       view.getConnectors().setModel(new 
DefaultComboBoxModel<>(keys));
+                       view.setConnectors(keys);
                        editConnectorAction(keys.length > 0 ? keys[0] : null);
                }
        }
@@ -204,7 +191,7 @@ public class DBConnectorPreferencesController extends 
ChildController<Preference
         * Opens specified DB Connector in the editor.
         */
        public void editConnectorAction(Object connectorKey) {
-               view.getConnectors().setSelectedItem(connectorKey);
+               view.selectConnector(connectorKey);
                editConnectorAction();
        }
 
@@ -212,13 +199,13 @@ public class DBConnectorPreferencesController extends 
ChildController<Preference
         * Opens current DB Connector in the editor.
         */
        public void editConnectorAction() {
-               
this.view.getConnectorEditor().setConnectionInfo(getConnectionInfo());
+               editorController.setConnector(getConnectionInfo());
        }
 
        /**
         * Tries to establish a DB connection, reporting the status of this 
operation.
         */
-       public void testConnectorAction() {
+       void testConnectorClicked() {
                DBConnector currentConnector = getConnectionInfo();
                if (currentConnector == null) {
                        return;
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorPreferencesView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorPreferencesView.java
index 0578974aa..d7e92d4bc 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorPreferencesView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorPreferencesView.java
@@ -19,37 +19,37 @@
 
 package org.apache.cayenne.modeler.ui.preferences.dbconnector;
 
-import java.awt.BorderLayout;
-
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JPanel;
-
-import org.apache.cayenne.modeler.mvc.RootController;
-
 import com.jgoodies.forms.builder.PanelBuilder;
 import com.jgoodies.forms.layout.CellConstraints;
 import com.jgoodies.forms.layout.FormLayout;
 
+import javax.swing.*;
+import java.awt.*;
+
 
 public class DBConnectorPreferencesView extends JPanel {
 
-    protected JButton addConnector;
-    protected JButton duplicateConnector;
-    protected JButton removeConnector;
-    protected JButton testConnector;
-    protected JComboBox<Object> connectors;
-    protected DBConnectionInfoEditorController connectorEditor;
+    private final JComboBox<Object> connectors;
 
-    public DBConnectorPreferencesView(RootController controller) {
-        this.addConnector = new JButton("New...");
-        this.duplicateConnector = new JButton("Duplicate...");
-        this.removeConnector = new JButton("Delete");
-        this.testConnector = new JButton("Test...");
+    public DBConnectorPreferencesView(DBConnectorPreferencesController 
controller, Component editorView) {
+        JButton addConnector = new JButton("New...");
+        JButton duplicateConnector = new JButton("Duplicate...");
+        JButton removeConnector = new JButton("Delete");
+        JButton testConnector = new JButton("Test...");
         this.connectors = new JComboBox<>();
-        this.connectorEditor = new 
DBConnectionInfoEditorController(controller);
 
-        // assemble
+        addConnector.addActionListener(e -> controller.addConnectorClicked());
+        duplicateConnector.addActionListener(e -> {
+            Object selected = connectors.getSelectedItem();
+            controller.duplicateConnectorClicked(selected != null ? 
selected.toString() : null);
+        });
+        removeConnector.addActionListener(e -> 
controller.removeConnectorClicked());
+        testConnector.addActionListener(e -> 
controller.testConnectorClicked());
+        connectors.addActionListener(e -> {
+            Object sel = connectors.getSelectedItem();
+            controller.connectorSelected(sel != null ? sel.toString() : null);
+        });
+
         CellConstraints cc = new CellConstraints();
         PanelBuilder sidebar = new PanelBuilder(new FormLayout(
                 "fill:min(150dlu;pref)",
@@ -67,34 +67,18 @@ public class DBConnectorPreferencesView extends JPanel {
                 "p, 3dlu, fill:default:grow"));
         editor.setDefaultDialogBorder();
         editor.addSeparator("Edit DB Connector", cc.xy(1, 1));
-        editor.add(connectorEditor.getView(), cc.xy(1, 3));
+        editor.add(editorView, cc.xy(1, 3));
 
         setLayout(new BorderLayout());
         add(editor.getPanel(), BorderLayout.CENTER);
         add(sidebar.getPanel(), BorderLayout.EAST);
     }
 
-    public DBConnectionInfoEditorController getConnectorEditor() {
-        return connectorEditor;
-    }
-
-    public JComboBox<Object> getConnectors() {
-        return connectors;
-    }
-
-    public JButton getAddConnector() {
-        return addConnector;
-    }
-
-    public JButton getRemoveConnector() {
-        return removeConnector;
-    }
-
-    public JButton getTestConnector() {
-        return testConnector;
+    public void setConnectors(Object[] keys) {
+        connectors.setModel(new DefaultComboBoxModel<>(keys));
     }
 
-    public JButton getDuplicateConnector() {
-        return duplicateConnector;
+    public void selectConnector(Object key) {
+        connectors.setSelectedItem(key);
     }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/creator/DBConnectorCreatorController.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/creator/DBConnectorCreatorController.java
index db0af61de..16a40ea1e 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/creator/DBConnectorCreatorController.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/creator/DBConnectorCreatorController.java
@@ -22,35 +22,31 @@ package 
org.apache.cayenne.modeler.ui.preferences.dbconnector.creator;
 import org.apache.cayenne.modeler.mvc.ChildController;
 import 
org.apache.cayenne.modeler.ui.preferences.dbconnector.DBConnectorPreferencesController;
 import org.apache.cayenne.modeler.dbconnector.DBConnector;
-import org.apache.cayenne.modeler.util.DbAdapterInfo;
 
-import javax.swing.*;
-import java.awt.*;
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
+import java.awt.Component;
 import java.util.Map;
 
 public class DBConnectorCreatorController extends 
ChildController<DBConnectorPreferencesController> {
 
-    private static final String NO_ADAPTER = "Custom / Undefined";
     private static final String NAME_PREFIX = "Connector";
 
-    protected DBConnectorCreatorView view;
+    protected final DBConnectorCreatorView view;
+    protected final Map<String, DBConnector> connectors;
     protected boolean canceled;
-    protected Map<String, DBConnector> connectors;
+
+    private String enteredName;
+    private String enteredAdapter;
 
     public DBConnectorCreatorController(DBConnectorPreferencesController 
parent) {
         super(parent);
-        this.view = new DBConnectorCreatorView((JDialog) SwingUtilities
-                .getWindowAncestor(parent.getView()));
         this.connectors = parent.getConnectors();
-
-        DefaultComboBoxModel model = new DefaultComboBoxModel(DbAdapterInfo
-                .getStandardAdapters());
-        model.insertElementAt(NO_ADAPTER, 0);
-        this.view.getAdapters().setModel(model);
-        this.view.getAdapters().setSelectedIndex(0);
-
-        this.view.getConnectorName().setText(suggestName());
-        initBindings();
+        this.view = new DBConnectorCreatorView(
+                (JDialog) SwingUtilities.getWindowAncestor(parent.getView()),
+                this,
+                suggestName());
     }
 
     private String suggestName() {
@@ -67,33 +63,30 @@ public class DBConnectorCreatorController extends 
ChildController<DBConnectorPre
         return view;
     }
 
-    protected void initBindings() {
-        view.getCancelButton().addActionListener(e -> cancelAction());
-        view.getOkButton().addActionListener(e -> okAction());
-    }
-
-    public void okAction() {
-        if (getName() == null) {
+    void okClicked(String name, String adapter) {
+        if (name == null || name.isEmpty()) {
             JOptionPane.showMessageDialog(
                     view,
                     "Enter Connector Name",
                     null,
                     JOptionPane.WARNING_MESSAGE);
+            return;
         }
-        else if (connectors.containsKey(getName())) {
+        if (connectors.containsKey(name)) {
             JOptionPane.showMessageDialog(
                     view,
-                    "'" + getName() + "' is already in use, enter a different 
name",
+                    "'" + name + "' is already in use, enter a different name",
                     null,
                     JOptionPane.WARNING_MESSAGE);
+            return;
         }
-        else {
-            canceled = false;
-            view.dispose();
-        }
+        this.enteredName = name;
+        this.enteredAdapter = adapter;
+        this.canceled = false;
+        view.dispose();
     }
 
-    public void cancelAction() {
+    void cancelClicked() {
         canceled = true;
         view.dispose();
     }
@@ -116,8 +109,7 @@ public class DBConnectorCreatorController extends 
ChildController<DBConnectorPre
     }
 
     public String getName() {
-        String name = view.getConnectorName().getText();
-        return (name.length() > 0) ? name : null;
+        return enteredName;
     }
 
     protected DBConnector createConnector() {
@@ -125,20 +117,13 @@ public class DBConnectorCreatorController extends 
ChildController<DBConnectorPre
             return null;
         }
 
-        DBConnector connector = parent.create(getName());
-
-        Object adapter = view.getAdapters().getSelectedItem();
-        if (NO_ADAPTER.equals(adapter)) {
-            adapter = null;
-        }
-
-        if (adapter != null) {
-            String adapterString = adapter.toString();
-            connector.setDbAdapter(adapterString);
+        DBConnector connector = parent.create(enteredName);
 
+        if (enteredAdapter != null) {
+            connector.setDbAdapter(enteredAdapter);
             // guess adapter defaults...
-            connector.setJdbcDriver(Adapters.driver(adapterString));
-            connector.setUrl(Adapters.jdbcURL(adapterString));
+            connector.setJdbcDriver(Adapters.driver(enteredAdapter));
+            connector.setUrl(Adapters.jdbcURL(enteredAdapter));
         }
 
         return connector;
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/creator/DBConnectorCreatorView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/creator/DBConnectorCreatorView.java
index b9d687b16..0d1c56da0 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/creator/DBConnectorCreatorView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/creator/DBConnectorCreatorView.java
@@ -21,7 +21,9 @@ package 
org.apache.cayenne.modeler.ui.preferences.dbconnector.creator;
 
 import com.jgoodies.forms.builder.DefaultFormBuilder;
 import com.jgoodies.forms.layout.FormLayout;
+import org.apache.cayenne.modeler.util.DbAdapterInfo;
 
+import javax.swing.DefaultComboBoxModel;
 import javax.swing.JButton;
 import javax.swing.JComboBox;
 import javax.swing.JDialog;
@@ -33,22 +35,31 @@ import java.awt.FlowLayout;
 
 public class DBConnectorCreatorView extends JDialog {
 
-    protected JTextField connectorName;
-    protected JComboBox adapters;
-    protected JButton okButton;
-    protected JButton cancelButton;
+    private static final String NO_ADAPTER = "Custom / Undefined";
 
-    public DBConnectorCreatorView(JDialog owner) {
+    public DBConnectorCreatorView(JDialog owner, DBConnectorCreatorController 
controller, String suggestedName) {
         super(owner);
 
-        this.connectorName = new JTextField();
-        this.adapters = new JComboBox();
-        this.okButton = new JButton("Create");
-        this.cancelButton = new JButton("Cancel");
+        JTextField connectorName = new JTextField(suggestedName);
+        JComboBox adapters = new JComboBox();
+        DefaultComboBoxModel model = new 
DefaultComboBoxModel(DbAdapterInfo.getStandardAdapters());
+        model.insertElementAt(NO_ADAPTER, 0);
+        adapters.setModel(model);
+        adapters.setSelectedIndex(0);
+
+        JButton okButton = new JButton("Create");
+        JButton cancelButton = new JButton("Cancel");
 
         getRootPane().setDefaultButton(okButton);
 
-        // assemble
+        cancelButton.addActionListener(e -> controller.cancelClicked());
+        okButton.addActionListener(e -> {
+            Object adapter = adapters.getSelectedItem();
+            controller.okClicked(
+                    connectorName.getText(),
+                    NO_ADAPTER.equals(adapter) ? null : (String) adapter);
+        });
+
         FormLayout layout = new FormLayout(
                 "right:pref, 3dlu, fill:max(50dlu;pref):grow",
                 "");
@@ -68,20 +79,4 @@ public class DBConnectorCreatorView extends JDialog {
 
         setTitle("Create New DB Connector");
     }
-
-    public JComboBox getAdapters() {
-        return adapters;
-    }
-
-    public JButton getCancelButton() {
-        return cancelButton;
-    }
-
-    public JButton getOkButton() {
-        return okButton;
-    }
-
-    public JTextField getConnectorName() {
-        return connectorName;
-    }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/duplicator/DBConnectorDuplicatorController.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/duplicator/DBConnectorDuplicatorController.java
index 65aa87d3b..8486ef729 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/duplicator/DBConnectorDuplicatorController.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/duplicator/DBConnectorDuplicatorController.java
@@ -23,26 +23,31 @@ import org.apache.cayenne.modeler.mvc.ChildController;
 import 
org.apache.cayenne.modeler.ui.preferences.dbconnector.DBConnectorPreferencesController;
 import org.apache.cayenne.modeler.dbconnector.DBConnector;
 
-import javax.swing.*;
-import java.awt.*;
+import javax.swing.JOptionPane;
+import java.awt.Component;
 import java.util.Map;
 
 
 public class DBConnectorDuplicatorController extends 
ChildController<DBConnectorPreferencesController> {
 
-    protected DBConnectorDuplicatorView view;
+    protected final DBConnectorDuplicatorView view;
+    protected final Map<String, DBConnector> connectors;
+    protected final String prototypeKey;
     protected boolean canceled;
-    protected Map<String, DBConnector> connectors;
-    protected String prototypeKey;
+
+    private String enteredName;
 
     public DBConnectorDuplicatorController(DBConnectorPreferencesController 
parent, String prototypeKey) {
         super(parent);
-        this.view = new DBConnectorDuplicatorView("Create a copy of \""
-                + prototypeKey
-                + "\"");
         this.connectors = parent.getConnectors();
         this.prototypeKey = prototypeKey;
+        this.view = new DBConnectorDuplicatorView(
+                "Create a copy of \"" + prototypeKey + "\"",
+                this,
+                suggestName());
+    }
 
+    private String suggestName() {
         String suggestion = prototypeKey + "0";
         for (int i = 1; i <= connectors.size(); i++) {
             suggestion = prototypeKey + i;
@@ -50,42 +55,36 @@ public class DBConnectorDuplicatorController extends 
ChildController<DBConnector
                 break;
             }
         }
-
-        this.view.getConnectorName().setText(suggestion);
-        initBindings();
+        return suggestion;
     }
 
     public Component getView() {
         return view;
     }
 
-    protected void initBindings() {
-        view.getCancelButton().addActionListener(e -> cancelAction());
-        view.getOkButton().addActionListener(e -> okAction());
-    }
-
-    public void okAction() {
-        if (getName() == null) {
+    void okClicked(String name) {
+        if (name == null || name.isEmpty()) {
             JOptionPane.showMessageDialog(
                     view,
                     "Enter Connector Name",
                     null,
                     JOptionPane.WARNING_MESSAGE);
+            return;
         }
-        else if (connectors.containsKey(getName())) {
+        if (connectors.containsKey(name)) {
             JOptionPane.showMessageDialog(
                     view,
-                    "'" + getName() + "' is already in use, enter a different 
name",
+                    "'" + name + "' is already in use, enter a different name",
                     null,
                     JOptionPane.WARNING_MESSAGE);
+            return;
         }
-        else {
-            canceled = false;
-            view.dispose();
-        }
+        this.enteredName = name;
+        this.canceled = false;
+        view.dispose();
     }
 
-    public void cancelAction() {
+    void cancelClicked() {
         canceled = true;
         view.dispose();
     }
@@ -108,8 +107,7 @@ public class DBConnectorDuplicatorController extends 
ChildController<DBConnector
     }
 
     public String getName() {
-        String name = view.getConnectorName().getText();
-        return (name.length() > 0) ? name : null;
+        return enteredName;
     }
 
     protected DBConnector createConnector() {
@@ -118,7 +116,7 @@ public class DBConnectorDuplicatorController extends 
ChildController<DBConnector
         }
 
         DBConnector prototype = connectors.get(prototypeKey);
-        DBConnector connector = parent.create(getName());
+        DBConnector connector = parent.create(enteredName);
 
         prototype.copyTo(connector);
         return connector;
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/duplicator/DBConnectorDuplicatorView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/duplicator/DBConnectorDuplicatorView.java
index fb1d40eb3..c32ef3cbb 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/duplicator/DBConnectorDuplicatorView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/duplicator/DBConnectorDuplicatorView.java
@@ -32,20 +32,18 @@ import java.awt.FlowLayout;
 
 public class DBConnectorDuplicatorView extends JDialog {
 
-    protected JTextField connectorName;
-    protected JButton okButton;
-    protected JButton cancelButton;
-
-    public DBConnectorDuplicatorView(String title) {
+    public DBConnectorDuplicatorView(String title, 
DBConnectorDuplicatorController controller, String suggestedName) {
         setTitle(title);
 
-        this.connectorName = new JTextField();
-        this.okButton = new JButton("Create");
-        this.cancelButton = new JButton("Cancel");
+        JTextField connectorName = new JTextField(suggestedName);
+        JButton okButton = new JButton("Create");
+        JButton cancelButton = new JButton("Cancel");
 
         getRootPane().setDefaultButton(okButton);
 
-        // assemble
+        cancelButton.addActionListener(e -> controller.cancelClicked());
+        okButton.addActionListener(e -> 
controller.okClicked(connectorName.getText()));
+
         FormLayout layout = new FormLayout("right:pref, 3dlu, fill:250", "");
         DefaultFormBuilder builder = new DefaultFormBuilder(layout);
         builder.setDefaultDialogBorder();
@@ -60,16 +58,4 @@ public class DBConnectorDuplicatorView extends JDialog {
         getContentPane().add(builder.getPanel(), BorderLayout.CENTER);
         getContentPane().add(buttons, BorderLayout.SOUTH);
     }
-
-    public JButton getCancelButton() {
-        return cancelButton;
-    }
-
-    public JTextField getConnectorName() {
-        return connectorName;
-    }
-
-    public JButton getOkButton() {
-        return okButton;
-    }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/general/GeneralPreferencesController.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/general/GeneralPreferencesController.java
index aa41054b6..14ac4cf2f 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/general/GeneralPreferencesController.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/general/GeneralPreferencesController.java
@@ -23,13 +23,7 @@ import org.apache.cayenne.modeler.mvc.ChildController;
 import org.apache.cayenne.modeler.pref.GeneralPrefs;
 import org.apache.cayenne.modeler.ui.preferences.PreferenceDialogController;
 
-import javax.swing.*;
 import java.awt.*;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
 
 public class GeneralPreferencesController extends 
ChildController<PreferenceDialogController> {
 
@@ -38,22 +32,16 @@ public class GeneralPreferencesController extends 
ChildController<PreferenceDial
     };
 
     private final GeneralPreferencesView view;
-    private final String systemEncoding;
-    private final String defaultLabel;
 
     public GeneralPreferencesController(PreferenceDialogController parent) {
         super(parent);
 
         GeneralPrefs prefs = 
GeneralPrefs.of(getApplication().getPreferencesRepository());
-        this.systemEncoding = detectPlatformEncoding();
-        this.defaultLabel = systemEncoding + " (default)";
-
-        this.view = new GeneralPreferencesView();
-
-        view.getEncodingChoices().setModel(new 
DefaultComboBoxModel<>(supportedEncodings()));
-        selectEncoding(prefs.getEncoding());
-        view.getAutoLoadProject().setSelected(prefs.isAutoLoadProject());
-        view.getNoDeletePrompt().setSelected(prefs.isNoDeletePrompt());
+        this.view = new GeneralPreferencesView(
+                STANDARD_ENCODINGS,
+                prefs.getEncoding(),
+                prefs.isAutoLoadProject(),
+                prefs.isNoDeletePrompt());
     }
 
     @Override
@@ -63,43 +51,8 @@ public class GeneralPreferencesController extends 
ChildController<PreferenceDial
 
     public void commit() {
         GeneralPrefs prefs = 
GeneralPrefs.of(getApplication().getPreferencesRepository());
-
-        Object selected = view.getEncodingChoices().getSelectedItem();
-        String encoding = (selected == null || defaultLabel.equals(selected)) 
? systemEncoding : selected.toString();
-
-        prefs.setEncoding(encoding);
-        prefs.setAutoLoadProject(view.getAutoLoadProject().isSelected());
-        prefs.setNoDeletePrompt(view.getNoDeletePrompt().isSelected());
-    }
-
-    /**
-     * Returns the canonical name of the platform's default charset. 
Canonicalizing
-     * (vs. e.g. {@code OutputStreamWriter.getEncoding()}, which returns 
historical
-     * aliases like "UTF8") ensures the value compares cleanly against
-     * {@link #STANDARD_ENCODINGS}.
-     */
-    static String detectPlatformEncoding() {
-        return Charset.defaultCharset().name();
-    }
-
-    /**
-     * Returns charsets that all JVMs must support cross-platform, sorted
-     * alphabetically, with the platform default labeled in place. See
-     * java.nio.charset.Charset for the list of "standard" charsets.
-     */
-    private String[] supportedEncodings() {
-        List<String> charsets = new 
ArrayList<>(Arrays.asList(STANDARD_ENCODINGS));
-        charsets.remove(systemEncoding);
-        charsets.add(defaultLabel);
-        Collections.sort(charsets);
-        return charsets.toArray(new String[0]);
-    }
-
-    private void selectEncoding(String encoding) {
-        if (encoding == null || encoding.isEmpty() || 
encoding.equals(systemEncoding)) {
-            view.getEncodingChoices().setSelectedItem(defaultLabel);
-        } else {
-            view.getEncodingChoices().setSelectedItem(encoding);
-        }
+        prefs.setEncoding(view.getSelectedEncoding());
+        prefs.setAutoLoadProject(view.isAutoLoadProjectSelected());
+        prefs.setNoDeletePrompt(view.isNoDeletePromptSelected());
     }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/general/GeneralPreferencesView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/general/GeneralPreferencesView.java
index 6f667c7c1..5f3a31017 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/general/GeneralPreferencesView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/general/GeneralPreferencesView.java
@@ -25,6 +25,11 @@ import com.jgoodies.forms.layout.FormLayout;
 
 import javax.swing.*;
 import java.awt.*;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 
 
 public class GeneralPreferencesView extends JPanel {
@@ -32,14 +37,30 @@ public class GeneralPreferencesView extends JPanel {
     private final JComboBox<String> encodingChoices;
     private final JCheckBox autoLoadProject;
     private final JCheckBox noDeletePrompt;
+    private final String systemEncoding;
+    private final String defaultLabel;
+
+    public GeneralPreferencesView(
+            String[] supportedEncodings,
+            String currentEncoding,
+            boolean autoLoadProject,
+            boolean noDeletePrompt) {
+
+        this.systemEncoding = Charset.defaultCharset().name();
+        this.defaultLabel = systemEncoding + " (default)";
+
+        String[] encodingLabels = createEncodingLabels(supportedEncodings);
+        this.encodingChoices = new JComboBox<>(new 
DefaultComboBoxModel<>(encodingLabels));
+        selectEncoding(currentEncoding);
+
+        this.autoLoadProject = new JCheckBox();
+        this.autoLoadProject.setSelected(autoLoadProject);
+        this.noDeletePrompt = new JCheckBox();
+        this.noDeletePrompt.setSelected(noDeletePrompt);
 
-    public GeneralPreferencesView() {
-        this.encodingChoices = new JComboBox<>();
         JLabel encodingSelectorLabel = new JLabel("File Encoding:");
         JLabel autoLoadProjectLabel = new JLabel("Auto-Load Last Project:");
         JLabel noDeletePromptLabel = new JLabel("Delete Without Prompt:");
-        this.autoLoadProject = new JCheckBox();
-        this.noDeletePrompt = new JCheckBox();
 
         FormLayout layout = new FormLayout(
                 "right:pref, 3dlu, fill:120dlu, default:grow",
@@ -53,23 +74,40 @@ public class GeneralPreferencesView extends JPanel {
         builder.add(encodingSelectorLabel, cc.xy(1, 3));
         builder.add(encodingChoices, cc.xy(3, 3));
         builder.add(autoLoadProjectLabel, cc.xy(1, 5));
-        builder.add(autoLoadProject, cc.xy(3, 5, CellConstraints.LEFT, 
CellConstraints.DEFAULT));
+        builder.add(this.autoLoadProject, cc.xy(3, 5, CellConstraints.LEFT, 
CellConstraints.DEFAULT));
         builder.add(noDeletePromptLabel, cc.xy(1, 7));
-        builder.add(noDeletePrompt, cc.xy(3, 7, CellConstraints.LEFT, 
CellConstraints.DEFAULT));
+        builder.add(this.noDeletePrompt, cc.xy(3, 7, CellConstraints.LEFT, 
CellConstraints.DEFAULT));
+
+        setLayout(new BorderLayout());
+        add(builder.getPanel(), BorderLayout.CENTER);
+    }
+
+    public String getSelectedEncoding() {
+        Object selected = encodingChoices.getSelectedItem();
+        return (selected == null || defaultLabel.equals(selected)) ? 
systemEncoding : selected.toString();
+    }
 
-        this.setLayout(new BorderLayout());
-        this.add(builder.getPanel(), BorderLayout.CENTER);
+    public boolean isAutoLoadProjectSelected() {
+        return autoLoadProject.isSelected();
     }
 
-    public JComboBox<String> getEncodingChoices() {
-        return encodingChoices;
+    public boolean isNoDeletePromptSelected() {
+        return noDeletePrompt.isSelected();
     }
 
-    public JCheckBox getAutoLoadProject() {
-        return autoLoadProject;
+    private String[] createEncodingLabels(String[] supportedEncodings) {
+        List<String> labels = new 
ArrayList<>(Arrays.asList(supportedEncodings));
+        labels.remove(systemEncoding);
+        labels.add(defaultLabel);
+        Collections.sort(labels);
+        return labels.toArray(new String[0]);
     }
 
-    public JCheckBox getNoDeletePrompt() {
-        return noDeletePrompt;
+    private void selectEncoding(String encoding) {
+        if (encoding == null || encoding.isEmpty() || 
encoding.equals(systemEncoding)) {
+            encodingChoices.setSelectedItem(defaultLabel);
+        } else {
+            encodingChoices.setSelectedItem(encoding);
+        }
     }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/more/MorePreferencesController.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/more/MorePreferencesController.java
index 2c414d188..266074274 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/more/MorePreferencesController.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/more/MorePreferencesController.java
@@ -35,11 +35,7 @@ public class MorePreferencesController extends 
ChildController<PreferenceDialogC
 
     public MorePreferencesController(PreferenceDialogController parent) {
         super(parent);
-
-        this.view = new MorePreferencesView();
-
-        view.getCopyAllButton().addActionListener(e -> copyAllToClipboard());
-        view.getResetToDefaultsButton().addActionListener(e -> 
resetToDefaults());
+        this.view = new MorePreferencesView(this);
     }
 
     @Override
@@ -47,17 +43,13 @@ public class MorePreferencesController extends 
ChildController<PreferenceDialogC
         return view;
     }
 
-    public void commit() {
-        // no-op: this card has no deferred state
-    }
-
-    private void copyAllToClipboard() {
+    void copyAllClicked() {
         PreferencesRepository repository = 
getApplication().getPreferencesRepository();
         String json = repository.exportAsJson();
         Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new 
StringSelection(json), null);
     }
 
-    private void resetToDefaults() {
+    void resetToDefaultsClicked(boolean importLegacy) {
         int answer = JOptionPane.showConfirmDialog(
                 view,
                 "Resetting preferences to defaults requires closing and 
restarting CayenneModeler. Continue?",
@@ -68,8 +60,6 @@ public class MorePreferencesController extends 
ChildController<PreferenceDialogC
             return;
         }
 
-        boolean importLegacy = 
view.getImportLegacyPreferencesCheckBox().isSelected();
-
         // Close the open project first (with the standard unsaved-changes
         // prompt). closeProject is a no-op when no project is open. If the 
user
         // cancels the save prompt, abort the wipe entirely.
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/more/MorePreferencesView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/more/MorePreferencesView.java
index a35e13b63..50df5cae1 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/more/MorePreferencesView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/more/MorePreferencesView.java
@@ -28,15 +28,16 @@ import java.awt.*;
 
 public class MorePreferencesView extends JPanel {
 
-    private final JButton copyAllButton;
-    private final JButton resetToDefaultsButton;
-    private final JCheckBox importLegacyPreferencesCheckBox;
+    public MorePreferencesView(MorePreferencesController controller) {
+        JButton copyAllButton = new JButton("Copy All to Clipboard");
+        JButton resetToDefaultsButton = new JButton("Reset to Defaults");
+        JCheckBox importLegacyPreferencesCheckBox =
+                new JCheckBox("Import older Modeler preferences if available", 
true);
+        
importLegacyPreferencesCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 
12, 0, 0));
 
-    public MorePreferencesView() {
-        this.copyAllButton = new JButton("Copy All to Clipboard");
-        this.resetToDefaultsButton = new JButton("Reset to Defaults");
-        this.importLegacyPreferencesCheckBox = new JCheckBox("Import older 
Modeler preferences if available", true);
-        
this.importLegacyPreferencesCheckBox.setBorder(BorderFactory.createEmptyBorder(0,
 12, 0, 0));
+        copyAllButton.addActionListener(e -> controller.copyAllClicked());
+        resetToDefaultsButton.addActionListener(
+                e -> 
controller.resetToDefaultsClicked(importLegacyPreferencesCheckBox.isSelected()));
 
         FormLayout layout = new FormLayout(
                 "12dlu, default:grow",
@@ -53,19 +54,7 @@ public class MorePreferencesView extends JPanel {
         builder.add(resetToDefaultsButton, cc.xy(2, 7, CellConstraints.LEFT, 
CellConstraints.DEFAULT));
         builder.add(importLegacyPreferencesCheckBox, cc.xy(2, 9, 
CellConstraints.LEFT, CellConstraints.DEFAULT));
 
-        this.setLayout(new BorderLayout());
-        this.add(builder.getPanel(), BorderLayout.CENTER);
-    }
-
-    public JButton getCopyAllButton() {
-        return copyAllButton;
-    }
-
-    public JButton getResetToDefaultsButton() {
-        return resetToDefaultsButton;
-    }
-
-    public JCheckBox getImportLegacyPreferencesCheckBox() {
-        return importLegacyPreferencesCheckBox;
+        setLayout(new BorderLayout());
+        add(builder.getPanel(), BorderLayout.CENTER);
     }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/action/GetDbConnectionAction.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/action/GetDbConnectionAction.java
index 025288e13..b41eb9768 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/action/GetDbConnectionAction.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/action/GetDbConnectionAction.java
@@ -42,7 +42,7 @@ public class GetDbConnectionAction extends 
DBConnectionAwareAction {
 
     @Override
     public void performAction(ActionEvent e) {
-        DataSourceController connectWizard = 
getDataSourceController(DIALOG_TITLE, new String[]{"Continue", "Cancel"});
+        DataSourceController connectWizard = 
getDataSourceController(DIALOG_TITLE);
         if (connectWizard == null) {
             return;
         }
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 e52408f70..5ad1ab761 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
@@ -172,9 +172,8 @@ public class ObjRelationshipPanel extends JPanel implements 
ObjEntityDisplayList
 
         // Important: process event even if this is the same entity,
         // since the inheritance structure might have changed
-        if (entity != null) {
-            rebuildTable(entity);
-        }
+        rebuildTable(entity);
+
 
         // if an entity was selected on a tree,
         // unselect currently selected row
@@ -182,8 +181,7 @@ public class ObjRelationshipPanel extends JPanel implements 
ObjEntityDisplayList
             table.clearSelection();
         }
 
-        ObjEntity objEntity = (ObjEntity) e.getEntity();
-        
parentPanel.getToolBar().getComponentAtIndex(2).setEnabled(objEntity.getSuperEntity()
 == null);
+        
parentPanel.getToolBar().getComponentAtIndex(2).setEnabled(entity.getSuperEntity()
 == null);
     }
 
     public void objEntityChanged(ObjEntityEvent e) {
diff --git 
a/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/ui/preferences/general/GeneralPreferencesControllerTest.java
 
b/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/ui/preferences/general/GeneralPreferencesControllerTest.java
index 1be47c24e..d6ed1e460 100644
--- 
a/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/ui/preferences/general/GeneralPreferencesControllerTest.java
+++ 
b/modeler/cayenne-modeler/src/test/java/org/apache/cayenne/modeler/ui/preferences/general/GeneralPreferencesControllerTest.java
@@ -23,7 +23,6 @@ import org.junit.jupiter.api.Test;
 
 import java.nio.charset.Charset;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 
@@ -39,12 +38,4 @@ public class GeneralPreferencesControllerTest {
                     "Charset not supported by JVM: " + encoding);
         }
     }
-
-    @Test
-    public void detectPlatformEncodingReturnsCanonicalName() {
-        // Must return the canonical Charset name (e.g. "UTF-8"), not a 
historical
-        // alias (e.g. "UTF8"), so it matches entries in STANDARD_ENCODINGS.
-        String encoding = 
GeneralPreferencesController.detectPlatformEncoding();
-        assertEquals(Charset.forName(encoding).name(), encoding);
-    }
 }

Reply via email to