2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3 * Copyright (C) 2014 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.bin.Cache;
25 import jalview.datamodel.Alignment;
26 import jalview.datamodel.AlignmentI;
27 import jalview.datamodel.AlignmentOrder;
28 import jalview.datamodel.AlignmentView;
29 import jalview.datamodel.ColumnSelection;
30 import jalview.datamodel.Sequence;
31 import jalview.datamodel.SequenceI;
32 import jalview.gui.AlignFrame;
33 import jalview.gui.Desktop;
34 import jalview.gui.SplitFrame;
35 import jalview.gui.WebserviceInfo;
36 import jalview.util.MessageManager;
37 import jalview.ws.AWsJob;
38 import jalview.ws.JobStateSummary;
39 import jalview.ws.WSClientI;
40 import jalview.ws.jws2.dm.JabaWsParamSet;
41 import jalview.ws.params.WsParamSetI;
43 import java.util.ArrayList;
44 import java.util.Hashtable;
45 import java.util.List;
47 import java.util.Vector;
49 import javax.swing.JInternalFrame;
51 import compbio.data.msa.MsaWS;
52 import compbio.metadata.Argument;
53 import compbio.metadata.ChunkHolder;
54 import compbio.metadata.JobStatus;
55 import compbio.metadata.Preset;
57 class MsaWSThread extends AWS2Thread implements WSClientI
59 boolean submitGaps = false; // pass sequences including gaps to alignment
63 boolean preserveOrder = true; // and always store and recover sequence
67 class MsaWSJob extends JWs2Job
71 WsParamSetI preset = null;
73 List<Argument> arguments = null;
78 ArrayList<compbio.data.sequence.FastaSequence> seqs = new ArrayList<compbio.data.sequence.FastaSequence>();
83 compbio.data.sequence.Alignment alignment;
85 // set if the job didn't get run - then the input is simply returned to the
87 private boolean returnInput = false;
97 public MsaWSJob(int jobNum, SequenceI[] inSeqs)
100 if (!prepareInput(inSeqs, 2))
103 subjobComplete = true;
109 Hashtable<String, Map> SeqNames = new Hashtable();
111 Vector<String[]> emptySeqs = new Vector();
114 * prepare input sequences for MsaWS service
117 * jalview sequences to be prepared
119 * minimum number of residues required for this MsaWS service
120 * @return true if seqs contains sequences to be submitted to service.
122 // TODO: return compbio.seqs list or nothing to indicate validity.
123 private boolean prepareInput(SequenceI[] seqs, int minlen)
128 throw new Error(MessageManager.getString("error.implementation_error_minlen_must_be_greater_zero"));
130 for (int i = 0; i < seqs.length; i++)
132 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
137 boolean valid = nseqs > 1; // need at least two seqs
138 compbio.data.sequence.FastaSequence seq;
139 for (int i = 0, n = 0; i < seqs.length; i++)
142 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
146 SeqNames.put(newname,
147 jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i]));
148 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
150 // make new input sequence with or without gaps
151 seq = new compbio.data.sequence.FastaSequence(newname,
152 (submitGaps) ? seqs[i].getSequenceAsString()
153 : AlignSeq.extractGaps(
154 jalview.util.Comparison.GapChars,
155 seqs[i].getSequenceAsString()));
161 if (seqs[i].getEnd() >= seqs[i].getStart())
163 empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq
164 .extractGaps(jalview.util.Comparison.GapChars,
165 seqs[i].getSequenceAsString());
167 emptySeqs.add(new String[]
176 * @return true if getAlignment will return a valid alignment result.
178 public boolean hasResults()
182 && (alignment != null || (emptySeqs != null && emptySeqs
192 * get the alignment including any empty sequences in the original order
193 * with original ids. Caller must access the alignment.getMetadata() object
194 * to annotate the final result passsed to the user.
196 * @return { SequenceI[], AlignmentOrder }
198 public Object[] getAlignment()
200 // is this a generic subjob or a Jws2 specific Object[] return signature
203 SequenceI[] alseqs = null;
204 char alseq_gapchar = '-';
206 if (alignment.getSequences().size() > 0)
208 alseqs = new SequenceI[alignment.getSequences().size()];
209 for (compbio.data.sequence.FastaSequence seq : alignment
212 alseqs[alseq_l++] = new Sequence(seq.getId(), seq.getSequence());
214 alseq_gapchar = alignment.getMetadata().getGapchar();
217 // add in the empty seqs.
218 if (emptySeqs.size() > 0)
220 SequenceI[] t_alseqs = new SequenceI[alseq_l + emptySeqs.size()];
225 for (i = 0, w = alseqs[0].getLength(); i < alseq_l; i++)
227 if (w < alseqs[i].getLength())
229 w = alseqs[i].getLength();
231 t_alseqs[i] = alseqs[i];
235 // check that aligned width is at least as wide as emptySeqs width.
237 for (i = 0, w = emptySeqs.size(); i < w; i++)
239 String[] es = emptySeqs.get(i);
240 if (es != null && es[1] != null)
242 int sw = es[1].length();
249 // make a gapped string.
250 StringBuffer insbuff = new StringBuffer(w);
251 for (i = 0; i < nw; i++)
253 insbuff.append(alseq_gapchar);
257 for (i = 0; i < alseq_l; i++)
259 int sw = t_alseqs[i].getLength();
263 alseqs[i].setSequence(t_alseqs[i].getSequenceAsString()
264 + insbuff.substring(0, sw - nw));
268 for (i = 0, w = emptySeqs.size(); i < w; i++)
270 String[] es = emptySeqs.get(i);
273 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(es[0],
274 insbuff.toString(), 1, 0);
278 if (es[1].length() < nw)
280 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(
282 es[1] + insbuff.substring(0, nw - es[1].length()),
283 1, 1 + es[1].length());
287 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(
294 AlignmentOrder msaorder = new AlignmentOrder(alseqs);
295 // always recover the order - makes parseResult()'s life easier.
296 jalview.analysis.AlignmentSorter.recoverOrder(alseqs);
297 // account for any missing sequences
298 jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs);
300 { alseqs, msaorder };
306 * mark subjob as cancelled and set result object appropriatly
311 subjobComplete = true;
317 * @return boolean true if job can be submitted.
319 public boolean hasValidInput()
321 // TODO: get attributes for this MsaWS instance to check if it can do two
322 // sequence alignment.
323 if (seqs != null && seqs.size() >= 2) // two or more sequences is valid ?
330 StringBuffer jobProgress = new StringBuffer();
332 public void setStatus(String string)
334 jobProgress.setLength(0);
335 jobProgress.append(string);
339 public String getStatus()
341 return jobProgress.toString();
345 public boolean hasStatus()
347 return jobProgress != null;
351 * @return the lastChunk
353 public long getLastChunk()
360 * the lastChunk to set
362 public void setLastChunk(long lastChunk)
364 this.lastChunk = lastChunk;
367 String alignmentProgram = null;
369 public String getAlignmentProgram()
371 return alignmentProgram;
374 public boolean hasArguments()
376 return (arguments != null && arguments.size() > 0)
377 || (preset != null && preset instanceof JabaWsParamSet);
380 public List<Argument> getJabaArguments()
382 List<Argument> newargs = new ArrayList<Argument>();
383 if (preset != null && preset instanceof JabaWsParamSet)
385 newargs.addAll(((JabaWsParamSet) preset).getjabaArguments());
387 if (arguments != null && arguments.size() > 0)
389 newargs.addAll(arguments);
395 * add a progess header to status string containing presets/args used
397 public void addInitialStatus()
401 jobProgress.append("Using "
402 + (preset instanceof JabaPreset ? "Server" : "User")
403 + "Preset: " + preset.getName());
404 if (preset instanceof JabaWsParamSet)
406 for (Argument opt : ((JabaWsParamSet) preset).getjabaArguments())
408 jobProgress.append(opt.getName() + " " + opt.getDefaultValue()
413 if (arguments != null && arguments.size() > 0)
415 jobProgress.append("With custom parameters : \n");
416 // merge arguments with preset's own arguments.
417 for (Argument opt : arguments)
419 jobProgress.append(opt.getName() + " " + opt.getDefaultValue()
423 jobProgress.append("\nJob Output:\n");
426 public boolean isPresetJob()
428 return preset != null && preset instanceof JabaPreset;
431 public Preset getServerPreset()
433 return (isPresetJob()) ? ((JabaPreset) preset).p : null;
437 String alTitle; // name which will be used to form new alignment window.
439 Alignment dataset; // dataset to which the new alignment will be
443 @SuppressWarnings("unchecked")
447 * set basic options for this (group) of Msa jobs
454 private MsaWSThread(MsaWS server, String wsUrl, WebserviceInfo wsinfo,
455 jalview.gui.AlignFrame alFrame, AlignmentView alview,
456 String wsname, boolean subgaps, boolean presorder)
458 super(alFrame, wsinfo, alview, wsname, wsUrl);
459 this.server = server;
460 this.submitGaps = subgaps;
461 this.preserveOrder = presorder;
465 * create one or more Msa jobs to align visible seuqences in _msa
478 MsaWSThread(MsaWS server2, WsParamSetI preset, List<Argument> paramset,
479 String wsUrl, WebserviceInfo wsinfo,
480 jalview.gui.AlignFrame alFrame, String wsname, String title,
481 AlignmentView _msa, boolean subgaps, boolean presorder,
484 this(server2, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder);
485 OutputHeader = wsInfo.getProgressText();
489 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
492 int nvalid = 0, njobs = conmsa.length;
493 jobs = new MsaWSJob[njobs];
494 for (int j = 0; j < njobs; j++)
498 jobs[j] = new MsaWSJob(wsinfo.addJobPane(), conmsa[j]);
502 jobs[j] = new MsaWSJob(0, conmsa[j]);
504 if (((MsaWSJob) jobs[j]).hasValidInput())
508 ((MsaWSJob) jobs[j]).preset = preset;
509 ((MsaWSJob) jobs[j]).arguments = paramset;
510 ((MsaWSJob) jobs[j]).alignmentProgram = wsname;
513 wsinfo.setProgressName("region " + jobs[j].getJobnum(),
514 jobs[j].getJobnum());
516 wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
518 validInput = nvalid > 0;
522 boolean validInput = false;
526 * @return true if the thread will perform a calculation
528 public boolean hasValidInput()
532 public boolean isCancellable()
537 public void cancelJob()
539 if (!jobComplete && jobs != null)
541 boolean cancelled = true;
542 for (int job = 0; job < jobs.length; job++)
544 if (jobs[job].isSubmitted() && !jobs[job].isSubjobComplete())
546 String cancelledMessage = "";
549 boolean cancelledJob = server.cancelJob(jobs[job].getJobId());
550 if (true) // cancelledJob || true)
553 // if the Jaba server indicates the job can't be cancelled, its
554 // because its running on the server's local execution engine
555 // so we just close the window anyway.
556 cancelledMessage = "Job cancelled.";
557 ((MsaWSJob) jobs[job]).cancel(); // TODO: refactor to avoid this
559 wsInfo.setStatus(jobs[job].getJobnum(),
560 WebserviceInfo.STATE_CANCELLED_OK);
564 // VALID UNSTOPPABLE JOB
565 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
567 // wsInfo.setStatus(jobs[job].jobnum,
568 // WebserviceInfo.STATE_RUNNING);
570 } catch (Exception exc)
572 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
575 "Exception whilst cancelling " + jobs[job].getJobId(),
578 wsInfo.setProgressText(jobs[job].getJobnum(), OutputHeader
579 + cancelledMessage + "\n");
583 // if we hadn't submitted then just mark the job as cancelled.
584 jobs[job].setSubjobComplete(true);
585 wsInfo.setStatus(jobs[job].getJobnum(),
586 WebserviceInfo.STATE_CANCELLED_OK);
592 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
595 this.interrupt(); // kick thread to update job states.
601 wsInfo.setProgressText(OutputHeader
602 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
607 public void pollJob(AWsJob job) throws Exception
609 // TODO: investigate if we still need to cast here in J1.6
610 MsaWSJob j = ((MsaWSJob) job);
611 // this is standard code, but since the interface doesn't comprise of a
612 // basic one that implements (getJobStatus, pullExecStatistics) we have to
613 // repeat the code for all jw2s services.
614 j.setjobStatus(server.getJobStatus(job.getJobId()));
615 updateJobProgress(j);
621 * @return true if more job progress data was available
624 protected boolean updateJobProgress(MsaWSJob j) throws Exception
626 StringBuffer response = j.jobProgress;
627 long lastchunk = j.getLastChunk();
628 boolean changed = false;
631 j.setLastChunk(lastchunk);
632 ChunkHolder chunk = server
633 .pullExecStatistics(j.getJobId(), lastchunk);
636 changed |= chunk.getChunk().length() > 0;
637 response.append(chunk.getChunk());
638 lastchunk = chunk.getNextPosition();
642 } catch (InterruptedException x)
648 } while (lastchunk >= 0 && j.getLastChunk() != lastchunk);
652 public void StartJob(AWsJob job)
654 Exception lex = null;
655 // boiler plate template
656 if (!(job instanceof MsaWSJob))
658 throw new Error(MessageManager.formatMessage("error.implementation_error_msawbjob_called", new String[]{job.getClass().toString()}));
660 MsaWSJob j = (MsaWSJob) job;
663 if (Cache.log.isDebugEnabled())
665 Cache.log.debug("Tried to submit an already submitted job "
672 if (j.seqs == null || j.seqs.size() == 0)
674 // special case - selection consisted entirely of empty sequences...
675 j.setjobStatus(JobStatus.FINISHED);
676 j.setStatus(MessageManager.getString("label.empty_alignment_job"));
680 j.addInitialStatus(); // list the presets/parameters used for the job in
684 j.setJobId(server.presetAlign(j.seqs, j.getServerPreset()));
686 else if (j.hasArguments())
688 j.setJobId(server.customAlign(j.seqs, j.getJabaArguments()));
692 j.setJobId(server.align(j.seqs));
695 if (j.getJobId() != null)
697 j.setSubmitted(true);
698 j.setSubjobComplete(false);
699 // System.out.println(WsURL + " Job Id '" + jobId + "'");
704 throw new Exception(MessageManager.formatMessage("exception.web_service_returned_null_try_later", new String[]{WsUrl}));
706 } catch (compbio.metadata.UnsupportedRuntimeException _lex)
709 wsInfo.appendProgressText(MessageManager.formatMessage("info.job_couldnt_be_run_server_doesnt_support_program", new String[]{_lex.getMessage()}));
710 wsInfo.warnUser(_lex.getMessage(), MessageManager.getString("warn.service_not_supported"));
711 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
712 wsInfo.setStatus(j.getJobnum(),
713 WebserviceInfo.STATE_STOPPED_SERVERERROR);
714 } catch (compbio.metadata.LimitExceededException _lex)
717 wsInfo.appendProgressText(MessageManager.formatMessage("info.job_couldnt_be_run_exceeded_hard_limit", new String[]{_lex.getMessage()}));
718 wsInfo.warnUser(_lex.getMessage(), MessageManager.getString("warn.input_is_too_big"));
719 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
720 wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR);
721 } catch (compbio.metadata.WrongParameterException _lex)
724 wsInfo.warnUser(_lex.getMessage(), MessageManager.getString("warn.invalid_job_param_set"));
725 wsInfo.appendProgressText(MessageManager.formatMessage("info.job_couldnt_be_run_incorrect_param_setting", new String[]{_lex.getMessage()}));
726 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
727 wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR);
730 // For unexpected errors
732 .println(WebServiceName
733 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
734 + "When contacting Server:" + WsUrl + "\n");
735 e.printStackTrace(System.err);
736 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
737 wsInfo.setStatus(j.getJobnum(),
738 WebserviceInfo.STATE_STOPPED_SERVERERROR);
739 } catch (Exception e)
741 // For unexpected errors
743 .println(WebServiceName
744 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
745 + "When contacting Server:" + WsUrl + "\n");
746 e.printStackTrace(System.err);
747 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
748 wsInfo.setStatus(j.getJobnum(),
749 WebserviceInfo.STATE_STOPPED_SERVERERROR);
752 if (!j.isSubmitted())
754 // Boilerplate code here
755 // TODO: JBPNote catch timeout or other fault types explicitly
757 j.setAllowedServerExceptions(0);
758 wsInfo.appendProgressText(j.getJobnum(),
759 MessageManager.getString("info.failed_to_submit_sequences_for_alignment"));
764 public void parseResult()
766 long progbar = System.currentTimeMillis();
767 wsInfo.setProgressBar(MessageManager.getString("status.collecting_job_results"), progbar);
768 int results = 0; // number of result sets received
769 JobStateSummary finalState = new JobStateSummary();
772 for (int j = 0; j < jobs.length; j++)
774 MsaWSJob msjob = ((MsaWSJob) jobs[j]);
775 if (jobs[j].isFinished() && msjob.alignment == null)
777 int nunchanged = 3, nexcept = 3;
778 boolean jpchanged = false, jpex = false;
783 jpchanged = updateJobProgress(msjob);
789 } catch (Exception e)
793 .warn("Exception when retrieving remaining Job progress data for job "
794 + msjob.getJobId() + " on server " + WsUrl);
798 // set flag remember that we've had an exception.
806 Thread.sleep(jpex ? 2400 : 1200); // wait a bit longer if we
807 // experienced an exception.
808 } catch (Exception ex)
814 } while (nunchanged > 0 && nexcept > 0);
816 if (Cache.log.isDebugEnabled())
818 System.out.println("Job Execution file for job: "
819 + msjob.getJobId() + " on server " + WsUrl);
820 System.out.println(msjob.getStatus());
821 System.out.println("*** End of status");
826 msjob.alignment = server.getResult(msjob.getJobId());
827 } catch (compbio.metadata.ResultNotAvailableException e)
829 // job has failed for some reason - probably due to invalid
832 .debug("Results not available for finished job - marking as broken job.",
835 .append("\nResult not available. Probably due to invalid input or parameter settings. Server error message below:\n\n"
836 + e.getLocalizedMessage());
837 msjob.setjobStatus(JobStatus.FAILED);
838 } catch (Exception e)
840 Cache.log.error("Couldn't get Alignment for job.", e);
841 // TODO: Increment count and retry ?
842 msjob.setjobStatus(JobStatus.UNDEFINED);
845 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
846 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
847 && jobs[j].hasResults())
850 compbio.data.sequence.Alignment alignment = ((MsaWSJob) jobs[j]).alignment;
851 if (alignment != null)
853 // server.close(jobs[j].getJobnum());
854 // wsInfo.appendProgressText(jobs[j].getJobnum(),
855 // "\nAlignment Object Method Notes\n");
856 // wsInfo.appendProgressText(jobs[j].getJobnum(),
857 // "Calculated with "+alignment.getMetadata().getProgram().toString());
858 // JBPNote The returned files from a webservice could be
859 // hidden behind icons in the monitor window that,
860 // when clicked, pop up their corresponding data
864 } catch (Exception ex)
867 Cache.log.error("Unexpected exception when processing results for "
869 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
873 wsInfo.showResultsNewFrame
874 .addActionListener(new java.awt.event.ActionListener()
876 public void actionPerformed(java.awt.event.ActionEvent evt)
878 displayResults(true);
882 .addActionListener(new java.awt.event.ActionListener()
884 public void actionPerformed(java.awt.event.ActionEvent evt)
886 displayResults(false);
889 wsInfo.setResultsReady();
893 wsInfo.setFinishedNoResults();
895 updateGlobalStatus(finalState);
896 wsInfo.setProgressBar(null, progbar);
900 * Display alignment results in a new frame (or - not currently supported -
901 * added to an existing alignment).
905 void displayResults(boolean newFrame)
907 // view input or result data for each block
908 List<AlignmentOrder> alorders = new ArrayList<AlignmentOrder>();
909 SequenceI[][] results = new SequenceI[jobs.length][];
910 AlignmentOrder[] orders = new AlignmentOrder[jobs.length];
911 String lastProgram = null;
913 for (int j = 0; j < jobs.length; j++)
915 if (jobs[j].hasResults())
917 msjob = (MsaWSJob) jobs[j];
918 Object[] res = msjob.getAlignment();
919 lastProgram = msjob.getAlignmentProgram();
920 alorders.add((AlignmentOrder) res[1]);
921 results[j] = (SequenceI[]) res[0];
922 orders[j] = (AlignmentOrder) res[1];
924 // SequenceI[] alignment = input.getUpdated
931 Object[] newview = input.getUpdatedView(results, orders, getGapChar());
932 // trash references to original result data
933 for (int j = 0; j < jobs.length; j++)
938 SequenceI[] alignment = (SequenceI[]) newview[0];
939 ColumnSelection columnselection = (ColumnSelection) newview[1];
940 Alignment al = new Alignment(alignment);
941 // TODO: add 'provenance' property to alignment from the method notes
942 if (lastProgram != null)
944 al.setProperty("Alignment Program", lastProgram);
946 // accompanying each subjob
949 al.setDataset(dataset);
952 propagateDatasetMappings(al);
953 // JBNote- TODO: warn user if a block is input rather than aligned data ?
957 displayInNewFrame(al, alorders, columnselection);
962 System.out.println("MERGE WITH OLD FRAME");
963 // TODO: modify alignment in original frame, replacing old for new
964 // alignment using the commands.EditCommand model to ensure the update can
970 * Display the alignment result in a new frame.
974 * @param columnselection
976 protected void displayInNewFrame(AlignmentI al,
977 List<AlignmentOrder> alorders, ColumnSelection columnselection)
979 AlignFrame af = new AlignFrame(al, columnselection,
980 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
982 // initialise with same renderer settings as in parent alignframe.
983 af.getFeatureRenderer().transferSettings(this.featureSettings);
985 if (alorders.size() > 0)
987 addSortByMenuItems(af, alorders);
991 * If alignment was requested from one half of a SplitFrame, show in a
992 * SplitFrame with the other pane similarly aligned.
994 AlignFrame requestedBy = getRequestingAlignFrame();
995 if (requestedBy != null && requestedBy.getSplitViewContainer() != null)
997 AlignmentI complement = requestedBy.getSplitViewContainer()
998 .getComplement(requestedBy);
999 String complementTitle = requestedBy.getSplitViewContainer()
1000 .getComplementTitle(requestedBy);
1001 AlignmentI copyComplement = new Alignment(complement);
1002 copyComplement.alignAs(al);
1003 if (copyComplement.getHeight() > 0)
1005 af.setTitle(alTitle);
1006 AlignFrame af2 = new AlignFrame(copyComplement,
1007 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
1008 af2.setTitle(complementTitle);
1009 String linkedTitle = MessageManager
1010 .getString("label.linked_view_title");
1011 JInternalFrame splitFrame = new SplitFrame(al.isNucleotide() ? af
1012 : af2, al.isNucleotide() ? af2 : af);
1013 Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1);
1019 * Not from SplitFrame, or failed to created a complementary alignment
1021 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
1022 AlignFrame.DEFAULT_HEIGHT);
1026 * Add sort order options to the AlignFrame menus.
1031 protected void addSortByMenuItems(AlignFrame af,
1032 List<AlignmentOrder> alorders)
1035 if (alorders.size() == 1)
1037 af.addSortByOrderMenuItem(WebServiceName + " Ordering",
1042 // construct a non-redundant ordering set
1043 List<String> names = new ArrayList<String>();
1044 for (int i = 0, l = alorders.size(); i < l; i++)
1046 String orderName = " Region " + i;
1051 if (alorders.get(i).equals(alorders.get(j)))
1055 orderName += "," + j;
1063 if (i == 0 && j == 1)
1069 names.add(orderName);
1072 for (int i = 0, l = alorders.size(); i < l; i++)
1074 af.addSortByOrderMenuItem(WebServiceName + (names.get(i))
1075 + " Ordering", alorders.get(i));
1080 public boolean canMergeResults()