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