cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kmen...@apache.org
Subject svn commit: r661168 - in /cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler: ./ dialog/ editor/ editor/dbentity/ event/ util/ util/combo/
Date Thu, 29 May 2008 00:51:18 GMT
Author: kmenard
Date: Wed May 28 17:51:17 2008
New Revision: 661168

URL: http://svn.apache.org/viewvc?rev=661168&view=rev
Log:
Fixed CAY-911: CM Usability: JComboBox Autocompletion

Added:
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/AutoCompletion.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/ComboBoxCellEditor.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/CustomTypeComboBoxEditor.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/EditorTextField.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/SuggestionList.java
Modified:
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ModelerPreferences.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/ResolveDbRelationshipDialog.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityAttributeTab.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityRelationshipTab.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityTab.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureParameterTab.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityAttributeTab.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipTab.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/event/TablePopupHandler.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/CayenneTable.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/CayenneWidgetFactory.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/CellRenderers.java

Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ModelerPreferences.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ModelerPreferences.java?rev=661168&r1=661167&r2=661168&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ModelerPreferences.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ModelerPreferences.java Wed May 28 17:51:17 2008
@@ -48,7 +48,7 @@
 
     // Keys for the preference file.
 
-    /** List of the last 4 opened project files. */
+    /** List of the last 12 opened project files. */
     public static final String LAST_PROJ_FILES = "Editor.lastSeveralProjectFiles";
     public static final int LAST_PROJ_FILES_SIZE = 12;
 
@@ -59,6 +59,11 @@
     /** Log file */
     public static final String EDITOR_LOGFILE_ENABLED = "Editor.logfileEnabled";
     public static final String EDITOR_LOGFILE = "Editor.logfile";
+    
+    /*
+     * Number of items in combobox visible without scrolling 
+     */
+    public static final int COMBOBOX_MAX_VISIBLE_SIZE = 12;
 
     protected static ModelerPreferences sharedInstance;
 

Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/ResolveDbRelationshipDialog.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/ResolveDbRelationshipDialog.java?rev=661168&r1=661167&r2=661168&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/ResolveDbRelationshipDialog.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/ResolveDbRelationshipDialog.java Wed May 28 17:51:17 2008
@@ -30,7 +30,6 @@
 import java.util.Iterator;
 import java.util.List;
 
-import javax.swing.DefaultCellEditor;
 import javax.swing.JButton;
 import javax.swing.JComboBox;
 import javax.swing.JOptionPane;
@@ -55,6 +54,7 @@
 import org.apache.cayenne.modeler.util.ModelerUtil;
 import org.apache.cayenne.modeler.util.PanelFactory;
 import org.apache.cayenne.modeler.util.ProjectUtil;
+import org.apache.cayenne.modeler.util.combo.AutoCompletion;
 import org.apache.cayenne.project.NamedObjectFactory;
 import org.apache.cayenne.util.Util;
 
@@ -172,8 +172,9 @@
         JComboBox comboBox = CayenneWidgetFactory.createComboBox(ModelerUtil
                 .getDbAttributeNames(getMediator(), (DbEntity) relationship
                         .getSourceEntity()), true);
-        comboBox.setEditable(false);
-        sourceColumn.setCellEditor(new DefaultCellEditor(comboBox));
+        
+        AutoCompletion.enable(comboBox);
+        sourceColumn.setCellEditor(CayenneWidgetFactory.createCellEditor(comboBox));
 
         TableColumn targetColumn = table.getColumnModel().getColumn(
                 DbJoinTableModel.TARGET);
@@ -181,8 +182,9 @@
         comboBox = CayenneWidgetFactory.createComboBox(ModelerUtil.getDbAttributeNames(
                 getMediator(),
                 (DbEntity) relationship.getTargetEntity()), true);
