KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > j2seproject > ui > customizer > J2SESourceRootsUi


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.java.j2seproject.ui.customizer;
21
22 import java.awt.*;
23 import java.awt.event.ActionEvent JavaDoc;
24 import java.awt.event.ActionListener JavaDoc;
25 import java.io.File JavaDoc;
26 import java.net.URI JavaDoc;
27 import java.net.URL JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.HashSet JavaDoc;
31 import java.util.Set JavaDoc;
32 import java.util.Vector JavaDoc;
33 import java.text.MessageFormat JavaDoc;
34 import javax.swing.*;
35 import javax.swing.JButton JavaDoc;
36 import javax.swing.event.ListSelectionEvent JavaDoc;
37 import javax.swing.event.ListSelectionListener JavaDoc;
38 import javax.swing.event.CellEditorListener JavaDoc;
39 import javax.swing.event.ChangeEvent JavaDoc;
40 import javax.swing.table.DefaultTableCellRenderer JavaDoc;
41 import javax.swing.table.DefaultTableModel JavaDoc;
42 import org.netbeans.api.java.project.JavaProjectConstants;
43 import org.netbeans.api.project.ProjectUtils;
44 import org.netbeans.api.project.SourceGroup;
45 import org.netbeans.api.project.Sources;
46 import org.netbeans.modules.java.j2seproject.J2SEProject;
47 import org.netbeans.modules.java.j2seproject.ui.FoldersListSettings;
48 import org.netbeans.api.project.FileOwnerQuery;
49 import org.netbeans.api.project.Project;
50 import org.netbeans.api.project.ProjectInformation;
51 import org.netbeans.modules.java.j2seproject.SourceRoots;
52 import org.openide.DialogDisplayer;
53 import org.openide.DialogDescriptor;
54 import org.openide.NotifyDescriptor;
55 import org.openide.filesystems.FileObject;
56 import org.openide.filesystems.FileUtil;
57 import org.openide.util.NbBundle;
58 import org.openide.util.HelpCtx;
59
60 /** Handles adding, removing, reordering of source roots.
61  *
62  * @author Tomas Zezula
63  */

