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.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.HiddenColumns;
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<>();
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)
130 .getString("error.implementation_error_minlen_must_be_greater_zero"));
132 for (int i = 0; i < seqs.length; i++)
134 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
139 boolean valid = nseqs > 1; // need at least two seqs
140 compbio.data.sequence.FastaSequence seq;
141 for (int i = 0, n = 0; i < seqs.length; i++)
143 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
147 SeqNames.put(newname,
148 jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i]));
149 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
151 // make new input sequence with or without gaps
152 seq = new compbio.data.sequence.FastaSequence(newname,
153 (submitGaps) ? seqs[i].getSequenceAsString()
154 : AlignSeq.extractGaps(
155 jalview.util.Comparison.GapChars,
156 seqs[i].getSequenceAsString()));
162 if (seqs[i].getEnd() >= seqs[i].getStart())
164 empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq
165 .extractGaps(jalview.util.Comparison.GapChars,
166 seqs[i].getSequenceAsString());
168 emptySeqs.add(new String[] { newname, empty });
176 * @return true if getAlignment will return a valid alignment result.
179 public boolean hasResults()
183 && (alignment != null || (emptySeqs != null && emptySeqs
193 * get the alignment including any empty sequences in the original order
194 * with original ids. Caller must access the alignment.getMetadata() object
195 * to annotate the final result passsed to the user.
197 * @return { SequenceI[], AlignmentOrder }
199 public Object[] getAlignment()
201 // is this a generic subjob or a Jws2 specific Object[] return signature
204 SequenceI[] alseqs = null;
205 char alseq_gapchar = '-';
207 if (alignment.getSequences().size() > 0)
209 alseqs = new SequenceI[alignment.getSequences().size()];
210 for (compbio.data.sequence.FastaSequence seq : alignment
213 alseqs[alseq_l++] = new Sequence(seq.getId(), seq.getSequence());
215 alseq_gapchar = alignment.getMetadata().getGapchar();
218 // add in the empty seqs.
219 if (emptySeqs.size() > 0)
221 SequenceI[] t_alseqs = new SequenceI[alseq_l + emptySeqs.size()];
226 for (i = 0, w = alseqs[0].getLength(); i < alseq_l; i++)
228 if (w < alseqs[i].getLength())
230 w = alseqs[i].getLength();
232 t_alseqs[i] = alseqs[i];
236 // check that aligned width is at least as wide as emptySeqs width.
238 for (i = 0, w = emptySeqs.size(); i < w; i++)
240 String[] es = emptySeqs.get(i);
241 if (es != null && es[1] != null)
243 int sw = es[1].length();
250 // make a gapped string.
251 StringBuffer insbuff = new StringBuffer(w);
252 for (i = 0; i < nw; i++)
254 insbuff.append(alseq_gapchar);
258 for (i = 0; i < alseq_l; i++)
260 int sw = t_alseqs[i].getLength();
264 alseqs[i].setSequence(t_alseqs[i].getSequenceAsString()
265 + insbuff.substring(0, sw - nw));
269 for (i = 0, w = emptySeqs.size(); i < w; i++)
271 String[] es = emptySeqs.get(i);
274 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(es[0],
275 insbuff.toString(), 1, 0);
279 if (es[1].length() < nw)
281 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(
283 es[1] + insbuff.substring(0, nw - es[1].length()),
284 1, 1 + es[1].length());
288 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(
295 AlignmentOrder msaorder = new AlignmentOrder(alseqs);
296 // always recover the order - makes parseResult()'s life easier.
297 jalview.analysis.AlignmentSorter.recoverOrder(alseqs);
298 // account for any missing sequences
299 jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs);
300 return new Object[] { alseqs, msaorder };
306 * mark subjob as cancelled and set result object appropriatly
311 subjobComplete = true;
317 * @return boolean true if job can be submitted.
320 public boolean hasValidInput()
322 // TODO: get attributes for this MsaWS instance to check if it can do two
323 // sequence alignment.
324 if (seqs != null && seqs.size() >= 2) // two or more sequences is valid ?
331 StringBuffer jobProgress = new StringBuffer();
333 public void setStatus(String string)
335 jobProgress.setLength(0);
336 jobProgress.append(string);
340 public String getStatus()
342 return jobProgress.toString();
346 public boolean hasStatus()
348 return jobProgress != null;
352 * @return the lastChunk
354 public long getLastChunk()
361 * the lastChunk to set
363 public void setLastChunk(long lastChunk)
365 this.lastChunk = lastChunk;
368 String alignmentProgram = null;
370 public String getAlignmentProgram()
372 return alignmentProgram;
375 public boolean hasArguments()
377 return (arguments != null && arguments.size() > 0)
378 || (preset != null && preset instanceof JabaWsParamSet);
381 public List<Argument> getJabaArguments()
383 List<Argument> newargs = new ArrayList<>();
384 if (preset != null && preset instanceof JabaWsParamSet)
386 newargs.addAll(((JabaWsParamSet) preset).getjabaArguments());
388 if (arguments != null && arguments.size() > 0)
390 newargs.addAll(arguments);
396 * add a progess header to status string containing presets/args used
398 public void addInitialStatus()
402 jobProgress.append("Using "
403 + (preset instanceof JabaPreset ? "Server" : "User")
404 + "Preset: " + preset.getName());
405 if (preset instanceof JabaWsParamSet)
407 for (Argument opt : ((JabaWsParamSet) preset).getjabaArguments())
409 jobProgress.append(opt.getName() + " " + opt.getDefaultValue()
414 if (arguments != null && arguments.size() > 0)
416 jobProgress.append("With custom parameters : \n");
417 // merge arguments with preset's own arguments.
418 for (Argument opt : arguments)
420 jobProgress.append(opt.getName() + " " + opt.getDefaultValue()
424 jobProgress.append("\nJob Output:\n");
427 public boolean isPresetJob()
429 return preset != null && preset instanceof JabaPreset;
432 public Preset getServerPreset()
434 return (isPresetJob()) ? ((JabaPreset) preset).p : null;
438 String alTitle; // name which will be used to form new alignment window.
440 AlignmentI dataset; // dataset to which the new alignment will be
444 @SuppressWarnings("unchecked")
448 * set basic options for this (group) of Msa jobs
455 private MsaWSThread(MsaWS server, String wsUrl, WebserviceInfo wsinfo,
456 jalview.gui.AlignFrame alFrame, AlignmentView alview,
457 String wsname, boolean subgaps, boolean presorder)
459 super(alFrame, wsinfo, alview, wsname, wsUrl);
460 this.server = server;
461 this.submitGaps = subgaps;
462 this.preserveOrder = presorder;
466 * create one or more Msa jobs to align visible seuqences in _msa
479 MsaWSThread(MsaWS server2, WsParamSetI preset, List<Argument> paramset,
480 String wsUrl, WebserviceInfo wsinfo,
481 jalview.gui.AlignFrame alFrame, String wsname, String title,
482 AlignmentView _msa, boolean subgaps, boolean presorder,
485 this(server2, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder);
486 OutputHeader = wsInfo.getProgressText();
490 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
493 int nvalid = 0, njobs = conmsa.length;
494 jobs = new MsaWSJob[njobs];
495 for (int j = 0; j < njobs; j++)
499 jobs[j] = new MsaWSJob(wsinfo.addJobPane(), conmsa[j]);
503 jobs[j] = new MsaWSJob(0, conmsa[j]);
505 if (((MsaWSJob) jobs[j]).hasValidInput())
509 ((MsaWSJob) jobs[j]).preset = preset;
510 ((MsaWSJob) jobs[j]).arguments = paramset;
511 ((MsaWSJob) jobs[j]).alignmentProgram = wsname;
514 wsinfo.setProgressName("region " + jobs[j].getJobnum(),
515 jobs[j].getJobnum());
517 wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
519 validInput = nvalid > 0;
523 boolean validInput = false;
527 * @return true if the thread will perform a calculation
529 public boolean hasValidInput()
535 public boolean isCancellable()
541 public void cancelJob()
543 if (!jobComplete && jobs != null)
545 boolean cancelled = true;
546 for (int job = 0; job < jobs.length; job++)
548 if (jobs[job].isSubmitted() && !jobs[job].isSubjobComplete())
550 String cancelledMessage = "";
553 boolean cancelledJob = server.cancelJob(jobs[job].getJobId());
554 if (true) // cancelledJob || true)
557 // if the Jaba server indicates the job can't be cancelled, its
558 // because its running on the server's local execution engine
559 // so we just close the window anyway.
560 cancelledMessage = "Job cancelled.";
561 ((MsaWSJob) jobs[job]).cancel(); // TODO: refactor to avoid this
563 wsInfo.setStatus(jobs[job].getJobnum(),
564 WebserviceInfo.STATE_CANCELLED_OK);
568 // VALID UNSTOPPABLE JOB
569 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
571 // wsInfo.setStatus(jobs[job].jobnum,
572 // WebserviceInfo.STATE_RUNNING);
574 } catch (Exception exc)
576 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
579 "Exception whilst cancelling " + jobs[job].getJobId(),
582 wsInfo.setProgressText(jobs[job].getJobnum(), OutputHeader
583 + cancelledMessage + "\n");
587 // if we hadn't submitted then just mark the job as cancelled.
588 jobs[job].setSubjobComplete(true);
589 wsInfo.setStatus(jobs[job].getJobnum(),
590 WebserviceInfo.STATE_CANCELLED_OK);
596 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
599 this.interrupt(); // kick thread to update job states.
605 wsInfo.setProgressText(OutputHeader
606 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
612 public void pollJob(AWsJob job) throws Exception
614 // TODO: investigate if we still need to cast here in J1.6
615 MsaWSJob j = ((MsaWSJob) job);
616 // this is standard code, but since the interface doesn't comprise of a
617 // basic one that implements (getJobStatus, pullExecStatistics) we have to
618 // repeat the code for all jw2s services.
619 j.setjobStatus(server.getJobStatus(job.getJobId()));
620 updateJobProgress(j);
626 * @return true if more job progress data was available
629 protected boolean updateJobProgress(MsaWSJob j) throws Exception
631 StringBuffer response = j.jobProgress;
632 long lastchunk = j.getLastChunk();
633 boolean changed = false;
636 j.setLastChunk(lastchunk);
637 ChunkHolder chunk = server
638 .pullExecStatistics(j.getJobId(), lastchunk);
641 changed |= chunk.getChunk().length() > 0;
642 response.append(chunk.getChunk());
643 lastchunk = chunk.getNextPosition();
647 } catch (InterruptedException x)
653 } while (lastchunk >= 0 && j.getLastChunk() != lastchunk);
658 public void StartJob(AWsJob job)
660 Exception lex = null;
661 // boiler plate template
662 if (!(job instanceof MsaWSJob))
664 throw new Error(MessageManager.formatMessage(
665 "error.implementation_error_msawbjob_called",
666 new String[] { job.getClass().toString() }));
668 MsaWSJob j = (MsaWSJob) job;
671 if (Cache.log.isDebugEnabled())
673 Cache.log.debug("Tried to submit an already submitted job "
680 if (j.seqs == null || j.seqs.size() == 0)
682 // special case - selection consisted entirely of empty sequences...
683 j.setjobStatus(JobStatus.FINISHED);
684 j.setStatus(MessageManager.getString("label.empty_alignment_job"));
688 j.addInitialStatus(); // list the presets/parameters used for the job in
692 j.setJobId(server.presetAlign(j.seqs, j.getServerPreset()));
694 else if (j.hasArguments())
696 j.setJobId(server.customAlign(j.seqs, j.getJabaArguments()));
700 j.setJobId(server.align(j.seqs));
703 if (j.getJobId() != null)
705 j.setSubmitted(true);
706 j.setSubjobComplete(false);
707 // System.out.println(WsURL + " Job Id '" + jobId + "'");
712 throw new Exception(MessageManager.formatMessage(
713 "exception.web_service_returned_null_try_later",
714 new String[] { WsUrl }));
716 } catch (compbio.metadata.UnsupportedRuntimeException _lex)
719 wsInfo.appendProgressText(MessageManager.formatMessage(
720 "info.job_couldnt_be_run_server_doesnt_support_program",
721 new String[] { _lex.getMessage() }));
722 wsInfo.warnUser(_lex.getMessage(),
723 MessageManager.getString("warn.service_not_supported"));
724 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
725 wsInfo.setStatus(j.getJobnum(),
726 WebserviceInfo.STATE_STOPPED_SERVERERROR);
727 } catch (compbio.metadata.LimitExceededException _lex)
730 wsInfo.appendProgressText(MessageManager.formatMessage(
731 "info.job_couldnt_be_run_exceeded_hard_limit",
732 new String[] { _lex.getMessage() }));
733 wsInfo.warnUser(_lex.getMessage(),
734 MessageManager.getString("warn.input_is_too_big"));
735 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
736 wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR);
737 } catch (compbio.metadata.WrongParameterException _lex)
740 wsInfo.warnUser(_lex.getMessage(),
741 MessageManager.getString("warn.invalid_job_param_set"));
742 wsInfo.appendProgressText(MessageManager.formatMessage(
743 "info.job_couldnt_be_run_incorrect_param_setting",
744 new String[] { _lex.getMessage() }));
745 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
746 wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR);
749 // For unexpected errors
751 .println(WebServiceName
752 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
753 + "When contacting Server:" + WsUrl + "\n");
754 e.printStackTrace(System.err);
755 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
756 wsInfo.setStatus(j.getJobnum(),
757 WebserviceInfo.STATE_STOPPED_SERVERERROR);
758 } catch (Exception e)
760 // For unexpected errors
762 .println(WebServiceName
763 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
764 + "When contacting Server:" + WsUrl + "\n");
765 e.printStackTrace(System.err);
766 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
767 wsInfo.setStatus(j.getJobnum(),
768 WebserviceInfo.STATE_STOPPED_SERVERERROR);
771 if (!j.isSubmitted())
773 // Boilerplate code here
774 // TODO: JBPNote catch timeout or other fault types explicitly
776 j.setAllowedServerExceptions(0);
777 wsInfo.appendProgressText(j.getJobnum(), MessageManager
778 .getString("info.failed_to_submit_sequences_for_alignment"));
784 public void parseResult()
786 long progbar = System.currentTimeMillis();
787 wsInfo.setProgressBar(
788 MessageManager.getString("status.collecting_job_results"),
790 int results = 0; // number of result sets received
791 JobStateSummary finalState = new JobStateSummary();
794 for (int j = 0; j < jobs.length; j++)
796 MsaWSJob msjob = ((MsaWSJob) jobs[j]);
797 if (jobs[j].isFinished() && msjob.alignment == null)
799 int nunchanged = 3, nexcept = 3;
800 boolean jpchanged = false, jpex = false;
805 jpchanged = updateJobProgress(msjob);
811 } catch (Exception e)
815 .warn("Exception when retrieving remaining Job progress data for job "
816 + msjob.getJobId() + " on server " + WsUrl);
820 // set flag remember that we've had an exception.
828 Thread.sleep(jpex ? 2400 : 1200); // wait a bit longer if we
829 // experienced an exception.
830 } catch (Exception ex)
836 } while (nunchanged > 0 && nexcept > 0);
838 if (Cache.log.isDebugEnabled())
840 System.out.println("Job Execution file for job: "
841 + msjob.getJobId() + " on server " + WsUrl);
842 System.out.println(msjob.getStatus());
843 System.out.println("*** End of status");
848 msjob.alignment = server.getResult(msjob.getJobId());
849 } catch (compbio.metadata.ResultNotAvailableException e)
851 // job has failed for some reason - probably due to invalid
854 .debug("Results not available for finished job - marking as broken job.",
857 .append("\nResult not available. Probably due to invalid input or parameter settings. Server error message below:\n\n"
858 + e.getLocalizedMessage());
859 msjob.setjobStatus(JobStatus.FAILED);
860 } catch (Exception e)
862 Cache.log.error("Couldn't get Alignment for job.", e);
863 // TODO: Increment count and retry ?
864 msjob.setjobStatus(JobStatus.UNDEFINED);
867 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
868 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
869 && jobs[j].hasResults())
872 compbio.data.sequence.Alignment alignment = ((MsaWSJob) jobs[j]).alignment;
873 if (alignment != null)
875 // server.close(jobs[j].getJobnum());
876 // wsInfo.appendProgressText(jobs[j].getJobnum(),
877 // "\nAlignment Object Method Notes\n");
878 // wsInfo.appendProgressText(jobs[j].getJobnum(),
879 // "Calculated with "+alignment.getMetadata().getProgram().toString());
880 // JBPNote The returned files from a webservice could be
881 // hidden behind icons in the monitor window that,
882 // when clicked, pop up their corresponding data
886 } catch (Exception ex)
889 Cache.log.error("Unexpected exception when processing results for "
891 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
895 wsInfo.showResultsNewFrame
896 .addActionListener(new java.awt.event.ActionListener()
899 public void actionPerformed(java.awt.event.ActionEvent evt)
901 displayResults(true);
905 .addActionListener(new java.awt.event.ActionListener()
908 public void actionPerformed(java.awt.event.ActionEvent evt)
910 displayResults(false);
913 wsInfo.setResultsReady();
917 wsInfo.setFinishedNoResults();
919 updateGlobalStatus(finalState);
920 wsInfo.setProgressBar(null, progbar);
924 * Display alignment results in a new frame (or - not currently supported -
925 * added to an existing alignment).
929 void displayResults(boolean newFrame)
931 // view input or result data for each block
932 List<AlignmentOrder> alorders = new ArrayList<>();
933 SequenceI[][] results = new SequenceI[jobs.length][];
934 AlignmentOrder[] orders = new AlignmentOrder[jobs.length];
935 String lastProgram = null;
937 for (int j = 0; j < jobs.length; j++)
939 if (jobs[j].hasResults())
941 msjob = (MsaWSJob) jobs[j];
942 Object[] res = msjob.getAlignment();
943 lastProgram = msjob.getAlignmentProgram();
944 alorders.add((AlignmentOrder) res[1]);
945 results[j] = (SequenceI[]) res[0];
946 orders[j] = (AlignmentOrder) res[1];
948 // SequenceI[] alignment = input.getUpdated
955 Object[] newview = input.getUpdatedView(results, orders, getGapChar());
956 // trash references to original result data
957 for (int j = 0; j < jobs.length; j++)
962 SequenceI[] alignment = (SequenceI[]) newview[0];
963 HiddenColumns hidden = (HiddenColumns) newview[1];
964 Alignment al = new Alignment(alignment);
965 // TODO: add 'provenance' property to alignment from the method notes
966 if (lastProgram != null)
968 al.setProperty("Alignment Program", lastProgram);
970 // accompanying each subjob
973 al.setDataset(dataset);
976 propagateDatasetMappings(al);
977 // JBNote- TODO: warn user if a block is input rather than aligned data ?
981 displayInNewFrame(al, alorders, hidden);
985 // TODO 2.9.x feature
986 System.out.println("MERGE WITH OLD FRAME");
987 // TODO: modify alignment in original frame, replacing old for new
988 // alignment using the commands.EditCommand model to ensure the update can
994 * Display the alignment result in a new frame.
998 * @param columnselection
1000 protected void displayInNewFrame(AlignmentI al,
1001 List<AlignmentOrder> alorders, HiddenColumns hidden)
1003 AlignFrame af = new AlignFrame(al, hidden,
1004 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
1006 // initialise with same renderer settings as in parent alignframe.
1007 af.getFeatureRenderer().transferSettings(this.featureSettings);
1009 if (alorders.size() > 0)
1011 addSortByMenuItems(af, alorders);
1014 // TODO: refactor retrieve and show as new splitFrame as Desktop method
1017 * If alignment was requested from one half of a SplitFrame, show in a
1018 * SplitFrame with the other pane similarly aligned.
1020 AlignFrame requestedBy = getRequestingAlignFrame();
1021 if (requestedBy != null
1022 && requestedBy.getSplitViewContainer() != null
1023 && requestedBy.getSplitViewContainer().getComplement(
1024 requestedBy) != null)
1026 AlignmentI complement = requestedBy.getSplitViewContainer()
1027 .getComplement(requestedBy);
1028 String complementTitle = requestedBy.getSplitViewContainer()
1029 .getComplementTitle(requestedBy);
1030 // becomes null if the alignment window was closed before the alignment
1032 AlignmentI copyComplement = new Alignment(complement);
1033 // todo should this be done by copy constructor?
1034 copyComplement.setGapCharacter(complement.getGapCharacter());
1035 // share the same dataset (and the mappings it holds)
1036 copyComplement.setDataset(complement.getDataset());
1037 copyComplement.alignAs(al);
1038 if (copyComplement.getHeight() > 0)
1040 af.setTitle(alTitle);
1041 AlignFrame af2 = new AlignFrame(copyComplement,
1042 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
1043 af2.setTitle(complementTitle);
1044 String linkedTitle = MessageManager
1045 .getString("label.linked_view_title");
1046 JInternalFrame splitFrame = new SplitFrame(al.isNucleotide() ? af
1047 : af2, al.isNucleotide() ? af2 : af);
1048 Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1);
1054 * Not from SplitFrame, or failed to created a complementary alignment
1056 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
1057 AlignFrame.DEFAULT_HEIGHT);
1061 * Add sort order options to the AlignFrame menus.
1066 protected void addSortByMenuItems(AlignFrame af,
1067 List<AlignmentOrder> alorders)
1070 if (alorders.size() == 1)
1072 af.addSortByOrderMenuItem(WebServiceName + " Ordering",
1077 // construct a non-redundant ordering set
1078 List<String> names = new ArrayList<>();
1079 for (int i = 0, l = alorders.size(); i < l; i++)
1081 String orderName = " Region " + i;
1086 if (alorders.get(i).equals(alorders.get(j)))
1090 orderName += "," + j;
1098 if (i == 0 && j == 1)
1104 names.add(orderName);
1107 for (int i = 0, l = alorders.size(); i < l; i++)
1109 af.addSortByOrderMenuItem(WebServiceName + (names.get(i))
1110 + " Ordering", alorders.get(i));
1116 public boolean canMergeResults()