JAL-1645 Version-Rel Version 2.9 Year-Rel 2015 Licensing glob
[jalview.git] / src / jalview / gui / DasSourceBrowser.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9)
3  * Copyright (C) 2015 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.gui;
22
23 import jalview.jbgui.GDasSourceBrowser;
24 import jalview.util.MessageManager;
25 import jalview.util.TableSorter;
26 import jalview.ws.dbsources.das.api.DasSourceRegistryI;
27 import jalview.ws.dbsources.das.api.jalviewSourceI;
28
29 import java.awt.BorderLayout;
30 import java.awt.event.ActionEvent;
31 import java.awt.event.MouseAdapter;
32 import java.awt.event.MouseEvent;
33 import java.util.ArrayList;
34 import java.util.List;
35 import java.util.Properties;
36 import java.util.StringTokenizer;
37 import java.util.Vector;
38
39 import javax.swing.JCheckBox;
40 import javax.swing.JLabel;
41 import javax.swing.JOptionPane;
42 import javax.swing.JPanel;
43 import javax.swing.JTextField;
44 import javax.swing.ListSelectionModel;
45 import javax.swing.SwingUtilities;
46 import javax.swing.event.ListSelectionEvent;
47 import javax.swing.event.ListSelectionListener;
48 import javax.swing.table.AbstractTableModel;
49
50 import org.biodas.jdas.schema.sources.CAPABILITY;
51 import org.biodas.jdas.schema.sources.COORDINATES;
52 import org.biodas.jdas.schema.sources.PROP;
53 import org.biodas.jdas.schema.sources.VERSION;
54
55 public class DasSourceBrowser extends GDasSourceBrowser implements
56         Runnable, ListSelectionListener
57 {
58   DasSourceRegistryI sourceRegistry = null;
59
60   Vector<String> selectedSources;
61
62   public DasSourceBrowser(FeatureSettings featureSettings)
63   {
64     fs = featureSettings;
65     // TODO DasSourceRegistryProvider API
66     sourceRegistry = jalview.bin.Cache.getDasSourceRegistry();
67     String registry = sourceRegistry.getDasRegistryURL();
68
69     registryURL.setText(registry);
70
71     setSelectedFromProperties();
72
73     displayFullDetails(null);
74     table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
75
76     filter1.addListSelectionListener(this);
77     filter2.addListSelectionListener(this);
78     filter3.addListSelectionListener(this);
79
80     // Ask to be notified of selection changes.
81     ListSelectionModel rowSM = table.getSelectionModel();
82     rowSM.addListSelectionListener(new ListSelectionListener()
83     {
84       public void valueChanged(ListSelectionEvent e)
85       {
86         ListSelectionModel lsm = (ListSelectionModel) e.getSource();
87         if (!lsm.isSelectionEmpty())
88         {
89           int selectedRow = lsm.getMinSelectionIndex();
90           displayFullDetails(table.getValueAt(selectedRow, 0).toString());
91         }
92       }
93     });
94
95     table.addMouseListener(new MouseAdapter()
96     {
97       public void mouseClicked(MouseEvent evt)
98       {
99         if (evt.getClickCount() == 2
100                 || SwingUtilities.isRightMouseButton(evt))
101         {
102           editRemoveLocalSource(evt);
103         }
104       }
105     });
106
107     if (sourceRegistry.getSources() != null)
108     {
109       init();
110     }
111   }
112
113   FeatureSettings fs = null;
114
115   private boolean loadingDasSources;
116
117   public DasSourceBrowser()
118   {
119     this(null);
120   }
121
122   public void paintComponent(java.awt.Graphics g)
123   {
124     if (sourceRegistry == null)
125     {
126       Thread worker = new Thread(this);
127       worker.start();
128     }
129   }
130
131   void init()
132   {
133     List<jalviewSourceI> sources = sourceRegistry.getSources();
134     int dSize = sources.size();
135     Object[][] data = new Object[dSize][2];
136     for (int i = 0; i < dSize; i++)
137     {
138       data[i][0] = sources.get(i).getTitle(); // what's equivalent of nickname
139       data[i][1] = new Boolean(selectedSources.contains(sources.get(i)
140               .getTitle()));
141     }
142
143     refreshTableData(data);
144     setCapabilities(sourceRegistry);
145
146     javax.swing.SwingUtilities.invokeLater(new Runnable()
147     {
148       public void run()
149       {
150         TableSorter sorter = (TableSorter) table.getModel();
151         sorter.setSortingStatus(1, TableSorter.DESCENDING);
152         sorter.setSortingStatus(1, TableSorter.NOT_SORTED);
153       }
154     });
155
156     progressBar.setIndeterminate(false);
157     progressBar.setVisible(false);
158     addLocal.setVisible(true);
159     refresh.setVisible(true);
160   }
161
162   public void refreshTableData(Object[][] data)
163   {
164     TableSorter sorter = new TableSorter(new DASTableModel(data));
165     sorter.setTableHeader(table.getTableHeader());
166     table.setModel(sorter);
167   }
168
169   void displayFullDetails(String nickName)
170   {
171
172     StringBuffer text = new StringBuffer(
173             "<HTML><font size=\"2\" face=\"Verdana, Arial, Helvetica, sans-serif\">");
174
175     if (nickName == null)
176     {
177       fullDetails.setText(text
178               + MessageManager
179                       .getString("label.select_das_service_from_table"));
180       return;
181     }
182
183     int dSize = sourceRegistry.getSources().size();
184     for (jalviewSourceI ds : sourceRegistry.getSources())
185     {
186       if (!ds.getTitle().equals(nickName))
187       {
188         continue;
189       }
190
191       VERSION latest = ds.getVersion();
192       text.append("<font color=\"#0000FF\">Id:</font> " + ds.getUri()
193               + "<br>");
194       text.append("<font color=\"#0000FF\">Nickname:</font> "
195               + ds.getTitle() + "<br>");
196
197       text.append("<font color=\"#0000FF\">URL:</font> <a href=\""
198               + ds.getSourceURL() + "\">" + ds.getSourceURL() + "</a>"
199               + "<br>");
200       if (!ds.isLocal())
201       {
202         if (ds.getDocHref() != null && ds.getDocHref().length() > 0)
203         {
204           text.append("<font color=\"#0000FF\">Site:</font> <a href=\""
205                   + ds.getDocHref() + "\">" + ds.getDocHref() + "</a>"
206                   + "<br>");
207         }
208
209         text.append("<font color=\"#0000FF\">Description:</font> "
210                 + ds.getDescription() + "<br>");
211
212         text.append("<font color=\"#0000FF\">Admin Email:</font> <a href=\"mailto:"
213                 + ds.getEmail() + "\">" + ds.getEmail() + "</a>" + "<br>");
214
215         text.append("<font color=\"#0000FF\">Registered at:</font> "
216                 + latest.getCreated() + "<br>");
217
218         // TODO: Identify last successful test date
219         // text.append("<font color=\"#0000FF\">Last successful test:</font> "
220         // + latest.dasSources[i].getLeaseDate() + "<br>");
221       }
222       else
223       {
224         text.append("Source was added manually.<br/>");
225       }
226       text.append("<font color=\"#0000FF\">Labels:</font> ");
227       boolean b = false;
228       for (PROP labl : latest.getPROP())
229       {
230         if (labl.getName().equalsIgnoreCase("LABEL"))
231         {
232           if (b)
233           {
234             text.append(",");
235           }
236           text.append(" ");
237
238           text.append(labl.getValue());
239           b = true;
240         }
241         ;
242       }
243       text.append("<br>");
244
245       text.append("<font color=\"#0000FF\">Capabilities:</font> ");
246       CAPABILITY[] scap = latest.getCAPABILITY().toArray(new CAPABILITY[0]);
247       for (int j = 0; j < scap.length; j++)
248       {
249         text.append(scap[j].getType());
250         if (j < scap.length - 1)
251         {
252           text.append(", ");
253         }
254       }
255       text.append("<br>");
256
257       text.append("<font color=\"#0000FF\">Coordinates:</font>");
258       int i = 1;
259       for (COORDINATES dcs : latest.getCOORDINATES())
260       {
261         text.append("<br/>" + i++ + ". ");
262         text.append(dcs.getAuthority() + " : " + dcs.getSource());
263         if (dcs.getTaxid() != null && dcs.getTaxid().trim().length() > 0)
264         {
265           text.append(" [TaxId:" + dcs.getTaxid() + "]");
266         }
267         if (dcs.getVersion() != null
268                 && dcs.getVersion().trim().length() > 0)
269         {
270           {
271             text.append(" {v. " + dcs.getVersion() + "}");
272           }
273         }
274         text.append(" (<a href=\"" + dcs.getUri() + "\">" + dcs.getUri()
275                 + "</a>)");
276       }
277       text.append("</font></html>");
278
279       break;
280     }
281
282     fullDetails.setText(text.toString());
283     javax.swing.SwingUtilities.invokeLater(new Runnable()
284     {
285       public void run()
286       {
287         fullDetailsScrollpane.getVerticalScrollBar().setValue(0);
288       }
289     });
290   }
291
292   public void run()
293   {
294     loadingDasSources = true;
295
296     addLocal.setVisible(false);
297     refresh.setVisible(false);
298     progressBar.setVisible(true);
299     progressBar.setIndeterminate(true);
300     setParentGuiEnabled(false);
301     // Refresh the source list.
302     sourceRegistry.refreshSources();
303
304     init();
305
306     setParentGuiEnabled(true);
307     loadingDasSources = false;
308
309   }
310
311   private void setParentGuiEnabled(boolean b)
312   {
313     if (fs != null)
314     {
315       fs.fetchDAS.setEnabled(b);
316       fs.saveDAS.setEnabled(b);
317     }
318   }
319
320   public Vector<jalviewSourceI> getSelectedSources()
321   {
322     // wait around if we're still loading.
323     while (sourceRegistry == null)
324     {
325       if (!loadingDasSources)
326       {
327         new Thread(this).start();
328         try
329         {
330           Thread.sleep(5);
331         } catch (Exception e)
332         {
333         }
334         ;
335         while (loadingDasSources)
336         {
337           try
338           {
339             Thread.sleep(5);
340           } catch (Exception e)
341           {
342           }
343           ;
344         }
345         ;
346       }
347     }
348
349     Vector<jalviewSourceI> selected = new Vector<jalviewSourceI>();
350     for (String source : selectedSources)
351     {
352       jalviewSourceI srce = sourceRegistry.getSource(source);
353       if (srce != null)
354       {
355         selected.addElement(srce);
356       }
357     }
358     return selected;
359   }
360
361   public void refresh_actionPerformed(ActionEvent e)
362   {
363     saveProperties(jalview.bin.Cache.applicationProperties);
364
365     Thread worker = new Thread(this);
366     worker.start();
367   }
368
369   private void setCapabilities(DasSourceRegistryI sourceRegistry2)
370   {
371     Vector<String> authority = new Vector<String>();
372     Vector<String> type = new Vector<String>();
373     Vector<String> label = new Vector<String>();
374     Vector<String> taxIds = new Vector<String>();
375     authority.add("Any");
376     type.add("Any");
377     label.add("Any");
378
379     for (jalviewSourceI ds : sourceRegistry2.getSources())
380     {
381       VERSION latest = ds.getVersion();
382
383       for (COORDINATES cs : latest.getCOORDINATES())
384       {
385         if (!type.contains(cs.getSource()))
386         {
387           type.add(cs.getSource()); // source==category
388         }
389
390         if (!authority.contains(cs.getAuthority()))
391         {
392           authority.add(cs.getAuthority());
393         }
394       }
395
396       for (PROP slabel : latest.getPROP())
397       {
398         if (slabel.getName().equalsIgnoreCase("LABEL")
399                 && !label.contains(slabel.getValue()))
400         {
401           label.add(slabel.getValue());
402         }
403       }
404
405     }
406
407     filter1.setListData(authority);
408     filter2.setListData(type);
409     filter3.setListData(label);
410     // filter4 taxIds
411
412     javax.swing.SwingUtilities.invokeLater(new Runnable()
413     {
414       public void run()
415       {
416         filter1.setSelectedIndex(0);
417         filter2.setSelectedIndex(0);
418         filter3.setSelectedIndex(0);
419       }
420     });
421   }
422
423   public void amendLocal(boolean newSource)
424   {
425     String url = "http://localhost:8080/", nickname = "";
426     boolean seqsrc = false;
427     if (!newSource)
428     {
429       int selectedRow = table.getSelectionModel().getMinSelectionIndex();
430       nickname = table.getValueAt(selectedRow, 0).toString();
431       jalviewSourceI source = sourceRegistry.getSource(nickname);
432       url = source.getUri();
433       seqsrc = source.isSequenceSource();
434     }
435
436     JTextField nametf = new JTextField(nickname, 40);
437     JTextField urltf = new JTextField(url, 40);
438     JCheckBox seqs = new JCheckBox(
439             MessageManager.getString("label.sequence_source"));
440     seqs.setSelected(seqsrc);
441     JPanel panel = new JPanel(new BorderLayout());
442     JPanel pane12 = new JPanel(new BorderLayout());
443     pane12.add(new JLabel(MessageManager.getString("label.name")),
444             BorderLayout.CENTER);
445     pane12.add(nametf, BorderLayout.EAST);
446     panel.add(pane12, BorderLayout.NORTH);
447     pane12 = new JPanel(new BorderLayout());
448     pane12.add(new JLabel(MessageManager.getString("label.url")),
449             BorderLayout.NORTH);
450     pane12.add(seqs, BorderLayout.SOUTH);
451     pane12.add(urltf, BorderLayout.EAST);
452     panel.add(pane12, BorderLayout.SOUTH);
453
454     int reply = JOptionPane.showInternalConfirmDialog(Desktop.desktop,
455             panel,
456             MessageManager.getString("label.enter_local_das_source"),
457             JOptionPane.OK_CANCEL_OPTION);
458
459     if (reply != JOptionPane.OK_OPTION)
460     {
461       return;
462     }
463
464     if (!urltf.getText().endsWith("/"))
465     {
466       urltf.setText(urltf.getText() + "/");
467     }
468
469     jalviewSourceI local = sourceRegistry.createLocalSource(
470             urltf.getText(), nametf.getText(), seqs.isSelected(), true);
471     List sources = sourceRegistry.getSources();
472     int osize = sources.size();
473     int size = osize + (newSource ? 1 : 0);
474
475     Object[][] data = new Object[size][2];
476     DASTableModel dtm = (table != null) ? (DASTableModel) ((TableSorter) table
477             .getModel()).getTableModel() : null;
478     for (int i = 0; i < osize; i++)
479     {
480       String osrc = (dtm == null || i >= osize) ? null : (String) dtm
481               .getValueAt(i, 0);
482       if (!newSource && osrc != null
483               && dtm.getValueAt(i, 0).equals(nickname))
484       {
485         data[i][0] = local.getTitle();
486         data[i][1] = new Boolean(true);
487       }
488       else
489       {
490         data[i][0] = osrc;
491         data[i][1] = new Boolean(selectedSources.contains(osrc));
492       }
493     }
494     // Always add a new source at the end
495     if (newSource)
496     {
497       data[osize][0] = local.getTitle();
498       data[osize][1] = new Boolean(true);
499       selectedSources.add(local.getTitle());
500     }
501
502     refreshTableData(data);
503
504     SwingUtilities.invokeLater(new Runnable()
505     {
506       public void run()
507       {
508         scrollPane.getVerticalScrollBar().setValue(
509                 scrollPane.getVerticalScrollBar().getMaximum());
510       }
511     });
512
513     displayFullDetails(local.getTitle());
514   }
515
516   public void editRemoveLocalSource(MouseEvent evt)
517   {
518     int selectedRow = table.getSelectionModel().getMinSelectionIndex();
519     if (selectedRow == -1)
520     {
521       return;
522     }
523
524     String nickname = table.getValueAt(selectedRow, 0).toString();
525
526     if (!sourceRegistry.getSource(nickname).isLocal())
527     {
528       JOptionPane
529               .showInternalMessageDialog(
530                       Desktop.desktop,
531                       MessageManager
532                               .getString("label.you_can_only_edit_or_remove_local_das_sources"),
533                       MessageManager.getString("label.public_das_source"),
534                       JOptionPane.WARNING_MESSAGE);
535       return;
536     }
537
538     Object[] options = { "Edit", "Remove", "Cancel" };
539     int choice = JOptionPane.showInternalOptionDialog(Desktop.desktop,
540             "Do you want to edit or remove " + nickname + "?",
541             "Edit / Remove Local DAS Source",
542             JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,
543             null, options, options[2]);
544
545     switch (choice)
546     {
547     case 0:
548       amendLocal(false);
549       break;
550     case 1:
551       sourceRegistry.removeLocalSource(sourceRegistry.getSource(nickname));
552       selectedSources.remove(nickname);
553       Object[][] data = new Object[sourceRegistry.getSources().size()][2];
554       int index = 0,
555       l = table.getRowCount();
556
557       for (int i = 0; i < l; i++)
558       {
559         String nm;
560         if ((nm = (String) table.getValueAt(i, 0)).equals(nickname))
561         {
562           continue;
563         }
564         else
565         {
566           data[index][0] = nm;
567           data[index][1] = new Boolean(selectedSources.contains(nm));
568           index++;
569         }
570       }
571       refreshTableData(data);
572       SwingUtilities.invokeLater(new Runnable()
573       {
574         public void run()
575         {
576           scrollPane.getVerticalScrollBar().setValue(
577                   scrollPane.getVerticalScrollBar().getMaximum());
578         }
579       });
580
581       break;
582     }
583   }
584
585   public void valueChanged(ListSelectionEvent evt)
586   {
587     // Called when the MainTable selection changes
588     if (evt.getValueIsAdjusting())
589     {
590       return;
591     }
592
593     displayFullDetails(null);
594
595     // Filter the displayed data sources
596
597     ArrayList names = new ArrayList();
598     ArrayList selected = new ArrayList();
599
600     // The features filter is not visible, but we must still
601     // filter the das source list here.
602     // July 2006 - only 6 sources fo not serve features
603     Object[] dummyFeatureList = new Object[] { "features" };
604     List<jalviewSourceI> srcs = sourceRegistry.getSources();
605     for (jalviewSourceI ds : srcs)
606     {
607
608       VERSION v = ds.getVersion();
609       List<COORDINATES> coords = v.getCOORDINATES();
610       if (ds.isLocal()
611               || ((coords == null || coords.size() == 0)
612                       && filter1.getSelectedIndex() == 0
613                       && filter2.getSelectedIndex() == 0 && filter3
614                       .getSelectedIndex() == 0))
615       {
616         // THIS IS A FIX FOR LOCAL SOURCES WHICH DO NOT
617         // HAVE COORDINATE SYSTEMS, INFO WHICH AT PRESENT
618         // IS ADDED FROM THE REGISTRY
619         names.add(ds.getTitle());
620         selected.add(new Boolean(selectedSources.contains(ds.getTitle())));
621         continue;
622       }
623
624       if (!selectedInList(dummyFeatureList, ds.getCapabilityList(v))
625               || !selectedInList(filter3.getSelectedValues(),
626                       ds.getLabelsFor(v)))
627       {
628         continue;
629       }
630
631       for (int j = 0; j < coords.size(); j++)
632       {
633         if (selectedInList(filter1.getSelectedValues(),
634                 new String[] { coords.get(j).getAuthority() })
635                 && selectedInList(filter2.getSelectedValues(), new String[]
636                 { coords.get(j).getSource() }))
637         {
638           names.add(ds.getTitle());
639           selected.add(new Boolean(selectedSources.contains(ds.getTitle())));
640           break;
641         }
642       }
643     }
644
645     int dSize = names.size();
646     Object[][] data = new Object[dSize][2];
647     for (int d = 0; d < dSize; d++)
648     {
649       data[d][0] = names.get(d);
650       data[d][1] = selected.get(d);
651     }
652
653     refreshTableData(data);
654   }
655
656   private boolean selectedInList(Object[] selection, String[] items)
657   {
658     for (int i = 0; i < selection.length; i++)
659     {
660       if (selection[i].equals("Any"))
661       {
662         return true;
663       }
664       if (items == null || items.length == 0)
665       {
666         return false;
667       }
668       String sel = (items[0].startsWith("das1:") ? "das1:" : "")
669               + selection[i];
670       for (int j = 0; j < items.length; j++)
671       {
672         if (sel.equals(items[j]))
673         {
674           return true;
675         }
676       }
677     }
678
679     return false;
680   }
681
682   void setSelectedFromProperties()
683   {
684     String active = jalview.bin.Cache.getDefault("DAS_ACTIVE_SOURCE",
685             "uniprot");
686     StringTokenizer st = new StringTokenizer(active, "\t");
687     selectedSources = new Vector();
688     while (st.hasMoreTokens())
689     {
690       selectedSources.addElement(st.nextToken());
691     }
692   }
693
694   public void reset_actionPerformed(ActionEvent e)
695   {
696     registryURL.setText(sourceRegistry.getDasRegistryURL());
697   }
698
699   /**
700    * set the DAS source settings in the given jalview properties.
701    * 
702    * @param properties
703    */
704   public void saveProperties(Properties properties)
705   {
706     if (registryURL.getText() == null || registryURL.getText().length() < 1)
707     {
708       properties.remove(jalview.bin.Cache.DAS_REGISTRY_URL);
709     }
710     else
711     {
712       properties.setProperty(jalview.bin.Cache.DAS_REGISTRY_URL,
713               registryURL.getText());
714     }
715
716     StringBuffer sb = new StringBuffer();
717     for (int r = 0; r < table.getModel().getRowCount(); r++)
718     {
719       if (((Boolean) table.getValueAt(r, 1)).booleanValue())
720       {
721         sb.append(table.getValueAt(r, 0) + "\t");
722       }
723     }
724
725     properties.setProperty(jalview.bin.Cache.DAS_ACTIVE_SOURCE,
726             sb.toString());
727
728     String sourceprop = sourceRegistry.getLocalSourceString();
729     properties.setProperty(jalview.bin.Cache.DAS_LOCAL_SOURCE, sourceprop);
730   }
731
732   class DASTableModel extends AbstractTableModel
733   {
734
735     public DASTableModel(Object[][] data)
736     {
737       this.data = data;
738     }
739
740     private String[] columnNames = new String[] {
741         MessageManager.getString("label.nickname"),
742         MessageManager.getString("label.use_source") };
743
744     private Object[][] data;
745
746     public int getColumnCount()
747     {
748       return columnNames.length;
749     }
750
751     public int getRowCount()
752     {
753       return data.length;
754     }
755
756     public String getColumnName(int col)
757     {
758       return columnNames[col];
759     }
760
761     public Object getValueAt(int row, int col)
762     {
763       return data[row][col];
764     }
765
766     /*
767      * JTable uses this method to determine the default renderer/ editor for
768      * each cell. If we didn't implement this method, then the last column would
769      * contain text ("true"/"false"), rather than a check box.
770      */
771     public Class getColumnClass(int c)
772     {
773       return getValueAt(0, c).getClass();
774     }
775
776     /*
777      * Don't need to implement this method unless your table's editable.
778      */
779     public boolean isCellEditable(int row, int col)
780     {
781       // Note that the data/cell address is constant,
782       // no matter where the cell appears onscreen.
783       return col == 1;
784
785     }
786
787     /*
788      * Don't need to implement this method unless your table's data can change.
789      */
790     public void setValueAt(Object value, int row, int col)
791     {
792       data[row][col] = value;
793       fireTableCellUpdated(row, col);
794
795       String name = getValueAt(row, 0).toString();
796       boolean selected = ((Boolean) value).booleanValue();
797
798       if (selectedSources.contains(name) && !selected)
799       {
800         selectedSources.remove(name);
801       }
802
803       if (!selectedSources.contains(name) && selected)
804       {
805         selectedSources.add(name);
806       }
807     }
808   }
809
810   public void initDasSources()
811   {
812
813     Thread thr = new Thread(new Runnable()
814     {
815       public void run()
816       {
817         // this actually initialises the das source list
818         paintComponent(null); // yuk
819       }
820     });
821     thr.start();
822     while (loadingDasSources || sourceRegistry == null)
823     {
824       try
825       {
826         Thread.sleep(10);
827       } catch (Exception e)
828       {
829       }
830       ;
831     }
832   }
833
834   /**
835    * disable or enable the buttons on the source browser
836    * 
837    * @param b
838    */
839   public void setGuiEnabled(boolean b)
840   {
841     refresh.setEnabled(b);
842     addLocal.setEnabled(b);
843   }
844 }