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