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