cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From skolbac...@apache.org
Subject [6/8] cayenne git commit: cleanup
Date Mon, 07 Dec 2015 15:31:45 GMT
http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityRelationshipPanel.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityRelationshipPanel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityRelationshipPanel.java
index dffd96d..f417989 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityRelationshipPanel.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityRelationshipPanel.java
@@ -18,15 +18,10 @@
  ****************************************************************/
 package org.apache.cayenne.modeler.editor;
 
-import org.apache.cayenne.map.Attribute;
 import org.apache.cayenne.map.DataMap;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbRelationship;
 import org.apache.cayenne.map.DeleteRule;
-import org.apache.cayenne.map.ObjAttribute;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.ObjRelationship;
-import org.apache.cayenne.map.Relationship;
 import org.apache.cayenne.map.event.EntityEvent;
 import org.apache.cayenne.map.event.ObjEntityListener;
 import org.apache.cayenne.map.event.ObjRelationshipListener;
@@ -45,19 +40,18 @@ import org.apache.cayenne.modeler.event.TablePopupHandler;
 import org.apache.cayenne.modeler.pref.TableColumnPreferences;
 import org.apache.cayenne.modeler.util.CayenneTable;
 import org.apache.cayenne.modeler.util.CellRenderers;
-import org.apache.cayenne.modeler.util.EntityTreeFilter;
-import org.apache.cayenne.modeler.util.EntityTreeModel;
+import org.apache.cayenne.modeler.util.DbRelationshipPathComboBoxEditor;
+import org.apache.cayenne.modeler.util.JTableCollectionTypeComboBoxEditor;
+import org.apache.cayenne.modeler.util.JTableCollectionTypeComboBoxRenderer;
+import org.apache.cayenne.modeler.util.JTableMapKeyComboBoxEditor;
+import org.apache.cayenne.modeler.util.JTableMapKeyComboBoxRenderer;
 import org.apache.cayenne.modeler.util.ModelerUtil;
 import org.apache.cayenne.modeler.util.PanelFactory;
 import org.apache.cayenne.modeler.util.UIUtil;
-import org.apache.cayenne.modeler.util.combo.AutoCompletion;
-import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
-import javax.swing.AbstractCellEditor;
 import javax.swing.DefaultCellEditor;
-import javax.swing.DefaultComboBoxModel;
 import javax.swing.Icon;
 import javax.swing.JComboBox;
 import javax.swing.JLabel;
@@ -71,22 +65,14 @@ import javax.swing.event.ListSelectionListener;
 import javax.swing.event.TableModelEvent;
 import javax.swing.event.TableModelListener;
 import javax.swing.table.DefaultTableCellRenderer;
-import javax.swing.table.TableCellEditor;
-import javax.swing.table.TableCellRenderer;
 import javax.swing.table.TableColumn;
-import javax.swing.text.JTextComponent;
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;
-import java.awt.Font;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
-import java.util.regex.Pattern;
 
 /**
  * Displays ObjRelationships for the edited ObjEntity.
@@ -96,20 +82,15 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
 
     private static Log logObj = LogFactory.getLog(ObjEntityRelationshipPanel.class);
 
-    private static final Object[] deleteRules = new Object[]{
+    private static final Object[] DELETE_RULES = new Object[]{
             DeleteRule.deleteRuleName(DeleteRule.NO_ACTION),
             DeleteRule.deleteRuleName(DeleteRule.NULLIFY),
             DeleteRule.deleteRuleName(DeleteRule.CASCADE),
             DeleteRule.deleteRuleName(DeleteRule.DENY),
     };
 
- /*   static final String COLLECTION_TYPE_MAP = "java.util.Map";
-    static final String COLLECTION_TYPE_SET = "java.util.Set";
-    static final String COLLECTION_TYPE_COLLECTION = "java.util.Collection";
-    static final String DEFAULT_COLLECTION_TYPE = "java.util.List";*/
-
-    protected ProjectController mediator;
-    protected CayenneTable table;
+    private ProjectController mediator;
+    private CayenneTable table;
     private TableColumnPreferences tablePreferences;
     private ActionListener resolver;
     private ObjEntityAttributeRelationshipTab parentPanel;
@@ -119,7 +100,7 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
      * By now popup menu item is made similar to toolbar button. (i.e. all functionality
      * is here) This should be probably refactored as Action.
      */
-    protected JMenuItem resolveMenu;
+    private JMenuItem resolveMenu;
 
     public ObjEntityRelationshipPanel(ProjectController mediator, ObjEntityAttributeRelationshipTab parentPanel) {
         this.mediator = mediator;
@@ -129,21 +110,20 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
         initController();
     }
 
