You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by sk...@apache.org on 2015/12/07 16:31:40 UTC

[1/8] cayenne git commit: rename table columns

Repository: cayenne
Updated Branches:
  refs/heads/master ee4f50658 -> 9baef19b7


rename table columns


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/7bf68c60
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/7bf68c60
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/7bf68c60

Branch: refs/heads/master
Commit: 7bf68c6014ca93043edccadaccf414e357e1af28
Parents: ee4f506
Author: AlexandrShestak <sh...@mail.ru>
Authored: Tue Nov 24 12:03:11 2015 +0300
Committer: Savva Kolbachev <s....@gmail.com>
Committed: Mon Dec 7 13:21:40 2015 +0300

----------------------------------------------------------------------
 .../java/org/apache/cayenne/modeler/dialog/DbJoinTableModel.java | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/7bf68c60/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/DbJoinTableModel.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/DbJoinTableModel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/DbJoinTableModel.java
index 45f9eba..e95e0a6 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/DbJoinTableModel.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/DbJoinTableModel.java
@@ -87,9 +87,9 @@ public class DbJoinTableModel extends CayenneTableModel {
 
     public String getColumnName(int column) {
         if (column == SOURCE)
-            return "Source";
+            return relationship.getSourceEntity().getName();
         else if (column == TARGET)
-            return "Target";
+            return relationship.getTargetEntity().getName();
         else
             return "";
     }


[4/8] cayenne git commit: add auto suggestion DbAttributePath to table. reason : reduse DatabaseMapping dialog

Posted by sk...@apache.org.
add auto suggestion DbAttributePath to table. reason : reduse DatabaseMapping dialog


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/681a1fac
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/681a1fac
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/681a1fac

Branch: refs/heads/master
Commit: 681a1fac58559ef9f315da02903c4451d227cffd
Parents: 7bf68c6
Author: AlexandrShestak <sh...@mail.ru>
Authored: Tue Nov 24 12:26:36 2015 +0300
Committer: Savva Kolbachev <s....@gmail.com>
Committed: Mon Dec 7 13:21:41 2015 +0300

----------------------------------------------------------------------
 .../modeler/editor/ObjAttributeTableModel.java  |  11 +-
 .../modeler/editor/ObjEntityAttributePanel.java | 378 ++++++++++++++++++-
 2 files changed, 369 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/681a1fac/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjAttributeTableModel.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjAttributeTableModel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjAttributeTableModel.java
index cfd4fdb..0cee45a 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjAttributeTableModel.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjAttributeTableModel.java
@@ -164,7 +164,7 @@ public class ObjAttributeTableModel extends CayenneTableModel<ObjAttributeWrappe
             case OBJ_ATTRIBUTE_TYPE:
                 return "Java Type";
             case DB_ATTRIBUTE:
-                return "DbAttribute";
+                return "DbAttributePath";
             case DB_ATTRIBUTE_TYPE:
                 return "DB Type";
             case LOCKING:
@@ -281,9 +281,9 @@ public class ObjAttributeTableModel extends CayenneTableModel<ObjAttributeWrappe
 
         return true;
     }
-    
+
+    @Override
     public void setUpdatedValueAt(Object value, int row, int column) {
-        
         ObjAttributeWrapper attribute = getAttribute(row);
         attribute.resetEdits();
         AttributeEvent event = new AttributeEvent(eventSource, attribute.getValue(), entity);
@@ -438,11 +438,6 @@ public class ObjAttributeTableModel extends CayenneTableModel<ObjAttributeWrappe
                 else if (attribute.getDbAttribute() != null) {
                     attribute.setDbAttributePath(null);
                 }
-
-                // If path is flattened attribute, update the JComboBox
-                if (path != null && path.split("\\.").length > 1 && dbEntity != null) {
-                    setComboBoxes(nameAttr, column);
-                }
             }
             fireTableRowsUpdated(row, row);
         }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/681a1fac/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityAttributePanel.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityAttributePanel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityAttributePanel.java
index fa980e6..d3496e8 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityAttributePanel.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityAttributePanel.java
@@ -19,10 +19,16 @@
 package org.apache.cayenne.modeler.editor;
 
 import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.map.Attribute;
 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.Embeddable;
+import org.apache.cayenne.map.Entity;
 import org.apache.cayenne.map.ObjAttribute;
 import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.Relationship;
 import org.apache.cayenne.map.event.AttributeEvent;
 import org.apache.cayenne.map.event.EntityEvent;
 import org.apache.cayenne.map.event.ObjAttributeListener;
@@ -44,36 +50,50 @@ 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.CayenneTableModel;
+import org.apache.cayenne.modeler.util.EntityTreeFilter;
+import org.apache.cayenne.modeler.util.EntityTreeModel;
 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.cayenne.util.CayenneMapEntry;
+import org.apache.commons.lang.StringUtils;
 
+import javax.swing.AbstractCellEditor;
+import javax.swing.DefaultComboBoxModel;
 import javax.swing.Icon;
 import javax.swing.ImageIcon;
 import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JList;
 import javax.swing.JMenuItem;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.JTable;
+import javax.swing.ListCellRenderer;
 import javax.swing.ListSelectionModel;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
 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.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Pattern;
 
 /**
  * Detail view of the ObjEntity attributes.
@@ -108,7 +128,16 @@ public class ObjEntityAttributePanel extends JPanel implements ObjEntityDisplayL
 
         ActionManager actionManager = Application.getInstance().getActionManager();
 
-        table = new CayenneTable();
+        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.setDefaultRenderer(String.class, new CellRenderer());
         tablePreferences = new TableColumnPreferences(
                 ObjAttributeTableModel.class,
@@ -205,16 +234,6 @@ public class ObjEntityAttributePanel extends JPanel implements ObjEntityDisplayL
         AutoCompletion.enable(javaTypesCombo, false, true);
         typeColumn.setCellEditor(Application.getWidgetFactory().createCellEditor(
                 javaTypesCombo));
-
-        if (model.getEntity().getDbEntity() != null) {
-            Collection<String> nameAttr = ModelerUtil.getDbAttributeNames(mediator, model
-                    .getEntity()
-                    .getDbEntity());
-
-            model.setCellEditor(nameAttr, table);
-            model.setComboBoxes(nameAttr, ObjAttributeTableModel.DB_ATTRIBUTE);
-        }
-
     }
 
     /**
@@ -347,6 +366,9 @@ public class ObjEntityAttributePanel extends JPanel implements ObjEntityDisplayL
 
         initComboBoxes(model);
 
+        table.getColumnModel().getColumn(3).setCellRenderer(new JTableDbAttributeComboBoxRenderer());
+        table.getColumnModel().getColumn(3).setCellEditor(new JTableDbAttributeComboBoxEditor());
+
         tablePreferences.bind(
                 table,
                 minSizes,
@@ -502,4 +524,336 @@ public class ObjEntityAttributePanel extends JPanel implements ObjEntityDisplayL
     public ActionListener getResolver() {
         return resolver;
     }
-}
\ No newline at end of file
+
+
+    private static final class JTableDbAttributeComboBoxRenderer extends DefaultTableCellRenderer {
+
+        public JTableDbAttributeComboBoxRenderer() {
+        }
+
+        @Override
+        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
+                                                       boolean hasFocus, int row, int column) {
+            if (value instanceof DbAttribute){
+                JLabel jLabel = new  JLabel(ModelerUtil.getObjectName(value));
+                jLabel.setFont(new Font("Verdana", Font.PLAIN , 12));
+                return jLabel;
+            }
+            if (value !=null){
+                JLabel jLabel = new JLabel(value.toString());
+                jLabel.setFont(new Font("Verdana", Font.PLAIN , 12));
+                return jLabel;
+            }
+            return new JLabel("");
+        }
+    }
+
+    private final static class JTableDbAttributeComboBoxEditor extends AbstractCellEditor implements TableCellEditor {
+
+        private int row;
+        private int column;
+        private JComboBox dbAttributePathCombo;
+        private EntityTreeModel treeModel;
+        private int previousEmbededLevel = 0;
+        private ObjAttributeTableModel model;
+
+        private JTableDbAttributeComboBoxEditor() {
+        }
+
+        @Override
+        public Object getCellEditorValue() {
+             return model.getValueAt(row,column);
+        }
+
+        @Override
+        public Component getTableCellEditorComponent(final JTable table, Object o, boolean b, int i, int i1) {
+            this.model = (ObjAttributeTableModel) table.getModel();
+            row = i;
+            column = i1;
+            treeModel = createTreeModelForComboBoxBrowser(row);
+            if (treeModel == null)
+                return new JLabel("You need select table to this ObjectEntity");
+            initializeCombo(model , row);
+
+            String dbAttributePath = ((JTextComponent) (dbAttributePathCombo).
+                    getEditor().getEditorComponent()).getText();
+            previousEmbededLevel =  StringUtils.countMatches(dbAttributePath,".");
+
+            dbAttributePathCombo.getEditor().getEditorComponent().addKeyListener(new KeyAdapter() {
+                private void enterPressed(){
+                    String dbAttributePath = ((JTextComponent) (dbAttributePathCombo).
+                            getEditor().getEditorComponent()).getText();
+                    Object currentNode = getCurrentNode(dbAttributePath);
+                    if (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, column);
+                        }
+                    }else if (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 + ".";
+                            previousEmbededLevel =  StringUtils.countMatches(dbAttributePath,".");
+                            ((JTextComponent) (dbAttributePathCombo).
+                                    getEditor().getEditorComponent()).setText(dbAttributePath);
+                        }
+                        List<String> currentNodeChildren = new ArrayList<>();
+                        currentNodeChildren.add(dbAttributePath + "");
+                        currentNodeChildren.addAll(getChildren(getCurrentNode(dbAttributePath), dbAttributePath));
+                        dbAttributePathCombo.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
+                        dbAttributePathCombo.showPopup();
+                        dbAttributePathCombo.setPopupVisible(true);
+                    }
+                }
+
+                @Override
+                public void keyReleased(KeyEvent event) {
+                    if(event.getKeyCode() == KeyEvent.VK_ENTER){
+                        enterPressed();
+                        return;
+                    }
+                    parseDbAttributeString(event.getKeyChar());
+                }
+            });
+            return dbAttributePathCombo;
+        }
+
+        private void initializeCombo(ObjAttributeTableModel model , int row){
+            String dbAttributePath = model.getAttribute(row).getValue().getDbAttributePath();
+            Object currentNode;
+            if (dbAttributePath == null){
+                //case if it is new attribute or for some reason dbAttributePath is null
+                currentNode = getCurrentNode(dbAttributePath);
+                dbAttributePath = "";
+
+            }else{
+                //case if  dbAttributePath isn't null and we must change it to find auto completion list
+                String[] pathStrings = dbAttributePath.split(Pattern.quote("."));
+                String lastStringInPath = pathStrings[pathStrings.length - 1];
+                dbAttributePath = dbAttributePath.replaceAll(lastStringInPath + "$", "");
+                currentNode = getCurrentNode(dbAttributePath);
+            }
+            List<String> nodeChildren = getChildren(currentNode , dbAttributePath);
+            dbAttributePathCombo = Application.getWidgetFactory().createComboBox(
+                    nodeChildren,
+                    false);
+            AutoCompletion.enable(dbAttributePathCombo, false, true);
+            ((JTextComponent) (dbAttributePathCombo).
+                    getEditor().getEditorComponent()).setText(model.getAttribute(row).getValue().getDbAttributePath());
+            return;
+        }
+
+        private void parseDbAttributeString(char lastEnteredCharacter){
+            String dbAttributePath = ((JTextComponent) (dbAttributePathCombo).
+                    getEditor().getEditorComponent()).getText();
+
+            if (dbAttributePath.equals("")){
+                List<String> currentNodeChildren = new ArrayList<>();
+                currentNodeChildren.add("");
+                currentNodeChildren.addAll(getChildren(getCurrentNode(dbAttributePath),""));
+                dbAttributePathCombo.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
+                dbAttributePathCombo.showPopup();
+                dbAttributePathCombo.setPopupVisible(true);
+                return;
+            }
+
+            if (lastEnteredCharacter == '.') {
+                processDotEntered();
+                return;
+            }
+            int currentEmbededLevel =  StringUtils.countMatches(dbAttributePath,".");
+            if (previousEmbededLevel != currentEmbededLevel){
+                previousEmbededLevel = currentEmbededLevel;
+                List<String> currentNodeChildren = new ArrayList<>();
+                String[] pathStrings = dbAttributePath.split(Pattern.quote("."));
+                String lastStringInPath = pathStrings[pathStrings.length - 1];
+                String saveDbAttributePath = dbAttributePath;
+                dbAttributePath = dbAttributePath.replaceAll(lastStringInPath + "$", "");
+                currentNodeChildren.addAll(getChildren(getCurrentNode(dbAttributePath), dbAttributePath));
+
+                dbAttributePathCombo.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
+                ((JTextComponent) (dbAttributePathCombo).
+                        getEditor().getEditorComponent()).setText(saveDbAttributePath);
+                dbAttributePathCombo.showPopup();
+                dbAttributePathCombo.setPopupVisible(true);
+                return;
+            }
+        }
+
+            private void processDotEntered(){
+            String dbAttributePath = ((JTextComponent) (dbAttributePathCombo).
+                    getEditor().getEditorComponent()).getText();
+            if (dbAttributePath.equals(".")){
+                List<String> currentNodeChildren = new ArrayList<>();
+                currentNodeChildren.add("");
+                currentNodeChildren.addAll(getChildren(getCurrentNode(""),""));
+                dbAttributePathCombo.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
+                dbAttributePathCombo.showPopup();
+                dbAttributePathCombo.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) (dbAttributePathCombo).
+                            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){
+                        //previous root is treeModel.getRoot()
+                        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));
+                        dbAttributePathCombo.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
+                        dbAttributePathCombo.showPopup();
+                        dbAttributePathCombo.setPopupVisible(true);
+                    }else{
+                        ((JTextComponent) (dbAttributePathCombo).
+                                getEditor().getEditorComponent()).setText(dbAttributePath.substring(0,dbAttributePath.length()-1));
+                    }
+                }
+            }
+            previousEmbededLevel =  StringUtils.countMatches(dbAttributePath,".");
+            return;
+        }
+
+        /**
+         * find current node by dbAttributePath
+         * @param dbAttributePath
+         * @return last node in dbAttributePath which matches DbRelationship or DbAttribute
+         */
+        private final Object getCurrentNode(String dbAttributePath) {
+            try {
+                //case for new attribute
+                if(dbAttributePath == null){
+                    return treeModel.getRoot();
+                }
+                String[] pathStrings = dbAttributePath.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);
+                        String objectName = ModelerUtil.getObjectName(child);
+                        if (objectName.equals(rootChildText)) {
+                            root = child;
+                            break;
+                        }
+                    }
+                }
+                return root;
+            }catch (Exception e){
+                return treeModel.getRoot();
+            }
+        }
+
+        /**
+         * @param node for which we will find children
+         * @param dbAttributePath 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 dbAttributePath){
+            List<String> currentNodeChildren = new ArrayList<>();
+            for(int j = 0 ; j <  treeModel.getChildCount(node) ; j++){
+                Object child = treeModel.getChild(node, j);
+                String objectName = ModelerUtil.getObjectName(child);
+                currentNodeChildren.add(dbAttributePath+objectName);
+            }
+            return currentNodeChildren;
+        }
+
+        /**
+         * @param attributeIndexInTable index of attribute for which now we will create cell editor
+         * @return treeModel for nessesary for us attribute
+         */
+        private EntityTreeModel createTreeModelForComboBoxBrowser(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.size() > 0) {
+                            Iterator<DbAttribute> iterator = attributes.iterator();
+                            firstEntity = iterator.next().getEntity();
+                        } else if (rel.size() > 0) {
+                            Iterator<DbRelationship> iterator = rel.iterator();
+                            firstEntity = iterator.next().getSourceEntity();
+                        }
+                    }
+                }
+            } else {
+                firstEntity = getFirstEntity(attribute);
+            }
+
+            if (firstEntity != null) {
+                EntityTreeModel treeModel = new EntityTreeModel(firstEntity);
+                treeModel.setFilter(new 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);
+                    }
+                });
+                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;
+        }
+    }
+}


