reenable canceldas after a cancel and subsequence fetch
[jalview.git] / src / jalview / gui / FeatureSettings.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer
3  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program 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
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.gui;
20
21 import java.io.*;
22 import java.util.*;
23
24 import java.awt.*;
25 import java.awt.event.*;
26 import javax.swing.*;
27 import javax.swing.event.*;
28 import javax.swing.table.*;
29
30 import jalview.datamodel.*;
31 import jalview.io.*;
32
33 public class FeatureSettings
34     extends JPanel
35 {
36   DasSourceBrowser dassourceBrowser;
37   jalview.io.DasSequenceFeatureFetcher dasFeatureFetcher;
38   JPanel settingsPane = new JPanel();
39   JPanel dasSettingsPane = new JPanel();
40
41   final FeatureRenderer fr;
42   public final AlignFrame af;
43   Object[][] originalData;
44   final JInternalFrame frame;
45   JScrollPane scrollPane = new JScrollPane();
46   JTable table;
47   JPanel groupPanel;
48   JSlider transparency = new JSlider();
49
50   JPanel transPanel = new JPanel(new FlowLayout());
51
52   public FeatureSettings(AlignFrame af)
53   {
54     this.af = af;
55     fr = af.getFeatureRenderer();
56
57     transparency.setMaximum(100 - (int) (fr.transparency * 100));
58
59     try
60     {
61       jbInit();
62     }
63     catch (Exception ex)
64     {
65       ex.printStackTrace();
66     }
67
68     table = new JTable();
69     table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
70     table.setFont(new Font("Verdana", Font.PLAIN, 12));
71     table.setDefaultRenderer(Color.class,
72                              new ColorRenderer());
73
74     table.setDefaultEditor(Color.class,
75                            new ColorEditor());
76
77     table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
78
79     table.addMouseListener(new MouseAdapter()
80     {
81       public void mousePressed(MouseEvent evt)
82       {
83         selectedRow = table.rowAtPoint(evt.getPoint());
84       }
85     });
86
87     table.addMouseMotionListener(new MouseMotionAdapter()
88     {
89       public void mouseDragged(MouseEvent evt)
90       {
91         int newRow = table.rowAtPoint(evt.getPoint());
92         if (newRow != selectedRow
93             && selectedRow != -1
94             && newRow != -1)
95         {
96           Object[] temp = new Object[3];
97           temp[0] = table.getValueAt(selectedRow, 0);
98           temp[1] = table.getValueAt(selectedRow, 1);
99           temp[2] = table.getValueAt(selectedRow, 2);
100
101           table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
102           table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
103           table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
104
105           table.setValueAt(temp[0], newRow, 0);
106           table.setValueAt(temp[1], newRow, 1);
107           table.setValueAt(temp[2], newRow, 2);
108
109           selectedRow = newRow;
110         }
111       }
112     });
113
114     scrollPane.setViewportView(table);
115
116     dassourceBrowser = new DasSourceBrowser();
117     dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
118
119     if (af.getViewport().featuresDisplayed == null || fr.renderOrder == null)
120     {
121       fr.findAllFeatures();
122     }
123
124     setTableData();
125
126     frame = new JInternalFrame();
127     frame.setContentPane(this);
128     Desktop.addInternalFrame(frame, "Sequence Feature Settings", 400, 450);
129     frame.setLayer(JLayeredPane.PALETTE_LAYER);
130   }
131
132   synchronized public void setTableData()
133   {
134     if (fr.featureGroups == null)
135     {
136       fr.featureGroups = new Hashtable();
137     }
138
139     Vector allFeatures = new Vector();
140     Vector allGroups = new Vector();
141     SequenceFeature[] tmpfeatures;
142     String group;
143
144     for (int i = 0; i < af.getViewport().alignment.getHeight(); i++)
145     {
146       if (af.getViewport().alignment.getSequenceAt(i).getDatasetSequence().
147           getSequenceFeatures() == null)
148       {
149         continue;
150       }
151
152       tmpfeatures = af.getViewport().alignment.getSequenceAt(i).
153           getDatasetSequence().getSequenceFeatures();
154
155       int index = 0;
156       while (index < tmpfeatures.length)
157       {
158         if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
159         {
160           index++;
161           continue;
162         }
163
164         if (tmpfeatures[index].getFeatureGroup() != null)
165         {
166           group = tmpfeatures[index].featureGroup;
167           if (!allGroups.contains(group))
168           {
169             allGroups.addElement(group);
170
171             boolean visible = true;
172             if (fr.featureGroups.containsKey(group))
173             {
174               visible = ( (Boolean) fr.featureGroups.get(group)).booleanValue();
175             }
176
177             if (groupPanel == null)
178             {
179               groupPanel = new JPanel();
180             }
181
182             boolean alreadyAdded = false;
183             for (int g = 0; g < groupPanel.getComponentCount(); g++)
184             {
185               if ( ( (JCheckBox) groupPanel.getComponent(g))
186                   .getText().equals(group))
187               {
188                 alreadyAdded = true;
189                 break;
190               }
191             }
192
193             if (alreadyAdded)
194             {
195               continue;
196             }
197
198             fr.featureGroups.put(group, new Boolean(visible));
199
200             final JCheckBox check = new JCheckBox(group, visible);
201             check.setFont(new Font("Serif", Font.BOLD, 12));
202             check.addItemListener(new ItemListener()
203             {
204               public void itemStateChanged(ItemEvent evt)
205               {
206                 fr.featureGroups.put(check.getText(),
207                                      new Boolean(check.isSelected()));
208                 af.alignPanel.seqPanel.seqCanvas.repaint();
209                 if (af.alignPanel.overviewPanel != null)
210                 {
211                   af.alignPanel.overviewPanel.updateOverviewImage();
212                 }
213
214                 resetTable(true);
215               }
216             });
217             groupPanel.add(check);
218           }
219         }
220
221         if (!allFeatures.contains(tmpfeatures[index].getType()))
222         {
223           allFeatures.addElement(tmpfeatures[index].getType());
224         }
225         index++;
226       }
227     }
228
229     resetTable(false);
230
231     validate();
232   }
233
234   void resetTable(boolean groupsChanged)
235   {
236     SequenceFeature[] tmpfeatures;
237     String group = null, type;
238     Vector visibleChecks = new Vector();
239
240     //Find out which features should be visible depending on which groups
241     //are selected / deselected
242     for (int i = 0; i < af.getViewport().alignment.getHeight(); i++)
243     {
244
245       tmpfeatures = af.getViewport().alignment.getSequenceAt(i).
246           getDatasetSequence().getSequenceFeatures();
247       if (tmpfeatures == null)
248       {
249         continue;
250       }
251
252       int index = 0;
253       while (index < tmpfeatures.length)
254       {
255         group = tmpfeatures[index].featureGroup;
256
257         if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
258         {
259           index++;
260           continue;
261         }
262
263         if (group == null || fr.featureGroups.get(group) == null ||
264             ( (Boolean) fr.featureGroups.get(group)).booleanValue())
265         {
266           type = tmpfeatures[index].getType();
267           if (!visibleChecks.contains(type))
268           {
269             visibleChecks.addElement(type);
270           }
271         }
272         index++;
273       }
274     }
275
276     int fSize = visibleChecks.size();
277     Object[][] data = new Object[fSize][3];
278     int dataIndex = 0;
279
280     if (fr.renderOrder != null)
281     {
282       //First add the checks in the previous render order,
283       //in case the window has been closed and reopened
284       for (int ro = fr.renderOrder.length - 1; ro > -1; ro--)
285       {
286         type = fr.renderOrder[ro];
287
288         if (!visibleChecks.contains(type))
289         {
290           continue;
291         }
292
293         data[dataIndex][0] = type;
294         data[dataIndex][1] = fr.getColour(type);
295         data[dataIndex][2] = new Boolean(af.getViewport().featuresDisplayed.
296                                          containsKey(type));
297         dataIndex++;
298         visibleChecks.removeElement(type);
299       }
300     }
301
302     fSize = visibleChecks.size();
303     for (int i = 0; i < fSize; i++)
304     {
305       //These must be extra features belonging to the group
306       //which was just selected
307       type = visibleChecks.elementAt(i).toString();
308       data[dataIndex][0] = type;
309
310       data[dataIndex][1] = fr.getColour(type);
311       if (data[dataIndex][1] == null)
312       {
313         //"Colour has been updated in another view!!"
314         fr.renderOrder = null;
315         return;
316       }
317
318       data[dataIndex][2] = new Boolean(true);
319       dataIndex++;
320     }
321
322     if (originalData == null)
323     {
324       originalData = new Object[data.length][3];
325       System.arraycopy(data, 0, originalData, 0, data.length);
326     }
327
328     table.setModel(new FeatureTableModel(data));
329     table.getColumnModel().getColumn(0).setPreferredWidth(200);
330
331     if (groupPanel != null)
332     {
333       groupPanel.setLayout(
334           new GridLayout(fr.featureGroups.size() / 4 + 1, 4));
335
336       groupPanel.validate();
337       bigPanel.add(groupPanel, BorderLayout.NORTH);
338     }
339
340     updateFeatureRenderer(data);
341
342   }
343
344   void load()
345   {
346     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
347         getProperty(
348             "LAST_DIRECTORY"), new String[]
349         {"fc"},
350         new String[]
351         {"Sequence Feature Colours"}, "Sequence Feature Colours");
352     chooser.setFileView(new jalview.io.JalviewFileView());
353     chooser.setDialogTitle("Load Feature Colours");
354     chooser.setToolTipText("Load");
355
356     int value = chooser.showOpenDialog(this);
357
358     if (value == JalviewFileChooser.APPROVE_OPTION)
359     {
360       File file = chooser.getSelectedFile();
361
362       try
363       {
364         InputStreamReader in = new InputStreamReader(new FileInputStream(
365             file), "UTF-8");
366
367         jalview.binding.JalviewUserColours jucs = new jalview.binding.
368             JalviewUserColours();
369         jucs = (jalview.binding.JalviewUserColours) jucs.unmarshal(in);
370
371         for (int i = 0; i < jucs.getColourCount(); i++)
372         {
373           fr.setColour(jucs.getColour(i).getName(),
374                        new Color(Integer.parseInt(jucs.getColour(i).getRGB(),
375                                                   16)));
376         }
377
378         setTableData();
379         af.alignPanel.paintAlignment(true);
380       }
381       catch (Exception ex)
382       {
383         System.out.println("Error loading User Colour File\n" + ex);
384       }
385     }
386   }
387
388   void save()
389   {
390     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
391         getProperty(
392             "LAST_DIRECTORY"), new String[]
393         {"fc"},
394         new String[]
395         {"Sequence Feature Colours"}, "Sequence Feature Colours");
396     chooser.setFileView(new jalview.io.JalviewFileView());
397     chooser.setDialogTitle("Save Feature Colour Scheme");
398     chooser.setToolTipText("Save");
399
400     int value = chooser.showSaveDialog(this);
401
402     if (value == JalviewFileChooser.APPROVE_OPTION)
403     {
404       String choice = chooser.getSelectedFile().getPath();
405       jalview.binding.JalviewUserColours ucs = new jalview.binding.
406           JalviewUserColours();
407       ucs.setSchemeName("Sequence Features");
408       try
409       {
410         PrintWriter out = new PrintWriter(new OutputStreamWriter(
411             new FileOutputStream(choice), "UTF-8"));
412
413         Enumeration e = fr.featureColours.keys();
414         while (e.hasMoreElements())
415         {
416           jalview.binding.Colour col = new jalview.binding.Colour();
417           col.setName(e.nextElement().toString());
418           col.setRGB(jalview.util.Format.getHexString(
419               fr.getColour(col.getName())));
420           ucs.addColour(col);
421         }
422
423         ucs.marshal(out);
424         out.close();
425       }
426       catch (Exception ex)
427       {
428         ex.printStackTrace();
429       }
430     }
431   }
432
433   public void invertSelection()
434   {
435     for (int i = 0; i < table.getRowCount(); i++)
436     {
437       Boolean value = (Boolean) table.getValueAt(i, 2);
438
439       table.setValueAt(
440           new Boolean(!value.booleanValue()),
441           i, 2);
442     }
443   }
444
445   public void close()
446   {
447     try
448     {
449       frame.setClosed(true);
450     }
451     catch (Exception exe)
452     {}
453
454   }
455
456   public void updateFeatureRenderer(Object[][] data)
457   {
458     fr.setFeaturePriority(data);
459     af.alignPanel.paintAlignment(true);
460
461     if (af.alignPanel.overviewPanel != null)
462     {
463       af.alignPanel.overviewPanel.updateOverviewImage();
464     }
465   }
466
467   int selectedRow = -1;
468   JTabbedPane tabbedPane = new JTabbedPane();
469   BorderLayout borderLayout1 = new BorderLayout();
470   BorderLayout borderLayout2 = new BorderLayout();
471   BorderLayout borderLayout3 = new BorderLayout();
472   JPanel bigPanel = new JPanel();
473   BorderLayout borderLayout4 = new BorderLayout();
474   JButton invert = new JButton();
475   JPanel buttonPanel = new JPanel();
476   JButton cancel = new JButton();
477   JButton ok = new JButton();
478   JButton loadColours = new JButton();
479   JButton saveColours = new JButton();
480   JPanel dasButtonPanel = new JPanel();
481   JButton fetchDAS = new JButton();
482   JButton saveDAS = new JButton();
483   JButton cancelDAS = new JButton();
484   private void jbInit()
485       throws Exception
486   {
487     this.setLayout(borderLayout1);
488     settingsPane.setLayout(borderLayout2);
489     dasSettingsPane.setLayout(borderLayout3);
490     bigPanel.setLayout(borderLayout4);
491     invert.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
492     invert.setText("Invert Selection");
493     invert.addActionListener(new ActionListener()
494     {
495       public void actionPerformed(ActionEvent e)
496       {
497         invertSelection();
498       }
499     });
500     cancel.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
501     cancel.setText("Cancel");
502     cancel.addActionListener(new ActionListener()
503     {
504       public void actionPerformed(ActionEvent e)
505       {
506         updateFeatureRenderer(originalData);
507         close();
508       }
509     });
510     ok.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
511     ok.setText("OK");
512     ok.addActionListener(new ActionListener()
513     {
514       public void actionPerformed(ActionEvent e)
515       {
516         close();
517       }
518     });
519     loadColours.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
520     loadColours.setText("Load Colours");
521     loadColours.addActionListener(new ActionListener()
522     {
523       public void actionPerformed(ActionEvent e)
524       {
525         load();
526       }
527     });
528     saveColours.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
529     saveColours.setText("Save Colours");
530     saveColours.addActionListener(new ActionListener()
531     {
532       public void actionPerformed(ActionEvent e)
533       {
534         save();
535       }
536     });
537     transparency.addChangeListener(new ChangeListener()
538     {
539       public void stateChanged(ChangeEvent evt)
540       {
541         fr.setTransparency( (float) (100 - transparency.getValue()) / 100f);
542         af.alignPanel.paintAlignment(true);
543       }
544     });
545
546     transparency.setMaximum(70);
547     fetchDAS.setText("Fetch DAS Features");
548     fetchDAS.addActionListener(new ActionListener()
549     {
550       public void actionPerformed(ActionEvent e)
551       {
552         fetchDAS_actionPerformed(e);
553       }
554     });
555     saveDAS.setText("Save as default");
556     saveDAS.addActionListener(new ActionListener()
557     {
558       public void actionPerformed(ActionEvent e)
559       {
560         saveDAS_actionPerformed(e);
561       }
562     });
563     dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
564     dasSettingsPane.setBorder(null);
565     cancelDAS.setEnabled(false);
566     cancelDAS.setText("Cancel Fetch");
567     cancelDAS.addActionListener(new ActionListener()
568     {
569       public void actionPerformed(ActionEvent e)
570       {
571         cancelDAS_actionPerformed(e);
572       }
573     });
574     this.add(tabbedPane, java.awt.BorderLayout.CENTER);
575     tabbedPane.addTab("Feature Settings", settingsPane);
576     tabbedPane.addTab("DAS Settings", dasSettingsPane);
577     bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
578     transPanel.add(transparency);
579     transPanel.add(invert);
580     buttonPanel.add(ok);
581     buttonPanel.add(cancel);
582     buttonPanel.add(loadColours);
583     buttonPanel.add(saveColours);
584     bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
585     dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
586     dasButtonPanel.add(fetchDAS);
587     dasButtonPanel.add(cancelDAS);
588     dasButtonPanel.add(saveDAS);
589     settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
590     settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
591   }
592
593   public void fetchDAS_actionPerformed(ActionEvent e)
594   {
595     fetchDAS.setEnabled(false);
596     cancelDAS.setEnabled(true);
597     Vector selectedSources = dassourceBrowser.getSelectedSources();
598
599     SequenceI[] dataset, seqs;
600     int iSize;
601
602     if (af.getViewport().getSelectionGroup() != null
603         && af.getViewport().getSelectionGroup().getSize() > 0)
604     {
605       iSize = af.getViewport().getSelectionGroup().getSize();
606       dataset = new SequenceI[iSize];
607       seqs = af.getViewport().getSelectionGroup().
608           getSequencesInOrder(
609               af.getViewport().getAlignment());
610     }
611     else
612     {
613       iSize = af.getViewport().getAlignment().getHeight();
614       seqs = af.getViewport().getAlignment().getSequencesArray();
615     }
616
617     dataset = new SequenceI[iSize];
618     for (int i = 0; i < iSize; i++)
619     {
620       dataset[i] = seqs[i].getDatasetSequence();
621     }
622
623     dasFeatureFetcher =
624         new jalview.io.DasSequenceFeatureFetcher(
625             dataset,
626             this,
627             selectedSources);
628     cancelDAS.setEnabled(true);
629     af.getViewport().setShowSequenceFeatures(true);
630     af.showSeqFeatures.setSelected(true);
631   }
632
633   public void saveDAS_actionPerformed(ActionEvent e)
634   {
635     dassourceBrowser.saveProperties(jalview.bin.Cache.applicationProperties);
636   }
637
638   public void complete()
639   {
640     fetchDAS.setEnabled(true);
641     cancelDAS.setEnabled(false);
642   }
643
644   public void cancelDAS_actionPerformed(ActionEvent e)
645   {
646     dasFeatureFetcher.cancel();
647     fetchDAS.setEnabled(true);
648     cancelDAS.setEnabled(false);
649   }
650
651   /////////////////////////////////////////////////////////////////////////
652   // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
653   /////////////////////////////////////////////////////////////////////////
654   class FeatureTableModel
655       extends AbstractTableModel
656   {
657     FeatureTableModel(Object[][] data)
658     {
659       this.data = data;
660     }
661
662     private String[] columnNames =
663         {
664         "Feature Type", "Colour", "Display"};
665     private Object[][] data;
666
667     public Object[][] getData()
668     {
669       return data;
670     }
671
672     public void setData(Object[][] data)
673     {
674       this.data = data;
675     }
676
677     public int getColumnCount()
678     {
679       return columnNames.length;
680     }
681
682     public Object[] getRow(int row)
683     {
684       return data[row];
685     }
686
687     public int getRowCount()
688     {
689       return data.length;
690     }
691
692     public String getColumnName(int col)
693     {
694       return columnNames[col];
695     }
696
697     public Object getValueAt(int row, int col)
698     {
699       return data[row][col];
700     }
701
702     public Class getColumnClass(int c)
703     {
704       return getValueAt(0, c).getClass();
705     }
706
707     public boolean isCellEditable(int row, int col)
708     {
709       return col == 0 ? false : true;
710     }
711
712     public void setValueAt(Object value, int row, int col)
713     {
714       data[row][col] = value;
715       fireTableCellUpdated(row, col);
716       updateFeatureRenderer(data);
717     }
718
719   }
720
721   class ColorRenderer
722       extends JLabel implements TableCellRenderer
723   {
724     javax.swing.border.Border unselectedBorder = null;
725     javax.swing.border.Border selectedBorder = null;
726
727     public ColorRenderer()
728     {
729       setOpaque(true); //MUST do this for background to show up.
730     }
731
732     public Component getTableCellRendererComponent(
733         JTable table, Object color,
734         boolean isSelected, boolean hasFocus,
735         int row, int column)
736     {
737       Color newColor = (Color) color;
738       setBackground(newColor);
739       if (isSelected)
740       {
741         if (selectedBorder == null)
742         {
743           selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
744               table.getSelectionBackground());
745         }
746         setBorder(selectedBorder);
747       }
748       else
749       {
750         if (unselectedBorder == null)
751         {
752           unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
753               table.getBackground());
754         }
755         setBorder(unselectedBorder);
756       }
757
758       setToolTipText("RGB value: " + newColor.getRed() + ", "
759                      + newColor.getGreen() + ", "
760                      + newColor.getBlue());
761       return this;
762     }
763   }
764 }
765
766 class ColorEditor
767     extends AbstractCellEditor implements TableCellEditor,
768     ActionListener
769 {
770   Color currentColor;
771   JButton button;
772   JColorChooser colorChooser;
773   JDialog dialog;
774   protected static final String EDIT = "edit";
775
776   public ColorEditor()
777   {
778     //Set up the editor (from the table's point of view),
779     //which is a button.
780     //This button brings up the color chooser dialog,
781     //which is the editor from the user's point of view.
782     button = new JButton();
783     button.setActionCommand(EDIT);
784     button.addActionListener(this);
785     button.setBorderPainted(false);
786     //Set up the dialog that the button brings up.
787     colorChooser = new JColorChooser();
788     dialog = JColorChooser.createDialog(button,
789                                         "Select new Colour",
790                                         true, //modal
791                                         colorChooser,
792                                         this, //OK button handler
793                                         null); //no CANCEL button handler
794   }
795
796   /**
797    * Handles events from the editor button and from
798    * the dialog's OK button.
799    */
800   public void actionPerformed(ActionEvent e)
801   {
802
803     if (EDIT.equals(e.getActionCommand()))
804     {
805       //The user has clicked the cell, so
806       //bring up the dialog.
807       button.setBackground(currentColor);
808       colorChooser.setColor(currentColor);
809       dialog.setVisible(true);
810
811       //Make the renderer reappear.
812       fireEditingStopped();
813
814     }
815     else
816     { //User pressed dialog's "OK" button.
817       currentColor = colorChooser.getColor();
818     }
819   }
820
821   //Implement the one CellEditor method that AbstractCellEditor doesn't.
822   public Object getCellEditorValue()
823   {
824     return currentColor;
825   }
826
827   //Implement the one method defined by TableCellEditor.
828   public Component getTableCellEditorComponent(JTable table,
829                                                Object value,
830                                                boolean isSelected,
831                                                int row,
832                                                int column)
833   {
834     currentColor = (Color) value;
835     return button;
836   }
837 }