(JAL-972) jdas source retrieval and use of jdas structures for local sources
[jalview.git] / src / jalview / gui / DasSourceBrowser.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)\r
3  * Copyright (C) 2011 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle\r
4  * \r
5  * This file is part of Jalview.\r
6  * \r
7  * Jalview is free software: you can redistribute it and/or\r
8  * modify it under the terms of the GNU General Public License \r
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\r
10  * \r
11  * Jalview is distributed in the hope that it will be useful, but \r
12  * WITHOUT ANY WARRANTY; without even the implied warranty \r
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR \r
14  * PURPOSE.  See the GNU General Public License for more details.\r
15  * \r
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.\r
17  */\r
18 package jalview.gui;\r
19 \r
20 import java.text.ParseException;\r
21 import java.util.*;\r
22 import java.util.List;\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 org.biodas.jdas.dassources.Capabilities;\r
31 import org.biodas.jdas.dassources.utils.DasCoordinateSystemCollector;\r
32 import org.biodas.jdas.dassources.utils.DasTimeFormat;\r
33 import org.biodas.jdas.schema.registrycoordinates.DASCOORDINATESYSTEM;\r
34 import org.biodas.jdas.schema.sources.CAPABILITY;\r
35 import org.biodas.jdas.schema.sources.COORDINATES;\r
36 import org.biodas.jdas.schema.sources.MAINTAINER;\r
37 import org.biodas.jdas.schema.sources.PROP;\r
38 import org.biodas.jdas.schema.sources.SOURCE;\r
39 import org.biodas.jdas.schema.sources.SOURCES;\r
40 import org.biodas.jdas.schema.sources.VERSION;\r
41 \r
42 import jalview.jbgui.*;\r
43 import jalview.util.*;\r
44 \r
45 public class DasSourceBrowser extends GDasSourceBrowser implements\r
46         Runnable, ListSelectionListener\r
47 {\r
48   static org.biodas.jdas.schema.sources.SOURCE[] dasSources = null;\r
49 \r
50   Hashtable<String, SOURCE> localSources = null;\r
51 \r
52   Vector selectedSources;\r
53 \r
54   public static String DEFAULT_REGISTRY = "http://www.dasregistry.org/das1/sources/";\r
55 \r
56   /**\r
57    * true if thread is running and we are talking to DAS registry service\r
58    */\r
59   public boolean loadingDasSources = false;\r
60 \r
61   protected static String getDasRegistryURL()\r
62   {\r
63     String registry = jalview.bin.Cache.getDefault("DAS_REGISTRY_URL",\r
64             DEFAULT_REGISTRY);\r
65 \r
66     if (registry.indexOf("/registry/das1/sources/") > -1)\r
67     {\r
68       jalview.bin.Cache.setProperty(jalview.bin.Cache.DAS_REGISTRY_URL,\r
69               DEFAULT_REGISTRY);\r
70       registry = DEFAULT_REGISTRY;\r
71     }\r
72     return registry;\r
73   }\r
74 \r
75   public DasSourceBrowser(FeatureSettings featureSettings)\r
76   {\r
77     fs = featureSettings;\r
78     String registry = getDasRegistryURL();\r
79 \r
80     registryURL.setText(registry);\r
81 \r
82     setSelectedFromProperties();\r
83 \r
84     displayFullDetails(null);\r
85     table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);\r
86 \r
87     filter1.addListSelectionListener(this);\r
88     filter2.addListSelectionListener(this);\r
89     filter3.addListSelectionListener(this);\r
90 \r
91     // Ask to be notified of selection changes.\r
92     ListSelectionModel rowSM = table.getSelectionModel();\r
93     rowSM.addListSelectionListener(new ListSelectionListener()\r
94     {\r
95       public void valueChanged(ListSelectionEvent e)\r
96       {\r
97         ListSelectionModel lsm = (ListSelectionModel) e.getSource();\r
98         if (!lsm.isSelectionEmpty())\r
99         {\r
100           int selectedRow = lsm.getMinSelectionIndex();\r
101           displayFullDetails(table.getValueAt(selectedRow, 0).toString());\r
102         }\r
103       }\r
104     });\r
105 \r
106     table.addMouseListener(new MouseAdapter()\r
107     {\r
108       public void mouseClicked(MouseEvent evt)\r
109       {\r
110         if (evt.getClickCount() == 2\r
111                 || SwingUtilities.isRightMouseButton(evt))\r
112         {\r
113           editRemoveLocalSource(evt);\r
114         }\r
115       }\r
116     });\r
117 \r
118     if (dasSources != null)\r
119     {\r
120       init();\r
121     }\r
122   }\r
123 \r
124   FeatureSettings fs = null;\r
125 \r
126   public DasSourceBrowser()\r
127   {\r
128     this(null);\r
129   }\r
130 \r
131   public void paintComponent(java.awt.Graphics g)\r
132   {\r
133     if (dasSources == null && !loadingDasSources)\r
134     {\r
135       Thread worker = new Thread(this);\r
136       worker.start();\r
137     }\r
138   }\r
139 \r
140   void init()\r
141   {\r
142     int dSize = dasSources.length;\r
143     Object[][] data = new Object[dSize][2];\r
144     for (int i = 0; i < dSize; i++)\r
145     {\r
146       data[i][0] = dasSources[i].getTitle(); // what's equivalent of nickname\r
147       data[i][1] = new Boolean(selectedSources.contains(dasSources[i]\r
148               .getTitle()));\r
149     }\r
150 \r
151     refreshTableData(data);\r
152     setCapabilities(dasSources);\r
153 \r
154     javax.swing.SwingUtilities.invokeLater(new Runnable()\r
155     {\r
156       public void run()\r
157       {\r
158         TableSorter sorter = (TableSorter) table.getModel();\r
159         sorter.setSortingStatus(1, TableSorter.DESCENDING);\r
160         sorter.setSortingStatus(1, TableSorter.NOT_SORTED);\r
161       }\r
162     });\r
163 \r
164     progressBar.setIndeterminate(false);\r
165     progressBar.setVisible(false);\r
166     addLocal.setVisible(true);\r
167     refresh.setVisible(true);\r
168   }\r
169 \r
170   public void refreshTableData(Object[][] data)\r
171   {\r
172     TableSorter sorter = new TableSorter(new DASTableModel(data));\r
173     sorter.setTableHeader(table.getTableHeader());\r
174     table.setModel(sorter);\r
175   }\r
176 \r
177   void displayFullDetails(String nickName)\r
178   {\r
179 \r
180     StringBuffer text = new StringBuffer(\r
181             "<HTML><font size=\"2\" face=\"Verdana, Arial, Helvetica, sans-serif\">");\r
182 \r
183     if (nickName == null)\r
184     {\r
185       fullDetails.setText(text + "Select a DAS service from the table"\r
186               + " to read a full description here.</font></html>");\r
187       return;\r
188     }\r
189 \r
190     int dSize = dasSources.length;\r
191     for (int i = 0; i < dSize; i++)\r
192     {\r
193       if (!dasSources[i].getTitle().equals(nickName))\r
194       {\r
195         continue;\r
196       }\r
197 \r
198       SOURCE ds = dasSources[i];\r
199       VERSION latest = getVersionFor(ds);\r
200       text.append("<font color=\"#0000FF\">Id:</font> "\r
201               + dasSources[i].getUri() + "<br>");\r
202       text.append("<font color=\"#0000FF\">Nickname:</font> "\r
203               + dasSources[i].getTitle() + "<br>");\r
204       text.append("<font color=\"#0000FF\">URL:</font> " + latest.getUri()\r
205               + "<br>");\r
206 \r
207       text.append("<font color=\"#0000FF\">Admin Email:</font> <a href=\"mailto:"\r
208               + ds.getMAINTAINER().getEmail()\r
209               + "\">"\r
210               + ds.getMAINTAINER().getEmail() + "</a>" + "<br>");\r
211 \r
212       text.append("<font color=\"#0000FF\">Registered at:</font> "\r
213               + latest.getCreated() + "<br>");\r
214 \r
215       // TODO: Identify last successful test date\r
216       // text.append("<font color=\"#0000FF\">Last successful test:</font> "\r
217       // + latest.dasSources[i].getLeaseDate() + "<br>");\r
218 \r
219       text.append("<font color=\"#0000FF\">Labels:</font> ");\r
220       boolean b = false;\r
221       for (PROP labl : latest.getPROP())\r
222       {\r
223         if (labl.getName().equalsIgnoreCase("LABEL"))\r
224         {\r
225           if (!b)\r
226           {\r
227             text.append(",");\r
228           }\r
229           text.append(" ");\r
230 \r
231           text.append(labl.getValue());\r
232           b = true;\r
233         }\r
234         ;\r
235       }\r
236       text.append("<br>");\r
237 \r
238       text.append("<font color=\"#0000FF\">Capabilities:</font> ");\r
239       CAPABILITY[] scap = latest.getCAPABILITY().toArray(new CAPABILITY[0]);\r
240       for (int j = 0; j < scap.length; j++)\r
241       {\r
242         text.append(scap[j]);\r
243         if (j < scap.length - 1)\r
244         {\r
245           text.append(", ");\r
246         }\r
247       }\r
248       text.append("<br>");\r
249 \r
250       text.append("<font color=\"#0000FF\">Coordinates:</font> ");\r
251       for (COORDINATES dcs : latest.getCOORDINATES())\r
252       {\r
253         text.append("(" + dcs.getUri() + ") "\r
254 \r
255         + dcs.getSource() + ", " + dcs.getAuthority());\r
256         if (dcs.getTaxid() != null && dcs.getTaxid().trim().length() > 0)\r
257         {\r
258           text.append(", " + dcs.getTaxid());\r
259         }\r
260         if (dcs.getVersion().trim().length() > 0)\r
261         {\r
262           {\r
263             text.append(", " + dcs.getVersion());\r
264           }\r
265 \r
266           text.append("<br>");\r
267         }\r
268 \r
269         text.append("<font color=\"#0000FF\">Description:</font> "\r
270                 + dasSources[i].getDescription() + "<br>");\r
271 \r
272         if (dasSources[i].getDocHref() != null\r
273                 && dasSources[i].getDocHref().length() > 0)\r
274         {\r
275           text.append("<font color=\"#0000FF\"><a href=\""\r
276                   + dasSources[i].getDocHref()\r
277                   + "\">Go to site</a></font<br>");\r
278         }\r
279 \r
280         text.append("</font></html>");\r
281 \r
282         break;\r
283       }\r
284     }\r
285     fullDetails.setText(text.toString());\r
286     javax.swing.SwingUtilities.invokeLater(new Runnable()\r
287     {\r
288       public void run()\r
289       {\r
290         fullDetailsScrollpane.getVerticalScrollBar().setValue(0);\r
291       }\r
292     });\r
293   }\r
294 \r
295   public void run()\r
296   {\r
297     loadingDasSources = true;\r
298 \r
299     addLocal.setVisible(false);\r
300     refresh.setVisible(false);\r
301     progressBar.setVisible(true);\r
302     progressBar.setIndeterminate(true);\r
303     setParentGuiEnabled(false);\r
304     // Refresh the source list.\r
305     dasSources = null;\r
306     getDASSource();\r
307 \r
308     init();\r
309 \r
310     setParentGuiEnabled(true);\r
311     loadingDasSources = false;\r
312 \r
313   }\r
314 \r
315   private void setParentGuiEnabled(boolean b)\r
316   {\r
317     if (fs != null)\r
318     {\r
319       fs.fetchDAS.setEnabled(b);\r
320       fs.saveDAS.setEnabled(b);\r
321     }\r
322   }\r
323 \r
324   public Vector getSelectedSources()\r
325   {\r
326     // wait around if we're still loading.\r
327     while (dasSources == null)\r
328     {\r
329       if (!loadingDasSources)\r
330       {\r
331         new Thread(this).start();\r
332         try\r
333         {\r
334           Thread.sleep(5);\r
335         } catch (Exception e)\r
336         {\r
337         }\r
338         ;\r
339         while (loadingDasSources)\r
340         {\r
341           try\r
342           {\r
343             Thread.sleep(5);\r
344           } catch (Exception e)\r
345           {\r
346           }\r
347           ;\r
348         }\r
349         ;\r
350       }\r
351     }\r
352 \r
353     Vector selected = new Vector();\r
354     for (int r = 0; r < selectedSources.size(); r++)\r
355     {\r
356       for (int i = 0; i < dasSources.length; i++)\r
357       {\r
358         if (dasSources[i].getTitle().equals(selectedSources.elementAt(r)))\r
359         {\r
360           selected.addElement(dasSources[i]);\r
361           break;\r
362         }\r
363       }\r
364     }\r
365 \r
366     return selected;\r
367   }\r
368 \r
369   /**\r
370    * retrieve das sources from registry and add local source list\r
371    * \r
372    * @return\r
373    */\r
374   public SOURCE[] getDASSource()\r
375   {\r
376     if (dasSources == null)\r
377     {\r
378       dasSources = jalview.ws.DasSequenceFeatureFetcher.getDASSources();\r
379       appendLocalSources();\r
380     }\r
381 \r
382     return dasSources;\r
383   }\r
384 \r
385   public void refresh_actionPerformed(ActionEvent e)\r
386   {\r
387     saveProperties(jalview.bin.Cache.applicationProperties);\r
388 \r
389     Thread worker = new Thread(this);\r
390     worker.start();\r
391   }\r
392 \r
393   private boolean isLaterThan(String ref, String newer)\r
394   {\r
395     Date refdate = null, newdate = null;\r
396     try\r
397     {\r
398       refdate = DasTimeFormat.fromDASString(ref);\r
399 \r
400     } catch (ParseException x)\r
401     {\r
402       return false;\r
403     }\r
404     try\r
405     {\r
406       newdate = DasTimeFormat.fromDASString(newer);\r
407     } catch (ParseException e)\r
408     {\r
409       // TODO: handle exception\r
410     }\r
411     if (refdate != null)\r
412     {\r
413       if (newdate != null)\r
414       {\r
415         return refdate.before(newdate);\r
416       }\r
417       return false;\r
418     }\r
419     if (newdate != null)\r
420     {\r
421       return true;\r
422     }\r
423     // assume first instance of source is newest in list. - TODO: check if\r
424     // natural ordering of source versions is newest first or oldest first\r
425     return false;\r
426   }\r
427 \r
428   private VERSION getVersionFor(SOURCE ds)\r
429   {\r
430     VERSION latest = null;\r
431     for (VERSION v : ds.getVERSION())\r
432     {\r
433       if (latest == null\r
434               || isLaterThan(latest.getCreated(), v.getCreated()))\r
435       {\r
436         // TODO: das 1.6 - should just get the first version - ignore other\r
437         // versions since not specified how to construct URL from version's URI\r
438         // + source URI\r
439         latest = v;\r
440       }\r
441     }\r
442     return latest;\r
443   }\r
444 \r
445   private void setCapabilities(SOURCE[] sources)\r
446   {\r
447     Vector<String> authority = new Vector<String>();\r
448     Vector<String> type = new Vector<String>();\r
449     Vector<String> label = new Vector<String>();\r
450     Vector<String> taxIds = new Vector<String>();\r
451     authority.add("Any");\r
452     type.add("Any");\r
453     label.add("Any");\r
454 \r
455     for (int i = 0; i < sources.length; i++)\r
456     {\r
457       SOURCE ds = sources[i];\r
458       VERSION latest = getVersionFor(ds);\r
459 \r
460       for (COORDINATES cs : latest.getCOORDINATES())\r
461       {\r
462         if (!type.contains(cs.getSource()))\r
463         {\r
464           type.add(cs.getSource()); // source==category\r
465         }\r
466 \r
467         if (!authority.contains(cs.getAuthority()))\r
468         {\r
469           authority.add(cs.getAuthority());\r
470         }\r
471       }\r
472 \r
473       for (PROP slabel : latest.getPROP())\r
474       {\r
475         if (slabel.getName().equalsIgnoreCase("LABEL")\r
476                 && !label.contains(slabel.getValue()))\r
477         {\r
478           label.add(slabel.getValue());\r
479         }\r
480       }\r
481 \r
482     }\r
483 \r
484     filter1.setListData(authority);\r
485     filter2.setListData(type);\r
486     filter3.setListData(label);\r
487     // filter4 taxIds\r
488 \r
489     javax.swing.SwingUtilities.invokeLater(new Runnable()\r
490     {\r
491       public void run()\r
492       {\r
493         filter1.setSelectedIndex(0);\r
494         filter2.setSelectedIndex(0);\r
495         filter3.setSelectedIndex(0);\r
496       }\r
497     });\r
498   }\r
499 \r
500   public void amendLocal(boolean newSource)\r
501   {\r
502     String url = "http://localhost:8080/", nickname = "";\r
503     boolean seqsrc = false;\r
504     if (!newSource)\r
505     {\r
506       int selectedRow = table.getSelectionModel().getMinSelectionIndex();\r
507       nickname = table.getValueAt(selectedRow, 0).toString();\r
508       url = ((SOURCE) localSources.get(nickname)).getUri();\r
509       seqsrc = ((SOURCE) localSources.get(nickname)).getVERSION().get(0)\r
510               .getCAPABILITY().contains(Capabilities.SEQUENCE);\r
511     }\r
512 \r
513     JTextField nametf = new JTextField(nickname, 40);\r
514     JTextField urltf = new JTextField(url, 40);\r
515     JCheckBox seqs = new JCheckBox("Sequence Source");\r
516     seqs.setSelected(seqsrc);\r
517     JPanel panel = new JPanel(new BorderLayout());\r
518     JPanel pane12 = new JPanel(new BorderLayout());\r
519     pane12.add(new JLabel("Nickname: "), BorderLayout.CENTER);\r
520     pane12.add(nametf, BorderLayout.EAST);\r
521     panel.add(pane12, BorderLayout.NORTH);\r
522     pane12 = new JPanel(new BorderLayout());\r
523     pane12.add(new JLabel("URL: "), BorderLayout.NORTH);\r
524     pane12.add(seqs, BorderLayout.SOUTH);\r
525     pane12.add(urltf, BorderLayout.EAST);\r
526     panel.add(pane12, BorderLayout.SOUTH);\r
527 \r
528     int reply = JOptionPane.showInternalConfirmDialog(Desktop.desktop,\r
529             panel, "Enter Nickname & URL of Local DAS Source",\r
530             JOptionPane.OK_CANCEL_OPTION);\r
531 \r
532     if (reply != JOptionPane.OK_OPTION)\r
533     {\r
534       return;\r
535     }\r
536 \r
537     if (!urltf.getText().endsWith("/"))\r
538     {\r
539       urltf.setText(urltf.getText() + "/");\r
540     }\r
541 \r
542     SOURCE local = createLocalSource(urltf.getText(), nametf.getText(), seqs.isSelected(), true);\r
543     \r
544     if (localSources == null)\r
545     {\r
546       localSources = new Hashtable();\r
547     }\r
548 \r
549     localSources.put(local.getTitle(), local);\r
550 \r
551     if (!newSource && !nickname.equals(nametf.getText()))\r
552     {\r
553       localSources.remove(nickname);\r
554     }\r
555 \r
556     int size = dasSources.length;\r
557     int adjust = newSource ? 1 : 0;\r
558 \r
559     Object[][] data = new Object[size + adjust][2];\r
560     for (int i = 0; i < size; i++)\r
561     {\r
562       if (!newSource && dasSources[i].getTitle().equals(nickname))\r
563       {\r
564         dasSources[i] = local;\r
565         data[i][0] = local.getTitle();\r
566         data[i][1] = new Boolean(true);\r
567       }\r
568       else\r
569       {\r
570         data[i][0] = dasSources[i].getTitle();\r
571         data[i][1] = new Boolean(selectedSources.contains(dasSources[i]\r
572                 .getTitle()));\r
573       }\r
574     }\r
575 \r
576     if (newSource)\r
577     {\r
578       data[size][0] = local.getTitle();\r
579       data[size][1] = new Boolean(true);\r
580       selectedSources.add(local.getTitle());\r
581     }\r
582 \r
583     SOURCE[] tmp = new SOURCE[size + adjust];\r
584 \r
585     System.arraycopy(dasSources, 0, tmp, 0, size);\r
586 \r
587     if (newSource)\r
588     {\r
589       tmp[size] = local;\r
590     }\r
591 \r
592     dasSources = tmp;\r
593 \r
594     refreshTableData(data);\r
595 \r
596     SwingUtilities.invokeLater(new Runnable()\r
597     {\r
598       public void run()\r
599       {\r
600         scrollPane.getVerticalScrollBar().setValue(\r
601                 scrollPane.getVerticalScrollBar().getMaximum());\r
602       }\r
603     });\r
604 \r
605     displayFullDetails(local.getTitle());\r
606   }\r
607 \r
608   private SOURCE createLocalSource(String url, String name,\r
609           boolean sequence, boolean features)\r
610   {\r
611     SOURCE local = new SOURCE();\r
612 \r
613     local.setUri(url);\r
614     local.setTitle(name);\r
615     local.setVERSION(new ArrayList<VERSION>());\r
616     VERSION v = new VERSION();\r
617     List<CAPABILITY> cp = new ArrayList<CAPABILITY>();\r
618     if (sequence)\r
619     {\r
620 /* Could try and synthesize a coordinate system for the source if needbe\r
621  *       COORDINATES coord = new COORDINATES();\r
622       coord.setAuthority("NCBI");\r
623       coord.setSource("Chromosome");\r
624       coord.setTaxid("9606");\r
625       coord.setVersion("35");\r
626       version.getCOORDINATES().add(coord);*/\r
627       CAPABILITY cap=new CAPABILITY();\r
628       cap.setType("das1:"+Capabilities.SEQUENCE.getName());\r
629       cp.add(cap);\r
630     }\r
631     if (features)\r
632     {\r
633     CAPABILITY cap = new CAPABILITY();\r
634     cap.setType("das1:"+Capabilities.FEATURES.getName());\r
635     cp.add(cap);\r
636     }\r
637     \r
638     v.getCAPABILITY().addAll(cp);\r
639     local.getVERSION().add(v);\r
640 \r
641     return local;\r
642   }\r
643 \r
644   public void editRemoveLocalSource(MouseEvent evt)\r
645   {\r
646     int selectedRow = table.getSelectionModel().getMinSelectionIndex();\r
647     if (selectedRow == -1)\r
648     {\r
649       return;\r
650     }\r
651 \r
652     String nickname = table.getValueAt(selectedRow, 0).toString();\r
653 \r
654     if (!localSources.containsKey(nickname))\r
655     {\r
656       JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
657               "You can only edit or remove local DAS Sources!",\r
658               "Public DAS source - not editable",\r
659               JOptionPane.WARNING_MESSAGE);\r
660       return;\r
661     }\r
662 \r
663     Object[] options =\r
664     { "Edit", "Remove", "Cancel" };\r
665     int choice = JOptionPane.showInternalOptionDialog(Desktop.desktop,\r
666             "Do you want to edit or remove " + nickname + "?",\r
667             "Edit / Remove Local DAS Source",\r
668             JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,\r
669             null, options, options[2]);\r
670 \r
671     switch (choice)\r
672     {\r
673     case 0:\r
674       amendLocal(false);\r
675       break;\r
676     case 1:\r
677       localSources.remove(nickname);\r
678       selectedSources.remove(nickname);\r
679       Object[][] data = new Object[dasSources.length - 1][2];\r
680       SOURCE[] tmp = new SOURCE[dasSources.length - 1];\r
681       int index = 0;\r
682       for (int i = 0; i < dasSources.length; i++)\r
683       {\r
684         if (dasSources[i].getTitle().equals(nickname))\r
685         {\r
686           continue;\r
687         }\r
688         else\r
689         {\r
690           tmp[index] = dasSources[i];\r
691           data[index][0] = dasSources[i].getTitle();\r
692           data[index][1] = new Boolean(\r
693                   selectedSources.contains(dasSources[i].getTitle()));\r
694           index++;\r
695         }\r
696       }\r
697       dasSources = tmp;\r
698       refreshTableData(data);\r
699       SwingUtilities.invokeLater(new Runnable()\r
700       {\r
701         public void run()\r
702         {\r
703           scrollPane.getVerticalScrollBar().setValue(\r
704                   scrollPane.getVerticalScrollBar().getMaximum());\r
705         }\r
706       });\r
707 \r
708       break;\r
709     }\r
710   }\r
711 \r
712   void appendLocalSources()\r
713   {\r
714     if (localSources == null)\r
715     {\r
716       return;\r
717     }\r
718     // note - we add all das sources to list so they can be filtered for the\r
719     // standard fetchDbRefs function\r
720     int size = dasSources != null ? dasSources.length : 0;\r
721     int lsize = localSources.size();\r
722 \r
723     Object[][] data = new Object[size + lsize][2];\r
724     for (int i = 0; i < size; i++)\r
725     {\r
726       data[i][0] = dasSources[i].getTitle();\r
727       data[i][1] = new Boolean(selectedSources.contains(dasSources[i]\r
728               .getTitle()));\r
729     }\r
730 \r
731     SOURCE[] tmp = new SOURCE[size + lsize];\r
732     if (dasSources != null)\r
733     {\r
734       System.arraycopy(dasSources, 0, tmp, 0, size);\r
735     }\r
736 \r
737     Enumeration en = localSources.keys();\r
738     int index = size;\r
739     while (en.hasMoreElements())\r
740     {\r
741       String key = en.nextElement().toString();\r
742       data[index][0] = key;\r
743       data[index][1] = new Boolean(false);\r
744       tmp[index] = createLocalSource(localSources.get(key).getUri(), key, false, true);\r
745 \r
746       index++;\r
747     }\r
748 \r
749     dasSources = tmp;\r
750 \r
751     refreshTableData(data);\r
752   }\r
753 \r
754   public void valueChanged(ListSelectionEvent evt)\r
755   {\r
756     // Called when the MainTable selection changes\r
757     if (evt.getValueIsAdjusting())\r
758     {\r
759       return;\r
760     }\r
761 \r
762     displayFullDetails(null);\r
763 \r
764     // Filter the displayed data sources\r
765     int dSize = dasSources.length;\r
766 \r
767     ArrayList names = new ArrayList();\r
768     ArrayList selected = new ArrayList();\r
769     SOURCE ds;\r
770 \r
771     // The features filter is not visible, but we must still\r
772     // filter the das source list here.\r
773     // July 2006 - only 6 sources fo not serve features\r
774     Object[] dummyFeatureList = new Object[]\r
775     { "features" };\r
776 \r
777     for (int i = 0; i < dSize; i++)\r
778     {\r
779       ds = dasSources[i];\r
780       VERSION v=getVersionFor(ds);\r
781       List<COORDINATES> coords = v.getCOORDINATES();\r
782       if ((coords==null || coords.size()==0)\r
783               && filter1.getSelectedIndex() == 0\r
784               && filter2.getSelectedIndex() == 0\r
785               && filter3.getSelectedIndex() == 0)\r
786       {\r
787         // THIS IS A FIX FOR LOCAL SOURCES WHICH DO NOT\r
788         // HAVE COORDINATE SYSTEMS, INFO WHICH AT PRESENT\r
789         // IS ADDED FROM THE REGISTRY\r
790         names.add(ds.getTitle());\r
791         selected.add(new Boolean(selectedSources.contains(ds.getTitle())));\r
792         continue;\r
793       }\r
794 \r
795       if (!selectedInList(dummyFeatureList, getCapabilityKeys(v))\r
796               || !selectedInList(filter3.getSelectedValues(),\r
797                       getLabelsFor(v)))\r
798       {\r
799         continue;\r
800       }\r
801 \r
802       for (int j = 0; j <coords.size(); j++)\r
803       {\r
804         if (selectedInList(filter1.getSelectedValues(), new String[]\r
805         { coords.get(j).getAuthority() })\r
806                 && selectedInList(filter2.getSelectedValues(), new String[]\r
807                 { coords.get(j).getSource()}))\r
808         {\r
809           names.add(ds.getTitle());\r
810           selected.add(new Boolean(selectedSources.contains(ds.getTitle())));\r
811           break;\r
812         }\r
813       }\r
814     }\r
815 \r
816     dSize = names.size();\r
817     Object[][] data = new Object[dSize][2];\r
818     for (int d = 0; d < dSize; d++)\r
819     {\r
820       data[d][0] = names.get(d);\r
821       data[d][1] = selected.get(d);\r
822     }\r
823 \r
824     refreshTableData(data);\r
825   }\r
826 \r
827   private String[] getLabelsFor(VERSION v)\r
828   {\r
829     ArrayList<String> labels=new ArrayList<String>();\r
830     for (PROP p: v.getPROP())\r
831     {\r
832       if (p.getName().equalsIgnoreCase("LABEL"))\r
833       {\r
834         labels.add(p.getValue());\r
835       }\r
836     }\r
837     return labels.toArray(new String[0]);\r
838   }\r
839 \r
840   private String[] getCapabilityKeys(VERSION v)\r
841   {\r
842 \r
843     ArrayList<String> labels=new ArrayList<String>();\r
844     for (CAPABILITY p: v.getCAPABILITY())\r
845     {\r
846       // TODO: work out what to do with namespace prefix \r
847       // does SEQUENCE == das1:SEQUENCE and das2:SEQUENCE ?\r
848       // for moment, just show all capabilities...\r
849       if (p.getType().startsWith("das1:"))\r
850       {\r
851         labels.add(p.getType());\r
852       }\r
853     }\r
854     return labels.toArray(new String[0]);\r
855   }\r
856 \r
857   boolean selectedInList(Object[] selection, String[] items)\r
858   {\r
859     for (int i = 0; i < selection.length; i++)\r
860     {\r
861       if (selection[i].equals("Any"))\r
862       {\r
863         return true;\r
864       }\r
865 \r
866       for (int j = 0; j < items.length; j++)\r
867       {\r
868         if (selection[i].equals(items[j]))\r
869         {\r
870           return true;\r
871         }\r
872       }\r
873     }\r
874 \r
875     return false;\r
876   }\r
877 \r
878   void setSelectedFromProperties()\r
879   {\r
880     String active = jalview.bin.Cache.getDefault("DAS_ACTIVE_SOURCE",\r
881             "uniprot");\r
882     StringTokenizer st = new StringTokenizer(active, "\t");\r
883     selectedSources = new Vector();\r
884     while (st.hasMoreTokens())\r
885     {\r
886       selectedSources.addElement(st.nextToken());\r
887     }\r
888 \r
889     Vector _localSources = jalview.bin.Cache.getLocalDasSources();\r
890     if (_localSources != null)\r
891     {\r
892       if (localSources == null)\r
893       {\r
894         localSources = new Hashtable<String, SOURCE>();\r
895       }\r
896       Enumeration sources = _localSources.elements();\r
897       while (sources.hasMoreElements())\r
898       {\r
899         SOURCE source = (SOURCE) sources.nextElement();\r
900         localSources.put(source.getTitle(), source);\r
901       }\r
902     }\r
903   }\r
904 \r
905   public void reset_actionPerformed(ActionEvent e)\r
906   {\r
907     registryURL.setText(DEFAULT_REGISTRY);\r
908   }\r
909 \r
910   /**\r
911    * set the DAS source settings in the given jalview properties.\r
912    * \r
913    * @param properties\r
914    */\r
915   public void saveProperties(Properties properties)\r
916   {\r
917     if (registryURL.getText() == null || registryURL.getText().length() < 1)\r
918     {\r
919       properties.remove(jalview.bin.Cache.DAS_REGISTRY_URL);\r
920     }\r
921     else\r
922     {\r
923       properties.setProperty(jalview.bin.Cache.DAS_REGISTRY_URL,\r
924               registryURL.getText());\r
925     }\r
926 \r
927     StringBuffer sb = new StringBuffer();\r
928     for (int r = 0; r < table.getModel().getRowCount(); r++)\r
929     {\r
930       if (((Boolean) table.getValueAt(r, 1)).booleanValue())\r
931       {\r
932         sb.append(table.getValueAt(r, 0) + "\t");\r
933       }\r
934     }\r
935 \r
936     properties.setProperty(jalview.bin.Cache.DAS_ACTIVE_SOURCE,\r
937             sb.toString());\r
938 \r
939     if (localSources != null)\r
940     {\r
941       sb = new StringBuffer();\r
942       Enumeration en = localSources.keys();\r
943       while (en.hasMoreElements())\r
944       {\r
945         String token = en.nextElement().toString();\r
946         sb.append(token\r
947                 + "|"\r
948                 + (selectedInList(getCapabilityKeys(getVersionFor(localSources.get(token))),\r
949                         new String[] { "das1:"+Capabilities.SEQUENCE.getName()}) ? "sequence:" : "")\r
950                 + getVersionFor(localSources.get(token)).getUri() + "\t");\r
951       }\r
952 \r
953       properties.setProperty(jalview.bin.Cache.DAS_LOCAL_SOURCE,\r
954               sb.toString());\r
955     }\r
956 \r
957   }\r
958 \r
959   class DASTableModel extends AbstractTableModel\r
960   {\r
961 \r
962     public DASTableModel(Object[][] data)\r
963     {\r
964       this.data = data;\r
965     }\r
966 \r
967     private String[] columnNames = new String[]\r
968     { "Nickname", "Use Source" };\r
969 \r
970     private Object[][] data;\r
971 \r
972     public int getColumnCount()\r
973     {\r
974       return columnNames.length;\r
975     }\r
976 \r
977     public int getRowCount()\r
978     {\r
979       return data.length;\r
980     }\r
981 \r
982     public String getColumnName(int col)\r
983     {\r
984       return columnNames[col];\r
985     }\r
986 \r
987     public Object getValueAt(int row, int col)\r
988     {\r
989       return data[row][col];\r
990     }\r
991 \r
992     /*\r
993      * JTable uses this method to determine the default renderer/ editor for\r
994      * each cell. If we didn't implement this method, then the last column would\r
995      * contain text ("true"/"false"), rather than a check box.\r
996      */\r
997     public Class getColumnClass(int c)\r
998     {\r
999       return getValueAt(0, c).getClass();\r
1000     }\r
1001 \r
1002     /*\r
1003      * Don't need to implement this method unless your table's editable.\r
1004      */\r
1005     public boolean isCellEditable(int row, int col)\r
1006     {\r
1007       // Note that the data/cell address is constant,\r
1008       // no matter where the cell appears onscreen.\r
1009       return col == 1;\r
1010 \r
1011     }\r
1012 \r
1013     /*\r
1014      * Don't need to implement this method unless your table's data can change.\r
1015      */\r
1016     public void setValueAt(Object value, int row, int col)\r
1017     {\r
1018       data[row][col] = value;\r
1019       fireTableCellUpdated(row, col);\r
1020 \r
1021       String name = getValueAt(row, 0).toString();\r
1022       boolean selected = ((Boolean) value).booleanValue();\r
1023 \r
1024       if (selectedSources.contains(name) && !selected)\r
1025       {\r
1026         selectedSources.remove(name);\r
1027       }\r
1028 \r
1029       if (!selectedSources.contains(name) && selected)\r
1030       {\r
1031         selectedSources.add(name);\r
1032       }\r
1033     }\r
1034   }\r
1035 \r
1036   public void initDasSources()\r
1037   {\r
1038 \r
1039     Thread thr = new Thread(new Runnable()\r
1040     {\r
1041       public void run()\r
1042       {\r
1043         // this actually initialises the das source list\r
1044         paintComponent(null); // yuk\r
1045       }\r
1046     });\r
1047     thr.start();\r
1048     while (loadingDasSources || dasSources == null)\r
1049     {\r
1050       try\r
1051       {\r
1052         Thread.sleep(10);\r
1053       } catch (Exception e)\r
1054       {\r
1055       }\r
1056       ;\r
1057     }\r
1058   }\r
1059 \r
1060   public Vector resolveSourceNicknames(Vector sources)\r
1061   {\r
1062 \r
1063     Vector resolved = new Vector();\r
1064     if (sources != null)\r
1065     {\r
1066       for (int i = 0; i < dasSources.length; i++)\r
1067       {\r
1068         if (sources.contains(dasSources[i].getTitle()))\r
1069         {\r
1070           if (!resolved.contains(dasSources[i]))\r
1071           {\r
1072             resolved.addElement(dasSources[i]);\r
1073           }\r
1074         }\r
1075       }\r
1076     }\r
1077     return resolved;\r
1078   }\r
1079 \r
1080   /**\r
1081    * disable or enable the buttons on the source browser\r
1082    * \r
1083    * @param b\r
1084    */\r
1085   public void setGuiEnabled(boolean b)\r
1086   {\r
1087     refresh.setEnabled(b);\r
1088     addLocal.setEnabled(b);\r
1089   }\r
1090 }\r