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

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

commit 56e15563ade026a4c8445ce6016b04dcd63c1497
Author: Arseni Bulatski <[email protected]>
AuthorDate: Fri Feb 15 14:44:11 2019 +0300

    CAY-2540 Modeler: redesign dbRelationship editor dialog
---
 RELEASE-NOTES.txt                                  |   1 +
 .../cayenne/modeler/DbRelationshipDialogView.java  | 230 ++++++++++++
 .../modeler/action/CreateRelationshipAction.java   |  16 +-
 .../modeler/dialog/DbRelationshipDialog.java       | 385 ++++++++++++++++++++
 .../dialog/ResolveDbRelationshipDialog.java        | 401 ---------------------
 .../dialog/objentity/DbRelationshipTarget.java     | 144 --------
 .../dialog/objentity/ObjRelationshipInfo.java      |  66 +---
 .../editor/dbentity/DbEntityRelationshipPanel.java |  56 ++-
 .../editor/dbentity/DbRelationshipTableModel.java  |  37 +-
 .../modeler/undo/RelationshipUndoableEdit.java     |  37 +-
 10 files changed, 707 insertions(+), 666 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 36274dd..4e52647 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -21,6 +21,7 @@ CAY-2511 Contribute custom properties for attributes
 CAY-2517 EventManager: optimization of adding listeners
 CAY-2518 Add method to append having qualifier expression to ObjectSelect
 CAY-2520 Split ObjectId into several specialized variants
