From bd9ab53a139bdb8086390331196b04dde41b3909 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Fri, 27 Feb 2015 14:43:36 +0000 Subject: [PATCH] JAL-845 SplitFrame for "show product" and after aligning from SplitFrame --- resources/lang/Messages.properties | 15 +- src/jalview/analysis/AlignmentUtils.java | 144 +++++++++++++ src/jalview/api/SplitContainerI.java | 21 ++ src/jalview/appletgui/SeqCanvas.java | 1 + src/jalview/commands/EditCommand.java | 8 +- src/jalview/datamodel/AlignedCodonFrame.java | 6 +- src/jalview/datamodel/Alignment.java | 25 +++ src/jalview/datamodel/AlignmentI.java | 9 + src/jalview/datamodel/SearchResults.java | 35 ++++ src/jalview/gui/AlignFrame.java | 211 ++++++++------------ src/jalview/gui/AlignViewport.java | 30 +-- src/jalview/gui/AlignmentPanel.java | 2 +- src/jalview/gui/Jalview2XML.java | 8 - src/jalview/gui/SplitFrame.java | 34 +++- src/jalview/jbgui/GAlignFrame.java | 121 +++++------ src/jalview/jbgui/GSplitFrame.java | 30 ++- src/jalview/structure/SequenceListener.java | 2 + .../structure/StructureSelectionManager.java | 2 +- src/jalview/viewmodel/AlignmentViewport.java | 6 +- src/jalview/ws/AWSThread.java | 8 + src/jalview/ws/jws2/MsaWSThread.java | 168 ++++++++++------ test/jalview/analysis/AlignmentUtilsTests.java | 26 +++ test/jalview/datamodel/SearchResultsTest.java | 24 +++ 23 files changed, 619 insertions(+), 317 deletions(-) create mode 100644 src/jalview/api/SplitContainerI.java create mode 100644 test/jalview/datamodel/SearchResultsTest.java diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index 6f47422..b12d163 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -216,6 +216,7 @@ label.none = None label.above_identity_threshold = Above Identity Threshold label.show_sequence_features = Show Sequence Features label.nucleotide = Nucleotide +label.protein = Protein label.to_new_alignment = To New Alignment label.to_this_alignment = Add To This Alignment label.apply_colour_to_all_groups = Apply Colour To All Groups @@ -579,7 +580,8 @@ label.database_references = Database References label.share_selection_across_views = Share selection across views label.scroll_highlighted_regions = Scroll to highlighted regions label.gap_symbol = Gap Symbol -label.alignment_colour = Alignment Colour +label.prot_alignment_colour = Protein Alignment Colour +label.nuc_alignment_colour = Nucleotide Alignment Colour label.address = Address label.port = Port label.default_browser_unix = Default Browser (Unix) @@ -693,17 +695,6 @@ label.load_tree_for_sequence_set = Load a tree for this sequence set label.export_image = Export Image label.vamsas_store = VAMSAS store label.translate_cDNA = Translate as cDNA -label.cdna = cDNA -label.link_cdna = Link cDNA -label.link_cdna_tip = Link to any compatible cDNA alignments.
Sequences are linked that have the same name and compatible lengths. -label.no_cdna = No compatible cDNA was found -label.linked_cdna = {0} cDNA alignments linked -label.cdna_all_linked = All {0} compatible cDNA alignments are already linked -label.align_cdna = Align linked cDNA -label.align_cdna_tip = Any linked cDNA sequences will be realigned to match this alignment. -label.cdna_aligned = {0} sequences in {1} alignments were realigned -label.view_as_cdna = Show aligned cDNA -label.view_as_cdna_tip = Open a new alignment of the related cDNA sequences label.linked_view_title = Linked cDNA and protein view label.align = Align label.extract_scores = Extract Scores diff --git a/src/jalview/analysis/AlignmentUtils.java b/src/jalview/analysis/AlignmentUtils.java index 0441b1d..0ae782e 100644 --- a/src/jalview/analysis/AlignmentUtils.java +++ b/src/jalview/analysis/AlignmentUtils.java @@ -23,6 +23,8 @@ package jalview.analysis; import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; +import jalview.datamodel.SearchResults; +import jalview.datamodel.Sequence; import jalview.datamodel.SequenceI; import jalview.schemes.ResidueProperties; import jalview.util.MapList; @@ -636,4 +638,146 @@ public class AlignmentUtils } return gapsToAdd; } + + /** + * Returns a list of sequences mapped from the given sequences and aligned + * (gapped) in the same way. For example, the cDNA for aligned protein, where + * a single gap in protein generates three gaps in cDNA. + * + * @param sequences + * @param gapCharacter + * @param mappings + * @return + */ + public static List getAlignedTranslation( + List sequences, char gapCharacter, + Set mappings) + { + List alignedSeqs = new ArrayList(); + + for (SequenceI seq : sequences) + { + List mapped = getAlignedTranslation(seq, gapCharacter, + mappings); + alignedSeqs.addAll(mapped); + } + return alignedSeqs; + } + + /** + * Returns sequences aligned 'like' the source sequence, as mapped by the + * given mappings. Normally we expect zero or one 'mapped' sequences, but this + * will support 1-to-many as well. + * + * @param seq + * @param gapCharacter + * @param mappings + * @return + */ + protected static List getAlignedTranslation(SequenceI seq, + char gapCharacter, Set mappings) + { + List result = new ArrayList(); + for (AlignedCodonFrame mapping : mappings) + { + if (mapping.involvesSequence(seq)) + { + SequenceI mapped = getAlignedTranslation(seq, gapCharacter, mapping); + if (mapped != null) + { + result.add(mapped); + } + } + } + return result; + } + + /** + * Returns the translation of 'seq' (as held in the mapping) with + * corresponding alignment (gaps). + * + * @param seq + * @param gapCharacter + * @param mapping + * @return + */ + protected static SequenceI getAlignedTranslation(SequenceI seq, + char gapCharacter, AlignedCodonFrame mapping) + { + String gap = String.valueOf(gapCharacter); + boolean toDna = false; + int fromRatio = 1; + SequenceI mapTo = mapping.getDnaForAaSeq(seq); + if (mapTo != null) + { + // mapping is from protein to nucleotide + toDna = true; + // should ideally get gap count ratio from mapping + gap = String.valueOf(new char[] + { gapCharacter, gapCharacter, gapCharacter }); + } + else + { + // mapping is from nucleotide to protein + mapTo = mapping.getAaForDnaSeq(seq); + fromRatio = 3; + } + StringBuilder newseq = new StringBuilder(seq.getLength() + * (toDna ? 3 : 1)); + + int residueNo = 0; // in seq, base 1 + int[] phrase = new int[fromRatio]; + int phraseOffset = 0; + int gapWidth = 0; + boolean first = true; + final Sequence alignedSeq = new Sequence("", ""); + + for (char c : seq.getSequence()) + { + if (c == gapCharacter) + { + gapWidth++; + if (gapWidth >= fromRatio) + { + newseq.append(gap); + gapWidth = 0; + } + } + else + { + phrase[phraseOffset++] = residueNo + 1; + if (phraseOffset == fromRatio) + { + /* + * Have read a whole codon (or protein residue), now translate: map + * source phrase to positions in target sequence add characters at + * these positions to newseq Note mapping positions are base 1, our + * sequence positions base 0. + */ + SearchResults sr = new SearchResults(); + for (int pos : phrase) + { + mapping.markMappedRegion(seq, pos, sr); + } + newseq.append(sr.toString()); + if (first) + { + first = false; + // Hack: Copy sequence dataset, name and description from + // SearchResults.match[0].sequence + // TODO? carry over sequence names from original 'complement' + // alignment + SequenceI mappedTo = sr.getResultSequence(0); + alignedSeq.setName(mappedTo.getName()); + alignedSeq.setDescription(mappedTo.getDescription()); + alignedSeq.setDatasetSequence(mappedTo); + } + phraseOffset = 0; + } + residueNo++; + } + } + alignedSeq.setSequence(newseq.toString()); + return alignedSeq; + } } diff --git a/src/jalview/api/SplitContainerI.java b/src/jalview/api/SplitContainerI.java new file mode 100644 index 0000000..22f5201 --- /dev/null +++ b/src/jalview/api/SplitContainerI.java @@ -0,0 +1,21 @@ +package jalview.api; + +/** + * Describes a visual container that can show two alignments. + * + * @author gmcarstairs + * + */ +public interface SplitContainerI +{ + + /** + * Set visibility of the specified split view component. + * + * @param alignFrame + * @param show + */ + // TODO need an interface for AlignFrame? + void setComplementVisible(Object alignFrame, boolean show); + +} diff --git a/src/jalview/appletgui/SeqCanvas.java b/src/jalview/appletgui/SeqCanvas.java index ec94c6f..4cf1996 100755 --- a/src/jalview/appletgui/SeqCanvas.java +++ b/src/jalview/appletgui/SeqCanvas.java @@ -280,6 +280,7 @@ public class SeqCanvas extends Panel paint(g); } + @Override public void paint(Graphics g) { diff --git a/src/jalview/commands/EditCommand.java b/src/jalview/commands/EditCommand.java index 38a45ce..b2ecb7e 100644 --- a/src/jalview/commands/EditCommand.java +++ b/src/jalview/commands/EditCommand.java @@ -63,7 +63,7 @@ public class EditCommand implements CommandI { public enum Action { - INSERT_GAP() + INSERT_GAP { @Override public Action getUndoAction() @@ -71,7 +71,7 @@ public class EditCommand implements CommandI return DELETE_GAP; } }, - DELETE_GAP() + DELETE_GAP { @Override public Action getUndoAction() @@ -79,7 +79,7 @@ public class EditCommand implements CommandI return INSERT_GAP; } }, - CUT() + CUT { @Override public Action getUndoAction() @@ -87,7 +87,7 @@ public class EditCommand implements CommandI return PASTE; } }, - PASTE() + PASTE { @Override public Action getUndoAction() diff --git a/src/jalview/datamodel/AlignedCodonFrame.java b/src/jalview/datamodel/AlignedCodonFrame.java index d3f6ad5..9c17306 100644 --- a/src/jalview/datamodel/AlignedCodonFrame.java +++ b/src/jalview/datamodel/AlignedCodonFrame.java @@ -42,16 +42,14 @@ public class AlignedCodonFrame private Mapping[] dnaToProt = null; /** - * initialise codon frame with a nominal alignment width - * - * @param aWidth + * Constructor */ public AlignedCodonFrame() { } /** - * add a mapping between the dataset sequences for the associated dna and + * Adds a mapping between the dataset sequences for the associated dna and * protein sequence objects * * @param dnaseq diff --git a/src/jalview/datamodel/Alignment.java b/src/jalview/datamodel/Alignment.java index cb571ac..56545e1 100755 --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@ -1734,4 +1734,29 @@ public class Alignment implements AlignmentI } return names; } + + /** + * Returns a (possibly empty) alignment whose sequences are aligned to match + * the current alignment, as mapped by the given codon mappings. + * + * @param codonFrames + * @return + */ + @Override + public AlignmentI getAlignedComplement(Set codonFrames) + { + // Note: passing codonFrames as a parameter rather than using + // this.codonFrameList as more flexible. Specifically, mappings are held + // on the protein alignment but we might want to act on dna. + + // TODO we want the gap character of the mapped alignment, not this one! + List alignedSeqs = AlignmentUtils.getAlignedTranslation( + getSequences(), getGapCharacter(), codonFrames); + final SequenceI[] seqsAsArray = alignedSeqs + .toArray(new SequenceI[alignedSeqs.size()]); + AlignmentI al = new Alignment(seqsAsArray); + al.padGaps(); + al.setDataset(null); + return al; + } } diff --git a/src/jalview/datamodel/AlignmentI.java b/src/jalview/datamodel/AlignmentI.java index fe93683..eb396ad 100755 --- a/src/jalview/datamodel/AlignmentI.java +++ b/src/jalview/datamodel/AlignmentI.java @@ -517,4 +517,13 @@ public interface AlignmentI extends AnnotatedCollectionI * @return */ Set getSequenceNames(); + + /** + * Returns a (possibly empty) alignment whose sequences are aligned to match + * the current alignment, as mapped by the given codon mappings. + * + * @param codonFrames + * @return + */ + AlignmentI getAlignedComplement(Set codonFrames); } diff --git a/src/jalview/datamodel/SearchResults.java b/src/jalview/datamodel/SearchResults.java index 7a241fd..a53d103 100755 --- a/src/jalview/datamodel/SearchResults.java +++ b/src/jalview/datamodel/SearchResults.java @@ -21,6 +21,7 @@ package jalview.datamodel; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -39,8 +40,14 @@ public class SearchResults { SequenceI sequence; + /* + * Start position of match in sequence (base 1) + */ int start; + /* + * End position (inclusive) (base 1) + */ int end; public Match(SequenceI seq, int start, int end) @@ -64,6 +71,16 @@ public class SearchResults { return end; } + + /** + * Returns the string of characters in the matched region. + */ + @Override + public String toString() + { + char[] chars = sequence.getSequence(); + return String.valueOf(Arrays.copyOfRange(chars, start - 1, end)); + } } /** @@ -228,4 +245,22 @@ public class SearchResults { return matches; } + + /** + * Return the results as a string of characters. Meant for use when the + * context ensures that all matches are to regions of the same sequence + * (otherwise the result is meaningless). + * + * @return + */ + @Override + public String toString() + { + StringBuilder result = new StringBuilder(256); + for (Match m : matches) + { + result.append(m.toString()); + } + return result.toString(); + } } diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 38940d2..2b92142 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -23,7 +23,6 @@ package jalview.gui; import jalview.analysis.AAFrequency; import jalview.analysis.AlignmentSorter; import jalview.analysis.AlignmentUtils; -import jalview.analysis.AlignmentUtils.MappingResult; import jalview.analysis.Conservation; import jalview.analysis.CrossRef; import jalview.analysis.Dna; @@ -33,6 +32,7 @@ import jalview.api.AlignViewControllerGuiI; import jalview.api.AlignViewControllerI; import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; +import jalview.api.SplitContainerI; import jalview.api.ViewStyleI; import jalview.api.analysis.ScoreModelI; import jalview.bin.Cache; @@ -89,7 +89,6 @@ import jalview.schemes.TaylorColourScheme; import jalview.schemes.TurnColourScheme; import jalview.schemes.UserColourScheme; import jalview.schemes.ZappoColourScheme; -import jalview.structure.StructureSelectionManager; import jalview.util.MessageManager; import jalview.viewmodel.AlignmentViewport; import jalview.ws.jws1.Discoverer; @@ -769,104 +768,28 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, }).start(); } + /** + * Configure menu items that vary according to whether the alignment is + * nucleotide or protein + * + * @param nucleotide + */ public void setGUINucleotide(boolean nucleotide) { showTranslation.setVisible(nucleotide); - cdna.setVisible(!nucleotide); conservationMenuItem.setEnabled(!nucleotide); modifyConservation.setEnabled(!nucleotide); showGroupConservation.setEnabled(!nucleotide); rnahelicesColour.setEnabled(nucleotide); purinePyrimidineColour.setEnabled(nucleotide); + showComplementMenuItem.setText(MessageManager + .getString(nucleotide ? "label.protein" : "label.nucleotide")); + setColourSelected(jalview.bin.Cache.getDefault( + nucleotide ? Preferences.DEFAULT_COLOUR_NUC + : Preferences.DEFAULT_COLOUR_PROT, "None")); } /** - * Builds codon mappings from this (protein) alignment to any compatible - * nucleotide alignments. Mappings are built between sequences with the same - * name and compatible lengths. Also makes the cDNA alignment a - * CommandListener for the protein alignment so that edits are mirrored. - */ - @Override - protected void linkCdna_actionPerformed() - { - int linkedCount = 0; - int alreadyLinkedCount = 0; - final AlignmentI thisAlignment = this.alignPanel.getAlignment(); - - for (AlignFrame af : Desktop.getAlignFrames()) - { - if (af.alignPanel != null) - { - final AlignmentI thatAlignment = af.alignPanel.getAlignment(); - if (thatAlignment.isNucleotide()) - { - MappingResult mapped = AlignmentUtils.mapProteinToCdna( - thisAlignment, thatAlignment); - if (mapped == MappingResult.AlreadyMapped) - { - alreadyLinkedCount++; - } - else if (mapped == MappingResult.Mapped) - { - final StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); - ssm.addMappings(thisAlignment.getCodonFrames()); - // enable the next line to enable linked editing - // ssm.addCommandListener(af.getViewport()); - linkedCount++; - } - } - } - } - String msg = ""; - if (linkedCount == 0 && alreadyLinkedCount == 0) - { - msg = MessageManager.getString("label.no_cdna"); - } - else if (linkedCount > 0) - { - msg = MessageManager.formatMessage("label.linked_cdna", linkedCount); - } - else - { - msg = MessageManager.formatMessage("label.cdna_all_linked", - alreadyLinkedCount); - } - setStatus(msg); - } - - /** - * Align any linked cDNA to match the alignment of this (protein) alignment. - * Any mapped sequence regions will be realigned, unmapped sequences are not - * affected. - */ - @Override - protected void alignCdna_actionPerformed() - { - int seqCount = 0; - int alignCount = 0; - final AlignmentI thisAlignment = this.alignPanel.getAlignment(); - for (AlignFrame af : Desktop.getAlignFrames()) - { - if (af.alignPanel != null) - { - final AlignmentI thatAlignment = af.alignPanel.getAlignment(); - if (thatAlignment.isNucleotide()) - { - int seqsAligned = thatAlignment.alignAs(thisAlignment); - seqCount += seqsAligned; - if (seqsAligned > 0) - { - af.alignPanel.alignmentChanged(); - alignCount++; - } - } - } - } - setStatus(MessageManager.formatMessage("label.cdna_aligned", seqCount, - alignCount)); - } - /** * set up menus for the current viewport. This may be called after any * operation that affects the data in the current view (selection changed, * etc) to update the menus to reflect the new state. @@ -2386,15 +2309,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, return; } - List seqs = new ArrayList(sg.getSize()); - SequenceI seq; - for (int i = 0; i < sg.getSize(); i++) - { - seq = sg.getSequenceAt(i); - seqs.add(seq); - } - - // If the cut affects all sequences, warn, remove highlighted columns + /* + * If the cut affects all sequences, warn, remove highlighted columns + */ if (sg.getSize() == viewport.getAlignment().getHeight()) { int confirm = JOptionPane.showConfirmDialog(this, @@ -2411,15 +2328,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, sg.getEndRes() + 1); } - SequenceI[] cut = new SequenceI[seqs.size()]; - for (int i = 0; i < seqs.size(); i++) - { - cut[i] = seqs.get(i); - } + SequenceI[] cut = sg.getSequences() + .toArray(new SequenceI[sg.getSize()]); - /* - * //ADD HISTORY ITEM - */ addHistoryItem(new EditCommand( MessageManager.getString("label.cut_sequences"), Action.CUT, cut, sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1, @@ -2934,6 +2845,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override protected void followHighlight_actionPerformed() { + /* + * Set the 'follow' flag on the Viewport (and scroll to position if now + * true). + */ if (viewport.followHighlight = this.followHighlightMenuItem.getState()) { alignPanel.scrollToPosition( @@ -4810,7 +4725,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, public void actionPerformed(ActionEvent e) { // TODO: new thread for this call with vis-delay - af.showProductsFor(af.viewport.getSequenceSelection(), ds, + af.showProductsFor(af.viewport.getSequenceSelection(), isRegSel, dna, source); } @@ -4829,14 +4744,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, return showp; } - protected void showProductsFor(SequenceI[] sel, Alignment ds, - boolean isRegSel, boolean dna, String source) + protected void showProductsFor(final SequenceI[] sel, + final boolean isRegSel, final boolean dna, final String source) { - final boolean fisRegSel = isRegSel; - final boolean fdna = dna; - final String fsrc = source; - final AlignFrame ths = this; - final SequenceI[] fsel = sel; Runnable foo = new Runnable() { @@ -4844,15 +4754,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, public void run() { final long sttime = System.currentTimeMillis(); - ths.setProgressBar(MessageManager.formatMessage("status.searching_for_sequences_from", new Object[]{fsrc}), sttime); + AlignFrame.this.setProgressBar(MessageManager.formatMessage( + "status.searching_for_sequences_from", new Object[] + { source }), sttime); try { - Alignment ds = ths.getViewport().getAlignment().getDataset(); // update - // our local - // dataset - // reference + // update our local dataset reference + Alignment ds = AlignFrame.this.getViewport().getAlignment() + .getDataset(); Alignment prods = CrossRef - .findXrefSequences(fsel, fdna, fsrc, ds); + .findXrefSequences(sel, dna, source, ds); if (prods != null) { SequenceI[] sprods = new SequenceI[prods.getHeight()]; @@ -4876,16 +4787,38 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } AlignFrame naf = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT); - String newtitle = "" + ((fdna) ? "Proteins " : "Nucleotides ") - + " for " + ((fisRegSel) ? "selected region of " : "") + String newtitle = "" + ((dna) ? "Proteins" : "Nucleotides") + + " for " + ((isRegSel) ? "selected region of " : "") + getTitle(); - Desktop.addInternalFrame(naf, newtitle, DEFAULT_WIDTH, - DEFAULT_HEIGHT); + naf.setTitle(newtitle); + + // remove this flag once confirmed we want a split view + boolean asSplitFrame = true; + if (asSplitFrame) + { + AlignFrame copyThis = new AlignFrame( + AlignFrame.this.viewport.getAlignment(), + AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + copyThis.setTitle(AlignFrame.this.getTitle()); + // SplitFrame with dna above, protein below + SplitFrame sf = new SplitFrame(dna ? copyThis : naf, + dna ? naf : copyThis); + naf.setVisible(true); + copyThis.setVisible(true); + String linkedTitle = MessageManager + .getString("label.linked_view_title"); + Desktop.addInternalFrame(sf, linkedTitle, -1, -1); + } + else + { + Desktop.addInternalFrame(naf, newtitle, DEFAULT_WIDTH, + DEFAULT_HEIGHT); + } } else { System.err.println("No Sequences generated for xRef type " - + fsrc); + + source); } } catch (Exception e) { @@ -4899,7 +4832,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, jalview.bin.Cache.log.error("Error when finding crossreferences", e); } - ths.setProgressBar(MessageManager.formatMessage("status.finished_searching_for_sequences_from", new Object[]{fsrc}), + AlignFrame.this.setProgressBar(MessageManager.formatMessage( + "status.finished_searching_for_sequences_from", + new Object[] + { source }), sttime); } @@ -4968,10 +4904,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, "label.translation_of_params", new Object[] { this.getTitle() }); af.setTitle(newTitle); - viewport.openSplitFrame(af, viewport.getAlignment()); + final SequenceI[] seqs = viewport.getSelectionGroup() == null ? viewport + .getAlignment().getSequencesArray() : viewport + .getSelectionAsNewSequence(); + viewport.openSplitFrame(af, seqs); // Desktop.addInternalFrame(af, newTitle, DEFAULT_WIDTH, DEFAULT_HEIGHT); - // // enable next line for linked editing - // viewport.getStructureSelectionManager().addCommandListener(viewport); } } @@ -6000,9 +5937,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * Open a new alignment window, with the cDNA associated with this (protein) * alignment, aligned as is the protein. */ - @Override protected void viewAsCdna_actionPerformed() { + // TODO no longer a menu action - refactor as required final AlignmentI alignment = getViewport().getAlignment(); Set mappings = alignment.getCodonFrames(); if (mappings == null) @@ -6041,7 +5978,21 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, Desktop.addInternalFrame(alignFrame, newtitle, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + } + /** + * Set visibility of dna/protein complement view (available when shown in a + * split frame). + * + * @param show + */ + @Override + protected void showComplement_actionPerformed(boolean show) + { + SplitContainerI sf = getSplitViewContainer(); + if (sf != null) { + sf.setComplementVisible(this, show); + } } } diff --git a/src/jalview/gui/AlignViewport.java b/src/jalview/gui/AlignViewport.java index 4ba2113..cad90e3 100644 --- a/src/jalview/gui/AlignViewport.java +++ b/src/jalview/gui/AlignViewport.java @@ -300,10 +300,10 @@ public class AlignViewport extends AlignmentViewport implements showConsensus = Cache.getDefault("SHOW_IDENTITY", true); } initAutoAnnotation(); - if (jalview.bin.Cache.getProperty("DEFAULT_COLOUR") != null) + if (jalview.bin.Cache.getProperty(Preferences.DEFAULT_COLOUR) != null) { globalColourScheme = ColourSchemeProperty.getColour(alignment, - jalview.bin.Cache.getProperty("DEFAULT_COLOUR")); + jalview.bin.Cache.getProperty(Preferences.DEFAULT_COLOUR)); if (globalColourScheme instanceof UserColourScheme) { @@ -1060,7 +1060,8 @@ public class AlignViewport extends AlignmentViewport implements if (openSplitPane) { - protein = openSplitFrame(newAlignFrame, thisAlignment); + protein = openSplitFrame(newAlignFrame, + thisAlignment.getSequencesArray()); } /* @@ -1080,18 +1081,19 @@ public class AlignViewport extends AlignmentViewport implements * * @param newAlignFrame * containing a new alignment to be shown - * @param existingAlignment - * an existing alignment to be copied for display in the split frame + * @param seqs + * 'complementary' sequences to show in the other split half * @return the protein alignment in the split frame */ protected AlignmentI openSplitFrame(AlignFrame newAlignFrame, - AlignmentI existingAlignment) + SequenceI[] seqs) { + AlignmentI complementAlignment = new Alignment(seqs); // TODO: move this to a factory/controller method ? /* * Open in split pane. DNA sequence above, protein below. */ - AlignFrame copyMe = new AlignFrame(existingAlignment, + AlignFrame copyMe = new AlignFrame(complementAlignment, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); copyMe.setTitle(getAlignPanel().alignFrame.getTitle()); @@ -1109,20 +1111,6 @@ public class AlignViewport extends AlignmentViewport implements JInternalFrame splitFrame = new SplitFrame(cdnaFrame, proteinFrame); Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1); - /* - * Set the frames to listen for each other's edit and sort commands. - */ - final StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); - ssm.addCommandListener(cdnaFrame.getViewport()); - ssm.addCommandListener(proteinFrame.getViewport()); - - /* - * 'Coding complement' (dna/protein) views will mirror each others' edits, - * selections, sorting etc as decided from time to time by the relevant - * authorities. - */ - proteinFrame.getViewport().setCodingComplement(cdnaFrame.getViewport()); return protein; } diff --git a/src/jalview/gui/AlignmentPanel.java b/src/jalview/gui/AlignmentPanel.java index 7132ff0..ccbc031 100644 --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@ -1493,7 +1493,7 @@ public class AlignmentPanel extends GAlignmentPanel implements .getStructureSelectionManager(); ssm.removeStructureViewerListener(getSeqPanel(), null); ssm.removeSelectionListener(getSeqPanel()); - ssm.removeEditListener(av); + ssm.removeCommandListener(av); ssm.removeStructureViewerListener(getSeqPanel(), null); ssm.removeSelectionListener(getSeqPanel()); av.setAlignment(null); diff --git a/src/jalview/gui/Jalview2XML.java b/src/jalview/gui/Jalview2XML.java index b30b28f..8342151 100644 --- a/src/jalview/gui/Jalview2XML.java +++ b/src/jalview/gui/Jalview2XML.java @@ -2263,14 +2263,6 @@ public class Jalview2XML protected SplitFrame createSplitFrame(AlignFrame dnaFrame, AlignFrame proteinFrame) { - dnaFrame.setVisible(true); - proteinFrame.setVisible(true); - proteinFrame.getViewport().setCodingComplement(dnaFrame.getViewport()); - final StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); - ssm.addCommandListener(proteinFrame.getViewport()); - ssm.addCommandListener(dnaFrame.getViewport()); - SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame); String title = MessageManager.getString("label.linked_view_title"); Desktop.addInternalFrame(splitFrame, title, -1, -1); diff --git a/src/jalview/gui/SplitFrame.java b/src/jalview/gui/SplitFrame.java index e441371..81a6ddc 100644 --- a/src/jalview/gui/SplitFrame.java +++ b/src/jalview/gui/SplitFrame.java @@ -52,6 +52,14 @@ public class SplitFrame extends GSplitFrame */ protected void init() { + getTopFrame().setSplitFrame(this); + getBottomFrame().setSplitFrame(this); + getTopFrame().setVisible(true); + getBottomFrame().setVisible(true); + + ((AlignFrame) getTopFrame()).getViewport().setCodingComplement( + ((AlignFrame) getBottomFrame()).getViewport()); + setSize(AlignFrame.DEFAULT_WIDTH, Desktop.instance.getHeight() - 20); adjustLayout(); @@ -61,6 +69,22 @@ public class SplitFrame extends GSplitFrame addKeyListener(); addKeyBindings(); + + addCommandListeners(); + } + + /** + * Set the top and bottom frames to listen to each others Commands (e.g. Edit, + * Order). + */ + protected void addCommandListeners() + { + // TODO if CommandListener is only ever 1:1 for complementary views, + // may change broadcast pattern to direct messaging (more efficient) + final StructureSelectionManager ssm = StructureSelectionManager + .getStructureSelectionManager(Desktop.instance); + ssm.addCommandListener(((AlignFrame) getTopFrame()).getViewport()); + ssm.addCommandListener(((AlignFrame) getBottomFrame()).getViewport()); } /** @@ -74,8 +98,14 @@ public class SplitFrame extends GSplitFrame int w1 = ((AlignFrame) getTopFrame()).getViewport().getIdWidth(); int w2 = ((AlignFrame) getBottomFrame()).getViewport().getIdWidth(); int w3 = Math.max(w1, w2); - ((AlignFrame) getTopFrame()).getViewport().setIdWidth(w3); - ((AlignFrame) getBottomFrame()).getViewport().setIdWidth(w3); + if (w1 != w3) + { + ((AlignFrame) getTopFrame()).getViewport().setIdWidth(w3); + } + if (w2 != w3) + { + ((AlignFrame) getBottomFrame()).getViewport().setIdWidth(w3); + } /* * Set the character width for protein to 3 times that for dna. diff --git a/src/jalview/jbgui/GAlignFrame.java b/src/jalview/jbgui/GAlignFrame.java index 4b36729..d9c87cb 100755 --- a/src/jalview/jbgui/GAlignFrame.java +++ b/src/jalview/jbgui/GAlignFrame.java @@ -21,6 +21,7 @@ package jalview.jbgui; import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder; +import jalview.api.SplitContainerI; import jalview.bin.Cache; import jalview.gui.JvSwingUtils; import jalview.gui.Preferences; @@ -260,8 +261,6 @@ public class GAlignFrame extends JInternalFrame protected JMenuItem showTranslation = new JMenuItem(); - protected JMenu cdna = new JMenu(); - protected JMenuItem extractScores = new JMenuItem(); protected JMenuItem expandAlignment = new JMenuItem(); @@ -302,7 +301,7 @@ public class GAlignFrame extends JInternalFrame GridLayout gridLayout1 = new GridLayout(); - JMenu jMenu3 = new JMenu(); + JMenu showMenu = new JMenu(); JMenuItem showAllSeqs = new JMenuItem(); @@ -328,6 +327,8 @@ public class GAlignFrame extends JInternalFrame protected JMenuItem hideAllAlAnnotations = new JMenuItem(); + protected JCheckBoxMenuItem showComplementMenuItem = new JCheckBoxMenuItem(); + protected JCheckBoxMenuItem sortAnnBySequence = new JCheckBoxMenuItem(); protected JCheckBoxMenuItem sortAnnByLabel = new JCheckBoxMenuItem(); @@ -396,6 +397,8 @@ public class GAlignFrame extends JInternalFrame private Map accelerators = new HashMap(); + private SplitContainerI splitFrame; + public GAlignFrame() { try @@ -513,9 +516,8 @@ public class GAlignFrame extends JInternalFrame // colours.add(covariationColour); colours.add(tcoffeeColour); colours.add(RNAInteractionColour); - setColourSelected(jalview.bin.Cache - .getDefault("DEFAULT_COLOUR", "None")); - + setColourSelected(jalview.bin.Cache.getDefault( + Preferences.DEFAULT_COLOUR, "None")); } public void setColourSelected(String defaultColour) @@ -1835,54 +1837,6 @@ public class GAlignFrame extends JInternalFrame } }); - /* - * cDNA menu options - */ - cdna.setText(MessageManager.getString("label.cdna")); - // link to available cDNA - JMenuItem linkCdna = new JMenuItem( - MessageManager.getString("label.link_cdna")); - linkCdna.setToolTipText(JvSwingUtils.wrapTooltip(true, - MessageManager.getString("label.link_cdna_tip"))); - linkCdna.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - linkCdna_actionPerformed(); - } - }); - cdna.add(linkCdna); - // align linked cDNA - JMenuItem alignCdna = new JMenuItem( - MessageManager.getString("label.align_cdna")); - alignCdna.setToolTipText(JvSwingUtils.wrapTooltip(true, - MessageManager.getString("label.align_cdna_tip"))); - alignCdna.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - alignCdna_actionPerformed(); - } - }); - cdna.add(alignCdna); - - // view alignment as cDNA (when known) - JMenuItem viewAsCdna = new JMenuItem( - MessageManager.getString("label.view_as_cdna")); - viewAsCdna.setToolTipText(JvSwingUtils.wrapTooltip(true, - MessageManager.getString("label.view_as_cdna_tip"))); - viewAsCdna.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - viewAsCdna_actionPerformed(); - } - }); - cdna.add(viewAsCdna); - extractScores.setText(MessageManager.getString("label.extract_scores") + "..."); extractScores.addActionListener(new ActionListener() @@ -2057,7 +2011,7 @@ public class GAlignFrame extends JInternalFrame } }); statusPanel.setLayout(gridLayout1); - jMenu3.setText(MessageManager.getString("action.show")); + showMenu.setText(MessageManager.getString("action.show")); showAllSeqs.setText(MessageManager.getString("label.all_sequences")); showAllSeqs.setToolTipText(MessageManager .getString("label.toggle_sequence_visibility")); @@ -2164,6 +2118,16 @@ public class GAlignFrame extends JInternalFrame }; addMenuActionAndAccelerator(keyStroke, invertColSel, al); + showComplementMenuItem.setVisible(false); + showComplementMenuItem.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + showComplement_actionPerformed(showComplementMenuItem.getState()); + } + }); + tabbedPane.addChangeListener(new javax.swing.event.ChangeListener() { @Override @@ -2354,8 +2318,9 @@ public class GAlignFrame extends JInternalFrame viewMenu.add(expandViews); viewMenu.add(gatherViews); viewMenu.addSeparator(); - viewMenu.add(jMenu3); + viewMenu.add(showMenu); viewMenu.add(hideMenu); + viewMenu.add(showComplementMenuItem); viewMenu.addSeparator(); viewMenu.add(followHighlightMenuItem); annotationsMenu.add(annotationPanelMenuItem); @@ -2425,7 +2390,6 @@ public class GAlignFrame extends JInternalFrame calculateMenu.add(PCAMenuItem); calculateMenu.addSeparator(); calculateMenu.add(showTranslation); - calculateMenu.add(cdna); calculateMenu.add(showProducts); calculateMenu.add(autoCalculate); calculateMenu.add(sortByTree); @@ -2452,9 +2416,9 @@ public class GAlignFrame extends JInternalFrame this.getContentPane().add(statusPanel, java.awt.BorderLayout.SOUTH); statusPanel.add(statusBar, null); this.getContentPane().add(tabbedPane, java.awt.BorderLayout.CENTER); - jMenu3.add(showAllColumns); - jMenu3.add(showAllSeqs); - jMenu3.add(showAllhidden); + showMenu.add(showAllColumns); + showMenu.add(showAllSeqs); + showMenu.add(showAllhidden); hideMenu.add(hideSelColumns); hideMenu.add(hideSelSequences); hideMenu.add(hideAllSelection); @@ -2509,18 +2473,6 @@ public class GAlignFrame extends JInternalFrame menuItem.addActionListener(actionListener); } - protected void viewAsCdna_actionPerformed() - { - } - - protected void alignCdna_actionPerformed() - { - } - - protected void linkCdna_actionPerformed() - { - } - /** * Action on clicking sort annotations by type. * @@ -3269,4 +3221,29 @@ public class GAlignFrame extends JInternalFrame { return statusPanel; } + + /** + * Sets a reference to the containing split frame. Also makes the 'toggle + * split view' menu item visible and checked. + * + * @param sf + */ + public void setSplitFrame(SplitContainerI sf) + { + this.splitFrame = sf; + if (sf != null) + { + this.showComplementMenuItem.setVisible(true); + this.showComplementMenuItem.setState(true); + } + } + + public SplitContainerI getSplitViewContainer() + { + return this.splitFrame; + } + + protected void showComplement_actionPerformed(boolean state) + { + } } diff --git a/src/jalview/jbgui/GSplitFrame.java b/src/jalview/jbgui/GSplitFrame.java index b2ecaeb..062fe9f 100644 --- a/src/jalview/jbgui/GSplitFrame.java +++ b/src/jalview/jbgui/GSplitFrame.java @@ -1,5 +1,6 @@ package jalview.jbgui; +import jalview.api.SplitContainerI; import jalview.util.Platform; import java.awt.Component; @@ -11,7 +12,7 @@ import javax.swing.JInternalFrame; import javax.swing.JSplitPane; import javax.swing.plaf.basic.BasicInternalFrameUI; -public class GSplitFrame extends JInternalFrame +public class GSplitFrame extends JInternalFrame implements SplitContainerI { private static final long serialVersionUID = 1L; @@ -106,9 +107,36 @@ public class GSplitFrame extends JInternalFrame private boolean isIn(Point loc, Component comp) { + if (!comp.isVisible()) + { + return false; + } Point p = comp.getLocationOnScreen(); Rectangle r = new Rectangle(p.x, p.y, comp.getWidth(), comp.getHeight()); return r.contains(loc); } + /** + * Make the complement of the specified split component visible or hidden, + * adjusting the position of the split divide. + */ + @Override + public void setComplementVisible(Object alignFrame, boolean show) + { + if (alignFrame == this.topFrame) + { + this.bottomFrame.setVisible(show); + } + else if (alignFrame == this.bottomFrame) + { + this.topFrame.setVisible(show); + } + if (show) + { + // SplitPane needs nudging to restore 50-50 split + splitPane.setDividerLocation(0.5d); + } + validate(); + } + } diff --git a/src/jalview/structure/SequenceListener.java b/src/jalview/structure/SequenceListener.java index 24c11e5..1306f9f 100644 --- a/src/jalview/structure/SequenceListener.java +++ b/src/jalview/structure/SequenceListener.java @@ -25,10 +25,12 @@ import jalview.datamodel.SequenceI; public interface SequenceListener { + // TODO remove this? never called on SequenceListener type public void mouseOverSequence(SequenceI sequence, int index, int pos); public void highlightSequence(jalview.datamodel.SearchResults results); + // TODO remove this? never called public void updateColours(SequenceI sequence, int index); public VamsasSource getVamsasSource(); diff --git a/src/jalview/structure/StructureSelectionManager.java b/src/jalview/structure/StructureSelectionManager.java index eb9abab..f564f63 100644 --- a/src/jalview/structure/StructureSelectionManager.java +++ b/src/jalview/structure/StructureSelectionManager.java @@ -1023,7 +1023,7 @@ public class StructureSelectionManager return this.commandListeners.contains(cl); } - public boolean removeEditListener(CommandListener l) + public boolean removeCommandListener(CommandListener l) { return commandListeners.remove(l); } diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java index 9a88a3f..d504093 100644 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@ -1404,10 +1404,8 @@ public abstract class AlignmentViewport implements AlignViewportI, AlignmentAnnotation[] annots = alignment.getAlignmentAnnotation(); for (int i = 0; i < sequences.length; i++) { - sequences[i] = new Sequence(sequences[i], annots); // construct new - // sequence with - // subset of visible - // annotation + // construct new sequence with subset of visible annotation + sequences[i] = new Sequence(sequences[i], annots); } } else diff --git a/src/jalview/ws/AWSThread.java b/src/jalview/ws/AWSThread.java index 0945b2a..1c9931d 100644 --- a/src/jalview/ws/AWSThread.java +++ b/src/jalview/ws/AWSThread.java @@ -90,6 +90,8 @@ public abstract class AWSThread extends Thread */ protected String WsUrl = null; + private boolean fromSplitFrame; + /** * generic web service job/subjob poll loop */ @@ -364,6 +366,7 @@ public abstract class AWSThread extends Thread { super(); // this.alignFrame = alframe; + this.fromSplitFrame = alframe.getSplitViewContainer() != null; currentView = alframe.getCurrentView().getAlignment(); featureSettings = alframe.getFeatureRenderer().getSettings(); defGapChar = alframe.getViewport().getGapCharacter(); @@ -381,4 +384,9 @@ public abstract class AWSThread extends Thread } } } + + protected boolean isFromSplitFrame() + { + return this.fromSplitFrame; + } } diff --git a/src/jalview/ws/jws2/MsaWSThread.java b/src/jalview/ws/jws2/MsaWSThread.java index 2bae428..60694e3 100644 --- a/src/jalview/ws/jws2/MsaWSThread.java +++ b/src/jalview/ws/jws2/MsaWSThread.java @@ -23,6 +23,7 @@ package jalview.ws.jws2; import jalview.analysis.AlignSeq; import jalview.bin.Cache; import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentOrder; import jalview.datamodel.AlignmentView; import jalview.datamodel.ColumnSelection; @@ -30,6 +31,7 @@ import jalview.datamodel.Sequence; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; import jalview.gui.Desktop; +import jalview.gui.SplitFrame; import jalview.gui.WebserviceInfo; import jalview.util.MessageManager; import jalview.ws.AWsJob; @@ -44,6 +46,8 @@ import java.util.List; import java.util.Map; import java.util.Vector; +import javax.swing.JInternalFrame; + import compbio.data.msa.MsaWS; import compbio.metadata.Argument; import compbio.metadata.ChunkHolder; @@ -892,10 +896,16 @@ class MsaWSThread extends AWS2Thread implements WSClientI wsInfo.setProgressBar(null, progbar); } + /** + * Display alignment results in a new frame (or - not currently supported - + * added to an existing alignment). + * + * @param newFrame + */ void displayResults(boolean newFrame) { // view input or result data for each block - Vector alorders = new Vector(); + List alorders = new ArrayList(); SequenceI[][] results = new SequenceI[jobs.length][]; AlignmentOrder[] orders = new AlignmentOrder[jobs.length]; String lastProgram = null; @@ -907,7 +917,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI msjob = (MsaWSJob) jobs[j]; Object[] res = msjob.getAlignment(); lastProgram = msjob.getAlignmentProgram(); - alorders.add(res[1]); + alorders.add((AlignmentOrder) res[1]); results[j] = (SequenceI[]) res[0]; orders[j] = (AlignmentOrder) res[1]; @@ -944,71 +954,115 @@ class MsaWSThread extends AWS2Thread implements WSClientI if (newFrame) { - AlignFrame af = new AlignFrame(al, columnselection, - AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + displayInNewFrame(al, alorders, columnselection); - // initialise with same renderer settings as in parent alignframe. - af.getFeatureRenderer().transferSettings(this.featureSettings); - // update orders - if (alorders.size() > 0) - { - if (alorders.size() == 1) - { - af.addSortByOrderMenuItem(WebServiceName + " Ordering", - (AlignmentOrder) alorders.get(0)); - } - else - { - // construct a non-redundant ordering set - Vector names = new Vector(); - for (int i = 0, l = alorders.size(); i < l; i++) - { - String orderName = new String(" Region " + i); - int j = i + 1; + } + else + { + System.out.println("MERGE WITH OLD FRAME"); + // TODO: modify alignment in original frame, replacing old for new + // alignment using the commands.EditCommand model to ensure the update can + // be undone + } + } - while (j < l) - { - if (((AlignmentOrder) alorders.get(i)) - .equals(((AlignmentOrder) alorders.get(j)))) - { - alorders.remove(j); - l--; - orderName += "," + j; - } - else - { - j++; - } - } + /** + * Display the alignment result in a new frame. + * + * @param al + * @param alorders + * @param columnselection + */ + protected void displayInNewFrame(AlignmentI al, + List alorders, ColumnSelection columnselection) + { + AlignFrame af = new AlignFrame(al, columnselection, + AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); - if (i == 0 && j == 1) - { - names.add(new String("")); - } - else - { - names.add(orderName); - } - } - for (int i = 0, l = alorders.size(); i < l; i++) - { - af.addSortByOrderMenuItem( - WebServiceName + ((String) names.get(i)) + " Ordering", - (AlignmentOrder) alorders.get(i)); - } - } - } + // initialise with same renderer settings as in parent alignframe. + af.getFeatureRenderer().transferSettings(this.featureSettings); + if (alorders.size() > 0) + { + addSortByMenuItems(af, alorders); + } + + /* + * If alignment was requested from one half of a SplitFrame, show in a + * SplitFrame with the other pane similarly aligned. + */ + if (this.isFromSplitFrame()) + { + // TODO will only work for protein, as it holds the codon frame mappings + // may need this thread to hold a reference to the requesting AlignFrame + AlignmentI complement = al.getAlignedComplement(al.getCodonFrames()); + AlignFrame af2 = new AlignFrame(complement, AlignFrame.DEFAULT_WIDTH, + AlignFrame.DEFAULT_HEIGHT); + String linkedTitle = MessageManager + .getString("label.linked_view_title"); + JInternalFrame splitFrame = new SplitFrame(al.isNucleotide() ? af + : af2, al.isNucleotide() ? af2 : af); + Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1); + } + else + { Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + } + } + /** + * Add sort order options to the AlignFrame menus. + * + * @param af + * @param alorders + */ + protected void addSortByMenuItems(AlignFrame af, + List alorders) + { + // update orders + if (alorders.size() == 1) + { + af.addSortByOrderMenuItem(WebServiceName + " Ordering", + alorders.get(0)); } else { - System.out.println("MERGE WITH OLD FRAME"); - // TODO: modify alignment in original frame, replacing old for new - // alignment using the commands.EditCommand model to ensure the update can - // be undone + // construct a non-redundant ordering set + List names = new ArrayList(); + for (int i = 0, l = alorders.size(); i < l; i++) + { + String orderName = " Region " + i; + int j = i + 1; + + while (j < l) + { + if (alorders.get(i).equals(alorders.get(j))) + { + alorders.remove(j); + l--; + orderName += "," + j; + } + else + { + j++; + } + } + + if (i == 0 && j == 1) + { + names.add(""); + } + else + { + names.add(orderName); + } + } + for (int i = 0, l = alorders.size(); i < l; i++) + { + af.addSortByOrderMenuItem(WebServiceName + (names.get(i)) + + " Ordering", alorders.get(i)); + } } } diff --git a/test/jalview/analysis/AlignmentUtilsTests.java b/test/jalview/analysis/AlignmentUtilsTests.java index d1300fe..c29658b 100644 --- a/test/jalview/analysis/AlignmentUtilsTests.java +++ b/test/jalview/analysis/AlignmentUtilsTests.java @@ -21,6 +21,7 @@ package jalview.analysis; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import jalview.analysis.AlignmentUtils.MappingResult; import jalview.datamodel.AlignedCodonFrame; @@ -481,4 +482,29 @@ public class AlignmentUtilsTests checkAlignSequenceAs("GG-G-AA-A-C-CC-T-TT", "AL", false, true, map, "GG-G-AA-ACCCTTT"); } + + /** + * Test for the method that generates an aligned translated sequence from one + * mapping. + */ + @Test + public void testGetAlignedTranslation_dnaLikeProtein() + { + // dna alignment will be replaced + SequenceI dna = new Sequence("Seq1", "T-G-CC-A--T-TAC-CAG-"); + dna.createDatasetSequence(); + // protein alignment will be 'applied' to dna + SequenceI protein = new Sequence("Seq1", "-CH-Y--Q-"); + protein.createDatasetSequence(); + MapList map = new MapList(new int[] + { 1, 12 }, new int[] + { 1, 4 }, 3, 1); + AlignedCodonFrame acf = new AlignedCodonFrame(); + acf.addMap(dna.getDatasetSequence(), protein.getDatasetSequence(), map); + + final SequenceI aligned = AlignmentUtils + .getAlignedTranslation(protein, '-', acf); + assertEquals("---TGCCAT---TAC------CAG---", aligned.getSequenceAsString()); + assertSame(aligned.getDatasetSequence(), dna.getDatasetSequence()); + } } diff --git a/test/jalview/datamodel/SearchResultsTest.java b/test/jalview/datamodel/SearchResultsTest.java new file mode 100644 index 0000000..3738614 --- /dev/null +++ b/test/jalview/datamodel/SearchResultsTest.java @@ -0,0 +1,24 @@ +package jalview.datamodel; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class SearchResultsTest +{ + + @Test + public void testToString() + { + SequenceI seq = new Sequence("", "abcdefghijklm"); + SearchResults sr = new SearchResults(); + sr.addResult(seq, 0, 0); + assertEquals("a", sr.toString()); + sr.addResult(seq, 2, 4); + assertEquals("acde", sr.toString()); + + seq = new Sequence("", "pqrstuvwxy"); + sr.addResult(seq, 5, 6); + assertEquals("acdeuv", sr.toString()); + } +} -- 1.7.10.2