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