This is an automated email from the ASF dual-hosted git repository.
aadamchik 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 452fe9638 CAY-2918 Remove OGNL Binding Architecture from CayenneModeler
452fe9638 is described below
commit 452fe963881d9a91681e49a3b1c2b66389b9b356
Author: Andrus Adamchik <[email protected]>
AuthorDate: Sun Apr 12 15:45:08 2026 -0400
CAY-2918 Remove OGNL Binding Architecture from CayenneModeler
getting rid of "bindToTextField"
---
.../modeler/dialog/db/gen/DBGeneratorOptions.java | 17 +----
.../modeler/dialog/db/merge/MergerOptions.java | 14 +---
.../dialog/pref/DBConnectionInfoEditor.java | 86 ++++++++++------------
.../editor/datanode/CustomDataSourceEditor.java | 23 ++++--
.../modeler/editor/datanode/DataSourceEditor.java | 29 ++------
.../editor/datanode/JDBCDataSourceEditor.java | 75 ++++++++++++-------
.../editor/datanode/MainDataNodeEditor.java | 30 ++++++--
.../cayenne/modeler/pref/DBConnectionInfo.java | 21 +++---
.../apache/cayenne/modeler/util/TextBinder.java | 79 ++++++++++++++++++++
9 files changed, 229 insertions(+), 145 deletions(-)
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/gen/DBGeneratorOptions.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/gen/DBGeneratorOptions.java
index beb800374..dc55e1fd6 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/gen/DBGeneratorOptions.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/gen/DBGeneratorOptions.java
@@ -34,13 +34,10 @@ import org.apache.cayenne.swing.BindingBuilder;
import org.apache.cayenne.swing.ObjectBinding;
import org.apache.cayenne.validation.ValidationResult;
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.JFileChooser;
-import javax.swing.JOptionPane;
-import javax.swing.WindowConstants;
+import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
-import java.awt.Component;
+import java.awt.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
@@ -55,7 +52,6 @@ public class DBGeneratorOptions extends CayenneController {
protected DBGeneratorOptionsView view;
protected ObjectBinding[] optionBindings;
- protected ObjectBinding sqlBinding;
protected ObjectBinding adapterBinding;
protected DBConnectionInfo connectionInfo;
@@ -98,10 +94,6 @@ public class DBGeneratorOptions extends CayenneController {
return generatorDefaults;
}
- public String getTextForSQL() {
- return textForSQL;
- }
-
protected void initController() {
DefaultComboBoxModel<String> adapterModel = new DefaultComboBoxModel<>(
@@ -113,7 +105,6 @@ public class DBGeneratorOptions extends CayenneController {
getApplication().getBindingFactory(),
this);
- sqlBinding = builder.bindToTextArea(view.getSql(), "textForSQL");
adapterBinding = builder.bindToComboSelection(
view.getAdapters(),
"connectionInfo.dbAdapter",
@@ -208,7 +199,7 @@ public class DBGeneratorOptions extends CayenneController {
optionBinding.updateView();
}
- sqlBinding.updateView();
+ view.getSql().setText(textForSQL);
}
// ===============
@@ -242,7 +233,7 @@ public class DBGeneratorOptions extends CayenneController {
prepareGenerator();
generatorDefaults.configureGenerator(generators);
createSQL();
- sqlBinding.updateView();
+ view.getSql().setText(textForSQL);
}
/**
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/merge/MergerOptions.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/merge/MergerOptions.java
index 8a169a806..411a206a1 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/merge/MergerOptions.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/merge/MergerOptions.java
@@ -49,10 +49,9 @@ import org.apache.cayenne.modeler.ProjectController;
import org.apache.cayenne.modeler.dialog.ValidationResultBrowser;
import org.apache.cayenne.modeler.pref.DBConnectionInfo;
import org.apache.cayenne.modeler.util.CayenneController;
+import org.apache.cayenne.modeler.util.TextBinder;
import org.apache.cayenne.project.Project;
import org.apache.cayenne.resource.Resource;
-import org.apache.cayenne.swing.BindingBuilder;
-import org.apache.cayenne.swing.ObjectBinding;
import org.apache.cayenne.validation.ValidationResult;
import org.slf4j.LoggerFactory;
@@ -77,7 +76,6 @@ import java.util.List;
public class MergerOptions extends CayenneController {
protected MergerOptionsView view;
- protected ObjectBinding sqlBinding;
protected DBConnectionInfo connectionInfo;
protected DataMap dataMap;
@@ -123,11 +121,7 @@ public class MergerOptions extends CayenneController {
protected void initController() {
- BindingBuilder builder = new BindingBuilder(
- getApplication().getBindingFactory(),
- this);
-
- sqlBinding = builder.bindToTextArea(view.getSql(), "textForSQL");
+ TextBinder.bind(view.getSql(), v -> textForSQL = v);
view.getGenerateButton().addActionListener(e ->
generateSchemaAction());
view.getSaveSqlButton().addActionListener(e -> storeSQLAction());
@@ -213,7 +207,7 @@ public class MergerOptions extends CayenneController {
}
protected void refreshView() {
- sqlBinding.updateView();
+ view.getSql().setText(textForSQL);
}
// ===============
@@ -241,7 +235,7 @@ public class MergerOptions extends CayenneController {
*/
public void refreshSQLAction() {
createSQL();
- sqlBinding.updateView();
+ view.getSql().setText(textForSQL);
}
/**
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/pref/DBConnectionInfoEditor.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/pref/DBConnectionInfoEditor.java
index 8e95e6e37..3ab91e24c 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/pref/DBConnectionInfoEditor.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/pref/DBConnectionInfoEditor.java
@@ -19,19 +19,16 @@
package org.apache.cayenne.modeler.dialog.pref;
-import java.awt.Component;
-
-import javax.swing.DefaultComboBoxModel;
-
import org.apache.cayenne.modeler.pref.DBConnectionInfo;
import org.apache.cayenne.modeler.util.CayenneController;
import org.apache.cayenne.modeler.util.DbAdapterInfo;
-import org.apache.cayenne.swing.BindingBuilder;
-import org.apache.cayenne.swing.ObjectBinding;
+import org.apache.cayenne.modeler.util.TextBinder;
+
+import javax.swing.*;
+import java.awt.*;
/**
* A reusable editor for DBConnectionInfo object.
- *
*/
public class DBConnectionInfoEditor extends CayenneController {
@@ -40,63 +37,58 @@ public class DBConnectionInfoEditor extends
CayenneController {
protected DBConnectionInfoEditorView view;
protected DBConnectionInfo connectionInfo;
- protected ObjectBinding[] bindings;
public DBConnectionInfoEditor(CayenneController parent) {
super(parent);
this.view = new DBConnectionInfoEditorView();
- initBindings();
- }
-
- public Component getView() {
- return view;
- }
-
- protected void initBindings() {
this.view.setEnabled(false);
- DefaultComboBoxModel adapterModel = new
DefaultComboBoxModel(DbAdapterInfo
- .getStandardAdapters());
+ DefaultComboBoxModel adapterModel = new
DefaultComboBoxModel(DbAdapterInfo.getStandardAdapters());
view.getAdapters().setModel(adapterModel);
view.getAdapters().setSelectedIndex(0);
- BindingBuilder builder = new BindingBuilder(
- getApplication().getBindingFactory(),
- this);
-
- bindings = new ObjectBinding[5];
-
- bindings[0] = builder.bindToTextField(
- view.getUserName(),
- "connectionInfo.userName");
- bindings[1] = builder.bindToTextField(
- view.getPassword(),
- "connectionInfo.password");
- bindings[2] = builder.bindToTextField(
- view.getDriver(),
- "connectionInfo.jdbcDriver");
- bindings[3] = builder.bindToTextField(view.getUrl(),
"connectionInfo.url");
-
- bindings[4] = builder.bindToComboSelection(
- view.getAdapters(),
- "connectionInfo.dbAdapter", "Automatic");
+ TextBinder.bind(view.getUserName(), v -> {
+ DBConnectionInfo ci = connectionInfo;
+ if (ci != null) ci.setUserName(v);
+ });
+ TextBinder.bind(view.getPassword(), v -> {
+ DBConnectionInfo ci = connectionInfo;
+ if (ci != null) ci.setPassword(v);
+ });
+ TextBinder.bind(view.getDriver(), v -> {
+ DBConnectionInfo ci = connectionInfo;
+ if (ci != null) ci.setJdbcDriver(v);
+ });
+ TextBinder.bind(view.getUrl(), v -> {
+ DBConnectionInfo ci = connectionInfo;
+ if (ci != null) ci.setUrl(v);
+ });
+
+ view.getAdapters().addActionListener(e -> {
+ DBConnectionInfo ci = connectionInfo;
+ if (ci != null) {
+ Object sel = view.getAdapters().getSelectedItem();
+ ci.setDbAdapter("Automatic".equals(sel) ? null : (String) sel);
+ }
+ });
}
- public DBConnectionInfo getConnectionInfo() {
- return connectionInfo != null ? connectionInfo : emptyInfo;
+ @Override
+ public Component getView() {
+ return view;
}
public void setConnectionInfo(DBConnectionInfo connectionInfo) {
this.connectionInfo = connectionInfo;
- refreshView();
- }
- protected void refreshView() {
- getView().setEnabled(connectionInfo != null);
+ view.setEnabled(connectionInfo != null);
- for (ObjectBinding binding : bindings) {
- binding.updateView();
- }
+ DBConnectionInfo 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/editor/datanode/CustomDataSourceEditor.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/datanode/CustomDataSourceEditor.java
index a3bf188ec..ba9ad527c 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/datanode/CustomDataSourceEditor.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/datanode/CustomDataSourceEditor.java
@@ -21,16 +21,14 @@ package org.apache.cayenne.modeler.editor.datanode;
import org.apache.cayenne.configuration.DataNodeDescriptor;
import org.apache.cayenne.modeler.ProjectController;
-import org.apache.cayenne.swing.BindingBuilder;
+import org.apache.cayenne.modeler.util.TextBinder;
import org.apache.cayenne.swing.BindingDelegate;
-import org.apache.cayenne.swing.ObjectBinding;
/**
*/
public class CustomDataSourceEditor extends DataSourceEditor {
protected CustomDataSourceView view;
-
protected String factoryName;
public CustomDataSourceEditor(ProjectController controller,
BindingDelegate nodeChangeProcessor) {
@@ -44,12 +42,23 @@ public class CustomDataSourceEditor extends
DataSourceEditor {
}
@Override
- protected void prepareBindings(BindingBuilder builder) {
+ protected void initFieldListeners() {
this.view = new CustomDataSourceView();
- fieldAdapters = new ObjectBinding[2];
- fieldAdapters[0] = builder.bindToTextField(view.getFactoryName(),
"factoryName");
- fieldAdapters[1] = builder.bindToTextField(view.getLocationHint(),
"node.parameters");
+ TextBinder.bind(view.getFactoryName(), v -> {
+ setFactoryName(v);
+ nodeChangeProcessor.modelUpdated(null, null, null);
+ });
+ TextBinder.bind(view.getLocationHint(), v -> {
+ getNode().setParameters(v);
+ nodeChangeProcessor.modelUpdated(null, null, null);
+ });
+ }
+
+ @Override
+ protected void refreshView() {
+ view.getFactoryName().setText(factoryName);
+ view.getLocationHint().setText(getNode().getParameters());
}
@Override
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/datanode/DataSourceEditor.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/datanode/DataSourceEditor.java
index 051b68b9d..500325ed3 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/datanode/DataSourceEditor.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/datanode/DataSourceEditor.java
@@ -22,24 +22,20 @@ package org.apache.cayenne.modeler.editor.datanode;
import org.apache.cayenne.configuration.DataNodeDescriptor;
import org.apache.cayenne.modeler.ProjectController;
import org.apache.cayenne.modeler.util.CayenneController;
-import org.apache.cayenne.swing.BindingBuilder;
import org.apache.cayenne.swing.BindingDelegate;
-import org.apache.cayenne.swing.ObjectBinding;
import org.apache.cayenne.util.Util;
/**
*/
public abstract class DataSourceEditor extends CayenneController {
- protected ObjectBinding[] fieldAdapters;
private DataNodeDescriptor node;
protected BindingDelegate nodeChangeProcessor;
- public DataSourceEditor(ProjectController controller,
- BindingDelegate nodeChangeProcessor) {
+ public DataSourceEditor(ProjectController controller, BindingDelegate
nodeChangeProcessor) {
super(controller);
this.nodeChangeProcessor = nodeChangeProcessor;
- initBindings();
+ initFieldListeners();
}
public DataNodeDescriptor getNode() {
@@ -49,26 +45,11 @@ public abstract class DataSourceEditor extends
CayenneController {
public void setNode(DataNodeDescriptor node) {
if (!Util.nullSafeEquals(this.node, node)) {
this.node = node;
-
- for (ObjectBinding fieldAdapter : fieldAdapters) {
- fieldAdapter.updateView();
- }
+ refreshView();
}
}
- protected void initBindings() {
- BindingBuilder builder = new BindingBuilder(
- getApplication().getBindingFactory(),
- this);
- builder.setDelegate(nodeChangeProcessor);
- prepareBindings(builder);
- }
-
- protected abstract void prepareBindings(BindingBuilder builder);
+ protected abstract void initFieldListeners();
- protected void refreshView() {
- for (ObjectBinding fieldAdapter : fieldAdapters) {
- fieldAdapter.updateView();
- }
- }
+ protected abstract void refreshView();
}
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/datanode/JDBCDataSourceEditor.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/datanode/JDBCDataSourceEditor.java
index 2b66732a7..2d6d0a18b 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/datanode/JDBCDataSourceEditor.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/datanode/JDBCDataSourceEditor.java
@@ -26,9 +26,8 @@ import org.apache.cayenne.configuration.DataSourceDescriptor;
import org.apache.cayenne.modeler.CayenneModelerController;
import org.apache.cayenne.modeler.ProjectController;
import org.apache.cayenne.modeler.pref.DBConnectionInfo;
-import org.apache.cayenne.swing.BindingBuilder;
+import org.apache.cayenne.modeler.util.TextBinder;
import org.apache.cayenne.swing.BindingDelegate;
-import org.apache.cayenne.swing.ObjectBinding;
import org.apache.cayenne.util.Util;
public class JDBCDataSourceEditor extends DataSourceEditor {
@@ -42,7 +41,7 @@ public class JDBCDataSourceEditor extends DataSourceEditor {
public Component getView() {
return view;
}
-
+
@Override
public void setNode(DataNodeDescriptor node) {
if (!Util.nullSafeEquals(getNode(), node)) {
@@ -53,34 +52,58 @@ public class JDBCDataSourceEditor extends DataSourceEditor {
}
}
- protected void prepareBindings(BindingBuilder builder) {
+ @Override
+ protected void initFieldListeners() {
this.view = new JDBCDataSourceView();
-
- fieldAdapters = new ObjectBinding[6];
- fieldAdapters[0] =
- builder.bindToTextField(view.getUserName(),
"node.dataSourceDescriptor.userName");
- fieldAdapters[1] =
- builder.bindToTextField(view.getPassword(),
"node.dataSourceDescriptor.password");
- fieldAdapters[2] =
- builder.bindToTextField(view.getUrl(),
"node.dataSourceDescriptor.dataSourceUrl");
- fieldAdapters[3] =
- builder.bindToTextField(view.getDriver(),
"node.dataSourceDescriptor.jdbcDriver");
- fieldAdapters[4] =
- builder.bindToTextField(view.getMaxConnections(),
"node.dataSourceDescriptor.maxConnections");
- fieldAdapters[5] =
- builder.bindToTextField(view.getMinConnections(),
"node.dataSourceDescriptor.minConnections");
-
+
+ TextBinder.bind(view.getUserName(), v -> {
+ getNode().getDataSourceDescriptor().setUserName(v);
+ nodeChangeProcessor.modelUpdated(null, null, null);
+ });
+ TextBinder.bind(view.getPassword(), v -> {
+ getNode().getDataSourceDescriptor().setPassword(v);
+ nodeChangeProcessor.modelUpdated(null, null, null);
+ });
+ TextBinder.bind(view.getUrl(), v -> {
+ getNode().getDataSourceDescriptor().setDataSourceUrl(v);
+ nodeChangeProcessor.modelUpdated(null, null, null);
+ });
+ TextBinder.bind(view.getDriver(), v -> {
+ getNode().getDataSourceDescriptor().setJdbcDriver(v);
+ nodeChangeProcessor.modelUpdated(null, null, null);
+ });
+ TextBinder.bind(view.getMaxConnections(), v -> {
+ if (v != null) {
+ try {
+
getNode().getDataSourceDescriptor().setMaxConnections(Integer.parseInt(v));
+ nodeChangeProcessor.modelUpdated(null, null, null);
+ } catch (NumberFormatException ignored) {
+ }
+ }
+ });
+ TextBinder.bind(view.getMinConnections(), v -> {
+ if (v != null) {
+ try {
+
getNode().getDataSourceDescriptor().setMinConnections(Integer.parseInt(v));
+ nodeChangeProcessor.modelUpdated(null, null, null);
+ } catch (NumberFormatException ignored) {
+ }
+ }
+ });
view.getSyncWithLocal().addActionListener(e -> syncDataSourceAction());
}
-
- /**
- * This action is called whenever the password location is changed
- * in the GUI pulldown. It changes labels and editability of the
- * password fields depending on the option that was selected.
- */
-
+ @Override
+ protected void refreshView() {
+ DataSourceDescriptor d = getNode().getDataSourceDescriptor();
+ view.getUserName().setText(d.getUserName());
+ view.getPassword().setText(d.getPassword());
+ view.getUrl().setText(d.getDataSourceUrl());
+ view.getDriver().setText(d.getJdbcDriver());
+
view.getMaxConnections().setText(String.valueOf(d.getMaxConnections()));
+
view.getMinConnections().setText(String.valueOf(d.getMinConnections()));
+ }
public void syncDataSourceAction() {
CayenneModelerController mainController =
getApplication().getFrameController();
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/datanode/MainDataNodeEditor.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/datanode/MainDataNodeEditor.java
index 1f2b28f63..ba2bf85cd 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/datanode/MainDataNodeEditor.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/datanode/MainDataNodeEditor.java
@@ -42,6 +42,7 @@ import org.apache.cayenne.modeler.pref.DBConnectionInfo;
import org.apache.cayenne.modeler.pref.DataNodeDefaults;
import org.apache.cayenne.modeler.util.CayenneController;
import org.apache.cayenne.modeler.util.ProjectUtil;
+import org.apache.cayenne.modeler.util.TextBinder;
import org.apache.cayenne.swing.BindingBuilder;
import org.apache.cayenne.swing.BindingDelegate;
import org.apache.cayenne.swing.ObjectBinding;
@@ -194,13 +195,28 @@ public class MainDataNodeEditor extends CayenneController
{
// use delegate for the rest of them
- builder.setDelegate(nodeChangeProcessor);
+ TextBinder.bind(view.getDataNodeName(), v -> {
+ if (node == null) return;
+ String oldName = node.getName();
+ try {
+ setNodeName(v);
+ } catch (ValidationException ignored) {
+ return;
+ }
+ DataNodeEvent e = new
DataNodeEvent(MainDataNodeEditor.this, node);
+ e.setOldName(oldName);
+ ((ProjectController) getParent()).fireDataNodeEvent(e);
+ });
+
+ TextBinder.bind(view.getCustomAdapter(), v -> {
+ if (node == null) return;
+ setAdapterName(v);
+ ((ProjectController) getParent()).fireDataNodeEvent(new
DataNodeEvent(MainDataNodeEditor.this, node));
+ });
- bindings = new ObjectBinding[4];
- bindings[0] = builder.bindToTextField(view.getDataNodeName(),
"nodeName");
- bindings[1] = builder.bindToComboSelection(view.getFactories(),
"factoryName");
- bindings[2] =
builder.bindToComboSelection(view.getSchemaUpdateStrategy(),
"schemaUpdateStrategy");
- bindings[3] = builder.bindToTextField(view.getCustomAdapter(),
"adapterName");
+ bindings = new ObjectBinding[2];
+ bindings[0] = builder.bindToComboSelection(view.getFactories(),
"factoryName");
+ bindings[1] =
builder.bindToComboSelection(view.getSchemaUpdateStrategy(),
"schemaUpdateStrategy");
// one way bindings
view.getConfigLocalDataSources().addActionListener(e ->
dataSourceConfigAction());
@@ -244,6 +260,8 @@ public class MainDataNodeEditor extends CayenneController {
refreshLocalDataSources();
+ view.getDataNodeName().setText(getNodeName());
+ view.getCustomAdapter().setText(getAdapterName());
for (ObjectBinding binding : bindings) {
binding.updateView();
}
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/DBConnectionInfo.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/DBConnectionInfo.java
index b16e02d6e..d9a58e105 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/DBConnectionInfo.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/DBConnectionInfo.java
@@ -19,16 +19,6 @@
package org.apache.cayenne.modeler.pref;
-import java.io.PrintWriter;
-import java.sql.Connection;
-import java.sql.Driver;
-import java.sql.SQLException;
-import java.sql.SQLFeatureNotSupportedException;
-import java.util.logging.Logger;
-import java.util.prefs.Preferences;
-
-import javax.sql.DataSource;
-
import org.apache.cayenne.configuration.DataNodeDescriptor;
import org.apache.cayenne.configuration.DataSourceDescriptor;
import org.apache.cayenne.configuration.runtime.DbAdapterFactory;
@@ -39,6 +29,15 @@ import org.apache.cayenne.modeler.ClassLoadingService;
import org.apache.cayenne.pref.CayennePreference;
import org.apache.cayenne.util.Util;
+import javax.sql.DataSource;
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.logging.Logger;
+import java.util.prefs.Preferences;
+
public class DBConnectionInfo extends CayennePreference {
private static final String EMPTY_STRING = "";
@@ -49,8 +48,6 @@ public class DBConnectionInfo extends CayennePreference {
public static final String USER_NAME_PROPERTY = "userName";
private static final String DB_CONNECTION_INFO = "dbConnectionInfo";
- public static final String ID_PK_COLUMN = "id";
-
private String nodeName;
private String dbAdapter;
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/TextBinder.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/TextBinder.java
new file mode 100644
index 000000000..050234a14
--- /dev/null
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/TextBinder.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.util;
+
+import javax.swing.InputVerifier;
+import javax.swing.JComponent;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import java.util.function.Consumer;
+
+/**
+ * Utility for wiring Swing text components to model setters using default
content update rules.
+ * <p>
+ * For {@link JTextField}: registers both an {@code ActionListener} (fires on
Enter) and an {@code InputVerifier}
+ * (fires on focus loss) so every commit path is covered.
+ * <p>
+ * For {@link JTextArea}: registers a {@code DocumentListener} that fires on
every character change.
+ * <p>
+ * Empty strings are normalized to {@code null} before the consumer is called.
+ *
+ * @since 5.0
+ */
+public final class TextBinder {
+
+ private TextBinder() {
+ }
+
+ public static void bind(JTextField field, Consumer<String> onCommit) {
+ field.addActionListener(e ->
onCommit.accept(nullIfEmpty(field.getText())));
+ field.setInputVerifier(new InputVerifier() {
+ @Override
+ public boolean verify(JComponent c) {
+ onCommit.accept(nullIfEmpty(field.getText()));
+ return true;
+ }
+ });
+ }
+
+ public static void bind(JTextArea area, Consumer<String> onCommit) {
+ area.getDocument().addDocumentListener(new DocumentListener() {
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ onCommit.accept(nullIfEmpty(area.getText()));
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ onCommit.accept(nullIfEmpty(area.getText()));
+ }
+
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+ }
+ });
+ }
+
+ private static String nullIfEmpty(String s) {
+ return (s != null && s.isEmpty()) ? null : s;
+ }
+}