[7/8] cayenne git commit: cleanup

Posted by sk...@apache.org.
cleanup


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/b444b1df
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/b444b1df
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/b444b1df

Branch: refs/heads/master
Commit: b444b1df065004a41edc5f6bd13aab7788b1c7c2
Parents: 1d1bc93
Author: AlexandrShestak <sh...@mail.ru>
Authored: Tue Nov 24 13:03:41 2015 +0300
Committer: Savva Kolbachev <s....@gmail.com>
Committed: Mon Dec 7 18:27:13 2015 +0300

----------------------------------------------------------------------
 .../java/org/apache/cayenne/map/Entity.java     |  23 +-
 .../cayenne/modeler/ProjectController.java      |  13 +-
 .../objentity/ObjAttributeInfoDialog.java       |  83 +--
 .../objentity/ObjAttributeInfoDialogView.java   |  51 +-
 .../dialog/objentity/ObjRelationshipInfo.java   |  59 +-
 .../modeler/editor/ObjAttributeTableModel.java  | 400 ++++++-------
 .../modeler/editor/ObjEntityAttributePanel.java | 399 ++-----------
 .../editor/ObjEntityRelationshipPanel.java      | 568 +------------------
 .../editor/ObjRelationshipTableModel.java       | 186 +++---
 .../util/DbAttributePathComboBoxEditor.java     | 208 +++++++
 .../util/DbRelationshipPathComboBoxEditor.java  | 150 +++++
 .../EntityTreeAttributeRelationshipFilter.java  |  47 ++
 .../cayenne/modeler/util/EntityTreeFilter.java  |   4 +-
 .../util/EntityTreeRelationshipFilter.java      |  45 ++
 .../JTableCollectionTypeComboBoxEditor.java     |  84 +++
 .../JTableCollectionTypeComboBoxRenderer.java   |  55 ++
 .../util/JTableMapKeyComboBoxEditor.java        |  99 ++++
 .../util/JTableMapKeyComboBoxRenderer.java      |  58 ++
 .../util/PathChooserComboBoxCellEditor.java     | 192 +++++++
 .../cayenne/modeler/util/ProjectUtil.java       |  85 ++-
 .../modeler/util/SortButtonRenderer.java        |  82 ++-
 .../modeler/util/TableHeaderListener.java       |   2 -
 .../modeler/util/combo/AutoCompletion.java      | 182 ++++--
 23 files changed, 1546 insertions(+), 1529 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/cayenne-server/src/main/java/org/apache/cayenne/map/Entity.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/Entity.java b/cayenne-server/src/main/java/org/apache/cayenne/map/Entity.java
index 97613e7..e687964 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/Entity.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/Entity.java
@@ -19,6 +19,13 @@
 
 package org.apache.cayenne.map;
 
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionException;
+import org.apache.cayenne.util.CayenneMapEntry;
+import org.apache.cayenne.util.ToStringBuilder;
+import org.apache.cayenne.util.XMLSerializable;
+
 import java.io.Serializable;
 import java.util.Collection;
 import java.util.Collections;
