You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2017/07/25 13:34:11 UTC

[2/2] cayenne git commit: CAY-2336 Support for comments in Cayenne Modeler - Comments in Modeler

CAY-2336 Support for comments in Cayenne Modeler
 - Comments in Modeler


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

Branch: refs/heads/master
Commit: 11b916f85700a770a86e1ba652c71be82f605242
Parents: 6198555
Author: Nikita Timofeev <st...@gmail.com>
Authored: Tue Jul 25 15:54:51 2017 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Tue Jul 25 15:54:51 2017 +0300

----------------------------------------------------------------------
 .../modeler/dialog/query/QueryTypeView.java     |   2 +-
 .../cayenne/modeler/editor/DataMapView.java     |  32 ++++-
 .../modeler/editor/EjbqlQueryMainTab.java       |  29 ++++-
 .../cayenne/modeler/editor/EmbeddableTab.java   |  33 ++++--
 .../modeler/editor/ObjAttributeTableModel.java  |  86 ++++++++------
 .../modeler/editor/ObjCallbackMethod.java       |   5 +-
 .../cayenne/modeler/editor/ObjEntityTab.java    |  60 ++++------
 .../editor/ObjRelationshipTableModel.java       | 118 +++++++++++--------
 .../modeler/editor/ProcedureQueryView.java      |  42 +++++--
 .../cayenne/modeler/editor/ProcedureTab.java    |  40 +++++--
 .../modeler/editor/SQLTemplateMainTab.java      |  29 ++++-
 .../modeler/editor/SelectQueryMainTab.java      |  27 ++++-
 .../editor/dbentity/DbAttributeTableModel.java  |  70 +++++------
 .../editor/dbentity/DbEntityAttributePanel.java |   2 +-
 .../dbentity/DbEntityRelationshipPanel.java     |  36 +++---
 .../modeler/editor/dbentity/DbEntityTab.java    |  29 ++++-
 .../dbentity/DbRelationshipTableModel.java      |  84 +++++++------
 .../modeler/init/CayenneModelerModule.java      |   4 +
 18 files changed, 471 insertions(+), 257 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/query/QueryTypeView.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/query/QueryTypeView.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/query/QueryTypeView.java
