JAL-845 SplitFrame for "show product" and after aligning from SplitFrame
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 27 Feb 2015 14:43:36 +0000 (14:43 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 27 Feb 2015 14:43:36 +0000 (14:43 +0000)
23 files changed:
resources/lang/Messages.properties
src/jalview/analysis/AlignmentUtils.java
src/jalview/api/SplitContainerI.java [new file with mode: 0644]
src/jalview/appletgui/SeqCanvas.java
src/jalview/commands/EditCommand.java
src/jalview/datamodel/AlignedCodonFrame.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/AlignmentI.java
src/jalview/datamodel/SearchResults.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/AlignmentPanel.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/SplitFrame.java
src/jalview/jbgui/GAlignFrame.java
src/jalview/jbgui/GSplitFrame.java
src/jalview/structure/SequenceListener.java
src/jalview/structure/StructureSelectionManager.java
src/jalview/viewmodel/AlignmentViewport.java
src/jalview/ws/AWSThread.java
src/jalview/ws/jws2/MsaWSThread.java
test/jalview/analysis/AlignmentUtilsTests.java
test/jalview/datamodel/SearchResultsTest.java [new file with mode: 0644]

index 6f47422..b12d163 100644 (file)
@@ -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.<br>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
index 0441b1d..0ae782e 100644 (file)
@@ -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<SequenceI> getAlignedTranslation(
+          List<SequenceI> sequences, char gapCharacter,
+          Set<AlignedCodonFrame> mappings)
+  {
+    List<SequenceI> alignedSeqs = new ArrayList<SequenceI>();
+
+    for (SequenceI seq : sequences)
+    {
+      List<SequenceI> 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<SequenceI> getAlignedTranslation(SequenceI seq,
+          char gapCharacter, Set<AlignedCodonFrame> mappings)
+  {
+    List<SequenceI> result = new ArrayList<SequenceI>();
+    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 (file)
index 0000000..22f5201
--- /dev/null
@@ -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);
+
+}
index ec94c6f..4cf1996 100755 (executable)
@@ -280,6 +280,7 @@ public class SeqCanvas extends Panel
     paint(g);
   }
 
+  @Override
   public void paint(Graphics g)
   {
 
index 38a45ce..b2ecb7e 100644 (file)
@@ -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()
index d3f6ad5..9c17306 100644 (file)
@@ -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
index cb571ac..56545e1 100755 (executable)
@@ -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<AlignedCodonFrame> 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<SequenceI> 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;
+  }
 }
index fe93683..eb396ad 100755 (executable)
@@ -517,4 +517,13 @@ public interface AlignmentI extends AnnotatedCollectionI
    * @return
    */
   Set<String> 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<AlignedCodonFrame> codonFrames);
 }
index 7a241fd..a53d103 100755 (executable)
@@ -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();
+  }
 }
index 38940d2..2b92142 100644 (file)
@@ -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<SequenceI> seqs = new ArrayList<SequenceI>(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<AlignedCodonFrame> 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);
+    }
   }
 }
 
index 4ba2113..cad90e3 100644 (file)
@@ -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;
   }
 
index 7132ff0..ccbc031 100644 (file)
@@ -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);
index b30b28f..8342151 100644 (file)
@@ -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);
index e441371..81a6ddc 100644 (file)
@@ -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.
index 4b36729..d9c87cb 100755 (executable)
@@ -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<KeyStroke, JMenuItem> accelerators = new HashMap<KeyStroke, JMenuItem>();
 
+  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)
+  {
+  }
 }
index b2ecaeb..062fe9f 100644 (file)
@@ -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();
+  }
+
 }
index 24c11e5..1306f9f 100644 (file)
@@ -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();
index eb9abab..f564f63 100644 (file)
@@ -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);
   }
index 9a88a3f..d504093 100644 (file)
@@ -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
index 0945b2a..1c9931d 100644 (file)
@@ -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;
+  }
 }
index 2bae428..60694e3 100644 (file)
@@ -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<AlignmentOrder> alorders = new ArrayList<AlignmentOrder>();
     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<AlignmentOrder> 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<AlignmentOrder> 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<String> names = new ArrayList<String>();
+      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));
+      }
     }
   }
 
index d1300fe..c29658b 100644 (file)
@@ -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 (file)
index 0000000..3738614
--- /dev/null
@@ -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());
+  }
+}