@@ -28,13 +35,6 @@ import java.util.SortedMap;
 import java.util.StringTokenizer;
 import java.util.TreeMap;
 
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.exp.Expression;
-import org.apache.cayenne.exp.ExpressionException;
-import org.apache.cayenne.util.CayenneMapEntry;
-import org.apache.cayenne.util.ToStringBuilder;
-import org.apache.cayenne.util.XMLSerializable;
-
 /**
  * An Entity is an abstract descriptor for an entity mapping concept. Entity can represent
  * either a descriptor of database table or a persistent object.
@@ -164,6 +164,15 @@ public abstract class Entity implements CayenneMapEntry, XMLSerializable, Serial
         attributes.remove(attrName);
     }
 
+    /**
+     *
+     * @since 4.0
+     */
+    public void updateAttribute(Attribute attribute) {
+        removeAttribute(attribute.getName());
+        addAttribute(attribute);
+    }
+
     public void clearAttributes() {
         attributes.clear();
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ProjectController.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ProjectController.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ProjectController.java
index 4d75685..fc805c8 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ProjectController.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ProjectController.java
@@ -121,8 +121,10 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.EventListener;
 import java.util.EventObject;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 import java.util.Vector;
 import java.util.prefs.Preferences;
 
@@ -1779,7 +1781,7 @@ public class ProjectController extends CayenneController {
     	
     }
 
-    public ArrayList<Embeddable> getEmbeddableNamesInCurRentDataDomain() {
+    public ArrayList<Embeddable> getEmbeddablesInCurrentDataDomain() {
         DataChannelDescriptor dataChannelDescriptor = (DataChannelDescriptor) getProject().getRootNode();
         Collection<DataMap> maps = dataChannelDescriptor.getDataMaps();
         Iterator<DataMap> it = maps.iterator();
@@ -1790,6 +1792,15 @@ public class ProjectController extends CayenneController {
         return embs;
     }
 
+    public Set<String> getEmbeddableNamesInCurrentDataDomain() {
+        ArrayList<Embeddable> embs = getEmbeddablesInCurrentDataDomain();
+        Set<String> embNames = new HashSet<>(embs.size());
+        for (Embeddable emb : embs) {
+            embNames.add(emb.getClassName());
+        }
+        return embNames;
+    }
+
     public void updateProjectControllerPreferences() {
         String key = getProject().getConfigurationResource() == null ? new String(IDUtil.pseudoUniqueByteSequence16())
                 : project.getConfigurationResource().getURL().getPath();

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjAttributeInfoDialog.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjAttributeInfoDialog.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjAttributeInfoDialog.java
index eceaa4f..11b4a68 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjAttributeInfoDialog.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjAttributeInfoDialog.java
@@ -18,31 +18,7 @@
  ****************************************************************/
 package org.apache.cayenne.modeler.dialog.objentity;
 
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.awt.event.KeyEvent;
-import java.awt.event.KeyListener;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.JOptionPane;
-import javax.swing.JTable;
-import javax.swing.WindowConstants;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.table.DefaultTableCellRenderer;
-import javax.swing.table.TableColumn;
-import javax.swing.tree.TreePath;
-
 import org.apache.cayenne.configuration.DataChannelDescriptor;
-import org.apache.cayenne.map.Attribute;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.DbRelationship;
@@ -52,7 +28,6 @@ import org.apache.cayenne.map.EmbeddedAttribute;
 import org.apache.cayenne.map.Entity;
 import org.apache.cayenne.map.ObjAttribute;
 import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.Relationship;
 import org.apache.cayenne.map.event.AttributeEvent;
 import org.apache.cayenne.map.event.EntityEvent;
 import org.apache.cayenne.map.event.MapEvent;
@@ -61,12 +36,34 @@ import org.apache.cayenne.modeler.editor.ObjAttributeTableModel;
 import org.apache.cayenne.modeler.event.AttributeDisplayEvent;
 import org.apache.cayenne.modeler.event.EntityDisplayEvent;
 import org.apache.cayenne.modeler.util.CayenneController;
-import org.apache.cayenne.modeler.util.EntityTreeFilter;
+import org.apache.cayenne.modeler.util.EntityTreeAttributeRelationshipFilter;
 import org.apache.cayenne.modeler.util.EntityTreeModel;
 import org.apache.cayenne.modeler.util.ModelerUtil;
 import org.apache.cayenne.swing.BindingBuilder;
 import org.apache.cayenne.util.CayenneMapEntry;
 
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JOptionPane;
+import javax.swing.JTable;
+import javax.swing.WindowConstants;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableColumn;
+import javax.swing.tree.TreePath;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
 public class ObjAttributeInfoDialog extends CayenneController implements TreeSelectionListener {
 
 	private ObjAttributeTableModel model;
@@ -95,9 +92,9 @@ public class ObjAttributeInfoDialog extends CayenneController implements TreeSel
 		this.stringToEmbeddables = new HashMap<>();
 		this.embeddableNames = new ArrayList<String>();
 
-		Iterator<Embeddable> embs = mediator.getEmbeddableNamesInCurRentDataDomain().iterator();
+		Iterator<Embeddable> embs = mediator.getEmbeddablesInCurrentDataDomain().iterator();
 		while (embs.hasNext()) {
-			Embeddable emb = (Embeddable) embs.next();
+			Embeddable emb = embs.next();
 			stringToEmbeddables.put(emb.getClassName(), emb);
 			embeddableNames.add(emb.getClassName());
 		}
@@ -194,28 +191,7 @@ public class ObjAttributeInfoDialog extends CayenneController implements TreeSel
 
 			if (firstEntity != null) {
 				EntityTreeModel treeModel = new EntityTreeModel(firstEntity);
-				treeModel.setFilter(new 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);
-					}
-				});
+				treeModel.setFilter(new EntityTreeAttributeRelationshipFilter());
 				view.getPathBrowser().setModel(treeModel);
 			}
 		}
@@ -342,12 +318,11 @@ public class ObjAttributeInfoDialog extends CayenneController implements TreeSel
 		}
 		if (embeddableNames.contains(typeName)) {
 
-			Collection<EmbeddableAttribute> embAttrTemp = ((Embeddable) stringToEmbeddables.get(typeName))
-					.getAttributes();
+			Collection<EmbeddableAttribute> embAttrTemp = stringToEmbeddables.get(typeName).getAttributes();
 			Iterator<EmbeddableAttribute> it = embAttrTemp.iterator();
 
 			while (it.hasNext()) {
-				EmbeddableAttribute temp = (EmbeddableAttribute) it.next();
+				EmbeddableAttribute temp = it.next();
 				EmbeddableAttribute at = new EmbeddableAttribute();
 				at.setDbAttributeName(temp.getDbAttributeName());
 				at.setName(temp.getName());
@@ -387,7 +362,7 @@ public class ObjAttributeInfoDialog extends CayenneController implements TreeSel
 
 			StringBuilder attributePath = new StringBuilder();
 			StringBuilder pathStr = new StringBuilder();
-			if (((ObjEntity) attribute.getEntity()).getDbEntity() != null) {
+			if (attribute.getEntity().getDbEntity() != null) {
 				TreePath path = view.getPathBrowser().getSelectionPath();
 
 				if (path.getLastPathComponent() instanceof DbAttribute) {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjAttributeInfoDialogView.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjAttributeInfoDialogView.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjAttributeInfoDialogView.java
index 3a7641e..e826f79 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjAttributeInfoDialogView.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjAttributeInfoDialogView.java
@@ -18,26 +18,10 @@
  ****************************************************************/
 package org.apache.cayenne.modeler.dialog.objentity;
 
-import java.awt.BorderLayout;
-import java.awt.CardLayout;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ComponentEvent;
-import java.awt.event.ComponentListener;
-import java.util.ArrayList;
-import java.util.Iterator;
-
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextField;
-
-import org.apache.cayenne.map.Embeddable;
+import com.jgoodies.forms.builder.PanelBuilder;
+import com.jgoodies.forms.layout.CellConstraints;
+import com.jgoodies.forms.layout.FormLayout;
+import com.jgoodies.forms.layout.RowSpec;
 import org.apache.cayenne.modeler.Application;
 import org.apache.cayenne.modeler.ProjectController;
 import org.apache.cayenne.modeler.pref.TableColumnPreferences;
@@ -47,10 +31,21 @@ import org.apache.cayenne.modeler.util.MultiColumnBrowser;
 import org.apache.cayenne.modeler.util.PanelFactory;
 import org.apache.cayenne.modeler.util.combo.AutoCompletion;
 
-import com.jgoodies.forms.builder.PanelBuilder;
-import com.jgoodies.forms.layout.CellConstraints;
-import com.jgoodies.forms.layout.FormLayout;
-import com.jgoodies.forms.layout.RowSpec;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
 
 public class ObjAttributeInfoDialogView extends JDialog {
 
@@ -209,13 +204,7 @@ public class ObjAttributeInfoDialogView extends JDialog {
                     }
                 }
 
-                Iterator<Embeddable> embs = mediator.getEmbeddableNamesInCurRentDataDomain().iterator();
-                ArrayList<String> embNames = new ArrayList<String>();
-                while (embs.hasNext()) {
-                    embNames.add(embs.next().getClassName());
-                }
-
-                if (isType || !embNames.contains(typeComboBox.getSelectedItem())) {
+                if (isType || !mediator.getEmbeddableNamesInCurrentDataDomain().contains(typeComboBox.getSelectedItem())) {
                     ((CardLayout) typeManagerPane.getLayout()).show(typeManagerPane, FLATTENED_PANEL);
                 } else {
                     ((CardLayout) typeManagerPane.getLayout()).show(typeManagerPane, EMBEDDABLE_PANEL);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfo.java
----------------------------------------------------------------------
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 caf6ed5..d7b0317 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,23 +18,7 @@
  ****************************************************************/
 package org.apache.cayenne.modeler.dialog.objentity;
 
-import java.awt.Component;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Vector;
-
-import javax.swing.JOptionPane;
-import javax.swing.WindowConstants;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.tree.TreePath;
-
 import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.map.Attribute;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.DbRelationship;
 import org.apache.cayenne.map.Entity;
@@ -49,10 +33,29 @@ 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.util.*;
+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.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Vector;
+
 public class ObjRelationshipInfo extends CayenneController implements TreeSelectionListener {
 
     static final String COLLECTION_TYPE_MAP = "java.util.Map";
@@ -182,27 +185,7 @@ public class ObjRelationshipInfo extends CayenneController implements TreeSelect
 
         if (view.pathBrowser.getModel() == null) {
             EntityTreeModel treeModel = new EntityTreeModel(getStartEntity());
-            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);
-                }
-
-            });
+            treeModel.setFilter(new EntityTreeRelationshipFilter());
 
             view.pathBrowser.setModel(treeModel);
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjAttributeTableModel.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjAttributeTableModel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjAttributeTableModel.java
index 0cee45a..8ea39c1 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjAttributeTableModel.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjAttributeTableModel.java
@@ -19,27 +19,13 @@
 
 package org.apache.cayenne.modeler.editor;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.swing.DefaultCellEditor;
-import javax.swing.JComboBox;
-
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.configuration.DataChannelDescriptor;
 import org.apache.cayenne.dba.TypesMapping;
 import org.apache.cayenne.map.Attribute;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.Embeddable;
 import org.apache.cayenne.map.EmbeddedAttribute;
-import org.apache.cayenne.map.Entity;
 import org.apache.cayenne.map.ObjAttribute;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.event.AttributeEvent;
@@ -54,8 +40,16 @@ import org.apache.cayenne.modeler.util.CayenneTable;
 import org.apache.cayenne.modeler.util.CayenneTableModel;
 import org.apache.cayenne.modeler.util.CellEditorForAttributeTable;
 import org.apache.cayenne.modeler.util.ModelerUtil;
+import org.apache.cayenne.modeler.util.ProjectUtil;
 import org.apache.cayenne.util.Util;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
 /**
  * Model for the Object Entity attributes and for Obj to DB Attribute Mapping tables.
  * Allows adding/removing attributes, modifying the types and the names.
@@ -71,21 +65,12 @@ public class ObjAttributeTableModel extends CayenneTableModel<ObjAttributeWrappe
     public static final int DB_ATTRIBUTE_TYPE = 4;
     public static final int LOCKING = 5;
 
-    protected ObjEntity entity;
-    protected DbEntity dbEntity;
+    private ObjEntity entity;
+    private DbEntity dbEntity;
     private CellEditorForAttributeTable cellEditor;
     private CayenneTable table;
 
-    private static List<ObjAttributeWrapper> wrapObjAttributes(Collection<ObjAttribute> attributes) {
-        List<ObjAttributeWrapper>  wrappedAttributes = new ArrayList<ObjAttributeWrapper>();
-        for(ObjAttribute attr : attributes) {
-            wrappedAttributes.add(new ObjAttributeWrapper(attr));
-        }
-        return wrappedAttributes;
-    }
-
-    public ObjAttributeTableModel(ObjEntity entity, ProjectController mediator,
-            Object eventSource) {
+    public ObjAttributeTableModel(ObjEntity entity, ProjectController mediator, Object eventSource) {
         super(mediator, eventSource, wrapObjAttributes(entity.getAttributes()));
         // take a copy
         this.entity = entity;
@@ -94,6 +79,14 @@ public class ObjAttributeTableModel extends CayenneTableModel<ObjAttributeWrappe
         // order using local comparator
         Collections.sort(objectList, new AttributeComparator());
     }
+
+    private static List<ObjAttributeWrapper> wrapObjAttributes(Collection<ObjAttribute> attributes) {
+        List<ObjAttributeWrapper>  wrappedAttributes = new ArrayList<ObjAttributeWrapper>();
+        for(ObjAttribute attr : attributes) {
+            wrappedAttributes.add(new ObjAttributeWrapper(attr));
+        }
+        return wrappedAttributes;
+    }
     
     protected void orderList() {
         // NOOP
@@ -204,16 +197,14 @@ public class ObjAttributeTableModel extends CayenneTableModel<ObjAttributeWrappe
 
     private String getDBAttribute(ObjAttributeWrapper attribute, DbAttribute dbAttribute) {
         if (dbAttribute == null) {
-            if (!attribute.isInherited()
-                    && ((ObjEntity) attribute.getEntity()).isAbstract()) {
+            if (!attribute.isInherited() && attribute.getEntity().isAbstract()) {
                 return attribute.getDbAttributePath();
             }
             else {
                 return null;
             }
         }
-        else if (attribute.getDbAttributePath() != null
-                && attribute.getDbAttributePath().contains(".")) {
+        else if (attribute.getDbAttributePath() != null && attribute.getDbAttributePath().contains(".")) {
             return attribute.getDbAttributePath();
         }
         return dbAttribute.getName();
@@ -282,186 +273,115 @@ public class ObjAttributeTableModel extends CayenneTableModel<ObjAttributeWrappe
         return true;
     }
 
-    @Override
-    public void setUpdatedValueAt(Object value, int row, int column) {
-        ObjAttributeWrapper attribute = getAttribute(row);
-        attribute.resetEdits();
-        AttributeEvent event = new AttributeEvent(eventSource, attribute.getValue(), entity);
-        String path = null;
-        Collection<String> nameAttr = null;
+    private void setObjAttribute(ObjAttributeWrapper attribute, Object value) {
+        attribute.setName(value != null ? value.toString().trim() : null);
+        if (attribute.isValid()) {
+            attribute.commitEdits();
+        }
+    }
 
-        if (column == OBJ_ATTRIBUTE) {
-            event.setOldName(attribute.getName());
+    private void setObjAttributeType(ObjAttributeWrapper attribute, Object value) {
+        String oldType = attribute.getType();
+        String newType = value != null ? value.toString() : null;
 
-            attribute.setName(value != null ? value.toString().trim() : null);
+        attribute.setType(newType);
+        if (oldType == null || newType == null) {
+            return;
+        }
 
-            if (attribute.isValid()) {
-                attribute.commitEdits();
-            }
-            fireTableCellUpdated(row, column);
+        String[] registeredTypes = ModelerUtil.getRegisteredTypeNames();
+        Collection<String> registeredTypesList = Arrays.asList(registeredTypes);
+        if (registeredTypesList.contains(oldType) == registeredTypesList.contains(newType)) {
+            return;
         }
-        else if (column == OBJ_ATTRIBUTE_TYPE) {
-            String oldType = attribute.getType();
-            attribute.setType(value != null ? value.toString() : null);
-            String newType = attribute.getType();
-            String[] registeredTypes = ModelerUtil.getRegisteredTypeNames();
-            Collection<String> registeredTypesList = Arrays.asList(registeredTypes);
-
-            if (oldType != null
-                    && newType != null
-                    && !(registeredTypesList.contains(oldType) == registeredTypesList
-                            .contains(newType))) {
-                ObjAttribute attributeNew;
-
-                ArrayList<Embeddable> embs = mediator
-                        .getEmbeddableNamesInCurRentDataDomain();
-                ArrayList<String> embNames = new ArrayList<String>();
-                Iterator<Embeddable> it = embs.iterator();
-                while (it.hasNext()) {
-                    embNames.add(it.next().getClassName());
-                }
 
-                if (registeredTypesList.contains(newType) || !embNames.contains(newType)) {
-                    attributeNew = new ObjAttribute();
-                }
-                else {
-                    attributeNew = new EmbeddedAttribute();
-                    attribute.setDbAttributePath(null);
-                }
+        ObjEntity entity = attribute.getEntity();
 
-                attributeNew.setDbAttributePath(attribute.getDbAttributePath());
-                attributeNew.setName(attribute.getName());
-                attributeNew.setEntity(attribute.getEntity());
-                attributeNew.setParent(attribute.getParent());
-                attributeNew.setType(attribute.getType());
-                attributeNew.setUsedForLocking(attribute.isUsedForLocking());
-                Entity ent = attribute.getEntity();
-                ent.removeAttribute(attribute.getName());
-                ent.addAttribute(attributeNew);
-
-                mediator.fireObjEntityEvent(new EntityEvent(this, ent, MapEvent.CHANGE));
-
-                EntityDisplayEvent ev = new EntityDisplayEvent(
-                        this,
-                        mediator.getCurrentObjEntity(),
-                        mediator.getCurrentDataMap(),
-                        (DataChannelDescriptor) mediator.getProject().getRootNode());
-
-                mediator.fireObjEntityDisplayEvent(ev);
-
-                mediator.fireObjAttributeEvent(new AttributeEvent(
-                        this,
-                        attributeNew,
-                        ent,
-                        MapEvent.CHANGE));
-
-                AttributeDisplayEvent eventAttr = new AttributeDisplayEvent(
-                        this,
-                        attributeNew,
-                        mediator.getCurrentObjEntity(),
-                        mediator.getCurrentDataMap(),
-                        (DataChannelDescriptor) mediator.getProject().getRootNode());
-
-                mediator.fireObjAttributeDisplayEvent(eventAttr);
-            }
-
-            fireTableCellUpdated(row, column);
+        ObjAttribute attributeNew;
+        if (registeredTypesList.contains(newType) ||
+                !mediator.getEmbeddableNamesInCurrentDataDomain().contains(newType)) {
+            attributeNew = new ObjAttribute();
+            attributeNew.setDbAttributePath(attribute.getDbAttributePath());
+        } else {
+            attributeNew = new EmbeddedAttribute();
+            attributeNew.setDbAttributePath(null);
         }
-        else if (column == LOCKING) {
-            attribute.setUsedForLocking((value instanceof Boolean)
-                    && ((Boolean) value).booleanValue());
-            fireTableCellUpdated(row, column);
-        }
-        else {
-            if (column == DB_ATTRIBUTE) {
 
-                // If db attrib exist, associate it with obj attribute
-                if (value != null) {
-                    path = value.toString();
-
-                    String[] pathSplit = path.split("\\.");
-
-                    // If flattened attribute
-                    if (pathSplit.length > 1) {
-
-                        DbEntity currentEnt = dbEntity;
-                        StringBuilder pathBuf = new StringBuilder();
-                        boolean isTruePath = true;
-
-                        if (dbEntity != null) {
-
-                            nameAttr = ModelerUtil
-                                    .getDbAttributeNames(mediator, dbEntity);
-
-                            for (int j = 0; j < pathSplit.length; j++) {
-
-                                if (j == pathSplit.length - 1 && isTruePath) {
-                                    DbAttribute dbAttribute = (DbAttribute) currentEnt
-                                            .getAttribute(pathSplit[j]);
-                                    if (dbAttribute != null) {
-                                        pathBuf.append(dbAttribute.getName());
-                                    }
-                                    else {
-                                        isTruePath = false;
-                                    }
-                                }
-                                else if (isTruePath) {
-                                    DbRelationship dbRelationship = (DbRelationship) currentEnt
-                                            .getRelationship(pathSplit[j]);
-                                    if (dbRelationship != null) {
-                                        currentEnt = (DbEntity) dbRelationship
-                                                .getTargetEntity();
-                                        pathBuf.append(dbRelationship.getName());
-                                        pathBuf.append(".");
-                                    }
-                                    else {
-                                        isTruePath = false;
-                                    }
-                                }
-                            }
-                        }
-                        path = isTruePath ? pathBuf.toString() : null;
-
-                    }
-                    else {
-
-                        if (dbEntity != null) {
-                            DbAttribute dbAttribute = (DbAttribute) dbEntity
-                                    .getAttribute(value.toString());
-                            path = dbAttribute != null ? dbAttribute.getName() : null;
-                        }
-                    }
-                    attribute.setDbAttributePath(path);
+        attributeNew.setName(attribute.getName());
+        attributeNew.setEntity(entity);
+        attributeNew.setParent(attribute.getParent());
+        attributeNew.setType(attribute.getType());
+        attributeNew.setUsedForLocking(attribute.isUsedForLocking());
+
+        entity.updateAttribute(attributeNew);
+
+        mediator.fireObjEntityEvent(new EntityEvent(this, entity, MapEvent.CHANGE));
+
+        mediator.fireObjEntityDisplayEvent(new EntityDisplayEvent(
+                this,
+                mediator.getCurrentObjEntity(),
+                mediator.getCurrentDataMap(),
+                (DataChannelDescriptor) mediator.getProject().getRootNode()));
+
+        mediator.fireObjAttributeEvent(new AttributeEvent(
+                this,
+                attributeNew,
+                entity,
+                MapEvent.CHANGE));
+
+        mediator.fireObjAttributeDisplayEvent(new AttributeDisplayEvent(
+                this,
+                attributeNew,
+                mediator.getCurrentObjEntity(),
+                mediator.getCurrentDataMap(),
+                (DataChannelDescriptor) mediator.getProject().getRootNode()));
+    }
 
-                }
-                // If name is erased, remove db attribute from obj attribute.
-                else if (attribute.getDbAttribute() != null) {
-                    attribute.setDbAttributePath(null);
-                }
+    private void setColumnLocking(ObjAttributeWrapper attribute, Object value) {
+        attribute.setUsedForLocking((value instanceof Boolean)
+                && ((Boolean) value).booleanValue());
+    }
+
+    private void setDbAttribute(ObjAttributeWrapper attribute, Object value) {
+
+        // If db attribute exist, associate it with obj attribute
+        if (value != null) {
+
+            if (ProjectUtil.isDbAttributePathCorrect(dbEntity,value.toString())) {
+                attribute.setDbAttributePath(value.toString());
+            } else {
+                attribute.setDbAttributePath(null);
             }
-            fireTableRowsUpdated(row, row);
         }
-        mediator.fireObjAttributeEvent(event);
+        // If name is erased, remove db attribute from obj attribute.
+        else if (attribute.getDbAttribute() != null) {
+            attribute.setDbAttributePath(null);
+        }
     }
 
-    public void setComboBoxes(Collection<String> nameAttr, int column) {
-        int count = getRowCount();
-        for (int i = 0; i < count; i++) {
-            if (getAttribute(i).getDbAttributePath() != null
-                    && getAttribute(i).getDbAttributePath().contains(".")) {
-                Collection<String> attributeComboForRow = new ArrayList<String>();
-                attributeComboForRow.addAll(nameAttr);
-                attributeComboForRow.add(getAttribute(i).getDbAttributePath());
-                JComboBox comboBoxForRow = Application.getWidgetFactory().createComboBox(
-                        attributeComboForRow,
-                        true);
-
-                cellEditor.setEditorAt(new Integer(i), new DefaultCellEditor(
-                        comboBoxForRow));
+    @Override
+    public void setUpdatedValueAt(Object value, int row, int column) {
+        ObjAttributeWrapper attribute = getAttribute(row);
+        attribute.resetEdits();
+        AttributeEvent event = new AttributeEvent(eventSource, attribute.getValue(), entity);
 
+        if (column == OBJ_ATTRIBUTE) {
+            event.setOldName(attribute.getName());
+            setObjAttribute(attribute, value);
+            fireTableCellUpdated(row, column);
+        } else if (column == OBJ_ATTRIBUTE_TYPE) {
+            setObjAttributeType(attribute, value);
+            fireTableCellUpdated(row, column);
+        } else if (column == LOCKING) {
+            setColumnLocking(attribute, value);
+            fireTableCellUpdated(row, column);
+        } else {
+            if (column == DB_ATTRIBUTE) {
+                setDbAttribute(attribute, value);
             }
+            fireTableRowsUpdated(row, row);
         }
-        table.getColumnModel().getColumn(column).setCellEditor(cellEditor);
+        mediator.fireObjAttributeEvent(event);
     }
 
     public boolean isCellEditable(int row, int col) {
@@ -511,57 +431,69 @@ public class ObjAttributeTableModel extends CayenneTableModel<ObjAttributeWrappe
                 break;
             case DB_ATTRIBUTE:
             case DB_ATTRIBUTE_TYPE:
-                Collections.sort(objectList, new Comparator<ObjAttributeWrapper>() {
-
-                    public int compare(ObjAttributeWrapper o1, ObjAttributeWrapper o2) {
-                        Integer compareObjAttributesVal = compareObjAttributes(o1, o2);
-                        if (compareObjAttributesVal != null) {
-                            return compareObjAttributesVal;
-                        }
-
-                        String valToCompare1 = getDBAttribute(o1, o1.getDbAttribute());
-                        String valToCompare2 = getDBAttribute(o2, o2.getDbAttribute());
-                        switch (sortCol) {
-                            case DB_ATTRIBUTE:
-                                valToCompare1 = getDBAttribute(o1, o1.getDbAttribute());
-                                valToCompare2 = getDBAttribute(o2, o2.getDbAttribute());
-                                break;
-                            case DB_ATTRIBUTE_TYPE:
-                                valToCompare1 = getDBAttributeType(o1, o1
-                                        .getDbAttribute());
-                                valToCompare2 = getDBAttributeType(o2, o2
-                                        .getDbAttribute());
-                                break;
-                        }
-                        return (valToCompare1 == null) ? -1 : (valToCompare2 == null)
-                                ? 1
-                                : valToCompare1.compareTo(valToCompare2);
-                    }
-
-                });
+                Collections.sort(objectList, new ObjAttributeTableComparator(sortCol));
                 if (!isAscent) {
                     Collections.reverse(objectList);
                 }
                 break;
+            default:
+                return;
+        }
+    }
+
+    private class ObjAttributeTableComparator implements Comparator<ObjAttributeWrapper>{
+
+        private int sortCol;
+
+        public ObjAttributeTableComparator(int sortCol) {
+            this.sortCol = sortCol;
+        }
 
+        @Override
+        public int compare(ObjAttributeWrapper o1, ObjAttributeWrapper o2) {
+            Integer compareObjAttributesVal = compareObjAttributes(o1, o2);
+            if (compareObjAttributesVal != null) {
+                return compareObjAttributesVal;
+            }
+            String valToCompare1 = getDBAttribute(o1, o1.getDbAttribute());
+            String valToCompare2 = getDBAttribute(o2, o2.getDbAttribute());
+            switch (sortCol) {
+                case DB_ATTRIBUTE:
+                    valToCompare1 = getDBAttribute(o1, o1.getDbAttribute());
+                    valToCompare2 = getDBAttribute(o2, o2.getDbAttribute());
+                    break;
+                case DB_ATTRIBUTE_TYPE:
+                    valToCompare1 = getDBAttributeType(o1, o1
+                            .getDbAttribute());
+                    valToCompare2 = getDBAttributeType(o2, o2
+                            .getDbAttribute());
+                    break;
+                default:
+                    break;
+            }
+            return (valToCompare1 == null) ? -1 : (valToCompare2 == null)
+                    ? 1
+                    : valToCompare1.compareTo(valToCompare2);
+        }
+
+        private Integer compareObjAttributes(ObjAttributeWrapper o1, ObjAttributeWrapper 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;
+            }
+            return null;
         }
     }
 
+
     @Override
     public boolean isColumnSortable(int sortCol) {
         return true;
     }
 
-    private Integer compareObjAttributes(ObjAttributeWrapper o1, ObjAttributeWrapper 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;
-        }
-        return null;
-    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityAttributePanel.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityAttributePanel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityAttributePanel.java
index d3496e8..46c4215 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityAttributePanel.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityAttributePanel.java
@@ -19,16 +19,11 @@
 package org.apache.cayenne.modeler.editor;
 
 import org.apache.cayenne.configuration.DataChannelDescriptor;
-import org.apache.cayenne.map.Attribute;
 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.Embeddable;
-import org.apache.cayenne.map.Entity;
 import org.apache.cayenne.map.ObjAttribute;
 import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.Relationship;
 import org.apache.cayenne.map.event.AttributeEvent;
 import org.apache.cayenne.map.event.EntityEvent;
 import org.apache.cayenne.map.event.ObjAttributeListener;
@@ -50,50 +45,38 @@ 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.CayenneTableModel;
-import org.apache.cayenne.modeler.util.EntityTreeFilter;
-import org.apache.cayenne.modeler.util.EntityTreeModel;
+import org.apache.cayenne.modeler.util.DbAttributePathComboBoxEditor;
 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.cayenne.util.CayenneMapEntry;
-import org.apache.commons.lang.StringUtils;
 
-import javax.swing.AbstractCellEditor;
-import javax.swing.DefaultComboBoxModel;
 import javax.swing.Icon;
 import javax.swing.ImageIcon;
 import javax.swing.JComboBox;
 import javax.swing.JLabel;
-import javax.swing.JList;
 import javax.swing.JMenuItem;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.JTable;
-import javax.swing.ListCellRenderer;
 import javax.swing.ListSelectionModel;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
 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.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.regex.Pattern;
 
 /**
  * Detail view of the ObjEntity attributes.
@@ -101,8 +84,8 @@ import java.util.regex.Pattern;
 public class ObjEntityAttributePanel extends JPanel implements ObjEntityDisplayListener,
         ObjEntityListener, ObjAttributeListener, ProjectOnSaveListener {
 
-    protected ProjectController mediator;
-    protected CayenneTable table;
+    private ProjectController mediator;
+    private CayenneTable table;
     private TableColumnPreferences tablePreferences;
     private ObjEntityAttributeRelationshipTab parentPanel;
     private boolean enabledResolve;//for JBottom "resolve" in ObjEntityAttrRelationshipTab
@@ -113,7 +96,7 @@ public class ObjEntityAttributePanel extends JPanel implements ObjEntityDisplayL
      * 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 ObjEntityAttributePanel(ProjectController mediator, ObjEntityAttributeRelationshipTab parentPanel) {
         this.mediator = mediator;
@@ -123,21 +106,20 @@ public class ObjEntityAttributePanel extends JPanel implements ObjEntityDisplayL
         initController();
     }
 
+    public CayenneTable getTable() {
+        return table;
+    }
+
+    public void setTable(CayenneTable table) {
+        this.table = table;
+    }
+
     private void initView() {
         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 CellRenderer());
         tablePreferences = new TableColumnPreferences(
                 ObjAttributeTableModel.class,
@@ -203,7 +185,7 @@ public class ObjEntityAttributePanel extends JPanel implements ObjEntityDisplayL
                 CopyAttributeRelationshipAction.class);
     }
 
-    public void initComboBoxes(ObjAttributeTableModel model) {
+    public void initComboBoxes() {
         List<String> embeddableNames = new ArrayList<String>();
         List<String> typeNames = new ArrayList<String>();
 
@@ -212,17 +194,13 @@ public class ObjEntityAttributePanel extends JPanel implements ObjEntityDisplayL
                 .iterator();
         while (it.hasNext()) {
             DataMap dataMap = (DataMap) it.next();
-            Iterator<Embeddable> embs = dataMap.getEmbeddables().iterator();
-            while (embs.hasNext()) {
-                Embeddable emb = embs.next();
+            for (Embeddable emb : dataMap.getEmbeddables()) {
                 embeddableNames.add(emb.getClassName());
             }
         }
 
         String[] registeredTypes = ModelerUtil.getRegisteredTypeNames();
-        for (int i = 0; i < registeredTypes.length; i++) {
-            typeNames.add(registeredTypes[i]);
-        }
+        Collections.addAll(typeNames, registeredTypes);
         typeNames.addAll(embeddableNames);
 
         TableColumn typeColumn = table.getColumnModel().getColumn(
@@ -352,10 +330,10 @@ public class ObjEntityAttributePanel extends JPanel implements ObjEntityDisplayL
         table.setModel(model);
         table.setRowHeight(25);
         table.setRowMargin(3);
-        setUpTableStructure(model);
+        setUpTableStructure();
     }
 
-    protected void setUpTableStructure(ObjAttributeTableModel model) {
+    protected void setUpTableStructure() {
         int inheritanceColumnWidth = 30;
 
         Map<Integer, Integer> minSizes = new HashMap<Integer, Integer>();
@@ -364,10 +342,10 @@ public class ObjEntityAttributePanel extends JPanel implements ObjEntityDisplayL
         minSizes.put(ObjAttributeTableModel.INHERITED, inheritanceColumnWidth);
         maxSizes.put(ObjAttributeTableModel.INHERITED, inheritanceColumnWidth);
 
-        initComboBoxes(model);
+        initComboBoxes();
 
         table.getColumnModel().getColumn(3).setCellRenderer(new JTableDbAttributeComboBoxRenderer());
-        table.getColumnModel().getColumn(3).setCellEditor(new JTableDbAttributeComboBoxEditor());
+        table.getColumnModel().getColumn(3).setCellEditor(new DbAttributePathComboBoxEditor());
 
         tablePreferences.bind(
                 table,
@@ -394,7 +372,7 @@ public class ObjEntityAttributePanel extends JPanel implements ObjEntityDisplayL
         ObjAttributeTableModel model = (ObjAttributeTableModel) table.getModel();
         if (model.getDbEntity() != ((ObjEntity) e.getEntity()).getDbEntity()) {
             model.resetDbEntity();
-            setUpTableStructure(model);
+            setUpTableStructure();
         }
     }
 
@@ -479,9 +457,10 @@ public class ObjEntityAttributePanel extends JPanel implements ObjEntityDisplayL
 
             if (!e.getValueIsAdjusting() && !((ListSelectionModel) e.getSource()).isSelectionEmpty()) {
 
-                parentPanel.getRelationshipPanel().table.getSelectionModel().clearSelection();
-                if (parentPanel.getRelationshipPanel().table.getCellEditor() != null)
-                    parentPanel.getRelationshipPanel().table.getCellEditor().stopCellEditing();
+                parentPanel.getRelationshipPanel().getTable().getSelectionModel().clearSelection();
+                if (parentPanel.getRelationshipPanel().getTable().getCellEditor() != null) {
+                    parentPanel.getRelationshipPanel().getTable().getCellEditor().stopCellEditing();
+                }
                 Application.getInstance().getActionManager().getAction(RemoveAttributeRelationshipAction.class).setCurrentSelectedPanel(parentPanel.getAttributePanel());
                 Application.getInstance().getActionManager().getAction(CutAttributeRelationshipAction.class).setCurrentSelectedPanel(parentPanel.getAttributePanel());
                 Application.getInstance().getActionManager().getAction(CopyAttributeRelationshipAction.class).setCurrentSelectedPanel(parentPanel.getAttributePanel());
@@ -534,326 +513,16 @@ public class ObjEntityAttributePanel extends JPanel implements ObjEntityDisplayL
         @Override
         public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                                                        boolean hasFocus, int row, int column) {
-            if (value instanceof DbAttribute){
-                JLabel jLabel = new  JLabel(ModelerUtil.getObjectName(value));
-                jLabel.setFont(new Font("Verdana", Font.PLAIN , 12));
-                return jLabel;
-            }
-            if (value !=null){
-                JLabel jLabel = new JLabel(value.toString());
-                jLabel.setFont(new Font("Verdana", Font.PLAIN , 12));
-                return jLabel;
-            }
-            return new JLabel("");
-        }
-    }
-
-    private final static class JTableDbAttributeComboBoxEditor extends AbstractCellEditor implements TableCellEditor {
-
-        private int row;
-        private int column;
-        private JComboBox dbAttributePathCombo;
-        private EntityTreeModel treeModel;
-        private int previousEmbededLevel = 0;
-        private ObjAttributeTableModel model;
-
-        private JTableDbAttributeComboBoxEditor() {
-        }
-
-        @Override
-        public Object getCellEditorValue() {
-             return model.getValueAt(row,column);
-        }
+            JLabel jLabel = new JLabel("");
+            jLabel.setFont(new Font("Verdana", Font.PLAIN , 12));
 
-        @Override
-        public Component getTableCellEditorComponent(final JTable table, Object o, boolean b, int i, int i1) {
-            this.model = (ObjAttributeTableModel) table.getModel();
-            row = i;
-            column = i1;
-            treeModel = createTreeModelForComboBoxBrowser(row);
-            if (treeModel == null)
-                return new JLabel("You need select table to this ObjectEntity");
-            initializeCombo(model , row);
-
-            String dbAttributePath = ((JTextComponent) (dbAttributePathCombo).
-                    getEditor().getEditorComponent()).getText();
-            previousEmbededLevel =  StringUtils.countMatches(dbAttributePath,".");
-
-            dbAttributePathCombo.getEditor().getEditorComponent().addKeyListener(new KeyAdapter() {
-                private void enterPressed(){
-                    String dbAttributePath = ((JTextComponent) (dbAttributePathCombo).
-                            getEditor().getEditorComponent()).getText();
-                    Object currentNode = getCurrentNode(dbAttributePath);
-                    if (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, column);
-                        }
-                    }else if (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 + ".";
-                            previousEmbededLevel =  StringUtils.countMatches(dbAttributePath,".");
-                            ((JTextComponent) (dbAttributePathCombo).
-                                    getEditor().getEditorComponent()).setText(dbAttributePath);
-                        }
-                        List<String> currentNodeChildren = new ArrayList<>();
-                        currentNodeChildren.add(dbAttributePath + "");
-                        currentNodeChildren.addAll(getChildren(getCurrentNode(dbAttributePath), dbAttributePath));
-                        dbAttributePathCombo.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
-                        dbAttributePathCombo.showPopup();
-                        dbAttributePathCombo.setPopupVisible(true);
-                    }
-                }
-
-                @Override
-                public void keyReleased(KeyEvent event) {
-                    if(event.getKeyCode() == KeyEvent.VK_ENTER){
-                        enterPressed();
-                        return;
-                    }
-                    parseDbAttributeString(event.getKeyChar());
-                }
-            });
-            return dbAttributePathCombo;
-        }
-
-        private void initializeCombo(ObjAttributeTableModel model , int row){
-            String dbAttributePath = model.getAttribute(row).getValue().getDbAttributePath();
-            Object currentNode;
-            if (dbAttributePath == null){
-                //case if it is new attribute or for some reason dbAttributePath is null
-                currentNode = getCurrentNode(dbAttributePath);
-                dbAttributePath = "";
-
-            }else{
-                //case if  dbAttributePath isn't null and we must change it to find auto completion list
-                String[] pathStrings = dbAttributePath.split(Pattern.quote("."));
-                String lastStringInPath = pathStrings[pathStrings.length - 1];
-                dbAttributePath = dbAttributePath.replaceAll(lastStringInPath + "$", "");
-                currentNode = getCurrentNode(dbAttributePath);
-            }
-            List<String> nodeChildren = getChildren(currentNode , dbAttributePath);
-            dbAttributePathCombo = Application.getWidgetFactory().createComboBox(
-                    nodeChildren,
-                    false);
-            AutoCompletion.enable(dbAttributePathCombo, false, true);
-            ((JTextComponent) (dbAttributePathCombo).
-                    getEditor().getEditorComponent()).setText(model.getAttribute(row).getValue().getDbAttributePath());
-            return;
-        }
-
-        private void parseDbAttributeString(char lastEnteredCharacter){
-            String dbAttributePath = ((JTextComponent) (dbAttributePathCombo).
-                    getEditor().getEditorComponent()).getText();
-
-            if (dbAttributePath.equals("")){
-                List<String> currentNodeChildren = new ArrayList<>();
-                currentNodeChildren.add("");
-                currentNodeChildren.addAll(getChildren(getCurrentNode(dbAttributePath),""));
-                dbAttributePathCombo.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
-                dbAttributePathCombo.showPopup();
-                dbAttributePathCombo.setPopupVisible(true);
-                return;
+            if (value instanceof DbAttribute) {
+                jLabel.setText(ModelerUtil.getObjectName(value));
+            } else if (value != null) {
+                jLabel.setText(value.toString());
             }
 
-            if (lastEnteredCharacter == '.') {
-                processDotEntered();
-                return;
-            }
-            int currentEmbededLevel =  StringUtils.countMatches(dbAttributePath,".");
-            if (previousEmbededLevel != currentEmbededLevel){
-                previousEmbededLevel = currentEmbededLevel;
-                List<String> currentNodeChildren = new ArrayList<>();
-                String[] pathStrings = dbAttributePath.split(Pattern.quote("."));
-                String lastStringInPath = pathStrings[pathStrings.length - 1];
-                String saveDbAttributePath = dbAttributePath;
-                dbAttributePath = dbAttributePath.replaceAll(lastStringInPath + "$", "");
-                currentNodeChildren.addAll(getChildren(getCurrentNode(dbAttributePath), dbAttributePath));
-
-                dbAttributePathCombo.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
-                ((JTextComponent) (dbAttributePathCombo).
-                        getEditor().getEditorComponent()).setText(saveDbAttributePath);
-                dbAttributePathCombo.showPopup();
-                dbAttributePathCombo.setPopupVisible(true);
-                return;
-            }
-        }
-
-            private void processDotEntered(){
-            String dbAttributePath = ((JTextComponent) (dbAttributePathCombo).
-                    getEditor().getEditorComponent()).getText();
-            if (dbAttributePath.equals(".")){
-                List<String> currentNodeChildren = new ArrayList<>();
-                currentNodeChildren.add("");
-                currentNodeChildren.addAll(getChildren(getCurrentNode(""),""));
-                dbAttributePathCombo.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
-                dbAttributePathCombo.showPopup();
-                dbAttributePathCombo.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) (dbAttributePathCombo).
-                            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){
-                        //previous root is treeModel.getRoot()
-                        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));
-                        dbAttributePathCombo.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
-                        dbAttributePathCombo.showPopup();
-                        dbAttributePathCombo.setPopupVisible(true);
-                    }else{
-                        ((JTextComponent) (dbAttributePathCombo).
-                                getEditor().getEditorComponent()).setText(dbAttributePath.substring(0,dbAttributePath.length()-1));
-                    }
-                }
-            }
-            previousEmbededLevel =  StringUtils.countMatches(dbAttributePath,".");
-            return;
-        }
-
-        /**
-         * find current node by dbAttributePath
-         * @param dbAttributePath
-         * @return last node in dbAttributePath which matches DbRelationship or DbAttribute
-         */
-        private final Object getCurrentNode(String dbAttributePath) {
-            try {
-                //case for new attribute
-                if(dbAttributePath == null){
-                    return treeModel.getRoot();
-                }
-                String[] pathStrings = dbAttributePath.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);
-                        String objectName = ModelerUtil.getObjectName(child);
-                        if (objectName.equals(rootChildText)) {
-                            root = child;
-                            break;
-                        }
-                    }
-                }
-                return root;
-            }catch (Exception e){
-                return treeModel.getRoot();
-            }
-        }
-
-        /**
-         * @param node for which we will find children
-         * @param dbAttributePath 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 dbAttributePath){
-            List<String> currentNodeChildren = new ArrayList<>();
-            for(int j = 0 ; j <  treeModel.getChildCount(node) ; j++){
-                Object child = treeModel.getChild(node, j);
-                String objectName = ModelerUtil.getObjectName(child);
-                currentNodeChildren.add(dbAttributePath+objectName);
-            }
-            return currentNodeChildren;
-        }
-
-        /**
-         * @param attributeIndexInTable index of attribute for which now we will create cell editor
-         * @return treeModel for nessesary for us attribute
-         */
-        private EntityTreeModel createTreeModelForComboBoxBrowser(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.size() > 0) {
-                            Iterator<DbAttribute> iterator = attributes.iterator();
-                            firstEntity = iterator.next().getEntity();
-                        } else if (rel.size() > 0) {
-                            Iterator<DbRelationship> iterator = rel.iterator();
-                            firstEntity = iterator.next().getSourceEntity();
-                        }
-                    }
-                }
-            } else {
-                firstEntity = getFirstEntity(attribute);
-            }
-
-            if (firstEntity != null) {
-                EntityTreeModel treeModel = new EntityTreeModel(firstEntity);
-                treeModel.setFilter(new 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);
-                    }
-                });
-                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;
+            return jLabel;
         }
     }