-        comboBox.setEditable(false);
-        targetColumn.setCellEditor(new DefaultCellEditor(comboBox));
+        AutoCompletion.enable(comboBox);
+        
+        targetColumn.setCellEditor(CayenneWidgetFactory.createCellEditor(comboBox));
 
         if (reverseRelationship != null) {
             reverseName.setText(reverseRelationship.getName());
@@ -400,6 +402,7 @@
 
         final Dimension preferredSize = new Dimension(203, 100);
 
+        @Override
         public Dimension getPreferredScrollableViewportSize() {
             return preferredSize;
         }

Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityAttributeTab.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityAttributeTab.java?rev=661168&r1=661167&r2=661168&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityAttributeTab.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityAttributeTab.java Wed May 28 17:51:17 2008
@@ -24,7 +24,6 @@
 import java.awt.Component;
 import java.util.EventObject;
 
-import javax.swing.DefaultCellEditor;
 import javax.swing.JComboBox;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
@@ -56,6 +55,7 @@
 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;
 
 /**
  * Detail view of the ObjEntity attributes.
@@ -214,8 +214,8 @@
 
         JComboBox javaTypesCombo = CayenneWidgetFactory.createComboBox(ModelerUtil
                 .getRegisteredTypeNames(), false);
-        javaTypesCombo.setEditable(true);
-        typeColumn.setCellEditor(new DefaultCellEditor(javaTypesCombo));
+        AutoCompletion.enable(javaTypesCombo, false, true);
+        typeColumn.setCellEditor(CayenneWidgetFactory.createCellEditor(javaTypesCombo));
 
         TableColumn lockColumn = table.getColumnModel().getColumn(
                 ObjAttributeTableModel.LOCKING);
@@ -234,9 +234,9 @@
                     .createComboBox(ModelerUtil.getDbAttributeNames(mediator, model
                             .getEntity()
                             .getDbEntity()), true);
+            AutoCompletion.enable(dbAttributesCombo);
 
-            dbAttributesCombo.setEditable(false);
-            dbNameColumn.setCellEditor(new DefaultCellEditor(dbAttributesCombo));
+            dbNameColumn.setCellEditor(CayenneWidgetFactory.createCellEditor(dbAttributesCombo));
         }
     }
 
@@ -269,6 +269,7 @@
     // custom renderer used for inherited attributes highlighting
     final class CellRenderer extends DefaultTableCellRenderer {
 
+        @Override
         public Component getTableCellRendererComponent(
                 JTable table,
                 Object value,

Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityRelationshipTab.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityRelationshipTab.java?rev=661168&r1=661167&r2=661168&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityRelationshipTab.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityRelationshipTab.java Wed May 28 17:51:17 2008
@@ -48,7 +48,6 @@
 
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.DeleteRule;
-import org.apache.cayenne.map.Entity;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.ObjRelationship;
 import org.apache.cayenne.map.event.EntityEvent;
@@ -71,7 +70,7 @@
 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.util.CayenneMapEntry;
+import org.apache.cayenne.modeler.util.combo.AutoCompletion;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
@@ -387,13 +386,12 @@
         JComboBox targetCombo = CayenneWidgetFactory.createComboBox(
                 createObjEntityComboModel(),
                 false);
+        AutoCompletion.enable(targetCombo);        
+        
         targetCombo.setRenderer(CellRenderers.entityListRendererWithIcons(entity
                 .getDataMap()));
-        targetCombo.setEditable(false);
         targetCombo.setSelectedIndex(-1);
-        DefaultCellEditor editor = new DefaultCellEditor(targetCombo);
-        editor.setClickCountToStart(1);
-        col.setCellEditor(editor);
+        col.setCellEditor(CayenneWidgetFactory.createCellEditor(targetCombo));
 
         col = table.getColumnModel().getColumn(ObjRelationshipTableModel.REL_SEMANTICS);
         col.setMinWidth(150);
@@ -405,13 +403,12 @@
                 false);
         deleteRulesCombo.setEditable(false);
         deleteRulesCombo.setSelectedIndex(0); // Default to the first value
-        editor = new DefaultCellEditor(deleteRulesCombo);
-        editor.setClickCountToStart(1);
-        col.setCellEditor(editor);
+        col.setCellEditor(CayenneWidgetFactory.createCellEditor(deleteRulesCombo));
     }
 
     class EntityRenderer extends StringRenderer {
 
+        @Override
         public Component getTableCellRendererComponent(
                 JTable table,
                 Object value,
@@ -420,35 +417,25 @@
                 int row,
                 int column) {
 
-            if (value instanceof CayenneMapEntry) {
-                CayenneMapEntry mapObject = (CayenneMapEntry) value;
-                String label = mapObject.getName();
-
-                if (mapObject instanceof Entity) {
-                    Entity entity = (Entity) mapObject;
-
-                    // for different namespace display its name
-                    DataMap dataMap = entity.getDataMap();
-                    if (dataMap != null && dataMap != mediator.getCurrentDataMap()) {
-                        label += " (" + dataMap.getName() + ")";
-                    }
-                }
+            Object oldValue = value;
+            value = CellRenderers.asString(value);
 
-                value = label;
-            }
-
-            return super.getTableCellRendererComponent(
+            super.getTableCellRendererComponent(
                     table,
                     value,
                     isSelected,
                     hasFocus,
                     row,
                     column);
+            
+            setIcon(CellRenderers.iconForObject(oldValue));
+            return this;
         }
     }
 
     class StringRenderer extends DefaultTableCellRenderer {
 
+        @Override
         public Component getTableCellRendererComponent(
                 JTable table,
                 Object value,

Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityTab.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityTab.java?rev=661168&r1=661167&r2=661168&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityTab.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityTab.java Wed May 28 17:51:17 2008
@@ -56,6 +56,7 @@
 import org.apache.cayenne.modeler.util.ExpressionConvertor;
 import org.apache.cayenne.modeler.util.ModelerUtil;
 import org.apache.cayenne.modeler.util.TextAdapter;
+import org.apache.cayenne.modeler.util.combo.AutoCompletion;
 import org.apache.cayenne.util.CayenneMapEntry;
 import org.apache.cayenne.util.Util;
 import org.apache.cayenne.validation.ValidationException;
@@ -132,24 +133,28 @@
         // create widgets
         name = new TextAdapter(new JTextField()) {
 
+            @Override
             protected void updateModel(String text) {
                 setEntityName(text);
             }
         };
         superClassName = new TextAdapter(new JTextField()) {
 
+            @Override
             protected void updateModel(String text) {
                 setSuperClassName(text);
             }
         };
         className = new TextAdapter(new JTextField()) {
 
+            @Override
             protected void updateModel(String text) {
                 setClassName(text);
             }
         };
         qualifier = new TextAdapter(new JTextField()) {
 
+            @Override
             protected void updateModel(String text) {
                 setQualifier(text);
             }
@@ -157,6 +162,9 @@
 
         dbEntityCombo = CayenneWidgetFactory.createComboBox();
         superEntityCombo = CayenneWidgetFactory.createComboBox();
+        
+        AutoCompletion.enable(dbEntityCombo);
+        AutoCompletion.enable(superEntityCombo);
 
         readOnly = new JCheckBox();
         optimisticLocking = new JCheckBox();
@@ -171,12 +179,14 @@
         serverOnly = new JCheckBox();
         clientClassName = new TextAdapter(new JTextField()) {
 
+            @Override
             protected void updateModel(String text) {
                 setClientClassName(text);
             }
         };
         clientSuperClassName = new TextAdapter(new JTextField()) {
 
+            @Override
             protected void updateModel(String text) {
                 setClientSuperClassName(text);
             }

Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureParameterTab.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureParameterTab.java?rev=661168&r1=661167&r2=661168&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureParameterTab.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureParameterTab.java Wed May 28 17:51:17 2008
@@ -60,6 +60,7 @@
 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;
 
 /**
  * @author Andrus Adamchik
@@ -258,8 +259,8 @@
 
         JComboBox typesEditor =
             CayenneWidgetFactory.createComboBox(TypesMapping.getDatabaseTypes(), true);
-        typesEditor.setEditable(true);
-        typesColumn.setCellEditor(new DefaultCellEditor(typesEditor));
+        AutoCompletion.enable(typesEditor);
+        typesColumn.setCellEditor(CayenneWidgetFactory.createCellEditor(typesEditor));
 
         // direction column tweaking
         TableColumn directionColumn =
@@ -322,8 +323,7 @@
     /**
      * Synchronizes state of toolbar and popup menu buttons
      */
-    private void syncButtons()
-    {
+    private void syncButtons() {
         removeParameterMenu.setEnabled(removeParameterButton.isEnabled());
         moveUpMenu.setEnabled(moveUp.isEnabled());
         moveDownMenu.setEnabled(moveDown.isEnabled());   

Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java?rev=661168&r1=661167&r2=661168&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java Wed May 28 17:51:17 2008
@@ -40,6 +40,7 @@
 import org.apache.cayenne.modeler.util.ExpressionConvertor;
 import org.apache.cayenne.modeler.util.ProjectUtil;
 import org.apache.cayenne.modeler.util.TextAdapter;
+import org.apache.cayenne.modeler.util.combo.AutoCompletion;
 import org.apache.cayenne.query.AbstractQuery;
 import org.apache.cayenne.query.Query;
 import org.apache.cayenne.query.SelectQuery;
@@ -76,16 +77,19 @@
         // create widgets
         name = new TextAdapter(new JTextField()) {
 
+            @Override
             protected void updateModel(String text) {
                 setQueryName(text);
             }
         };
 
         queryRoot = CayenneWidgetFactory.createComboBox();
+        AutoCompletion.enable(queryRoot);
         queryRoot.setRenderer(CellRenderers.listRendererWithIcons());
 
         qualifier = new TextAdapter(new JTextField()) {
 
+            @Override
             protected void updateModel(String text) {
                 setQueryQualifier(text);
             }

Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityAttributeTab.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityAttributeTab.java?rev=661168&r1=661167&r2=661168&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityAttributeTab.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityAttributeTab.java Wed May 28 17:51:17 2008
@@ -22,7 +22,6 @@
 import java.awt.BorderLayout;
 import java.util.EventObject;
 
-import javax.swing.DefaultCellEditor;
 import javax.swing.JComboBox;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
@@ -52,6 +51,7 @@
 import org.apache.cayenne.modeler.util.CayenneWidgetFactory;
 import org.apache.cayenne.modeler.util.PanelFactory;
 import org.apache.cayenne.modeler.util.UIUtil;
+import org.apache.cayenne.modeler.util.combo.AutoCompletion;
 
 /**
  * Detail view of the DbEntity attributes.
@@ -198,7 +198,10 @@
 
         String[] types = TypesMapping.getDatabaseTypes();
         JComboBox comboBox = CayenneWidgetFactory.createComboBox(types, true);
-        col.setCellEditor(new DefaultCellEditor(comboBox));
+        
+        AutoCompletion.enable(comboBox);
+        
+        col.setCellEditor(CayenneWidgetFactory.createCellEditor(comboBox));
 
         table.getSelectionModel().addListSelectionListener(this);
     }

Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipTab.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipTab.java?rev=661168&r1=661167&r2=661168&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipTab.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipTab.java Wed May 28 17:51:17 2008
@@ -20,13 +20,11 @@
 package org.apache.cayenne.modeler.editor.dbentity;
 
 import java.awt.BorderLayout;
-import java.awt.Component;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.EventObject;
 
 import javax.swing.ComboBoxModel;
-import javax.swing.DefaultCellEditor;
 import javax.swing.DefaultComboBoxModel;
 import javax.swing.Icon;
 import javax.swing.JButton;
@@ -34,20 +32,17 @@
 import javax.swing.JMenuItem;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
-import javax.swing.JTable;
 import javax.swing.JToolBar;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
 import javax.swing.event.TableModelEvent;
 import javax.swing.event.TableModelListener;
-import javax.swing.table.DefaultTableCellRenderer;
 import javax.swing.table.TableColumn;
 
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.Entity;
 import org.apache.cayenne.map.event.DbEntityListener;
 import org.apache.cayenne.map.event.DbRelationshipListener;
 import org.apache.cayenne.map.event.EntityEvent;
@@ -70,7 +65,7 @@
 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.util.CayenneMapEntry;
+import org.apache.cayenne.modeler.util.combo.AutoCompletion;
 
 /**
  * Displays DbRelationships for the current DbEntity.
@@ -92,6 +87,11 @@
      * This should be probably refactored as Action.
      */
     protected JMenuItem resolveMenu;
+    
+    /**
+     * Combo to edit 'target' field
+     */
+    protected JComboBox targetCombo;
 
     public DbEntityRelationshipTab(ProjectController mediator) {
 
@@ -144,7 +144,7 @@
         add(toolBar, BorderLayout.NORTH);
 
         table = new CayenneTable();
-        table.setDefaultRenderer(DbEntity.class, new EntityRenderer());
+        table.setDefaultRenderer(DbEntity.class, CellRenderers.entityTableRendererWithIcons(mediator));
         
         /**
          * Create and install a popup
@@ -271,11 +271,12 @@
         col = table.getColumnModel().getColumn(DbRelationshipTableModel.TARGET);
         col.setMinWidth(150);
 
-        JComboBox combo = CayenneWidgetFactory.createComboBox();
-        combo.setRenderer(CellRenderers.entityListRendererWithIcons(entity.getDataMap()));
-        combo.setModel(createComboModel());
-        combo.setEditable(false);
-        col.setCellEditor(new DefaultCellEditor(combo));
+        targetCombo = CayenneWidgetFactory.createComboBox();
+        AutoCompletion.enable(targetCombo);
+        
+        targetCombo.setRenderer(CellRenderers.entityListRendererWithIcons(entity.getDataMap()));
+        targetCombo.setModel(createComboModel());
+        col.setCellEditor(CayenneWidgetFactory.createCellEditor(targetCombo));
         table.getSelectionModel().addListSelectionListener(this);
     }
 
@@ -327,11 +328,7 @@
         // If this is just loading new currentDbEntity, do nothing
         if (mediator.getCurrentDbEntity() == null)
             return;
-        TableColumn col = table.getColumnModel().getColumn(
-                DbRelationshipTableModel.TARGET);
-        DefaultCellEditor editor = (DefaultCellEditor) col.getCellEditor();
-        JComboBox combo = (JComboBox) editor.getComponent();
-        combo.setModel(createComboModel());
+        targetCombo.setModel(createComboModel());
 
         DbRelationshipTableModel model = (DbRelationshipTableModel) table.getModel();
         model.fireTableDataChanged();
@@ -347,43 +344,4 @@
         return new DefaultComboBoxModel(objects);
     }
 
-    class EntityRenderer extends DefaultTableCellRenderer {
-
-        public Component getTableCellRendererComponent(
-                JTable table,
-                Object value,
-                boolean isSelected,
-                boolean hasFocus,
-                int row,
-                int column) {
-
-            if (value instanceof CayenneMapEntry) {
-                CayenneMapEntry mapObject = (CayenneMapEntry) value;
-                String label = mapObject.getName();
-
-                if (mapObject instanceof Entity) {
-                    Entity entity = (Entity) mapObject;
-
-                    // for different namespace display its name
-                    DataMap dataMap = entity.getDataMap();
-                    if (dataMap != null && dataMap != mediator.getCurrentDataMap()) {
-                        label += " (" + dataMap.getName() + ")";
-                    }
-                }
-
-                value = label;
-            }
-
-            super.getTableCellRendererComponent(
-                    table,
-                    value,
-                    isSelected,
-                    hasFocus,
-                    row,
-                    column);
-
-            return this;
-        }
-    }
-
 }

Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/event/TablePopupHandler.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/event/TablePopupHandler.java?rev=661168&r1=661167&r2=661168&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/event/TablePopupHandler.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/event/TablePopupHandler.java Wed May 28 17:51:17 2008
@@ -22,55 +22,54 @@
 import java.awt.event.MouseEvent;
 
 import javax.swing.JPopupMenu;
-import javax.swing.JTable;
+
+import org.apache.cayenne.modeler.util.CayenneTable;
 
 /**
- * A class to handle mouse right-click on table and show popup
- * after selecting specified table row
+ * A class to handle mouse right-click on table and show popup after selecting specified
+ * table row
  */
-public class TablePopupHandler extends MouseAdapter 
-{
-    private JTable table;
-    
-    private JPopupMenu popup;
-    
+public class TablePopupHandler extends MouseAdapter {
+
+    private final CayenneTable table;
+
+    private final JPopupMenu popup;
+
     /**
-     * Creates new mouse handler for table, which shows specified
-     * popupmenu on right-click 
+     * Creates new mouse handler for table, which shows specified popupmenu on right-click
      */
-    public TablePopupHandler(JTable table, JPopupMenu popup)
-    {
+    public TablePopupHandler(CayenneTable table, JPopupMenu popup) {
         this.table = table;
         this.popup = popup;
     }
-    
+
     /**
-     * Creates and installs mouse listener for a table 
+     * Creates and installs mouse listener for a table
      */
-    public static void install(JTable table, JPopupMenu popup)
-    {
+    public static void install(CayenneTable table, JPopupMenu popup) {
         table.addMouseListener(new TablePopupHandler(table, popup));
     }
-    
+
     /**
      * Invoked when a mouse button has been pressed on a component.
      */
-    public void mousePressed(MouseEvent e) 
-    {
+    @Override
+    public void mousePressed(MouseEvent e) {
         mouseReleased(e);
     }
 
     /**
      * Invoked when a mouse button has been released on a component.
      */
-    public void mouseReleased(MouseEvent e) 
-    {
-        if(e.isPopupTrigger())
-        {
+    @Override
+    public void mouseReleased(MouseEvent e) {
+        if (e.isPopupTrigger()) {
+            table.cancelEditing();
+
             int row = table.rowAtPoint(e.getPoint());
-            if(row != -1)
+            if (row != -1)
                 table.setRowSelectionInterval(row, row);
-            
+
             popup.show(table, e.getX(), e.getY());
         }
     }

Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/CayenneTable.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/CayenneTable.java?rev=661168&r1=661167&r2=661168&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/CayenneTable.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/CayenneTable.java Wed May 28 17:51:17 2008
@@ -25,10 +25,11 @@
 import javax.swing.JTable;
 import javax.swing.JTextField;
 import javax.swing.event.ChangeEvent;
+import javax.swing.event.TableModelEvent;
 import javax.swing.table.TableCellEditor;
 import javax.swing.text.JTextComponent;
 
-/**  
+/**
  * Common superclass of tables used in Cayenne. Contains some common configuration
  * settings and utility methods.
  * 
@@ -43,9 +44,10 @@
         this.setRowMargin(3);
     }
 
+    @Override
     protected void createDefaultEditors() {
         super.createDefaultEditors();
-        
+
         JTextField textField = CayenneWidgetFactory.createTextField(0);
         final DefaultCellEditor textEditor = new DefaultCellEditor(textField);
         textEditor.setClickCountToStart(1);
@@ -57,21 +59,20 @@
     public CayenneTableModel getCayenneModel() {
         return (CayenneTableModel) getModel();
     }
-    
+
     /**
-     * Cancels editing of any cells that maybe currently edited.
-     * This method should be called before updating any selections.
+     * Cancels editing of any cells that maybe currently edited. This method should be
+     * called before updating any selections.
      */
-    protected void cancelEditing() {
-    	editingCanceled(new ChangeEvent(this));
+    public void cancelEditing() {
+        editingCanceled(new ChangeEvent(this));
     }
 
     public void select(Object row) {
         if (row == null) {
             return;
         }
-		cancelEditing();
-		
+
         CayenneTableModel model = getCayenneModel();
         int ind = model.getObjectList().indexOf(row);
 
@@ -81,8 +82,7 @@
     }
 
     public void select(int index) {
-		cancelEditing();
-		
+
         CayenneTableModel model = getCayenneModel();
         if (index >= model.getObjectList().size()) {
             index = model.getObjectList().size() - 1;
@@ -109,4 +109,10 @@
         }
         return null;
     }
+
+    @Override
+    public void tableChanged(TableModelEvent e) {
+        cancelEditing();
+        super.tableChanged(e);
+    }
 }

Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/CayenneWidgetFactory.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/CayenneWidgetFactory.java?rev=661168&r1=661167&r2=661168&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/CayenneWidgetFactory.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/CayenneWidgetFactory.java Wed May 28 17:51:17 2008
@@ -28,12 +28,18 @@
 import java.util.Arrays;
 import java.util.Collection;
 
+import javax.swing.DefaultCellEditor;
 import javax.swing.DefaultComboBoxModel;
 import javax.swing.JButton;
 import javax.swing.JComboBox;
 import javax.swing.JComponent;
 import javax.swing.JTextField;
 import javax.swing.SwingConstants;
+import javax.swing.table.TableCellEditor;
+
+import org.apache.cayenne.modeler.ModelerPreferences;
+import org.apache.cayenne.modeler.util.combo.AutoCompletion;
+import org.apache.cayenne.modeler.util.combo.ComboBoxCellEditor;
 
 /**
  * Utility class to create standard Swing widgets following default look-and-feel of
@@ -59,7 +65,7 @@
     public static JComboBox createComboBox(Collection<String> model, boolean sort) {
         return createComboBox(model.toArray(), sort);
     }
-
+    
     /**
      * Creates a new JComboBox with an array of model objects.
      */
@@ -73,7 +79,7 @@
         comboBox.setModel(new DefaultComboBoxModel(model));
         return comboBox;
     }
-
+    
     /**
      * Creates a new JComboBox.
      */
@@ -81,8 +87,27 @@
         JComboBox comboBox = new JComboBox();
         initFormWidget(comboBox);
         comboBox.setBackground(Color.WHITE);
+        comboBox.setMaximumRowCount(ModelerPreferences.COMBOBOX_MAX_VISIBLE_SIZE);
+                
         return comboBox;
     }
+    
+    /**
+     * Creates cell editor for a table with combo as editor component. Type of this editor
+     * depends on auto-completion behavior of JComboBox
+     * 
+     * @param combo JComboBox to be used as editor component
+     */
+    public static TableCellEditor createCellEditor(JComboBox combo) {
+        if (Boolean.TRUE.equals(combo.getClientProperty(AutoCompletion.AUTOCOMPLETION_PROPERTY))) {
+            return new ComboBoxCellEditor(combo);
+        }
+        
+        DefaultCellEditor editor = new DefaultCellEditor(combo);
+        editor.setClickCountToStart(1);        
+
+        return editor;
+    }
 
     /**
      * Creates a new JTextField with a default columns count of 20.

Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/CellRenderers.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/CellRenderers.java?rev=661168&r1=661167&r2=661168&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/CellRenderers.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/CellRenderers.java Wed May 28 17:51:17 2008
@@ -24,8 +24,11 @@
 import javax.swing.DefaultListCellRenderer;
 import javax.swing.ImageIcon;
 import javax.swing.JList;
+import javax.swing.JTable;
 import javax.swing.JTree;
 import javax.swing.ListCellRenderer;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableCellRenderer;
 import javax.swing.tree.DefaultMutableTreeNode;
 import javax.swing.tree.DefaultTreeCellRenderer;
 import javax.swing.tree.TreeCellRenderer;
@@ -40,6 +43,8 @@
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.Procedure;
 import org.apache.cayenne.map.Relationship;
+import org.apache.cayenne.modeler.Application;
+import org.apache.cayenne.modeler.ProjectController;
 import org.apache.cayenne.query.Query;
 import org.apache.cayenne.util.CayenneMapEntry;
 
@@ -140,6 +145,52 @@
     public static ListCellRenderer entityListRendererWithIcons(MappingNamespace namespace) {
         return new EntityRenderer(namespace);
     }
+    
+    /**
+     * Returns a TableCellRenderer to display Cayenne project entities with icons in table.
+     */
+    public static TableCellRenderer entityTableRendererWithIcons(ProjectController mediator) {
+        return new EntityTableRenderer(mediator);
+    }
+    
+    /**
+     * Converts non-String Object used in renderers (currently CayenneMapEntry
+     * instances only) to String
+     * 
+     * @param obj Object to be converted
+     */
+    public static String asString(Object obj) {
+        return asString(obj, Application.getInstance(). //none of these is suppeosed to be null
+           getFrameController().getProjectController().getCurrentDataMap());
+    }
+    
+    /**
+     * Converts non-String Object used in renderers (currently CayenneMapEntry
+     * instances only) to String
+     * 
+     * @param obj Object to be converted
+     * @param namespace the current namespace
+     */
+    public static String asString(Object obj, MappingNamespace namespace) {
+        if (obj instanceof CayenneMapEntry) {
+            CayenneMapEntry mapObject = (CayenneMapEntry) obj;
+            String label = mapObject.getName();
+
+            if (mapObject instanceof Entity) {
+                Entity entity = (Entity) mapObject;
+
+                // for different namespace display its name
+                DataMap dataMap = entity.getDataMap();
+                if (dataMap != null && dataMap != namespace) {
+                    label += " (" + dataMap.getName() + ")";
+                }
+            }
+            
+            obj = label;
+        }
+        
+        return obj == null ? null : String.valueOf(obj);
+    }
 
     final static class EntityRenderer extends DefaultListCellRenderer {
         MappingNamespace namespace;
@@ -162,22 +213,7 @@
             // then set an icon, and then return "this" 
             ImageIcon icon = CellRenderers.iconForObject(value);
 
-            if (value instanceof CayenneMapEntry) {
-                CayenneMapEntry mapObject = (CayenneMapEntry) value;
-                String label = mapObject.getName();
-
-                if (mapObject instanceof Entity) {
-                    Entity entity = (Entity) mapObject;
-
-                    // for different namespace display its name
-                    DataMap dataMap = entity.getDataMap();
-                    if (dataMap != null && dataMap != this.namespace) {
-                        label += " (" + dataMap.getName() + ")";
-                    }
-                }
-                
-                value = label;
-            }
+            value = asString(value, namespace);
 
             super.getListCellRendererComponent(
                 list,
@@ -261,4 +297,37 @@
             return this;
         }
     }
+    
+    final static class EntityTableRenderer extends DefaultTableCellRenderer {
+        
+        private ProjectController mediator;
+        
+        public EntityTableRenderer(ProjectController mediator) {
+            this.mediator = mediator;
+        }
+
+        public Component getTableCellRendererComponent(
+                JTable table,
+                Object value,
+                boolean isSelected,
+                boolean hasFocus,
+                int row,
+                int column) {
+
+            Object oldValue = value;
+            value = CellRenderers.asString(value, mediator.getCurrentDataMap());
+
+            super.getTableCellRendererComponent(
+                    table,
+                    value,
+                    isSelected,
+                    hasFocus,
+                    row,
+                    column);
+            
+            setIcon(CellRenderers.iconForObject(oldValue));
+
+            return this;
+        }
+    }
 }

Added: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/AutoCompletion.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/AutoCompletion.java?rev=661168&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/AutoCompletion.java (added)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/AutoCompletion.java Wed May 28 17:51:17 2008
@@ -0,0 +1,222 @@
+/*****************************************************************
+ *   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.combo;
+
+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)
+ *
+ * @author Andrey Razumovsky
+ */
+public class AutoCompletion implements FocusListener, KeyListener, Runnable {
+    /**
+     * Property to mark combobox as 'auto-completing'
+     */
+    public static final String AUTOCOMPLETION_PROPERTY = "JComboBox.autoCompletion";
+    
+    /**
+     * A list with matching items
+     */
+    private final SuggestionList suggestionList; 
+
+    /**
+     * Combo with auto-completion
+     */
+    private final JComboBox comboBox;
+    
+    private final JTextComponent textEditor;
+    
+    private final boolean allowsUserValues;
+    
+    protected AutoCompletion(final JComboBox comboBox, boolean strict, boolean allowsUserValues) {
+        this.comboBox = comboBox;
+        textEditor = ((JTextComponent)comboBox.getEditor().getEditorComponent());
+        
+        this.allowsUserValues = allowsUserValues; 
+        
+        suggestionList = new SuggestionList(comboBox, strict);
+        
+        /**
+         * Marking combobox as auto-completing
+         */
+        comboBox.putClientProperty(AUTOCOMPLETION_PROPERTY, Boolean.TRUE);
+    }
+
+    /**
+     * Enables auto-completion for specified combobox
+     *
+     * @param comboBox Combo to be featured
+     * @param strict Whether strict matching (check 'startWith' or 'contains') should be used
+     * @param allowsUserValues Whether non-present items are allowed 
+     */
+    public static void enable(JComboBox comboBox, boolean strict, boolean allowsUserValues) {
+        comboBox.setEditable(true);
+        
+        comboBox.setEditor(new CustomTypeComboBoxEditor(comboBox, allowsUserValues));
+        
+        AutoCompletion ac = new AutoCompletion(comboBox, strict, allowsUserValues);
+        comboBox.addFocusListener(ac);
+        ac.textEditor.addKeyListener(ac);
+        
+        //original keys would not work properly
+        SwingUtilities.replaceUIActionMap(comboBox, null);
+    }
+    
+    /**
+     * Enables auto-completion for specified combobox
+     */
+    public static void enable(JComboBox comboBox) {
+        enable(comboBox, true, false);
+    }
+
+    public void focusGained(FocusEvent e) {}
+
+    public void focusLost(FocusEvent e) {
+        suggestionList.hide();
+    }
+
+    public void keyPressed(KeyEvent e) {
+        handleKeyPressed(comboBox, e);
+    }
+
+    public void keyReleased(KeyEvent e) {}
+
+    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();
+            }
+        }
+    }
+    
+    /**
+     * 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) {
+        boolean suggest = suggestionList.isVisible();
+        
+        int sel, next, max;
+        
+        if (suggest) {
+            sel = suggestionList.getSelectedIndex();
+            max = suggestionList.getItemCount() - 1;
+        }
+        else {
+            sel = comboBox.getSelectedIndex();
+            max = comboBox.getItemCount() - 1;
+        }
+        
+        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:
+                if (suggest) {
+                    Object value = suggestionList.getSelectedValue();
+                    if(!allowsUserValues && value == null && suggestionList.getItemCount() > 0) {
+                        value = suggestionList.getItemAt(0);
+                    }
+                    
+                    comboBox.setSelectedItem(value);
+                    suggestionList.hide();
+                }
+                return;
+                
+            case KeyEvent.VK_ESCAPE:
+                if (suggest) {
+                    suggestionList.hide();
+                }
+                return;
+                
+            default:
+                //invoke in end of AWT thread so that information in textEditor would update
+                SwingUtilities.invokeLater(this);
+                return;
+        }
+        
+        /**
+         * Handle navigation keys
+         */
+
+        e.consume();
+        if (!suggest && !comboBox.isPopupVisible()) {
+            comboBox.setPopupVisible(true);
+            return;
+        }
+
+        if (comboBox.getItemCount() > 0) {
+            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);
+                }
+            }
+            
+            textEditor.requestFocus();
+        }
+    }
+}
\ No newline at end of file

Added: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/ComboBoxCellEditor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/ComboBoxCellEditor.java?rev=661168&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/ComboBoxCellEditor.java (added)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/ComboBoxCellEditor.java Wed May 28 17:51:17 2008
@@ -0,0 +1,87 @@
+/*****************************************************************
+ *   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.combo;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.Serializable;
+
+import javax.swing.AbstractCellEditor;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.table.TableCellEditor;
+
+/**
+ * ComboBoxCellEditor class is a workaround of collision between DefaultCellEditor and 
+ * AutoCompletion behavior. Using DefaultCellEditor will cause combo popup to close
+ * out of time.
+ *
+ * @author Andrey Razumovsky
+ */
+public class ComboBoxCellEditor extends AbstractCellEditor implements ActionListener, TableCellEditor, Serializable {
+    static final String IS_TABLE_CELL_EDITOR_PROPERTY = "JComboBox.isTableCellEditor";
+    
+    private final JComboBox comboBox;
+    
+    public ComboBoxCellEditor(JComboBox comboBox) {
+        this.comboBox = comboBox;
+        this.comboBox.putClientProperty(IS_TABLE_CELL_EDITOR_PROPERTY, Boolean.TRUE);
+
+        // hitting enter in the combo box should stop cellediting (see below)
+        this.comboBox.addActionListener(this);
+
+        // remove the editor's border - the cell itself already has one
+        ((JComponent) comboBox.getEditor().getEditorComponent()).setBorder(null);
+    }
+    
+    // Implementing ActionListener
+    public void actionPerformed(ActionEvent e) {
+        // Selecting an item results in an actioncommand "comboBoxChanged".
+        // We should ignore these ones.
+        
+        // Hitting enter results in an actioncommand "comboBoxEdited"
+        if (e.getActionCommand().equals("comboBoxEdited")) {
+            stopCellEditing();
+        }
+    }
+    
+    public Object getCellEditorValue() {
+        return comboBox.getSelectedItem();
+    }
+    
+    @Override
+    public boolean stopCellEditing() {
+        if (comboBox.isEditable()) {
+            // Notify the combo box that editing has stopped (e.g. User pressed F2)
+            comboBox.actionPerformed(new ActionEvent(this, 0, ""));
+        }
+
+        fireEditingStopped();
+
+        return true;
+    }
+    
+    public Component getTableCellEditorComponent(javax.swing.JTable table, Object value, boolean isSelected, int row, int column) {
+        comboBox.setSelectedItem(value);
+        
+        return comboBox;
+    }
+}

Added: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/CustomTypeComboBoxEditor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/CustomTypeComboBoxEditor.java?rev=661168&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/CustomTypeComboBoxEditor.java (added)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/CustomTypeComboBoxEditor.java Wed May 28 17:51:17 2008
@@ -0,0 +1,156 @@
+/*****************************************************************
+ *   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.combo;
+
+import java.lang.reflect.Method;
+
+import javax.swing.ComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.plaf.basic.BasicComboBoxEditor;
+
+import org.apache.cayenne.modeler.util.CellRenderers;
+
+/**
+ * CustomTypeComboBoxEditor is used as an editor of a combobox, when
+ * custom type (such as Entity) is to be used. BasicComboBoxEditor
+ * cannot be used, because it converts String values to other types
+ * incorrectly (in fact, only classes with valueOf(String) methods
+ * are supported).
+ * 
+ * @author Andrey Razumovsky
+ */
+public class CustomTypeComboBoxEditor extends BasicComboBoxEditor {
+    /**
+     * 'oldValue' property is private somewhy, so we make our local
+     * copy
+     */
+    protected Object localOldValue;
+    
+    /**
+     * The combobox being edited
+     */
+    protected final JComboBox combo;
+    
+    /**
+     * Whether non-present items are allowed
+     */
+    protected final boolean allowsUserValues;
+    
+    /**
+     * Creates new editor
+     * @param combo ComboBox being edited
+     */
+    public CustomTypeComboBoxEditor(JComboBox combo, boolean allowsUserValues) {
+        editor = new EditorTextField(combo);
+        this.combo = combo;
+        this.allowsUserValues = allowsUserValues;
+    }
+    
+    /** 
+     * Sets the item that should be edited. 
+     *
+     * @param anObject the displayed value of the editor
+     */
+    @Override
+    public void setItem(Object anObject) {
+        localOldValue = anObject;
+        super.setItem(anObject == null ? null : CellRenderers.asString(anObject));
+    }
+    
+    /**
+     * @return edited item
+     */
+    @Override
+    public Object getItem() {
+        Object newValue = editor.getText();
+        
+        if (localOldValue != null && !(localOldValue instanceof String))  {
+            // The original value is not a string. Should return the value in it's
+            // original type.
+            if (newValue.equals(localOldValue.toString())) {
+                return localOldValue;
+            }
+            else {
+                // Must take the value from the editor and get the value and cast it to the new type.
+                Class cls = localOldValue.getClass();
+                try {
+                    newValue = convert((String)newValue, cls);
+                }
+                catch (Exception ignored) {}
+            }
+        }
+        
+        if (!allowsUserValues && newValue != null) {
+            boolean contains = false;
+            
+            for (int i = 0; i < combo.getItemCount(); i++) {
+                if (newValue.equals(combo.getItemAt(i))) {
+                    contains = true;
+                    break;
+                }
+            }
+                   
+            if (!contains) {
+                return null;
+            }
+        }
+        
+        return newValue;
+    }
+    
+    /**
+     * Converts String value to specified type
+     *
+     * @param value String value of textfield
+     * @param classTo type of result item
+     * 
+     * @return value of classTo type, or null if conversion is impossible
+     */
+    protected Object convert(String value, Class classTo) {
+        if (classTo == String.class) {
+            return value;
+        }
+        
+        /**
+         * We still try to it in BasicComboBox's way, so that primary object
+         * types (such as numbers) would still be supported 
+         */
+        try {
+            Method method = classTo.getMethod("valueOf", new Class[]{String.class});
+            return method.invoke(null, new Object[] { value});
+        }
+        catch (Exception ignored) {}
+        
+        /**
+         * We could manually convert strings to dbentities, attrs and other, but
+         * in this implementation we use reverse operation instead, and convert 
+         * combobox model's items to String.
+         * All string values are assumed unique is one model.
+         */
+        ComboBoxModel model = combo.getModel();
+        for (int i = 0; i < model.getSize(); i++) {
+            if (value.equals(CellRenderers.asString(model.getElementAt(i)))) {
+                return model.getElementAt(i);
+            }
+        }
+        
+        //we return null, since String will not be appreciated
+        return null;
+    }
+}

Added: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/EditorTextField.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/EditorTextField.java?rev=661168&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/EditorTextField.java (added)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/EditorTextField.java Wed May 28 17:51:17 2008
@@ -0,0 +1,91 @@
+/*****************************************************************
+ *   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.combo;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+
+import javax.swing.CellRendererPane;
+import javax.swing.JComboBox;
+import javax.swing.JList;
+import javax.swing.JTextField;
+import javax.swing.ListCellRenderer;
+
+/**
+ * EditorTextField is a text field to be used in combobox editor. It paints self normally
+ * when focused, otherwise combo's renderer is used.
+ * 
+ * @author Andrey Razumovsky
+ */
+public class EditorTextField extends JTextField implements FocusListener {
+
+    /**
+     * Edited combobox
+     */
+    protected JComboBox combo;
+
+    /**
+     * Panel to draw renderer component
+     */
+    private final CellRendererPane rendererPane;
+
+    /**
+     * Combo's popup list is unaccessible, so we use our own default list
+     */
+    private final JList list = new JList();
+
+    /**
+     * True if editor has focus.
+     */
+    private boolean hasFocus;
+
+    public EditorTextField(JComboBox edited) {
+        combo = edited;
+        rendererPane = new CellRendererPane();
+
+        addFocusListener(this);
+    }
+
+    @Override
+    public void paintComponent(Graphics g) {
+        if (hasFocus)
+            super.paintComponent(g);
+        else {
+            list.setEnabled(combo.isEnabled());
+
+            ListCellRenderer renderer = combo.getRenderer();
+            Component c = renderer.getListCellRendererComponent(list, combo
+                    .getSelectedItem(), -1, false, false);
+            rendererPane.paintComponent(g, c, combo, 0, 0, getWidth(), getHeight());
+        }
+    }
+
+    public void focusGained(FocusEvent e) {
+        hasFocus = true;
+
+        combo.repaint();
+    }
+
+    public void focusLost(FocusEvent e) {
+        hasFocus = false;
+        combo.repaint();
+    }
+}

Added: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/SuggestionList.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/SuggestionList.java?rev=661168&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/SuggestionList.java (added)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/SuggestionList.java Wed May 28 17:51:17 2008
@@ -0,0 +1,181 @@
+/*****************************************************************
+ *   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.combo;
+
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+import javax.swing.ComboBoxModel;
+import javax.swing.DefaultListModel;
+import javax.swing.JComboBox;
+import javax.swing.event.MouseInputAdapter;
+import javax.swing.plaf.basic.BasicComboPopup;
+
+import org.apache.cayenne.modeler.util.CellRenderers;
+
+/**
+ * SuggestionList is a combo-popup displaying all items matching for
+ * autocompletion.
+ * 
+ * @author Andrey Razumovsky
+ */
+public class SuggestionList extends BasicComboPopup {
+    /**
+     * 'Strict' matching, i.e. whether 'startWith' or 'contains' function
+     * should be used for checking match 
+     */
+    protected boolean strict;
+    
+    /**
+     * Creates a strict suggestion-popup for a combobox
+     */
+    public SuggestionList(JComboBox cb) {
+       this(cb, false); 
+    }
+    
+    /**
+     * Creates a suggestion-popup for a combobox
+     */
+    public SuggestionList(JComboBox cb, boolean strict) {
+        super(cb);
+        
+        this.strict = strict;
+        list.addMouseListener(new MouseHandler());
+    }
+    
+    /**
+     * 'Filters' the list, leaving only matching items
+     * @param prefix user-typed string, used to filter
+     */
+    public void filter(String prefix) {
+        ComboBoxModel model = comboBox.getModel();
+        DefaultListModel lm = new DefaultListModel();
+        
+        for (int i = 0; i < model.getSize(); i++) {
+            String item = CellRenderers.asString(model.getElementAt(i));
+            
+            if (matches(item, prefix)) {
+                lm.addElement(model.getElementAt(i));
+            }
+        }
+        
+        list.setModel(lm);
+    }
+    
+    /**
+     * Checks if an item matches input pattern
+     */
+    protected boolean matches(String item, String pattern) {
+        if (strict) {
+            return item.toLowerCase().startsWith(pattern.toLowerCase());
+        }
+        else {
+            return item.toLowerCase().contains(pattern.toLowerCase());
+        }
+    }
+    
+    /**
+     * Retrieves the height of the popup based on the current
+     * ListCellRenderer and the maximum row count.
+     * 
+     * Overrriden to count for local list size
+     */
+    @Override
+    protected int getPopupHeightForRowCount(int maxRowCount) {
+        int h = super.getPopupHeightForRowCount(Math.min(maxRowCount, list.getModel().getSize()));
+
+        return h;
+    }
+
+    /**
+     * @return selected index in popup
+     */
+    public int getSelectedIndex() {
+        return list.getSelectedIndex();
+    }
+    
+    /**
+     * @return selected item in popup
+     */
+    public Object getSelectedValue() {
+        return list.getSelectedValue();
+    }
+    
+    /**
+     * Selects an item in list
+     */
+    public void setSelectedIndex(int i) {
+        list.setSelectedIndex(i);
+        comboBox.setSelectedItem(list.getModel().getElementAt(i));
+    }
+    
+    /**
+     * @return current suggestions count
+     */
+    public int getItemCount() {
+        return list.getModel().getSize();
+    }
+    
+    /**
+     * @return an item from the list
+     */
+    public Object getItemAt(int i) {
+        return list.getModel().getElementAt(i);
+    }
+    
+    @Override
+    public MouseListener createListMouseListener() {
+        return new MouseHandler();
+    }
+    
+    /**
+     * We don't want items in the list be automatically selected at all
+     */
+    @Override
+    protected ItemListener createItemListener() {
+        return 
+          new ItemListener() {
+            public void itemStateChanged(ItemEvent e) {}
+          };
+    }
+    
+    /**
+     * @return Whether match-check is 'strict'
+     */
+    public boolean isStrict() {
+        return strict;
+    }
+    
+    protected class MouseHandler extends MouseInputAdapter {
+        @Override
+        public void mouseReleased(MouseEvent e) {
+            comboBox.setSelectedItem(list.getSelectedValue());
+            comboBox.setPopupVisible(false);
+
+            // Workaround for cancelling an edited item (JVM bug 4530953).
+            if (comboBox.isEditable() && comboBox.getEditor() != null) {
+                comboBox.configureEditor(comboBox.getEditor(), comboBox.getSelectedItem());
+            }
+            
+            hide();
+        }
+    }
+}



Mime
View raw message