+CAY-2540 Modeler: redesign dbRelationship editor dialog
 
 Bug Fixes:
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/DbRelationshipDialogView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/DbRelationshipDialogView.java
new file mode 100644
index 0000000..46f5369
--- /dev/null
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/DbRelationshipDialogView.java
@@ -0,0 +1,230 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+
+import com.jgoodies.forms.builder.PanelBuilder;
+import com.jgoodies.forms.layout.CellConstraints;
+import com.jgoodies.forms.layout.FormLayout;
+import org.apache.cayenne.modeler.pref.TableColumnPreferences;
+import org.apache.cayenne.modeler.util.CayenneDialog;
+import org.apache.cayenne.modeler.util.CayenneTable;
+import org.apache.cayenne.modeler.util.PanelFactory;
+
+/**
+ * @since 4.2
+ */
+public class DbRelationshipDialogView extends CayenneDialog {
+
+    private JTextField name;
+    private JComboBox<String> targetEntities;
+    private JCheckBox toDepPk;
+    private JCheckBox toMany;
+    private JTextField comment;
+    private JLabel sourceName;
+    private JTextField reverseName;
+    private CayenneTable table;
+    private TableColumnPreferences tablePreferences;
+    private JButton addButton;
+    private JButton removeButton;
+    private  JButton saveButton;
+    private JButton cancelButton;
+
+    private boolean cancelPressed;
+
+    public DbRelationshipDialogView() {
+        super(Application.getFrame(), "Create dbRelationship", true);
+
+        initView();
+        this.pack();
+        this.centerWindow();
+    }
+
+    private void initView() {
+        name = new JTextField(25);
+        targetEntities = new JComboBox<>();
+        toDepPk = new JCheckBox();
+        toMany = new JCheckBox();
+        comment = new JTextField(25);
+
+        sourceName = new JLabel();
+        reverseName = new JTextField(25);
+
+        addButton = new JButton("Add");
+
+        removeButton = new JButton("Remove");
+
+        saveButton = new JButton("Done");
+
+        cancelButton = new JButton("Cancel");
+
+        table = new AttributeTable();
+
+        
table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        tablePreferences = new TableColumnPreferences(getClass(), 
"dbentity/dbjoinTable");
+
+        getRootPane().setDefaultButton(saveButton);
+
+        getContentPane().setLayout(new BorderLayout());
+
+        CellConstraints cc = new CellConstraints();
+        PanelBuilder builder = new PanelBuilder(
+                new FormLayout(
+                        "right:max(50dlu;pref), 3dlu, fill:min(150dlu;pref), 
3dlu, fill:min(50dlu;pref)",
+                        "p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, 
p, 3dlu, p, 3dlu, " +
+                                "p, 3dlu, p, 9dlu, p, 3dlu, top:14dlu, 3dlu, 
top:p:grow"));
+        builder.setDefaultDialogBorder();
+
+        builder.addSeparator("Create dbRelationship", cc.xywh(1, 1, 5, 1));
+
+        builder.addLabel("Relationship Name:", cc.xy(1, 3));
+        builder.add(name, cc.xywh(3, 3, 1, 1));
+
+        builder.addLabel("Target Entity:", cc.xy(1, 5));
+        builder.add(targetEntities, cc.xywh(3, 5, 1, 1));
+
+        builder.addLabel("To Dep PK:", cc.xy(1, 7));
+        builder.add(toDepPk, cc.xywh(3, 7, 1, 1));
+
+        builder.addLabel("To Many:", cc.xy(1, 11));
+        builder.add(toMany, cc.xywh(3, 11, 1, 1));
+
+        builder.addLabel("Comment:", cc.xy(1, 13));
+        builder.add(comment, cc.xywh(3, 13, 1, 1));
+
+        builder.addSeparator("DbRelationship Information", cc.xywh(1, 15, 5, 
1));
+
+        builder.addLabel("Source Entity:", cc.xy(1, 17));
+        builder.add(sourceName, cc.xywh(3, 17, 1, 1));
+
+        builder.addLabel("Reverse Relationship Name:", cc.xy(1, 19));
+        builder.add(reverseName, cc.xywh(3, 19, 1, 1));
+
+        builder.addSeparator("Joins", cc.xywh(1, 21, 5, 1));
+        builder.add(new JScrollPane(table), cc.xywh(1, 23, 3, 3, "fill, 
fill"));
+
+        JPanel joinButtons = new JPanel(new FlowLayout(FlowLayout.LEADING));
+        joinButtons.add(addButton);
+        joinButtons.add(removeButton);
+
+        builder.add(joinButtons, cc.xywh(5, 23, 1, 3));
+
+        getContentPane().add(builder.getPanel(), BorderLayout.CENTER);
+        JButton[] buttons = {cancelButton, saveButton};
+        getContentPane().add(PanelFactory.createButtonPanel(buttons), 
BorderLayout.SOUTH);
+    }
+
+    public void enableOptions(boolean enable) {
+        saveButton.setEnabled(enable);
+        reverseName.setEnabled(enable);
+        addButton.setEnabled(enable);
+        removeButton.setEnabled(enable);
+    }
+
+    @Override
+    public void setVisible(boolean b) {
+        if(b && cancelPressed) {
+            return;
+        }
+        super.setVisible(b);
+    }
+
+    public JTextField getNameField() {
+        return name;
+    }
+
+    public JComboBox<String> getTargetEntities() {
+        return targetEntities;
+    }
+
+    public JCheckBox getToDepPk() {
+        return toDepPk;
+    }
+
+    public JCheckBox getToMany() {
+        return toMany;
+    }
+
+    public JTextField getComment() {
+        return comment;
+    }
+
+    public JLabel getSourceName() {
+        return sourceName;
+    }
+
+    public JTextField getReverseName() {
+        return reverseName;
+    }
+
+    public CayenneTable getTable() {
+        return table;
+    }
+
+    public TableColumnPreferences getTablePreferences() {
+        return tablePreferences;
+    }
+
+    public JButton getAddButton() {
+        return addButton;
+    }
+
+    public JButton getRemoveButton() {
+        return removeButton;
+    }
+
+    public JButton getSaveButton() {
+        return saveButton;
+    }
+
+    public JButton getCancelButton() {
+        return cancelButton;
+    }
+
+    public boolean isCancelPressed() {
+        return cancelPressed;
+    }
+
+    public void setCancelPressed(boolean cancelPressed) {
+        this.cancelPressed = cancelPressed;
+    }
+
+    final class AttributeTable extends CayenneTable {
+
+        final Dimension preferredSize = new Dimension(203, 100);
+
+        @Override
+        public Dimension getPreferredScrollableViewportSize() {
+            return preferredSize;
+        }
+    }
+
+}
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/CreateRelationshipAction.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/CreateRelationshipAction.java
index 07cfbc3..9c74e42 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/CreateRelationshipAction.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/CreateRelationshipAction.java
@@ -19,6 +19,8 @@
 
 package org.apache.cayenne.modeler.action;
 
+import java.awt.event.ActionEvent;
+
 import org.apache.cayenne.configuration.ConfigurationNode;
 import org.apache.cayenne.configuration.DataChannelDescriptor;
 import org.apache.cayenne.dbsync.naming.NameBuilder;
@@ -32,13 +34,12 @@ import org.apache.cayenne.map.event.MapEvent;
 import org.apache.cayenne.map.event.RelationshipEvent;
 import org.apache.cayenne.modeler.Application;
 import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.dialog.DbRelationshipDialog;
 import org.apache.cayenne.modeler.event.RelationshipDisplayEvent;
 import org.apache.cayenne.modeler.undo.CreateRelationshipUndoableEdit;
 import org.apache.cayenne.modeler.util.CayenneAction;
 import org.apache.cayenne.util.DeleteRuleUpdater;
 
-import java.awt.event.ActionEvent;
-
 public class CreateRelationshipAction extends CayenneAction {
 
     /**
@@ -102,12 +103,9 @@ public class CreateRelationshipAction extends 
CayenneAction {
             DbEntity dbEnt = getProjectController().getCurrentDbEntity();
             if (dbEnt != null) {
 
-                DbRelationship rel = new DbRelationship();
-                rel.setName(NameBuilder.builder(rel, dbEnt).name());
-                createDbRelationship(dbEnt, rel);
-
-                application.getUndoManager().addEdit(
-                        new CreateRelationshipUndoableEdit(dbEnt, new 
DbRelationship[]{rel}));
+                new DbRelationshipDialog(getProjectController())
+                        .createNewRaltionship(dbEnt)
+                        .startUp();
             }
         }
     }
@@ -124,8 +122,6 @@ public class CreateRelationshipAction extends CayenneAction 
{
 
     public void createDbRelationship(DbEntity dbEntity, DbRelationship rel) {
         ProjectController mediator = getProjectController();
-
-        rel.setSourceEntity(dbEntity);
         dbEntity.addRelationship(rel);
 
         fireDbRelationshipEvent(this, mediator, dbEntity, rel);
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/DbRelationshipDialog.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/DbRelationshipDialog.java
new file mode 100644
index 0000000..92f49d9
--- /dev/null
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/DbRelationshipDialog.java
@@ -0,0 +1,385 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.dialog;
+
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.table.TableColumn;
+import java.awt.Component;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.dbsync.naming.NameBuilder;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbJoin;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.event.MapEvent;
+import org.apache.cayenne.map.event.RelationshipEvent;
+import org.apache.cayenne.modeler.Application;
+import org.apache.cayenne.modeler.DbRelationshipDialogView;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.event.RelationshipDisplayEvent;
+import org.apache.cayenne.modeler.undo.CreateRelationshipUndoableEdit;
+import org.apache.cayenne.modeler.undo.RelationshipUndoableEdit;
+import org.apache.cayenne.modeler.util.CayenneController;
+import org.apache.cayenne.modeler.util.ModelerUtil;
+import org.apache.cayenne.modeler.util.combo.AutoCompletion;
+import org.apache.cayenne.project.extension.info.ObjectInfo;
+import org.apache.cayenne.util.Util;
+
+/**
+ * @since 4.2
+ */
+public class DbRelationshipDialog extends CayenneController {
+
+    private DbRelationship relationship;
+    private DbRelationship reverseRelationship;
+
+    private DbRelationshipDialogView view;
+
+    private boolean isCreate = false;
+
+    private ProjectController projectController;
+
+    private RelationshipUndoableEdit undo;
+
+    public DbRelationshipDialog(ProjectController projectController) {
+        this.view = new DbRelationshipDialogView();
+        this.projectController = projectController;
+    }
+
+    @Override
+    public Component getView() {
+        return view;
+    }
+
+    public DbRelationshipDialog createNewRaltionship(DbEntity dbEntity) {
+        isCreate = true;
+
+        DbRelationship rel = new DbRelationship();
+        rel.setName(NameBuilder.builder(rel, dbEntity).name());
+        rel.setSourceEntity(dbEntity);
+
+        return modifyRaltionship(rel);
+    }
+
+    public DbRelationshipDialog modifyRaltionship(DbRelationship 
dbRelationship) {
+        this.undo = new RelationshipUndoableEdit(dbRelationship);
+
+        this.relationship = dbRelationship;
+        this.reverseRelationship = this.relationship.getReverseRelationship();
+
+        if (relationship.getSourceEntity() == null) {
+            throw new CayenneRuntimeException("Null source entity: %s", 
relationship);
+        }
+        if (relationship.getSourceEntity().getDataMap() == null) {
+            throw new CayenneRuntimeException("Null DataMap: %s", 
relationship.getSourceEntity());
+        }
+
+        initController();
+        initFromModel();
+
+        return this;
+    }
+
+    public void startUp() {
+        view.setVisible(true);
+        view.dispose();
+    }
+
+    private void initFromModel() {
+        TargetComboBoxModel targetComboBoxModel = new 
TargetComboBoxModel(relationship
+                .getSourceEntity().getDataMap().getDbEntities());
+        view.getTargetEntities().setModel(targetComboBoxModel);
+
+        view.getSourceName().setText(relationship.getSourceEntityName());
+        view.getToDepPk().setSelected(relationship.isToDependentPK());
+        view.getToMany().setSelected(relationship.isToMany());
+
+        view.getNameField().setText(relationship.getName());
+        if(reverseRelationship != null) {
+            view.getReverseName().setText(reverseRelationship.getName());
+        }
+
+        if(relationship.getTargetEntity() == null) {
+            enableOptions(false);
+        } else {
+            enableInfo();
+        }
+
+        view.getComment().setText(ObjectInfo
+                
.getFromMetaData(projectController.getApplication().getMetaData(),
+                        relationship,
+                        ObjectInfo.COMMENT));
+    }
+
+    private void initController() {
+        view.getTargetEntities().addActionListener(action -> {
+            String selectedItem = 
(String)view.getTargetEntities().getSelectedItem();
+            if(relationship.getTargetEntityName() == null) {
+                relationship.setTargetEntityName(selectedItem);
+            } else {
+                if 
(WarningDialogByDbTargetChange.showWarningDialog(projectController, 
relationship)) {
+                    // clear joins...
+                    relationship.removeAllJoins();
+                    relationship.setTargetEntityName(selectedItem);
+                }
+                projectController.fireDbRelationshipEvent(new 
RelationshipEvent(this, relationship, relationship.getSourceEntity()));
+            }
+            enableInfo();
+        });
+
+        view.getAddButton().addActionListener(e -> {
+            DbJoinTableModel model = (DbJoinTableModel) 
view.getTable().getModel();
+
+            DbJoin join = new DbJoin(relationship);
+            model.addRow(join);
+
+            view.getTable().select(model.getRowCount() - 1);
+        });
+
+        view.getRemoveButton().addActionListener(e -> {
+            DbJoinTableModel model = (DbJoinTableModel) 
view.getTable().getModel();
+            stopEditing();
+            int row = view.getTable().getSelectedRow();
+
+            DbJoin join = model.getJoin(row);
+
+            model.removeRow(join);
+        });
+
+        view.getSaveButton().addActionListener(e -> {
+            view.setCancelPressed(false);
+            save();
+            view.dispose();
+            view.setVisible(false);
+        });
+
+        view.getCancelButton().addActionListener(e -> {
+            view.setCancelPressed(true);
+            view.setVisible(false);
+        });
+
+        view.addWindowListener(new WindowAdapter()
+        {
+            @Override
+            public void windowClosing(WindowEvent e) {
+                view.setCancelPressed(true);
+            }
+        });
+
+        view.getToDepPk().setEnabled(false);
+    }
+
+    private void enableInfo() {
+        enableOptions(true);
+
+        view.getTable().setModel(new DbJoinTableModel(relationship,
+                projectController, this, true));
+        TableColumn sourceColumn = 
view.getTable().getColumnModel().getColumn(DbJoinTableModel.SOURCE);
+        JComboBox comboBox = Application.getWidgetFactory().createComboBox(
+                
ModelerUtil.getDbAttributeNames(relationship.getSourceEntity()), true);
+
+        AutoCompletion.enable(comboBox);
+        
sourceColumn.setCellEditor(Application.getWidgetFactory().createCellEditor(comboBox));
+
+        TableColumn targetColumn = 
view.getTable().getColumnModel().getColumn(DbJoinTableModel.TARGET);
+        comboBox = Application.getWidgetFactory().createComboBox(
+                
ModelerUtil.getDbAttributeNames(relationship.getTargetEntity()), true);
+        AutoCompletion.enable(comboBox);
+
+        
targetColumn.setCellEditor(Application.getWidgetFactory().createCellEditor(comboBox));
+
+        view.getTablePreferences().bind(view.getTable(), null, null, null, 
DbJoinTableModel.SOURCE, true);
+    }
+
+    private void enableOptions(boolean enable) {
+        view.enableOptions(enable);
+    }
+
+    private void stopEditing() {
+        // Stop whatever editing may be taking place
+        int col_index = view.getTable().getEditingColumn();
+        if (col_index >= 0) {
+            TableColumn col = 
view.getTable().getColumnModel().getColumn(col_index);
+            col.getCellEditor().stopCellEditing();
+        }
+    }
+
+    private void save() {
+        stopEditing();
+
+        DbJoinTableModel model = (DbJoinTableModel) view.getTable().getModel();
+        boolean updatingReverse = model.getObjectList().size() > 0;
+
+        // handle name update
+        handleNameUpdate(relationship, view.getNameField().getText().trim());
+
+        model.commit();
+
+        relationship.setToMany(view.getToMany().isSelected());
+
+        // check "to dep pk" setting,
+        // maybe this is no longer valid
+        if (relationship.isToDependentPK() && !relationship.isValidForDepPk()) 
{
+            relationship.setToDependentPK(false);
+        }
+
+        
ObjectInfo.putToMetaData(projectController.getApplication().getMetaData(),
+                relationship,
+                ObjectInfo.COMMENT, view.getComment().getText());
+        // If new reverse DbRelationship was created, add it to the target
+        // Don't create reverse with no joins - makes no sense...
+        if (updatingReverse) {
+
+            // If didn't find anything, create reverseDbRel
+            if (reverseRelationship == null) {
+                reverseRelationship = new DbRelationship();
+                reverseRelationship.setName(NameBuilder
+                        .builder(reverseRelationship, 
relationship.getTargetEntity())
+                        .baseName(view.getReverseName().getText().trim())
+                        .name());
+
+                
reverseRelationship.setSourceEntity(relationship.getTargetEntity());
+                
reverseRelationship.setTargetEntityName(relationship.getSourceEntity());
+                reverseRelationship.setToMany(!relationship.isToMany());
+                
relationship.getTargetEntity().addRelationship(reverseRelationship);
+
+                // fire only if the relationship is to the same entity...
+                // this is needed to update entity view...
+                if (relationship.getSourceEntity() == 
relationship.getTargetEntity()) {
+                    projectController
+                            .fireDbRelationshipEvent(
+                            new RelationshipEvent(
+                                    this,
+                                    reverseRelationship,
+                                    reverseRelationship.getSourceEntity(),
+                                    MapEvent.ADD));
+                }
+            } else {
+                handleNameUpdate(reverseRelationship, 
view.getReverseName().getText().trim());
+            }
+
+            Collection<DbJoin> reverseJoins = getReverseJoins();
+            reverseRelationship.setJoins(reverseJoins);
+
+            // check if joins map to a primary key of this entity
+            if (!relationship.isToDependentPK() && 
reverseRelationship.isValidForDepPk()) {
+                reverseRelationship.setToDependentPK(true);
+            }
+        }
+
+        fireDbRelationshipEvent(isCreate);
+    }
+
+    private void handleNameUpdate(DbRelationship relationship, String 
userInputName) {
+        if(Util.nullSafeEquals(relationship.getName(), userInputName)) {
+            return;
+        }
+
+        String sourceEntityName = NameBuilder
+                .builder(relationship, relationship.getSourceEntity())
+                .baseName(userInputName)
+                .name();
+
+        if (Util.nullSafeEquals(sourceEntityName, relationship.getName())) {
+            return;
+        }
+        String oldName = relationship.getName();
+        relationship.setName(sourceEntityName);
+
+        projectController
+                .fireDbRelationshipEvent(
+                new RelationshipEvent(this, relationship, 
relationship.getSourceEntity(), oldName));
+    }
+
+    private Collection<DbJoin> getReverseJoins() {
+        Collection<DbJoin> joins = relationship.getJoins();
+
+        if ((joins == null) || (joins.size() == 0)) {
+            return Collections.emptyList();
+        }
+
+        List<DbJoin> reverseJoins = new ArrayList<>(joins.size());
+
+        // Loop through the list of attribute pairs, create reverse pairs
+        // and put them to the reverse list.
+        for (DbJoin pair : joins) {
+            DbJoin reverseJoin = pair.createReverseJoin();
+
+            // since reverse relationship is not yet initialized,
+            // reverse join will not have it set automatically
+            reverseJoin.setRelationship(reverseRelationship);
+            reverseJoins.add(reverseJoin);
+        }
+
+        return reverseJoins;
+    }
+
+    private void fireDbRelationshipEvent(boolean isCreate) {
+        if(!isCreate) {
+            projectController
+                    .fireDbRelationshipEvent(
+                            new RelationshipEvent(this, relationship, 
relationship.getSourceEntity(), MapEvent.CHANGE));
+
+            Application.getInstance().getUndoManager().addEdit(undo);
+        } else {
+            DbEntity dbEntity = relationship.getSourceEntity();
+            if(dbEntity.getRelationship(relationship.getName()) == null) {
+                dbEntity.addRelationship(relationship);
+            }
+
+            projectController.fireDbRelationshipEvent(new 
RelationshipEvent(this, relationship, dbEntity, MapEvent.ADD));
+
+            RelationshipDisplayEvent rde = new RelationshipDisplayEvent(this, 
relationship, dbEntity, projectController.getCurrentDataMap(),
+                    (DataChannelDescriptor) 
projectController.getProject().getRootNode());
+
+            projectController.fireDbRelationshipDisplayEvent(rde);
+
+            Application.getInstance().getUndoManager().addEdit(
+                    new 
CreateRelationshipUndoableEdit(relationship.getSourceEntity(), new 
DbRelationship[]{relationship}));
+        }
+    }
+
+    public Optional<DbRelationship> getRelationship() {
+        return view.isCancelPressed() ? Optional.empty() : 
Optional.of(relationship);
+    }
+
+    final class TargetComboBoxModel extends DefaultComboBoxModel<String> {
+
+        TargetComboBoxModel(Collection<DbEntity> dbEntities) {
+            super();
+            dbEntities.forEach(dbEntity -> 
this.addElement(dbEntity.getName()));
+            if(relationship.getTargetEntity() == null) {
+                this.setSelectedItem(null);
+            } else {
+                this.setSelectedItem(relationship.getTargetEntity().getName());
+            }
+        }
+
+    }
+}
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/ResolveDbRelationshipDialog.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/ResolveDbRelationshipDialog.java
deleted file mode 100644
index d708e00..0000000
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/ResolveDbRelationshipDialog.java
+++ /dev/null
@@ -1,401 +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
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-
-package org.apache.cayenne.modeler.dialog;
-
-import com.jgoodies.forms.builder.PanelBuilder;
-import com.jgoodies.forms.layout.CellConstraints;
-import com.jgoodies.forms.layout.FormLayout;
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.dbsync.naming.NameBuilder;
-import org.apache.cayenne.map.DbJoin;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.event.MapEvent;
-import org.apache.cayenne.map.event.RelationshipEvent;
-import org.apache.cayenne.modeler.Application;
-import org.apache.cayenne.modeler.pref.TableColumnPreferences;
-import org.apache.cayenne.modeler.undo.RelationshipUndoableEdit;
-import org.apache.cayenne.modeler.util.CayenneDialog;
-import org.apache.cayenne.modeler.util.CayenneTable;
-import org.apache.cayenne.modeler.util.ModelerUtil;
-import org.apache.cayenne.modeler.util.PanelFactory;
-import org.apache.cayenne.modeler.util.combo.AutoCompletion;
-import org.apache.cayenne.util.Util;
-
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextField;
-import javax.swing.ListSelectionModel;
-import javax.swing.table.TableColumn;
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Editor of DbRelationship joins.
- */
-public class ResolveDbRelationshipDialog extends CayenneDialog {
-
-    protected DbRelationship relationship;
-    protected DbRelationship reverseRelationship;
-
-    protected JLabel sourceName;
-    protected JLabel targetName;
-    protected JTextField name;
-    protected JTextField reverseName;
-    protected CayenneTable table;
-    protected TableColumnPreferences tablePreferences;
-    protected JButton addButton;
-    protected JButton removeButton;
-    protected JButton saveButton;
-    protected JButton cancelButton;
-
-    private boolean cancelPressed;
-
-    private RelationshipUndoableEdit undo;
-
-    private boolean editable;
-
-    public ResolveDbRelationshipDialog(DbRelationship relationship) {
-        this(relationship, true);
-    }
-
-    public ResolveDbRelationshipDialog(DbRelationship relationship, boolean 
editable) {
-        super(Application.getFrame(), "DbRelationship Inspector", true);
-        this.editable = editable;
-
-        if(!validateAndSetRelationship(relationship)) {
-            this.cancelPressed = true;
-            return;
-        }
-
-        initView();
-        initController();
-        initWithModel();
-
-        this.undo = new RelationshipUndoableEdit(relationship);
-
-        this.pack();
-        this.centerWindow();
-
-    }
-
-    @Override
-    public void setVisible(boolean b) {
-        if(b && cancelPressed) {
-            return;
-        }
-        super.setVisible(b);
-    }
-
-    /**
-     * Creates graphical components.
-     */
-    private void initView() {
-
-        // create widgets
-        sourceName = new JLabel();
-        targetName = new JLabel();
-        name = new JTextField(25);
-        reverseName = new JTextField(25);
-
-        addButton = new JButton("Add");
-        addButton.setEnabled(this.editable);
-
-        removeButton = new JButton("Remove");
-        removeButton.setEnabled(this.editable);
-
-        saveButton = new JButton("Done");
-
-        cancelButton = new JButton("Cancel");
-        cancelButton.setEnabled(this.editable);
-
-        table = new AttributeTable();
-
-        
table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-        tablePreferences = new TableColumnPreferences(getClass(), 
"dbentity/dbjoinTable");
-
-        getRootPane().setDefaultButton(saveButton);
-
-        // assemble
-        getContentPane().setLayout(new BorderLayout());
-
-        CellConstraints cc = new CellConstraints();
-        PanelBuilder builder = new PanelBuilder(
-                new FormLayout(
-                        "right:max(50dlu;pref), 3dlu, fill:min(150dlu;pref), 
3dlu, fill:min(50dlu;pref)",
-                        "p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 9dlu, p, 3dlu, 
top:14dlu, 3dlu, top:p:grow"));
-        builder.setDefaultDialogBorder();
-
-        builder.addSeparator("DbRelationship Information", cc.xywh(1, 1, 5, 
1));
-
-        builder.addLabel("Source Entity:", cc.xy(1, 3));
-        builder.add(sourceName, cc.xywh(3, 3, 1, 1));
-
-        builder.addLabel("Target Entity:", cc.xy(1, 5));
-        builder.add(targetName, cc.xywh(3, 5, 1, 1));
-
-        builder.addLabel("Relationship Name:", cc.xy(1, 7));
-        builder.add(name, cc.xywh(3, 7, 1, 1));
-
-        builder.addLabel("Reverse Relationship Name:", cc.xy(1, 9));
-        builder.add(reverseName, cc.xywh(3, 9, 1, 1));
-
-        builder.addSeparator("Joins", cc.xywh(1, 11, 5, 1));
-        builder.add(new JScrollPane(table), cc.xywh(1, 13, 3, 3, "fill, 
fill"));
-
-        JPanel joinButtons = new JPanel(new FlowLayout(FlowLayout.LEADING));
-        joinButtons.add(addButton);
-        joinButtons.add(removeButton);
-
-        builder.add(joinButtons, cc.xywh(5, 13, 1, 3));
-
-        getContentPane().add(builder.getPanel(), BorderLayout.CENTER);
-        JButton[] buttons = {cancelButton, saveButton};
-        getContentPane().add(PanelFactory.createButtonPanel(buttons), 
BorderLayout.SOUTH);
-    }
-
-    private boolean validateAndSetRelationship(DbRelationship relationship) {
-        this.relationship = relationship;
-        this.reverseRelationship = relationship.getReverseRelationship();
-        // sanity check
-        if (relationship.getSourceEntity() == null) {
-            throw new CayenneRuntimeException("Null source entity: %s", 
relationship);
-        }
-        if (relationship.getSourceEntity().getDataMap() == null) {
-            throw new CayenneRuntimeException("Null DataMap: %s", 
relationship.getSourceEntity());
-        }
-
-        // warn if no target entity
-        if (relationship.getTargetEntity() == null) {
-            JOptionPane.showMessageDialog(
-                    this,
-                    "Please select target DbEntity first",
-                    "Select target",
-                    JOptionPane.INFORMATION_MESSAGE);
-            return false;
-        }
-
-        return true;
-    }
-
-    private void initWithModel() {
-        // init UI components
-        sourceName.setText(relationship.getSourceEntityName());
-        targetName.setText(relationship.getTargetEntityName());
-        name.setText(relationship.getName());
-        if (reverseRelationship != null) {
-            reverseName.setText(reverseRelationship.getName());
-        }
-
-        table.setModel(new DbJoinTableModel(relationship, getMediator(), this, 
true));
-        TableColumn sourceColumn = 
table.getColumnModel().getColumn(DbJoinTableModel.SOURCE);
-        JComboBox comboBox = Application.getWidgetFactory().createComboBox(
-                
ModelerUtil.getDbAttributeNames(relationship.getSourceEntity()), true);
-
-        AutoCompletion.enable(comboBox);
-        
sourceColumn.setCellEditor(Application.getWidgetFactory().createCellEditor(comboBox));
-
-        TableColumn targetColumn = 
table.getColumnModel().getColumn(DbJoinTableModel.TARGET);
-        comboBox = Application.getWidgetFactory().createComboBox(
-                
ModelerUtil.getDbAttributeNames(relationship.getTargetEntity()), true);
-        AutoCompletion.enable(comboBox);
-
-        
targetColumn.setCellEditor(Application.getWidgetFactory().createCellEditor(comboBox));
-
-        tablePreferences.bind(table, null, null, null, 
DbJoinTableModel.SOURCE, true);
-    }
-
-    private void initController() {
-        addButton.addActionListener(e -> {
-            DbJoinTableModel model = (DbJoinTableModel) table.getModel();
-
-            DbJoin join = new DbJoin(relationship);
-            model.addRow(join);
-
-            undo.addDbJoinAddUndo(join);
-
-            table.select(model.getRowCount() - 1);
-        });
-
-        removeButton.addActionListener(e -> {
-            DbJoinTableModel model = (DbJoinTableModel) table.getModel();
-            stopEditing();
-            int row = table.getSelectedRow();
-
-            DbJoin join = model.getJoin(row);
-            undo.addDbJoinRemoveUndo(join);
-
-            model.removeRow(join);
-        });
-
-        saveButton.addActionListener(e -> {
-            cancelPressed = false;
-
-            if (editable) {
-                save();
-            }
-
-            dispose();
-        });
-
-        cancelButton.addActionListener(e -> {
-            cancelPressed = true;
-            setVisible(false);
-        });
-    }
-
-    public boolean isCancelPressed() {
-        return cancelPressed;
-    }
-
-    private void stopEditing() {
-        // Stop whatever editing may be taking place
-        int col_index = table.getEditingColumn();
-        if (col_index >= 0) {
-            TableColumn col = table.getColumnModel().getColumn(col_index);
-            col.getCellEditor().stopCellEditing();
-        }
-    }
-
-    private void save() {
-        stopEditing();
-
-        DbJoinTableModel model = (DbJoinTableModel) table.getModel();
-        boolean updatingReverse = model.getObjectList().size() > 0;
-
-        // handle name update
-        handleNameUpdate(relationship, name.getText().trim());
-
-        model.commit();
-
-        // check "to dep pk" setting,
-        // maybe this is no longer valid
-        if (relationship.isToDependentPK() && !relationship.isValidForDepPk()) 
{
-            relationship.setToDependentPK(false);
-        }
-
-        // If new reverse DbRelationship was created, add it to the target
-        // Don't create reverse with no joins - makes no sense...
-        if (updatingReverse) {
-
-            // If didn't find anything, create reverseDbRel
-            if (reverseRelationship == null) {
-                reverseRelationship = new DbRelationship();
-                reverseRelationship.setName(NameBuilder
-                        .builder(reverseRelationship, 
relationship.getTargetEntity())
-                        .baseName(reverseName.getText().trim())
-                        .name());
-
-                
reverseRelationship.setSourceEntity(relationship.getTargetEntity());
-                
reverseRelationship.setTargetEntityName(relationship.getSourceEntity());
-                reverseRelationship.setToMany(!relationship.isToMany());
-                
relationship.getTargetEntity().addRelationship(reverseRelationship);
-
-                // fire only if the relationship is to the same entity...
-                // this is needed to update entity view...
-                if (relationship.getSourceEntity() == 
relationship.getTargetEntity()) {
-                    getMediator().fireDbRelationshipEvent(
-                            new RelationshipEvent(
-                                    this,
-                                    reverseRelationship,
-                                    reverseRelationship.getSourceEntity(),
-                                    MapEvent.ADD));
-                }
-            } else {
-                handleNameUpdate(reverseRelationship, 
reverseName.getText().trim());
-            }
-
-            Collection<DbJoin> reverseJoins = getReverseJoins();
-            reverseRelationship.setJoins(reverseJoins);
-
-            // check if joins map to a primary key of this entity
-            if (!relationship.isToDependentPK() && 
reverseRelationship.isValidForDepPk()) {
-                reverseRelationship.setToDependentPK(true);
-            }
-        }
-
-        Application.getInstance().getUndoManager().addEdit(undo);
-
-        getMediator().fireDbRelationshipEvent(
-                new RelationshipEvent(this, relationship, 
relationship.getSourceEntity()));
-    }
-
-    private void handleNameUpdate(DbRelationship relationship, String 
userInputName) {
-        if(Util.nullSafeEquals(relationship.getName(), userInputName)) {
-            return;
-        }
-
-        String sourceEntityName = NameBuilder
-                .builder(relationship, relationship.getSourceEntity())
-                .baseName(userInputName)
-                .name();
-
-        if (Util.nullSafeEquals(sourceEntityName, relationship.getName())) {
-            return;
-        }
-        String oldName = relationship.getName();
-        relationship.setName(sourceEntityName);
-        undo.addNameUndo(relationship, oldName, sourceEntityName);
-
-        getMediator().fireDbRelationshipEvent(
-                new RelationshipEvent(this, relationship, 
relationship.getSourceEntity(), oldName));
-    }
-
-    private Collection<DbJoin> getReverseJoins() {
-        Collection<DbJoin> joins = relationship.getJoins();
-
-        if ((joins == null) || (joins.size() == 0)) {
-            return Collections.emptyList();
-        }
-
-        List<DbJoin> reverseJoins = new ArrayList<>(joins.size());
-
-        // Loop through the list of attribute pairs, create reverse pairs
-        // and put them to the reverse list.
-        for (DbJoin pair : joins) {
-            DbJoin reverseJoin = pair.createReverseJoin();
-
-            // since reverse relationship is not yet initialized,
-            // reverse join will not have it set automatically
-            reverseJoin.setRelationship(reverseRelationship);
-            reverseJoins.add(reverseJoin);
-        }
-
-        return reverseJoins;
-    }
-
-    final class AttributeTable extends CayenneTable {
-
-        final Dimension preferredSize = new Dimension(203, 100);
-
-        @Override
-        public Dimension getPreferredScrollableViewportSize() {
-            return preferredSize;
-        }
-    }
-}
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/DbRelationshipTarget.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/DbRelationshipTarget.java
deleted file mode 100644
index 5927e58..0000000
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/DbRelationshipTarget.java
+++ /dev/null
@@ -1,144 +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
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-package org.apache.cayenne.modeler.dialog.objentity;
-
-import java.awt.Component;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.JOptionPane;
-import javax.swing.WindowConstants;
-
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.EntityResolver;
-import org.apache.cayenne.modeler.ProjectController;
-import org.apache.cayenne.modeler.util.CayenneController;
-import org.apache.cayenne.modeler.util.CellRenderers;
-import org.apache.cayenne.modeler.util.Comparators;
-
-public class DbRelationshipTarget extends CayenneController {
-
-    private DbEntity source1;
-    private DbEntity source2;
-    protected DbEntity relTarget;
-    protected List<DbEntity> relTargets;
-
-    protected DbEntity source;
-    protected CayenneController mediator;
-    protected boolean source1Selected;
-    protected DbRelationshipTargetView view;
-    protected boolean toMany;
-    protected boolean savePressed;
-
-    public DbRelationshipTarget(ProjectController mediator, DbEntity source1, 
DbEntity source2) {
-        super(mediator);
-        view = new DbRelationshipTargetView(source1, source2);
-        initController();
-        view.getSource1Button().setSelected(true);
-        view.getToManyCheckBox().setSelected(false);
-        setSource(source1, true);
-        this.mediator = mediator;
-        this.source1 = source1;
-        this.source2 = source2;
-
-        EntityResolver resolver = mediator.getEntityResolver();
-        this.relTargets = new ArrayList<>(resolver.getDbEntities());
-        relTargets.sort(Comparators.getNamedObjectComparator());
-
-        DbEntity[] dbEntities = relTargets.toArray(new DbEntity[0]);
-
-        DefaultComboBoxModel<DbEntity> dbModel = new 
DefaultComboBoxModel<>(dbEntities);
-        
view.targetCombo.setRenderer(CellRenderers.entityListRendererWithIcons(mediator.getCurrentDataMap()));
-        view.targetCombo.removeAllItems();
-        view.targetCombo.setModel(dbModel);
-    }
-        
-    private void initController() {
-        view.getCancelButton().addActionListener(e -> view.dispose());
-        view.getSaveButton().addActionListener(e -> save());
-        view.getSource1Button().addActionListener(e -> setSource(source1, 
true));
-        view.getSource2Button().addActionListener(e -> setSource(source2, 
false));
-        view.getToManyCheckBox().addChangeListener(e -> toMany = 
view.getToManyCheckBox().isSelected());
-    }
-    
-    @Override
-    public Component getView() {
-        return view;
-    }
-    
-    protected void save() {
-        this.relTarget = relTargets.get(view.targetCombo.getSelectedIndex());
-        DbEntity target = getTarget();
-
-        if (target == null) {
-            JOptionPane.showMessageDialog(getView(), "Please select target 
entity first.",
-                    "Warning", JOptionPane.WARNING_MESSAGE);
-            return;
-        }
-        
-        savePressed = true;
-        view.dispose();
-    }
-    
-    /**
-     * Creates and runs the dialog.
-     */
-    public void startupAction() {
-        view.pack();
-        view.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
-        view.setModal(true);
-        makeCloseableOnEscape();
-        centerView();
-        view.setVisible(true);
-    }
-    
-    boolean isSavePressed() {
-        return savePressed;
-    }
-    
-    public List<DbEntity> getTargets() {
-        return relTargets;
-    }
-    
-    public DbEntity getTarget() {
-        return relTarget;
-    }
-    
-    public void setTarget(DbEntity newRelTarget) {
-        this.relTarget = newRelTarget;
-    }
-    
-    public boolean isSource1Selected() {
-        return source1Selected;
-    }
-    
-    public DbEntity getSource() {
-        return source;
-    }
-    
-    public void setSource(DbEntity source, boolean source1) {
-        this.source = source;
-        this.source1Selected = source1;
-    }
-    
-    public boolean isToMany() {
-        return toMany;
-    }
-}
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfo.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfo.java
index d381f82..2bf03af 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfo.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfo.java
@@ -18,6 +18,18 @@
  ****************************************************************/
 package org.apache.cayenne.modeler.dialog.objentity;
 
+import javax.swing.*;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.TreePath;
+import java.awt.*;
+import java.awt.event.ItemEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.dbsync.naming.ObjectNameGenerator;
 import org.apache.cayenne.map.DbEntity;
@@ -31,28 +43,15 @@ import org.apache.cayenne.map.event.RelationshipEvent;
 import org.apache.cayenne.modeler.Application;
 import org.apache.cayenne.modeler.ClassLoadingService;
 import org.apache.cayenne.modeler.ProjectController;
-import org.apache.cayenne.modeler.dialog.ResolveDbRelationshipDialog;
+import org.apache.cayenne.modeler.dialog.DbRelationshipDialog;
 import org.apache.cayenne.modeler.util.CayenneController;
 import org.apache.cayenne.modeler.util.Comparators;
 import org.apache.cayenne.modeler.util.EntityTreeModel;
 import org.apache.cayenne.modeler.util.EntityTreeRelationshipFilter;
 import org.apache.cayenne.modeler.util.MultiColumnBrowser;
-import org.apache.cayenne.modeler.util.NameGeneratorPreferences;
 import org.apache.cayenne.util.DeleteRuleUpdater;
 import org.apache.cayenne.util.Util;
 
-import javax.swing.JOptionPane;
-import javax.swing.WindowConstants;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.tree.TreePath;
-import java.awt.Component;
-import java.awt.event.ItemEvent;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Objects;
-
 public class ObjRelationshipInfo extends CayenneController implements 
TreeSelectionListener {
 
     static final String COLLECTION_TYPE_MAP = "java.util.Map";
@@ -289,40 +288,17 @@ public class ObjRelationshipInfo extends 
CayenneController implements TreeSelect
      */
     protected void createRelationship() {
 
-        DbRelationship dbRel = getLastRelationship();
-        DbEntity source = dbRel != null ? dbRel.getTargetEntity() : null;
+        DbEntity dbEntity = relationship.getSourceEntity().getDbEntity();
 
-        DbRelationshipTarget targetModel = new DbRelationshipTarget(mediator, 
getStartEntity(), source);
-        targetModel.startupAction();
+        DbRelationshipDialog dbRelationshipDialog = new 
DbRelationshipDialog(mediator)
+                .createNewRaltionship(dbEntity);
 
-        if (!targetModel.isSavePressed()) {
-            return;
-        }
+        dbRelationshipDialog.startUp();
 
-        DbRelationship dbRelationship = new DbRelationship();
-        dbRelationship.setSourceEntity(targetModel.getSource());
-        dbRelationship.setTargetEntityName(targetModel.getTarget());
-        dbRelationship.setToMany(targetModel.isToMany());
-
-        dbRelationship.setName(createNamingStrategy(NameGeneratorPreferences
-                .getInstance()
-                .getLastUsedStrategies()
-                .get(0)).relationshipName(dbRelationship));
-
-        targetModel.getSource().addRelationship(dbRelationship);
-
-        // TODO: creating relationship outside of ResolveDbRelationshipDialog
-        // confuses it to send incorrect event - CHANGE instead of ADD
-        ResolveDbRelationshipDialog dialog = new 
ResolveDbRelationshipDialog(dbRelationship);
-
-        dialog.setVisible(true);
-        if (dialog.isCancelPressed()) {
-            
targetModel.getSource().removeRelationship(dbRelationship.getName());
-        } else {
+        Optional<DbRelationship> dbRelationship = 
dbRelationshipDialog.getRelationship();
+        if(dbRelationship.isPresent()) {
             MultiColumnBrowser pathBrowser = getPathBrowser();
-            Object[] oldPath = targetModel.isSource1Selected()
-                    ? new Object[] { getStartEntity() }
-                    : pathBrowser.getSelectionPath().getPath();
+            Object[] oldPath = new Object[] { getStartEntity() };
 
             // Update the view
             EntityTreeModel treeModel = (EntityTreeModel) 
pathBrowser.getModel();
@@ -337,8 +313,6 @@ public class ObjRelationshipInfo extends CayenneController 
implements TreeSelect
             path[path.length - 1] = dbRelationship;
             pathBrowser.setSelectionPath(new TreePath(path));
         }
-
-        dialog.dispose();
     }
 
     public ObjectNameGenerator createNamingStrategy(String strategyClass) {
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipPanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipPanel.java
index 2307ef9..871ef42 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipPanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipPanel.java
@@ -18,22 +18,44 @@
  ****************************************************************/
 package org.apache.cayenne.modeler.editor.dbentity;
 
+import javax.swing.ComboBoxModel;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.Icon;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingConstants;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.event.ActionListener;
+import java.util.List;
+
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.Entity;
 import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.map.event.DbEntityListener;
 import org.apache.cayenne.map.event.DbRelationshipListener;
 import org.apache.cayenne.map.event.EntityEvent;
 import org.apache.cayenne.map.event.RelationshipEvent;
 import org.apache.cayenne.modeler.Application;
+import org.apache.cayenne.modeler.dialog.DbRelationshipDialog;
 import org.apache.cayenne.modeler.ProjectController;
 import org.apache.cayenne.modeler.action.ActionManager;
 import org.apache.cayenne.modeler.action.CopyAttributeRelationshipAction;
 import org.apache.cayenne.modeler.action.CutAttributeRelationshipAction;
 import org.apache.cayenne.modeler.action.PasteAction;
 import org.apache.cayenne.modeler.action.RemoveAttributeRelationshipAction;
-import org.apache.cayenne.modeler.dialog.ResolveDbRelationshipDialog;
 import org.apache.cayenne.modeler.event.DbEntityDisplayListener;
 import org.apache.cayenne.modeler.event.EntityDisplayEvent;
 import org.apache.cayenne.modeler.event.TablePopupHandler;
@@ -47,30 +69,6 @@ import org.apache.cayenne.modeler.util.PanelFactory;
 import org.apache.cayenne.modeler.util.UIUtil;
 import org.apache.cayenne.modeler.util.combo.AutoCompletion;
 
-import javax.swing.ComboBoxModel;
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.Icon;
-import javax.swing.JComboBox;
-import javax.swing.JCheckBox;
-import javax.swing.JMenuItem;
-import javax.swing.JPanel;
-import javax.swing.JPopupMenu;
-import javax.swing.JTable;
-import javax.swing.ListSelectionModel;
-import javax.swing.SwingConstants;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.event.TableModelEvent;
-import javax.swing.event.TableModelListener;
-import javax.swing.table.TableCellRenderer;
-import javax.swing.table.TableColumn;
-import java.awt.BorderLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.Component;
-import java.awt.Color;
-import java.util.List;
-
 /**
  * Displays DbRelationships for the current DbEntity.
  */
@@ -147,9 +145,9 @@ public class DbEntityRelationshipPanel extends JPanel 
implements DbEntityDisplay
             // Get DbRelationship
             DbRelationshipTableModel model = (DbRelationshipTableModel) 
table.getModel();
             DbRelationship rel = model.getRelationship(row);
-            ResolveDbRelationshipDialog dialog = new 
ResolveDbRelationshipDialog(rel);
-            dialog.setVisible(true);
-            dialog.dispose();
+            new DbRelationshipDialog(mediator)
+                    .modifyRaltionship(rel)
+                    .startUp();
         };
         resolveMenu.addActionListener(resolver);
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbRelationshipTableModel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbRelationshipTableModel.java
index f4f9229..20d3cc6 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbRelationshipTableModel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbRelationshipTableModel.java
@@ -19,23 +19,16 @@
 
 package org.apache.cayenne.modeler.editor.dbentity;
 
+import javax.swing.JOptionPane;
 import java.util.ArrayList;
 import java.util.Collection;
 
-import javax.swing.JOptionPane;
-
-import org.apache.cayenne.configuration.DataChannelDescriptor;
-import org.apache.cayenne.map.DataMap;
-import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.ObjRelationship;
-import org.apache.cayenne.map.Relationship;
 import org.apache.cayenne.map.event.RelationshipEvent;
 import org.apache.cayenne.modeler.Application;
 import org.apache.cayenne.modeler.ProjectController;
-import org.apache.cayenne.modeler.dialog.WarningDialogByDbTargetChange;
 import org.apache.cayenne.modeler.util.CayenneTableModel;
 import org.apache.cayenne.modeler.util.ProjectUtil;
 import org.apache.cayenne.project.extension.info.ObjectInfo;
@@ -145,18 +138,20 @@ public class DbRelationshipTableModel extends 
CayenneTableModel<DbRelationship>
             rel.setName((String) aValue);
             mediator.fireDbRelationshipEvent(e);
             fireTableCellUpdated(row, column);
-        } else if (column == TARGET) {
-            // If target column
-            DbEntity target = (DbEntity) aValue;
-
-            if (WarningDialogByDbTargetChange.showWarningDialog(mediator, 
rel)) {
-                // clear joins...
-                rel.removeAllJoins();
-                rel.setTargetEntityName(target);
-            }
-
-            mediator.fireDbRelationshipEvent(new 
RelationshipEvent(eventSource, rel, entity));
-        } else if (column == TO_DEPENDENT_KEY) {
+        }
+//        else if (column == TARGET) {
+//            // If target column
+//            DbEntity target = (DbEntity) aValue;
+//
+//            if (WarningDialogByDbTargetChange.showWarningDialog(mediator, 
rel)) {
+//                // clear joins...
+//                rel.removeAllJoins();
+//                rel.setTargetEntityName(target);
+//            }
+//
+//            mediator.fireDbRelationshipEvent(new 
RelationshipEvent(eventSource, rel, entity));
+//        }
+        else if (column == TO_DEPENDENT_KEY) {
             boolean flag = (Boolean) aValue;
 
             // make sure reverse relationship "to-dep-pk" is unset.
@@ -214,6 +209,8 @@ public class DbRelationshipTableModel extends 
CayenneTableModel<DbRelationship>
         DbRelationship rel = getRelationship(row);
         if (rel == null) {
             return false;
+        } else if(col == TARGET) {
+            return false;
         } else if (col == TO_DEPENDENT_KEY) {
             return rel.isValidForDepPk();
         }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/undo/RelationshipUndoableEdit.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/undo/RelationshipUndoableEdit.java
index d303e09..cd3359c 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/undo/RelationshipUndoableEdit.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/undo/RelationshipUndoableEdit.java
@@ -25,31 +25,30 @@ import javax.swing.undo.CompoundEdit;
 
 import org.apache.cayenne.map.DbJoin;
 import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.modeler.dialog.ResolveDbRelationshipDialog;
+import org.apache.cayenne.modeler.Application;
+import org.apache.cayenne.modeler.dialog.DbRelationshipDialog;
 import org.apache.cayenne.modeler.util.ProjectUtil;
 
 public class RelationshipUndoableEdit extends CompoundEdit {
 
     private DbRelationship relationship;
-       
+
+       public RelationshipUndoableEdit(DbRelationship relationship) {
+               this.relationship = relationship;
+       }
+
     @Override
        public void redo() throws CannotRedoException {
-               super.redo();
-               
-               ResolveDbRelationshipDialog dialog = new 
ResolveDbRelationshipDialog(
-                               relationship, false);
-
-               dialog.setVisible(true);
+               new 
DbRelationshipDialog(Application.getInstance().getFrameController().getProjectController())
+                               .modifyRaltionship(relationship)
+                               .startUp();
        }
 
        @Override
        public void undo() throws CannotUndoException {
-               super.undo();
-               
-               ResolveDbRelationshipDialog dialog = new 
ResolveDbRelationshipDialog(
-                               relationship, false);
-
-               dialog.setVisible(true);
+               new 
DbRelationshipDialog(Application.getInstance().getFrameController().getProjectController())
+                               .modifyRaltionship(relationship)
+                               .startUp();
        }
 
        @Override
@@ -62,8 +61,14 @@ public class RelationshipUndoableEdit extends CompoundEdit {
                return "Undo Edit relationship";
        }
 
-       public RelationshipUndoableEdit(DbRelationship relationship) {
-               this.relationship = relationship;
+       @Override
+       public boolean isSignificant() {
+       return true;
+       }
+
+       @Override
+       public boolean canUndo() {
+               return true;
        }
 
        public void addDbJoinAddUndo(final DbJoin join) {

Reply via email to