-}
+}
\ No newline at end of file


[8/8] cayenne git commit: revert SortButtonRenderer

Posted by sk...@apache.org.
revert SortButtonRenderer


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/9baef19b
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/9baef19b
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/9baef19b

Branch: refs/heads/master
Commit: 9baef19b7b460aecf669a689552d15fc62eb5560
Parents: b444b1d
Author: Savva Kolbachev <s....@gmail.com>
Authored: Mon Dec 7 18:20:50 2015 +0300
Committer: Savva Kolbachev <s....@gmail.com>
Committed: Mon Dec 7 18:27:13 2015 +0300

----------------------------------------------------------------------
 .../modeler/util/SortButtonRenderer.java        | 81 +++++++++++---------
 1 file changed, 46 insertions(+), 35 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/9baef19b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/SortButtonRenderer.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/SortButtonRenderer.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/SortButtonRenderer.java
index 595ba4d..beae1e7 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/SortButtonRenderer.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/SortButtonRenderer.java
@@ -19,32 +19,49 @@
 package org.apache.cayenne.modeler.util;
 
 import javax.swing.BorderFactory;
-import javax.swing.JLabel;
+import javax.swing.JButton;
 import javax.swing.JTable;
-import javax.swing.border.Border;
+import javax.swing.border.MatteBorder;
 import javax.swing.table.TableCellRenderer;
 import java.awt.Color;
 import java.awt.Component;
