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