JAL-1097 - ensure replace comma for semicolon always disabled for das sources
[jalview.git] / src / jalview / gui / SequenceFetcher.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
3  * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle
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  */
18 package jalview.gui;
19
20 import java.util.*;
21 import java.util.List;
22
23 import java.awt.*;
24 import java.awt.event.*;
25
26 import javax.swing.*;
27 import javax.swing.tree.DefaultMutableTreeNode;
28 import javax.swing.tree.MutableTreeNode;
29 import javax.swing.tree.TreeModel;
30
31 import jalview.datamodel.*;
32 import jalview.io.*;
33 import jalview.util.DBRefUtils;
34 import jalview.ws.dbsources.das.api.DasSourceRegistryI;
35 import jalview.ws.seqfetcher.DbSourceProxy;
36 import jalview.ws.seqfetcher.DbSourceProxyImpl;
37
38 import java.awt.BorderLayout;
39
40 public class SequenceFetcher extends JPanel implements Runnable
41 {
42   // ASequenceFetcher sfetch;
43   JInternalFrame frame;
44
45   IProgressIndicator guiWindow;
46
47   AlignFrame alignFrame;
48
49   StringBuffer result;
50
51   final String noDbSelected = "-- Select Database --";
52
53   private static jalview.ws.SequenceFetcher sfetch = null;
54
55   private static long lastDasSourceRegistry = -3;
56
57   private static DasSourceRegistryI dasRegistry = null;
58
59   private static boolean _initingFetcher = false;
60
61   private static Thread initingThread = null;
62
63   /**
64    * Blocking method that initialises and returns the shared instance of the
65    * SequenceFetcher client
66    * 
67    * @param guiWindow
68    *          - where the initialisation delay message should be shown
69    * @return the singleton instance of the sequence fetcher client
70    */
71   public static jalview.ws.SequenceFetcher getSequenceFetcherSingleton(
72           final IProgressIndicator guiWindow)
73   {
74     if (_initingFetcher && initingThread != null && initingThread.isAlive())
75     {
76       if (guiWindow != null)
77       {
78         guiWindow.setProgressBar(
79                 "Waiting for Sequence Database Fetchers to initialise",
80                 Thread.currentThread().hashCode());
81       }
82       // initting happening on another thread - so wait around to see if it
83       // finishes.
84       while (_initingFetcher && initingThread != null
85               && initingThread.isAlive())
86       {
87         try
88         {
89           Thread.sleep(10);
90         } catch (Exception e)
91         {
92         }
93         ;
94       }
95       if (guiWindow != null)
96       {
97         guiWindow.setProgressBar(
98                 "Waiting for Sequence Database Fetchers to initialise",
99                 Thread.currentThread().hashCode());
100       }
101     }
102     if (sfetch == null
103             || dasRegistry != jalview.bin.Cache.getDasSourceRegistry()
104             || lastDasSourceRegistry != (jalview.bin.Cache
105                     .getDasSourceRegistry().getDasRegistryURL() + jalview.bin.Cache
106                     .getDasSourceRegistry().getLocalSourceString())
107                     .hashCode())
108     {
109       _initingFetcher = true;
110       initingThread = Thread.currentThread();
111       /**
112        * give a visual indication that sequence fetcher construction is occuring
113        */
114       if (guiWindow != null)
115       {
116         guiWindow.setProgressBar("Initialising Sequence Database Fetchers",
117                 Thread.currentThread().hashCode());
118       }
119       dasRegistry = jalview.bin.Cache.getDasSourceRegistry();
120       dasRegistry.refreshSources();
121
122       jalview.ws.SequenceFetcher sf = new jalview.ws.SequenceFetcher();
123       if (guiWindow != null)
124       {
125         guiWindow.setProgressBar("Initialising Sequence Database Fetchers",
126                 Thread.currentThread().hashCode());
127       }
128       lastDasSourceRegistry = (dasRegistry.getDasRegistryURL() + dasRegistry
129               .getLocalSourceString()).hashCode();
130       sfetch = sf;
131       _initingFetcher = false;
132       initingThread = null;
133     }
134     return sfetch;
135   }
136
137   public SequenceFetcher(IProgressIndicator guiIndic)
138   {
139     final IProgressIndicator guiWindow = guiIndic;
140     final SequenceFetcher us = this;
141     // launch initialiser thread
142     Thread sf = new Thread(new Runnable()
143     {
144
145       public void run()
146       {
147         if (getSequenceFetcherSingleton(guiWindow) != null)
148         {
149           us.initGui(guiWindow);
150         }
151         else
152         {
153           javax.swing.SwingUtilities.invokeLater(new Runnable()
154           {
155             public void run()
156             {
157               JOptionPane
158                       .showInternalMessageDialog(
159                               Desktop.desktop,
160                               "Could not create the sequence fetcher client. Check error logs for details.",
161                               "Couldn't create SequenceFetcher",
162                               JOptionPane.ERROR_MESSAGE);
163             }
164           });
165
166           // raise warning dialog
167         }
168       }
169     });
170     sf.start();
171   }
172
173   private class DatabaseAuthority extends DefaultMutableTreeNode
174   {
175
176   };
177
178   private class DatabaseSource extends DefaultMutableTreeNode
179   {
180
181   };
182
183   /**
184    * called by thread spawned by constructor
185    * 
186    * @param guiWindow
187    */
188   private void initGui(IProgressIndicator guiWindow)
189   {
190     this.guiWindow = guiWindow;
191     if (guiWindow instanceof AlignFrame)
192     {
193       alignFrame = (AlignFrame) guiWindow;
194     }
195     database = new JDatabaseTree(sfetch);
196     try
197     {
198       jbInit();
199     } catch (Exception ex)
200     {
201       ex.printStackTrace();
202     }
203
204     frame = new JInternalFrame();
205     frame.setContentPane(this);
206     if (new jalview.util.Platform().isAMac())
207     {
208       Desktop.addInternalFrame(frame, getFrameTitle(), 400, 240);
209     }
210     else
211     {
212       Desktop.addInternalFrame(frame, getFrameTitle(), 400, 180);
213     }
214   }
215
216   private String getFrameTitle()
217   {
218     return ((alignFrame == null) ? "New " : "Additional ")
219             + "Sequence Fetcher";
220   }
221
222   private void jbInit() throws Exception
223   {
224     this.setLayout(borderLayout2);
225
226     database.setFont(JvSwingUtils.getLabelFont());
227     dbeg.setFont(new java.awt.Font("Verdana", Font.BOLD, 11));
228     jLabel1.setFont(new java.awt.Font("Verdana", Font.ITALIC, 11));
229     jLabel1.setHorizontalAlignment(SwingConstants.CENTER);
230     jLabel1.setText("Separate multiple accession ids with semi colon \";\"");
231
232     replacePunctuation.setHorizontalAlignment(SwingConstants.CENTER);
233     replacePunctuation
234             .setFont(new java.awt.Font("Verdana", Font.ITALIC, 11));
235     replacePunctuation.setText("Replace commas with semi-colons");
236     ok.setText("OK");
237     ok.addActionListener(new ActionListener()
238     {
239       public void actionPerformed(ActionEvent e)
240       {
241         ok_actionPerformed();
242       }
243     });
244     clear.setText("Clear");
245     clear.addActionListener(new ActionListener()
246     {
247       public void actionPerformed(ActionEvent e)
248       {
249         clear_actionPerformed();
250       }
251     });
252
253     example.setText("Example");
254     example.addActionListener(new ActionListener()
255     {
256       public void actionPerformed(ActionEvent e)
257       {
258         example_actionPerformed();
259       }
260     });
261     close.setText("Close");
262     close.addActionListener(new ActionListener()
263     {
264       public void actionPerformed(ActionEvent e)
265       {
266         close_actionPerformed(e);
267       }
268     });
269     textArea.setFont(JvSwingUtils.getLabelFont());
270     textArea.setLineWrap(true);
271     textArea.addKeyListener(new KeyAdapter()
272     {
273       public void keyPressed(KeyEvent e)
274       {
275         if (e.getKeyCode() == KeyEvent.VK_ENTER)
276           ok_actionPerformed();
277       }
278     });
279     jPanel3.setLayout(borderLayout1);
280     borderLayout1.setVgap(5);
281     jPanel1.add(ok);
282     jPanel1.add(example);
283     jPanel1.add(clear);
284     jPanel1.add(close);
285     jPanel3.add(jPanel2, java.awt.BorderLayout.CENTER);
286     jPanel2.setLayout(borderLayout3);
287     databaseButt = database.getDatabaseSelectorButton();
288     databaseButt.setFont(JvSwingUtils.getLabelFont());
289     database.addActionListener(new ActionListener()
290     {
291
292       public void actionPerformed(ActionEvent e)
293       {
294         try
295         {
296           databaseButt.setText(database.getSelectedItem()
297                   + (database.getSelectedSources().size() > 1 ? " (and "
298                           + database.getSelectedSources().size()
299                           + " others)" : ""));
300           String eq = database.getExampleQueries();
301           dbeg.setText("Example query: " + eq);
302           boolean enablePunct=!(eq != null && eq.indexOf(",") > -1);
303           for (DbSourceProxy dbs:database.getSelectedSources()) {
304             if (dbs instanceof jalview.ws.dbsources.das.datamodel.DasSequenceSource)
305             {
306               enablePunct = false;
307               break;
308             }
309           }
310           replacePunctuation.setEnabled(enablePunct);
311
312         } catch (Exception ex)
313         {
314           dbeg.setText("");
315           replacePunctuation.setEnabled(true);
316         }
317         jPanel2.repaint();
318       }
319     });
320     dbeg.setText("");
321     jPanel2.add(databaseButt, java.awt.BorderLayout.NORTH);
322     jPanel2.add(dbeg, java.awt.BorderLayout.CENTER);
323     JPanel jPanel2a = new JPanel(new BorderLayout());
324     jPanel2a.add(jLabel1, java.awt.BorderLayout.NORTH);
325     jPanel2a.add(replacePunctuation, java.awt.BorderLayout.SOUTH);
326     jPanel2.add(jPanel2a, java.awt.BorderLayout.SOUTH);
327     // jPanel2.setPreferredSize(new Dimension())
328     jPanel3.add(jScrollPane1, java.awt.BorderLayout.CENTER);
329     this.add(jPanel1, java.awt.BorderLayout.SOUTH);
330     this.add(jPanel3, java.awt.BorderLayout.CENTER);
331     this.add(jPanel2, java.awt.BorderLayout.NORTH);
332     jScrollPane1.getViewport().add(textArea);
333
334   }
335
336   protected void example_actionPerformed()
337   {
338     DbSourceProxy db = null;
339     try
340     {
341       textArea.setText(database.getExampleQueries());
342     } catch (Exception ex)
343     {
344     }
345     jPanel3.repaint();
346   }
347
348   protected void clear_actionPerformed()
349   {
350     textArea.setText("");
351     jPanel3.repaint();
352   }
353
354   JLabel dbeg = new JLabel();
355
356   JDatabaseTree database;
357
358   JButton databaseButt;
359
360   JLabel jLabel1 = new JLabel();
361
362   JCheckBox replacePunctuation = new JCheckBox();
363
364   JButton ok = new JButton();
365
366   JButton clear = new JButton();
367
368   JButton example = new JButton();
369
370   JButton close = new JButton();
371
372   JPanel jPanel1 = new JPanel();
373
374   JTextArea textArea = new JTextArea();
375
376   JScrollPane jScrollPane1 = new JScrollPane();
377
378   JPanel jPanel2 = new JPanel();
379
380   JPanel jPanel3 = new JPanel();
381
382   JPanel jPanel4 = new JPanel();
383
384   BorderLayout borderLayout1 = new BorderLayout();
385
386   BorderLayout borderLayout2 = new BorderLayout();
387
388   BorderLayout borderLayout3 = new BorderLayout();
389
390   public void close_actionPerformed(ActionEvent e)
391   {
392     try
393     {
394       frame.setClosed(true);
395     } catch (Exception ex)
396     {
397     }
398   }
399
400   public void ok_actionPerformed()
401   {
402     database.setEnabled(false);
403     textArea.setEnabled(false);
404     ok.setEnabled(false);
405     close.setEnabled(false);
406
407     Thread worker = new Thread(this);
408     worker.start();
409   }
410
411   private void resetDialog()
412   {
413     database.setEnabled(true);
414     textArea.setEnabled(true);
415     ok.setEnabled(true);
416     close.setEnabled(true);
417   }
418
419   public void run()
420   {
421     String error = "";
422     if (!database.hasSelection())
423     {
424       error += "Please select the source database\n";
425     }
426     // TODO: make this transformation more configurable
427     com.stevesoft.pat.Regex empty;
428     if (replacePunctuation.isEnabled() && replacePunctuation.isSelected())
429     {
430       empty = new com.stevesoft.pat.Regex(
431       // replace commas and spaces with a semicolon
432               "(\\s|[,; ])+", ";");
433     }
434     else
435     {
436       // just turn spaces and semicolons into single semicolons
437       empty = new com.stevesoft.pat.Regex("(\\s|[; ])+", ";");
438     }
439     textArea.setText(empty.replaceAll(textArea.getText()));
440     // see if there's anthing to search with
441     if (!new com.stevesoft.pat.Regex("[A-Za-z0-9_.]").search(textArea
442             .getText()))
443     {
444       error += "Please enter a (semi-colon separated list of) database id(s)";
445     }
446     if (error.length() > 0)
447     {
448       showErrorMessage(error);
449       resetDialog();
450       return;
451     }
452     // indicate if successive sources should be merged into one alignment.
453     boolean addToLast=false;
454     ArrayList<String> aresultq = new ArrayList<String>(), presultTitle = new ArrayList<String>();
455     ArrayList<AlignmentI> presult = new ArrayList<AlignmentI>(), aresult = new ArrayList<AlignmentI>();
456     Iterator<DbSourceProxy> proxies = database.getSelectedSources()
457             .iterator();
458     String[] qries;
459     List<String> nextfetch = Arrays.asList(qries = textArea.getText()
460             .split(";"));
461     Iterator<String> en = Arrays.asList(new String[0]).iterator();
462     int nqueries = qries.length;
463     while (proxies.hasNext() && (en.hasNext() || nextfetch.size() > 0))
464     {
465       if (!en.hasNext() && nextfetch.size() > 0)
466       {
467         en = nextfetch.iterator();
468         nqueries = nextfetch.size();
469         // save the remaining queries in the original array
470         qries = nextfetch.toArray(new String[nqueries]);
471         nextfetch = new ArrayList<String>();
472       }
473
474       DbSourceProxy proxy = proxies.next();
475       boolean isAliSource = false;
476       try
477       {
478         // update status
479         guiWindow.setProgressBar("Fetching " + nqueries
480                 + " sequence queries from " + proxy.getDbName(), Thread
481                 .currentThread().hashCode());
482         isAliSource = proxy.isA(DBRefSource.ALIGNMENTDB);
483         if (proxy.getAccessionSeparator() == null)
484         {
485           while (en.hasNext())
486           {
487             String item = en.next();
488             try
489             {
490               if (aresult != null)
491               {
492                 try
493                 {
494                   // give the server a chance to breathe
495                   Thread.sleep(5);
496                 } catch (Exception e)
497                 {
498                   //
499                 }
500
501               }
502
503               AlignmentI indres = null;
504               try
505               {
506                 indres = proxy.getSequenceRecords(item);
507               } catch (OutOfMemoryError oome)
508               {
509                 new OOMWarning("fetching " + item + " from "
510                         + proxy.getDbName(), oome, this);
511               }
512               if (indres != null)
513               {
514                 aresultq.add(item);
515                 aresult.add(indres);
516               }
517               else
518               {
519                 nextfetch.add(item);
520               }
521             } catch (Exception e)
522             {
523               jalview.bin.Cache.log.info("Error retrieving " + item
524                       + " from " + proxy.getDbName(), e);
525               nextfetch.add(item);
526             }
527           }
528         }
529         else
530         {
531           StringBuffer multiacc = new StringBuffer();
532           ArrayList<String> tosend = new ArrayList<String>();
533           while (en.hasNext())
534           {
535             String nel = en.next();
536             tosend.add(nel);
537             multiacc.append(nel);
538             if (en.hasNext())
539             {
540               multiacc.append(proxy.getAccessionSeparator());
541             }
542           }
543           try
544           {
545             AlignmentI rslt;
546             SequenceI[] rs;
547             List<String> nores = new ArrayList<String>();
548             rslt = proxy.getSequenceRecords(multiacc.toString());
549             if (rslt == null || rslt.getHeight() == 0)
550             {
551               // no results - pass on all queries to next source
552               nextfetch.addAll(tosend);
553             }
554             else
555             {
556               aresultq.add(multiacc.toString());
557               aresult.add(rslt);
558
559               rs = rslt.getSequencesArray();
560               // search for each query in the dbrefs associated with each
561               // sequence
562               // returned.
563               // ones we do not find will be used to query next source (if any)
564               for (String q : tosend)
565               {
566                 DBRefEntry dbr = new DBRefEntry(), found[] = null;
567                 dbr.setSource(proxy.getDbSource());
568                 boolean rfound = false;
569                 for (int r = 0; r < rs.length; r++)
570                 {
571                   if (rs[r] != null
572                           && (found = DBRefUtils.searchRefs(
573                                   rs[r].getDBRef(), dbr)) != null
574                           && found.length > 0)
575                   {
576                     rfound = true;
577                     rs[r] = null;
578                     continue;
579                   }
580                 }
581                 if (!rfound)
582                 {
583                   nextfetch.add(q);
584                 }
585               }
586             }
587           } catch (OutOfMemoryError oome)
588           {
589             new OOMWarning("fetching " + multiacc + " from "
590                     + database.getSelectedItem(), oome, this);
591           }
592         }
593
594       } catch (Exception e)
595       {
596         showErrorMessage("Error retrieving " + textArea.getText()
597                 + " from " + database.getSelectedItem());
598         // error
599         // +="Couldn't retrieve sequences from "+database.getSelectedItem();
600         System.err.println("Retrieval failed for source ='"
601                 + database.getSelectedItem() + "' and query\n'"
602                 + textArea.getText() + "'\n");
603         e.printStackTrace();
604       } catch (OutOfMemoryError e)
605       {
606         // resets dialog box - so we don't use OOMwarning here.
607         showErrorMessage("Out of Memory when retrieving "
608                 + textArea.getText()
609                 + " from "
610                 + database.getSelectedItem()
611                 + "\nPlease see the Jalview FAQ for instructions for increasing the memory available to Jalview.\n");
612         e.printStackTrace();
613       } catch (Error e)
614       {
615         showErrorMessage("Serious Error retrieving " + textArea.getText()
616                 + " from " + database.getSelectedItem());
617         e.printStackTrace();
618       }
619       // Stack results ready for opening in alignment windows
620       if (aresult != null && aresult.size() > 0)
621       {
622         AlignmentI ar = null;
623         if (isAliSource)
624         {
625           addToLast=false;
626           // new window for each result
627           while (aresult.size() > 0)
628           {
629             presult.add(aresult.remove(0));
630             presultTitle.add(aresultq.remove(0) + " "
631                     + getDefaultRetrievalTitle());
632           }
633         }
634         else
635         {
636           String titl=null;
637           if (addToLast && presult.size()>0)
638           {
639             ar=presult.remove(presult.size()-1);
640             titl=presultTitle.remove(presultTitle.size()-1);
641           }
642           // concatenate all results in one window
643           while (aresult.size() > 0)
644           {
645             if (ar == null)
646             {
647               ar = aresult.remove(0);
648             }
649             else
650             {
651               ar.append(aresult.remove(0));
652             }
653             ;
654           }
655           addToLast=true;
656           presult.add(ar);
657           presultTitle.add(titl);
658         }
659       }
660       guiWindow.setProgressBar("Finished querying", Thread.currentThread().hashCode());
661     }
662     guiWindow.setProgressBar((presult.size()>0) ? "Parsing results.":"Processing ..", Thread.currentThread().hashCode());
663     // process results
664     while (presult.size() > 0)
665     {
666       parseResult(presult.remove(0), presultTitle.remove(0), null);
667     }
668     // only remove visual delay after we finished parsing.
669     guiWindow.setProgressBar(null, Thread.currentThread().hashCode());
670     if (nextfetch.size() > 0)
671     {
672       StringBuffer sb = new StringBuffer();
673       sb.append("Didn't retrieve the following "
674               + (nextfetch.size() == 1 ? "query" : nextfetch.size()
675                       + " queries") + ": \n");
676       int l = sb.length(),lr=0;
677       for (String s : nextfetch)
678       {
679         if (l != sb.length())
680         {
681           sb.append("; ");
682         }
683         if (lr-sb.length()>40)
684         {
685           sb.append("\n");
686         }
687         sb.append(s);
688       }
689       showErrorMessage(sb.toString());
690     }
691     resetDialog();
692   }
693
694   AlignmentI parseResult(String result, String title)
695   {
696     String format = new IdentifyFile().Identify(result, "Paste");
697     Alignment sequences = null;
698     if (FormatAdapter.isValidFormat(format))
699     {
700       sequences = null;
701       try
702       {
703         sequences = new FormatAdapter().readFile(result.toString(),
704                 "Paste", format);
705       } catch (Exception ex)
706       {
707       }
708
709       if (sequences != null)
710       {
711         return parseResult(sequences, title, format);
712       }
713     }
714     else
715     {
716       showErrorMessage("Error retrieving " + textArea.getText() + " from "
717               + database.getSelectedItem());
718     }
719
720     return null;
721   }
722
723   /**
724    * 
725    * @return a standard title for any results retrieved using the currently
726    *         selected source and settings
727    */
728   public String getDefaultRetrievalTitle()
729   {
730     return "Retrieved from " + database.getSelectedItem();
731   }
732
733   AlignmentI parseResult(AlignmentI al, String title,
734           String currentFileFormat)
735   {
736
737     if (al != null && al.getHeight() > 0)
738     {
739       if (alignFrame == null)
740       {
741         AlignFrame af = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH,
742                 AlignFrame.DEFAULT_HEIGHT);
743         if (currentFileFormat != null)
744         {
745           af.currentFileFormat = currentFileFormat; // WHAT IS THE DEFAULT
746           // FORMAT FOR
747           // NON-FormatAdapter Sourced
748           // Alignments?
749         }
750
751         if (title == null)
752         {
753           title = getDefaultRetrievalTitle();
754         }
755         SequenceFeature[] sfs = null;
756         for (Enumeration sq = al.getSequences().elements(); sq
757                 .hasMoreElements();)
758         {
759           if ((sfs = ((SequenceI) sq.nextElement()).getDatasetSequence()
760                   .getSequenceFeatures()) != null)
761           {
762             if (sfs.length > 0)
763             {
764               af.setShowSeqFeatures(true);
765               break;
766             }
767           }
768
769         }
770         Desktop.addInternalFrame(af, title, AlignFrame.DEFAULT_WIDTH,
771                 AlignFrame.DEFAULT_HEIGHT);
772
773         af.statusBar.setText("Successfully pasted alignment file");
774
775         try
776         {
777           af.setMaximum(jalview.bin.Cache.getDefault("SHOW_FULLSCREEN",
778                   false));
779         } catch (Exception ex)
780         {
781         }
782       }
783       else
784       {
785         for (int i = 0; i < al.getHeight(); i++)
786         {
787           alignFrame.viewport.getAlignment().addSequence(
788                   al.getSequenceAt(i)); // this
789           // also
790           // creates
791           // dataset
792           // sequence
793           // entries
794         }
795         alignFrame.viewport.setEndSeq(alignFrame.viewport.getAlignment()
796                 .getHeight());
797         alignFrame.viewport.getAlignment().getWidth();
798         alignFrame.viewport.firePropertyChange("alignment", null,
799                 alignFrame.viewport.getAlignment().getSequences());
800       }
801     }
802     return al;
803   }
804
805   void showErrorMessage(final String error)
806   {
807     resetDialog();
808     javax.swing.SwingUtilities.invokeLater(new Runnable()
809     {
810       public void run()
811       {
812         JOptionPane.showInternalMessageDialog(Desktop.desktop, error,
813                 "Error Retrieving Data", JOptionPane.WARNING_MESSAGE);
814       }
815     });
816   }
817 }