-import java.awt.Font;
+import java.awt.Insets;
 import java.util.Hashtable;
 
-public class SortButtonRenderer extends JLabel implements TableCellRenderer {
+public class SortButtonRenderer extends JButton implements TableCellRenderer {
 
     public static final int NONE = 0;
     public static final int DOWN = 1;
     public static final int UP = 2;
 
+    private int pushedColumn;
     private Hashtable state;
-    private JLabel downLabel , upLabel;
+    private JButton downButton, upButton;
 
     public SortButtonRenderer() {
+        MatteBorder matteBorder = BorderFactory.createMatteBorder(0, 0, 1, 1, Color.gray);
+        setBorder(matteBorder);
+
+        pushedColumn = -1;
         state = new Hashtable();
 
-        downLabel = new JLabel();
-        downLabel.setIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, false));
+        setMargin(new Insets(0, 0, 0, 0));
+        setHorizontalTextPosition(CENTER);
+        setIcon(new BlankIcon());
+
+        downButton = new JButton();
+
+        downButton.setBorder(matteBorder);
+        downButton.setMargin(new Insets(0, 0, 0, 0));
+        downButton.setHorizontalTextPosition(LEFT);
+        downButton.setIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, false));
+        downButton.setPressedIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, true));
 
-        upLabel = new JLabel();
-        upLabel.setIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, false));
+        upButton = new JButton();
+        upButton.setBorder(matteBorder);
+        upButton.setMargin(new Insets(0, 0, 0, 0));
+        upButton.setHorizontalTextPosition(LEFT);
+        upButton.setIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, false));
     }
 
     public Component getTableCellRendererComponent(
@@ -54,54 +71,48 @@ public class SortButtonRenderer extends JLabel implements TableCellRenderer {
             boolean hasFocus,
             int row,
             int column) {
-        JLabel  label = this;
-        Object obj = state.get(column);
+        JButton button = this;
+        Object obj = state.get(new Integer(column));
 
         if (obj != null) {
-            if ((Integer) obj == DOWN) {
-                label = downLabel;
-            }
-            else {
-                label = upLabel;
+            if (((Integer) obj).intValue() == DOWN) {
+                button = downButton;
+            } else {
+                button = upButton;
             }
         }
-        Border border = BorderFactory.createLineBorder(Color.GRAY, 1);
-        label.setText(' ' + ((value == null) ? "" : value.toString()));
-        label.setFont(new Font("Verdana", Font.BOLD , 13));
-        label.setHorizontalTextPosition(JLabel.LEFT);
-        label.setBorder(border);
-        label.setOpaque(true);
-        label.setBackground(new Color(204, 238, 255));
-        return label;
+        button.setText((value == null) ? "" : value.toString());
+        return button;
+    }
+
+    public void setPressedColumn(int col) {
+        pushedColumn = col;
     }
 
     public void setSelectedColumn(int col, boolean isAscOrder) {
-        if (col < 0) {
+        if (col < 0)
             return;
-        }
         Integer value = null;
         //shows the direction of ordering
         if (isAscOrder) {
-            value = DOWN;
+            value = new Integer(DOWN);
         } else {
-            value = UP;
+            value = new Integer(UP);
         }
 
         state.clear();
-        state.put(col, value);
+        state.put(new Integer(col), value);
     }
 
     public int getState(int col) {
         int retValue;
-        Object obj = state.get(col);
+        Object obj = state.get(new Integer(col));
         if (obj == null) {
             retValue = NONE;
-        }
-        else {
-            if ((Integer) obj == DOWN) {
+        } else {
+            if (((Integer) obj).intValue() == DOWN) {
                 retValue = DOWN;
-            }
-            else {
+            } else {
                 retValue = UP;
             }
         }


[6/8] cayenne git commit: cleanup

Posted by sk...@apache.org.
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


[3/8] cayenne git commit: add auto suggestion DbRelationshipPath . add extra columns relationship table. reason : reduse DatabaseMapping dialog

Posted by sk...@apache.org.
add auto suggestion DbRelationshipPath . add extra columns relationship table. reason : reduse DatabaseMapping dialog


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/8367f77a
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/8367f77a
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/8367f77a

Branch: refs/heads/master
Commit: 8367f77a52c910a2dc56a49668b068edf402e713
Parents: 681a1fa
Author: AlexandrShestak <sh...@mail.ru>
Authored: Tue Nov 24 12:34:32 2015 +0300
Committer: Savva Kolbachev <s....@gmail.com>
Committed: Mon Dec 7 13:21:41 2015 +0300

----------------------------------------------------------------------
 .../editor/ObjEntityRelationshipPanel.java      | 535 ++++++++++++++++++-
 .../editor/ObjRelationshipTableModel.java       |  69 ++-
 2 files changed, 586 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/8367f77a/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 3b557e2..dffd96d 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,10 +18,15 @@
  ****************************************************************/
 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;
@@ -40,13 +45,17 @@ 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.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;
@@ -62,14 +71,22 @@ 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.
@@ -86,6 +103,11 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
             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 TableColumnPreferences tablePreferences;
@@ -94,7 +116,7 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
     private boolean enabledResolve;//for JBottom "resolve" in ObjEntityAttrRelationshipTab
 
     /**
-     * By now popup menu item is made similiar to toolbar button. (i.e. all functionality
+     * 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;
@@ -112,7 +134,16 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
 
         ActionManager actionManager = Application.getInstance().getActionManager();
 
-        table = new CayenneTable();
+        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.setDefaultRenderer(String.class, new StringRenderer());
         table.setDefaultRenderer(ObjEntity.class, new EntityRenderer());
         tablePreferences = new TableColumnPreferences(
@@ -287,7 +318,8 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
 
         JComboBox combo = (JComboBox) editor.getComponent();
         combo.setRenderer(CellRenderers.entityListRendererWithIcons(entity.getDataMap()));
-        combo.setModel(new DefaultComboBoxModel(createObjEntityComboModel()));
+        //combo.setModel(new DefaultComboBoxModel(createObjEntityComboModel()));
+        //combo.setEnabled(false);
 
         ObjRelationshipTableModel model = (ObjRelationshipTableModel) table.getModel();
         model.fireTableDataChanged();
@@ -319,7 +351,7 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
         table.setRowMargin(3);
 
         TableColumn col = table.getColumnModel().getColumn(
-                ObjRelationshipTableModel.REL_TARGET);
+                ObjRelationshipTableModel.REL_TARGET_PATH);
         JComboBox targetCombo = Application.getWidgetFactory().createComboBox(
                 createObjEntityComboModel(),
                 false);
@@ -328,9 +360,9 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
         targetCombo.setRenderer(CellRenderers.entityListRendererWithIcons(entity
                 .getDataMap()));
         targetCombo.setSelectedIndex(-1);
-        col.setCellEditor(Application.getWidgetFactory().createCellEditor(targetCombo));
+        col.setCellEditor(new JTableTargetComboBoxEditor());
 
-        col = table.getColumnModel().getColumn(ObjRelationshipTableModel.REL_DELETERULE);
+        col = table.getColumnModel().getColumn(ObjRelationshipTableModel.REL_DELETE_RULE);
         JComboBox deleteRulesCombo = Application.getWidgetFactory().createComboBox(
                 deleteRules,
                 false);
@@ -339,6 +371,15 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
         col.setCellEditor(Application.getWidgetFactory().createCellEditor(
                 deleteRulesCombo));
 
+        col = table.getColumnModel().getColumn(ObjRelationshipTableModel.REL_COLLECTION_TYPE);
+
+        col.setCellEditor(new JTableCollectionTypeComboBoxEditor());
+        col.setCellRenderer(new JTableCollectionTypeComboBoxRenderer());
+
+        col = table.getColumnModel().getColumn(ObjRelationshipTableModel.REL_MAP_KEY);
+        col.setCellEditor(new JTableMapKeyComboBoxEditor());
+        col.setCellRenderer(new JTableMapKeyComboBoxRenderer());
+
         tablePreferences.bind(
                 table,
                 null,
@@ -469,4 +510,486 @@ public class ObjEntityRelationshipPanel extends JPanel implements ObjEntityDispl
     public ActionListener getResolver() {
         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/8367f77a/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 5dca446..91592f6 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
@@ -39,9 +39,14 @@ public class ObjRelationshipTableModel extends CayenneTableModel {
     // Columns
     static final int REL_NAME = 0;
     static final int REL_TARGET = 1;
-    static final int REL_SEMANTICS = 2;
-    static final int REL_DELETERULE = 3;
-    static final int REL_LOCKING = 4;
+    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;
 
@@ -72,7 +77,7 @@ public class ObjRelationshipTableModel extends CayenneTableModel {
     }
 
     public int getColumnCount() {
-        return 5;
+        return COLUMN_COUNT;
     }
 
     @Override
@@ -86,8 +91,14 @@ public class ObjRelationshipTableModel extends CayenneTableModel {
                 return "Used for Locking";
             case REL_SEMANTICS:
                 return "Semantics";
-            case REL_DELETERULE:
+            case REL_DELETE_RULE:
                 return "Delete Rule";
+            case REL_COLLECTION_TYPE:
+                return "Collection Type";
+            case REL_MAP_KEY:
+                return "Map key";
+            case REL_TARGET_PATH:
+                return "DbRelationshipPath";
 
             default:
                 return null;
@@ -126,8 +137,16 @@ public class ObjRelationshipTableModel extends CayenneTableModel {
         else if (column == REL_SEMANTICS) {
             return getSemantics(relationship);
         }
-        else if (column == REL_DELETERULE) {
+        else if (column == REL_DELETE_RULE) {
             return DeleteRule.deleteRuleName(relationship.getDeleteRule());
+        } else if (column == REL_COLLECTION_TYPE) {
+            if (!relationship.isToMany())
+                return null;
+            return relationship.getCollectionType();
+        } else if (column == REL_MAP_KEY){
+            return relationship.getMapKey();
+        } else if (column == REL_TARGET_PATH){
+            return relationship.getDbRelationshipPath();
         }
         else {
             return null;
@@ -191,7 +210,7 @@ public class ObjRelationshipTableModel extends CayenneTableModel {
 
             fireTableRowsUpdated(row, row);
         }
-        else if (column == REL_DELETERULE) {
+        else if (column == REL_DELETE_RULE) {
             relationship.setDeleteRule(DeleteRule.deleteRuleForName((String) value));
             fireTableCellUpdated(row, column);
         }
@@ -200,6 +219,17 @@ public class ObjRelationshipTableModel extends CayenneTableModel {
                     && ((Boolean) value).booleanValue());
             fireTableCellUpdated(row, column);
         }
+        else if (column == REL_COLLECTION_TYPE){
+            relationship.setCollectionType((String) value);
+            fireTableCellUpdated(row, column);
+        }else if (column == REL_MAP_KEY){
+            relationship.setMapKey((String) value);
+            fireTableCellUpdated(row, column);
+            }
+        else if (column == REL_TARGET_PATH){
+            relationship.setDbRelationshipPath((String) value);
+            fireTableCellUpdated(row, column);
+        }
 
         mediator.fireObjRelationshipEvent(event);
     }
@@ -223,7 +253,8 @@ public class ObjRelationshipTableModel extends CayenneTableModel {
 
     @Override
     public boolean isCellEditable(int row, int col) {
-        return !isInherited(row) && col != REL_SEMANTICS;
+        return !isInherited(row) && col != REL_SEMANTICS
+                && col != REL_TARGET;
     }
 
     final class RelationshipComparator implements Comparator {
@@ -261,7 +292,10 @@ public class ObjRelationshipTableModel extends CayenneTableModel {
                 sortByElementProperty("usedForLocking", isAscent);
                 break;
             case REL_SEMANTICS:
-            case REL_DELETERULE:
+            case REL_COLLECTION_TYPE:
+            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) {
@@ -278,14 +312,25 @@ public class ObjRelationshipTableModel extends CayenneTableModel {
                         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_DELETERULE:
+                            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)
@@ -298,7 +343,7 @@ public class ObjRelationshipTableModel extends CayenneTableModel {
                     Collections.reverse(objectList);
                 }
                 break;
-            
+
         }
 
     }


[2/8] cayenne git commit: add font to comboboxes which made by factory

Posted by sk...@apache.org.
add font to comboboxes which made by factory


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/1d1bc935
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/1d1bc935
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/1d1bc935

Branch: refs/heads/master
Commit: 1d1bc9359d992848225a7bdfb0c58801d4654e04
Parents: 8367f77
Author: AlexandrShestak <sh...@mail.ru>
Authored: Tue Nov 24 12:37:04 2015 +0300
Committer: Savva Kolbachev <s....@gmail.com>
Committed: Mon Dec 7 13:21:41 2015 +0300

----------------------------------------------------------------------
 .../java/org/apache/cayenne/modeler/util/DefaultWidgetFactory.java | 2 ++
 1 file changed, 2 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/1d1bc935/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/DefaultWidgetFactory.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/DefaultWidgetFactory.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/DefaultWidgetFactory.java
index b86fc2c..c0596c7 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/DefaultWidgetFactory.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/DefaultWidgetFactory.java
@@ -19,6 +19,7 @@
 package org.apache.cayenne.modeler.util;
 
 import java.awt.Color;
+import java.awt.Font;
 import java.util.Arrays;
 import java.util.Collection;
 
@@ -62,6 +63,7 @@ public class DefaultWidgetFactory implements WidgetFactory {
      */
     public JComboBox createComboBox() {
         JComboBox comboBox = new JComboBox();
+        comboBox.setFont(new Font("Verdana", Font.PLAIN , 12));
         comboBox.setBackground(Color.WHITE);
         comboBox.setMaximumRowCount(ModelerPreferences.COMBOBOX_MAX_VISIBLE_SIZE);
         return comboBox;


[5/8] cayenne git commit: cleanup

Posted by sk...@apache.org.
http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/PathChooserComboBoxCellEditor.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/PathChooserComboBoxCellEditor.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/PathChooserComboBoxCellEditor.java
new file mode 100644
index 0000000..ae4a639
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/PathChooserComboBoxCellEditor.java
@@ -0,0 +1,192 @@
+/*****************************************************************
+ *   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.util.combo.AutoCompletion;
+import org.apache.commons.lang.StringUtils;
+
+import javax.swing.AbstractCellEditor;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.JTable;
+import javax.swing.table.TableCellEditor;
+import javax.swing.text.JTextComponent;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * This class used as cell editor, when you need to
+ * choose path in comboBox and use autocompletion.
+ */
+public abstract class PathChooserComboBoxCellEditor extends AbstractCellEditor implements TableCellEditor {
+
+    protected JComboBox comboBoxPathChooser;
+    protected int previousEmbeddedLevel = 0;
+    protected EntityTreeModel treeModel;
+    protected int row;
+
+    protected abstract void enterPressed(JTable table);
+
+    protected abstract EntityTreeModel createTreeModelForComboBox(int indexInTable);
+
+    protected abstract Object getCurrentNodeToInitializeCombo(CayenneTableModel model, int row);
+
+    protected abstract String getPathToInitializeCombo(CayenneTableModel model, int row);
+
+    protected void initializeCombo(CayenneTableModel model, int row, final JTable table) {
+        Object currentNode = getCurrentNodeToInitializeCombo(model, row);
+        String dbAttributePath = getPathToInitializeCombo(model, row);
+        List<String> nodeChildren = getChildren(currentNode, dbAttributePath);
+        comboBoxPathChooser = Application.getWidgetFactory().createComboBox(
+                nodeChildren,
+                false);
+        comboBoxPathChooser.getEditor().getEditorComponent().addKeyListener(new KeyAdapter() {
+            @Override
+            public void keyReleased(KeyEvent event) {
+                if (event.getKeyCode() == KeyEvent.VK_ENTER) {
+                    enterPressed(table);
+                    return;
+                }
+                parsePathString(event.getKeyChar());
+            }
+        });
+        AutoCompletion.enable(comboBoxPathChooser, false, true);
+    }
+
+    private void setComboModelAccordingToPath(String pathString) {
+        List<String> currentNodeChildren = new ArrayList<>();
+        currentNodeChildren.add(pathString);
+        currentNodeChildren.addAll(getChildren(getCurrentNode(pathString), pathString));
+        comboBoxPathChooser.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
+        comboBoxPathChooser.showPopup();
+        comboBoxPathChooser.setPopupVisible(true);
+    }
+
+    protected void parsePathString(char lastEnteredCharacter) {
+        JTextComponent editorComponent = (JTextComponent) (comboBoxPathChooser).getEditor().getEditorComponent();
+
+        String pathString = editorComponent.getText();
+        if (pathString != null && pathString.isEmpty()) {
+            setComboModelAccordingToPath("");
+            previousEmbeddedLevel = StringUtils.countMatches(pathString, ".");
+            return;
+        }
+
+        if (lastEnteredCharacter == '.') {
+            processDotEntered();
+            previousEmbeddedLevel = StringUtils.countMatches(pathString, ".");
+            return;
+        }
+
+        int currentEmbeddedLevel = StringUtils.countMatches(pathString, ".");
+        if (previousEmbeddedLevel != currentEmbeddedLevel) {
+            previousEmbeddedLevel = currentEmbeddedLevel;
+            List<String> currentNodeChildren = new ArrayList<>();
+            String[] pathStrings = pathString.split(Pattern.quote("."));
+            String lastStringInPath = pathStrings[pathStrings.length - 1];
+            String saveDbAttributePath = pathString;
+            pathString = pathString.replaceAll(lastStringInPath + "$", "");
+            currentNodeChildren.addAll(getChildren(getCurrentNode(pathString), pathString));
+            comboBoxPathChooser.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
+            editorComponent.setText(saveDbAttributePath);
+            return;
+        }
+    }
+
+    private void processDotEntered() {
+        JTextComponent editorComponent = (JTextComponent) (comboBoxPathChooser).getEditor().getEditorComponent();
+
+        String dbAttributePath = editorComponent.getText();
+        if (".".equals(dbAttributePath)) {
+            setComboModelAccordingToPath("");
+            return;
+        }
+        char secondFromEndCharacter = dbAttributePath.charAt(dbAttributePath.length() - 2);
+        if (secondFromEndCharacter == '.') {
+            // two dots entered one by one , we replace it by one dot
+            editorComponent.setText(dbAttributePath.substring(0, dbAttributePath.length() - 1));
+            return;
+        }
+        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) {
+            //previous root is treeModel.getRoot()
+            dbAttributePathForPreviousNode = "";
+        } else {
+            dbAttributePathForPreviousNode = dbAttributePath.replace('.' + lastStringInPath, "");
+        }
+        List<String> potentialVariantsToChoose = getChildren(getCurrentNode(dbAttributePathForPreviousNode), "");
+        if (potentialVariantsToChoose.contains(lastStringInPath)) {
+            setComboModelAccordingToPath(dbAttributePath);
+        } else {
+            editorComponent.setText(dbAttributePath.substring(0, dbAttributePath.length() - 1));
+        }
+        previousEmbeddedLevel = StringUtils.countMatches(dbAttributePath, ".");
+    }
+
+    /**
+     * find current node by dbAttributePath
+     *
+     * @param pathString
+     * @return last node in dbAttributePath which matches DbRelationship or DbAttribute
+     */
+    protected Object getCurrentNode(String pathString) {
+        //case for new attribute
+        if (pathString == null || pathString.isEmpty()) {
+            return treeModel.getRoot();
+        }
+        String[] pathStrings = pathString.split(Pattern.quote("."));
+        Object root = treeModel.getRoot();
+        for (String rootChildText : pathStrings) {
+            for (int j = 0; j < treeModel.getChildCount(root); j++) {
+                Object child = treeModel.getChild(root, j);
+                String objectName = ModelerUtil.getObjectName(child);
+                if (objectName.equals(rootChildText)) {
+                    root = child;
+                    break;
+                }
+            }
+        }
+        return root;
+    }
+
+    /**
+     * @param node       for which we will find children
+     * @param pathString string which will be added to each child to make right autocomplete
+     * @return list with children , which will be used to autocomplete
+     */
+    protected List<String> getChildren(Object node, String pathString) {
+        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(pathString + relationshipName);
+        }
+        return currentNodeChildren;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectUtil.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectUtil.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectUtil.java
index 20aaf3d..fc7735d 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectUtil.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectUtil.java
@@ -19,11 +19,6 @@
 
 package org.apache.cayenne.modeler.util;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
 import org.apache.cayenne.configuration.DataChannelDescriptor;
 import org.apache.cayenne.configuration.DataNodeDescriptor;
 import org.apache.cayenne.map.Attribute;
@@ -48,6 +43,11 @@ import org.apache.cayenne.query.EJBQLQuery;
 import org.apache.cayenne.query.Query;
 import org.apache.cayenne.util.Util;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
 /**
  * Provides utility methods to perform various manipulations with project objects.
  */
@@ -198,7 +198,7 @@ public class ProjectUtil {
         }
     }
 
-    
+
     /**
      * Changes the name of the embeddable attribute and all references to this embeddable attribute.
      */
@@ -207,7 +207,7 @@ public class ProjectUtil {
 
         attribute.setName(newName);
         Embeddable embeddable = attribute.getEmbeddable();
-        
+
         if (embeddable != null) {
             embeddable.removeAttribute(oldName);
             embeddable.addAttribute(attribute);
@@ -245,46 +245,15 @@ public class ProjectUtil {
             for (ObjAttribute att : entity.getAttributes()) {
 
                 // If flattenet atribute
-                if (att.getDbAttributePath() != null
-                        && att.getDbAttributePath().contains(".")) {
-                    String[] pathSplit = att.getDbAttributePath().split("\\.");
+                String dbAttributePath = att.getDbAttributePath();
+                if (dbAttributePath != null
+                        && dbAttributePath.contains(".")) {
+                    String[] pathSplit = dbAttributePath.split("\\.");
 
                     // If flattened attribute
                     if (pathSplit.length > 1) {
 
-                        DbEntity currentEnt = dbEnt;
-                        StringBuilder pathBuf = new StringBuilder();
-                        boolean isTruePath = true;
-
-                        if (currentEnt != null) {
-
-                            for (int j = 0; j < pathSplit.length; j++) {
-
-                                if (j == pathSplit.length - 1 && isTruePath) {
-                                    DbAttribute dbAttribute = (DbAttribute) currentEnt
-                                            .getAttribute(pathSplit[j]);
-                                    if (dbAttribute != null) {
-                                        pathBuf.append(dbAttribute.getName());
-                                    }
-                                    else {
-                                        isTruePath = false;
-                                    }
-                                }
-                                else if (isTruePath) {
-                                    DbRelationship dbRelationship = (DbRelationship) currentEnt
-                                            .getRelationship(pathSplit[j]);
-                                    if (dbRelationship != null) {
-                                        currentEnt = (DbEntity) dbRelationship
-                                                .getTargetEntity();
-                                        pathBuf.append(dbRelationship.getName());
-                                        pathBuf.append(".");
-                                    }
-                                    else {
-                                        isTruePath = false;
-                                    }
-                                }
-                            }
-                        }
+                        boolean isTruePath = isDbAttributePathCorrect(dbEnt, dbAttributePath);
 
                         if (!isTruePath) {
                             att.setDbAttributePath(null);
@@ -319,6 +288,34 @@ public class ProjectUtil {
     }
 
     /**
+     * check if path is correct. path is correct when he consist from <code>DbRelationship</code>
+     * objects, each <code>DbRelationship</code> object have  following <code>DbRelationship</code>
+     * object as a target, last component is <code>DbAttribute</code>
+     *
+     * @param currentEnt current db entity
+     * @param dbAttributePath path to check
+     * @return if path is correct return true
+     */
+    public static boolean isDbAttributePathCorrect(DbEntity currentEnt, String dbAttributePath) {
+        if (currentEnt == null) {
+            return true;
+        }
+
+        String[] pathSplit = dbAttributePath.split("\\.");
+
+        int size = pathSplit.length - 1;
+        for (int j = 0; j < size; j++) {
+            DbRelationship relationship = currentEnt.getRelationship(pathSplit[j]);
+            if (relationship == null) {
+                return false;
+            }
+            currentEnt = relationship.getTargetEntity();
+        }
+
+        return currentEnt.getAttribute(pathSplit[(size)]) != null;
+    }
+
+    /**
      * Clears all the mapping between this obj entity and its current db entity. Clears
      * mapping between entities, attributes and relationships.
      */
@@ -439,4 +436,4 @@ public class ProjectUtil {
         }
         return relationships;
     }
-}
+}
\ 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/SortButtonRenderer.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/SortButtonRenderer.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/SortButtonRenderer.java
index 524d8ba..595ba4d 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/SortButtonRenderer.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/SortButtonRenderer.java
@@ -18,51 +18,33 @@
  ****************************************************************/
 package org.apache.cayenne.modeler.util;
 
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Insets;
-import java.util.Hashtable;
-
 import javax.swing.BorderFactory;
-import javax.swing.JButton;
+import javax.swing.JLabel;
 import javax.swing.JTable;
-import javax.swing.border.MatteBorder;
+import javax.swing.border.Border;
 import javax.swing.table.TableCellRenderer;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Font;
+import java.util.Hashtable;
 
-public class SortButtonRenderer extends JButton implements TableCellRenderer {
+public class SortButtonRenderer extends JLabel implements TableCellRenderer {
 
     public static final int NONE = 0;
     public static final int DOWN = 1;
     public static final int UP = 2;
 
-    private int pushedColumn;
     private Hashtable state;
-    private JButton downButton, upButton;
+    private JLabel downLabel , upLabel;
 
     public SortButtonRenderer() {
-        MatteBorder matteBorder = BorderFactory.createMatteBorder(0, 0, 1, 1, Color.gray);
-        setBorder(matteBorder);
-
-        pushedColumn = -1;
         state = new Hashtable();
 
-        setMargin(new Insets(0, 0, 0, 0));
-        setHorizontalTextPosition(CENTER);
-        setIcon(new BlankIcon());
+        downLabel = new JLabel();
+        downLabel.setIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, false));
 
-        downButton = new JButton();
-
-        downButton.setBorder(matteBorder);
-        downButton.setMargin(new Insets(0, 0, 0, 0));
-        downButton.setHorizontalTextPosition(LEFT);
-        downButton.setIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, false));
-        downButton.setPressedIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, true));
-
-        upButton = new JButton();
-        upButton.setBorder(matteBorder);
-        upButton.setMargin(new Insets(0, 0, 0, 0));
-        upButton.setHorizontalTextPosition(LEFT);
-        upButton.setIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, false));
+        upLabel = new JLabel();
+        upLabel.setIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, false));
     }
 
     public Component getTableCellRendererComponent(
@@ -72,49 +54,51 @@ public class SortButtonRenderer extends JButton implements TableCellRenderer {
             boolean hasFocus,
             int row,
             int column) {
-        JButton button = this;
-        Object obj = state.get(new Integer(column));
+        JLabel  label = this;
+        Object obj = state.get(column);
 
         if (obj != null) {
-            if (((Integer) obj).intValue() == DOWN) {
-                button = downButton;
+            if ((Integer) obj == DOWN) {
+                label = downLabel;
             }
             else {
-                button = upButton;
+                label = upLabel;
             }
         }
-        button.setText((value == null) ? "" : value.toString());
-        return button;
-    }
-
-    public void setPressedColumn(int col) {
-        pushedColumn = col;
+        Border border = BorderFactory.createLineBorder(Color.GRAY, 1);
+        label.setText(' ' + ((value == null) ? "" : value.toString()));
+        label.setFont(new Font("Verdana", Font.BOLD , 13));
+        label.setHorizontalTextPosition(JLabel.LEFT);
+        label.setBorder(border);
+        label.setOpaque(true);
+        label.setBackground(new Color(204, 238, 255));
+        return label;
     }
 
     public void setSelectedColumn(int col, boolean isAscOrder) {
-        if (col < 0)
+        if (col < 0) {
             return;
+        }
         Integer value = null;
         //shows the direction of ordering
         if (isAscOrder) {
-            value = new Integer(DOWN);
-        }
-        else {
-            value = new Integer(UP);
+            value = DOWN;
+        } else {
+            value = UP;
         }
 
         state.clear();
-        state.put(new Integer(col), value);
+        state.put(col, value);
     }
 
     public int getState(int col) {
         int retValue;
-        Object obj = state.get(new Integer(col));
+        Object obj = state.get(col);
         if (obj == null) {
             retValue = NONE;
         }
         else {
-            if (((Integer) obj).intValue() == DOWN) {
+            if ((Integer) obj == DOWN) {
                 retValue = DOWN;
             }
             else {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/TableHeaderListener.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/TableHeaderListener.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/TableHeaderListener.java
index 29bf1a7..b665730 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/TableHeaderListener.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/TableHeaderListener.java
@@ -72,14 +72,12 @@ public class TableHeaderListener extends MouseAdapter {
     }
 
     public void mouseReleased(MouseEvent e) {
-        renderer.setPressedColumn(-1); // clear
         header.repaint();
     }
 
     public void sortByDefinedColumn(int col, int sortCol, boolean order) {
         CayenneTableModel model = (CayenneTableModel) table.getModel();
         if (model.isColumnSortable(sortCol)) {
-            renderer.setPressedColumn(col);
             renderer.setSelectedColumn(col, order);
             header.repaint();
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/AutoCompletion.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/AutoCompletion.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/AutoCompletion.java
index 2e86251..9c8a371 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/AutoCompletion.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/AutoCompletion.java
@@ -19,15 +19,17 @@
 
 package org.apache.cayenne.modeler.util.combo;
 
+import javax.swing.JComboBox;
+import javax.swing.JScrollBar;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+import javax.swing.text.JTextComponent;
+import java.awt.Component;
 import java.awt.event.FocusEvent;
 import java.awt.event.FocusListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
 
-import javax.swing.JComboBox;
-import javax.swing.SwingUtilities;
-import javax.swing.text.JTextComponent;
-
 /**
  * AutoCompletion class handles user input and suggests matching variants (see CAY-911)
  *
@@ -55,8 +57,8 @@ public class AutoCompletion implements FocusListener, KeyListener, Runnable {
     protected AutoCompletion(final JComboBox comboBox, boolean strict, boolean allowsUserValues) {
         this.comboBox = comboBox;
         textEditor = ((JTextComponent)comboBox.getEditor().getEditorComponent());
-        
-        this.allowsUserValues = allowsUserValues; 
+
+        this.allowsUserValues = allowsUserValues;
         
         suggestionList = new SuggestionList(comboBox, strict);
         
@@ -75,13 +77,17 @@ public class AutoCompletion implements FocusListener, KeyListener, Runnable {
      */
     public static void enable(JComboBox comboBox, boolean strict, boolean allowsUserValues) {
         comboBox.setEditable(true);
-        
+        KeyListener[] listeners = comboBox.getEditor().getEditorComponent().getListeners(KeyListener.class);
         comboBox.setEditor(new CustomTypeComboBoxEditor(comboBox, allowsUserValues));
-        
+        for (KeyListener listener : listeners) {
+            comboBox.getEditor().getEditorComponent().addKeyListener(listener);
+        }
+
+
         AutoCompletion ac = new AutoCompletion(comboBox, strict, allowsUserValues);
         comboBox.addFocusListener(ac);
         ac.textEditor.addKeyListener(ac);
-        
+
         //original keys would not work properly
         SwingUtilities.replaceUIActionMap(comboBox, null);
     }
@@ -100,23 +106,34 @@ public class AutoCompletion implements FocusListener, KeyListener, Runnable {
     }
 
     public void keyPressed(KeyEvent e) {
-        handleKeyPressed(comboBox, e);
+        handleKeyPressed(e);
     }
 
-    public void keyReleased(KeyEvent e) {}
+    public void keyReleased(KeyEvent e) {
+        if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE ||
+                e.getKeyCode() == KeyEvent.VK_ENTER) {
+
+            String text = textEditor.getText();
+            if (comboBox.isShowing()) {
+                suggestionList.hide();
+                suggestionList.filter(text);
+                suggestionList.show();
+            }
+        }
+    }
 
     public void keyTyped(KeyEvent e) {}
-    
+
     public void run() {
         String text = textEditor.getText();
-        
+
         //need to hide first because Swing incorrectly updates popups (getSize() returns
         //dimension not the same as seen on the screen)
         suggestionList.hide();
-        
+
         if (comboBox.isShowing()) {
             suggestionList.filter(text);
-            
+
             if (suggestionList.getItemCount() > 0) {
                 suggestionList.show();
             }
@@ -127,24 +144,31 @@ public class AutoCompletion implements FocusListener, KeyListener, Runnable {
      * Calculates next selection row, according to a pressed key and selects it.
      * This might affect either suggestion list or original popup
      */
-    private void handleKeyPressed(JComboBox comboBox, KeyEvent e) {
+    private void handleKeyPressed(KeyEvent e) {
         boolean suggest = suggestionList.isVisible();
-        
-        int sel, next, max;
-        
+
         if (suggest) {
-            sel = suggestionList.getSelectedIndex();
-            max = suggestionList.getItemCount() - 1;
+            processKeyPressedWhenSuggestionListIsVisible(e);
         }
         else {
-            sel = comboBox.getSelectedIndex();
-            max = comboBox.getItemCount() - 1;
+            processKeyPressedWhenSuggestionListIsInvisible(e);
         }
-        
+
+        //scroll doesn't work in suggestionList..so we will scroll manually
+        suggestionListScrolling();
+
+        textEditor.requestFocus();
+    }
+
+    private void   processKeyPressedWhenSuggestionListIsInvisible(KeyEvent e){
+        int sel = comboBox.getSelectedIndex();
+        int max = comboBox.getItemCount() - 1;
+
+        int next;
         switch (e.getKeyCode()) {
             case KeyEvent.VK_UP:
             case KeyEvent.VK_NUMPAD8:
-                next = sel - 1; 
+                next = sel - 1;
                 break;
             case KeyEvent.VK_DOWN:
             case KeyEvent.VK_NUMPAD2:
@@ -163,42 +187,71 @@ public class AutoCompletion implements FocusListener, KeyListener, Runnable {
                 next = max;
                 break;
             case KeyEvent.VK_ENTER:
-                if (suggest) {
-                    Object value = suggestionList.getSelectedValue();
-                    if (!allowsUserValues && value == null && suggestionList.getItemCount() > 0) {
-                        value = suggestionList.getItemAt(0);
-                    }
-                    
-                    //reset the item (value == null) only if user values are not supported
-                    if (value != null || !allowsUserValues) {
-                        comboBox.setSelectedItem(value);
-                    }
-                    suggestionList.hide();
-                }
                 return;
-                
             case KeyEvent.VK_ESCAPE:
-                if (suggest) {
-                    suggestionList.hide();
-                }
                 return;
-                
-            case KeyEvent.VK_CONTROL:
-            case KeyEvent.VK_ALT:
-            case KeyEvent.VK_SHIFT:
-                return;
-                
             default:
                 //invoke in end of AWT thread so that information in textEditor would update
                 SwingUtilities.invokeLater(this);
                 return;
         }
-        
-        /**
-         * Handle navigation keys
-         */
+        e.consume();
+        handleNavigationKeys(false,next,sel,max);
+    }
 
+    private void processKeyPressedWhenSuggestionListIsVisible(KeyEvent e){
+        int sel = suggestionList.getSelectedIndex();
+        int max = suggestionList.getItemCount() - 1;
+        int next;
+        switch (e.getKeyCode()) {
+            case KeyEvent.VK_UP:
+            case KeyEvent.VK_NUMPAD8:
+                next = sel - 1;
+                break;
+            case KeyEvent.VK_DOWN:
+            case KeyEvent.VK_NUMPAD2:
+                next = sel + 1;
+                break;
+            case KeyEvent.VK_PAGE_UP:
+                next = sel - comboBox.getMaximumRowCount();
+                break;
+            case KeyEvent.VK_PAGE_DOWN:
+                next = sel + comboBox.getMaximumRowCount();
+                break;
+            case KeyEvent.VK_HOME:
+                next = 0;
+                break;
+            case KeyEvent.VK_END:
+                next = max;
+                break;
+            case KeyEvent.VK_ENTER:
+                processEnterPressed();
+                return;
+            case KeyEvent.VK_ESCAPE:
+                suggestionList.hide();
+                return;
+            default:
+                //invoke in end of AWT thread so that information in textEditor would update
+                SwingUtilities.invokeLater(this);
+                return;
+        }
         e.consume();
+        handleNavigationKeys(true,next,sel,max);
+    }
+
+    private void processEnterPressed(){
+        Object value = suggestionList.getSelectedValue();
+        if (!allowsUserValues && value == null && suggestionList.getItemCount() > 0) {
+            value = suggestionList.getItemAt(0);
+        }
+        //reset the item (value == null) only if user values are not supported
+        if (value != null || !allowsUserValues) {
+            comboBox.setSelectedItem(value);
+        }
+        suggestionList.hide();
+    }
+
+    private void handleNavigationKeys(boolean suggest, int next, int sel, int max){
         if (!suggest && !comboBox.isPopupVisible()) {
             comboBox.setPopupVisible(true);
             return;
@@ -208,22 +261,33 @@ public class AutoCompletion implements FocusListener, KeyListener, Runnable {
             if (next < 0) {
                 next = 0;
             }
-        
+
             if (next > max) {
                 next = max;
             }
-            
+
             if (next != sel) {
                 if (suggest) {
                     suggestionList.setSelectedIndex(next);
-                }
-                else {
-                   comboBox.setPopupVisible(true);
-                   comboBox.setSelectedIndex(next);
+                } else {
+                    comboBox.setPopupVisible(true);
+                    comboBox.setSelectedIndex(next);
                 }
             }
-            
-            textEditor.requestFocus();
+        }
+    }
+
+    private void suggestionListScrolling(){
+        Component c = suggestionList.getComponent(0);
+        if (c instanceof JScrollPane) {
+            double height = suggestionList.getPreferredSize().getHeight();
+            int itemCount = suggestionList.getItemCount();
+            int selectedIndex = suggestionList.getSelectedIndex();
+            double scrollValue = Math.ceil(height*selectedIndex/itemCount);
+            JScrollPane scrollPane = (JScrollPane) c;
+            JScrollBar scrollBar = scrollPane.getVerticalScrollBar();
+            scrollBar.setValue((int) scrollValue);
         }
     }
 }
+