only need to remove progress bar if fetch wasn't cancelled (bug #0059977)
[jalview.git] / src / jalview / ws / MsaWSThread.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)\r
3  * Copyright (C) 2009 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  * \r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  * \r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  * \r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 package jalview.ws;\r
20 \r
21 import java.util.*;\r
22 \r
23 import jalview.analysis.*;\r
24 import jalview.bin.*;\r
25 import jalview.datamodel.*;\r
26 import jalview.datamodel.Alignment;\r
27 import jalview.gui.*;\r
28 import vamsas.objects.simple.MsaResult;\r
29 \r
30 /**\r
31  * <p>\r
32  * Title:\r
33  * </p>\r
34  * \r
35  * <p>\r
36  * Description:\r
37  * </p>\r
38  * \r
39  * <p>\r
40  * Copyright: Copyright (c) 2004\r
41  * </p>\r
42  * \r
43  * <p>\r
44  * Company: Dundee University\r
45  * </p>\r
46  * \r
47  * @author not attributable\r
48  * @version 1.0\r
49  */\r
50 class MsaWSThread extends WSThread implements WSClientI\r
51 {\r
52   boolean submitGaps = false; // pass sequences including gaps to alignment\r
53 \r
54   // service\r
55 \r
56   boolean preserveOrder = true; // and always store and recover sequence\r
57 \r
58   // order\r
59 \r
60   class MsaWSJob extends WSThread.WSJob\r
61   {\r
62     // hold special input for this\r
63     vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();\r
64 \r
65     /**\r
66      * MsaWSJob\r
67      * \r
68      * @param jobNum\r
69      *                int\r
70      * @param jobId\r
71      *                String\r
72      */\r
73     public MsaWSJob(int jobNum, SequenceI[] inSeqs)\r
74     {\r
75       this.jobnum = jobNum;\r
76       if (!prepareInput(inSeqs, 2))\r
77       {\r
78         submitted = true;\r
79         subjobComplete = true;\r
80         result = new MsaResult();\r
81         result.setFinished(true);\r
82         result.setStatus("Job never ran - input returned to user.");\r
83       }\r
84 \r
85     }\r
86 \r
87     Hashtable SeqNames = new Hashtable();\r
88 \r
89     Vector emptySeqs = new Vector();\r
90 \r
91     /**\r
92      * prepare input sequences for MsaWS service\r
93      * \r
94      * @param seqs\r
95      *                jalview sequences to be prepared\r
96      * @param minlen\r
97      *                minimum number of residues required for this MsaWS service\r
98      * @return true if seqs contains sequences to be submitted to service.\r
99      */\r
100     private boolean prepareInput(SequenceI[] seqs, int minlen)\r
101     {\r
102       int nseqs = 0;\r
103       if (minlen < 0)\r
104       {\r
105         throw new Error(\r
106                 "Implementation error: minlen must be zero or more.");\r
107       }\r
108       for (int i = 0; i < seqs.length; i++)\r
109       {\r
110         if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)\r
111         {\r
112           nseqs++;\r
113         }\r
114       }\r
115       boolean valid = nseqs > 1; // need at least two seqs\r
116       vamsas.objects.simple.Sequence[] seqarray = (valid) ? new vamsas.objects.simple.Sequence[nseqs]\r
117               : null;\r
118       for (int i = 0, n = 0; i < seqs.length; i++)\r
119       {\r
120 \r
121         String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same\r
122         // for\r
123         // any\r
124         // subjob\r
125         SeqNames.put(newname, jalview.analysis.SeqsetUtils\r
126                 .SeqCharacterHash(seqs[i]));\r
127         if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)\r
128         {\r
129           seqarray[n] = new vamsas.objects.simple.Sequence();\r
130           seqarray[n].setId(newname);\r
131           seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequenceAsString()\r
132                   : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,\r
133                           seqs[i].getSequenceAsString()));\r
134         }\r
135         else\r
136         {\r
137           String empty = null;\r
138           if (seqs[i].getEnd() >= seqs[i].getStart())\r
139           {\r
140             empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq\r
141                     .extractGaps(jalview.util.Comparison.GapChars, seqs[i]\r
142                             .getSequenceAsString());\r
143           }\r
144           emptySeqs.add(new String[]\r
145           { newname, empty });\r
146         }\r
147       }\r
148       this.seqs = new vamsas.objects.simple.SequenceSet();\r
149       this.seqs.setSeqs(seqarray);\r
150       return valid;\r
151     }\r
152 \r
153     /**\r
154      * \r
155      * @return true if getAlignment will return a valid alignment result.\r
156      */\r
157     public boolean hasResults()\r
158     {\r
159       if (subjobComplete && result != null && result.isFinished()\r
160               && ((MsaResult) result).getMsa() != null\r
161               && ((MsaResult) result).getMsa().getSeqs() != null)\r
162       {\r
163         return true;\r
164       }\r
165       return false;\r
166     }\r
167 \r
168     public Object[] getAlignment()\r
169     {\r
170 \r
171       if (result != null && result.isFinished())\r
172       {\r
173         SequenceI[] alseqs = null;\r
174         char alseq_gapchar = '-';\r
175         int alseq_l = 0;\r
176         if (((MsaResult) result).getMsa() != null)\r
177         {\r
178           alseqs = getVamsasAlignment(((MsaResult) result).getMsa());\r
179           alseq_gapchar = ((MsaResult) result).getMsa().getGapchar()\r
180                   .charAt(0);\r
181           alseq_l = alseqs.length;\r
182         }\r
183         if (emptySeqs.size() > 0)\r
184         {\r
185           SequenceI[] t_alseqs = new SequenceI[alseq_l + emptySeqs.size()];\r
186           // get width\r
187           int i, w = 0;\r
188           if (alseq_l > 0)\r
189           {\r
190             for (i = 0, w = alseqs[0].getLength(); i < alseq_l; i++)\r
191             {\r
192               if (w < alseqs[i].getLength())\r
193               {\r
194                 w = alseqs[i].getLength();\r
195               }\r
196               t_alseqs[i] = alseqs[i];\r
197               alseqs[i] = null;\r
198             }\r
199           }\r
200           // check that aligned width is at least as wide as emptySeqs width.\r
201           int ow = w, nw = w;\r
202           for (i = 0, w = emptySeqs.size(); i < w; i++)\r
203           {\r
204             String[] es = (String[]) emptySeqs.get(i);\r
205             if (es != null && es[1] != null)\r
206             {\r
207               int sw = es[1].length();\r
208               if (nw < sw)\r
209               {\r
210                 nw = sw;\r
211               }\r
212             }\r
213           }\r
214           // make a gapped string.\r
215           StringBuffer insbuff = new StringBuffer(w);\r
216           for (i = 0; i < nw; i++)\r
217           {\r
218             insbuff.append(alseq_gapchar);\r
219           }\r
220           if (ow < nw)\r
221           {\r
222             for (i = 0; i < alseq_l; i++)\r
223             {\r
224               int sw = t_alseqs[i].getLength();\r
225               if (nw > sw)\r
226               {\r
227                 // pad at end\r
228                 alseqs[i].setSequence(t_alseqs[i].getSequenceAsString()\r
229                         + insbuff.substring(0, sw - nw));\r
230               }\r
231             }\r
232           }\r
233           for (i = 0, w = emptySeqs.size(); i < w; i++)\r
234           {\r
235             String[] es = (String[]) emptySeqs.get(i);\r
236             if (es[1] == null)\r
237             {\r
238               t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(es[0],\r
239                       insbuff.toString(), 1, 0);\r
240             }\r
241             else\r
242             {\r
243               if (es[1].length() < nw)\r
244               {\r
245                 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(\r
246                         es[0],\r
247                         es[1] + insbuff.substring(0, nw - es[1].length()),\r
248                         1, 1 + es[1].length());\r
249               }\r
250               else\r
251               {\r
252                 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(\r
253                         es[0], es[1]);\r
254               }\r
255             }\r
256           }\r
257           alseqs = t_alseqs;\r
258         }\r
259         AlignmentOrder msaorder = new AlignmentOrder(alseqs);\r
260         // always recover the order - makes parseResult()'s life easier.\r
261         jalview.analysis.AlignmentSorter.recoverOrder(alseqs);\r
262         // account for any missing sequences\r
263         jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs);\r
264         return new Object[]\r
265         { alseqs, msaorder };\r
266       }\r
267       return null;\r
268     }\r
269 \r
270     /**\r
271      * mark subjob as cancelled and set result object appropriatly\r
272      */\r
273     void cancel()\r
274     {\r
275       cancelled = true;\r
276       subjobComplete = true;\r
277       result = null;\r
278     }\r
279 \r
280     /**\r
281      * \r
282      * @return boolean true if job can be submitted.\r
283      */\r
284     boolean hasValidInput()\r
285     {\r
286       if (seqs.getSeqs() != null)\r
287       {\r
288         return true;\r
289       }\r
290       return false;\r
291     }\r
292   }\r
293 \r
294   String alTitle; // name which will be used to form new alignment window.\r
295 \r
296   Alignment dataset; // dataset to which the new alignment will be\r
297 \r
298   // associated.\r
299 \r
300   ext.vamsas.MuscleWS server = null;\r
301 \r
302   /**\r
303    * set basic options for this (group) of Msa jobs\r
304    * \r
305    * @param subgaps\r
306    *                boolean\r
307    * @param presorder\r
308    *                boolean\r
309    */\r
310   MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,\r
311           WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,\r
312           AlignmentView alview, String wsname, boolean subgaps,\r
313           boolean presorder)\r
314   {\r
315     super(alFrame, wsinfo, alview, wsname, wsUrl);\r
316     this.server = server;\r
317     this.submitGaps = subgaps;\r
318     this.preserveOrder = presorder;\r
319   }\r
320 \r
321   /**\r
322    * create one or more Msa jobs to align visible seuqences in _msa\r
323    * \r
324    * @param title\r
325    *                String\r
326    * @param _msa\r
327    *                AlignmentView\r
328    * @param subgaps\r
329    *                boolean\r
330    * @param presorder\r
331    *                boolean\r
332    * @param seqset\r
333    *                Alignment\r
334    */\r
335   MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,\r
336           WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,\r
337           String wsname, String title, AlignmentView _msa, boolean subgaps,\r
338           boolean presorder, Alignment seqset)\r
339   {\r
340     this(server, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder);\r
341     OutputHeader = wsInfo.getProgressText();\r
342     alTitle = title;\r
343     dataset = seqset;\r
344 \r
345     SequenceI[][] conmsa = _msa.getVisibleContigs('-');\r
346     if (conmsa != null)\r
347     {\r
348       int njobs = conmsa.length;\r
349       jobs = new MsaWSJob[njobs];\r
350       for (int j = 0; j < njobs; j++)\r
351       {\r
352         if (j != 0)\r
353         {\r
354           jobs[j] = new MsaWSJob(wsinfo.addJobPane(), conmsa[j]);\r
355         }\r
356         else\r
357         {\r
358           jobs[j] = new MsaWSJob(0, conmsa[j]);\r
359         }\r
360         if (njobs > 0)\r
361         {\r
362           wsinfo\r
363                   .setProgressName("region " + jobs[j].jobnum,\r
364                           jobs[j].jobnum);\r
365         }\r
366         wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);\r
367       }\r
368     }\r
369   }\r
370 \r
371   public boolean isCancellable()\r
372   {\r
373     return true;\r
374   }\r
375 \r
376   public void cancelJob()\r
377   {\r
378     if (!jobComplete && jobs != null)\r
379     {\r
380       boolean cancelled = true;\r
381       for (int job = 0; job < jobs.length; job++)\r
382       {\r
383         if (jobs[job].submitted && !jobs[job].subjobComplete)\r
384         {\r
385           String cancelledMessage = "";\r
386           try\r
387           {\r
388             vamsas.objects.simple.WsJobId cancelledJob = server\r
389                     .cancel(jobs[job].jobId);\r
390             if (cancelledJob.getStatus() == 2)\r
391             {\r
392               // CANCELLED_JOB\r
393               cancelledMessage = "Job cancelled.";\r
394               ((MsaWSJob) jobs[job]).cancel();\r
395               wsInfo.setStatus(jobs[job].jobnum,\r
396                       WebserviceInfo.STATE_CANCELLED_OK);\r
397             }\r
398             else if (cancelledJob.getStatus() == 3)\r
399             {\r
400               // VALID UNSTOPPABLE JOB\r
401               cancelledMessage += "Server cannot cancel this job. just close the window.\n";\r
402               cancelled = false;\r
403               // wsInfo.setStatus(jobs[job].jobnum,\r
404               // WebserviceInfo.STATE_RUNNING);\r
405             }\r
406 \r
407             if (cancelledJob.getJobId() != null)\r
408             {\r
409               cancelledMessage += ("[" + cancelledJob.getJobId() + "]");\r
410             }\r
411 \r
412             cancelledMessage += "\n";\r
413           } catch (Exception exc)\r
414           {\r
415             cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"\r
416                     + exc + "\n");\r
417             Cache.log.warn(\r
418                     "Exception whilst cancelling " + jobs[job].jobId, exc);\r
419           }\r
420           wsInfo.setProgressText(jobs[job].jobnum, OutputHeader\r
421                   + cancelledMessage + "\n");\r
422         }\r
423       }\r
424       if (cancelled)\r
425       {\r
426         wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);\r
427         jobComplete = true;\r
428       }\r
429       this.interrupt(); // kick thread to update job states.\r
430     }\r
431     else\r
432     {\r
433       if (!jobComplete)\r
434       {\r
435         wsInfo\r
436                 .setProgressText(OutputHeader\r
437                         + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");\r
438       }\r
439     }\r
440   }\r
441 \r
442   void pollJob(WSJob job) throws Exception\r
443   {\r
444     ((MsaWSJob) job).result = server.getResult(((MsaWSJob) job).jobId);\r
445   }\r
446 \r
447   void StartJob(WSJob job)\r
448   {\r
449     if (!(job instanceof MsaWSJob))\r
450     {\r
451       throw new Error("StartJob(MsaWSJob) called on a WSJobInstance "\r
452               + job.getClass());\r
453     }\r
454     MsaWSJob j = (MsaWSJob) job;\r
455     if (j.submitted)\r
456     {\r
457       if (Cache.log.isDebugEnabled())\r
458       {\r
459         Cache.log.debug("Tried to submit an already submitted job "\r
460                 + j.jobId);\r
461       }\r
462       return;\r
463     }\r
464     if (j.seqs.getSeqs() == null)\r
465     {\r
466       // special case - selection consisted entirely of empty sequences...\r
467       j.submitted = true;\r
468       j.result = new MsaResult();\r
469       j.result.setFinished(true);\r
470       j.result.setStatus("Empty Alignment Job");\r
471       ((MsaResult) j.result).setMsa(null);\r
472     }\r
473     try\r
474     {\r
475       vamsas.objects.simple.WsJobId jobsubmit = server.align(j.seqs);\r
476 \r
477       if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))\r
478       {\r
479         j.jobId = jobsubmit.getJobId();\r
480         j.submitted = true;\r
481         j.subjobComplete = false;\r
482         // System.out.println(WsURL + " Job Id '" + jobId + "'");\r
483       }\r
484       else\r
485       {\r
486         if (jobsubmit == null)\r
487         {\r
488           throw new Exception(\r
489                   "Server at "\r
490                           + WsUrl\r
491                           + " returned null object, it probably cannot be contacted. Try again later ?");\r
492         }\r
493 \r
494         throw new Exception(jobsubmit.getJobId());\r
495       }\r
496     } catch (Exception e)\r
497     {\r
498       // TODO: JBPNote catch timeout or other fault types explicitly\r
499       // For unexpected errors\r
500       System.err\r
501               .println(WebServiceName\r
502                       + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"\r
503                       + "When contacting Server:" + WsUrl + "\n"\r
504                       + e.toString() + "\n");\r
505       j.allowedServerExceptions = 0;\r
506       wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);\r
507       wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);\r
508       wsInfo\r
509               .appendProgressText(\r
510                       j.jobnum,\r
511                       "Failed to submit sequences for alignment.\n"\r
512                               + "It is most likely that there is a problem with the server.\n"\r
513                               + "Just close the window\n");\r
514 \r
515       // e.printStackTrace(); // TODO: JBPNote DEBUG\r
516     }\r
517   }\r
518 \r
519   private jalview.datamodel.Sequence[] getVamsasAlignment(\r
520           vamsas.objects.simple.Alignment valign)\r
521   {\r
522     // TODO: refactor to helper class for vamsas.objects.simple objects\r
523     vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();\r
524     jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];\r
525 \r
526     for (int i = 0, j = seqs.length; i < j; i++)\r
527     {\r
528       msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(), seqs[i]\r
529               .getSeq());\r
530     }\r
531 \r
532     return msa;\r
533   }\r
534 \r
535   void parseResult()\r
536   {\r
537     int results = 0; // number of result sets received\r
538     JobStateSummary finalState = new JobStateSummary();\r
539     try\r
540     {\r
541       for (int j = 0; j < jobs.length; j++)\r
542       {\r
543         finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);\r
544         if (jobs[j].submitted && jobs[j].subjobComplete\r
545                 && jobs[j].hasResults())\r
546         {\r
547           results++;\r
548           vamsas.objects.simple.Alignment valign = ((MsaResult) jobs[j].result)\r
549                   .getMsa();\r
550           if (valign != null)\r
551           {\r
552             wsInfo.appendProgressText(jobs[j].jobnum,\r
553                     "\nAlignment Object Method Notes\n");\r
554             String[] lines = valign.getMethod();\r
555             for (int line = 0; line < lines.length; line++)\r
556             {\r
557               wsInfo.appendProgressText(jobs[j].jobnum, lines[line] + "\n");\r
558             }\r
559             // JBPNote The returned files from a webservice could be\r
560             // hidden behind icons in the monitor window that,\r
561             // when clicked, pop up their corresponding data\r
562           }\r
563         }\r
564       }\r
565     } catch (Exception ex)\r
566     {\r
567 \r
568       Cache.log.error("Unexpected exception when processing results for "\r
569               + alTitle, ex);\r
570       wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
571     }\r
572     if (results > 0)\r
573     {\r
574       wsInfo.showResultsNewFrame\r
575               .addActionListener(new java.awt.event.ActionListener()\r
576               {\r
577                 public void actionPerformed(java.awt.event.ActionEvent evt)\r
578                 {\r
579                   displayResults(true);\r
580                 }\r
581               });\r
582       wsInfo.mergeResults\r
583               .addActionListener(new java.awt.event.ActionListener()\r
584               {\r
585                 public void actionPerformed(java.awt.event.ActionEvent evt)\r
586                 {\r
587                   displayResults(false);\r
588                 }\r
589               });\r
590       wsInfo.setResultsReady();\r
591     }\r
592     else\r
593     {\r
594       wsInfo.setFinishedNoResults();\r
595     }\r
596   }\r
597 \r
598   void displayResults(boolean newFrame)\r
599   {\r
600     // view input or result data for each block\r
601     Vector alorders = new Vector();\r
602     SequenceI[][] results = new SequenceI[jobs.length][];\r
603     AlignmentOrder[] orders = new AlignmentOrder[jobs.length];\r
604     for (int j = 0; j < jobs.length; j++)\r
605     {\r
606       if (jobs[j].hasResults())\r
607       {\r
608         Object[] res = ((MsaWSJob) jobs[j]).getAlignment();\r
609         alorders.add(res[1]);\r
610         results[j] = (SequenceI[]) res[0];\r
611         orders[j] = (AlignmentOrder) res[1];\r
612 \r
613         // SequenceI[] alignment = input.getUpdated\r
614       }\r
615       else\r
616       {\r
617         results[j] = null;\r
618       }\r
619     }\r
620     Object[] newview = input.getUpdatedView(results, orders, getGapChar());\r
621     // trash references to original result data\r
622     for (int j = 0; j < jobs.length; j++)\r
623     {\r
624       results[j] = null;\r
625       orders[j] = null;\r
626     }\r
627     SequenceI[] alignment = (SequenceI[]) newview[0];\r
628     ColumnSelection columnselection = (ColumnSelection) newview[1];\r
629     Alignment al = new Alignment(alignment);\r
630     // TODO: add 'provenance' property to alignment from the method notes\r
631     // accompanying each subjob\r
632     if (dataset != null)\r
633     {\r
634       al.setDataset(dataset);\r
635     }\r
636 \r
637     propagateDatasetMappings(al);\r
638     // JBNote- TODO: warn user if a block is input rather than aligned data ?\r
639 \r
640     if (newFrame)\r
641     {\r
642       AlignFrame af = new AlignFrame(al, columnselection,\r
643               AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);\r
644 \r
645       // initialise with same renderer settings as in parent alignframe.\r
646       af.getFeatureRenderer().transferSettings(this.featureSettings);\r
647       // update orders\r
648       if (alorders.size() > 0)\r
649       {\r
650         if (alorders.size() == 1)\r
651         {\r
652           af.addSortByOrderMenuItem(WebServiceName + " Ordering",\r
653                   (AlignmentOrder) alorders.get(0));\r
654         }\r
655         else\r
656         {\r
657           // construct a non-redundant ordering set\r
658           Vector names = new Vector();\r
659           for (int i = 0, l = alorders.size(); i < l; i++)\r
660           {\r
661             String orderName = new String(" Region " + i);\r
662             int j = i + 1;\r
663 \r
664             while (j < l)\r
665             {\r
666               if (((AlignmentOrder) alorders.get(i))\r
667                       .equals(((AlignmentOrder) alorders.get(j))))\r
668               {\r
669                 alorders.remove(j);\r
670                 l--;\r
671                 orderName += "," + j;\r
672               }\r
673               else\r
674               {\r
675                 j++;\r
676               }\r
677             }\r
678 \r
679             if (i == 0 && j == 1)\r
680             {\r
681               names.add(new String(""));\r
682             }\r
683             else\r
684             {\r
685               names.add(orderName);\r
686             }\r
687           }\r
688           for (int i = 0, l = alorders.size(); i < l; i++)\r
689           {\r
690             af.addSortByOrderMenuItem(WebServiceName\r
691                     + ((String) names.get(i)) + " Ordering",\r
692                     (AlignmentOrder) alorders.get(i));\r
693           }\r
694         }\r
695       }\r
696 \r
697       Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,\r
698               AlignFrame.DEFAULT_HEIGHT);\r
699 \r
700     }\r
701     else\r
702     {\r
703       System.out.println("MERGE WITH OLD FRAME");\r
704       // TODO: modify alignment in original frame, replacing old for new\r
705       // alignment using the commands.EditCommand model to ensure the update can\r
706       // be undone\r
707     }\r
708   }\r
709 \r
710   public boolean canMergeResults()\r
711   {\r
712     return false;\r
713   }\r
714 }\r