NEW FILES
[jalview.git] / src / jalview / gui / DasSourceBrowser.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.jbgui.*;\r
22 import javax.swing.table.AbstractTableModel;\r
23 import javax.swing.event.*;\r
24 import jalview.util.TableSorter;\r
25 import java.awt.event.*;\r
26 import javax.swing.*;\r
27 import java.util.*;\r
28 import java.net.*;\r
29 \r
30 import org.biojava.services.das.registry.DasCoordinateSystem;\r
31 import org.biojava.services.das.registry.DasSource;\r
32 import java.awt.BorderLayout;\r
33 \r
34 public class DasSourceBrowser extends GDasSourceBrowser\r
35     implements Runnable, ListSelectionListener\r
36 {\r
37   static DasSource[] dasSources = null;\r
38 \r
39   Hashtable localSources = null;\r
40 \r
41   Vector selectedSources;\r
42 \r
43   public DasSourceBrowser()\r
44   {\r
45     registryURL.setText(jalview.bin.Cache.getDefault("DAS_REGISTRY_URL",\r
46         "http://servlet.sanger.ac.uk/dasregistry/services/das_registry") );\r
47 \r
48     setSelectedFromProperties();\r
49 \r
50     displayFullDetails(null);\r
51     table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);\r
52 \r
53     capabilities.addListSelectionListener(this);\r
54     coords1.addListSelectionListener(this);\r
55     coords2.addListSelectionListener(this);\r
56 \r
57     //Ask to be notified of selection changes.\r
58     ListSelectionModel rowSM = table.getSelectionModel();\r
59     rowSM.addListSelectionListener(new ListSelectionListener()\r
60     {\r
61       public void valueChanged(ListSelectionEvent e)\r
62       {\r
63         //Ignore extra messages.\r
64         if (e.getValueIsAdjusting())\r
65           return;\r
66 \r
67         ListSelectionModel lsm = (ListSelectionModel) e.getSource();\r
68         if (!lsm.isSelectionEmpty())\r
69         {\r
70           int selectedRow = lsm.getMinSelectionIndex();\r
71           displayFullDetails(table.getValueAt(selectedRow, 0).toString());\r
72         }\r
73       }\r
74     });\r
75 \r
76     table.addMouseListener(new MouseAdapter()\r
77         {\r
78           public void mouseClicked(MouseEvent evt)\r
79           {\r
80             if(evt.getClickCount()==2\r
81                || SwingUtilities.isRightMouseButton(evt))\r
82               editRemoveLocalSource(evt);\r
83           }\r
84         });\r
85 \r
86     if(dasSources==null)\r
87     {\r
88     Thread worker = new Thread(this);\r
89     worker.start();\r
90     }\r
91     else\r
92      {\r
93        init();\r
94      }\r
95   }\r
96 \r
97   void init()\r
98   {\r
99     int dSize = dasSources.length;\r
100     Object[][] data = new Object[dSize][2];\r
101     for (int i = 0; i < dSize; i++)\r
102     {\r
103       data[i][0] = dasSources[i].getNickname();\r
104       data[i][1] = new Boolean(selectedSources.contains(dasSources[i].\r
105           getNickname()));\r
106     }\r
107 \r
108     refreshTableData(data);\r
109     setCapabilities(dasSources);\r
110 \r
111     javax.swing.SwingUtilities.invokeLater(new Runnable()\r
112         {\r
113           public void run()\r
114           {\r
115             TableSorter sorter = (TableSorter)table.getModel();\r
116             sorter.setSortingStatus(1, TableSorter.DESCENDING);\r
117             sorter.setSortingStatus(1, TableSorter.NOT_SORTED);\r
118           }\r
119         });\r
120 \r
121     progressBar.setIndeterminate(false);\r
122     progressBar.setVisible(false);\r
123     addLocal.setVisible(true);\r
124     refresh.setVisible(true);\r
125   }\r
126 \r
127 \r
128   public void refreshTableData(Object[][] data)\r
129   {\r
130     TableSorter sorter = new TableSorter(new DASTableModel(data));\r
131     sorter.setTableHeader(table.getTableHeader());\r
132     table.setModel(sorter);\r
133   }\r
134 \r
135   void displayFullDetails(String nickName)\r
136   {\r
137 \r
138     StringBuffer text = new StringBuffer(\r
139         "<HTML><font size=\"2\" face=\"Verdana, Arial, Helvetica, sans-serif\">");\r
140 \r
141     if (nickName == null)\r
142     {\r
143       fullDetails.setText(text +\r
144                           "Select a DAS service from the table"\r
145                           + " to read a full description here.</font></html>");\r
146       return;\r
147     }\r
148 \r
149     int dSize = dasSources.length;\r
150     for (int i = 0; i < dSize; i++)\r
151     {\r
152       if (!dasSources[i].getNickname().equals(nickName))\r
153         continue;\r
154 \r
155       DasSource ds = dasSources[i];\r
156 \r
157       text.append("<font color=\"#0000FF\">Id:</font> " + dasSources[i].getId() +\r
158                   "<br>");\r
159       text.append("<font color=\"#0000FF\">Nickname:</font> " +\r
160                   dasSources[i].getNickname() + "<br>");\r
161       text.append("<font color=\"#0000FF\">URL:</font> " + dasSources[i].getUrl() +\r
162                   "<br>");\r
163 \r
164       text.append("<font color=\"#0000FF\">Admin Email:</font> <a href=\"mailto:"\r
165                   +dasSources[i].getAdminemail()\r
166                   +"\">"+dasSources[i].getAdminemail()+"</a>" +\r
167                   "<br>");\r
168 \r
169 \r
170       text.append("<font color=\"#0000FF\">Registered at:</font> " + dasSources[i].getRegisterDate() +\r
171                         "<br>");\r
172 \r
173       text.append("<font color=\"#0000FF\">Last successful test:</font> " + dasSources[i].getLeaseDate() +\r
174                         "<br>");\r
175 \r
176       text.append("<font color=\"#0000FF\">Labels:</font> ");\r
177       for(int s=0; s<dasSources[i].getLabels().length; s++)\r
178       {\r
179         text.append( dasSources[i].getLabels()[s]);\r
180         if(s<dasSources[i].getLabels().length-1)\r
181           text.append(",");\r
182         text.append(" ");\r
183       }\r
184       text.append("<br>");\r
185 \r
186 \r
187 \r
188       text.append("<font color=\"#0000FF\">Capabilities:</font> ");\r
189       String[] scap = dasSources[i].getCapabilities();\r
190       for (int j = 0; j < scap.length; j++)\r
191       {\r
192         text.append(scap[j]);\r
193         if (j < scap.length - 1)\r
194           text.append(", ");\r
195       }\r
196       text.append("<br>");\r
197 \r
198       text.append("<font color=\"#0000FF\">Coordinates:</font> ");\r
199       DasCoordinateSystem[] dcs = ds.getCoordinateSystem();\r
200       for (int j = 0; j < dcs.length; j++)\r
201       {\r
202         text.append("(" + dcs[j].getUniqueId() + ") "\r
203                     + dcs[j].getCategory() + ", " + dcs[j].getName());\r
204         if (dcs[j].getNCBITaxId() != 0)\r
205           text.append(", " + dcs[j].getNCBITaxId());\r
206         if (dcs[j].getOrganismName().length() > 0)\r
207           text.append(", " + dcs[j].getOrganismName());\r
208 \r
209         text.append("<br>");\r
210       }\r
211 \r
212       text.append("<font color=\"#0000FF\">Description:</font> " +\r
213                   dasSources[i].getDescription() + "<br>");\r
214 \r
215       if (dasSources[i].getHelperurl().length() > 0)\r
216       {\r
217         text.append("<font color=\"#0000FF\"><a href=\"" +\r
218                     dasSources[i].getHelperurl()\r
219                     + "\">Go to site</a></font<br>");\r
220       }\r
221 \r
222       text.append("</font></html>");\r
223 \r
224       break;\r
225     }\r
226 \r
227     fullDetails.setText(text.toString());\r
228     javax.swing.SwingUtilities.invokeLater(new Runnable()\r
229     {\r
230       public void run()\r
231       {\r
232         fullDetailsScrollpane.getVerticalScrollBar().setValue(0);\r
233       }\r
234     });\r
235   }\r
236 \r
237 \r
238   public void run()\r
239   {\r
240     addLocal.setVisible(false);\r
241     refresh.setVisible(false);\r
242     progressBar.setVisible(true);\r
243     progressBar.setIndeterminate(true);\r
244 \r
245     dasSources = jalview.io.DasSequenceFeatureFetcher.getDASSources();\r
246 \r
247     appendLocalSources();\r
248 \r
249     init();\r
250   }\r
251 \r
252   public DasSource[] getDASSource()\r
253   {\r
254     if(dasSources==null)\r
255     {\r
256      dasSources = jalview.io.DasSequenceFeatureFetcher.getDASSources();\r
257      appendLocalSources();\r
258     }\r
259 \r
260     return dasSources;\r
261   }\r
262 \r
263   public void refresh_actionPerformed(ActionEvent e)\r
264   {\r
265     saveProperties(jalview.bin.Cache.applicationProperties);\r
266 \r
267     Thread worker = new Thread(this);\r
268     worker.start();\r
269   }\r
270 \r
271   private void setCapabilities(DasSource[] sources)\r
272   {\r
273     Vector vcapabilities = new Vector();\r
274     Vector vcoords = new Vector();\r
275     Vector vcoords2 = new Vector();\r
276 \r
277     vcapabilities.addElement("All");\r
278     vcoords.addElement("All");\r
279     vcoords2.addElement("All");\r
280 \r
281     for (int i = 0; i < sources.length; i++)\r
282     {\r
283       DasSource ds = sources[i];\r
284       String[] scap = ds.getCapabilities();\r
285       for (int s = 0; s < scap.length; s++)\r
286       {\r
287         if (!vcapabilities.contains(scap[s]))\r
288         {\r
289           vcapabilities.addElement(scap[s]);\r
290         }\r
291       }\r
292 \r
293       DasCoordinateSystem[] dcs = ds.getCoordinateSystem();\r
294 \r
295       for (int j = 0; j < dcs.length; j++)\r
296       {\r
297         if (!vcoords.contains(dcs[j].getCategory()))\r
298           vcoords.addElement(dcs[j].getCategory());\r
299 \r
300         if (!vcoords2.contains(dcs[j].getName()))\r
301           vcoords2.addElement(dcs[j].getName());\r
302       }\r
303     }\r
304 \r
305     capabilities.setListData(vcapabilities);\r
306     coords1.setListData(vcoords);\r
307     coords2.setListData(vcoords2);\r
308 \r
309     javax.swing.SwingUtilities.invokeLater(new Runnable()\r
310     {\r
311       public void run()\r
312       {\r
313         capabilities.setSelectedIndex(0);\r
314         coords1.setSelectedIndex(0);\r
315         coords2.setSelectedIndex(0);\r
316       }\r
317     });\r
318   }\r
319 \r
320   public void amendLocal(boolean newSource)\r
321   {\r
322     String url = "http://localhost:8080/", nickname = "";\r
323 \r
324     if(!newSource)\r
325     {\r
326       int selectedRow = table.getSelectionModel().getMinSelectionIndex();\r
327       nickname = table.getValueAt(selectedRow, 0).toString();\r
328       url = ((DasSource)localSources.get(nickname)).getUrl();\r
329     }\r
330 \r
331     JTextField nametf = new JTextField(nickname, 40);\r
332     JTextField urltf = new JTextField(url, 40);\r
333 \r
334     JPanel panel = new JPanel(new BorderLayout());\r
335     JPanel pane12 = new JPanel(new BorderLayout());\r
336     pane12.add(new JLabel("Nickname: "), BorderLayout.CENTER);\r
337     pane12.add(nametf, BorderLayout.EAST);\r
338     panel.add(pane12, BorderLayout.NORTH);\r
339     pane12 = new JPanel(new BorderLayout());\r
340     pane12.add(new JLabel("URL: "), BorderLayout.CENTER);\r
341     pane12.add(urltf, BorderLayout.EAST);\r
342     panel.add(pane12, BorderLayout.SOUTH);\r
343 \r
344 \r
345     int reply = JOptionPane.showInternalConfirmDialog(Desktop.desktop,\r
346         panel, "Enter Nickname & URL of Local DAS Source",\r
347         JOptionPane.OK_CANCEL_OPTION);\r
348 \r
349        if (reply != JOptionPane.OK_OPTION )\r
350        {\r
351            return;\r
352        }\r
353 \r
354        if(!urltf.getText().endsWith("/"))\r
355          urltf.setText(urltf.getText()+"/");\r
356 \r
357        DasSource local = new DasSource();\r
358 \r
359        local.setUrl(urltf.getText());\r
360        local.setNickname(nametf.getText());\r
361 \r
362 \r
363        if(localSources==null)\r
364          localSources = new Hashtable();\r
365 \r
366        localSources.put(local.getNickname(), local);\r
367 \r
368        if(!newSource && !nickname.equals(nametf.getText()))\r
369        {\r
370          localSources.remove(nickname);\r
371        }\r
372 \r
373        int size = dasSources.length;\r
374        int adjust = newSource ? 1 : 0;\r
375 \r
376        Object[][] data = new Object[size+adjust][2];\r
377        for (int i = 0; i < size; i++)\r
378        {\r
379          if(!newSource && dasSources[i].getNickname().equals(nickname))\r
380          {\r
381            ((DasSource)dasSources[i]).setNickname(local.getNickname());\r
382            ((DasSource)dasSources[i]).setUrl(local.getUrl());\r
383            data[i][0] = local.getNickname();\r
384            data[i][1] = new Boolean(true);\r
385          }\r
386          else\r
387          {\r
388            data[i][0] = dasSources[i].getNickname();\r
389            data[i][1] = new Boolean(selectedSources.contains(dasSources[i].\r
390                getNickname()));\r
391          }\r
392        }\r
393 \r
394        if(newSource)\r
395        {\r
396          data[size][0] = local.getNickname();\r
397          data[size][1] = new Boolean(true);\r
398          selectedSources.add(local.getNickname());\r
399        }\r
400 \r
401        DasSource [] tmp = new DasSource[size+adjust];\r
402 \r
403        System.arraycopy(dasSources, 0, tmp, 0, size);\r
404 \r
405        if(newSource)\r
406          tmp[size] = local;\r
407 \r
408        dasSources = tmp;\r
409 \r
410        refreshTableData(data);\r
411 \r
412        SwingUtilities.invokeLater(new Runnable()\r
413        {\r
414          public void run()\r
415          {\r
416            scrollPane.getVerticalScrollBar().setValue(\r
417                scrollPane.getVerticalScrollBar().getMaximum()\r
418                );\r
419          }\r
420        });\r
421 \r
422        displayFullDetails(local.getNickname());\r
423      }\r
424 \r
425     public void editRemoveLocalSource(MouseEvent evt)\r
426     {\r
427       int selectedRow = table.getSelectionModel().getMinSelectionIndex();\r
428       if(selectedRow==-1)\r
429         return;\r
430 \r
431       String nickname = table.getValueAt(selectedRow, 0).toString();\r
432 \r
433       if (!localSources.containsKey(nickname))\r
434       {\r
435         JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
436         "You can only edit or remove local DAS Sources!",\r
437          "Public DAS source - not editable",\r
438          JOptionPane.WARNING_MESSAGE);\r
439         return;\r
440       }\r
441 \r
442 \r
443       Object[] options = {"Edit", "Remove", "Cancel"};\r
444       int choice = JOptionPane.showInternalOptionDialog(Desktop.desktop,\r
445     "Do you want to edit or remove "+nickname+"?",\r
446     "Edit / Remove Local DAS Source",\r
447     JOptionPane.YES_NO_CANCEL_OPTION,\r
448     JOptionPane.QUESTION_MESSAGE,\r
449     null,\r
450     options,\r
451     options[2]);\r
452 \r
453       switch(choice)\r
454       {\r
455         case 0: amendLocal(false);   break;\r
456         case 1:\r
457           localSources.remove(nickname);\r
458           selectedSources.remove(nickname);\r
459           Object[][] data = new Object[dasSources.length-1][2];\r
460           DasSource [] tmp = new DasSource[dasSources.length-1];\r
461           int index = 0;\r
462           for (int i = 0; i < dasSources.length; i++)\r
463           {\r
464             if (dasSources[i].getNickname().equals(nickname))\r
465             {\r
466               continue;\r
467             }\r
468             else\r
469             {\r
470               tmp[index] = dasSources[i];\r
471               data[index][0] = dasSources[i].getNickname();\r
472               data[index][1] = new Boolean(selectedSources.contains(dasSources[i].\r
473                   getNickname()));\r
474               index++;\r
475             }\r
476           }\r
477            dasSources = tmp;\r
478            refreshTableData(data);\r
479            SwingUtilities.invokeLater(new Runnable()\r
480            {\r
481              public void run()\r
482              {\r
483                scrollPane.getVerticalScrollBar().setValue(\r
484                    scrollPane.getVerticalScrollBar().getMaximum()\r
485                    );\r
486              }\r
487            });\r
488 \r
489           break;\r
490       }\r
491     }\r
492 \r
493   void appendLocalSources()\r
494   {\r
495     if(localSources==null)\r
496       return;\r
497 \r
498     int size = dasSources.length;\r
499     int lsize = localSources.size();\r
500 \r
501     Object[][] data = new Object[size+lsize][2];\r
502     for (int i = 0; i < size; i++)\r
503     {\r
504       data[i][0] = dasSources[i].getNickname();\r
505       data[i][1] = new Boolean(selectedSources.contains(dasSources[i].\r
506           getNickname()));\r
507     }\r
508 \r
509     DasSource [] tmp = new DasSource[size+lsize];\r
510     System.arraycopy(dasSources, 0, tmp, 0, size);\r
511 \r
512     Enumeration en = localSources.keys();\r
513     int index = size;\r
514     while(en.hasMoreElements())\r
515     {\r
516       String key = en.nextElement().toString();\r
517       data[index][0] = key;\r
518       data[index][1] = new Boolean(false);\r
519       tmp[index] = new DasSource();\r
520       tmp[index].setNickname(key);\r
521       tmp[index].setUrl( ((DasSource)localSources.get(key)).getUrl() );\r
522 \r
523       index++;\r
524     }\r
525 \r
526        dasSources = tmp;\r
527 \r
528        refreshTableData(data);\r
529   }\r
530 \r
531   public void valueChanged(ListSelectionEvent evt)\r
532   {\r
533     //Called when the MainTable selection changes\r
534     if (evt.getValueIsAdjusting())\r
535     {\r
536       return;\r
537     }\r
538 \r
539     displayFullDetails(null);\r
540 \r
541     // Filter the displayed data sources\r
542     int dSize = dasSources.length;\r
543     ArrayList names = new ArrayList();\r
544     ArrayList selected = new ArrayList();\r
545     DasSource ds;\r
546 \r
547     // capabilities.get\r
548     for (int i = 0; i < dSize; i++)\r
549     {\r
550       ds = dasSources[i];\r
551 \r
552       if (!selectedInList(capabilities, ds.getCapabilities()))\r
553       {\r
554         continue;\r
555       }\r
556 \r
557       DasCoordinateSystem[] dcs = ds.getCoordinateSystem();\r
558       for (int j = 0; j < dcs.length; j++)\r
559       {\r
560         if (selectedInList(coords1, new String[]\r
561                            {dcs[j].getCategory()})\r
562             && selectedInList(coords2, new String[]\r
563                               {dcs[j].getName()}))\r
564         {\r
565           names.add(ds.getNickname());\r
566           selected.add(new Boolean(\r
567               selectedSources.contains(ds.getNickname())));\r
568           break;\r
569         }\r
570       }\r
571     }\r
572 \r
573     dSize = names.size();\r
574     Object[][] data = new Object[dSize][2];\r
575     for (int d = 0; d < dSize; d++)\r
576     {\r
577       data[d][0] = names.get(d);\r
578       data[d][1] = selected.get(d);\r
579     }\r
580 \r
581     refreshTableData(data);\r
582   }\r
583 \r
584   boolean selectedInList(JList list, String[] items)\r
585   {\r
586     Object[] selection = list.getSelectedValues();\r
587     for (int i = 0; i < selection.length; i++)\r
588     {\r
589       if (selection[i].equals("All"))\r
590         return true;\r
591 \r
592       for (int j = 0; j < items.length; j++)\r
593       {\r
594         if (selection[i].equals(items[j]))\r
595           return true;\r
596       }\r
597     }\r
598 \r
599     return false;\r
600   }\r
601 \r
602   void setSelectedFromProperties()\r
603   {\r
604      String active = jalview.bin.Cache.getDefault("DAS_ACTIVE_SOURCE", "uniprot");\r
605      StringTokenizer st = new StringTokenizer(active, "\t");\r
606      selectedSources = new Vector();\r
607      while(st.hasMoreTokens())\r
608      {\r
609        selectedSources.addElement(st.nextToken());\r
610      }\r
611 \r
612      String local = jalview.bin.Cache.getProperty("DAS_LOCAL_SOURCE");\r
613      if(local!=null)\r
614      {\r
615        if(localSources == null)\r
616          localSources = new Hashtable();\r
617 \r
618        st = new StringTokenizer(local, "\t");\r
619        while(st.hasMoreTokens())\r
620        {\r
621          String token = st.nextToken();\r
622          int bar = token.indexOf("|");\r
623          DasSource source = new DasSource();\r
624 \r
625          source.setUrl(token.substring(bar + 1));\r
626          source.setNickname(token.substring(0, bar));\r
627 \r
628          localSources.put(source.getNickname(), source);\r
629        }\r
630      }\r
631   }\r
632 \r
633   void saveProperties(Properties properties)\r
634   {\r
635     properties.setProperty("DAS_REGISTRY_URL", registryURL.getText());\r
636 \r
637     StringBuffer sb = new StringBuffer();\r
638     for(int r=0; r<table.getModel().getRowCount(); r++)\r
639     {\r
640       if( ((Boolean)table.getValueAt(r,1)).booleanValue())\r
641       {\r
642         sb.append(table.getValueAt(r,0)+"\t");\r
643       }\r
644     }\r
645 \r
646     properties.setProperty("DAS_ACTIVE_SOURCE", sb.toString() );\r
647 \r
648     if(localSources!=null)\r
649     {\r
650       sb = new StringBuffer();\r
651       Enumeration en = localSources.keys();\r
652       while(en.hasMoreElements())\r
653       {\r
654         String token = en.nextElement().toString();\r
655         sb.append(token+"|"\r
656                   + ((DasSource)localSources.get(token)).getUrl()\r
657                   +"\t");\r
658       }\r
659 \r
660       properties.setProperty("DAS_LOCAL_SOURCE", sb.toString());\r
661     }\r
662 \r
663   }\r
664 \r
665   class DASTableModel\r
666       extends AbstractTableModel\r
667   {\r
668 \r
669     public DASTableModel(Object[][] data)\r
670     {\r
671       this.data = data;\r
672     }\r
673 \r
674     private String[] columnNames = new String[]  {"Nickname", "Use Source"};\r
675 \r
676     private Object[][] data;\r
677 \r
678     public int getColumnCount()\r
679     {\r
680       return columnNames.length;\r
681     }\r
682 \r
683     public int getRowCount()\r
684     {\r
685       return data.length;\r
686     }\r
687 \r
688     public String getColumnName(int col)\r
689     {\r
690       return columnNames[col];\r
691     }\r
692 \r
693     public Object getValueAt(int row, int col)\r
694     {\r
695       return data[row][col];\r
696     }\r
697 \r
698     /*\r
699      * JTable uses this method to determine the default renderer/\r
700      * editor for each cell.  If we didn't implement this method,\r
701      * then the last column would contain text ("true"/"false"),\r
702      * rather than a check box.\r
703      */\r
704     public Class getColumnClass(int c)\r
705     {\r
706       return getValueAt(0, c).getClass();\r
707     }\r
708 \r
709     /*\r
710      * Don't need to implement this method unless your table's\r
711      * editable.\r
712      */\r
713     public boolean isCellEditable(int row, int col)\r
714     {\r
715       //Note that the data/cell address is constant,\r
716       //no matter where the cell appears onscreen.\r
717       return col == 1;\r
718 \r
719     }\r
720 \r
721     /*\r
722      * Don't need to implement this method unless your table's\r
723      * data can change.\r
724      */\r
725     public void setValueAt(Object value, int row, int col)\r
726     {\r
727       data[row][col] = value;\r
728       fireTableCellUpdated(row, col);\r
729 \r
730       String name = getValueAt(row,0).toString();\r
731       boolean selected = ((Boolean)value).booleanValue();\r
732 \r
733       if(selectedSources.contains(name) && !selected)\r
734         selectedSources.remove(name);\r
735 \r
736       if(!selectedSources.contains(name) && selected)\r
737         selectedSources.add(name);\r
738     }\r
739   }\r
740 }\r
741 \r
742 \r