+    public CayenneTable getTable() {
+        return table;
+    }
+
+    public void setTable(CayenneTable table) {
+        this.table = table;
+    }
+
     private void init() {
         this.setLayout(new BorderLayout());
 
         ActionManager actionManager = Application.getInstance().getActionManager();
 
-        table = new CayenneTable(){
-            @Override
-            public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
-                Component component = super.prepareRenderer(renderer, row, column);
-                int rendererWidth = component.getPreferredSize().width;
-                TableColumn tableColumn = getColumnModel().getColumn(column);
-                tableColumn.setPreferredWidth(Math.max(rendererWidth + getIntercellSpacing().width, tableColumn.getPreferredWidth()));
-                return component;
-            }
-        };
+        table = new CayenneTable();
         table.setDefaultRenderer(String.class, new StringRenderer());
         table.setDefaultRenderer(ObjEntity.class, new EntityRenderer());
         tablePreferences = new TableColumnPreferences(
@@ -318,8 +298,6 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
 
         JComboBox combo = (JComboBox) editor.getComponent();
         combo.setRenderer(CellRenderers.entityListRendererWithIcons(entity.getDataMap()));
-        //combo.setModel(new DefaultComboBoxModel(createObjEntityComboModel()));
-        //combo.setEnabled(false);
 
         ObjRelationshipTableModel model = (ObjRelationshipTableModel) table.getModel();
         model.fireTableDataChanged();
@@ -336,11 +314,7 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
             public void tableChanged(TableModelEvent e) {
                 if (table.getSelectedRow() >= 0) {
                     ObjRelationship rel = model.getRelationship(table.getSelectedRow());
-                    if (((ObjEntity) rel.getSourceEntity()).getDbEntity() != null) {
-                        enabledResolve = true;
-                    } else
-                        enabledResolve = false;
-
+                    enabledResolve = rel.getSourceEntity().getDbEntity() != null;
                     resolveMenu.setEnabled(enabledResolve);
                 }
             }
@@ -350,21 +324,12 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
         table.setRowHeight(25);
         table.setRowMargin(3);
 
-        TableColumn col = table.getColumnModel().getColumn(
-                ObjRelationshipTableModel.REL_TARGET_PATH);
-        JComboBox targetCombo = Application.getWidgetFactory().createComboBox(
-                createObjEntityComboModel(),
-                false);
-        AutoCompletion.enable(targetCombo);
-
-        targetCombo.setRenderer(CellRenderers.entityListRendererWithIcons(entity
-                .getDataMap()));
-        targetCombo.setSelectedIndex(-1);
-        col.setCellEditor(new JTableTargetComboBoxEditor());
+        TableColumn col = table.getColumnModel().getColumn(ObjRelationshipTableModel.REL_TARGET_PATH);
+        col.setCellEditor(new DbRelationshipPathComboBoxEditor());
 
         col = table.getColumnModel().getColumn(ObjRelationshipTableModel.REL_DELETE_RULE);
         JComboBox deleteRulesCombo = Application.getWidgetFactory().createComboBox(
-                deleteRules,
+                DELETE_RULES,
                 false);
         deleteRulesCombo.setEditable(false);
         deleteRulesCombo.setSelectedIndex(0); // Default to the first value
@@ -377,6 +342,7 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
         col.setCellRenderer(new JTableCollectionTypeComboBoxRenderer());
 
         col = table.getColumnModel().getColumn(ObjRelationshipTableModel.REL_MAP_KEY);
+
         col.setCellEditor(new JTableMapKeyComboBoxEditor());
         col.setCellRenderer(new JTableMapKeyComboBoxRenderer());
 
@@ -465,9 +431,10 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
 
             if (!e.getValueIsAdjusting() && !((ListSelectionModel) e.getSource()).isSelectionEmpty()) {
 
-                parentPanel.getAttributePanel().table.getSelectionModel().clearSelection();
-                if (parentPanel.getAttributePanel().table.getCellEditor() != null)
-                    parentPanel.getAttributePanel().table.getCellEditor().stopCellEditing();
+                parentPanel.getAttributePanel().getTable().getSelectionModel().clearSelection();
+                if (parentPanel.getAttributePanel().getTable().getCellEditor() != null) {
+                    parentPanel.getAttributePanel().getTable().getCellEditor().stopCellEditing();
+                }
                 Application.getInstance().getActionManager().getAction(RemoveAttributeRelationshipAction.class).setCurrentSelectedPanel(parentPanel.getRelationshipPanel());
                 Application.getInstance().getActionManager().getAction(CutAttributeRelationshipAction.class).setCurrentSelectedPanel(parentPanel.getRelationshipPanel());
                 Application.getInstance().getActionManager().getAction(CopyAttributeRelationshipAction.class).setCurrentSelectedPanel(parentPanel.getRelationshipPanel());
@@ -511,485 +478,4 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
         return resolver;
     }
 
-    private final static class JTableCollectionTypeComboBoxEditor extends AbstractCellEditor implements TableCellEditor{
-
-        static final String COLLECTION_TYPE_MAP = "java.util.Map";
-        static final String COLLECTION_TYPE_SET = "java.util.Set";
-        static final String COLLECTION_TYPE_COLLECTION = "java.util.Collection";
-        static final String DEFAULT_COLLECTION_TYPE = "java.util.List";
-
-        private ObjRelationshipTableModel model;
-        private int row;
-        private int column;
-
-        public JTableCollectionTypeComboBoxEditor() {
-        }
-
-        @Override
-        public Component getTableCellEditorComponent(final JTable table, Object value, boolean isSelected, final int row, final int column) {
-            this.model = (ObjRelationshipTableModel) table.getModel();
-            this.row = row;
-            this.column = column;
-
-            final JComboBox collectionTypeCombo = Application.getWidgetFactory().createComboBox(
-                    new Object[]{
-                            COLLECTION_TYPE_MAP,
-                            COLLECTION_TYPE_SET,
-                            COLLECTION_TYPE_COLLECTION,
-                            DEFAULT_COLLECTION_TYPE
-                    },
-                    false);
-            if(model.getRelationship(row).isToMany()){
-                collectionTypeCombo.setEnabled(true);
-                collectionTypeCombo.setSelectedItem( model.getRelationship(row).getCollectionType());
-            }else{
-                JLabel labelIfToOneRelationship = new JLabel();
-                labelIfToOneRelationship.setEnabled(false);
-                //collectionTypeCombo.setEnabled(false);
-                //collectionTypeCombo.setSelectedItem( model.getRelationship(row).getCollectionType());
-                return labelIfToOneRelationship;
-            }
-            collectionTypeCombo.addActionListener(new ActionListener() {
-                @Override
-                public void actionPerformed(ActionEvent e) {
-                    Object selected = collectionTypeCombo.getSelectedItem();
-                    model.setUpdatedValueAt(selected,row,column);
-                    table.repaint();
-                }
-            });
-            return collectionTypeCombo;
-        }
-
-        @Override
-        public Object getCellEditorValue() {
-            return model.getValueAt(row,column);
-        }
-    }
-
-    private final static class JTableCollectionTypeComboBoxRenderer implements TableCellRenderer {
-
-        private ObjRelationshipTableModel model;
-
-        public JTableCollectionTypeComboBoxRenderer() {
-        }
-
-        @Override
-        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
-            this.model = (ObjRelationshipTableModel) table.getModel();
-            JLabel labelIfToOneRelationship = new JLabel();
-            labelIfToOneRelationship.setEnabled(false);
-            JLabel labelIfToManyRelationship = new JLabel((String) value);
-            labelIfToManyRelationship.setEnabled(true);
-            labelIfToManyRelationship.setFont(new Font("Verdana", Font.PLAIN , 12));
-            if (value == null)
-                return labelIfToOneRelationship;
-
-            if (model.getRelationship(row).isToMany()) {
-                return labelIfToManyRelationship;
-            }else{
-                return labelIfToOneRelationship;
-            }
-
-        }
-    }
-
-    private final static class JTableMapKeyComboBoxEditor extends AbstractCellEditor implements TableCellEditor {
-
-        static final String DEFAULT_MAP_KEY = "ID (default)";
-        static final String COLLECTION_TYPE_MAP = "java.util.Map";
-
-        private List<String> mapKeys = new ArrayList<>() ;
-        private ObjRelationshipTableModel model;
-        private int row;
-        private int column;
-
-        private JTableMapKeyComboBoxEditor() {
-        }
-
-        private void initMapKeys() {
-            mapKeys.clear();
-            mapKeys.add(DEFAULT_MAP_KEY);
-            /**
-             * Object target can be null when selected target DbEntity has no
-             * ObjEntities
-             */
-            ObjEntity objectTarget = model.getRelationship(row).getTargetEntity();
-            if (objectTarget == null) {
-                return ;
-            }
-            for (ObjAttribute attribute : objectTarget.getAttributes()) {
-                mapKeys.add(attribute.getName());
-            }
-        }
-
-        @Override
-        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, final int row, final int column) {
-            this.model = (ObjRelationshipTableModel) table.getModel();
-            this.row = row;
-            this.column = column;
-            initMapKeys();
-            final JComboBox mapKeysComboBox =  Application.getWidgetFactory().createComboBox(
-                  mapKeys,
-                    false);
-            if ((model.getRelationship(row).getCollectionType() == null)
-                    ||(!model.getRelationship(row).getCollectionType().equals(COLLECTION_TYPE_MAP))){
-                JComboBox jComboBox = new JComboBox();
-                jComboBox.setFocusable(false);
-                jComboBox.setEnabled(false);
-                return jComboBox;
-            }else{
-                mapKeysComboBox.setFocusable(true);
-                mapKeysComboBox.setEnabled(true);
-            }
-            mapKeysComboBox.addActionListener(new ActionListener() {
-                @Override
-                public void actionPerformed(ActionEvent e) {
-                    Object selected = mapKeysComboBox.getSelectedItem();
-                    model.setUpdatedValueAt(selected,row,column);
-                }
-            });
-            mapKeysComboBox.setSelectedItem(model.getRelationship(row).getMapKey());
-            return mapKeysComboBox;
-        }
-
-        @Override
-        public Object getCellEditorValue() {
-            return model.getValueAt(row,column);
-        }
-    }
-
-    private final static class JTableMapKeyComboBoxRenderer implements TableCellRenderer{
-
-        static final String DEFAULT_MAP_KEY = "ID (default)";
-        static final String COLLECTION_TYPE_MAP = "java.util.Map";
-
-        private ObjRelationshipTableModel model;
-
-        public JTableMapKeyComboBoxRenderer() {
-        }
-
-        @Override
-        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
-            this.model = (ObjRelationshipTableModel) table.getModel();
-            if ( (model.getRelationship(row).getCollectionType() == null)
-                ||(!model.getRelationship(row).getCollectionType().equals(COLLECTION_TYPE_MAP))){
-                JComboBox jComboBox = new JComboBox();
-                jComboBox.setFocusable(false);
-                jComboBox.setEnabled(false);
-                return jComboBox;
-            }
-            if (model.getRelationship(row).getMapKey() == null){
-                model.getRelationship(row).setMapKey(DEFAULT_MAP_KEY);
-            }
-            JLabel jLabel  = new JLabel(model.getRelationship(row).getMapKey());
-            jLabel.setFont(new Font("Verdana", Font.PLAIN , 12));
-            return jLabel;
-        }
-    }
-
-    private static final class JTableTargetComboBoxEditor extends AbstractCellEditor implements TableCellEditor, ActionListener {
-
-        private ObjRelationshipTableModel model;
-        private int row;
-        private int column;
-        private JComboBox dbRelationshipPathCombo;
-        private EntityTreeModel treeModel;
-        private int previousEmbededLevel = 0;
-        private static int enterPressedCount = 0;
-
-        public JTableTargetComboBoxEditor() {
-        }
-
-        @Override
-        public Object getCellEditorValue() {
-            return model.getValueAt(row,column);
-        }
-
-        @Override
-        public Component getTableCellEditorComponent(final JTable table, Object value, boolean isSelected, final int row, int column) {
-            this.model = (ObjRelationshipTableModel) table.getModel();
-            this.row = row;
-            this.column = column;
-            treeModel = createTreeModelForComboBoxBrowser(row);
-            if (treeModel == null)
-                return new JLabel("You need select table to this ObjectEntity");
-            initializeCombo(model , row);
-
-            String dbRelationshipPath = ((JTextComponent) (dbRelationshipPathCombo).
-                    getEditor().getEditorComponent()).getText();
-            previousEmbededLevel =  dbRelationshipPath.split(Pattern.quote(".")).length;
-
-            dbRelationshipPathCombo.getEditor().getEditorComponent().addKeyListener(new KeyAdapter() {
-                private void enterPressed(){
-                    String dbRelationshipPath = ((JTextComponent) (dbRelationshipPathCombo).
-                            getEditor().getEditorComponent()).getText();
-                    Object currentNode = getCurrentNode(dbRelationshipPath);
-                    String[] pathStrings = dbRelationshipPath.split(Pattern.quote("."));
-                    String lastStringInPath = pathStrings[pathStrings.length - 1];
-
-                    if (lastStringInPath.equals(ModelerUtil.getObjectName(currentNode))) {
-                        if (enterPressedCount == 1) {
-                            //it is second time enter pressed.. so we will save input data
-                            enterPressedCount = 0;
-                            if (currentNode instanceof DbRelationship) {
-
-                                if (table.getCellEditor() != null) {
-
-                                    table.getCellEditor().stopCellEditing();
-                                    model.getRelationship(row).setDbRelationshipPath(dbRelationshipPath);
-
-                                    //we need object target to save it in model
-                                    DbEntity lastEntity = ((DbRelationship) currentNode).getTargetEntity();
-                                    Collection<ObjEntity> objEntities = ((DbRelationship) currentNode).getTargetEntity().
-                                            getDataMap().getMappedEntities(lastEntity);
-                                    ObjEntity objectTarget = objEntities.size() == 0 ? null : objEntities.iterator().next();
-                                    model.getRelationship(row).setTargetEntityName(objectTarget);
-                                }
-                            }
-                            table.repaint();
-                        } else {
-                            enterPressedCount = 1;
-                        }
-                    }
-                }
-
-                @Override
-                public void keyReleased(KeyEvent event) {
-                    if (event.getKeyCode() == KeyEvent.VK_ENTER) {
-                        enterPressed();
-                        return;
-                    }
-                    parseDbRelationshipString(event.getKeyChar());
-                }
-            });
-            return dbRelationshipPathCombo;
-        }
-
-        private void initializeCombo(ObjRelationshipTableModel model , int row){
-            String dbRelationshipPath = model.getRelationship(row).getDbRelationshipPath();
-            Object currentNode;
-            if (dbRelationshipPath == null){
-                //case if it is new attribute or for some reason dbRelationshipPath is null
-                currentNode = getCurrentNode(dbRelationshipPath);
-                dbRelationshipPath = "";
-
-            }else{
-                //case if  dbRelationshipPath isn't null and we must change it to find auto completion list
-                String[] pathStrings = dbRelationshipPath.split(Pattern.quote("."));
-                String lastStringInPath = pathStrings[pathStrings.length - 1];
-                dbRelationshipPath = dbRelationshipPath.replaceAll(lastStringInPath + "$", "");
-                currentNode = getCurrentNode(dbRelationshipPath);
-            }
-            List<String> nodeChildren = getChildren(currentNode , dbRelationshipPath);
-            dbRelationshipPathCombo = Application.getWidgetFactory().createComboBox(
-                    nodeChildren,
-                    false);
-            AutoCompletion.enable(dbRelationshipPathCombo, false, true);
-            dbRelationshipPathCombo.setEditable(true);
-            ((JTextComponent) (dbRelationshipPathCombo).
-                    getEditor().getEditorComponent()).setText(model.getRelationship(row).getDbRelationshipPath());
-            dbRelationshipPathCombo.setSelectedItem(model.getRelationship(row).getDbRelationshipPath());
-            dbRelationshipPathCombo.addActionListener(this);
-            return;
-        }
-
-        /*
-         * chech if potential child is child for father
-         * @param father
-         * @param potentialChild
-         * @return
-         */
-        /*private boolean isChild(Object father , Object potentialChild){
-            List<Object> fatherChildren = new ArrayList<>();
-            for(int j = 0 ; j <  treeModel.getChildCount(father) ; j++){
-                Object child = treeModel.getChild(father, j);
-                fatherChildren.add(child);
-            }
-            return fatherChildren.contains(potentialChild);
-        }*/
-
-        private void parseDbRelationshipString(char lastEnteredCharacter){
-            String dbRelationshipPath = ((JTextComponent) (dbRelationshipPathCombo).
-                    getEditor().getEditorComponent()).getText();
-
-            enterPressedCount = 0;
-
-            if (dbRelationshipPath.equals("")){
-                List<String> currentNodeChildren = new ArrayList<>();
-                currentNodeChildren.add("");
-                currentNodeChildren.addAll(getChildren(getCurrentNode(dbRelationshipPath),""));
-                dbRelationshipPathCombo.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
-                dbRelationshipPathCombo.showPopup();
-                dbRelationshipPathCombo.setPopupVisible(true);
-                return;
-            }
-
-            if (lastEnteredCharacter == '.') {
-                processDotEntered();
-                previousEmbededLevel  =  StringUtils.countMatches(dbRelationshipPath,".");
-                return;
-            }
-
-            int currentEmbededLevel =  StringUtils.countMatches(dbRelationshipPath,".");
-            if (previousEmbededLevel != currentEmbededLevel){
-                previousEmbededLevel = currentEmbededLevel;
-                List<String> currentNodeChildren = new ArrayList<>();
-                String[] pathStrings = dbRelationshipPath.split(Pattern.quote("."));
-                String lastStringInPath = pathStrings[pathStrings.length - 1];
-                String saveDbRelationshipPath = dbRelationshipPath;
-                dbRelationshipPath = dbRelationshipPath.replaceAll(lastStringInPath + "$", "");
-                currentNodeChildren.add("");
-                currentNodeChildren.addAll(getChildren(getCurrentNode(dbRelationshipPath), dbRelationshipPath));
-                dbRelationshipPathCombo.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
-                ((JTextComponent) (dbRelationshipPathCombo).
-                        getEditor().getEditorComponent()).setText(saveDbRelationshipPath);
-
-                dbRelationshipPathCombo.showPopup();
-                dbRelationshipPathCombo.setPopupVisible(true);
-                return;
-            }
-        }
-
-        private void processDotEntered(){
-            String dbAttributePath = ((JTextComponent) (dbRelationshipPathCombo).
-                    getEditor().getEditorComponent()).getText();
-            if (dbAttributePath.equals(".")){
-                List<String> currentNodeChildren = new ArrayList<>();
-                currentNodeChildren.add("");
-                currentNodeChildren.addAll(getChildren(getCurrentNode(""),""));
-                dbRelationshipPathCombo.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
-                dbRelationshipPathCombo.showPopup();
-                dbRelationshipPathCombo.setPopupVisible(true);
-                return;
-            }else {
-                char secondFromEndCharacter = dbAttributePath.charAt(dbAttributePath.length()-2);
-                if(secondFromEndCharacter == '.') {
-                    // two dots entered one by one , we replace it by one dot
-                    ((JTextComponent) (dbRelationshipPathCombo).
-                            getEditor().getEditorComponent()).setText(dbAttributePath.substring(0,dbAttributePath.length()-1));
-                    return;
-                }else{
-                    String[] pathStrings = dbAttributePath.split(Pattern.quote("."));
-                    String lastStringInPath = pathStrings[pathStrings.length - 1];
-
-                    //we will check if lastStringInPath is correct name of DbAttribute or DbRelationship
-                    //for appropriate previous node in path. if it is not we won't add entered dot to dbAttributePath
-                    String dbAttributePathForPreviousNode;
-                    if (pathStrings.length == 1){
-                        dbAttributePathForPreviousNode = null;
-                    }else {
-                        dbAttributePathForPreviousNode = dbAttributePath.replace("."+lastStringInPath,"");
-                    }
-                    List<String> potentialVariantsToChoose = getChildren(getCurrentNode(dbAttributePathForPreviousNode),"");
-                    if (potentialVariantsToChoose.contains(lastStringInPath)){
-                        List<String> currentNodeChildren = new ArrayList<>();
-                        currentNodeChildren.add(dbAttributePath + "");
-                        currentNodeChildren.addAll(getChildren(getCurrentNode(dbAttributePath), dbAttributePath));
-                        dbRelationshipPathCombo.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
-                        dbRelationshipPathCombo.showPopup();
-                        dbRelationshipPathCombo.setPopupVisible(true);
-                    }else{
-                        ((JTextComponent) (dbRelationshipPathCombo).
-                                getEditor().getEditorComponent()).setText(dbAttributePath.substring(0,dbAttributePath.length()-1));
-                    }
-                }
-            }
-            previousEmbededLevel =  StringUtils.countMatches(dbAttributePath,".");
-            return;
-        }
-
-        /**
-         * find current node by dbRelationshipPath
-         * @param dbRelationshipPath
-         * @return last node in dbRelationshipPath which matches DbRelationship
-         */
-        private final Object getCurrentNode(String dbRelationshipPath) {
-            try {
-                //case for new relationship
-                if(dbRelationshipPath == null){
-                    return treeModel.getRoot();
-                }
-                String[] pathStrings = dbRelationshipPath.split(Pattern.quote("."));
-                Object root = treeModel.getRoot();
-                for (int  i = 0 ; i < pathStrings.length ; i ++) {
-                    String rootChildText = pathStrings[i];
-                    for (int j = 0; j < treeModel.getChildCount(root); j++) {
-                        Object child = treeModel.getChild(root, j);
-                        if (child instanceof DbRelationship) {
-                            String relationshipName = ModelerUtil.getObjectName(child);
-                            if (relationshipName.equals(rootChildText)) {
-                                root = child;
-                                break;
-                            }
-                        }
-                    }
-                }
-                return root;
-            }catch (Exception e){
-                return treeModel.getRoot();
-            }
-        }
-
-        /**
-         * @param node for which we will find children
-         * @param dbRelationshipPath string which will be added to each child to make right autocomplete
-         * @return list with children , which will be used to autocomplete
-         */
-        private final List<String> getChildren(Object node , String dbRelationshipPath){
-            List<String> currentNodeChildren = new ArrayList<>();
-            for(int j = 0 ; j <  treeModel.getChildCount(node) ; j++){
-                Object child = treeModel.getChild(node, j);
-                String relationshipName = ModelerUtil.getObjectName(child);
-                currentNodeChildren.add(dbRelationshipPath + relationshipName);
-            }
-            return currentNodeChildren;
-        }
-
-        /**
-         * @param relationshipIndexInTable index of attribute for which now we will create cell editor
-         * @return treeModel for nessesary for us attribute
-         */
-        private EntityTreeModel createTreeModelForComboBoxBrowser(int relationshipIndexInTable){
-            if (model.getRelationship(relationshipIndexInTable).
-                    getSourceEntity().getDbEntity() == null)
-                return null;
-            EntityTreeModel treeModel = new EntityTreeModel(model.getRelationship(relationshipIndexInTable).
-                    getSourceEntity().getDbEntity());
-            treeModel.setFilter(new EntityTreeFilter() {
-
-                public boolean attributeMatch(Object node, Attribute attr) {
-                    // attrs not allowed here
-                    return false;
-                }
-
-                public boolean relationshipMatch(Object node, Relationship rel) {
-                    if (!(node instanceof Relationship)) {
-                        return true;
-                    }
-
-                    /**
-                     * We do not allow A->B->A chains, where relationships are
-                     * to-one
-                     */
-                    DbRelationship prev = (DbRelationship) node;
-                    return !(!rel.isToMany() && prev.getReverseRelationship() == rel);
-                }
-
-            });
-            return treeModel;
-        }
-
-        @Override
-        public void actionPerformed(ActionEvent e) {
-            model.getRelationship(row).setMapKey(null);
-
-            //for some reason dbRelationshipPathCombo don't load selected item text, so we made it by hand
-            if (dbRelationshipPathCombo.getSelectedIndex() != (-1)){
-                ((JTextComponent) (dbRelationshipPathCombo).
-                        getEditor().getEditorComponent()).setText(dbRelationshipPathCombo.getSelectedItem().toString());
-            }
-
-
-        }
-    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjRelationshipTableModel.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjRelationshipTableModel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjRelationshipTableModel.java
index 91592f6..eab255b 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjRelationshipTableModel.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjRelationshipTableModel.java
@@ -37,18 +37,17 @@ import java.util.Comparator;
 public class ObjRelationshipTableModel extends CayenneTableModel {
 
     // Columns
-    static final int REL_NAME = 0;
-    static final int REL_TARGET = 1;
-    static final int REL_TARGET_PATH = 2;
-    static final int REL_COLLECTION_TYPE = 3;
-    static final int REL_MAP_KEY = 4;
-    static final int REL_SEMANTICS = 5;
-    static final int REL_DELETE_RULE = 6;
-    static final int REL_LOCKING = 7;
-
-    static final int COLUMN_COUNT = 8;
-
-    protected ObjEntity entity;
+    public static final int REL_NAME = 0;
+    public static final int REL_TARGET = 1;
+    public static final int REL_TARGET_PATH = 2;
+    public static final int REL_COLLECTION_TYPE = 3;
+    public static final int REL_MAP_KEY = 4;
+    public static final int REL_SEMANTICS = 5;
+    public static final int REL_DELETE_RULE = 6;
+    public static final int REL_LOCKING = 7;
+    public static final int COLUMN_COUNT = 8;
+
+    private ObjEntity entity;
 
     public ObjRelationshipTableModel(ObjEntity entity, ProjectController mediator,
             Object eventSource) {
@@ -99,7 +98,6 @@ public class ObjRelationshipTableModel extends CayenneTableModel {
                 return "Map key";
             case REL_TARGET_PATH:
                 return "DbRelationshipPath";
-
             default:
                 return null;
         }
@@ -127,52 +125,35 @@ public class ObjRelationshipTableModel extends CayenneTableModel {
 
         if (column == REL_NAME) {
             return relationship.getName();
-        }
-        else if (column == REL_TARGET) {
+        } else if (column == REL_TARGET) {
             return relationship.getTargetEntity();
-        }
-        else if (column == REL_LOCKING) {
+        } else if (column == REL_LOCKING) {
             return relationship.isUsedForLocking() ? Boolean.TRUE : Boolean.FALSE;
-        }
-        else if (column == REL_SEMANTICS) {
+        } else if (column == REL_SEMANTICS) {
             return getSemantics(relationship);
-        }
-        else if (column == REL_DELETE_RULE) {
+        } else if (column == REL_DELETE_RULE) {
             return DeleteRule.deleteRuleName(relationship.getDeleteRule());
         } else if (column == REL_COLLECTION_TYPE) {
-            if (!relationship.isToMany())
+            if (!relationship.isToMany()) {
                 return null;
+            }
             return relationship.getCollectionType();
-        } else if (column == REL_MAP_KEY){
+        } else if (column == REL_MAP_KEY) {
             return relationship.getMapKey();
-        } else if (column == REL_TARGET_PATH){
+        } else if (column == REL_TARGET_PATH) {
             return relationship.getDbRelationshipPath();
-        }
-        else {
+        } else {
             return null;
         }
     }
 
-    private String getSemantics(ObjRelationship relationship) {
-        String semantics = relationship.isToMany() ? "to many" : "to one";
+    private static String getSemantics(ObjRelationship relationship) {
+        StringBuilder semantics =  new StringBuilder(20);
+        semantics.append(relationship.isToMany() ? "to many" : "to one");
         if (relationship.isReadOnly()) {
-            semantics += ", read-only";
-        }
-
-        if (relationship.isToMany()) {
-            String collection = "list";
-            if (relationship.getCollectionType() != null) {
-                int dot = relationship.getCollectionType().lastIndexOf('.');
-                collection = relationship
-                        .getCollectionType()
-                        .substring(dot + 1)
-                        .toLowerCase();
-            }
-
-            semantics += ", " + collection;
+            semantics.append(", read-only");
         }
-
-        return semantics;
+        return semantics.toString();
     }
 
     @Override
@@ -185,19 +166,18 @@ public class ObjRelationshipTableModel extends CayenneTableModel {
             event.setOldName(relationship.getName());
             ProjectUtil.setRelationshipName(entity, relationship, text);
             fireTableCellUpdated(row, column);
-        }
-        else if (column == REL_TARGET) {
+        } else if (column == REL_TARGET) {
             ObjEntity target = (ObjEntity) value;
             relationship.setTargetEntityName(target);
-            
+
             /**
              * Clear existing relationships, otherwise addDbRelationship() might fail
              */
             relationship.clearDbRelationships();
-            
+
             // now try to connect DbEntities if we can do it in one step
             if (target != null) {
-                DbEntity srcDB = ((ObjEntity) relationship.getSourceEntity())
+                DbEntity srcDB = relationship.getSourceEntity()
                         .getDbEntity();
                 DbEntity targetDB = target.getDbEntity();
                 if (srcDB != null && targetDB != null) {
@@ -209,24 +189,20 @@ public class ObjRelationshipTableModel extends CayenneTableModel {
             }
 
             fireTableRowsUpdated(row, row);
-        }
-        else if (column == REL_DELETE_RULE) {
+        } else if (column == REL_DELETE_RULE) {
             relationship.setDeleteRule(DeleteRule.deleteRuleForName((String) value));
             fireTableCellUpdated(row, column);
-        }
-        else if (column == REL_LOCKING) {
+        } else if (column == REL_LOCKING) {
             relationship.setUsedForLocking((value instanceof Boolean)
                     && ((Boolean) value).booleanValue());
             fireTableCellUpdated(row, column);
-        }
-        else if (column == REL_COLLECTION_TYPE){
+        } else if (column == REL_COLLECTION_TYPE) {
             relationship.setCollectionType((String) value);
             fireTableCellUpdated(row, column);
-        }else if (column == REL_MAP_KEY){
+        } else if (column == REL_MAP_KEY) {
             relationship.setMapKey((String) value);
             fireTableCellUpdated(row, column);
-            }
-        else if (column == REL_TARGET_PATH){
+        } else if (column == REL_TARGET_PATH) {
             relationship.setDbRelationshipPath((String) value);
             fireTableCellUpdated(row, column);
         }
@@ -235,8 +211,9 @@ public class ObjRelationshipTableModel extends CayenneTableModel {
     }
 
     public void removeRow(int row) {
-        if (row < 0)
+        if (row < 0) {
             return;
+        }
         Relationship rel = getRelationship(row);
         RelationshipEvent e;
         e = new RelationshipEvent(eventSource, rel, entity, RelationshipEvent.REMOVE);
@@ -296,55 +273,60 @@ public class ObjRelationshipTableModel extends CayenneTableModel {
             case REL_MAP_KEY:
             case REL_DELETE_RULE:
             case REL_TARGET_PATH:
-                Collections.sort(objectList, new Comparator<ObjRelationship>() {
-
-                    public int compare(ObjRelationship o1, ObjRelationship o2) {
-                        if ((o1 == null && o2 == null) || o1 == o2) {
-                            return 0;
-                        }
-                        else if (o1 == null && o2 != null) {
-                            return -1;
-                        }
-                        else if (o1 != null && o2 == null) {
-                            return 1;
-                        }
-                        
-                        String valueToCompare1 = "";
-                        String valueToCompare2 = "";
-                        switch(sortCol){
-                            case REL_COLLECTION_TYPE:
-                                valueToCompare1 = o1.getCollectionType();
-                                valueToCompare2 = o2.getCollectionType();
-                                break;
-                            case REL_MAP_KEY:
-                                valueToCompare1 = o1.getMapKey();
-                                valueToCompare2 = o2.getMapKey();
-                                break;
-                            case REL_SEMANTICS:
-                                valueToCompare1 = getSemantics(o1);
-                                valueToCompare2 = getSemantics(o2);
-                                break;
-                            case REL_DELETE_RULE:
-                                valueToCompare1 = DeleteRule.deleteRuleName(o1.getDeleteRule());
-                                valueToCompare2 = DeleteRule.deleteRuleName(o2.getDeleteRule());
-                                break;
-                            case REL_TARGET_PATH:
-                                valueToCompare1 = o1.getDbRelationshipPath();
-                                valueToCompare2 = o2.getDbRelationshipPath();
-                                break;
-                        }
-                        return (valueToCompare1 == null) ? -1 : (valueToCompare2 == null)
-                                ? 1
-                                : valueToCompare1.compareTo(valueToCompare2);
-                    }
-
-                });
+                Collections.sort(objectList, new ObjRelationshipTableComparator(sortCol));
                 if (!isAscent) {
                     Collections.reverse(objectList);
                 }
                 break;
+            default:
+                break;
+        }
+    }
+
+    private static class ObjRelationshipTableComparator implements Comparator<ObjRelationship>{
 
+        private int sortCol;
+
+        public ObjRelationshipTableComparator(int sortCol) {
+            this.sortCol = sortCol;
+        }
+
+        public int compare(ObjRelationship o1, ObjRelationship o2) {
+            if ((o1 == null && o2 == null) || o1 == o2) {
+                return 0;
+            }
+            else if (o1 == null && o2 != null) {
+                return -1;
+            }
+            else if (o1 != null && o2 == null) {
+                return 1;
+            }
+
+            switch(sortCol){
+                case REL_COLLECTION_TYPE:
+                    return compareColumnsData(o1.getCollectionType(), o2.getCollectionType());
+                case REL_MAP_KEY:
+                    return compareColumnsData(o1.getMapKey(), o2.getMapKey());
+                case REL_SEMANTICS:
+                    return compareColumnsData(getSemantics(o1), getSemantics(o2));
+                case REL_DELETE_RULE:
+                    return compareColumnsData(DeleteRule.deleteRuleName(o1.getDeleteRule()),
+                                    DeleteRule.deleteRuleName(o2.getDeleteRule()));
+                case REL_TARGET_PATH:
+                    return compareColumnsData(o1.getDbRelationshipPath(), o2.getDbRelationshipPath());
+                default:
+                    return compareColumnsData("", "");
+            }
         }
+    }
 
+    private static int compareColumnsData(String value1, String value2) {
+        if (value1 == null) {
+            return -1;
+        } else if (value2 == null) {
+            return 1;
+        } else {
+            return value1.compareTo(value2);
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/DbAttributePathComboBoxEditor.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/DbAttributePathComboBoxEditor.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/DbAttributePathComboBoxEditor.java
new file mode 100644
index 0000000..14cb155
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/DbAttributePathComboBoxEditor.java
@@ -0,0 +1,208 @@
+/*****************************************************************
+ *   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.util;
+
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.Entity;
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.modeler.editor.ObjAttributeTableModel;
+import org.apache.cayenne.util.CayenneMapEntry;
+import org.apache.commons.lang.StringUtils;
+
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JTable;
+import javax.swing.text.JTextComponent;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Font;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class DbAttributePathComboBoxEditor extends PathChooserComboBoxCellEditor {
+
+    private static final int DB_ATTRIBUTE_PATH_COLUMN = 3;
+
+    private ObjAttributeTableModel model;
+
+    @Override
+    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
+        this.model = (ObjAttributeTableModel) table.getModel();
+        this.row = row;
+        treeModel = createTreeModelForComboBox(row);
+        if (treeModel == null) {
+            return new JLabel("You should select table for this ObjectEntity");
+        }
+        initializeCombo(model, row, table);
+
+        String dbAttributePath = ((JTextComponent) (comboBoxPathChooser).getEditor().getEditorComponent()).getText();
+        previousEmbeddedLevel = StringUtils.countMatches(dbAttributePath, ".");
+        return comboBoxPathChooser;
+    }
+
+    @Override
+    public Object getCellEditorValue() {
+        return model.getValueAt(row, DB_ATTRIBUTE_PATH_COLUMN);
+    }
+
+    @Override
+    protected void initializeCombo(CayenneTableModel model, int row, final JTable table) {
+        super.initializeCombo(model, row, table);
+        ((JTextComponent) (comboBoxPathChooser).
+                getEditor().getEditorComponent()).
+                setText(((ObjAttributeTableModel) model).getAttribute(row).getValue().getDbAttributePath());
+        comboBoxPathChooser.setRenderer(new DefaultListCellRenderer() {
+            @Override
+            public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+                Object currentNode = getCurrentNode((String) value);
+                JLabel jLabel = new JLabel();
+                jLabel.setFont(new Font("Verdana", Font.PLAIN, 13));
+                if (isSelected) {
+                    jLabel.setOpaque(true);
+                    jLabel.setBackground(new Color(0xB4B4B4));
+                }
+                if (currentNode instanceof DbRelationship) {
+                    if (((String) value).charAt(((String) value).length() - 1) != '.') {
+                        jLabel.setText(ModelerUtil.getObjectName(value) + " ->");
+                    }
+                    return jLabel;
+                }
+                jLabel.setText(ModelerUtil.getObjectName(value));
+                return jLabel;
+            }
+        });
+    }
+
+
+    @Override
+    protected Object getCurrentNodeToInitializeCombo(CayenneTableModel model, int row) {
+        return getCurrentNode(getPathToInitializeCombo(model, row));
+    }
+
+    @Override
+    protected String getPathToInitializeCombo(CayenneTableModel model, int row) {
+        String pathString = ((ObjAttributeTableModel) model).getAttribute(row).getValue().getDbAttributePath();
+        if (pathString == null) {
+            return "";
+        }
+        String[] pathStrings = pathString.split(Pattern.quote("."));
+        String lastStringInPath = pathStrings[pathStrings.length - 1];
+        return pathString.replaceAll(lastStringInPath + '$', "");
+    }
+
+    @Override
+    protected void enterPressed(JTable table){
+        String dbAttributePath =((JTextComponent) comboBoxPathChooser.
+                getEditor().getEditorComponent()).getText();
+        Object currentNode = getCurrentNode(dbAttributePath);
+
+        String[] pathStrings = dbAttributePath.split(Pattern.quote("."));
+        String lastStringInPath = pathStrings[pathStrings.length - 1];
+        if (ModelerUtil.getObjectName(currentNode).equals(lastStringInPath) &&
+                currentNode instanceof DbAttribute) {
+            // in this case choose is made.. we save data
+
+            if (table.getCellEditor() != null) {
+                table.getCellEditor().stopCellEditing();
+                model.getAttribute(row).setDbAttributePath(dbAttributePath);
+                model.setUpdatedValueAt(dbAttributePath, row, DB_ATTRIBUTE_PATH_COLUMN);
+            }
+        }else if (ModelerUtil.getObjectName(currentNode).equals(lastStringInPath) &&
+                currentNode instanceof DbRelationship) {
+            // in this case we add dot  to pathString (if it is missing) and show variants for currentNode
+
+            if (dbAttributePath.charAt(dbAttributePath.length()-1) != '.') {
+                dbAttributePath = dbAttributePath + '.';
+                previousEmbeddedLevel =  StringUtils.countMatches(dbAttributePath,".");
+                ((JTextComponent) (comboBoxPathChooser).
+                        getEditor().getEditorComponent()).setText(dbAttributePath);
+            }
+            List<String> currentNodeChildren = new ArrayList<>();
+            currentNodeChildren.add(dbAttributePath);
+            currentNodeChildren.addAll(getChildren(getCurrentNode(dbAttributePath), dbAttributePath));
+            comboBoxPathChooser.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
+            comboBoxPathChooser.showPopup();
+            comboBoxPathChooser.setPopupVisible(true);
+        }
+    }
+
+    @Override
+    protected EntityTreeModel createTreeModelForComboBox(int attributeIndexInTable) {
+        ObjAttribute attribute = model.getAttribute(attributeIndexInTable).getValue();
+        Entity firstEntity = null;
+        if (attribute.getDbAttribute() == null) {
+
+            if (attribute.getParent() instanceof ObjEntity) {
+                DbEntity dbEnt = ((ObjEntity) attribute.getParent()).getDbEntity();
+
+                if (dbEnt != null) {
+                    Collection<DbAttribute> attributes = dbEnt.getAttributes();
+                    Collection<DbRelationship> rel = dbEnt.getRelationships();
+
+                    if (!attributes.isEmpty()) {
+                        Iterator<DbAttribute> iterator = attributes.iterator();
+                        firstEntity = iterator.next().getEntity();
+                    } else if (!rel.isEmpty()) {
+                        Iterator<DbRelationship> iterator = rel.iterator();
+                        firstEntity = iterator.next().getSourceEntity();
+                    }
+                }
+            }
+        } else {
+            firstEntity = getFirstEntity(attribute);
+        }
+
+        if (firstEntity != null) {
+            EntityTreeModel treeModel = new EntityTreeModel(firstEntity);
+            treeModel.setFilter(new EntityTreeAttributeRelationshipFilter());
+            return treeModel;
+        }
+        return null;
+    }
+
+    private Entity getFirstEntity(ObjAttribute attribute) {
+        Iterator<CayenneMapEntry> it = attribute.getDbPathIterator();
+        Entity firstEnt = attribute.getDbAttribute().getEntity();
+        boolean setEnt = false;
+
+        while (it.hasNext()) {
+            Object ob = it.next();
+            if (ob instanceof DbRelationship) {
+                if (!setEnt) {
+                    firstEnt = ((DbRelationship) ob).getSourceEntity();
+                    setEnt = true;
+                }
+            } else if (ob instanceof DbAttribute) {
+                if (!setEnt) {
+                    firstEnt = ((DbAttribute) ob).getEntity();
+                }
+            }
+        }
+        return firstEnt;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/DbRelationshipPathComboBoxEditor.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/DbRelationshipPathComboBoxEditor.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/DbRelationshipPathComboBoxEditor.java
new file mode 100644
index 0000000..9aac322
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/DbRelationshipPathComboBoxEditor.java
@@ -0,0 +1,150 @@
+/*****************************************************************
+ *   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.util;
+
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.modeler.editor.ObjRelationshipTableModel;
+
+import javax.swing.JLabel;
+import javax.swing.JTable;
+import javax.swing.text.JTextComponent;
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Collection;
+import java.util.regex.Pattern;
+
+public class DbRelationshipPathComboBoxEditor extends PathChooserComboBoxCellEditor implements ActionListener {
+
+    private static final int REL_TARGET_PATH_COLUMN = 2;
+    private static int enterPressedCount = 0;
+
+    private ObjRelationshipTableModel model;
+
+    @Override
+    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
+        this.model = (ObjRelationshipTableModel) table.getModel();
+        this.row = row;
+        treeModel = createTreeModelForComboBox(row);
+        if (treeModel == null) {
+            return new JLabel("You should select table for this ObjectEntity");
+        }
+        initializeCombo(model, row, table);
+
+        String dbRelationshipPath = ((JTextComponent) (comboBoxPathChooser).
+                getEditor().getEditorComponent()).getText();
+        previousEmbeddedLevel = dbRelationshipPath.split(Pattern.quote(".")).length;
+        return comboBoxPathChooser;
+    }
+
+    @Override
+    public Object getCellEditorValue() {
+        return model.getValueAt(row, REL_TARGET_PATH_COLUMN);
+    }
+
+    @Override
+    protected void initializeCombo(CayenneTableModel model, int row, final JTable table) {
+        super.initializeCombo(model, row, table);
+        ((JTextComponent) (comboBoxPathChooser).
+                getEditor().getEditorComponent()).
+                setText(((ObjRelationshipTableModel) model).getRelationship(row).getDbRelationshipPath());
+
+        enterPressedCount = 0;
+        comboBoxPathChooser.addActionListener(this);
+    }
+
+    @Override
+    protected void enterPressed(JTable table) {
+        String dbRelationshipPath = ((JTextComponent) (comboBoxPathChooser).
+                getEditor().getEditorComponent()).getText();
+        Object currentNode = getCurrentNode(dbRelationshipPath);
+        String[] pathStrings = dbRelationshipPath.split(Pattern.quote("."));
+        String lastStringInPath = pathStrings[pathStrings.length - 1];
+        if (lastStringInPath.equals(ModelerUtil.getObjectName(currentNode))
+                && currentNode instanceof DbRelationship) {
+            if (enterPressedCount == 1) {
+                //it is second time enter pressed.. so we will save input data
+                enterPressedCount = 0;
+                if (table.getCellEditor() != null) {
+
+                    table.getCellEditor().stopCellEditing();
+                    model.getRelationship(row).setDbRelationshipPath(dbRelationshipPath);
+
+                    //we need object target to save it in model
+                    DbEntity lastEntity = ((DbRelationship) currentNode).getTargetEntity();
+                    Collection<ObjEntity> objEntities = ((DbRelationship) currentNode).getTargetEntity().
+                            getDataMap().getMappedEntities(lastEntity);
+                    ObjEntity objectTarget = objEntities.isEmpty() ? null : objEntities.iterator().next();
+                    model.getRelationship(row).setTargetEntityName(objectTarget);
+                }
+                table.repaint();
+            } else {
+                enterPressedCount = 1;
+            }
+        }
+    }
+
+    @Override
+    protected void parsePathString(char lastEnteredCharacter) {
+        super.parsePathString(lastEnteredCharacter);
+        enterPressedCount = 0;
+    }
+
+    @Override
+    protected EntityTreeModel createTreeModelForComboBox(int relationshipIndexInTable) {
+        if (model.getRelationship(relationshipIndexInTable).
+                getSourceEntity().getDbEntity() == null) {
+            return null;
+        }
+        EntityTreeModel treeModel = new EntityTreeModel(model.getRelationship(relationshipIndexInTable).
+                getSourceEntity().getDbEntity());
+        treeModel.setFilter(new EntityTreeRelationshipFilter());
+        return treeModel;
+    }
+
+    @Override
+    protected Object getCurrentNodeToInitializeCombo(CayenneTableModel model, int row) {
+        return getCurrentNode(getPathToInitializeCombo(model, row));
+    }
+
+    @Override
+    protected String getPathToInitializeCombo(CayenneTableModel model, int row) {
+        String pathString = ((ObjRelationshipTableModel) model).getRelationship(row).getDbRelationshipPath();
+        if (pathString == null) {
+            return "";
+        }
+        String[] pathStrings = pathString.split(Pattern.quote("."));
+        String lastStringInPath = pathStrings[pathStrings.length - 1];
+        return pathString.replaceAll(lastStringInPath + '$', "");
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        model.getRelationship(row).setMapKey(null);
+
+        //for some reason dbRelationshipPathCombo don't load selected item text, so we made it by hand
+        if (comboBoxPathChooser.getSelectedIndex() != (-1)) {
+            ((JTextComponent) (comboBoxPathChooser).
+                    getEditor().getEditorComponent()).setText(comboBoxPathChooser.getSelectedItem().toString());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeAttributeRelationshipFilter.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeAttributeRelationshipFilter.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeAttributeRelationshipFilter.java
new file mode 100644
index 0000000..12d9900
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeAttributeRelationshipFilter.java
@@ -0,0 +1,47 @@
+/*****************************************************************
+ *   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.util;
+
+import org.apache.cayenne.map.Attribute;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.Relationship;
+
+public class EntityTreeAttributeRelationshipFilter implements EntityTreeFilter {
+
+    public boolean attributeMatch(Object node, Attribute attr) {
+        if (!(node instanceof Attribute)) {
+            return true;
+        }
+        return false;
+    }
+
+    public boolean relationshipMatch(Object node, Relationship rel) {
+        if (!(node instanceof Relationship)) {
+            return true;
+        }
+
+        /**
+         * We do not allow A->B->A chains, where relationships
+         * are to-one
+         */
+        DbRelationship prev = (DbRelationship) node;
+        return !(!rel.isToMany() && prev.getReverseRelationship() == rel);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeFilter.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeFilter.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeFilter.java
index 2b2b065..eaebb7c 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeFilter.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeFilter.java
@@ -29,10 +29,10 @@ public interface EntityTreeFilter {
     /**
      * Checks if attribute should appear in the tree 
      */
-    public boolean attributeMatch(Object node, Attribute attr);
+    boolean attributeMatch(Object node, Attribute attr);
     
     /**
      * Checks if relationship should appear in the tree 
      */
-    public boolean relationshipMatch(Object node, Relationship rel);
+    boolean relationshipMatch(Object node, Relationship rel);
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeRelationshipFilter.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeRelationshipFilter.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeRelationshipFilter.java
new file mode 100644
index 0000000..06cc25b
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeRelationshipFilter.java
@@ -0,0 +1,45 @@
+/*****************************************************************
+ *   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.util;
+
+import org.apache.cayenne.map.Attribute;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.Relationship;
+
+public class EntityTreeRelationshipFilter implements EntityTreeFilter {
+
+    public boolean attributeMatch(Object node, Attribute attr) {
+        // attrs not allowed here
+        return false;
+    }
+
+    public boolean relationshipMatch(Object node, Relationship rel) {
+        if (!(node instanceof Relationship)) {
+            return true;
+        }
+
+        /**
+         * We do not allow A->B->A chains, where relationships are
+         * to-one
+         */
+        DbRelationship prev = (DbRelationship) node;
+        return !(!rel.isToMany() && prev.getReverseRelationship() == rel);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/JTableCollectionTypeComboBoxEditor.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/JTableCollectionTypeComboBoxEditor.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/JTableCollectionTypeComboBoxEditor.java
new file mode 100644
index 0000000..f43b095
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/JTableCollectionTypeComboBoxEditor.java
@@ -0,0 +1,84 @@
+/*****************************************************************
+ *   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.util;
+
+import org.apache.cayenne.modeler.Application;
+import org.apache.cayenne.modeler.editor.ObjRelationshipTableModel;
+
+import javax.swing.AbstractCellEditor;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JTable;
+import javax.swing.table.TableCellEditor;
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class JTableCollectionTypeComboBoxEditor extends AbstractCellEditor implements TableCellEditor {
+
+        private static final String COLLECTION_TYPE_MAP = "java.util.Map";
+        private static final String COLLECTION_TYPE_SET = "java.util.Set";
+        private static final String COLLECTION_TYPE_COLLECTION = "java.util.Collection";
+        private static final String DEFAULT_COLLECTION_TYPE = "java.util.List";
+        private static final int REL_COLLECTION_TYPE_COLUMN = 3;
+
+        private ObjRelationshipTableModel model;
+        private int row;
+
+        public JTableCollectionTypeComboBoxEditor() {
+        }
+
+        @Override
+        public Component getTableCellEditorComponent(final JTable table, Object value, boolean isSelected, final int row, final int column) {
+            this.model = (ObjRelationshipTableModel) table.getModel();
+            this.row = row;
+
+            final JComboBox collectionTypeCombo = Application.getWidgetFactory().createComboBox(
+                    new Object[]{
+                            COLLECTION_TYPE_MAP,
+                            COLLECTION_TYPE_SET,
+                            COLLECTION_TYPE_COLLECTION,
+                            DEFAULT_COLLECTION_TYPE
+                    },
+                    false);
+            if (model.getRelationship(row).isToMany()) {
+                collectionTypeCombo.setEnabled(true);
+                collectionTypeCombo.setSelectedItem(model.getRelationship(row).getCollectionType());
+            } else {
+                JLabel labelIfToOneRelationship = new JLabel();
+                labelIfToOneRelationship.setEnabled(false);
+                return labelIfToOneRelationship;
+            }
+            collectionTypeCombo.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    Object selected = collectionTypeCombo.getSelectedItem();
+                    model.setUpdatedValueAt(selected, row, REL_COLLECTION_TYPE_COLUMN);
+                    table.repaint();
+                }
+            });
+            return collectionTypeCombo;
+        }
+
+        @Override
+        public Object getCellEditorValue() {
+            return model.getValueAt(row, REL_COLLECTION_TYPE_COLUMN);
+        }
+    }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/JTableCollectionTypeComboBoxRenderer.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/JTableCollectionTypeComboBoxRenderer.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/JTableCollectionTypeComboBoxRenderer.java
new file mode 100644
index 0000000..8c5d497
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/JTableCollectionTypeComboBoxRenderer.java
@@ -0,0 +1,55 @@
+/*****************************************************************
+ *   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.util;
+
+import org.apache.cayenne.modeler.editor.ObjRelationshipTableModel;
+
+import javax.swing.JLabel;
+import javax.swing.JTable;
+import javax.swing.table.TableCellRenderer;
+import java.awt.Component;
+import java.awt.Font;
+
+public class JTableCollectionTypeComboBoxRenderer implements TableCellRenderer {
+
+        private ObjRelationshipTableModel model;
+
+        public JTableCollectionTypeComboBoxRenderer() {
+        }
+
+        @Override
+        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+            this.model = (ObjRelationshipTableModel) table.getModel();
+            JLabel labelIfToOneRelationship = new JLabel();
+            labelIfToOneRelationship.setEnabled(false);
+            JLabel labelIfToManyRelationship = new JLabel((String) value);
+            labelIfToManyRelationship.setEnabled(true);
+            labelIfToManyRelationship.setFont(new Font("Verdana", Font.PLAIN, 12));
+            if (value == null) {
+                return labelIfToOneRelationship;
+            }
+            if (model.getRelationship(row).isToMany()) {
+                return labelIfToManyRelationship;
+            } else {
+                return labelIfToOneRelationship;
+            }
+
+        }
+    }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/JTableMapKeyComboBoxEditor.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/JTableMapKeyComboBoxEditor.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/JTableMapKeyComboBoxEditor.java
new file mode 100644
index 0000000..3e1178a
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/JTableMapKeyComboBoxEditor.java
@@ -0,0 +1,99 @@
+/*****************************************************************
+ *   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.util;
+
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.modeler.Application;
+import org.apache.cayenne.modeler.editor.ObjRelationshipTableModel;
+
+import javax.swing.AbstractCellEditor;
+import javax.swing.JComboBox;
+import javax.swing.JTable;
+import javax.swing.table.TableCellEditor;
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.List;
+
+public class JTableMapKeyComboBoxEditor extends AbstractCellEditor implements TableCellEditor {
+
+        private static final String DEFAULT_MAP_KEY = "ID (default)";
+        private static final String COLLECTION_TYPE_MAP = "java.util.Map";
+        private static final int REL_MAP_KEY_COLUMN = 4;
+
+        private List<String> mapKeys = new ArrayList<>();
+        private ObjRelationshipTableModel model;
+        private int row;
+
+        public JTableMapKeyComboBoxEditor() {
+        }
+
+        private void initMapKeys() {
+            mapKeys.clear();
+            mapKeys.add(DEFAULT_MAP_KEY);
+            /**
+             * Object target can be null when selected target DbEntity has no
+             * ObjEntities
+             */
+            ObjEntity objectTarget = model.getRelationship(row).getTargetEntity();
+            if (objectTarget == null) {
+                return;
+            }
+            for (ObjAttribute attribute : objectTarget.getAttributes()) {
+                mapKeys.add(attribute.getName());
+            }
+        }
+
+        @Override
+        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, final int row, final int column) {
+            this.model = (ObjRelationshipTableModel) table.getModel();
+            this.row = row;
+            initMapKeys();
+            final JComboBox mapKeysComboBox = Application.getWidgetFactory().createComboBox(
+                    mapKeys,
+                    false);
+            if ((model.getRelationship(row).getCollectionType() == null)
+                    || (!model.getRelationship(row).getCollectionType().equals(COLLECTION_TYPE_MAP))) {
+                JComboBox jComboBox = new JComboBox();
+                jComboBox.setFocusable(false);
+                jComboBox.setEnabled(false);
+                return jComboBox;
+            } else {
+                mapKeysComboBox.setFocusable(true);
+                mapKeysComboBox.setEnabled(true);
+            }
+            mapKeysComboBox.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    Object selected = mapKeysComboBox.getSelectedItem();
+                    model.setUpdatedValueAt(selected, row, REL_MAP_KEY_COLUMN);
+                }
+            });
+            mapKeysComboBox.setSelectedItem(model.getRelationship(row).getMapKey());
+            return mapKeysComboBox;
+        }
+
+        @Override
+        public Object getCellEditorValue() {
+            return model.getValueAt(row, REL_MAP_KEY_COLUMN);
+        }
+    }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/JTableMapKeyComboBoxRenderer.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/JTableMapKeyComboBoxRenderer.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/JTableMapKeyComboBoxRenderer.java
new file mode 100644
index 0000000..6f359a1
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/JTableMapKeyComboBoxRenderer.java
@@ -0,0 +1,58 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util;
+
+import org.apache.cayenne.modeler.editor.ObjRelationshipTableModel;
+
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JTable;
+import javax.swing.table.TableCellRenderer;
+import java.awt.Component;
+import java.awt.Font;
+
+public class JTableMapKeyComboBoxRenderer implements TableCellRenderer {
+
+        private static final String DEFAULT_MAP_KEY = "ID (default)";
+        private static final String COLLECTION_TYPE_MAP = "java.util.Map";
+
+        private ObjRelationshipTableModel model;
+
+        public JTableMapKeyComboBoxRenderer() {
+        }
+
+        @Override
+        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+            this.model = (ObjRelationshipTableModel) table.getModel();
+            if ((model.getRelationship(row).getCollectionType() == null)
+                    || (!model.getRelationship(row).getCollectionType().equals(COLLECTION_TYPE_MAP))) {
+                JComboBox jComboBox = new JComboBox();
+                jComboBox.setFocusable(false);
+                jComboBox.setEnabled(false);
+                return jComboBox;
+            }
+            if (model.getRelationship(row).getMapKey() == null) {
+                model.getRelationship(row).setMapKey(DEFAULT_MAP_KEY);
+            }
+            JLabel jLabel = new JLabel(model.getRelationship(row).getMapKey());
+            jLabel.setFont(new Font("Verdana", Font.PLAIN, 12));
+            return jLabel;
+        }
+    }
\ No newline at end of file


Mime
View raw message