Only add 1 feature settings table
[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 \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 \r
222 \r
223   void resetTable(boolean groupsChanged)\r
224   {\r
225    SequenceFeature [] tmpfeatures;\r
226    String group=null, type;\r
227    Vector visibleChecks = new Vector();\r
228 \r
229    //Find out which features should be visible depending on which groups\r
230    //are selected / deselected\r
231     for (int i = 0; i < af.getViewport().alignment.getHeight(); i++)\r
232     {\r
233 \r
234         tmpfeatures = af.getViewport().alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures();\r
235         if (tmpfeatures == null)\r
236           continue;\r
237 \r
238         int index = 0;\r
239         while (index < tmpfeatures.length)\r
240         {\r
241           group = tmpfeatures[index].featureGroup;\r
242 \r
243           if(tmpfeatures[index].begin==0 && tmpfeatures[index].end==0)\r
244           {\r
245             index ++;\r
246             continue;\r
247           }\r
248 \r
249           if (group==null || fr.featureGroups.get(group)==null ||\r
250               ((Boolean) fr.featureGroups.get(group)).booleanValue())\r
251           {\r
252             type = tmpfeatures[index].getType();\r
253             if(!visibleChecks.contains(type) )\r
254             {\r
255               visibleChecks.addElement(type);\r
256             }\r
257           }\r
258           index++;\r
259         }\r
260     }\r
261 \r
262     int fSize = visibleChecks.size();\r
263     Object [][] data = new Object[fSize][3];\r
264     int dataIndex = 0;\r
265 \r
266     if(fr.renderOrder!=null)\r
267     {\r
268       //First add the checks in the previous render order,\r
269       //in case the window has been closed and reopened\r
270       for(int ro=fr.renderOrder.length-1; ro>-1; ro--)\r
271       {\r
272            type = fr.renderOrder[ro];\r
273 \r
274            if(!visibleChecks.contains(type))\r
275              continue;\r
276 \r
277            data[dataIndex][0] = type;\r
278            data[dataIndex][1] = fr.getColour(type);\r
279            data[dataIndex][2] = new Boolean(af.getViewport().featuresDisplayed.containsKey(type));\r
280            dataIndex++;\r
281            visibleChecks.removeElement(type);\r
282       }\r
283     }\r
284 \r
285     fSize = visibleChecks.size();\r
286     for(int i=0; i<fSize; i++)\r
287     {\r
288       //These must be extra features belonging to the group\r
289       //which was just selected\r
290       type = visibleChecks.elementAt(i).toString();\r
291       data[dataIndex][0] = type;\r
292 \r
293       data[dataIndex][1] = fr.getColour(type);\r
294       data[dataIndex][2] = new Boolean(true);\r
295       dataIndex++;\r
296     }\r
297 \r
298     if(originalData==null)\r
299     {\r
300       originalData = new Object[data.length][3];\r
301       System.arraycopy(data,0,originalData,0,data.length);\r
302     }\r
303 \r
304     table.setModel(new FeatureTableModel(data));\r
305     table.getColumnModel().getColumn(0).setPreferredWidth(200);\r
306 \r
307 \r
308     if (groupPanel != null)\r
309     {\r
310       groupPanel.setLayout(\r
311           new GridLayout(fr.featureGroups.size() / 4 + 1, 4));\r
312 \r
313       groupPanel.validate();\r
314       bigPanel.add(groupPanel, BorderLayout.NORTH);\r
315     }\r
316 \r
317     updateFeatureRenderer(data);\r
318 \r
319   }\r
320 \r
321   void load()\r
322   {\r
323     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(\r
324                  "LAST_DIRECTORY"), new String[] { "fc" },\r
325              new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");\r
326      chooser.setFileView(new jalview.io.JalviewFileView());\r
327      chooser.setDialogTitle("Load Feature Colours");\r
328      chooser.setToolTipText("Load");\r
329 \r
330      int value = chooser.showOpenDialog(this);\r
331 \r
332      if (value == JalviewFileChooser.APPROVE_OPTION)\r
333      {\r
334        File file = chooser.getSelectedFile();\r
335 \r
336        try\r
337        {\r
338          InputStreamReader in = new InputStreamReader(new FileInputStream(\r
339              file), "UTF-8");\r
340 \r
341          jalview.binding.JalviewUserColours jucs = new jalview.binding.\r
342              JalviewUserColours();\r
343          jucs = (jalview.binding.JalviewUserColours) jucs.unmarshal(in);\r
344 \r
345 \r
346          for (int i = 0; i < jucs.getColourCount(); i++)\r
347          {\r
348            fr.setColour( jucs.getColour(i).getName(),\r
349                           new Color(Integer.parseInt( jucs.getColour(i).getRGB(), 16)));\r
350          }\r
351 \r
352          setTableData();\r
353          af.alignPanel.repaint();\r
354        }\r
355        catch (Exception ex)\r
356        {\r
357          System.out.println("Error loading User Colour File\n" + ex);\r
358        }\r
359      }\r
360   }\r
361 \r
362   void save()\r
363   {\r
364     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(\r
365                 "LAST_DIRECTORY"), new String[] { "fc" },\r
366             new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");\r
367     chooser.setFileView(new jalview.io.JalviewFileView());\r
368     chooser.setDialogTitle("Save Feature Colour Scheme");\r
369     chooser.setToolTipText("Save");\r
370 \r
371     int value = chooser.showSaveDialog(this);\r
372 \r
373     if (value == JalviewFileChooser.APPROVE_OPTION)\r
374     {\r
375         String choice = chooser.getSelectedFile().getPath();\r
376         jalview.binding.JalviewUserColours ucs = new jalview.binding.JalviewUserColours();\r
377         ucs.setSchemeName("Sequence Features");\r
378         try\r
379         {\r
380             PrintWriter out = new PrintWriter(new OutputStreamWriter(\r
381                         new FileOutputStream(choice), "UTF-8"));\r
382 \r
383             Enumeration e = fr.featureColours.keys();\r
384            while(e.hasMoreElements())\r
385            {\r
386                 jalview.binding.Colour col = new jalview.binding.Colour();\r
387                 col.setName(e.nextElement().toString());\r
388                 col.setRGB(jalview.util.Format.getHexString(\r
389                         fr.getColour(col.getName())));\r
390                 ucs.addColour(col);\r
391             }\r
392 \r
393             ucs.marshal(out);\r
394             out.close();\r
395         }\r
396         catch (Exception ex)\r
397         {\r
398             ex.printStackTrace();\r
399         }\r
400     }\r
401   }\r
402 \r
403   public void invertSelection()\r
404   {\r
405     for(int i=0; i<table.getRowCount(); i++)\r
406     {\r
407       Boolean value = (Boolean)table.getValueAt(i,2);\r
408 \r
409       table.setValueAt(\r
410           new Boolean(!value.booleanValue()),\r
411                        i,2);\r
412     }\r
413   }\r
414 \r
415   public void close()\r
416   {\r
417     try\r
418     {\r
419       frame.setClosed(true);\r
420     }\r
421     catch (Exception exe)\r
422     {}\r
423 \r
424   }\r
425 \r
426   public void updateFeatureRenderer(Object [][] data)\r
427   {\r
428     fr.setFeaturePriority( data );\r
429     af.alignPanel.repaint();\r
430 \r
431     if(af.alignPanel.overviewPanel!=null)\r
432       af.alignPanel.overviewPanel.updateOverviewImage();\r
433   }\r
434 \r
435   int selectedRow =-1;\r
436   JTabbedPane tabbedPane = new JTabbedPane();\r
437   BorderLayout borderLayout1 = new BorderLayout();\r
438   BorderLayout borderLayout2 = new BorderLayout();\r
439   BorderLayout borderLayout3 = new BorderLayout();\r
440   JPanel bigPanel = new JPanel();\r
441   BorderLayout borderLayout4 = new BorderLayout();\r
442   JButton invert = new JButton();\r
443   JPanel buttonPanel = new JPanel();\r
444   JButton cancel = new JButton();\r
445   JButton ok = new JButton();\r
446   JButton loadColours = new JButton();\r
447   JButton saveColours = new JButton();\r
448   JPanel dasButtonPanel = new JPanel();\r
449   JButton fetchDAS = new JButton();\r
450   JButton saveDAS = new JButton();\r
451   private void jbInit()\r
452       throws Exception\r
453   {\r
454     this.setLayout(borderLayout1);\r
455     settingsPane.setLayout(borderLayout2);\r
456     dasSettingsPane.setLayout(borderLayout3);\r
457     bigPanel.setLayout(borderLayout4);\r
458     invert.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));\r
459     invert.setText("Invert Selection");\r
460     invert.addActionListener(new ActionListener()\r
461     {\r
462       public void actionPerformed(ActionEvent e)\r
463       {\r
464         invertSelection();\r
465       }\r
466     });\r
467     cancel.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));\r
468     cancel.setText("Cancel");\r
469     cancel.addActionListener(new ActionListener()\r
470     {\r
471       public void actionPerformed(ActionEvent e)\r
472       {\r
473           updateFeatureRenderer(originalData);\r
474           close();\r
475       }\r
476     });\r
477     ok.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));\r
478     ok.setText("OK");\r
479     ok.addActionListener(new ActionListener()\r
480     {\r
481       public void actionPerformed(ActionEvent e)\r
482       {\r
483         close();\r
484       }\r
485     });\r
486     loadColours.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));\r
487     loadColours.setText("Load Colours");\r
488     loadColours.addActionListener(new ActionListener()\r
489     {\r
490       public void actionPerformed(ActionEvent e)\r
491       {\r
492         load();\r
493       }\r
494     });\r
495     saveColours.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));\r
496     saveColours.setText("Save Colours");\r
497     saveColours.addActionListener(new ActionListener()\r
498     {\r
499       public void actionPerformed(ActionEvent e)\r
500       {\r
501         save();\r
502       }\r
503     });\r
504     transparency.addChangeListener(new ChangeListener()\r
505     {\r
506       public void stateChanged(ChangeEvent evt)\r
507       {\r
508         fr.setTransparency( (float) (100 - transparency.getValue()) / 100f);\r
509         af.alignPanel.repaint();\r
510       }\r
511     });\r
512 \r
513 \r
514     transparency.setMaximum(70);\r
515     fetchDAS.setText("Fetch DAS Features");\r
516     fetchDAS.addActionListener(new ActionListener()\r
517     {\r
518       public void actionPerformed(ActionEvent e)\r
519       {\r
520         fetchDAS_actionPerformed(e);\r
521       }\r
522     });\r
523     saveDAS.setText("Save as default");\r
524     saveDAS.addActionListener(new ActionListener()\r
525     {\r
526       public void actionPerformed(ActionEvent e)\r
527       {\r
528         saveDAS_actionPerformed(e);\r
529       }\r
530     });\r
531     dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());\r
532     dasSettingsPane.setBorder(null);\r
533     this.add(tabbedPane, java.awt.BorderLayout.CENTER);\r
534     tabbedPane.addTab("Display Settings", settingsPane );\r
535     tabbedPane.addTab("DAS Settings", dasSettingsPane);\r
536     bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);\r
537     transPanel.add(transparency);\r
538     transPanel.add(invert);\r
539     buttonPanel.add(ok);\r
540     buttonPanel.add(cancel);\r
541     buttonPanel.add(loadColours);\r
542     buttonPanel.add(saveColours);\r
543     bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);\r
544     dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);\r
545     dasButtonPanel.add(fetchDAS);\r
546     dasButtonPanel.add(saveDAS);\r
547     settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);\r
548     settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);\r
549   }\r
550 \r
551   public void fetchDAS_actionPerformed(ActionEvent e)\r
552   {\r
553     Vector selectedSources = dassourceBrowser.getSelectedSources();\r
554 \r
555     SequenceI [] dataset, seqs ;\r
556     int iSize;\r
557 \r
558     if(af.getViewport().getSelectionGroup()!=null\r
559       && af.getViewport().getSelectionGroup().getSize(false)>0)\r
560     {\r
561       iSize = af.getViewport().getSelectionGroup().getSize(false);\r
562       dataset = new SequenceI[iSize];\r
563       seqs = af.getViewport().getSelectionGroup().\r
564           getSequencesInOrder(\r
565               af.getViewport().getAlignment());\r
566     }\r
567     else\r
568     {\r
569        iSize = af.getViewport().getAlignment().getHeight();\r
570        seqs = af.getViewport().getAlignment().getSequencesArray();\r
571     }\r
572 \r
573     dataset = new SequenceI[iSize];\r
574     for (int i = 0; i < iSize; i++)\r
575     {\r
576       dataset[i] = seqs[i].getDatasetSequence();\r
577     }\r
578 \r
579     new jalview.io.DasSequenceFeatureFetcher(\r
580         dataset,\r
581         af,\r
582         selectedSources);\r
583 \r
584     af.getViewport().setShowSequenceFeatures(true);\r
585     af.showSeqFeatures.setSelected(true);\r
586   }\r
587 \r
588   public void saveDAS_actionPerformed(ActionEvent e)\r
589   {\r
590     dassourceBrowser.saveProperties(jalview.bin.Cache.applicationProperties);\r
591   }\r
592 \r
593   /////////////////////////////////////////////////////////////////////////\r
594   // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html\r
595   /////////////////////////////////////////////////////////////////////////\r
596   class FeatureTableModel\r
597       extends AbstractTableModel\r
598   {\r
599     FeatureTableModel(Object[][] data)\r
600     {\r
601       this.data = data;\r
602     }\r
603 \r
604     private String[] columnNames = {"Feature Type", "Colour","Display"};\r
605           private Object[][] data;\r
606 \r
607           public Object[][] getData()\r
608           {\r
609             return data;\r
610           }\r
611 \r
612           public void setData(Object[][] data)\r
613           {\r
614             this.data = data;\r
615           }\r
616 \r
617           public int getColumnCount() {\r
618               return columnNames.length;\r
619           }\r
620 \r
621           public Object[] getRow(int row)\r
622           {\r
623             return data[row];\r
624           }\r
625 \r
626           public int getRowCount() {\r
627               return data.length;\r
628           }\r
629 \r
630           public String getColumnName(int col) {\r
631               return columnNames[col];\r
632           }\r
633 \r
634           public Object getValueAt(int row, int col) {\r
635               return data[row][col];\r
636           }\r
637 \r
638           public Class getColumnClass(int c) {\r
639               return getValueAt(0, c).getClass();\r
640           }\r
641 \r
642           public boolean isCellEditable(int row, int col) {\r
643               return col==0 ? false:true;\r
644           }\r
645 \r
646           public void setValueAt(Object value, int row, int col) {\r
647               data[row][col] = value;\r
648               fireTableCellUpdated(row, col);\r
649               updateFeatureRenderer(data);\r
650           }\r
651 \r
652     }\r
653     class ColorRenderer extends JLabel\r
654                               implements TableCellRenderer {\r
655        javax.swing.border.Border unselectedBorder = null;\r
656        javax.swing.border.Border selectedBorder = null;\r
657 \r
658        public ColorRenderer() {\r
659            setOpaque(true); //MUST do this for background to show up.\r
660        }\r
661 \r
662        public Component getTableCellRendererComponent(\r
663                                JTable table, Object color,\r
664                                boolean isSelected, boolean hasFocus,\r
665                                int row, int column) {\r
666            Color newColor = (Color)color;\r
667            setBackground(newColor);\r
668                if (isSelected) {\r
669                    if (selectedBorder == null) {\r
670                        selectedBorder = BorderFactory.createMatteBorder(2,5,2,5,\r
671                                                  table.getSelectionBackground());\r
672                    }\r
673                    setBorder(selectedBorder);\r
674                } else {\r
675                    if (unselectedBorder == null) {\r
676                        unselectedBorder = BorderFactory.createMatteBorder(2,5,2,5,\r
677                                                  table.getBackground());\r
678                    }\r
679                    setBorder(unselectedBorder);\r
680                }\r
681 \r
682            setToolTipText("RGB value: " + newColor.getRed() + ", "\r
683                                         + newColor.getGreen() + ", "\r
684                                         + newColor.getBlue());\r
685            return this;\r
686        }\r
687    }\r
688 }\r
689 \r
690  class ColorEditor extends AbstractCellEditor\r
691                           implements TableCellEditor,\r
692                                      ActionListener {\r
693      Color currentColor;\r
694      JButton button;\r
695      JColorChooser colorChooser;\r
696      JDialog dialog;\r
697      protected static final String EDIT = "edit";\r
698 \r
699      public ColorEditor() {\r
700          //Set up the editor (from the table's point of view),\r
701          //which is a button.\r
702          //This button brings up the color chooser dialog,\r
703          //which is the editor from the user's point of view.\r
704          button = new JButton();\r
705          button.setActionCommand(EDIT);\r
706          button.addActionListener(this);\r
707          button.setBorderPainted(false);\r
708          //Set up the dialog that the button brings up.\r
709          colorChooser = new JColorChooser();\r
710          dialog = JColorChooser.createDialog(button,\r
711                                          "Select new Colour",\r
712                                          true,  //modal\r
713                                          colorChooser,\r
714                                          this,  //OK button handler\r
715                                          null); //no CANCEL button handler\r
716      }\r
717 \r
718      /**\r
719       * Handles events from the editor button and from\r
720       * the dialog's OK button.\r
721       */\r
722      public void actionPerformed(ActionEvent e) {\r
723 \r
724           if (EDIT.equals(e.getActionCommand())) {\r
725              //The user has clicked the cell, so\r
726              //bring up the dialog.\r
727              button.setBackground(currentColor);\r
728              colorChooser.setColor(currentColor);\r
729              dialog.setVisible(true);\r
730 \r
731              //Make the renderer reappear.\r
732              fireEditingStopped();\r
733 \r
734          } else { //User pressed dialog's "OK" button.\r
735              currentColor = colorChooser.getColor();\r
736          }\r
737      }\r
738 \r
739      //Implement the one CellEditor method that AbstractCellEditor doesn't.\r
740      public Object getCellEditorValue() {\r
741          return currentColor;\r
742      }\r
743 \r
744      //Implement the one method defined by TableCellEditor.\r
745      public Component getTableCellEditorComponent(JTable table,\r
746                                                   Object value,\r
747                                                   boolean isSelected,\r
748                                                   int row,\r
749                                                   int column) {\r
750          currentColor = (Color)value;\r
751          return button;\r
752      }\r
753 }\r