64 public final class J2SESourceRootsUi {
65   
66     public static DefaultTableModel JavaDoc createModel( SourceRoots roots ) {
67         
68         String JavaDoc[] rootLabels = roots.getRootNames();
69         String JavaDoc[] rootProps = roots.getRootProperties();
70         URL JavaDoc[] rootURLs = roots.getRootURLs();
71         Object JavaDoc[][] data = new Object JavaDoc[rootURLs.length] [2];
72         for (int i=0; i< rootURLs.length; i++) {
73             data[i][0] = new File JavaDoc (URI.create (rootURLs[i].toExternalForm()));
74             data[i][1] = roots.getRootDisplayName(rootLabels[i], rootProps[i]);
75         }
76         return new SourceRootsModel(data);
77                 
78     }
79     
80     public static EditMediator registerEditMediator( J2SEProject master,
81                                              SourceRoots sourceRoots,
82                                              JTable rootsList,
83                                              JButton JavaDoc addFolderButton,
84                                              JButton JavaDoc removeButton,
85                                              JButton JavaDoc upButton,
86                                              JButton JavaDoc downButton) {
87         
88         EditMediator em = new EditMediator( master,
89                                             sourceRoots,
90                                             rootsList,
91                                             addFolderButton,
92                                             removeButton,
93                                             upButton,
94                                             downButton);
95         
96         // Register the listeners
97
// On all buttons
98
addFolderButton.addActionListener( em );
99         removeButton.addActionListener( em );
100         upButton.addActionListener( em );
101         downButton.addActionListener( em );
102         // On list selection
103
rootsList.getSelectionModel().addListSelectionListener( em );
104         DefaultCellEditor editor = new DefaultCellEditor(new JTextField());
105         editor.addCellEditorListener (em);
106         rootsList.setDefaultRenderer( File JavaDoc.class, new FileRenderer (FileUtil.toFile(master.getProjectDirectory())));
107         rootsList.setDefaultEditor(String JavaDoc.class, editor);
108         // Set the initial state of the buttons
109
em.valueChanged( null );
110         
111         DefaultTableModel JavaDoc model = (DefaultTableModel JavaDoc)rootsList.getModel();
112         String JavaDoc[] columnNames = new String JavaDoc[2];
113         columnNames[0] = NbBundle.getMessage( J2SESourceRootsUi.class,"CTL_PackageFolders");
114         columnNames[1] = NbBundle.getMessage( J2SESourceRootsUi.class,"CTL_PackageLabels");
115         model.setColumnIdentifiers(columnNames);
116         rootsList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
117         
118         return em;
119     }
120     
121     /**
122      * Opens the standard dialog for warning an user about illegal source roots.
123      * @param roots the set of illegal source/test roots
124      */

125     public static void showIllegalRootsDialog (Set JavaDoc/*<File>*/ roots) {
126         JButton JavaDoc closeOption = new JButton JavaDoc (NbBundle.getMessage(J2SESourceRootsUi.class,"CTL_J2SESourceRootsUi_Close"));
127         closeOption.getAccessibleContext ().setAccessibleDescription (NbBundle.getMessage(J2SESourceRootsUi.class,"AD_J2SESourceRootsUi_Close"));
128         JPanel warning = new WarningDlg (roots);
129         String JavaDoc message = NbBundle.getMessage(J2SESourceRootsUi.class,"MSG_InvalidRoot");
130         JOptionPane optionPane = new JOptionPane (new Object JavaDoc[] {message, warning},
131             JOptionPane.WARNING_MESSAGE,
132             0,
133             null,
134             new Object JavaDoc[0],
135             null);
136         optionPane.getAccessibleContext().setAccessibleDescription (NbBundle.getMessage(J2SESourceRootsUi.class,"AD_InvalidRootDlg"));
137         DialogDescriptor dd = new DialogDescriptor (optionPane,
138             NbBundle.getMessage(J2SESourceRootsUi.class,"TITLE_InvalidRoot"),
139             true,
140             new Object JavaDoc[] {
141                 closeOption,
142             },
143             closeOption,
144             DialogDescriptor.DEFAULT_ALIGN,
145             null,
146             null);
147         DialogDisplayer.getDefault().notify(dd);
148     }
149         
150     // Private innerclasses ----------------------------------------------------
151

152     public static class EditMediator implements ActionListener JavaDoc, ListSelectionListener JavaDoc, CellEditorListener JavaDoc {
153
154         
155         final JTable rootsList;
156         final JButton JavaDoc addFolderButton;
157         final JButton JavaDoc removeButton;
158         final JButton JavaDoc upButton;
159         final JButton JavaDoc downButton;
160         private final Project project;
161         private final SourceRoots sourceRoots;
162         private final Set JavaDoc ownedFolders;
163         private DefaultTableModel JavaDoc rootsModel;
164         private EditMediator relatedEditMediator;
165         private File JavaDoc lastUsedDir; //Last used current folder in JFileChooser
166

167         
168         public EditMediator( J2SEProject master,
169                              SourceRoots sourceRoots,
170                              JTable rootsList,
171                              JButton JavaDoc addFolderButton,
172                              JButton JavaDoc removeButton,
173                              JButton JavaDoc upButton,
174                              JButton JavaDoc downButton) {
175
176             if ( !( rootsList.getModel() instanceof DefaultTableModel JavaDoc ) ) {
177                 throw new IllegalArgumentException JavaDoc( "Jtable's model has to be of class DefaultTableModel" ); // NOI18N
178
}
179                     
180             this.rootsList = rootsList;
181             this.addFolderButton = addFolderButton;
182             this.removeButton = removeButton;
183             this.upButton = upButton;
184             this.downButton = downButton;
185             this.ownedFolders = new HashSet JavaDoc();
186
187             this.project = master;
188             this.sourceRoots = sourceRoots;
189
190             this.ownedFolders.clear();
191             this.rootsModel = (DefaultTableModel JavaDoc)rootsList.getModel();
192             Vector JavaDoc data = rootsModel.getDataVector();
193             for (Iterator JavaDoc it = data.iterator(); it.hasNext();) {
194                 Vector JavaDoc row = (Vector JavaDoc) it.next ();
195                 File JavaDoc f = (File JavaDoc) row.elementAt(0);
196                 this.ownedFolders.add (f);
197             }
198         }
199         
200         public void setRelatedEditMediator(EditMediator rem) {
201             this.relatedEditMediator = rem;
202         }
203         
204         // Implementation of ActionListener ------------------------------------
205

206         /** Handles button events
207          */

208         public void actionPerformed( ActionEvent JavaDoc e ) {
209             
210             Object JavaDoc source = e.getSource();
211             
212             if ( source == addFolderButton ) {
213                 
214                 // Let user search for the Jar file
215
JFileChooser chooser = new JFileChooser();
216                 FileUtil.preventFileChooserSymlinkTraversal(chooser, null);
217                 chooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY );
218                 chooser.setMultiSelectionEnabled( true );
219                 if (this.sourceRoots.isTest()) {
220                     chooser.setDialogTitle( NbBundle.getMessage( J2SESourceRootsUi.class, "LBL_TestFolder_DialogTitle" )); // NOI18N
221
}
222                 else {
223                     chooser.setDialogTitle( NbBundle.getMessage( J2SESourceRootsUi.class, "LBL_SourceFolder_DialogTitle" )); // NOI18N
224
}
225                 File JavaDoc curDir = this.lastUsedDir;
226                 if (curDir == null) {
227                     curDir = FileUtil.toFile(this.project.getProjectDirectory());
228                 }
229                 if (curDir != null) {
230                     chooser.setCurrentDirectory (curDir);
231                 }
232                 int option = chooser.showOpenDialog( SwingUtilities.getWindowAncestor( addFolderButton ) ); // Sow the chooser
233

234                 if ( option == JFileChooser.APPROVE_OPTION ) {
235                     curDir = chooser.getCurrentDirectory();
236                     if (curDir != null) {
237                         this.lastUsedDir = curDir;
238                         if (this.relatedEditMediator != null) {
239                             this.relatedEditMediator.lastUsedDir = curDir;
240                         }
241                     }
242                     File JavaDoc files[] = chooser.getSelectedFiles();
243                     addFolders( files );
244                 }
245                 
246             }
247             else if ( source == removeButton ) {
248                 removeElements();
249             }
250             else if ( source == upButton ) {
251                 moveUp();
252             }
253             else if ( source == downButton ) {
254                 moveDown();
255             }
256         }
257         
258         // Selection listener implementation ----------------------------------
259

260         /** Handles changes in the selection
261          */

262         public void valueChanged( ListSelectionEvent JavaDoc e ) {
263             
264             int[] si = rootsList.getSelectedRows();
265             
266             // addJar allways enabled
267

268             // addLibrary allways enabled
269

270             // addArtifact allways enabled
271

272             // edit enabled only if selection is not empty
273
boolean edit = si != null && si.length > 0;
274
275             // remove enabled only if selection is not empty
276
boolean remove = si != null && si.length > 0;
277             // and when the selection does not contain unremovable item
278

279             // up button enabled if selection is not empty
280
// and the first selected index is not the first row
281
boolean up = si != null && si.length > 0 && si[0] != 0;
282             
283             // up button enabled if selection is not empty
284
// and the laset selected index is not the last row
285
boolean down = si != null && si.length > 0 && si[si.length-1] !=rootsList.getRowCount() - 1;
286
287             removeButton.setEnabled( remove );
288             upButton.setEnabled( up );
289             downButton.setEnabled( down );
290                         
291             //System.out.println("Selection changed " + edit + ", " + remove + ", " + + ", " + + ", ");
292

293         }
294
295         public void editingCanceled(ChangeEvent JavaDoc e) {
296
297         }
298
299         public void editingStopped(ChangeEvent JavaDoc e) {
300             // fireActionPerformed();
301
}
302         
303         private void addFolders( File JavaDoc files[] ) {
304             int[] si = rootsList.getSelectedRows();
305             int lastIndex = si == null || si.length == 0 ? -1 : si[si.length - 1];
306             ListSelectionModel selectionModel = this.rootsList.getSelectionModel();
307             selectionModel.clearSelection();
308             Set JavaDoc rootsFromOtherProjects = new HashSet JavaDoc ();
309             Set JavaDoc rootsFromRelatedSourceRoots = new HashSet JavaDoc();
310 out: for( int i = 0; i < files.length; i++ ) {
311                 File JavaDoc normalizedFile = FileUtil.normalizeFile(files[i]);
312                 Project p;
313                 if (ownedFolders.contains(normalizedFile)) {
314                     Vector JavaDoc dataVector = rootsModel.getDataVector();
315                     for (int j=0; j<dataVector.size();j++) {
316                         //Sequential search in this minor case is faster than update of positions during each modification
317
File JavaDoc f = (File JavaDoc )((Vector JavaDoc)dataVector.elementAt(j)).elementAt(0);
318                         if (f.equals(normalizedFile)) {
319                             selectionModel.addSelectionInterval(j,j);
320                         }
321                     }
322                 }
323                 else if (this.relatedEditMediator != null && this.relatedEditMediator.ownedFolders.contains(normalizedFile)) {
324                     rootsFromRelatedSourceRoots.add (normalizedFile);
325                     continue;
326                 }
327                 if ((p=FileOwnerQuery.getOwner(normalizedFile.toURI()))!=null && !p.getProjectDirectory().equals(project.getProjectDirectory())) {
328                     final Sources sources = (Sources) p.getLookup().lookup (Sources.class);
329                     if (sources == null) {
330                         rootsFromOtherProjects.add (normalizedFile);
331                         continue;
332                     }
333                     final SourceGroup[] sourceGroups = sources.getSourceGroups(Sources.TYPE_GENERIC);
334                     final SourceGroup[] javaGroups = sources.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
335                     final SourceGroup[] groups = new SourceGroup [sourceGroups.length + javaGroups.length];
336                     System.arraycopy(sourceGroups,0,groups,0,sourceGroups.length);
337                     System.arraycopy(javaGroups,0,groups,sourceGroups.length,javaGroups.length);
338                     final FileObject projectDirectory = p.getProjectDirectory();
339                     final FileObject fileObject = FileUtil.toFileObject(normalizedFile);
340                     if (projectDirectory == null || fileObject == null) {
341                         rootsFromOtherProjects.add (normalizedFile);
342                         continue;
343                     }
344                     for (int j=0; j<groups.length; j++) {
345                         final FileObject sgRoot = groups[j].getRootFolder();
346                         if (fileObject.equals(sgRoot)) {
347                             rootsFromOtherProjects.add (normalizedFile);
348                             continue out;
349                         }
350                         if (!projectDirectory.equals(sgRoot) && FileUtil.isParentOf(sgRoot, fileObject)) {
351                             rootsFromOtherProjects.add (normalizedFile);
352                             continue out;
353                         }
354                     }
355                 }
356                 int current = lastIndex + 1 + i;
357                 rootsModel.insertRow( current, new Object JavaDoc[] {normalizedFile, sourceRoots.createInitialDisplayName(normalizedFile)}); //NOI18N
358
selectionModel.addSelectionInterval(current,current);
359                 this.ownedFolders.add (normalizedFile);
360             }
361             if (rootsFromOtherProjects.size() > 0 || rootsFromRelatedSourceRoots.size() > 0) {
362                 rootsFromOtherProjects.addAll(rootsFromRelatedSourceRoots);
363                 showIllegalRootsDialog (rootsFromOtherProjects);
364             }
365             // fireActionPerformed();
366
}
367
368         private void removeElements() {
369
370             int[] si = rootsList.getSelectedRows();
371
372             if( si == null || si.length == 0 ) {
373                 assert false : "Remove button should be disabled"; // NOI18N
374
}
375
376             // Remove the items
377
for( int i = si.length - 1 ; i >= 0 ; i-- ) {
378                 this.ownedFolders.remove(((Vector JavaDoc)rootsModel.getDataVector().elementAt(si[i])).elementAt(0));
379                 rootsModel.removeRow( si[i] );
380             }
381
382
383             if ( rootsModel.getRowCount() != 0) {
384                 // Select reasonable item
385
int selectedIndex = si[si.length - 1] - si.length + 1;
386                 if ( selectedIndex > rootsModel.getRowCount() - 1) {
387                     selectedIndex = rootsModel.getRowCount() - 1;
388                 }
389                 rootsList.setRowSelectionInterval( selectedIndex, selectedIndex );
390             }
391
392             // fireActionPerformed();
393

394         }
395
396         private void moveUp() {
397
398             int[] si = rootsList.getSelectedRows();
399
400             if( si == null || si.length == 0 ) {
401                 assert false : "MoveUp button should be disabled"; // NOI18N
402
}
403
404             // Move the items up
405
ListSelectionModel selectionModel = this.rootsList.getSelectionModel();
406             selectionModel.clearSelection();
407             for( int i = 0; i < si.length; i++ ) {
408                 Vector JavaDoc item = (Vector JavaDoc) rootsModel.getDataVector().elementAt(si[i]);
409                 int newIndex = si[i]-1;
410                 rootsModel.removeRow( si[i] );
411                 rootsModel.insertRow( newIndex, item );
412                 selectionModel.addSelectionInterval(newIndex,newIndex);
413             }
414             // fireActionPerformed();
415
}
416
417         private void moveDown() {
418
419             int[] si = rootsList.getSelectedRows();
420
421             if( si == null || si.length == 0 ) {
422                 assert false : "MoveDown button should be disabled"; // NOI18N
423
}
424
425             // Move the items up
426
ListSelectionModel selectionModel = this.rootsList.getSelectionModel();
427             selectionModel.clearSelection();
428             for( int i = si.length -1 ; i >= 0 ; i-- ) {
429                 Vector JavaDoc item = (Vector JavaDoc) rootsModel.getDataVector().elementAt(si[i]);
430                 int newIndex = si[i] + 1;
431                 rootsModel.removeRow( si[i] );
432                 rootsModel.insertRow( newIndex, item );
433                 selectionModel.addSelectionInterval(newIndex,newIndex);
434             }
435             // fireActionPerformed();
436
}
437         
438
439     }
440
441     private static class SourceRootsModel extends DefaultTableModel JavaDoc {
442
443         public SourceRootsModel (Object JavaDoc[][] data) {
444             super (data,new Object JavaDoc[]{"location","label"});//NOI18N
445
}
446
447         public boolean isCellEditable(int row, int column) {
448             return column == 1;
449         }
450
451         public Class JavaDoc getColumnClass(int columnIndex) {
452             switch (columnIndex) {
453                 case 0:
454                     return File JavaDoc.class;
455                 case 1:
456                     return String JavaDoc.class;
457                 default:
458                     return super.getColumnClass (columnIndex);
459             }
460         }
461     }
462     
463     private static class FileRenderer extends DefaultTableCellRenderer JavaDoc {
464         
465         private File JavaDoc projectFolder;
466         
467         public FileRenderer (File JavaDoc projectFolder) {
468             this.projectFolder = projectFolder;
469         }
470         
471         public Component getTableCellRendererComponent(JTable table, Object JavaDoc value, boolean isSelected, boolean hasFocus,int row, int column) {
472             String JavaDoc displayName;
473             if (value instanceof File JavaDoc) {
474                 File JavaDoc root = (File JavaDoc) value;
475                 String JavaDoc pfPath = projectFolder.getAbsolutePath() + File.separatorChar;
476                 String JavaDoc srPath = root.getAbsolutePath();
477                 if (srPath.startsWith(pfPath)) {
478                     displayName = srPath.substring(pfPath.length());
479                 }
480                 else {
481                     displayName = srPath;
482                 }
483             }
484             else {
485                 displayName = null;
486             }
487             Component c = super.getTableCellRendererComponent(table, displayName, isSelected, hasFocus, row, column);
488             if (c instanceof JComponent) {
489                 ((JComponent) c).setToolTipText (displayName);
490             }
491             return c;
492         }
493         
494     }
495
496     private static class WarningDlg extends JPanel {
497
498         public WarningDlg (Set JavaDoc invalidRoots) {
499             this.initGui (invalidRoots);
500         }
501
502         private void initGui (Set JavaDoc invalidRoots) {
503             setLayout( new GridBagLayout ());
504             JLabel label = new JLabel ();
505             label.setText (NbBundle.getMessage(J2SESourceRootsUi.class,"LBL_InvalidRoot"));
506             label.setDisplayedMnemonic(NbBundle.getMessage(J2SESourceRootsUi.class,"MNE_InvalidRoot").charAt(0));
507             GridBagConstraints c = new GridBagConstraints();
508             c.gridx = GridBagConstraints.RELATIVE;
509             c.gridy = GridBagConstraints.RELATIVE;
510             c.gridwidth = GridBagConstraints.REMAINDER;
511             c.fill = GridBagConstraints.HORIZONTAL;
512             c.anchor = GridBagConstraints.NORTHWEST;
513             c.weightx = 1.0;
514             c.insets = new Insets (12,0,6,0);
515             ((GridBagLayout)this.getLayout()).setConstraints(label,c);
516             this.add (label);
517             JList roots = new JList (invalidRoots.toArray());
518             roots.setCellRenderer (new InvalidRootRenderer(true));
519             JScrollPane p = new JScrollPane (roots);
520             c = new GridBagConstraints();
521             c.gridx = GridBagConstraints.RELATIVE;
522             c.gridy = GridBagConstraints.RELATIVE;
523             c.gridwidth = GridBagConstraints.REMAINDER;
524             c.fill = GridBagConstraints.BOTH;
525             c.anchor = GridBagConstraints.NORTHWEST;
526             c.weightx = c.weighty = 1.0;
527             c.insets = new Insets (0,0,12,0);
528             ((GridBagLayout)this.getLayout()).setConstraints(p,c);
529             this.add (p);
530             label.setLabelFor(roots);
531             roots.getAccessibleContext().setAccessibleDescription (NbBundle.getMessage(J2SESourceRootsUi.class,"AD_InvalidRoot"));
532             JLabel label2 = new JLabel ();
533             label2.setText (NbBundle.getMessage(J2SESourceRootsUi.class,"MSG_InvalidRoot2"));
534             c = new GridBagConstraints();
535             c.gridx = GridBagConstraints.RELATIVE;
536             c.gridy = GridBagConstraints.RELATIVE;
537             c.gridwidth = GridBagConstraints.REMAINDER;
538             c.fill = GridBagConstraints.HORIZONTAL;
539             c.anchor = GridBagConstraints.NORTHWEST;
540             c.weightx = 1.0;
541             c.insets = new Insets (0,0,0,0);
542             ((GridBagLayout)this.getLayout()).setConstraints(label2,c);
543             this.add (label2);
544         }
545
546         private static class InvalidRootRenderer extends DefaultListCellRenderer {
547
548             private boolean projectConflict;
549
550             public InvalidRootRenderer (boolean projectConflict) {
551                 this.projectConflict = projectConflict;
552             }
553
554             public Component getListCellRendererComponent(JList list, Object JavaDoc value, int index, boolean isSelected, boolean cellHasFocus) {
555                 File JavaDoc f = (File JavaDoc) value;
556                 String JavaDoc message = f.getAbsolutePath();
557                 if (projectConflict) {
558                     Project p = FileOwnerQuery.getOwner(f.toURI());
559                     if (p!=null) {
560                         ProjectInformation pi = ProjectUtils.getInformation(p);
561                         String JavaDoc projectName = pi.getDisplayName();
562                         message = MessageFormat.format (NbBundle.getMessage(J2SESourceRootsUi.class,"TXT_RootOwnedByProject"), new Object JavaDoc[] {
563                             message,
564                             projectName});
565                     }
566                 }
567                 return super.getListCellRendererComponent(list, message, index, isSelected, cellHasFocus);
568             }
569         }
570     }
571
572 }
573
Popular Tags