Coverage Report - net.wotonomy.ui.swing.components.IconCellRenderer
 
Classes in this File Line Coverage Branch Coverage Complexity
IconCellRenderer
0% 
0% 
2.105
 
 1  
 /*
 2  
 Wotonomy: OpenStep design patterns for pure Java applications.
 3  
 Copyright (C) 2000 Intersect Software Corporation
 4  
 
 5  
 This library is free software; you can redistribute it and/or
 6  
 modify it under the terms of the GNU Lesser General Public
 7  
 License as published by the Free Software Foundation; either
 8  
 version 2.1 of the License, or (at your option) any later version.
 9  
 
 10  
 This library is distributed in the hope that it will be useful,
 11  
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 Lesser General Public License for more details.
 14  
 
 15  
 You should have received a copy of the GNU Lesser General Public
 16  
 License along with this library; if not, see http://www.gnu.org
 17  
 */
 18  
 
 19  
 package net.wotonomy.ui.swing.components;
 20  
 
 21  
 import java.awt.Color;
 22  
 import java.awt.Component;
 23  
 import java.awt.GridBagConstraints;
 24  
 import java.awt.GridBagLayout;
 25  
 import java.awt.Insets;
 26  
 import java.awt.Point;
 27  
 import java.awt.event.ActionEvent;
 28  
 import java.awt.event.ActionListener;
 29  
 import java.awt.event.MouseEvent;
 30  
 import java.awt.event.MouseListener;
 31  
 import java.util.Enumeration;
 32  
 import java.util.EventObject;
 33  
 import java.util.Vector;
 34  
 
 35  
 import javax.swing.Icon;
 36  
 import javax.swing.JButton;
 37  
 import javax.swing.JComponent;
 38  
 import javax.swing.JLabel;
 39  
 import javax.swing.JList;
 40  
 import javax.swing.JPanel;
 41  
 import javax.swing.JTable;
 42  
 import javax.swing.JTree;
 43  
 import javax.swing.ListCellRenderer;
 44  
 import javax.swing.SwingUtilities;
 45  
 import javax.swing.UIManager;
 46  
 import javax.swing.border.Border;
 47  
 import javax.swing.border.EmptyBorder;
 48  
 import javax.swing.border.LineBorder;
 49  
 import javax.swing.event.CellEditorListener;
 50  
 import javax.swing.event.ChangeEvent;
 51  
 import javax.swing.table.TableCellEditor;
 52  
 import javax.swing.table.TableCellRenderer;
 53  
 import javax.swing.tree.TreeCellEditor;
 54  
 import javax.swing.tree.TreeCellRenderer;
 55  
 
 56  
 /**
 57  
 * A cell renderer that displays icons in addition to text,
 58  
 * and additionally is an editor in case you want to click
 59  
 * the icon to trigger some kind of action.  
 60  
 * You probably should override both getStringForContext and
 61  
 * getIconForContext to achieve your desired results. 
 62  
 * To receive mouse clicks, set the same instance of the
 63  
 * renderer as the editor for the same component.<br><br>
 64  
 *
 65  
 * One notable addition is that this class is an action event
 66  
 * broadcaster.  ActionEvents are broadcast when the mouse is
 67  
 * clicked on the button with an action event containing a 
 68  
 * user-configurable string that defaults to CLICKED. <br><br>
 69  
 *
 70  
 * The renderer itself can be used as a JComponent if
 71  
 * you need something like a JLabel that allows you to click
 72  
 * on the icon.  You will want to call setIcon and setText
 73  
 * to configure the component since the renderer method would
 74  
 * not be called.  (If you add an instance of the renderer
 75  
 * to a container, you cannnot use the same instance as an
 76  
 * editor in a table, tree, or list.)
 77  
 *
 78  
 * @author michael@mpowers.net
 79  
 * @version $Revision: 904 $
 80  
 * $Date: 2006-02-18 23:19:05 +0000 (Sat, 18 Feb 2006) $
 81  
 */
 82  
 public class IconCellRenderer extends JPanel
 83  
         implements TableCellRenderer, TableCellEditor, 
 84  
         TreeCellRenderer, TreeCellEditor, ListCellRenderer,
 85  
         Runnable, ActionListener, MouseListener 
 86  
 {        
 87  
         public static final String CLICKED = "CLICKED";
 88  
         
 89  
         /**
 90  
         * The panel that is re-used to render everything.
 91  
         * This is returned by getRendererForContext.
 92  
         */
 93  
     protected JPanel rendererPanel;
 94  
         protected JLabel rendererLabel;
 95  
     protected JButton rendererButton;
 96  
 
 97  
         /**
 98  
         * The panel that is used to receive mouse clicks.
 99  
         * It must be a different component from rendererPanel.
 100  
         * This is returned by getEditorForContext.
 101  
         */
 102  
     protected JPanel editorPanel;
 103  
         protected JLabel editorLabel;
 104  
     protected JButton editorButton;
 105  
         
 106  
         private Object lastKnownValue;
 107  
     private JComponent lastKnownComponent;
 108  
                 
 109  
         // do as DefaultTableCellRenderer does
 110  
         private Border noFocusBorder;
 111  
         private Border treeFocusBorder;
 112  
         private Color unselectedForeground;
 113  
         private Color unselectedBackground;
 114  
         
 115  
         private Vector actionListeners;
 116  
         private String actionCommand;
 117  
         private Vector cellEditorListeners;
 118  
     
 119  
     private boolean editable;
 120  
     private boolean clickable;
 121  
                                     
 122  
     /**
 123  
     * Default constructor.
 124  
     */
 125  0
     public IconCellRenderer()
 126  0
     {                                                
 127  0
         editable = true;
 128  0
         clickable = true;
 129  
         
 130  0
         noFocusBorder = new EmptyBorder(1, 1, 1, 1);
 131  0
         treeFocusBorder = new LineBorder( 
 132  0
             UIManager.getColor("Tree.selectionBorderColor") );
 133  0
                 setActionCommand( CLICKED );
 134  
 
 135  0
         rendererPanel = new JPanel();
 136  0
         rendererPanel.setLayout( new GridBagLayout() );
 137  
 
 138  0
         editorPanel = this;
 139  0
         editorPanel.setLayout( new GridBagLayout() );
 140  
                         
 141  
         // set up constraints
 142  0
         GridBagConstraints imageConstraints = new GridBagConstraints();
 143  0
         imageConstraints.gridx = 0;
 144  0
         GridBagConstraints labelConstraints = new GridBagConstraints();
 145  0
         labelConstraints.fill = GridBagConstraints.HORIZONTAL;
 146  0
         labelConstraints.gridx = 1;
 147  0
         labelConstraints.weightx = 1.0;
 148  0
         labelConstraints.ipadx = 1;
 149  0
         labelConstraints.insets = new Insets( 0, 1, 0, 0 ); // sweat the pixel
 150  
 
 151  
         // make the editor panel go away when not in use
 152  
         // and pass through all mouse events to container        
 153  
         
 154  
         //this is not very useful since editorLabel and editorButton
 155  
         //get all of the events        
 156  0
         editorPanel.addMouseListener( this );
 157  
         
 158  0
                 rendererLabel = new JLabel();
 159  0
                 rendererLabel.setOpaque( false );
 160  0
         rendererPanel.add( rendererLabel, labelConstraints );
 161  
 
 162  0
                 editorLabel = new JLabel();
 163  0
         editorLabel.setText( "" ); // default state
 164  0
                 editorLabel.setOpaque( false );
 165  0
         editorPanel.add( editorLabel, labelConstraints );
 166  
 
 167  0
                 unselectedForeground = rendererLabel.getForeground();
 168  0
                 unselectedBackground = rendererLabel.getBackground();
 169  
         
 170  0
         rendererButton = new JButton();
 171  0
         rendererButton.setBorder( null );
 172  0
         rendererButton.setBorderPainted( false );
 173  0
         rendererButton.setContentAreaFilled( false );
 174  0
         rendererButton.setFocusPainted( false );
 175  0
         rendererButton.setMargin( new Insets( 0, 0, 0, 0 ) );
 176  0
         rendererPanel.add( rendererButton, imageConstraints );
 177  
         
 178  0
         editorButton = new JButton();
 179  0
         editorButton.setEnabled( clickable ); // default state
 180  0
         editorButton.setIcon( null ); // default state
 181  0
         editorButton.setBorder( null );
 182  0
         editorButton.setBorderPainted( false );                                            
 183  0
         editorButton.setContentAreaFilled( false );
 184  0
         editorButton.setFocusPainted( false );
 185  0
         editorButton.setMargin( new Insets( 0, 0, 0, 0 ) );        
 186  0
         editorPanel.add( editorButton, imageConstraints );
 187  
 
 188  0
         editorButton.addActionListener( this );      
 189  
 
 190  
         //add these in order to dispatch the MouseEvents
 191  
         //to the lastKnownComponent, and proper management of
 192  
         //DnD operations
 193  0
         editorLabel.addMouseListener( this );    
 194  0
         editorButton.addMouseListener( this );                    
 195  0
     }
 196  
     
 197  
 /**
 198  
 * Returns the text string currently displayed in the editor component.
 199  
 */    
 200  
     public String getText() 
 201  
     {
 202  0
         return editorLabel.getText();
 203  
     }
 204  
     
 205  
 /**
 206  
 * Sets the text string displayed in the editor component.
 207  
 * Default is an empty string.
 208  
 */
 209  
     public void setText( String aString )
 210  
     {
 211  0
         editorLabel.setText( aString );
 212  0
     }
 213  
 
 214  
 /**
 215  
 * Returns the icon currently displayed in the editor component.
 216  
 */    
 217  
     public Icon getIcon() 
 218  
     {
 219  0
         return editorButton.getIcon();
 220  
     }
 221  
     
 222  
 /**
 223  
 * Sets the icon currently displayed in the editor component.
 224  
 * Default is null.
 225  
 */
 226  
     public void setIcon( Icon anIcon )
 227  
     {
 228  0
         editorButton.setIcon( anIcon );
 229  0
         if ( !isClickable() )
 230  
         {
 231  0
             editorButton.setDisabledIcon( anIcon );
 232  
         }
 233  0
     }
 234  
 
 235  
 /**
 236  
 * Returns whether the editor component's label text is editable.
 237  
 */    
 238  
     public boolean isEditable() 
 239  
     {
 240  0
         return editable;
 241  
     }
 242  
     
 243  
 /**
 244  
 * Sets whether the editor component's label text is editable.
 245  
 * Default is true.  Editable text is not yet implemented.
 246  
 */
 247  
     public void setEditable( boolean isEditable )
 248  
     {
 249  0
         editable = isEditable;
 250  0
     }
 251  
 
 252  
 /**
 253  
 * Returns whether the editor component's icon is clickable.
 254  
 */    
 255  
     public boolean isClickable() 
 256  
     {
 257  0
         return clickable;
 258  
     }
 259  
     
 260  
 /**
 261  
 * Sets whether the editor component's icon is clickable.
 262  
 * Default is true.
 263  
 */
 264  
     public void setClickable( boolean isClickable )
 265  
     {
 266  0
         clickable = isClickable;
 267  0
         editorButton.setEnabled( clickable );
 268  0
     }
 269  
 
 270  
 /**
 271  
 * Returns the component from getRendererForContext.
 272  
 */    
 273  
     public Component getListCellRendererComponent(JList list,
 274  
                                               Object value,
 275  
                                               int index,
 276  
                                               boolean isSelected,
 277  
                                               boolean cellHasFocus)
 278  
     {
 279  0
         lastKnownComponent = list;
 280  0
         return getRendererForContext(
 281  0
             list, value, index, 0, isSelected, cellHasFocus, false, true );
 282  
     }
 283  
 
 284  
 /**
 285  
 * Returns the component from getRendererForContext.
 286  
 */
 287  
     public Component getTableCellRendererComponent(JTable table, Object value,
 288  
                      boolean isSelected, boolean hasFocus, int row, int column)
 289  
     {
 290  0
         lastKnownComponent = table;
 291  0
                 return getRendererForContext( 
 292  0
                         table, value, row, column, isSelected, hasFocus, false, true );
 293  
     }
 294  
 
 295  
 /**
 296  
 * Returns the component from getRendererForContext.
 297  
 */
 298  
     public Component getTreeCellRendererComponent(JTree tree,
 299  
                                               Object value,
 300  
                                               boolean selected,
 301  
                                               boolean expanded,
 302  
                                               boolean leaf,
 303  
                                               int row,
 304  
                                               boolean hasFocus)
 305  
     {                
 306  0
         lastKnownComponent = tree;
 307  0
                 return getRendererForContext( 
 308  0
                         tree, value, row, 0, selected, hasFocus, expanded, leaf );
 309  
     }
 310  
         
 311  
 /**
 312  
 * Returns getEditorForContext with the same parameters with hasFocus true.
 313  
 */
 314  
         public Component getTableCellEditorComponent(JTable table,
 315  
                 Object value, boolean isSelected, int row, int column)
 316  
         {
 317  0
                 lastKnownValue = value;
 318  0
         lastKnownComponent = table;
 319  0
                 return getEditorForContext( 
 320  0
                         table, value, row, column, isSelected, true, false, true );
 321  
         }
 322  
 
 323  
 /**
 324  
 * Returns the component from getEditorForContext with hasFocus true.
 325  
 */
 326  
     public Component getTreeCellEditorComponent(JTree tree,
 327  
                                                 Object value,
 328  
                                                 boolean isSelected,
 329  
                                                 boolean expanded,
 330  
                                                 boolean leaf,
 331  
                                                 int row)
 332  
     {
 333  
 
 334  
         
 335  0
         lastKnownValue = value;
 336  0
         lastKnownComponent = tree;
 337  
                 
 338  0
                 return getEditorForContext( 
 339  0
                         tree, value, row, 0, isSelected, true, expanded, leaf );
 340  
     }                                                
 341  
                                                 
 342  
 /**
 343  
 * This default implementation returns a JPanel that is configured by
 344  
 * calling configureComponentForContext.  
 345  
 * @return An component that is used to render content.
 346  
 */
 347  
     public Component getRendererForContext(
 348  
         JComponent container, Object value,
 349  
         int row, int column,
 350  
         boolean isSelected, boolean hasFocus, 
 351  
         boolean isExpanded, boolean isLeaf )
 352  
     {
 353  
 
 354  
                 
 355  0
                 configureComponentForContext( rendererPanel, rendererButton, rendererLabel, 
 356  0
             container, value, row, column,
 357  0
                         isSelected, hasFocus, isExpanded, isLeaf );
 358  0
                 return rendererPanel;
 359  
     }
 360  
 
 361  
 /**
 362  
 * This method returns a separate component that should be visually
 363  
 * identical to the renderer component.  We can't simply reuse the
 364  
 * renderer component because the renderer is still used to paint
 365  
 * the table while the editor component is displayed. Clicks are 
 366  
 * received on this component.
 367  
 * This default implementation returns a JPanel that is configured by
 368  
 * calling configureComponentForContext.  
 369  
 * @return A component used to receive clicks on the cell.
 370  
 */
 371  
     public Component getEditorForContext(
 372  
         JComponent container, Object value,
 373  
         int row, int column,
 374  
         boolean isSelected, boolean hasFocus, 
 375  
         boolean isExpanded, boolean isLeaf )
 376  
     {
 377  0
                 configureComponentForContext( editorPanel, editorButton, editorLabel, 
 378  0
             container, value, row, column,
 379  0
                         true, hasFocus, isExpanded, isLeaf ); // editor should always be selected
 380  
 
 381  0
                 return editorPanel;
 382  
     }
 383  
 
 384  
 /**
 385  
 * Called to configure components
 386  
 */ 
 387  
         protected void configureComponentForContext(
 388  
         JPanel component, JButton iconButton, JLabel label, 
 389  
         JComponent container, Object value, 
 390  
         int row, int column,
 391  
         boolean isSelected, boolean hasFocus, 
 392  
         boolean isExpanded, boolean isLeaf )
 393  
         {
 394  0
         if (hasFocus) 
 395  
         {
 396  0
             if ( container instanceof JTable )
 397  
             {
 398  0
                 component.setBorder( 
 399  0
                     UIManager.getBorder("Table.focusCellHighlightBorder") );
 400  0
             }
 401  
             else
 402  
             {
 403  0
                 component.setBorder( noFocusBorder );   
 404  
             }
 405  
 
 406  0
             if ( container instanceof JTree ) // was: (false)
 407  
             {   
 408  0
                 label.setBorder( treeFocusBorder );
 409  0
             }
 410  
             else
 411  
             {
 412  0
                 label.setBorder( noFocusBorder );
 413  
             }
 414  0
         } 
 415  
         else 
 416  
         {
 417  0
             label.setBorder(noFocusBorder);
 418  0
             component.setBorder(noFocusBorder);
 419  
         }
 420  
         
 421  0
         if (isSelected) 
 422  
         {
 423  0
             if ( container instanceof JTree )
 424  
             {
 425  0
                 label.setOpaque( true );
 426  0
                 label.setForeground(UIManager.getColor("Tree.selectionForeground"));
 427  0
                 label.setBackground(UIManager.getColor("Tree.selectionBackground"));
 428  0
                 component.setBackground(container.getBackground());
 429  0
             }
 430  0
             else if ( container instanceof JTable )
 431  
             {
 432  0
                 label.setOpaque( false );
 433  0
                 label.setForeground( ((JTable)container).getSelectionForeground() );
 434  0
                 component.setBackground(((JTable)container).getSelectionBackground());
 435  0
             }
 436  
             else
 437  
             {
 438  0
                 label.setOpaque( false );
 439  0
                 label.setForeground(UIManager.getColor("Table.selectionForeground"));
 440  0
                 component.setBackground(UIManager.getColor("Table.selectionBackground"));
 441  
             }
 442  0
         }
 443  
         else 
 444  
         {
 445  0
             label.setOpaque( false );
 446  0
             label.setForeground(container.getForeground());
 447  0
             component.setBackground(container.getBackground());
 448  
         }
 449  
 
 450  0
         label.setFont(container.getFont());
 451  
 
 452  0
         Icon icon = getIconForContext( 
 453  0
                         container, value, row, column, isSelected, hasFocus, isExpanded, isLeaf );
 454  0
         iconButton.setIcon( icon );
 455  0
         if ( !isClickable() )
 456  
         {
 457  0
             iconButton.setDisabledIcon( icon );
 458  
         }
 459  
 
 460  0
         String text = getStringForContext( 
 461  0
                         container, value, row, column, isSelected, hasFocus, isExpanded, isLeaf );
 462  
             
 463  0
                 if ( ( text == null ) || ( "".equals( text ) ) )
 464  
                 {
 465  0
             if ( ! label.getText().equals( "" ) )
 466  0
                             label.setText( "" );
 467  
                 }
 468  
                 else
 469  
                 {
 470  0
             if ( ! label.getText().equals( text ) )
 471  0
                             label.setText( text );
 472  
                 }
 473  0
         }
 474  
         
 475  
 /**
 476  
 * Override this method to provide an icon for the renderer.
 477  
 * This default implementation returns null.
 478  
 * @return An icon to be displayed in the cell, or null to omit the
 479  
 * icon from the cell.
 480  
 */
 481  
     public Icon getIconForContext(
 482  
         JComponent container, Object value,
 483  
         int row, int column,
 484  
         boolean isSelected, boolean hasFocus, 
 485  
         boolean isExpanded, boolean isLeaf )
 486  
     {
 487  0
         return null;
 488  
     }
 489  
 
 490  
 /**
 491  
 * Override this method to provide a string for the renderer.
 492  
 * This default implementation returns toString on the value parameter,
 493  
 * or null if the value is null.
 494  
 * @return A string to be displayed in the cell.
 495  
 */
 496  
     public String getStringForContext(
 497  
         JComponent container, Object value,
 498  
         int row, int column,
 499  
         boolean isSelected, boolean hasFocus, 
 500  
         boolean isExpanded, boolean isLeaf )
 501  
     {
 502  0
                 if ( value == null ) return null;
 503  0
         return value.toString();
 504  
     }
 505  
         
 506  
         /**
 507  
         * Adds the specified listener to the list of listeners
 508  
         * to be notified when the button receives a click.
 509  
         */
 510  
         public void addActionListener( ActionListener aListener )
 511  
         {
 512  0
                 if ( actionListeners == null ) 
 513  
                 {
 514  0
                         actionListeners = new Vector( 2 );        
 515  
                 }
 516  0
                 actionListeners.add( aListener );
 517  0
         }
 518  
         
 519  
         /**
 520  
         * Removes the specified listener from the list of listeners
 521  
         * to be notified when the button receives a click.
 522  
         */
 523  
         public void removeActionListener( ActionListener aListener )
 524  
         {
 525  0
                 actionListeners.remove( aListener );
 526  0
         }
 527  
         
 528  
         /**
 529  
         * Broadcasts the specified action event to all listeners.
 530  
         */
 531  
         protected void fireActionEvent( ActionEvent anActionEvent )
 532  
         {
 533  0
                 if ( actionListeners == null ) return;
 534  
                 // vector's enumeration is not fail-fast
 535  0
                 Enumeration e = actionListeners.elements();
 536  0
                 while ( e.hasMoreElements() )
 537  
                 {
 538  0
                         ((ActionListener)e.nextElement()).actionPerformed( anActionEvent );
 539  0
                 }
 540  0
         }
 541  
         
 542  
         /**
 543  
         * Returns the action command broadcast when this icon
 544  
     * receives a click.  Defaults to CLICKED.
 545  
         */
 546  
         public String getActionCommand()
 547  
         {
 548  0
                 return actionCommand;
 549  
         }
 550  
 
 551  
         /**
 552  
         * Sets the action command broadcast when this table
 553  
         * receives a double click.
 554  
         */        
 555  
         public void setActionCommand( String anActionCommand )
 556  
         {
 557  0
                 actionCommand = anActionCommand;        
 558  0
         }
 559  
         
 560  
 // interface CellEditor
 561  
 
 562  
         /**
 563  
         * Returns lastKnownValue, although this should not be called.
 564  
         */
 565  
         public Object getCellEditorValue()
 566  
         {
 567  0
                 return lastKnownValue;
 568  
         }
 569  
         
 570  
         /**
 571  
         * Returns true.
 572  
         */
 573  
         public boolean isCellEditable(EventObject anEvent)
 574  
         {
 575  0
         return true;
 576  
         }
 577  
         
 578  
         /**
 579  
         * Returns true.
 580  
         */
 581  
         public boolean shouldSelectCell(EventObject anEvent)
 582  
         {
 583  0
                 return true;
 584  
         }
 585  
         
 586  
         /**
 587  
         * Fires an editing stopped event and returns true.
 588  
         */
 589  
         public boolean stopCellEditing()
 590  
         {
 591  0
                 ChangeEvent event = new ChangeEvent( this );
 592  0
                 if ( cellEditorListeners != null )
 593  
                 {
 594  
                         // vector's enumeration is not fail-fast
 595  0
                         Enumeration e = cellEditorListeners.elements();
 596  0
                         while ( e.hasMoreElements() )
 597  
                         {
 598  
                 // broadcast editing cancelled since no value is edited
 599  0
                                 ((CellEditorListener)e.nextElement()).editingCanceled( event );
 600  0
                         }
 601  
                 }
 602  0
         lastKnownComponent = null;                
 603  0
                 return true;
 604  
         }
 605  
         
 606  
         /**
 607  
         * Fires an editing cancelled event and returns true.
 608  
         */
 609  
         public void cancelCellEditing()
 610  
         {                
 611  
                 //HACK: cancelCellEditing() causes for the dragGesture
 612  
                 //to be NOT recognized AT ALL since on the next MOUSE_PRESSED
 613  
                 //the cell editor first needs to startEditing() [if in the tree
 614  
                 //the CellEditorListener is a BasicTreeUI class] 
 615  
                 //(before the drag gesture event can be recognized).        
 616  
         //Also the lastKnownComponent should not be set to null, 
 617  
         //none of the mouse events won't dispathced to the lastKnownComponent
 618  
         //in that case.                
 619  
                 
 620  
                 //Not calling it at all does seem to fix it, but what are the
 621  
                 //consequences???
 622  
                 //Trying to workaround this might solve it, but it introduces having
 623  
                 //an extra listener (a MouseMotionListnener), which might be wasteful
 624  
                 //(i.e. only if a Mouse_dragged event has been initiated, but DragGesture
 625  
                 //hasn't been recognized, postpone calling this till finish the DnD event)
 626  
                 //But what if do DnD and not exited ??? The mouseExited() is not called
 627  
                 //anyway until the DnD event is done.                                
 628  
                                         
 629  0
                 ChangeEvent event = new ChangeEvent( this );
 630  0
                 if ( cellEditorListeners == null ) return;
 631  
                 // vector's enumeration is not fail-fast
 632  0
                 Enumeration e = cellEditorListeners.elements();
 633  
                 
 634  0
                 while ( e.hasMoreElements() )
 635  
                 {            
 636  0
                         ((CellEditorListener)e.nextElement()).editingCanceled( event );
 637  0
                 }                
 638  
         
 639  
         //DO not nullify this 
 640  0
         lastKnownComponent = null;                       
 641  0
         }
 642  
         
 643  
         /**
 644  
         * Adds the specified listener to the list of listeners
 645  
         * to be notified when the table receives a double click.
 646  
         */
 647  
         public void addCellEditorListener( CellEditorListener aListener )
 648  
         {                
 649  0
                 if ( cellEditorListeners == null ) 
 650  
                 {
 651  0
                         cellEditorListeners = new Vector( 2 );        
 652  
                 }
 653  0
                 cellEditorListeners.add( aListener );        
 654  0
         }
 655  
         
 656  
         /**
 657  
         * Removes the specified listener from the list of listeners
 658  
         * to be notified when the table receives a double click.
 659  
         */
 660  
         public void removeCellEditorListener( CellEditorListener aListener )
 661  
         {
 662  0
                 cellEditorListeners.remove( aListener );
 663  0
         }
 664  
     
 665  
 // interface ActionListener
 666  
     
 667  
     /**
 668  
     * Puts ourself on the end of the event queue for 
 669  
     * firing our action event to all listeners.
 670  
     */
 671  
     public void actionPerformed( ActionEvent evt )
 672  
     {        
 673  
         //commented out in order NOT to set lastKnownComponent to null, since
 674  
         //if this object is inside a table or tree, relying on getCellEditorValue() 
 675  
         //to return the currently edited object
 676  
         //cancelCellEditing();        
 677  
         
 678  0
         SwingUtilities.invokeLater( this );
 679  0
     }
 680  
         
 681  
 // interface Runnable
 682  
         
 683  
         /**
 684  
         * Fires the action event to all listeners.  
 685  
         * This is triggered by a click on the icon.
 686  
         */
 687  
         public void run()
 688  
         {
 689  0
                 fireActionEvent( new ActionEvent( this, 0, getActionCommand() ) );        
 690  0
         }
 691  
 
 692  
 // interface MouseListener 
 693  
     
 694  
     /**
 695  
     * Passes through editor mouse clicks to last known component.
 696  
     * (left click only)
 697  
     */
 698  
         public void mouseClicked(MouseEvent e)
 699  
     {                        
 700  0
         if(lastKnownComponent != null){
 701  0
             Object source = e.getSource();            
 702  0
             if(source != null)
 703  
             {
 704  0
                 if(source == editorPanel)
 705  
                 {
 706  0
                     lastKnownComponent.dispatchEvent(                 
 707  0
                             SwingUtilities.convertMouseEvent(                    
 708  0
                                 editorPanel, e, lastKnownComponent ) );                     
 709  
 
 710  0
                 }                
 711  0
                 else if(source == editorLabel)
 712  
                 {
 713  0
                     lastKnownComponent.dispatchEvent(                 
 714  0
                         SwingUtilities.convertMouseEvent(                    
 715  0
                             editorLabel, e, lastKnownComponent ) );         
 716  0
                 }           
 717  
 
 718  0
                 else if(source == editorButton)
 719  
                 {
 720  0
                     lastKnownComponent.dispatchEvent(                 
 721  0
                         SwingUtilities.convertMouseEvent(                    
 722  0
                             editorButton, e, lastKnownComponent ) );         
 723  
                 }           
 724  
             }                
 725  
         }                
 726  0
     }
 727  
 
 728  
     /**
 729  
     * Passes through editor right-mouse (popup trigger) mouse events to last known component.
 730  
     * Needed for possible displaying of popup menus on right click 
 731  
     */
 732  
     public void mousePressed(MouseEvent e)
 733  
     {                
 734  0
         if ( e.isPopupTrigger() )
 735  
         {
 736  0
             if(lastKnownComponent != null)
 737  
             {
 738  0
                 Object source = e.getSource();            
 739  0
                 if(source != null)
 740  
                 {
 741  0
                     if(source == editorPanel)
 742  
                     {                     
 743  0
                         lastKnownComponent.dispatchEvent(                 
 744  0
                                 SwingUtilities.convertMouseEvent(                    
 745  0
                                     editorPanel, e, lastKnownComponent ) );                     
 746  0
                     }
 747  0
                     else if(source == editorLabel)
 748  
                     {
 749  0
                         lastKnownComponent.dispatchEvent(                 
 750  0
                             SwingUtilities.convertMouseEvent(                    
 751  0
                                 editorLabel, e, lastKnownComponent ) );         
 752  0
                     }           
 753  
     
 754  0
                     else if(source == editorButton)
 755  
                     {   
 756  0
                         lastKnownComponent.dispatchEvent(                 
 757  0
                             SwingUtilities.convertMouseEvent(                    
 758  0
                                 editorButton, e, lastKnownComponent ) );         
 759  
                     }           
 760  
                 }                
 761  
             }
 762  
         }                
 763  0
     }
 764  
 
 765  
     /**
 766  
     * Does nothing.
 767  
     */
 768  
     public void mouseReleased(MouseEvent e)
 769  
     {                      
 770  0
         if ( e.isPopupTrigger() )
 771  
         {
 772  0
             if(lastKnownComponent != null){        
 773  
     
 774  0
                 Object source = e.getSource();            
 775  0
                 if(source != null)
 776  
                 {
 777  0
                     if(source == editorPanel) 
 778  
                     {                    
 779  0
                         lastKnownComponent.dispatchEvent(                 
 780  0
                                 SwingUtilities.convertMouseEvent(                    
 781  0
                                     editorPanel, e, lastKnownComponent ) );                     
 782  0
                     }            
 783  
         
 784  0
                     else if(source == editorLabel) 
 785  
                     {
 786  0
                         lastKnownComponent.dispatchEvent(                 
 787  0
                             SwingUtilities.convertMouseEvent(                    
 788  0
                                 editorLabel, e, lastKnownComponent ) );         
 789  0
                     }           
 790  
     
 791  0
                     else if(source == editorButton) 
 792  
                     {
 793  0
                         lastKnownComponent.dispatchEvent(                 
 794  0
                             SwingUtilities.convertMouseEvent(                    
 795  0
                                 editorButton, e, lastKnownComponent ) );         
 796  
                     }           
 797  
                 }                
 798  
             }
 799  
         }                
 800  0
     }
 801  
 
 802  
     /**
 803  
     * Does nothing.
 804  
     */
 805  
     public void mouseEntered(MouseEvent e)
 806  
     {
 807  0
     }
 808  
     
 809  
     /**
 810  
     * Cancels cell editing.
 811  
     */
 812  
     public void mouseExited(MouseEvent e)
 813  
     {        
 814  0
         Object source = e.getSource();
 815  0
         if(source != null && source instanceof JComponent){
 816  
             //need to convert the Point from the source's coordinate system to editorPanel's coordinate system.
 817  
             //(note that simple editorPanel.contains(e.getPoint()) fails if source is editorButton)
 818  
             
 819  0
             Point convertedPoint = SwingUtilities.convertPoint((JComponent) source, e.getPoint(), editorPanel); 
 820  
             
 821  
             //check if exited from editorButton, but still inside the editorPanel (works for editorLabel as well)            
 822  0
             if(!editorPanel.contains(convertedPoint)){
 823  
 
 824  
                 //This was getting called before, but it interfers with the DnD operation
 825  0
                 cancelCellEditing();
 826  
             }
 827  
         }      
 828  0
     }
 829  
     
 830  
     /* This might be redundant    
 831  
     public void cleanUp(){
 832  
         
 833  
         //since cancelCellEditing() was never called call it now                
 834  
         cancelCellEditing();
 835  
         stopCellEditing();
 836  
         
 837  
         editorButton.removeActionListener( this );      
 838  
         editorPanel.removeMouseListener( this ); 
 839  
         editorLabel.removeMouseListener( this );    
 840  
         editorButton.removeMouseListener( this );                            
 841  
         lastKnownComponent = null;
 842  
         lastKnownValue = null;
 843  
     }        
 844  
     */
 845  
 }