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