2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
21 package jalview.ws.jws2;
23 import jalview.analysis.AlignSeq;
24 import jalview.analysis.AlignmentSorter;
25 import jalview.analysis.SeqsetUtils;
26 import jalview.bin.Cache;
27 import jalview.datamodel.Alignment;
28 import jalview.datamodel.AlignmentI;
29 import jalview.datamodel.AlignmentOrder;
30 import jalview.datamodel.AlignmentView;
31 import jalview.datamodel.ColumnSelection;
32 import jalview.datamodel.Sequence;
33 import jalview.datamodel.SequenceI;
34 import jalview.gui.AlignFrame;
35 import jalview.gui.Desktop;
36 import jalview.gui.SplitFrame;
37 import jalview.gui.WebserviceInfo;
38 import jalview.util.Comparison;
39 import jalview.util.MessageManager;
40 import jalview.ws.AWsJob;
41 import jalview.ws.JobStateSummary;
42 import jalview.ws.WSClientI;
43 import jalview.ws.jws2.dm.JabaWsParamSet;
44 import jalview.ws.params.WsParamSetI;
46 import java.util.ArrayList;
47 import java.util.Hashtable;
48 import java.util.List;
50 import java.util.Vector;
52 import javax.swing.JInternalFrame;
54 import compbio.data.msa.MsaWS;
55 import compbio.metadata.Argument;
56 import compbio.metadata.ChunkHolder;
57 import compbio.metadata.JobStatus;
58 import compbio.metadata.Preset;
60 class MsaWSThread extends AWS2Thread implements WSClientI
62 boolean submitGaps = false; // pass sequences including gaps to alignment
66 boolean preserveOrder = true; // and always store and recover sequence
70 class MsaWSJob extends JWs2Job
74 WsParamSetI preset = null;
76 List<Argument> arguments = null;
81 ArrayList<compbio.data.sequence.FastaSequence> seqs = new ArrayList<compbio.data.sequence.FastaSequence>();
86 compbio.data.sequence.Alignment alignment;
88 // set if the job didn't get run - then the input is simply returned to the
90 private boolean returnInput = false;
100 public MsaWSJob(int jobNum, SequenceI[] inSeqs)
102 this.jobnum = jobNum;
103 if (!prepareInput(inSeqs, 2))
106 subjobComplete = true;
112 Hashtable<String, Map> SeqNames = new Hashtable();
114 Vector<String[]> emptySeqs = new Vector();
117 * prepare input sequences for MsaWS service
120 * jalview sequences to be prepared
122 * minimum number of residues required for this MsaWS service
123 * @return true if seqs contains sequences to be submitted to service.
125 // TODO: return compbio.seqs list or nothing to indicate validity.
126 private boolean prepareInput(SequenceI[] seqs, int minlen)
131 throw new Error(MessageManager.getString("error.implementation_error_minlen_must_be_greater_zero"));
133 for (int i = 0; i < seqs.length; i++)
135 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
140 boolean valid = nseqs > 1; // need at least two seqs
141 compbio.data.sequence.FastaSequence seq;
142 for (int i = 0, n = 0; i < seqs.length; i++)
145 String newname = SeqsetUtils.unique_name(i); // same
149 SeqNames.put(newname, SeqsetUtils.SeqCharacterHash(seqs[i]));
150 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
152 // make new input sequence with or without gaps
153 seq = new compbio.data.sequence.FastaSequence(newname,
154 (submitGaps) ? seqs[i].getSequenceAsString()
155 : AlignSeq.extractGaps(
157 seqs[i].getSequenceAsString()));
163 if (seqs[i].getEnd() >= seqs[i].getStart())
165 empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq
166 .extractGaps(Comparison.GapChars,
167 seqs[i].getSequenceAsString());
169 emptySeqs.add(new String[]
178 * @return true if getAlignment will return a valid alignment result.
180 public boolean hasResults()
184 && (alignment != null || (emptySeqs != null && emptySeqs
194 * get the alignment including any empty sequences in the original order
195 * with original ids. Caller must access the alignment.getMetadata() object
196 * to annotate the final result passsed to the user.
198 * @return { SequenceI[], AlignmentOrder }
200 public Object[] getAlignment()
202 // is this a generic subjob or a Jws2 specific Object[] return signature
205 SequenceI[] alseqs = null;
206 char alseq_gapchar = '-';
208 if (alignment.getSequences().size() > 0)
210 alseqs = new SequenceI[alignment.getSequences().size()];
211 for (compbio.data.sequence.FastaSequence seq : alignment
214 alseqs[alseq_l++] = new Sequence(seq.getId(), seq.getSequence());
216 alseq_gapchar = alignment.getMetadata().getGapchar();
219 // add in the empty seqs.
220 if (emptySeqs.size() > 0)
222 SequenceI[] t_alseqs = new SequenceI[alseq_l + emptySeqs.size()];
227 for (i = 0, w = alseqs[0].getLength(); i < alseq_l; i++)
229 if (w < alseqs[i].getLength())
231 w = alseqs[i].getLength();
233 t_alseqs[i] = alseqs[i];
237 // check that aligned width is at least as wide as emptySeqs width.
239 for (i = 0, w = emptySeqs.size(); i < w; i++)
241 String[] es = emptySeqs.get(i);
242 if (es != null && es[1] != null)
244 int sw = es[1].length();
251 // make a gapped string.
252 StringBuffer insbuff = new StringBuffer(w);
253 for (i = 0; i < nw; i++)
255 insbuff.append(alseq_gapchar);
259 for (i = 0; i < alseq_l; i++)
261 int sw = t_alseqs[i].getLength();
265 alseqs[i].setSequence(t_alseqs[i].getSequenceAsString()
266 + insbuff.substring(0, sw - nw));
270 for (i = 0, w = emptySeqs.size(); i < w; i++)
272 String[] es = emptySeqs.get(i);
275 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(es[0],
276 insbuff.toString(), 1, 0);
280 if (es[1].length() < nw)
282 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(
284 es[1] + insbuff.substring(0, nw - es[1].length()),
285 1, 1 + es[1].length());
289 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(
296 AlignmentOrder msaorder = new AlignmentOrder(alseqs);
297 // always recover the order - makes parseResult()'s life easier.
298 AlignmentSorter.recoverOrder(alseqs);
299 // account for any missing sequences
300 SeqsetUtils.deuniquify(SeqNames, alseqs);
302 { alseqs, msaorder };
308 * mark subjob as cancelled and set result object appropriatly
313 subjobComplete = true;
319 * @return boolean true if job can be submitted.
321 public boolean hasValidInput()
323 // TODO: get attributes for this MsaWS instance to check if it can do two
324 // sequence alignment.
325 if (seqs != null && seqs.size() >= 2) // two or more sequences is valid ?
332 StringBuffer jobProgress = new StringBuffer();
334 public void setStatus(String string)
336 jobProgress.setLength(0);
337 jobProgress.append(string);
341 public String getStatus()
343 return jobProgress.toString();
347 public boolean hasStatus()
349 return jobProgress != null;
353 * @return the lastChunk
355 public long getLastChunk()
362 * the lastChunk to set
364 public void setLastChunk(long lastChunk)
366 this.lastChunk = lastChunk;
369 String alignmentProgram = null;
371 public String getAlignmentProgram()
373 return alignmentProgram;
376 public boolean hasArguments()
378 return (arguments != null && arguments.size() > 0)
379 || (preset != null && preset instanceof JabaWsParamSet);
382 public List<Argument> getJabaArguments()
384 List<Argument> newargs = new ArrayList<Argument>();
385 if (preset != null && preset instanceof JabaWsParamSet)
387 newargs.addAll(((JabaWsParamSet) preset).getjabaArguments());
389 if (arguments != null && arguments.size() > 0)
391 newargs.addAll(arguments);
397 * add a progess header to status string containing presets/args used
399 public void addInitialStatus()
403 jobProgress.append("Using "
404 + (preset instanceof JabaPreset ? "Server" : "User")
405 + "Preset: " + preset.getName());
406 if (preset instanceof JabaWsParamSet)
408 for (Argument opt : ((JabaWsParamSet) preset).getjabaArguments())
410 jobProgress.append(opt.getName() + " " + opt.getDefaultValue()
415 if (arguments != null && arguments.size() > 0)
417 jobProgress.append("With custom parameters : \n");
418 // merge arguments with preset's own arguments.
419 for (Argument opt : arguments)
421 jobProgress.append(opt.getName() + " " + opt.getDefaultValue()
425 jobProgress.append("\nJob Output:\n");
428 public boolean isPresetJob()
430 return preset != null && preset instanceof JabaPreset;
433 public Preset getServerPreset()
435 return (isPresetJob()) ? ((JabaPreset) preset).p : null;
439 String alTitle; // name which will be used to form new alignment window.
441 Alignment dataset; // dataset to which the new alignment will be
445 @SuppressWarnings("unchecked")
449 * set basic options for this (group) of Msa jobs
456 private MsaWSThread(MsaWS server, String wsUrl, WebserviceInfo wsinfo,
457 AlignFrame alFrame, AlignmentView alview,
458 String wsname, boolean subgaps, boolean presorder)
460 super(alFrame, wsinfo, alview, wsname, wsUrl);
461 this.server = server;
462 this.submitGaps = subgaps;
463 this.preserveOrder = presorder;
467 * create one or more Msa jobs to align visible seuqences in _msa
480 MsaWSThread(MsaWS server2, WsParamSetI preset, List<Argument> paramset,
481 String wsUrl, WebserviceInfo wsinfo,
483 String wsname, String title,
484 AlignmentView _msa, boolean subgaps, boolean presorder,
487 this(server2, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder);
488 OutputHeader = wsInfo.getProgressText();
492 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
495 int nvalid = 0, njobs = conmsa.length;
496 jobs = new MsaWSJob[njobs];
497 for (int j = 0; j < njobs; j++)
501 jobs[j] = new MsaWSJob(wsinfo.addJobPane(), conmsa[j]);
505 jobs[j] = new MsaWSJob(0, conmsa[j]);
507 if (((MsaWSJob) jobs[j]).hasValidInput())
511 ((MsaWSJob) jobs[j]).preset = preset;
512 ((MsaWSJob) jobs[j]).arguments = paramset;
513 ((MsaWSJob) jobs[j]).alignmentProgram = wsname;
516 wsinfo.setProgressName("region " + jobs[j].getJobnum(),
517 jobs[j].getJobnum());
519 wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
521 validInput = nvalid > 0;
525 boolean validInput = false;
529 * @return true if the thread will perform a calculation
531 public boolean hasValidInput()
535 public boolean isCancellable()
540 public void cancelJob()
542 if (!jobComplete && jobs != null)
544 boolean cancelled = true;
545 for (int job = 0; job < jobs.length; job++)
547 if (jobs[job].isSubmitted() && !jobs[job].isSubjobComplete())
549 String cancelledMessage = "";
552 boolean cancelledJob = server.cancelJob(jobs[job].getJobId());
553 if (true) // cancelledJob || true)
556 // if the Jaba server indicates the job can't be cancelled, its
557 // because its running on the server's local execution engine
558 // so we just close the window anyway.
559 cancelledMessage = "Job cancelled.";
560 ((MsaWSJob) jobs[job]).cancel(); // TODO: refactor to avoid this
562 wsInfo.setStatus(jobs[job].getJobnum(),
563 WebserviceInfo.STATE_CANCELLED_OK);
567 // VALID UNSTOPPABLE JOB
568 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
570 // wsInfo.setStatus(jobs[job].jobnum,
571 // WebserviceInfo.STATE_RUNNING);
573 } catch (Exception exc)
575 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
578 "Exception whilst cancelling " + jobs[job].getJobId(),
581 wsInfo.setProgressText(jobs[job].getJobnum(), OutputHeader
582 + cancelledMessage + "\n");
586 // if we hadn't submitted then just mark the job as cancelled.
587 jobs[job].setSubjobComplete(true);
588 wsInfo.setStatus(jobs[job].getJobnum(),
589 WebserviceInfo.STATE_CANCELLED_OK);
595 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
598 this.interrupt(); // kick thread to update job states.
604 wsInfo.setProgressText(OutputHeader
605 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
610 public void pollJob(AWsJob job) throws Exception
612 // TODO: investigate if we still need to cast here in J1.6
613 MsaWSJob j = ((MsaWSJob) job);
614 // this is standard code, but since the interface doesn't comprise of a
615 // basic one that implements (getJobStatus, pullExecStatistics) we have to
616 // repeat the code for all jw2s services.
617 j.setjobStatus(server.getJobStatus(job.getJobId()));
618 updateJobProgress(j);
624 * @return true if more job progress data was available
627 protected boolean updateJobProgress(MsaWSJob j) throws Exception
629 StringBuffer response = j.jobProgress;
630 long lastchunk = j.getLastChunk();
631 boolean changed = false;
634 j.setLastChunk(lastchunk);
635 ChunkHolder chunk = server
636 .pullExecStatistics(j.getJobId(), lastchunk);
639 changed |= chunk.getChunk().length() > 0;
640 response.append(chunk.getChunk());
641 lastchunk = chunk.getNextPosition();
645 } catch (InterruptedException x)
651 } while (lastchunk >= 0 && j.getLastChunk() != lastchunk);
655 public void StartJob(AWsJob job)
657 Exception lex = null;
658 // boiler plate template
659 if (!(job instanceof MsaWSJob))
661 throw new Error(MessageManager.formatMessage("error.implementation_error_msawbjob_called", new String[]{job.getClass().toString()}));
663 MsaWSJob j = (MsaWSJob) job;
666 if (Cache.log.isDebugEnabled())
668 Cache.log.debug("Tried to submit an already submitted job "
675 if (j.seqs == null || j.seqs.size() == 0)
677 // special case - selection consisted entirely of empty sequences...
678 j.setjobStatus(JobStatus.FINISHED);
679 j.setStatus(MessageManager.getString("label.empty_alignment_job"));
683 j.addInitialStatus(); // list the presets/parameters used for the job in
687 j.setJobId(server.presetAlign(j.seqs, j.getServerPreset()));
689 else if (j.hasArguments())
691 j.setJobId(server.customAlign(j.seqs, j.getJabaArguments()));
695 j.setJobId(server.align(j.seqs));
698 if (j.getJobId() != null)
700 j.setSubmitted(true);
701 j.setSubjobComplete(false);
702 // System.out.println(WsURL + " Job Id '" + jobId + "'");
707 throw new Exception(MessageManager.formatMessage("exception.web_service_returned_null_try_later", new String[]{WsUrl}));
709 } catch (compbio.metadata.UnsupportedRuntimeException _lex)
712 wsInfo.appendProgressText(MessageManager.formatMessage("info.job_couldnt_be_run_server_doesnt_support_program", new String[]{_lex.getMessage()}));
713 wsInfo.warnUser(_lex.getMessage(), MessageManager.getString("warn.service_not_supported"));
714 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
715 wsInfo.setStatus(j.getJobnum(),
716 WebserviceInfo.STATE_STOPPED_SERVERERROR);
717 } catch (compbio.metadata.LimitExceededException _lex)
720 wsInfo.appendProgressText(MessageManager.formatMessage("info.job_couldnt_be_run_exceeded_hard_limit", new String[]{_lex.getMessage()}));
721 wsInfo.warnUser(_lex.getMessage(), MessageManager.getString("warn.input_is_too_big"));
722 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
723 wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR);
724 } catch (compbio.metadata.WrongParameterException _lex)
727 wsInfo.warnUser(_lex.getMessage(), MessageManager.getString("warn.invalid_job_param_set"));
728 wsInfo.appendProgressText(MessageManager.formatMessage("info.job_couldnt_be_run_incorrect_param_setting", new String[]{_lex.getMessage()}));
729 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
730 wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR);
733 // For unexpected errors
735 .println(WebServiceName
736 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
737 + "When contacting Server:" + WsUrl + "\n");
738 e.printStackTrace(System.err);
739 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
740 wsInfo.setStatus(j.getJobnum(),
741 WebserviceInfo.STATE_STOPPED_SERVERERROR);
742 } catch (Exception e)
744 // For unexpected errors
746 .println(WebServiceName
747 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
748 + "When contacting Server:" + WsUrl + "\n");
749 e.printStackTrace(System.err);
750 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
751 wsInfo.setStatus(j.getJobnum(),
752 WebserviceInfo.STATE_STOPPED_SERVERERROR);
755 if (!j.isSubmitted())
757 // Boilerplate code here
758 // TODO: JBPNote catch timeout or other fault types explicitly
760 j.setAllowedServerExceptions(0);
761 wsInfo.appendProgressText(j.getJobnum(),
762 MessageManager.getString("info.failed_to_submit_sequences_for_alignment"));
767 public void parseResult()
769 long progbar = System.currentTimeMillis();
770 wsInfo.setProgressBar(MessageManager.getString("status.collecting_job_results"), progbar);
771 int results = 0; // number of result sets received
772 JobStateSummary finalState = new JobStateSummary();
775 for (int j = 0; j < jobs.length; j++)
777 MsaWSJob msjob = ((MsaWSJob) jobs[j]);
778 if (jobs[j].isFinished() && msjob.alignment == null)
780 int nunchanged = 3, nexcept = 3;
781 boolean jpchanged = false, jpex = false;
786 jpchanged = updateJobProgress(msjob);
792 } catch (Exception e)
796 .warn("Exception when retrieving remaining Job progress data for job "
797 + msjob.getJobId() + " on server " + WsUrl);
801 // set flag remember that we've had an exception.
809 Thread.sleep(jpex ? 2400 : 1200); // wait a bit longer if we
810 // experienced an exception.
811 } catch (Exception ex)
817 } while (nunchanged > 0 && nexcept > 0);
819 if (Cache.log.isDebugEnabled())
821 System.out.println("Job Execution file for job: "
822 + msjob.getJobId() + " on server " + WsUrl);
823 System.out.println(msjob.getStatus());
824 System.out.println("*** End of status");
829 msjob.alignment = server.getResult(msjob.getJobId());
830 } catch (compbio.metadata.ResultNotAvailableException e)
832 // job has failed for some reason - probably due to invalid
835 .debug("Results not available for finished job - marking as broken job.",
838 .append("\nResult not available. Probably due to invalid input or parameter settings. Server error message below:\n\n"
839 + e.getLocalizedMessage());
840 msjob.setjobStatus(JobStatus.FAILED);
841 } catch (Exception e)
843 Cache.log.error("Couldn't get Alignment for job.", e);
844 // TODO: Increment count and retry ?
845 msjob.setjobStatus(JobStatus.UNDEFINED);
848 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
849 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
850 && jobs[j].hasResults())
853 compbio.data.sequence.Alignment alignment = ((MsaWSJob) jobs[j]).alignment;
854 if (alignment != null)
856 // server.close(jobs[j].getJobnum());
857 // wsInfo.appendProgressText(jobs[j].getJobnum(),
858 // "\nAlignment Object Method Notes\n");
859 // wsInfo.appendProgressText(jobs[j].getJobnum(),
860 // "Calculated with "+alignment.getMetadata().getProgram().toString());
861 // JBPNote The returned files from a webservice could be
862 // hidden behind icons in the monitor window that,
863 // when clicked, pop up their corresponding data
867 } catch (Exception ex)
870 Cache.log.error("Unexpected exception when processing results for "
872 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
876 wsInfo.showResultsNewFrame
877 .addActionListener(new java.awt.event.ActionListener()
879 public void actionPerformed(java.awt.event.ActionEvent evt)
881 displayResults(true);
885 .addActionListener(new java.awt.event.ActionListener()
887 public void actionPerformed(java.awt.event.ActionEvent evt)
889 displayResults(false);
892 wsInfo.setResultsReady();
896 wsInfo.setFinishedNoResults();
898 updateGlobalStatus(finalState);
899 wsInfo.setProgressBar(null, progbar);
903 * Display alignment results in a new frame (or - not currently supported -
904 * added to an existing alignment).
908 void displayResults(boolean newFrame)
910 // view input or result data for each block
911 List<AlignmentOrder> alorders = new ArrayList<AlignmentOrder>();
912 SequenceI[][] results = new SequenceI[jobs.length][];
913 AlignmentOrder[] orders = new AlignmentOrder[jobs.length];
914 String lastProgram = null;
916 for (int j = 0; j < jobs.length; j++)
918 if (jobs[j].hasResults())
920 msjob = (MsaWSJob) jobs[j];
921 Object[] res = msjob.getAlignment();
922 lastProgram = msjob.getAlignmentProgram();
923 alorders.add((AlignmentOrder) res[1]);
924 results[j] = (SequenceI[]) res[0];
925 orders[j] = (AlignmentOrder) res[1];
927 // SequenceI[] alignment = input.getUpdated
934 Object[] newview = input.getUpdatedView(results, orders, getGapChar());
935 // trash references to original result data
936 for (int j = 0; j < jobs.length; j++)
941 SequenceI[] alignment = (SequenceI[]) newview[0];
942 ColumnSelection columnselection = (ColumnSelection) newview[1];
943 Alignment al = new Alignment(alignment);
944 // TODO: add 'provenance' property to alignment from the method notes
945 if (lastProgram != null)
947 al.setProperty("Alignment Program", lastProgram);
949 // accompanying each subjob
952 al.setDataset(dataset);
955 propagateDatasetMappings(al);
956 // JBNote- TODO: warn user if a block is input rather than aligned data ?
960 displayInNewFrame(al, alorders, columnselection);
965 // TODO 2.9.x feature
966 System.out.println("MERGE WITH OLD FRAME");
967 // TODO: modify alignment in original frame, replacing old for new
968 // alignment using the commands.EditCommand model to ensure the update can
974 * Display the alignment result in a new frame.
978 * @param columnselection
980 protected void displayInNewFrame(AlignmentI al,
981 List<AlignmentOrder> alorders, ColumnSelection columnselection)
983 AlignFrame af = new AlignFrame(al, columnselection,
984 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
986 // initialise with same renderer settings as in parent alignframe.
987 af.getFeatureRenderer().transferSettings(this.featureSettings);
989 if (alorders.size() > 0)
991 addSortByMenuItems(af, alorders);
994 // TODO: refactor retrieve and show as new splitFrame as Desktop method
997 * If alignment was requested from one half of a SplitFrame, show in a
998 * SplitFrame with the other pane similarly aligned.
1000 AlignFrame requestedBy = getRequestingAlignFrame();
1001 if (requestedBy != null && requestedBy.getSplitViewContainer() != null
1002 && requestedBy.getSplitViewContainer().getComplement(requestedBy)!=null)
1004 AlignmentI complement = requestedBy.getSplitViewContainer()
1005 .getComplement(requestedBy);
1006 String complementTitle = requestedBy.getSplitViewContainer()
1007 .getComplementTitle(requestedBy);
1008 // becomes null if the alignment window was closed before the alignment
1010 AlignmentI copyComplement = new Alignment(complement);
1011 copyComplement.alignAs(al);
1012 if (copyComplement.getHeight() > 0)
1014 af.setTitle(alTitle);
1015 AlignFrame af2 = new AlignFrame(copyComplement,
1016 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
1017 af2.setTitle(complementTitle);
1018 String linkedTitle = MessageManager
1019 .getString("label.linked_view_title");
1020 JInternalFrame splitFrame = new SplitFrame(al.isNucleotide() ? af
1021 : af2, al.isNucleotide() ? af2 : af);
1022 Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1);
1028 * Not from SplitFrame, or failed to created a complementary alignment
1030 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
1031 AlignFrame.DEFAULT_HEIGHT);
1035 * Add sort order options to the AlignFrame menus.
1040 protected void addSortByMenuItems(AlignFrame af,
1041 List<AlignmentOrder> alorders)
1044 if (alorders.size() == 1)
1046 af.addSortByOrderMenuItem(WebServiceName + " Ordering",
1051 // construct a non-redundant ordering set
1052 List<String> names = new ArrayList<String>();
1053 for (int i = 0, l = alorders.size(); i < l; i++)
1055 String orderName = " Region " + i;
1060 if (alorders.get(i).equals(alorders.get(j)))
1064 orderName += "," + j;
1072 if (i == 0 && j == 1)
1078 names.add(orderName);
1081 for (int i = 0, l = alorders.size(); i < l; i++)
1083 af.addSortByOrderMenuItem(WebServiceName + (names.get(i))
1084 + " Ordering", alorders.get(i));
1089 public boolean canMergeResults()