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