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.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)
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++)
144 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
148 SeqNames.put(newname,
149 jalview.analysis.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(
156 jalview.util.Comparison.GapChars,
157 seqs[i].getSequenceAsString()));
163 if (seqs[i].getEnd() >= seqs[i].getStart())
165 empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq
166 .extractGaps(jalview.util.Comparison.GapChars,
167 seqs[i].getSequenceAsString());
169 emptySeqs.add(new String[] { newname, empty });
177 * @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 jalview.analysis.AlignmentSorter.recoverOrder(alseqs);
299 // account for any missing sequences
300 jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs);
301 return new Object[] { alseqs, msaorder };
307 * mark subjob as cancelled and set result object appropriatly
312 subjobComplete = true;
318 * @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 AlignmentI 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 jalview.gui.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,
482 jalview.gui.AlignFrame alFrame, String wsname, String title,
483 AlignmentView _msa, boolean subgaps, boolean presorder,
486 this(server2, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder);
487 OutputHeader = wsInfo.getProgressText();
491 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
494 int nvalid = 0, njobs = conmsa.length;
495 jobs = new MsaWSJob[njobs];
496 for (int j = 0; j < njobs; j++)
500 jobs[j] = new MsaWSJob(wsinfo.addJobPane(), conmsa[j]);
504 jobs[j] = new MsaWSJob(0, conmsa[j]);
506 if (((MsaWSJob) jobs[j]).hasValidInput())
510 ((MsaWSJob) jobs[j]).preset = preset;
511 ((MsaWSJob) jobs[j]).arguments = paramset;
512 ((MsaWSJob) jobs[j]).alignmentProgram = wsname;
515 wsinfo.setProgressName("region " + jobs[j].getJobnum(),
516 jobs[j].getJobnum());
518 wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
520 validInput = nvalid > 0;
524 boolean validInput = false;
528 * @return true if the thread will perform a calculation
530 public boolean hasValidInput()
536 public boolean isCancellable()
542 public void cancelJob()
544 if (!jobComplete && jobs != null)
546 boolean cancelled = true;
547 for (int job = 0; job < jobs.length; job++)
549 if (jobs[job].isSubmitted() && !jobs[job].isSubjobComplete())
551 String cancelledMessage = "";
554 boolean cancelledJob = server.cancelJob(jobs[job].getJobId());
555 if (true) // cancelledJob || true)
558 // if the Jaba server indicates the job can't be cancelled, its
559 // because its running on the server's local execution engine
560 // so we just close the window anyway.
561 cancelledMessage = "Job cancelled.";
562 ((MsaWSJob) jobs[job]).cancel(); // TODO: refactor to avoid this
564 wsInfo.setStatus(jobs[job].getJobnum(),
565 WebserviceInfo.STATE_CANCELLED_OK);
569 // VALID UNSTOPPABLE JOB
570 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
572 // wsInfo.setStatus(jobs[job].jobnum,
573 // WebserviceInfo.STATE_RUNNING);
575 } catch (Exception exc)
577 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
580 "Exception whilst cancelling " + jobs[job].getJobId(),
583 wsInfo.setProgressText(jobs[job].getJobnum(), OutputHeader
584 + cancelledMessage + "\n");
588 // if we hadn't submitted then just mark the job as cancelled.
589 jobs[job].setSubjobComplete(true);
590 wsInfo.setStatus(jobs[job].getJobnum(),
591 WebserviceInfo.STATE_CANCELLED_OK);
597 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
600 this.interrupt(); // kick thread to update job states.
606 wsInfo.setProgressText(OutputHeader
607 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
613 public void pollJob(AWsJob job) throws Exception
615 // TODO: investigate if we still need to cast here in J1.6
616 MsaWSJob j = ((MsaWSJob) job);
617 // this is standard code, but since the interface doesn't comprise of a
618 // basic one that implements (getJobStatus, pullExecStatistics) we have to
619 // repeat the code for all jw2s services.
620 j.setjobStatus(server.getJobStatus(job.getJobId()));
621 updateJobProgress(j);
627 * @return true if more job progress data was available
630 protected boolean updateJobProgress(MsaWSJob j) throws Exception
632 StringBuffer response = j.jobProgress;
633 long lastchunk = j.getLastChunk();
634 boolean changed = false;
637 j.setLastChunk(lastchunk);
638 ChunkHolder chunk = server
639 .pullExecStatistics(j.getJobId(), lastchunk);
642 changed |= chunk.getChunk().length() > 0;
643 response.append(chunk.getChunk());
644 lastchunk = chunk.getNextPosition();
648 } catch (InterruptedException x)
654 } while (lastchunk >= 0 && j.getLastChunk() != lastchunk);
659 public void StartJob(AWsJob job)
661 Exception lex = null;
662 // boiler plate template
663 if (!(job instanceof MsaWSJob))
665 throw new Error(MessageManager.formatMessage(
666 "error.implementation_error_msawbjob_called",
667 new String[] { job.getClass().toString() }));
669 MsaWSJob j = (MsaWSJob) job;
672 if (Cache.log.isDebugEnabled())
674 Cache.log.debug("Tried to submit an already submitted job "
681 if (j.seqs == null || j.seqs.size() == 0)
683 // special case - selection consisted entirely of empty sequences...
684 j.setjobStatus(JobStatus.FINISHED);
685 j.setStatus(MessageManager.getString("label.empty_alignment_job"));
689 j.addInitialStatus(); // list the presets/parameters used for the job in
693 j.setJobId(server.presetAlign(j.seqs, j.getServerPreset()));
695 else if (j.hasArguments())
697 j.setJobId(server.customAlign(j.seqs, j.getJabaArguments()));
701 j.setJobId(server.align(j.seqs));
704 if (j.getJobId() != null)
706 j.setSubmitted(true);
707 j.setSubjobComplete(false);
708 // System.out.println(WsURL + " Job Id '" + jobId + "'");
713 throw new Exception(MessageManager.formatMessage(
714 "exception.web_service_returned_null_try_later",
715 new String[] { WsUrl }));
717 } catch (compbio.metadata.UnsupportedRuntimeException _lex)
720 wsInfo.appendProgressText(MessageManager.formatMessage(
721 "info.job_couldnt_be_run_server_doesnt_support_program",
722 new String[] { _lex.getMessage() }));
723 wsInfo.warnUser(_lex.getMessage(),
724 MessageManager.getString("warn.service_not_supported"));
725 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
726 wsInfo.setStatus(j.getJobnum(),
727 WebserviceInfo.STATE_STOPPED_SERVERERROR);
728 } catch (compbio.metadata.LimitExceededException _lex)
731 wsInfo.appendProgressText(MessageManager.formatMessage(
732 "info.job_couldnt_be_run_exceeded_hard_limit",
733 new String[] { _lex.getMessage() }));
734 wsInfo.warnUser(_lex.getMessage(),
735 MessageManager.getString("warn.input_is_too_big"));
736 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
737 wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR);
738 } catch (compbio.metadata.WrongParameterException _lex)
741 wsInfo.warnUser(_lex.getMessage(),
742 MessageManager.getString("warn.invalid_job_param_set"));
743 wsInfo.appendProgressText(MessageManager.formatMessage(
744 "info.job_couldnt_be_run_incorrect_param_setting",
745 new String[] { _lex.getMessage() }));
746 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
747 wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR);
750 // For unexpected errors
752 .println(WebServiceName
753 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
754 + "When contacting Server:" + WsUrl + "\n");
755 e.printStackTrace(System.err);
756 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
757 wsInfo.setStatus(j.getJobnum(),
758 WebserviceInfo.STATE_STOPPED_SERVERERROR);
759 } catch (Exception e)
761 // For unexpected errors
763 .println(WebServiceName
764 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
765 + "When contacting Server:" + WsUrl + "\n");
766 e.printStackTrace(System.err);
767 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
768 wsInfo.setStatus(j.getJobnum(),
769 WebserviceInfo.STATE_STOPPED_SERVERERROR);
772 if (!j.isSubmitted())
774 // Boilerplate code here
775 // TODO: JBPNote catch timeout or other fault types explicitly
777 j.setAllowedServerExceptions(0);
778 wsInfo.appendProgressText(j.getJobnum(), MessageManager
779 .getString("info.failed_to_submit_sequences_for_alignment"));
785 public void parseResult()
787 long progbar = System.currentTimeMillis();
788 wsInfo.setProgressBar(
789 MessageManager.getString("status.collecting_job_results"),
791 int results = 0; // number of result sets received
792 JobStateSummary finalState = new JobStateSummary();
795 for (int j = 0; j < jobs.length; j++)
797 MsaWSJob msjob = ((MsaWSJob) jobs[j]);
798 if (jobs[j].isFinished() && msjob.alignment == null)
800 int nunchanged = 3, nexcept = 3;
801 boolean jpchanged = false, jpex = false;
806 jpchanged = updateJobProgress(msjob);
812 } catch (Exception e)
816 .warn("Exception when retrieving remaining Job progress data for job "
817 + msjob.getJobId() + " on server " + WsUrl);
821 // set flag remember that we've had an exception.
829 Thread.sleep(jpex ? 2400 : 1200); // wait a bit longer if we
830 // experienced an exception.
831 } catch (Exception ex)
837 } while (nunchanged > 0 && nexcept > 0);
839 if (Cache.log.isDebugEnabled())
841 System.out.println("Job Execution file for job: "
842 + msjob.getJobId() + " on server " + WsUrl);
843 System.out.println(msjob.getStatus());
844 System.out.println("*** End of status");
849 msjob.alignment = server.getResult(msjob.getJobId());
850 } catch (compbio.metadata.ResultNotAvailableException e)
852 // job has failed for some reason - probably due to invalid
855 .debug("Results not available for finished job - marking as broken job.",
858 .append("\nResult not available. Probably due to invalid input or parameter settings. Server error message below:\n\n"
859 + e.getLocalizedMessage());
860 msjob.setjobStatus(JobStatus.FAILED);
861 } catch (Exception e)
863 Cache.log.error("Couldn't get Alignment for job.", e);
864 // TODO: Increment count and retry ?
865 msjob.setjobStatus(JobStatus.UNDEFINED);
868 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
869 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
870 && jobs[j].hasResults())
873 compbio.data.sequence.Alignment alignment = ((MsaWSJob) jobs[j]).alignment;
874 if (alignment != null)
876 // server.close(jobs[j].getJobnum());
877 // wsInfo.appendProgressText(jobs[j].getJobnum(),
878 // "\nAlignment Object Method Notes\n");
879 // wsInfo.appendProgressText(jobs[j].getJobnum(),
880 // "Calculated with "+alignment.getMetadata().getProgram().toString());
881 // JBPNote The returned files from a webservice could be
882 // hidden behind icons in the monitor window that,
883 // when clicked, pop up their corresponding data
887 } catch (Exception ex)
890 Cache.log.error("Unexpected exception when processing results for "
892 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
896 wsInfo.showResultsNewFrame
897 .addActionListener(new java.awt.event.ActionListener()
900 public void actionPerformed(java.awt.event.ActionEvent evt)
902 displayResults(true);
906 .addActionListener(new java.awt.event.ActionListener()
909 public void actionPerformed(java.awt.event.ActionEvent evt)
911 displayResults(false);
914 wsInfo.setResultsReady();
918 wsInfo.setFinishedNoResults();
920 updateGlobalStatus(finalState);
921 wsInfo.setProgressBar(null, progbar);
925 * Display alignment results in a new frame (or - not currently supported -
926 * added to an existing alignment).
930 void displayResults(boolean newFrame)
932 // view input or result data for each block
933 List<AlignmentOrder> alorders = new ArrayList<AlignmentOrder>();
934 SequenceI[][] results = new SequenceI[jobs.length][];
935 AlignmentOrder[] orders = new AlignmentOrder[jobs.length];
936 String lastProgram = null;
938 for (int j = 0; j < jobs.length; j++)
940 if (jobs[j].hasResults())
942 msjob = (MsaWSJob) jobs[j];
943 Object[] res = msjob.getAlignment();
944 lastProgram = msjob.getAlignmentProgram();
945 alorders.add((AlignmentOrder) res[1]);
946 results[j] = (SequenceI[]) res[0];
947 orders[j] = (AlignmentOrder) res[1];
949 // SequenceI[] alignment = input.getUpdated
956 Object[] newview = input.getUpdatedView(results, orders, getGapChar());
957 // trash references to original result data
958 for (int j = 0; j < jobs.length; j++)
963 SequenceI[] alignment = (SequenceI[]) newview[0];
964 ColumnSelection columnselection = (ColumnSelection) newview[1];
965 Alignment al = new Alignment(alignment);
966 // TODO: add 'provenance' property to alignment from the method notes
967 if (lastProgram != null)
969 al.setProperty("Alignment Program", lastProgram);
971 // accompanying each subjob
974 al.setDataset(dataset);
977 propagateDatasetMappings(al);
978 // JBNote- TODO: warn user if a block is input rather than aligned data ?
982 displayInNewFrame(al, alorders, columnselection);
987 // TODO 2.9.x feature
988 System.out.println("MERGE WITH OLD FRAME");
989 // TODO: modify alignment in original frame, replacing old for new
990 // alignment using the commands.EditCommand model to ensure the update can
996 * Display the alignment result in a new frame.
1000 * @param columnselection
1002 protected void displayInNewFrame(AlignmentI al,
1003 List<AlignmentOrder> alorders, ColumnSelection columnselection)
1005 AlignFrame af = new AlignFrame(al, columnselection,
1006 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
1008 // initialise with same renderer settings as in parent alignframe.
1009 af.getFeatureRenderer().transferSettings(this.featureSettings);
1011 if (alorders.size() > 0)
1013 addSortByMenuItems(af, alorders);
1016 // TODO: refactor retrieve and show as new splitFrame as Desktop method
1019 * If alignment was requested from one half of a SplitFrame, show in a
1020 * SplitFrame with the other pane similarly aligned.
1022 AlignFrame requestedBy = getRequestingAlignFrame();
1023 if (requestedBy != null
1024 && requestedBy.getSplitViewContainer() != null
1025 && requestedBy.getSplitViewContainer().getComplement(
1026 requestedBy) != null)
1028 AlignmentI complement = requestedBy.getSplitViewContainer()
1029 .getComplement(requestedBy);
1030 String complementTitle = requestedBy.getSplitViewContainer()
1031 .getComplementTitle(requestedBy);
1032 // becomes null if the alignment window was closed before the alignment
1034 AlignmentI copyComplement = new Alignment(complement);
1035 copyComplement.alignAs(al);
1036 if (copyComplement.getHeight() > 0)
1038 af.setTitle(alTitle);
1039 AlignFrame af2 = new AlignFrame(copyComplement,
1040 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
1041 af2.setTitle(complementTitle);
1042 String linkedTitle = MessageManager
1043 .getString("label.linked_view_title");
1044 JInternalFrame splitFrame = new SplitFrame(al.isNucleotide() ? af
1045 : af2, al.isNucleotide() ? af2 : af);
1046 Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1);
1052 * Not from SplitFrame, or failed to created a complementary alignment
1054 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
1055 AlignFrame.DEFAULT_HEIGHT);
1059 * Add sort order options to the AlignFrame menus.
1064 protected void addSortByMenuItems(AlignFrame af,
1065 List<AlignmentOrder> alorders)
1068 if (alorders.size() == 1)
1070 af.addSortByOrderMenuItem(WebServiceName + " Ordering",
1075 // construct a non-redundant ordering set
1076 List<String> names = new ArrayList<String>();
1077 for (int i = 0, l = alorders.size(); i < l; i++)
1079 String orderName = " Region " + i;
1084 if (alorders.get(i).equals(alorders.get(j)))
1088 orderName += "," + j;
1096 if (i == 0 && j == 1)
1102 names.add(orderName);
1105 for (int i = 0, l = alorders.size(); i < l; i++)
1107 af.addSortByOrderMenuItem(WebServiceName + (names.get(i))
1108 + " Ordering", alorders.get(i));
1114 public boolean canMergeResults()