index 523beb7..0da2a56 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/query/QueryTypeView.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/query/QueryTypeView.java
@@ -50,7 +50,7 @@ public class QueryTypeView extends JDialog {
         // create widgets
         ButtonGroup buttonGroup = new ButtonGroup();
         objectSelect = new JRadioButton("Object Select Query");
-        sqlSelect = new JRadioButton("Raw SQL");
+        sqlSelect = new JRadioButton("SQLTemplate Query");
         procedureSelect = new JRadioButton("Stored Procedure Query");
         ejbqlSelect = new JRadioButton("EJBQL Query");
         objectSelect.setSelected(true);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/DataMapView.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/DataMapView.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/DataMapView.java
index 2736907..f7cfc49 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/DataMapView.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/DataMapView.java
@@ -42,6 +42,7 @@ import org.apache.cayenne.modeler.util.CellRenderers;
 import org.apache.cayenne.modeler.util.Comparators;
 import org.apache.cayenne.modeler.util.ProjectUtil;
 import org.apache.cayenne.modeler.util.TextAdapter;
+import org.apache.cayenne.project.extension.info.ObjectInfo;
 import org.apache.cayenne.util.Util;
 import org.apache.cayenne.validation.ValidationException;
 
@@ -76,6 +77,8 @@ public class DataMapView extends JPanel {
     protected TextAdapter defaultSuperclass;
     protected JCheckBox quoteSQLIdentifiers;
 
+    protected TextAdapter comment;
+
     protected JButton updateDefaultCatalog;
     protected JButton updateDefaultSchema;
     protected JButton updateDefaultPackage;
@@ -130,6 +133,13 @@ public class DataMapView extends JPanel {
 
         quoteSQLIdentifiers = new JCayenneCheckBox();
 
+        comment = new TextAdapter(new JTextField()) {
+            @Override
+            protected void updateModel(String text) throws ValidationException {
+                updateComment(text);
+            }
+        };
+
         updateDefaultPackage = new JButton("Update...");
         defaultPackage = new TextAdapter(new JTextField()) {
 
@@ -178,6 +188,7 @@ public class DataMapView extends JPanel {
         builder.append("File:", location, 3);
         builder.append("DataNode:", nodeSelector, 2);
         builder.append("Quote SQL Identifiers:", quoteSQLIdentifiers, 3);
+        builder.append("Comment:", comment.getComponent(), 2);
 
         builder.appendSeparator("Entity Defaults");
         builder.append("DB Catalog:", defaultCatalog.getComponent(), updateDefaultCatalog);
@@ -307,10 +318,10 @@ public class DataMapView extends JPanel {
      */
     private void initFromModel(DataMap map) {
         name.setText(map.getName());
-        String locationText = map.getLocation();
-        location.setText((locationText != null) ? locationText : "(no file)");
-
+        location.setText((map.getLocation() != null) ? map.getLocation() : "(no file)");
         quoteSQLIdentifiers.setSelected(map.isQuotingSQLIdentifiers());
+        comment.setText(getComment(map));
+
         // rebuild data node list
 
         DataNodeDescriptor nodes[] = ((DataChannelDescriptor) eventController.getProject().getRootNode())
@@ -318,7 +329,6 @@ public class DataMapView extends JPanel {
 
         // add an empty item to the front
         DataNodeDescriptor[] objects = new DataNodeDescriptor[nodes.length + 1];
-        // objects[0] = null;
 
         // now add the entities
         if (nodes.length > 0) {
@@ -667,4 +677,18 @@ public class DataMapView extends JPanel {
             new LockingUpdateController(eventController, dataMap).startup();
         }
     }
+
+    void updateComment(String comment) {
+        DataMap dataMap = eventController.getCurrentDataMap();
+        if (dataMap == null) {
+            return;
+        }
+
+        ObjectInfo.putToMetaData(eventController.getApplication().getMetaData(), dataMap, ObjectInfo.COMMENT, comment);
+        eventController.fireDataMapEvent(new DataMapEvent(this, dataMap));
+    }
+
+    private String getComment(DataMap dataMap) {
+        return ObjectInfo.getFromMetaData(eventController.getApplication().getMetaData(), dataMap, ObjectInfo.COMMENT);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/EjbqlQueryMainTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/EjbqlQueryMainTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/EjbqlQueryMainTab.java
index 699511d..45211f9 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/EjbqlQueryMainTab.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/EjbqlQueryMainTab.java
@@ -28,6 +28,7 @@ import org.apache.cayenne.modeler.ProjectController;
 import org.apache.cayenne.modeler.util.ProjectUtil;
 import org.apache.cayenne.modeler.util.TextAdapter;
 import org.apache.cayenne.map.QueryDescriptor;
+import org.apache.cayenne.project.extension.info.ObjectInfo;
 import org.apache.cayenne.util.Util;
 import org.apache.cayenne.validation.ValidationException;
 import com.jgoodies.forms.builder.PanelBuilder;
@@ -39,6 +40,7 @@ public class EjbqlQueryMainTab extends JPanel{
 
     protected ProjectController mediator;
     protected TextAdapter name;
+    protected TextAdapter comment;
     protected EjbqlQueryPropertiesPanel properties;
     protected TextAdapter qualifier;
 
@@ -50,23 +52,32 @@ public class EjbqlQueryMainTab extends JPanel{
     private void initView() {
         // create widgets
         name = new TextAdapter(new JTextField()) {
-
+            @Override
             protected void updateModel(String text) {
                 setQueryName(text);
             }
         };
 
+        comment = new TextAdapter(new JTextField()) {
+            @Override
+            protected void updateModel(String text) {
+                setQueryComment(text);
+            }
+        };
+
         properties = new EjbqlQueryPropertiesPanel(mediator);
         // assemble
         CellConstraints cc = new CellConstraints();
         FormLayout layout = new FormLayout(
                 "right:max(80dlu;pref), 3dlu, fill:max(200dlu;pref)",
-                "p, 3dlu, p");
+                "p, 3dlu, p, 3dlu, p");
         PanelBuilder builder = new PanelBuilder(layout);
         builder.setDefaultDialogBorder();
         builder.addSeparator("EJBQL Query Settings", cc.xywh(1, 1, 3, 1));
         builder.addLabel("Query Name:", cc.xy(1, 3));
         builder.add(name.getComponent(), cc.xy(3, 3));
+        builder.addLabel("Comment:", cc.xy(1, 5));
+        builder.add(comment.getComponent(), cc.xy(3, 5));
 
         this.setLayout(new BorderLayout());
         this.add(builder.getPanel(), BorderLayout.NORTH);
@@ -86,6 +97,7 @@ public class EjbqlQueryMainTab extends JPanel{
         }
 
         name.setText(query.getName());
+        comment.setText(getQueryComment(query));
         properties.initFromModel(query);
         setVisible(true);
     }
@@ -132,4 +144,17 @@ public class EjbqlQueryMainTab extends JPanel{
                     + "'. Use a different name.");
         }
     }
+
+    private void setQueryComment(String text) {
+        QueryDescriptor query = getQuery();
+        if (query == null) {
+            return;
+        }
+        ObjectInfo.putToMetaData(mediator.getApplication().getMetaData(), query, ObjectInfo.COMMENT, text);
+        mediator.fireQueryEvent(new QueryEvent(this, query));
+    }
+
+    private String getQueryComment(QueryDescriptor queryDescriptor) {
+        return ObjectInfo.getFromMetaData(mediator.getApplication().getMetaData(), queryDescriptor, ObjectInfo.COMMENT);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/EmbeddableTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/EmbeddableTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/EmbeddableTab.java
index cf2040b..deb24b7 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/EmbeddableTab.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/EmbeddableTab.java
@@ -42,6 +42,7 @@ import org.apache.cayenne.modeler.action.CreateAttributeAction;
 import org.apache.cayenne.modeler.event.EmbeddableDisplayEvent;
 import org.apache.cayenne.modeler.event.EmbeddableDisplayListener;
 import org.apache.cayenne.modeler.util.TextAdapter;
+import org.apache.cayenne.project.extension.info.ObjectInfo;
 import org.apache.cayenne.util.Util;
 import org.apache.cayenne.validation.ValidationException;
 
@@ -52,6 +53,7 @@ public class EmbeddableTab extends JPanel implements EmbeddableDisplayListener {
 
     protected ProjectController mediator;
     protected TextAdapter className;
+    protected TextAdapter comment;
 
     public EmbeddableTab(ProjectController mediator) {
         this.mediator = mediator;
@@ -75,29 +77,30 @@ public class EmbeddableTab extends JPanel implements EmbeddableDisplayListener {
         add(toolBar, BorderLayout.NORTH);
 
         className = new TextAdapter(new JTextField()) {
-
             @Override
             protected void updateModel(String text) {
                 setClassName(text);
             }
         };
 
+        comment = new TextAdapter(new JTextField()) {
+            @Override
+            protected void updateModel(String text) {
+                setComment(text);
+            }
+        };
+
         FormLayout layout = new FormLayout(
                 "right:50dlu, 3dlu, fill:150dlu, 3dlu, fill:100",
                 "");
         DefaultFormBuilder builder = new DefaultFormBuilder(layout);
         builder.setDefaultDialogBorder();
         builder.append("Class Name:", className.getComponent(), 3);
+        builder.append("Comment:", comment.getComponent(), 3);
 
         add(builder.getPanel(), BorderLayout.CENTER);
     }
 
-    public void processExistingSelection(EventObject e) {
-        EmbeddableDisplayEvent ede = new EmbeddableDisplayEvent(this, mediator
-                .getCurrentEmbeddable(), mediator.getCurrentDataMap(), (DataChannelDescriptor)mediator.getProject().getRootNode());
-        mediator.fireEmbeddableDisplayEvent(ede);
-    }
-
     void setClassName(String newClassName) {
         if (newClassName != null && newClassName.trim().length() == 0) {
             newClassName = null;
@@ -187,5 +190,21 @@ public class EmbeddableTab extends JPanel implements EmbeddableDisplayListener {
 
     private void initFromModel(Embeddable embeddable) {
         className.setText(embeddable.getClassName());
+        comment.setText(getComment(embeddable));
+    }
+
+    void setComment(String comment) {
+        Embeddable embeddable = mediator.getCurrentEmbeddable();
+
+        if (embeddable == null) {
+            return;
+        }
+
+        ObjectInfo.putToMetaData(mediator.getApplication().getMetaData(), embeddable, ObjectInfo.COMMENT, comment);
+        mediator.fireEmbeddableEvent(new EmbeddableEvent(this, embeddable), mediator.getCurrentDataMap());
+    }
+
+    String getComment(Embeddable embeddable) {
+        return ObjectInfo.getFromMetaData(mediator.getApplication().getMetaData(), embeddable, ObjectInfo.COMMENT);
     }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/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 41739ac..fe0e69e 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
@@ -25,6 +25,7 @@ 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.EmbeddedAttribute;
 import org.apache.cayenne.map.ObjAttribute;
 import org.apache.cayenne.map.ObjEntity;
@@ -41,6 +42,7 @@ 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.project.extension.info.ObjectInfo;
 import org.apache.cayenne.util.Util;
 
 import java.util.ArrayList;
@@ -64,7 +66,8 @@ public class ObjAttributeTableModel extends CayenneTableModel<ObjAttributeWrappe
     public static final int DB_ATTRIBUTE = 3;
     public static final int DB_ATTRIBUTE_TYPE = 4;
     public static final int LOCKING = 5;
-    public static final int COLUMN_COUNT = 6;
+    public static final int COMMENT = 6;
+    public static final int COLUMN_COUNT = 7;
 
     private ObjEntity entity;
     private DbEntity dbEntity;
@@ -163,6 +166,8 @@ public class ObjAttributeTableModel extends CayenneTableModel<ObjAttributeWrappe
                 return "DB Type";
             case LOCKING:
                 return "Used for Locking";
+            case COMMENT:
+                return "Comment";
             default:
                 return "";
         }
@@ -170,29 +175,25 @@ public class ObjAttributeTableModel extends CayenneTableModel<ObjAttributeWrappe
 
     public Object getValueAt(int row, int column) {
         ObjAttributeWrapper attribute = getAttribute(row);
-        if (column == INHERITED) {
-            return attribute.isInherited();
-        }
-        else if (column == OBJ_ATTRIBUTE) {
-            return attribute.getName();
-        }
-        else if (column == OBJ_ATTRIBUTE_TYPE) {
-            return attribute.getType();
-        }
-        else if (column == LOCKING) {
-            return attribute.isUsedForLocking() ? Boolean.TRUE : Boolean.FALSE;
-        }
-        else {
-            DbAttribute dbAttribute = attribute.getDbAttribute();
-            if (column == DB_ATTRIBUTE) {
+        DbAttribute dbAttribute = attribute.getDbAttribute();
+
+        switch (column) {
+            case INHERITED:
+                return attribute.isInherited();
+            case OBJ_ATTRIBUTE:
+                return attribute.getName();
+            case OBJ_ATTRIBUTE_TYPE:
+                return attribute.getType();
+            case LOCKING:
+                return attribute.isUsedForLocking() ? Boolean.TRUE : Boolean.FALSE;
+            case DB_ATTRIBUTE:
                 return getDBAttribute(attribute, dbAttribute);
-            }
-            else if (column == DB_ATTRIBUTE_TYPE) {
+            case DB_ATTRIBUTE_TYPE:
                 return getDBAttributeType(attribute, dbAttribute);
-            }
-            else {
+            case COMMENT:
+                return getComment(attribute.getValue());
+            default:
                 return null;
-            }
         }
     }
 
@@ -365,21 +366,29 @@ public class ObjAttributeTableModel extends CayenneTableModel<ObjAttributeWrappe
         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) {
+        switch (column) {
+            case OBJ_ATTRIBUTE:
+                event.setOldName(attribute.getName());
+                setObjAttribute(attribute, value);
+                fireTableCellUpdated(row, column);
+                break;
+            case OBJ_ATTRIBUTE_TYPE:
+                setObjAttributeType(attribute, value);
+                fireTableCellUpdated(row, column);
+                break;
+            case LOCKING:
+                setColumnLocking(attribute, value);
+                fireTableCellUpdated(row, column);
+                break;
+            case DB_ATTRIBUTE:
                 setDbAttribute(attribute, value);
-            }
-            fireTableRowsUpdated(row, row);
+                fireTableRowsUpdated(row, row);
+                break;
+            case COMMENT:
+                setComment((String)value, attribute.getValue());
+            default:
+                fireTableRowsUpdated(row, row);
+                break;
         }
         mediator.fireObjAttributeEvent(event);
     }
@@ -490,6 +499,13 @@ public class ObjAttributeTableModel extends CayenneTableModel<ObjAttributeWrappe
         }
     }
 
+    private String getComment(ObjAttribute attr) {
+        return ObjectInfo.getFromMetaData(mediator.getApplication().getMetaData(), attr, ObjectInfo.COMMENT);
+    }
+
+    private void setComment(String newVal, ObjAttribute attr) {
+        ObjectInfo.putToMetaData(mediator.getApplication().getMetaData(), attr, ObjectInfo.COMMENT, newVal);
+    }
 
     @Override
     public boolean isColumnSortable(int sortCol) {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjCallbackMethod.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjCallbackMethod.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjCallbackMethod.java
index ddac69d..bfed494 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjCallbackMethod.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjCallbackMethod.java
@@ -38,10 +38,7 @@ public class ObjCallbackMethod implements XMLSerializable,
 	@Override
 	public void encodeAsXML(XMLEncoder encoder, ConfigurationNodeVisitor delegate) {
 
-        encoder.print("<" + encodeCallbackTypeForXML(callbackType));
-        encoder.print(" name=\"" + getName());
-
-        encoder.println("\"/>");
+        encoder.start( encodeCallbackTypeForXML(callbackType)).attribute( name, getName()).end();
 	}
 
 	private String encodeCallbackTypeForXML(CallbackType type) {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityTab.java
index d67437b..1b2b18c 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityTab.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityTab.java
@@ -70,6 +70,8 @@ import org.apache.cayenne.modeler.util.Comparators;
 import org.apache.cayenne.modeler.util.ExpressionConvertor;
 import org.apache.cayenne.modeler.util.TextAdapter;
 import org.apache.cayenne.modeler.util.combo.AutoCompletion;
+import org.apache.cayenne.project.extension.info.ObjectInfo;
+import org.apache.cayenne.util.CayenneMapEntry;
 import org.apache.cayenne.util.Util;
 import org.apache.cayenne.validation.ValidationException;
 import org.apache.commons.collections.CollectionUtils;
@@ -97,8 +99,6 @@ public class ObjEntityTab extends JPanel implements ObjEntityDisplayListener, Ex
     protected JButton tableLabel;
     protected JCheckBox readOnly;
     protected JCheckBox optimisticLocking;
-    protected JCheckBox excludeSuperclassListeners;
-    protected JCheckBox excludeDefaultListeners;
 
     protected JComponent clientSeparator;
     protected JLabel isAbstractLabel;
@@ -108,6 +108,7 @@ public class ObjEntityTab extends JPanel implements ObjEntityDisplayListener, Ex
 
     protected JCheckBox serverOnly;
     protected JCheckBox isAbstract;
+    protected TextAdapter comment;
     protected TextAdapter clientClassName;
     protected TextAdapter clientSuperClassName;
 
@@ -170,8 +171,6 @@ public class ObjEntityTab extends JPanel implements ObjEntityDisplayListener, Ex
         readOnly = new JCayenneCheckBox();
 
         optimisticLocking = new JCayenneCheckBox();
-        excludeSuperclassListeners = new JCayenneCheckBox();
-        excludeDefaultListeners = new JCayenneCheckBox();
 
         // borderless clickable button used as a label
         tableLabel = new JButton("Table/View:");
@@ -184,6 +183,13 @@ public class ObjEntityTab extends JPanel implements ObjEntityDisplayListener, Ex
 
         isAbstract = new JCayenneCheckBox();
         serverOnly = new JCayenneCheckBox();
+
+        comment = new TextAdapter(new JTextField()) {
+            @Override
+            protected void updateModel(String text) throws ValidationException {
+                setComment(text);
+            }
+        };
         clientClassName = new TextAdapter(new JTextField()) {
             @Override
             protected void updateModel(String text) {
@@ -207,6 +213,7 @@ public class ObjEntityTab extends JPanel implements ObjEntityDisplayListener, Ex
         builder.append("Inheritance:", superEntityCombo);
         builder.append(tableLabel, dbEntityCombo);
         isAbstractLabel = builder.append("Abstract class:", isAbstract);
+        builder.append("Comment:", comment.getComponent());
         builder.appendSeparator();
 
         builder.append("Java Class:", className.getComponent());
@@ -215,9 +222,6 @@ public class ObjEntityTab extends JPanel implements ObjEntityDisplayListener, Ex
         builder.append("Qualifier:", qualifier.getComponent());
         builder.append("Read-Only:", readOnly);
         builder.append("Optimistic Locking:", optimisticLocking);
-        // add callback-related stuff
-        builder.append("Exclude superclass listeners:", excludeSuperclassListeners);
-        builder.append("Exclude default listeners:", excludeDefaultListeners);
 
         clientSeparator = builder.appendSeparator("Java Client");
         serverOnlyLabel = builder.append("Not for Client Use:", serverOnly);
@@ -349,32 +353,7 @@ public class ObjEntityTab extends JPanel implements ObjEntityDisplayListener, Ex
             }
         });
 
-        excludeSuperclassListeners.addItemListener(new ItemListener() {
-
-            @Override
-            public void itemStateChanged(ItemEvent e) {
-                ObjEntity entity = mediator.getCurrentObjEntity();
-                if (entity != null) {
-                    entity.setExcludingSuperclassListeners(excludeSuperclassListeners.isSelected());
-                    mediator.fireObjEntityEvent(new EntityEvent(this, entity));
-                }
-            }
-        });
-
-        excludeDefaultListeners.addItemListener(new ItemListener() {
-
-            @Override
-            public void itemStateChanged(ItemEvent e) {
-                ObjEntity entity = mediator.getCurrentObjEntity();
-                if (entity != null) {
-                    entity.setExcludingDefaultListeners(excludeDefaultListeners.isSelected());
-                    mediator.fireObjEntityEvent(new EntityEvent(this, entity));
-                }
-            }
-        });
-
         serverOnly.addItemListener(new ItemListener() {
-
             @Override
             public void itemStateChanged(ItemEvent e) {
                 ObjEntity entity = mediator.getCurrentObjEntity();
@@ -415,6 +394,7 @@ public class ObjEntityTab extends JPanel implements ObjEntityDisplayListener, Ex
         readOnly.setSelected(entity.isReadOnly());
 
         isAbstract.setSelected(entity.isAbstract());
+        comment.setText(getComment(entity));
         serverOnly.setSelected(entity.isServerOnly());
         clientClassName.setText(entity.getClientClassName());
         clientSuperClassName.setText(entity.getClientSuperClassName());
@@ -425,8 +405,6 @@ public class ObjEntityTab extends JPanel implements ObjEntityDisplayListener, Ex
         // lock if superclass is not already locked,
         // otherwise we must keep this checked in but not editable.
         optimisticLocking.setSelected(entity.getDeclaredLockType() == ObjEntity.LOCK_TYPE_OPTIMISTIC);
-        excludeSuperclassListeners.setSelected(entity.isExcludingSuperclassListeners());
-        excludeDefaultListeners.setSelected(entity.isExcludingDefaultListeners());
 
         // init DbEntities
         EntityResolver resolver = mediator.getEntityResolver();
@@ -638,4 +616,18 @@ public class ObjEntityTab extends JPanel implements ObjEntityDisplayListener, Ex
         return result;
     }
 
+    private void setComment(String value) {
+        ObjEntity entity = mediator.getCurrentObjEntity();
+        if (entity == null) {
+            return;
+        }
+
+        ObjectInfo.putToMetaData(mediator.getApplication().getMetaData(), entity, ObjectInfo.COMMENT, value);
+        mediator.fireObjEntityEvent(new EntityEvent(this, entity));
+    }
+
+    private String getComment(ObjEntity entity) {
+        return ObjectInfo.getFromMetaData(mediator.getApplication().getMetaData(), entity, ObjectInfo.COMMENT);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/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 db7668a..4eba868 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
@@ -24,6 +24,7 @@ import org.apache.cayenne.map.event.RelationshipEvent;
 import org.apache.cayenne.modeler.ProjectController;
 import org.apache.cayenne.modeler.util.CayenneTableModel;
 import org.apache.cayenne.modeler.util.ProjectUtil;
+import org.apache.cayenne.project.extension.info.ObjectInfo;
 import org.apache.cayenne.util.Util;
 
 import java.util.ArrayList;
@@ -43,7 +44,8 @@ public class ObjRelationshipTableModel extends CayenneTableModel<ObjRelationship
     public static final int REL_SEMANTICS = 3;
     public static final int REL_DELETE_RULE = 4;
     public static final int REL_LOCKING = 5;
-    public static final int COLUMN_COUNT = 6;
+    public static final int REL_COMMENT = 6;
+    public static final int COLUMN_COUNT = 7;
 
     private ObjEntity entity;
 
@@ -86,6 +88,8 @@ public class ObjRelationshipTableModel extends CayenneTableModel<ObjRelationship
                 return "Delete Rule";
             case REL_TARGET_PATH:
                 return "DbRelationship Path";
+            case REL_COMMENT:
+                return "Comment";
             default:
                 return null;
         }
@@ -110,20 +114,23 @@ public class ObjRelationshipTableModel extends CayenneTableModel<ObjRelationship
     public Object getValueAt(int row, int column) {
         ObjRelationship relationship = getRelationship(row);
 
-        if (column == REL_NAME) {
-            return relationship.getName();
-        } else if (column == REL_TARGET) {
-            return relationship.getTargetEntity();
-        } else if (column == REL_LOCKING) {
-            return relationship.isUsedForLocking() ? Boolean.TRUE : Boolean.FALSE;
-        } else if (column == REL_SEMANTICS) {
-            return getSemantics(relationship);
-        } else if (column == REL_DELETE_RULE) {
-            return DeleteRule.deleteRuleName(relationship.getDeleteRule());
-        } else if (column == REL_TARGET_PATH) {
-            return relationship.getDbRelationshipPath();
-        } else {
-            return null;
+        switch (column) {
+            case REL_NAME:
+                return relationship.getName();
+            case REL_TARGET:
+                return relationship.getTargetEntity();
+            case REL_LOCKING:
+                return relationship.isUsedForLocking() ? Boolean.TRUE : Boolean.FALSE;
+            case REL_SEMANTICS:
+                return getSemantics(relationship);
+            case REL_DELETE_RULE:
+                return DeleteRule.deleteRuleName(relationship.getDeleteRule());
+            case REL_TARGET_PATH:
+                return relationship.getDbRelationshipPath();
+            case REL_COMMENT:
+                return getComment(relationship);
+            default:
+                return null;
         }
     }
 
@@ -153,41 +160,50 @@ public class ObjRelationshipTableModel extends CayenneTableModel<ObjRelationship
         ObjRelationship relationship = getRelationship(row);
         RelationshipEvent event = new RelationshipEvent(eventSource, relationship, entity);
 
-        if (column == REL_NAME) {
-            String text = (String) value;
-            event.setOldName(relationship.getName());
-            ProjectUtil.setRelationshipName(entity, relationship, text);
-            fireTableCellUpdated(row, column);
-        } 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 = relationship.getSourceEntity()
-                        .getDbEntity();
-                DbEntity targetDB = target.getDbEntity();
-                if (srcDB != null && targetDB != null) {
-                    Relationship anyConnector = srcDB.getAnyRelationship(targetDB);
-                    if (anyConnector != null) {
-                        relationship.addDbRelationship((DbRelationship) anyConnector);
+        switch (column) {
+            case REL_NAME:
+                String text = (String) value;
+                event.setOldName(relationship.getName());
+                ProjectUtil.setRelationshipName(entity, relationship, text);
+                fireTableCellUpdated(row, column);
+                break;
+            case 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 = relationship.getSourceEntity()
+                            .getDbEntity();
+                    DbEntity targetDB = target.getDbEntity();
+                    if (srcDB != null && targetDB != null) {
+                        Relationship anyConnector = srcDB.getAnyRelationship(targetDB);
+                        if (anyConnector != null) {
+                            relationship.addDbRelationship((DbRelationship) anyConnector);
+                        }
                     }
                 }
-            }
 
-            fireTableRowsUpdated(row, row);
-        } else if (column == REL_DELETE_RULE) {
-            relationship.setDeleteRule(DeleteRule.deleteRuleForName((String) value));
-            fireTableCellUpdated(row, column);
-        } else if (column == REL_LOCKING) {
-            relationship.setUsedForLocking((value instanceof Boolean) && (Boolean) value);
-            fireTableCellUpdated(row, column);
-        } else if (column == REL_TARGET_PATH) {
-            relationship.setDbRelationshipPath((String) value);
-            fireTableCellUpdated(row, column);
+                fireTableRowsUpdated(row, row);
+                break;
+            case REL_DELETE_RULE:
+                relationship.setDeleteRule(DeleteRule.deleteRuleForName((String) value));
+                fireTableCellUpdated(row, column);
+                break;
+            case REL_LOCKING:
+                relationship.setUsedForLocking((value instanceof Boolean) && (Boolean) value);
+                fireTableCellUpdated(row, column);
+                break;
+            case REL_TARGET_PATH:
+                relationship.setDbRelationshipPath((String) value);
+                fireTableCellUpdated(row, column);
+            case REL_COMMENT:
+                setComment((String)value, relationship);
+                fireTableRowsUpdated(row, row);
+                break;
         }
 
         mediator.fireObjRelationshipEvent(event);
@@ -297,4 +313,12 @@ public class ObjRelationshipTableModel extends CayenneTableModel<ObjRelationship
             return value1.compareTo(value2);
         }
     }
+
+    private String getComment(ObjRelationship rel) {
+        return ObjectInfo.getFromMetaData(mediator.getApplication().getMetaData(), rel, ObjectInfo.COMMENT);
+    }
+
+    private void setComment(String newVal, ObjRelationship rel) {
+        ObjectInfo.putToMetaData(mediator.getApplication().getMetaData(), rel, ObjectInfo.COMMENT, newVal);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureQueryView.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureQueryView.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureQueryView.java
index 819583d..787f515 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureQueryView.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureQueryView.java
@@ -27,6 +27,7 @@ import org.apache.cayenne.configuration.ConfigurationNode;
 import org.apache.cayenne.configuration.event.QueryEvent;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.Procedure;
 import org.apache.cayenne.map.ProcedureQueryDescriptor;
 import org.apache.cayenne.map.QueryDescriptor;
 import org.apache.cayenne.modeler.Application;
@@ -37,6 +38,7 @@ import org.apache.cayenne.modeler.util.CellRenderers;
 import org.apache.cayenne.modeler.util.Comparators;
 import org.apache.cayenne.modeler.util.ProjectUtil;
 import org.apache.cayenne.modeler.util.TextAdapter;
+import org.apache.cayenne.project.extension.info.ObjectInfo;
 import org.apache.cayenne.query.CapsStrategy;
 import org.apache.cayenne.query.ProcedureQuery;
 import org.apache.cayenne.util.Util;
@@ -72,7 +74,8 @@ public class ProcedureQueryView extends JPanel {
 
     protected ProjectController mediator;
     protected TextAdapter name;
-    protected JComboBox<ConfigurationNode> queryRoot;
+    protected TextAdapter comment;
+    protected JComboBox<Procedure> queryRoot;
     protected SelectPropertiesPanel properties;
 
     public ProcedureQueryView(ProjectController mediator) {
@@ -85,13 +88,19 @@ public class ProcedureQueryView extends JPanel {
     private void initView() {
         // create widgets
         name = new TextAdapter(new JTextField()) {
-
             @Override
             protected void updateModel(String text) {
                 setQueryName(text);
             }
         };
 
+        comment = new TextAdapter(new JTextField()) {
+            @Override
+            protected void updateModel(String text) {
+                setQueryComment(text);
+            }
+        };
+
         queryRoot = Application.getWidgetFactory().createUndoableComboBox();
         queryRoot.setRenderer(CellRenderers.listRendererWithIcons());
         properties = new ProcedureQueryPropertiesPanel(mediator);
@@ -100,7 +109,7 @@ public class ProcedureQueryView extends JPanel {
         CellConstraints cc = new CellConstraints();
         FormLayout layout = new FormLayout(
                 "right:max(80dlu;pref), 3dlu, fill:max(200dlu;pref)",
-                "p, 3dlu, p, 3dlu, p");
+                "p, 3dlu, p, 3dlu, p, 3dlu, p");
         PanelBuilder builder = new PanelBuilder(layout);
         builder.setDefaultDialogBorder();
 
@@ -109,6 +118,8 @@ public class ProcedureQueryView extends JPanel {
         builder.add(name.getComponent(), cc.xy(3, 3));
         builder.addLabel("Procedure:", cc.xy(1, 5));
         builder.add(queryRoot, cc.xy(3, 5));
+        builder.addLabel("Comment:", cc.xy(1, 7));
+        builder.add(comment.getComponent(), cc.xy(3, 7));
 
         this.setLayout(new BorderLayout());
         this.add(builder.getPanel(), BorderLayout.NORTH);
@@ -150,6 +161,7 @@ public class ProcedureQueryView extends JPanel {
 
         properties.setEnabled(true);
         name.setText(query.getName());
+        comment.setText(getQueryComment(query));
 
         // init root choices and title label..
 
@@ -160,13 +172,13 @@ public class ProcedureQueryView extends JPanel {
         // making it impossible to reference other DataMaps.
 
         DataMap map = mediator.getCurrentDataMap();
-        ConfigurationNode[] roots = map.getProcedures().toArray(new ConfigurationNode[0]);
+        Procedure[] roots = map.getProcedures().toArray(new Procedure[0]);
 
         if (roots.length > 1) {
             Arrays.sort(roots, Comparators.getDataMapChildrenComparator());
         }
 
-        DefaultComboBoxModel<ConfigurationNode> model = new DefaultComboBoxModel<>(roots);
+        DefaultComboBoxModel<Procedure> model = new DefaultComboBoxModel<>(roots);
         model.setSelectedItem(query.getRoot());
         queryRoot.setModel(model);
 
@@ -202,12 +214,9 @@ public class ProcedureQueryView extends JPanel {
             QueryEvent e = new QueryEvent(this, query, query.getName(), map);
             ProjectUtil.setQueryName(map, query, newName);
             mediator.fireQueryEvent(e);
-        }
-        else {
+        } else {
             // there is a query with the same name
-            throw new ValidationException("There is another query named '"
-                    + newName
-                    + "'. Use a different name.");
+            throw new ValidationException("There is another query named '" + newName + "'. Use a different name.");
         }
     }
 
@@ -236,6 +245,19 @@ public class ProcedureQueryView extends JPanel {
         }
     }
 
+    private void setQueryComment(String text) {
+        QueryDescriptor query = mediator.getCurrentQuery();
+        if (query == null) {
+            return;
+        }
+        ObjectInfo.putToMetaData(mediator.getApplication().getMetaData(), query, ObjectInfo.COMMENT, text);
+        mediator.fireQueryEvent(new QueryEvent(this, query));
+    }
+
+    private String getQueryComment(QueryDescriptor queryDescriptor) {
+        return ObjectInfo.getFromMetaData(mediator.getApplication().getMetaData(), queryDescriptor, ObjectInfo.COMMENT);
+    }
+
     final class LabelCapsRenderer extends DefaultListCellRenderer {
 
         public Component getListCellRendererComponent(

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureTab.java
index a9fa92e..57b2f61 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureTab.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureTab.java
@@ -25,7 +25,6 @@ import java.awt.event.ItemListener;
 import java.util.EventObject;
 
 import javax.swing.JCheckBox;
-import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JTextField;
 
@@ -38,6 +37,7 @@ import org.apache.cayenne.modeler.event.ProcedureDisplayEvent;
 import org.apache.cayenne.modeler.event.ProcedureDisplayListener;
 import org.apache.cayenne.modeler.util.ProjectUtil;
 import org.apache.cayenne.modeler.util.TextAdapter;
+import org.apache.cayenne.project.extension.info.ObjectInfo;
 import org.apache.cayenne.util.Util;
 import org.apache.cayenne.validation.ValidationException;
 
@@ -45,9 +45,7 @@ import com.jgoodies.forms.builder.DefaultFormBuilder;
 import com.jgoodies.forms.layout.FormLayout;
 
 /**
- * A panel for editing stored procedure general settings, such as name, schema,
- * etc.
- * 
+ * A panel for editing stored procedure general settings, such as name, schema, etc.
  */
 public class ProcedureTab extends JPanel implements ProcedureDisplayListener, ExistingSelectionProcessor {
 
@@ -55,6 +53,7 @@ public class ProcedureTab extends JPanel implements ProcedureDisplayListener, Ex
     protected TextAdapter name;
     protected TextAdapter schema;
     protected TextAdapter catalog;
+    protected TextAdapter comment;
     protected JCheckBox returnsValue;
     protected boolean ignoreChange;
 
@@ -69,31 +68,35 @@ public class ProcedureTab extends JPanel implements ProcedureDisplayListener, Ex
         // create widgets
 
         this.name = new TextAdapter(new JTextField()) {
-
+            @Override
             protected void updateModel(String text) {
                 setProcedureName(text);
             }
         };
 
         this.schema = new TextAdapter(new JTextField()) {
-
+            @Override
             protected void updateModel(String text) {
                 setSchema(text);
             }
         };
 
         this.catalog = new TextAdapter(new JTextField()) {
-
+            @Override
             protected void updateModel(String text) {
                 setCatalog(text);
             }
         };
 
-        JLabel returnValueHelp = new JLabel("(first parameter will be used as return value)");
-        returnValueHelp.setFont(returnValueHelp.getFont().deriveFont(10));
+        this.comment = new TextAdapter(new JTextField()) {
+            @Override
+            protected void updateModel(String text) {
+                setComment(text);
+            }
+        };
 
         this.returnsValue = new JCayenneCheckBox();
-        this.returnsValue.setToolTipText(returnValueHelp.getText());
+        this.returnsValue.setToolTipText("first parameter will be used as return value");
 
         FormLayout layout = new FormLayout("right:pref, 3dlu, fill:200dlu", "");
         DefaultFormBuilder builder = new DefaultFormBuilder(layout);
@@ -104,6 +107,7 @@ public class ProcedureTab extends JPanel implements ProcedureDisplayListener, Ex
         builder.append("Catalog:", catalog.getComponent());
         builder.append("Schema:", schema.getComponent());
         builder.append("Returns Value:", returnsValue);
+        builder.append("Comment:", comment.getComponent());
 
         this.setLayout(new BorderLayout());
         this.add(builder.getPanel(), BorderLayout.CENTER);
@@ -142,6 +146,7 @@ public class ProcedureTab extends JPanel implements ProcedureDisplayListener, Ex
         name.setText(procedure.getName());
         schema.setText(procedure.getSchema());
         catalog.setText(procedure.getCatalog());
+        comment.setText(getComment(procedure));
 
         ignoreChange = true;
         returnsValue.setSelected(procedure.isReturningValue());
@@ -197,4 +202,19 @@ public class ProcedureTab extends JPanel implements ProcedureDisplayListener, Ex
             eventController.fireProcedureEvent(new ProcedureEvent(this, procedure));
         }
     }
+
+    void setComment(String comment) {
+        Procedure procedure = eventController.getCurrentProcedure();
+
+        if (procedure == null) {
+            return;
+        }
+
+        ObjectInfo.putToMetaData(eventController.getApplication().getMetaData(), procedure, ObjectInfo.COMMENT, comment);
+        eventController.fireProcedureEvent(new ProcedureEvent(this, procedure));
+    }
+
+    String getComment(Procedure procedure) {
+        return ObjectInfo.getFromMetaData(eventController.getApplication().getMetaData(), procedure, ObjectInfo.COMMENT);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateMainTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateMainTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateMainTab.java
index 4433c53..387391c 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateMainTab.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateMainTab.java
@@ -31,6 +31,7 @@ import org.apache.cayenne.modeler.Application;
 import org.apache.cayenne.modeler.ProjectController;
 import org.apache.cayenne.modeler.util.ProjectUtil;
 import org.apache.cayenne.modeler.util.TextAdapter;
+import org.apache.cayenne.project.extension.info.ObjectInfo;
 import org.apache.cayenne.query.CapsStrategy;
 import org.apache.cayenne.query.SQLTemplate;
 import org.apache.cayenne.util.Util;
@@ -67,6 +68,7 @@ public class SQLTemplateMainTab extends JPanel {
 
     protected ProjectController mediator;
     protected TextAdapter name;
+    protected TextAdapter comment;
     protected SelectPropertiesPanel properties;
 
     public SQLTemplateMainTab(ProjectController mediator) {
@@ -78,25 +80,34 @@ public class SQLTemplateMainTab extends JPanel {
     private void initView() {
         // create widgets
         name = new TextAdapter(new JTextField()) {
-
+            @Override
             protected void updateModel(String text) {
                 setQueryName(text);
             }
         };
 
+        comment = new TextAdapter(new JTextField()) {
+            @Override
+            protected void updateModel(String text) {
+                setQueryComment(text);
+            }
+        };
+
         properties = new SQLTemplateQueryPropertiesPanel(mediator);
 
         // assemble
         CellConstraints cc = new CellConstraints();
         FormLayout layout = new FormLayout(
                 "right:max(80dlu;pref), 3dlu, fill:max(200dlu;pref)",
-                "p, 3dlu, p");
+                "p, 3dlu, p, 3dlu, p");
         PanelBuilder builder = new PanelBuilder(layout);
         builder.setDefaultDialogBorder();
 
         builder.addSeparator("SQLTemplate Settings", cc.xywh(1, 1, 3, 1));
         builder.addLabel("Query Name:", cc.xy(1, 3));
         builder.add(name.getComponent(), cc.xy(3, 3));
+        builder.addLabel("Comment:", cc.xy(1, 5));
+        builder.add(comment.getComponent(), cc.xy(3, 5));
 
         this.setLayout(new BorderLayout());
         this.add(builder.getPanel(), BorderLayout.NORTH);
@@ -117,6 +128,7 @@ public class SQLTemplateMainTab extends JPanel {
 
         name.setText(query.getName());
         properties.initFromModel(query);
+        comment.setText(getQueryComment(query));
 
         setVisible(true);
     }
@@ -183,6 +195,19 @@ public class SQLTemplateMainTab extends JPanel {
         }
     }
 
+    private void setQueryComment(String text) {
+        QueryDescriptor query = getQuery();
+        if (query == null) {
+            return;
+        }
+        ObjectInfo.putToMetaData(mediator.getApplication().getMetaData(), query, ObjectInfo.COMMENT, text);
+        mediator.fireQueryEvent(new QueryEvent(this, query));
+    }
+
+    private String getQueryComment(QueryDescriptor queryDescriptor) {
+        return ObjectInfo.getFromMetaData(mediator.getApplication().getMetaData(), queryDescriptor, ObjectInfo.COMMENT);
+    }
+
     final class LabelCapsRenderer extends DefaultListCellRenderer {
 
         public Component getListCellRendererComponent(

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java
index a8a0d63..e68d17a 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java
@@ -54,6 +54,7 @@ import org.apache.cayenne.modeler.util.ProjectUtil;
 import org.apache.cayenne.modeler.util.TextAdapter;
 import org.apache.cayenne.modeler.util.ValidatorTextAdapter;
 import org.apache.cayenne.modeler.util.combo.AutoCompletion;
+import org.apache.cayenne.project.extension.info.ObjectInfo;
 import org.apache.cayenne.query.*;
 import org.apache.cayenne.util.CayenneMapEntry;
 import org.apache.cayenne.util.Util;
@@ -72,6 +73,7 @@ public class SelectQueryMainTab extends JPanel {
     protected ProjectController mediator;
 
     protected TextAdapter name;
+    protected TextAdapter comment;
     protected JComboBox<ObjEntity> queryRoot;
     protected TextAdapter qualifier;
     protected JCheckBox distinct;
@@ -111,6 +113,13 @@ public class SelectQueryMainTab extends JPanel {
             }
         };
 
+        comment = new TextAdapter(new JTextField()) {
+            @Override
+            protected void updateModel(String text) {
+                setQueryComment(text);
+            }
+        };
+
         distinct = new JCayenneCheckBox();
 
         properties = new ObjectQueryPropertiesPanel(mediator);
@@ -119,7 +128,7 @@ public class SelectQueryMainTab extends JPanel {
         CellConstraints cc = new CellConstraints();
         FormLayout layout = new FormLayout(
                 "right:max(80dlu;pref), 3dlu, fill:200dlu",
-                "p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p");
+                "p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p");
         PanelBuilder builder = new PanelBuilder(layout);
         builder.setDefaultDialogBorder();
 
@@ -132,6 +141,8 @@ public class SelectQueryMainTab extends JPanel {
         builder.add(qualifier.getComponent(), cc.xy(3, 7));
         builder.addLabel("Distinct:", cc.xy(1, 9));
         builder.add(distinct, cc.xy(3, 9));
+        builder.addLabel("Comment:", cc.xy(1, 11));
+        builder.add(comment.getComponent(), cc.xy(3, 11));
 
         this.setLayout(new BorderLayout());
         this.add(builder.getPanel(), BorderLayout.NORTH);
@@ -178,6 +189,7 @@ public class SelectQueryMainTab extends JPanel {
         qualifier.setText(query.getQualifier() != null ? query
                 .getQualifier()
                 .toString() : null);
+        comment.setText(getQueryComment(query));
 
         // init root choices and title label..
 
@@ -409,4 +421,17 @@ public class SelectQueryMainTab extends JPanel {
             return name.getComponent().getText().startsWith(prefix);
         }
     }
+
+    private void setQueryComment(String text) {
+        QueryDescriptor query = getQuery();
+        if (query == null) {
+            return;
+        }
+        ObjectInfo.putToMetaData(mediator.getApplication().getMetaData(), query, ObjectInfo.COMMENT, text);
+        mediator.fireQueryEvent(new QueryEvent(this, query));
+    }
+
+    private String getQueryComment(QueryDescriptor queryDescriptor) {
+        return ObjectInfo.getFromMetaData(mediator.getApplication().getMetaData(), queryDescriptor, ObjectInfo.COMMENT);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbAttributeTableModel.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbAttributeTableModel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbAttributeTableModel.java
index 66451fd..c53be29 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbAttributeTableModel.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbAttributeTableModel.java
@@ -37,13 +37,12 @@ import org.apache.cayenne.modeler.Application;
 import org.apache.cayenne.modeler.ProjectController;
 import org.apache.cayenne.modeler.util.CayenneTableModel;
 import org.apache.cayenne.modeler.util.ProjectUtil;
+import org.apache.cayenne.project.extension.info.ObjectInfo;
 
 /**
- * Model for DbEntity attributes. Allows adding/removing attributes, modifying types and
- * names.
- * 
+ * Model for DbEntity attributes. Allows adding/removing attributes, modifying types and names.
  */
-public class DbAttributeTableModel extends CayenneTableModel {
+public class DbAttributeTableModel extends CayenneTableModel<DbAttribute> {
 
     // Columns
     private static final int DB_ATTRIBUTE_NAME = 0;
@@ -52,13 +51,13 @@ public class DbAttributeTableModel extends CayenneTableModel {
     private static final int DB_ATTRIBUTE_MANDATORY = 3;
     private static final int DB_ATTRIBUTE_MAX = 4;
     private static final int DB_ATTRIBUTE_SCALE = 5;
+    private static final int DB_ATTRIBUTE_COMMENT = 6;
 
     protected DbEntity entity;
 
     public DbAttributeTableModel(DbEntity entity, ProjectController mediator,
             Object eventSource) {
-        this(entity, mediator, eventSource, new ArrayList<DbAttribute>(entity
-                .getAttributes()));
+        this(entity, mediator, eventSource, new ArrayList<>(entity.getAttributes()));
         this.entity = entity;
     }
 
@@ -91,7 +90,7 @@ public class DbAttributeTableModel extends CayenneTableModel {
      * Returns the number of columns in the table.
      */
     public int getColumnCount() {
-        return 6;
+        return 7;
     }
 
     public DbAttribute getAttribute(int row) {
@@ -114,6 +113,8 @@ public class DbAttributeTableModel extends CayenneTableModel {
                 return "Mandatory";
             case DB_ATTRIBUTE_MAX:
                 return "Max Length";
+            case DB_ATTRIBUTE_COMMENT:
+                return "Comment";
             default:
                 return "";
         }
@@ -150,6 +151,8 @@ public class DbAttributeTableModel extends CayenneTableModel {
                 return isMandatory(attr);
             case DB_ATTRIBUTE_MAX:
                 return getMaxLength(attr);
+            case DB_ATTRIBUTE_COMMENT:
+                return getComment(attr);
             default:
                 return "";
         }
@@ -167,7 +170,7 @@ public class DbAttributeTableModel extends CayenneTableModel {
             case DB_ATTRIBUTE_NAME:
                 e.setOldName(attr.getName());
                 attr.setName((String) newVal);
-                ((DbEntity) attr.getEntity()).dbAttributeChanged(e);
+                attr.getEntity().dbAttributeChanged(e);
                 
                 fireTableCellUpdated(row, col);
                 break;
@@ -188,6 +191,9 @@ public class DbAttributeTableModel extends CayenneTableModel {
             case DB_ATTRIBUTE_MAX:
                 setMaxLength((String) newVal, attr);
                 break;
+            case DB_ATTRIBUTE_COMMENT:
+                setComment((String) newVal, attr);
+                break;
         }
 
         mediator.fireDbAttributeEvent(e);
@@ -217,21 +223,22 @@ public class DbAttributeTableModel extends CayenneTableModel {
         return (attr.isMandatory()) ? Boolean.TRUE : Boolean.FALSE;
     }
 
+    public String getComment(DbAttribute attr) {
+        return ObjectInfo.getFromMetaData(mediator.getApplication().getMetaData(), attr, ObjectInfo.COMMENT);
+    }
+
     public void setMaxLength(String newVal, DbAttribute attr) {
         if (newVal == null || newVal.trim().length() <= 0) {
             attr.setMaxLength(-1);
-        }
-        else {
+        } else {
             try {
                 attr.setMaxLength(Integer.parseInt(newVal));
-            }
-            catch (NumberFormatException ex) {
+            } catch (NumberFormatException ex) {
                 JOptionPane.showMessageDialog(
                         null,
                         "Invalid Max Length (" + newVal + "), only numbers are allowed",
                         "Invalid Maximum Length",
                         JOptionPane.ERROR_MESSAGE);
-                return;
             }
         }
     }
@@ -243,12 +250,10 @@ public class DbAttributeTableModel extends CayenneTableModel {
     public void setScale(String newVal, DbAttribute attr) {
         if (newVal == null || newVal.trim().length() <= 0) {
             attr.setScale(-1);
-        }
-        else {
+        } else {
             try {
                 attr.setScale(Integer.parseInt(newVal));
-            }
-            catch (NumberFormatException ex) {
+            } catch (NumberFormatException ex) {
                 JOptionPane.showMessageDialog(
                         null,
                         "Invalid precision (" + newVal + "), only numbers are allowed.",
@@ -260,7 +265,7 @@ public class DbAttributeTableModel extends CayenneTableModel {
 
     public boolean setPrimaryKey(Boolean newVal, DbAttribute attr, int row) {
 
-        boolean flag = newVal.booleanValue();
+        boolean flag = newVal;
 
         // when PK is unset, we need to fix some derived flags
         if (!flag) {
@@ -285,9 +290,8 @@ public class DbAttributeTableModel extends CayenneTableModel {
                 if (relationships.size() > 0) {
                     String message = (relationships.size() == 1)
                             ? "Fix \"To Dep PK\" relationship using this attribute?"
-                            : "Fix "
-                                    + relationships.size()
-                                    + " \"To Dep PK\" relationships using this attribute?";
+                            : "Fix " + relationships.size()
+                                     + " \"To Dep PK\" relationships using this attribute?";
 
                     int answer = JOptionPane.showConfirmDialog(
                             Application.getFrame(),
@@ -314,19 +318,22 @@ public class DbAttributeTableModel extends CayenneTableModel {
     }
 
     public void setMandatory(Boolean newVal, DbAttribute attr) {
-        attr.setMandatory(newVal.booleanValue());
+        attr.setMandatory(newVal);
     }
 
     public void setGenerated(Boolean newVal, DbAttribute attr) {
-        attr.setGenerated(newVal.booleanValue());
+        attr.setGenerated(newVal);
+    }
+
+    public void setComment(String newVal, DbAttribute attr) {
+        ObjectInfo.putToMetaData(mediator.getApplication().getMetaData(), attr, ObjectInfo.COMMENT, newVal);
     }
 
     public boolean isCellEditable(int row, int col) {
         DbAttribute attrib = getAttribute(row);
         if (null == attrib) {
             return false;
-        }
-        else if (col == mandatoryColumnInd()) {
+        } else if (col == mandatoryColumnInd()) {
             if (attrib.isPrimaryKey()) {
                 return false;
             }
@@ -336,7 +343,7 @@ public class DbAttributeTableModel extends CayenneTableModel {
 
     @Override
     public boolean isColumnSortable(int sortCol) {
-        return true;
+        return sortCol != DB_ATTRIBUTE_COMMENT;
     }
 
     @Override
@@ -351,20 +358,17 @@ public class DbAttributeTableModel extends CayenneTableModel {
                     public int compare(DbAttribute o1, DbAttribute o2) {
                         if ((o1 == null && o2 == null) || o1 == o2) {
                             return 0;
-                        }
-                        else if (o1 == null && o2 != null) {
+                        } else if (o1 == null) {
                             return -1;
-                        }
-                        else if (o1 != null && o2 == null) {
+                        } else if (o2 == null) {
                             return 1;
                         }
                         
                         String attrType1 = getAttributeType(o1);
                         String attrType2 = getAttributeType(o2);
                         
-                        return (attrType1 == null) ? -1 : (attrType2 == null)
-                                ? 1
-                                : attrType1.compareTo(attrType2);
+                        return (attrType1 == null) ? -1
+                                : (attrType2 == null) ? 1 : attrType1.compareTo(attrType2);
                     }
 
                 });

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityAttributePanel.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityAttributePanel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityAttributePanel.java
index 337ebe7..82deb69 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityAttributePanel.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityAttributePanel.java
@@ -140,7 +140,7 @@ public class DbEntityAttributePanel extends JPanel implements DbEntityDisplayLis
     public void dbAttributeRemoved(AttributeEvent e) {
         DbAttributeTableModel model = (DbAttributeTableModel) table.getModel();
         int ind = model.getObjectList().indexOf(e.getAttribute());
-        model.removeRow(e.getAttribute());
+        model.removeRow((DbAttribute) e.getAttribute());
         table.select(ind);
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipPanel.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipPanel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipPanel.java
index ca25022..0e3a4f5 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipPanel.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipPanel.java
@@ -93,7 +93,7 @@ public class DbEntityRelationshipPanel extends JPanel implements DbEntityDisplay
     /**
      * Combo to edit 'target' field
      */
-    protected JComboBox targetCombo;
+    protected JComboBox<DbEntity> targetCombo;
 
     public DbEntityRelationshipPanel(ProjectController mediator, DbEntityAttributeRelationshipTab parentPanel) {
         this.mediator = mediator;
@@ -165,10 +165,9 @@ public class DbEntityRelationshipPanel extends JPanel implements DbEntityDisplay
     }
 
     public void tableChanged(TableModelEvent e) {
-        DbRelationship rel = null;
         if (table.getSelectedRow() >= 0) {
             DbRelationshipTableModel model = (DbRelationshipTableModel) table.getModel();
-            rel = model.getRelationship(table.getSelectedRow());
+            DbRelationship rel = model.getRelationship(table.getSelectedRow());
             enabledResolve = (rel.getTargetEntity() != null);
             resolveMenu.setEnabled(enabledResolve);
         }
@@ -232,7 +231,7 @@ public class DbEntityRelationshipPanel extends JPanel implements DbEntityDisplay
                 .setCellRenderer(new CheckBoxCellRenderer());
 
         targetCombo.setRenderer(CellRenderers.entityListRendererWithIcons(entity.getDataMap()));
-        targetCombo.setModel(createComboModel(entity));
+        targetCombo.setModel(createComboModel());
         col.setCellEditor(Application.getWidgetFactory().createCellEditor(targetCombo));
 
         tablePreferences.bind(
@@ -274,8 +273,9 @@ public class DbEntityRelationshipPanel extends JPanel implements DbEntityDisplay
 
     public void dbRelationshipRemoved(RelationshipEvent e) {
         DbRelationshipTableModel model = (DbRelationshipTableModel) table.getModel();
-        int ind = model.getObjectList().indexOf(e.getRelationship());
-        model.removeRelationship(e.getRelationship());
+        DbRelationship relationship = (DbRelationship) e.getRelationship();
+        int ind = model.getObjectList().indexOf(relationship);
+        model.removeRelationship(relationship);
         table.select(ind);
     }
 
@@ -284,15 +284,13 @@ public class DbEntityRelationshipPanel extends JPanel implements DbEntityDisplay
      * relationships were deleted.
      */
     private void reloadEntityList(EntityEvent e) {
-        if (e.getSource() == this)
+        if (e.getSource() == this
+            || mediator.getCurrentDbEntity() == e.getEntity()  // If current model added/removed, do nothing.
+            || mediator.getCurrentDbEntity() == null) { // If this is just loading new currentDbEntity, do nothing
             return;
-        // If current model added/removed, do nothing.
-        if (mediator.getCurrentDbEntity() == e.getEntity())
-            return;
-        // If this is just loading new currentDbEntity, do nothing
-        if (mediator.getCurrentDbEntity() == null)
-            return;
-        targetCombo.setModel(createComboModel(e.getEntity()));
+        }
+
+        targetCombo.setModel(createComboModel());
 
         DbRelationshipTableModel model = (DbRelationshipTableModel) table.getModel();
         model.fireTableDataChanged();
@@ -301,14 +299,10 @@ public class DbEntityRelationshipPanel extends JPanel implements DbEntityDisplay
     /**
      * Creates a list of DbEntities.
      */
-    private ComboBoxModel createComboModel(Entity entity) {
+    private ComboBoxModel<DbEntity> createComboModel() {
         EntityResolver resolver = mediator.getEntityResolver();
-        Object[] objects = resolver.getDbEntities().toArray();
-        return new DefaultComboBoxModel(objects);
-    }
-
-    public boolean isEnabledResolve() {
-        return enabledResolve;
+        DbEntity[] objects = resolver.getDbEntities().toArray(new DbEntity[0]);
+        return new DefaultComboBoxModel<>(objects);
     }
 
     public ActionListener getResolver() {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityTab.java
index d772a46..0f49f46 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityTab.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityTab.java
@@ -38,6 +38,7 @@ import org.apache.cayenne.configuration.DataChannelDescriptor;
 import org.apache.cayenne.exp.Expression;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.ObjRelationship;
 import org.apache.cayenne.map.event.EntityEvent;
 import org.apache.cayenne.modeler.Application;
 import org.apache.cayenne.modeler.ProjectController;
@@ -53,6 +54,7 @@ import org.apache.cayenne.modeler.event.EntityDisplayEvent;
 import org.apache.cayenne.modeler.graph.action.ShowGraphEntityAction;
 import org.apache.cayenne.modeler.util.ExpressionConvertor;
 import org.apache.cayenne.modeler.util.TextAdapter;
+import org.apache.cayenne.project.extension.info.ObjectInfo;
 import org.apache.cayenne.util.Util;
 import org.apache.cayenne.validation.ValidationException;
 
@@ -74,6 +76,7 @@ public class DbEntityTab extends JPanel implements ExistingSelectionProcessor, D
     protected TextAdapter catalog;
     protected TextAdapter schema;
     protected TextAdapter qualifier;
+    protected TextAdapter comment;
 
     protected JLabel catalogLabel;
     protected JLabel schemaLabel;
@@ -137,6 +140,13 @@ public class DbEntityTab extends JPanel implements ExistingSelectionProcessor, D
             }
         };
 
+        comment = new TextAdapter(new JTextField()) {
+            @Override
+            protected void updateModel(String text) throws ValidationException {
+                setComment(text);
+            }
+        };
+
         pkGeneratorType = new JComboBox<>();
         pkGeneratorType.setEditable(false);
         pkGeneratorType.setModel(new DefaultComboBoxModel<>(PK_GENERATOR_TYPES));
@@ -156,7 +166,8 @@ public class DbEntityTab extends JPanel implements ExistingSelectionProcessor, D
         builder.append("DbEntity Name:", name.getComponent());
         builder.append(catalogLabel, catalog.getComponent());
         builder.append(schemaLabel, schema.getComponent());
-        builder.append("Qualifier", qualifier.getComponent());
+        builder.append("Qualifier:", qualifier.getComponent());
+        builder.append("Comment:", comment.getComponent());
 
         builder.appendSeparator("Primary Key");
         builder.append("PK Generation Strategy:", pkGeneratorType);
@@ -218,6 +229,7 @@ public class DbEntityTab extends JPanel implements ExistingSelectionProcessor, D
         catalog.setText(entity.getCatalog());
         schema.setText(entity.getSchema());
         qualifier.setText(new ExpressionConvertor().valueAsString(entity.getQualifier()));
+        comment.setText(getComment(entity));
 
         String type = PK_DEFAULT_GENERATOR;
 
@@ -329,4 +341,19 @@ public class DbEntityTab extends JPanel implements ExistingSelectionProcessor, D
 
         }
     }
+
+    private String getComment(DbEntity entity) {
+        return ObjectInfo.getFromMetaData(mediator.getApplication().getMetaData(), entity, ObjectInfo.COMMENT);
+    }
+
+    private void setComment(String value) {
+        DbEntity entity = mediator.getCurrentDbEntity();
+
+        if(entity == null) {
+            return;
+        }
+
+        ObjectInfo.putToMetaData(mediator.getApplication().getMetaData(), entity, ObjectInfo.COMMENT, value);
+        mediator.fireDbEntityEvent(new EntityEvent(this, entity));
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbRelationshipTableModel.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbRelationshipTableModel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbRelationshipTableModel.java
index 6b25e8a..f4f9229 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbRelationshipTableModel.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbRelationshipTableModel.java
@@ -20,11 +20,13 @@
 package org.apache.cayenne.modeler.editor.dbentity;
 
 import java.util.ArrayList;
+import java.util.Collection;
 
 import javax.swing.JOptionPane;
 
 import org.apache.cayenne.configuration.DataChannelDescriptor;
 import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.DbRelationship;
 import org.apache.cayenne.map.ObjEntity;
@@ -35,25 +37,28 @@ import org.apache.cayenne.modeler.Application;
 import org.apache.cayenne.modeler.ProjectController;
 import org.apache.cayenne.modeler.dialog.WarningDialogByDbTargetChange;
 import org.apache.cayenne.modeler.util.CayenneTableModel;
+import org.apache.cayenne.modeler.util.ProjectUtil;
+import org.apache.cayenne.project.extension.info.ObjectInfo;
 
 /**
  * Table model for DbRelationship table.
  * 
  */
-public class DbRelationshipTableModel extends CayenneTableModel {
+public class DbRelationshipTableModel extends CayenneTableModel<DbRelationship> {
 
     // Columns
     static final int NAME = 0;
     static final int TARGET = 1;
     static final int TO_DEPENDENT_KEY = 2;
     static final int CARDINALITY = 3;
+    static final int COMMENTS = 4;
 
     protected DbEntity entity;
 
     public DbRelationshipTableModel(DbEntity entity, ProjectController mediator,
             Object eventSource) {
 
-        super(mediator, eventSource, new ArrayList(entity.getRelationships()));
+        super(mediator, eventSource, new ArrayList<>(entity.getRelationships()));
         this.entity = entity;
     }
 
@@ -65,7 +70,7 @@ public class DbRelationshipTableModel extends CayenneTableModel {
     }
 
     public int getColumnCount() {
-        return 4;
+        return 5;
     }
 
     public String getColumnName(int col) {
@@ -78,6 +83,8 @@ public class DbRelationshipTableModel extends CayenneTableModel {
                 return "To Dep PK";
             case CARDINALITY:
                 return "To Many";
+            case COMMENTS:
+                return "Comment";
             default:
                 return null;
         }
@@ -96,8 +103,7 @@ public class DbRelationshipTableModel extends CayenneTableModel {
     }
 
     public DbRelationship getRelationship(int row) {
-        return (row >= 0 && row < objectList.size()) ? (DbRelationship) objectList
-                .get(row) : null;
+        return (row >= 0 && row < objectList.size()) ? objectList.get(row) : null;
     }
 
     public Object getValueAt(int row, int col) {
@@ -115,24 +121,32 @@ public class DbRelationshipTableModel extends CayenneTableModel {
                 return rel.isToDependentPK() ? Boolean.TRUE : Boolean.FALSE;
             case CARDINALITY:
                 return rel.isToMany() ? Boolean.TRUE : Boolean.FALSE;
+            case COMMENTS:
+                return getComment(rel);
             default:
                 return null;
         }
     }
 
+    private String getComment(DbRelationship rel) {
+        return ObjectInfo.getFromMetaData(mediator.getApplication().getMetaData(), rel, ObjectInfo.COMMENT);
+    }
+
+    private void setComment(String newVal, DbRelationship rel) {
+        ObjectInfo.putToMetaData(mediator.getApplication().getMetaData(), rel, ObjectInfo.COMMENT, newVal);
+    }
+
     public void setUpdatedValueAt(Object aValue, int row, int column) {
 
         DbRelationship rel = getRelationship(row);
         // If name column
         if (column == NAME) {
-            RelationshipEvent e = new RelationshipEvent(eventSource, rel, entity, rel
-                    .getName());
+            RelationshipEvent e = new RelationshipEvent(eventSource, rel, entity, rel.getName());
             rel.setName((String) aValue);
             mediator.fireDbRelationshipEvent(e);
             fireTableCellUpdated(row, column);
-        }
-        // If target column
-        else if (column == TARGET) {
+        } else if (column == TARGET) {
+            // If target column
             DbEntity target = (DbEntity) aValue;
 
             if (WarningDialogByDbTargetChange.showWarningDialog(mediator, rel)) {
@@ -141,11 +155,9 @@ public class DbRelationshipTableModel extends CayenneTableModel {
                 rel.setTargetEntityName(target);
             }
 
-            RelationshipEvent e = new RelationshipEvent(eventSource, rel, entity);
-            mediator.fireDbRelationshipEvent(e);
-        }
-        else if (column == TO_DEPENDENT_KEY) {
-            boolean flag = ((Boolean) aValue).booleanValue();
+            mediator.fireDbRelationshipEvent(new RelationshipEvent(eventSource, rel, entity));
+        } else if (column == TO_DEPENDENT_KEY) {
+            boolean flag = (Boolean) aValue;
 
             // make sure reverse relationship "to-dep-pk" is unset.
             if (flag) {
@@ -166,16 +178,15 @@ public class DbRelationshipTableModel extends CayenneTableModel {
             }
 
             rel.setToDependentPK(flag);
-            RelationshipEvent e = new RelationshipEvent(eventSource, rel, entity);
-            mediator.fireDbRelationshipEvent(e);
-        }
-        else if (column == CARDINALITY) {
-            Boolean temp = (Boolean) aValue;
-            rel.setToMany(temp.booleanValue());
-            RelationshipEvent e = new RelationshipEvent(eventSource, rel, entity);
-            mediator.fireDbRelationshipEvent(e);
+            mediator.fireDbRelationshipEvent(new RelationshipEvent(eventSource, rel, entity));
+        } else if (column == CARDINALITY) {
+            rel.setToMany((Boolean) aValue);
+            mediator.fireDbRelationshipEvent(new RelationshipEvent(eventSource, rel, entity));
 
             updateDependentObjRelationships(rel);
+        } else if(column == COMMENTS) {
+            setComment((String) aValue, rel);
+            mediator.fireDbRelationshipEvent(new RelationshipEvent(eventSource, rel, entity));
         }
         fireTableRowsUpdated(row, row);
     }
@@ -184,33 +195,18 @@ public class DbRelationshipTableModel extends CayenneTableModel {
      * Relationship just needs to be removed from the model. It is already removed from
      * the DataMap.
      */
-    void removeRelationship(Relationship rel) {
+    void removeRelationship(DbRelationship rel) {
         objectList.remove(rel);
         fireTableDataChanged();
     }
 
     void updateDependentObjRelationships(DbRelationship relationship) {
 
-        DataChannelDescriptor domain = (DataChannelDescriptor) mediator
-                .getProject()
-                .getRootNode();
-        if (domain != null) {
-
-            for (DataMap map : domain.getDataMaps()) {
-                for (ObjEntity entity : map.getObjEntities()) {
-                    for (ObjRelationship objRelationship : entity.getRelationships()) {
-
-                        for (DbRelationship dbRelationship : objRelationship
-                                .getDbRelationships()) {
-                            if (dbRelationship == relationship) {
-                                objRelationship.recalculateToManyValue();
-                                objRelationship.recalculateReadOnlyValue();
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
+        Collection<ObjRelationship> objRelationshipsForDbRelationship = ProjectUtil
+                .findObjRelationshipsForDbRelationship(mediator, relationship);
+        for(ObjRelationship objRelationship : objRelationshipsForDbRelationship) {
+            objRelationship.recalculateToManyValue();
+            objRelationship.recalculateReadOnlyValue();
         }
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/11b916f8/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/init/CayenneModelerModule.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/init/CayenneModelerModule.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/init/CayenneModelerModule.java
index 30f0f99..f255b1f 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/init/CayenneModelerModule.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/init/CayenneModelerModule.java
@@ -30,7 +30,9 @@ import org.apache.cayenne.modeler.init.platform.GenericPlatformInitializer;
 import org.apache.cayenne.modeler.init.platform.PlatformInitializer;
 import org.apache.cayenne.modeler.util.DefaultWidgetFactory;
 import org.apache.cayenne.modeler.util.WidgetFactory;
+import org.apache.cayenne.project.ProjectModule;
 import org.apache.cayenne.project.extension.ExtensionAwareHandlerFactory;
+import org.apache.cayenne.project.extension.info.InfoExtension;
 
 /**
  * A DI module for bootstrapping CayenneModeler services.
@@ -45,5 +47,7 @@ public class CayenneModelerModule implements Module {
         binder.bind(WidgetFactory.class).to(DefaultWidgetFactory.class);
         binder.bind(HandlerFactory.class).to(ExtensionAwareHandlerFactory.class);
         binder.bind(DataChannelMetaData.class).to(DefaultDataChannelMetaData.class);
+
+        ProjectModule.contributeExtensions(binder).add(InfoExtension.class);
     }
 }