Displays a split window view of protein and its related cDNA
+
+
diff --git a/examples/applets.html b/examples/applets.html
index 9d94c69..b557efc 100755
--- a/examples/applets.html
+++ b/examples/applets.html
@@ -313,6 +313,29 @@ Try out JalviewLite by pressing one of the buttons below.
secondary structure annotation
+
+
Linked amino acid and cDNA alignments for homologous proteins
+
+
+
+
+
+
Displays a split window view of protein and its related cDNA
Hidden Sequence Representatives and Multiple
Views
diff --git a/lib/jersey-client-1.19.jar b/lib/jersey-client-1.19.jar
new file mode 100644
index 0000000..c9e0f56
Binary files /dev/null and b/lib/jersey-client-1.19.jar differ
diff --git a/lib/jersey-core-1.19.jar b/lib/jersey-core-1.19.jar
new file mode 100644
index 0000000..92feb63
Binary files /dev/null and b/lib/jersey-core-1.19.jar differ
diff --git a/lib/jersey-json-1.19.jar b/lib/jersey-json-1.19.jar
new file mode 100644
index 0000000..b609411
Binary files /dev/null and b/lib/jersey-json-1.19.jar differ
diff --git a/lib/jsr311-api-1.1.1.jar b/lib/jsr311-api-1.1.1.jar
new file mode 100644
index 0000000..ec8bc81
Binary files /dev/null and b/lib/jsr311-api-1.1.1.jar differ
diff --git a/resources/images/dna.png b/resources/images/dna.png
new file mode 100644
index 0000000..f9854fe
Binary files /dev/null and b/resources/images/dna.png differ
diff --git a/resources/images/error.png b/resources/images/error.png
new file mode 100644
index 0000000..6d68a8c
Binary files /dev/null and b/resources/images/error.png differ
diff --git a/resources/images/good.png b/resources/images/good.png
new file mode 100644
index 0000000..ebbacc9
Binary files /dev/null and b/resources/images/good.png differ
diff --git a/resources/images/loading.gif b/resources/images/loading.gif
new file mode 100644
index 0000000..23ed238
Binary files /dev/null and b/resources/images/loading.gif differ
diff --git a/resources/images/protein.png b/resources/images/protein.png
new file mode 100644
index 0000000..3789793
Binary files /dev/null and b/resources/images/protein.png differ
diff --git a/resources/images/sugar.png b/resources/images/sugar.png
new file mode 100644
index 0000000..5d62ce5
Binary files /dev/null and b/resources/images/sugar.png differ
diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties
index 2e37e06..0d3d491 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
@@ -228,14 +229,17 @@ label.documentation = Documentation
label.about = About...
label.show_sequence_limits = Show Sequence Limits
label.feature_settings = Feature Settings...
-label.sequence_features = Sequence Features
label.all_columns = All Columns
label.all_sequences = All Sequences
label.selected_columns = Selected Columns
label.selected_sequences = Selected Sequences
+label.except_selected_sequences = All except selected sequences
label.all_but_selected_region = All but Selected Region (Shift+Ctrl+H)
label.selected_region = Selected Region
label.all_sequences_columns = All Sequences and Columns
+label.hide_insertions = Hide columns gapped for selection
+label.hide_selected_annotations = Hide selected annotations
+label.show_selected_annotations = Show selected annotations
label.group_consensus = Group Consensus
label.group_conservation = Group Conservation
label.show_consensus_histogram = Show Consensus Histogram
@@ -382,6 +386,7 @@ label.automatically_associate_pdb_files_with_sequences_same_name = Do you want t
label.automatically_associate_pdb_files_by_name = Automatically Associate PDB files by name
label.ignore_unmatched_dropped_files_info = Do you want to ignore the {0} files whose names did not match any sequence IDs ?
label.ignore_unmatched_dropped_files = Ignore unmatched dropped files?
+label.view_name_original = Original
label.enter_view_name = Enter View Name
label.enter_label = Enter label
label.enter_label_for_the_structure = Enter a label for the structure?
@@ -480,8 +485,6 @@ label.load_associated_tree = Load Associated Tree ...
label.load_features_annotations = Load Features/Annotations ...
label.export_features = Export Features ...
label.export_annotations = Export Annotations ...
-label.jalview_copy = Copy (Jalview Only)
-label.jalview_cut = Cut (Jalview Only)
label.to_upper_case = To Upper Case
label.to_lower_case = To Lower Case
label.toggle_case = Toggle Case
@@ -576,7 +579,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)
@@ -671,7 +675,7 @@ label.view_structure = View Structure
label.clustalx_colours = Clustalx colours
label.above_identity_percentage = Above % Identity
label.create_sequence_details_report_annotation_for = Annotation for {0}
-label.sequece_details_for = Sequece Details for {0}
+label.sequence_details_for = Sequence Details for {0}
label.sequence_name = Sequence Name
label.sequence_description = Sequence Description
label.edit_sequence_name_description = Edit Sequence Name/Description
@@ -689,12 +693,15 @@ label.save_png_image = Save As PNG Image
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 cDNA
+label.translate_cDNA = Translate as cDNA
+label.linked_view_title = Linked cDNA and protein view
+label.align = Align
label.extract_scores = Extract Scores
label.get_cross_refs = Get Cross References
label.sort_alignment_new_tree = Sort Alignment With New Tree
label.add_sequences = Add Sequences
label.new_window = New Window
+label.split_window = Split Window
label.refresh_available_sources = Refresh Available Sources
label.use_registry = Use Registry
label.add_local_source = Add Local Source
@@ -734,6 +741,7 @@ label.paste_new_window = Paste To New Window
label.settings_for_param = Settings for {0}
label.view_params = View {0}
label.select_all_views = Select all views
+label.all_views = All Views
label.align_sequences_to_existing_alignment = Align sequences to an existing alignment
label.realign_with_params = Realign with {0}
label.calcname_with_default_settings = {0} with Defaults
@@ -775,7 +783,6 @@ label.use_sequence_id_1 = Use $SEQUENCE_ID$ or $SEQUENCE_ID=//=$
label.use_sequence_id_2 = \nto embed sequence id in URL
label.ws_parameters_for = Parameters for {0}
label.switch_server = Switch server
-label.open_jabaws_web_page = Opens the JABAWS server's homepage in web browser
label.choose_jabaws_server = Choose a server for running this service
label.services_at = Services at {0}
label.rest_client_submit = {0} using {1}
@@ -1178,6 +1185,13 @@ label.show_logo = Show Logo
label.normalise_logo = Normalise Logo
label.no_colour_selection_in_scheme = Please, make a colour selection before to apply colour scheme
label.no_colour_selection_warn = Error saving colour scheme
+label.open_split_window? = Would you like to open as a split window, with cDNA and protein linked?
+label.open_split_window = Open split window
+label.no_mappings = No mappings found
+label.mapping_failed = No sequence mapping could be made between the alignments. A mapping requires sequence names to match, and equivalent sequence lengths.
+action.no = No
+action.yes = Yes
+label.for = for
label.select_by_annotation = Select By Annotation
action.select_by_annotation = Select by Annotation...
label.threshold_filter = Threshold Filter
@@ -1192,3 +1206,22 @@ label.search_filter = Search Filter
label.display_name = Display Label
label.description = Description
label.include_description= Include Description
+action.back = Back
+label.hide_insertions = Hide Insertions
+label.mark_as_representative = Mark as representative
+label.open_jabaws_web_page = Open JABAWS web page
+label.opens_the_jabaws_server_homepage = Opens the JABAWS server's homepage in web browser
+label.pdb_sequence_getcher = PDB Sequence Fetcher
+label.result = result
+label.results = results
+label.structure_chooser = Structure Chooser
+label.select = Select :
+label.invert = Invert
+label.select_pdb_file = Select PDB File
+info.select_filter_option = Select Filter Option/Manual Entry
+info.associate_wit_sequence = Associate with Sequence
+label.search_result = Search Result
+label.found_structures_summary = Found Structures Summary
+label.configure_displayed_columns = Configure Displayed Columns
+label.start_jalview = Start Jalview
+label.biojs_html_export = BioJS
diff --git a/schemas/jalview.xsd b/schemas/jalview.xsd
index f2ba0a5..d643648 100755
--- a/schemas/jalview.xsd
+++ b/schemas/jalview.xsd
@@ -359,12 +359,11 @@
type="xs:boolean" use="optional" default="true" />
-
+
-
-
+
@@ -388,6 +387,14 @@
+
+
+
+ The viewport id of this viewport's (cdna/protein) coding complement, if any
+
+
+ atoms)
{
if (!seqColoursReady)
{
return;
}
-
- if (highlightRes != null && highlightRes.contains((atomIndex - 1) + ""))
+ for (AtomSpec atom : atoms)
{
- return;
+ int atomIndex = atom.getAtomIndex();
+
+ if (highlightRes != null
+ && highlightRes.contains((atomIndex - 1) + ""))
+ {
+ continue;
+ }
+
+ highlightAtom(atomIndex);
}
+ redrawneeded = true;
+ repaint();
+ }
+
+ /**
+ * @param atomIndex
+ */
+ protected void highlightAtom(int atomIndex)
+ {
int index = -1;
Bond tmpBond;
for (index = 0; index < mainchain.bonds.size(); index++)
@@ -1178,9 +1218,6 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
break;
}
}
-
- redrawneeded = true;
- repaint();
}
public Color getColour(int atomIndex, int pdbResNum, String chain,
diff --git a/src/MCview/Atom.java b/src/MCview/Atom.java
index b600bc9..9cbcebb 100755
--- a/src/MCview/Atom.java
+++ b/src/MCview/Atom.java
@@ -20,7 +20,7 @@
*/
package MCview;
-import java.awt.*;
+import java.awt.Color;
public class Atom
{
@@ -77,16 +77,16 @@ public class Atom
chain = str.substring(21, 22);
resNumber = Integer.parseInt(str.substring(22, 26).trim());
- resNumIns = str.substring(22, 27);
+ resNumIns = str.substring(22, 27).trim();
insCode = str.substring(26, 27).charAt(0);
- this.x = (float) (new Float(str.substring(30, 38).trim()).floatValue());
- this.y = (float) (new Float(str.substring(38, 46).trim()).floatValue());
- this.z = (float) (new Float(str.substring(47, 55).trim()).floatValue());
+ this.x = (new Float(str.substring(30, 38).trim()).floatValue());
+ this.y = (new Float(str.substring(38, 46).trim()).floatValue());
+ this.z = (new Float(str.substring(47, 55).trim()).floatValue());
// optional entries - see JAL-730
String tm = str.substring(54, 60).trim();
if (tm.length() > 0)
{
- occupancy = (float) (new Float(tm)).floatValue();
+ occupancy = (new Float(tm)).floatValue();
}
else
{
@@ -96,7 +96,7 @@ public class Atom
tm = str.substring(60, 66).trim();
if (tm.length() > 0)
{
- tfactor = (float) (new Float(tm).floatValue());
+ tfactor = (new Float(tm).floatValue());
}
else
{
diff --git a/src/MCview/PDBCanvas.java b/src/MCview/PDBCanvas.java
index f6e6427..6f76a25 100644
--- a/src/MCview/PDBCanvas.java
+++ b/src/MCview/PDBCanvas.java
@@ -20,18 +20,37 @@
*/
package MCview;
-import java.io.*;
-import java.util.*;
-
+import jalview.analysis.AlignSeq;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignmentPanel;
+import jalview.gui.FeatureRenderer;
+import jalview.gui.SequenceRenderer;
+import jalview.structure.AtomSpec;
+import jalview.structure.StructureListener;
+import jalview.structure.StructureMapping;
+import jalview.structure.StructureSelectionManager;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Event;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
// JBPNote TODO: This class is quite noisy - needs proper log.info/log.debug
-import java.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-
-import jalview.analysis.*;
-import jalview.datamodel.*;
-import jalview.gui.*;
-import jalview.structure.*;
+import java.awt.Image;
+import java.awt.RenderingHints;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.io.PrintStream;
+import java.util.List;
+import java.util.Vector;
+
+import javax.swing.JPanel;
+import javax.swing.ToolTipManager;
public class PDBCanvas extends JPanel implements MouseListener,
MouseMotionListener, StructureListener
@@ -134,7 +153,9 @@ public class PDBCanvas extends JPanel implements MouseListener,
pdb = ssm.setMapping(seq, chains, pdbentry.getFile(), protocol);
if (protocol.equals(jalview.io.AppletFormatAdapter.PASTE))
+ {
pdbentry.setFile("INLINE" + pdb.id);
+ }
} catch (Exception ex)
{
@@ -167,17 +188,17 @@ public class PDBCanvas extends JPanel implements MouseListener,
{
mappingDetails.append("\n\nPDB Sequence is :\nSequence = "
- + ((PDBChain) pdb.chains.elementAt(i)).sequence
+ + pdb.chains.elementAt(i).sequence
.getSequenceAsString());
mappingDetails.append("\nNo of residues = "
- + ((PDBChain) pdb.chains.elementAt(i)).residues.size()
+ + pdb.chains.elementAt(i).residues.size()
+ "\n\n");
// Now lets compare the sequences to get
// the start and end points.
// Align the sequence to the pdb
AlignSeq as = new AlignSeq(sequence,
- ((PDBChain) pdb.chains.elementAt(i)).sequence, "pep");
+ pdb.chains.elementAt(i).sequence, "pep");
as.calcScoreMatrix();
as.traceAlignment();
PrintStream ps = new PrintStream(System.out)
@@ -210,7 +231,7 @@ public class PDBCanvas extends JPanel implements MouseListener,
mappingDetails.append("\nSEQ start/end " + seqstart + " " + seqend);
}
- mainchain = (PDBChain) pdb.chains.elementAt(maxchain);
+ mainchain = pdb.chains.elementAt(maxchain);
mainchain.pdbstart = pdbstart;
mainchain.pdbend = pdbend;
@@ -254,9 +275,9 @@ public class PDBCanvas extends JPanel implements MouseListener,
for (int ii = 0; ii < pdb.chains.size(); ii++)
{
- if (((PDBChain) pdb.chains.elementAt(ii)).isVisible)
+ if (pdb.chains.elementAt(ii).isVisible)
{
- Vector tmp = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
+ Vector tmp = pdb.chains.elementAt(ii).bonds;
for (int i = 0; i < tmp.size(); i++)
{
@@ -286,9 +307,9 @@ public class PDBCanvas extends JPanel implements MouseListener,
for (int ii = 0; ii < pdb.chains.size(); ii++)
{
- if (((PDBChain) pdb.chains.elementAt(ii)).isVisible)
+ if (pdb.chains.elementAt(ii).isVisible)
{
- Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
+ Vector bonds = pdb.chains.elementAt(ii).bonds;
for (int i = 0; i < bonds.size(); i++)
{
@@ -362,9 +383,9 @@ public class PDBCanvas extends JPanel implements MouseListener,
* System.out.println("zmax " + max[2] + " min " + min[2]);
*/
- width[0] = (float) Math.abs(max[0] - min[0]);
- width[1] = (float) Math.abs(max[1] - min[1]);
- width[2] = (float) Math.abs(max[2] - min[2]);
+ width[0] = Math.abs(max[0] - min[0]);
+ width[1] = Math.abs(max[1] - min[1]);
+ width[2] = Math.abs(max[2] - min[2]);
maxwidth = width[0];
@@ -421,9 +442,9 @@ public class PDBCanvas extends JPanel implements MouseListener,
// Find centre coordinate
for (int ii = 0; ii < pdb.chains.size(); ii++)
{
- if (((PDBChain) pdb.chains.elementAt(ii)).isVisible)
+ if (pdb.chains.elementAt(ii).isVisible)
{
- Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
+ Vector bonds = pdb.chains.elementAt(ii).bonds;
bsize += bonds.size();
@@ -537,7 +558,7 @@ public class PDBCanvas extends JPanel implements MouseListener,
{
for (int ii = 0; ii < pdb.chains.size(); ii++)
{
- chain = (PDBChain) pdb.chains.elementAt(ii);
+ chain = pdb.chains.elementAt(ii);
for (int i = 0; i < chain.bonds.size(); i++)
{
@@ -751,7 +772,7 @@ public class PDBCanvas extends JPanel implements MouseListener,
repaint();
if (foundchain != -1)
{
- PDBChain chain = (PDBChain) pdb.chains.elementAt(foundchain);
+ PDBChain chain = pdb.chains.elementAt(foundchain);
if (chain == mainchain)
{
if (fatom.alignmentMapping != -1)
@@ -797,7 +818,7 @@ public class PDBCanvas extends JPanel implements MouseListener,
PDBChain chain = null;
if (foundchain != -1)
{
- chain = (PDBChain) pdb.chains.elementAt(foundchain);
+ chain = pdb.chains.elementAt(foundchain);
if (chain == mainchain)
{
mouseOverStructure(fatom.resNumber, chain.id);
@@ -840,18 +861,18 @@ public class PDBCanvas extends JPanel implements MouseListener,
if ((evt.getModifiers() & Event.META_MASK) != 0)
{
- objmat.rotatez((float) ((mx - omx)));
+ objmat.rotatez(((mx - omx)));
}
else
{
- objmat.rotatex((float) ((my - omy)));
- objmat.rotatey((float) ((omx - mx)));
+ objmat.rotatex(((my - omy)));
+ objmat.rotatey(((omx - mx)));
}
// Alter the bonds
for (int ii = 0; ii < pdb.chains.size(); ii++)
{
- Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
+ Vector bonds = pdb.chains.elementAt(ii).bonds;
for (int i = 0; i < bonds.size(); i++)
{
@@ -892,11 +913,11 @@ public class PDBCanvas extends JPanel implements MouseListener,
for (int ii = 0; ii < pdb.chains.size(); ii++)
{
- PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
+ PDBChain chain = pdb.chains.elementAt(ii);
if (chain.isVisible)
{
- Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
+ Vector bonds = pdb.chains.elementAt(ii).bonds;
for (int i = 0; i < bonds.size(); i++)
{
@@ -948,13 +969,13 @@ public class PDBCanvas extends JPanel implements MouseListener,
for (int ii = 0; ii < pdb.chains.size(); ii++)
{
- PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
+ PDBChain chain = pdb.chains.elementAt(ii);
int truex;
Bond tmpBond = null;
if (chain.isVisible)
{
- Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
+ Vector bonds = pdb.chains.elementAt(ii).bonds;
for (int i = 0; i < bonds.size(); i++)
{
@@ -995,7 +1016,7 @@ public class PDBCanvas extends JPanel implements MouseListener,
if (fatom != null) // )&& chain.ds != null)
{
- chain = (PDBChain) pdb.chains.elementAt(foundchain);
+ chain = pdb.chains.elementAt(foundchain);
}
}
@@ -1060,7 +1081,7 @@ public class PDBCanvas extends JPanel implements MouseListener,
{
for (int ii = 0; ii < pdb.chains.size(); ii++)
{
- PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
+ PDBChain chain = pdb.chains.elementAt(ii);
chain.isVisible = b;
}
mainchain.isVisible = true;
@@ -1081,7 +1102,9 @@ public class PDBCanvas extends JPanel implements MouseListener,
public void mouseOverStructure(int pdbResNum, String chain)
{
if (lastMessage == null || !lastMessage.equals(pdbResNum + chain))
+ {
ssm.mouseOverStructure(pdbResNum, chain, pdbentry.getFile());
+ }
lastMessage = pdbResNum + chain;
}
@@ -1090,19 +1113,42 @@ public class PDBCanvas extends JPanel implements MouseListener,
StringBuffer eval = new StringBuffer();
- public void highlightAtom(int atomIndex, int pdbResNum, String chain,
- String pdbfile)
+ /**
+ * Highlight the specified atoms in the structure.
+ *
+ * @param atoms
+ */
+ @Override
+ public void highlightAtoms(List atoms)
{
if (!seqColoursReady)
{
return;
}
- if (highlightRes != null && highlightRes.contains((atomIndex - 1) + ""))
+ for (AtomSpec atom : atoms)
{
- return;
+ int atomIndex = atom.getAtomIndex();
+ if (highlightRes != null
+ && highlightRes.contains((atomIndex - 1) + ""))
+ {
+ continue;
+ }
+
+ highlightAtom(atomIndex);
}
+ redrawneeded = true;
+ repaint();
+ }
+
+ /**
+ * Highlight the atom at the specified index.
+ *
+ * @param atomIndex
+ */
+ protected void highlightAtom(int atomIndex)
+ {
int index = -1;
Bond tmpBond;
for (index = 0; index < mainchain.bonds.size(); index++)
@@ -1138,9 +1184,6 @@ public class PDBCanvas extends JPanel implements MouseListener,
break;
}
}
-
- redrawneeded = true;
- repaint();
}
public Color getColour(int atomIndex, int pdbResNum, String chain,
diff --git a/src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java b/src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java
index 2c40e1c..b74e65a 100644
--- a/src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java
+++ b/src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java
@@ -783,8 +783,8 @@ public class ChimeraManager
List reply = new ArrayList();
BufferedReader response = null;
try {
- response = HttpClientUtils.doHttpUrlPost(restUrl,
- commands);
+ response = HttpClientUtils
+ .doHttpUrlPost(restUrl, commands, 100, 2000);
String line = "";
while ((line = response.readLine()) != null) {
reply.add(line);
diff --git a/src/ext/vamsas/ServiceHandle.java b/src/ext/vamsas/ServiceHandle.java
index 442e5f7..83412ea 100755
--- a/src/ext/vamsas/ServiceHandle.java
+++ b/src/ext/vamsas/ServiceHandle.java
@@ -128,15 +128,15 @@ public class ServiceHandle implements java.io.Serializable
public synchronized boolean equals(java.lang.Object obj)
{
- if (!(obj instanceof ServiceHandle))
+ if (obj == null)
{
return false;
}
- ServiceHandle other = (ServiceHandle) obj;
- if (obj == null)
+ if (!(obj instanceof ServiceHandle))
{
return false;
}
+ ServiceHandle other = (ServiceHandle) obj;
if (this == obj)
{
return true;
diff --git a/src/ext/vamsas/ServiceHandles.java b/src/ext/vamsas/ServiceHandles.java
index 45c49d8..5ed466f 100755
--- a/src/ext/vamsas/ServiceHandles.java
+++ b/src/ext/vamsas/ServiceHandles.java
@@ -57,15 +57,15 @@ public class ServiceHandles implements java.io.Serializable
public synchronized boolean equals(java.lang.Object obj)
{
- if (!(obj instanceof ServiceHandles))
+ if (obj == null)
{
return false;
}
- ServiceHandles other = (ServiceHandles) obj;
- if (obj == null)
+ if (!(obj instanceof ServiceHandles))
{
return false;
}
+ ServiceHandles other = (ServiceHandles) obj;
if (this == obj)
{
return true;
diff --git a/src/jalview/analysis/AAFrequency.java b/src/jalview/analysis/AAFrequency.java
index b96bf8e..d6088e4 100755
--- a/src/jalview/analysis/AAFrequency.java
+++ b/src/jalview/analysis/AAFrequency.java
@@ -20,10 +20,19 @@
*/
package jalview.analysis;
-import java.util.*;
-
+import jalview.datamodel.AlignedCodonFrame;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.SequenceI;
import jalview.util.Format;
-import jalview.datamodel.*;
+import jalview.util.MappingUtils;
+import jalview.util.QuickSort;
+
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
/**
* Takes in a vector or array of sequences and column start and column end and
@@ -36,8 +45,8 @@ import jalview.datamodel.*;
*/
public class AAFrequency
{
- // No need to store 1000s of strings which are not
- // visible to the user.
+ private static final int TO_UPPER_CASE = 'A' - 'a'; // -32
+
public static final String MAXCOUNT = "C";
public static final String MAXRESIDUE = "R";
@@ -48,6 +57,21 @@ public class AAFrequency
public static final String PROFILE = "P";
+ public static final String ENCODED_CHARS = "E";
+
+ /*
+ * Quick look-up of String value of char 'A' to 'Z'
+ */
+ private static final String[] CHARS = new String['Z' - 'A' + 1];
+
+ static
+ {
+ for (char c = 'A'; c <= 'Z'; c++)
+ {
+ CHARS[c - 'A'] = String.valueOf(c);
+ }
+ }
+
public static final Hashtable[] calculate(List list,
int start, int end)
{
@@ -83,16 +107,11 @@ public class AAFrequency
}
public static final void calculate(SequenceI[] sequences, int start,
- int end, Hashtable[] result)
- {
- calculate(sequences, start, end, result, false);
- }
-
- public static final void calculate(SequenceI[] sequences, int start,
int end, Hashtable[] result, boolean profile)
{
Hashtable residueHash;
- int maxCount, nongap, i, j, v, jSize = sequences.length;
+ int maxCount, nongap, i, j, v;
+ int jSize = sequences.length;
String maxResidue;
char c = '-';
float percentage;
@@ -134,7 +153,7 @@ public class AAFrequency
}
else if ('a' <= c && c <= 'z')
{
- c -= 32; // ('a' - 'A');
+ c += TO_UPPER_CASE;
}
nongap++;
@@ -153,20 +172,21 @@ public class AAFrequency
}
else
{
- for (v = 'A'; v < 'Z'; v++)
+ for (v = 'A'; v <= 'Z'; v++)
{
- if (values[v] < 2 || values[v] < maxCount)
+ // TODO why ignore values[v] == 1?
+ if (values[v] < 1 /* 2 */|| values[v] < maxCount)
{
continue;
}
if (values[v] > maxCount)
{
- maxResidue = String.valueOf((char) v);
+ maxResidue = CHARS[v - 'A'];
}
else if (values[v] == maxCount)
{
- maxResidue += String.valueOf((char) v);
+ maxResidue += CHARS[v - 'A'];
}
maxCount = values[v];
}
@@ -177,6 +197,7 @@ public class AAFrequency
}
if (profile)
{
+ // TODO use a 1-dimensional array with jSize, nongap in [0] and [1]
residueHash.put(PROFILE, new int[][]
{ values, new int[]
{ jSize, nongap } });
@@ -218,17 +239,37 @@ public class AAFrequency
{
completeConsensus(consensus, hconsensus, iStart, width,
ignoreGapsInConsensusCalculation, includeAllConsSymbols, null,
- nseq); // new
- // char[]
- // { 'A', 'C', 'G', 'T', 'U' });
+ nseq);
}
+ /**
+ * Derive the consensus annotations to be added to the alignment for display.
+ * This does not recompute the raw data, but may be called on a change in
+ * display options, such as 'show logo', which may in turn result in a change
+ * in the derived values.
+ *
+ * @param consensus
+ * the annotation row to add annotations to
+ * @param hconsensus
+ * the source consensus data
+ * @param iStart
+ * start column
+ * @param width
+ * end column
+ * @param ignoreGapsInConsensusCalculation
+ * if true, use the consensus calculated ignoring gaps
+ * @param includeAllConsSymbols
+ * if true include all consensus symbols, else just show modal
+ * residue
+ * @param alphabet
+ * @param nseq
+ * number of sequences
+ */
public static void completeConsensus(AlignmentAnnotation consensus,
Hashtable[] hconsensus, int iStart, int width,
boolean ignoreGapsInConsensusCalculation,
boolean includeAllConsSymbols, char[] alphabet, long nseq)
{
- float tval, value;
if (consensus == null || consensus.annotations == null
|| consensus.annotations.length < width)
{
@@ -236,26 +277,9 @@ public class AAFrequency
// initialised properly
return;
}
- String fmtstr = "%3.1f";
- int precision = 0;
- while (nseq >= 10)
- {
- precision++;
- nseq /= 10;
- }
- final Format fmt;
- if (precision > 1)
- {
- // if (precision>2)
- {
- fmtstr = "%" + (2 + precision) + "." + (precision) + "f";
- }
- fmt = new Format(fmtstr);
- }
- else
- {
- fmt = null;
- }
+
+ final Format fmt = getPercentageFormat(nseq);
+
for (int i = iStart; i < width; i++)
{
Hashtable hci;
@@ -266,119 +290,377 @@ public class AAFrequency
consensus.annotations[i] = null;
continue;
}
- value = 0;
- Float fv;
- if (ignoreGapsInConsensusCalculation)
- {
- fv = (Float) hci.get(AAFrequency.PID_NOGAPS);
- }
- else
- {
- fv = (Float) hci.get(AAFrequency.PID_GAPS);
- }
+ Float fv = (Float) hci
+ .get(ignoreGapsInConsensusCalculation ? PID_NOGAPS : PID_GAPS);
if (fv == null)
{
consensus.annotations[i] = null;
// data has changed below us .. give up and
continue;
}
- value = fv.floatValue();
+ float value = fv.floatValue();
String maxRes = hci.get(AAFrequency.MAXRESIDUE).toString();
- String mouseOver = hci.get(AAFrequency.MAXRESIDUE) + " ";
+ StringBuilder mouseOver = new StringBuilder(64);
if (maxRes.length() > 1)
{
- mouseOver = "[" + maxRes + "] ";
+ mouseOver.append("[").append(maxRes).append("] ");
maxRes = "+";
}
+ else
+ {
+ mouseOver.append(hci.get(AAFrequency.MAXRESIDUE) + " ");
+ }
int[][] profile = (int[][]) hci.get(AAFrequency.PROFILE);
+ int sequenceCount = profile[1][0];
+ int nonGappedCount = profile[1][1];
+ int normalisedBy = ignoreGapsInConsensusCalculation ? nonGappedCount
+ : sequenceCount;
if (profile != null && includeAllConsSymbols)
{
- mouseOver = "";
+ mouseOver.setLength(0);
if (alphabet != null)
{
for (int c = 0; c < alphabet.length; c++)
{
- tval = profile[0][alphabet[c]] * 100f
- / profile[1][ignoreGapsInConsensusCalculation ? 1 : 0];
- mouseOver += ((c == 0) ? "" : "; ") + alphabet[c] + " "
- + ((fmt != null) ? fmt.form(tval) : ((int) tval)) + "%";
+ float tval = profile[0][alphabet[c]] * 100f / normalisedBy;
+ mouseOver
+ .append(((c == 0) ? "" : "; "))
+ .append(alphabet[c])
+ .append(" ")
+ .append(((fmt != null) ? fmt.form(tval) : ((int) tval)))
+ .append("%");
}
}
else
{
- Object[] ca = new Object[profile[0].length];
+ // TODO do this sort once only in calculate()?
+ // char[][] ca = new char[profile[0].length][];
+ char[] ca = new char[profile[0].length];
float[] vl = new float[profile[0].length];
for (int c = 0; c < ca.length; c++)
{
- ca[c] = new char[]
- { (char) c };
+ ca[c] = (char) c;
+ // ca[c] = new char[]
+ // { (char) c };
vl[c] = profile[0][c];
}
- ;
- jalview.util.QuickSort.sort(vl, ca);
- for (int p = 0, c = ca.length - 1; profile[0][((char[]) ca[c])[0]] > 0; c--)
+ QuickSort.sort(vl, ca);
+ for (int p = 0, c = ca.length - 1; profile[0][ca[c]] > 0; c--)
{
- if (((char[]) ca[c])[0] != '-')
+ final char residue = ca[c];
+ if (residue != '-')
{
- tval = profile[0][((char[]) ca[c])[0]]
- * 100f
- / profile[1][ignoreGapsInConsensusCalculation ? 1 : 0];
- mouseOver += ((p == 0) ? "" : "; ") + ((char[]) ca[c])[0]
- + " "
- + ((fmt != null) ? fmt.form(tval) : ((int) tval))
- + "%";
+ float tval = profile[0][residue] * 100f / normalisedBy;
+ mouseOver
+ .append((((p == 0) ? "" : "; ")))
+ .append(residue)
+ .append(" ")
+ .append(((fmt != null) ? fmt.form(tval)
+ : ((int) tval))).append("%");
p++;
-
}
}
-
}
}
else
{
- mouseOver += ((fmt != null) ? fmt.form(value) : ((int) value))
- + "%";
+ mouseOver.append(
+ (((fmt != null) ? fmt.form(value) : ((int) value))))
+ .append("%");
}
- consensus.annotations[i] = new Annotation(maxRes, mouseOver, ' ',
+ consensus.annotations[i] = new Annotation(maxRes,
+ mouseOver.toString(), ' ',
value);
}
}
/**
- * get the sorted profile for the given position of the consensus
+ * Returns a Format designed to show all significant figures for profile
+ * percentages. For less than 100 sequences, returns null (the integer
+ * percentage value will be displayed). For 100-999 sequences, returns "%3.1f"
+ *
+ * @param nseq
+ * @return
+ */
+ protected static Format getPercentageFormat(long nseq)
+ {
+ int scale = 0;
+ while (nseq >= 10)
+ {
+ scale++;
+ nseq /= 10;
+ }
+ return scale <= 1 ? null : new Format("%3." + (scale - 1) + "f");
+ }
+
+ /**
+ * Returns the sorted profile for the given consensus data. The returned array
+ * contains
+ *
+ *
+ * [profileType, numberOfValues, nonGapCount, charValue1, percentage1, charValue2, percentage2, ...]
+ * in descending order of percentage value
+ *
*
* @param hconsensus
+ * the data table from which to extract and sort values
+ * @param ignoreGaps
+ * if true, only non-gapped values are included in percentage
+ * calculations
* @return
*/
public static int[] extractProfile(Hashtable hconsensus,
- boolean ignoreGapsInConsensusCalculation)
+ boolean ignoreGaps)
{
int[] rtnval = new int[64];
int[][] profile = (int[][]) hconsensus.get(AAFrequency.PROFILE);
if (profile == null)
+ {
return null;
- Object[] ca = new Object[profile[0].length];
+ }
+ char[] ca = new char[profile[0].length];
float[] vl = new float[profile[0].length];
for (int c = 0; c < ca.length; c++)
{
- ca[c] = new char[]
- { (char) c };
+ ca[c] = (char) c;
vl[c] = profile[0][c];
}
- ;
- jalview.util.QuickSort.sort(vl, ca);
- rtnval[0] = 2;
- rtnval[1] = 0;
- for (int c = ca.length - 1; profile[0][((char[]) ca[c])[0]] > 0; c--)
+ QuickSort.sort(vl, ca);
+ int nextArrayPos = 2;
+ int totalPercentage = 0;
+ int distinctValuesCount = 0;
+ final int divisor = profile[1][ignoreGaps ? 1 : 0];
+ for (int c = ca.length - 1; profile[0][ca[c]] > 0; c--)
+ {
+ if (ca[c] != '-')
+ {
+ rtnval[nextArrayPos++] = ca[c];
+ final int percentage = (int) (profile[0][ca[c]] * 100f / divisor);
+ rtnval[nextArrayPos++] = percentage;
+ totalPercentage += percentage;
+ distinctValuesCount++;
+ }
+ }
+ rtnval[0] = distinctValuesCount;
+ rtnval[1] = totalPercentage;
+ int[] result = new int[rtnval.length + 1];
+ result[0] = AlignmentAnnotation.SEQUENCE_PROFILE;
+ System.arraycopy(rtnval, 0, result, 1, rtnval.length);
+
+ return result;
+ }
+
+ /**
+ * Extract a sorted extract of cDNA codon profile data. The returned array
+ * contains
+ *
+ *
+ * [profileType, numberOfValues, totalCount, charValue1, percentage1, charValue2, percentage2, ...]
+ * in descending order of percentage value, where the character values encode codon triplets
+ *
+ *
+ * @param hashtable
+ * @return
+ */
+ public static int[] extractCdnaProfile(Hashtable hashtable, boolean ignoreGaps)
+ {
+ // this holds #seqs, #ungapped, and then codon count, indexed by encoded
+ // codon triplet
+ int[] codonCounts = (int[]) hashtable.get(PROFILE);
+ int[] sortedCounts = new int[codonCounts.length - 2];
+ System.arraycopy(codonCounts, 2, sortedCounts, 0,
+ codonCounts.length - 2);
+
+ int[] result = new int[3 + 2 * sortedCounts.length];
+ // first value is just the type of profile data
+ result[0] = AlignmentAnnotation.CDNA_PROFILE;
+
+ char[] codons = new char[sortedCounts.length];
+ for (int i = 0; i < codons.length; i++)
+ {
+ codons[i] = (char) i;
+ }
+ QuickSort.sort(sortedCounts, codons);
+ int totalPercentage = 0;
+ int distinctValuesCount = 0;
+ int j = 3;
+ int divisor = ignoreGaps ? codonCounts[1] : codonCounts[0];
+ for (int i = codons.length - 1; i >= 0; i--)
+ {
+ final int codonCount = sortedCounts[i];
+ if (codonCount == 0)
+ {
+ break; // nothing else of interest here
+ }
+ distinctValuesCount++;
+ result[j++] = codons[i];
+ final int percentage = codonCount * 100 / divisor;
+ result[j++] = percentage;
+ totalPercentage += percentage;
+ }
+ result[2] = totalPercentage;
+
+ /*
+ * Just return the non-zero values
+ */
+ // todo next value is redundant if we limit the array to non-zero counts
+ result[1] = distinctValuesCount;
+ return Arrays.copyOfRange(result, 0, j);
+ }
+
+ /**
+ * Compute a consensus for the cDNA coding for a protein alignment.
+ *
+ * @param alignment
+ * the protein alignment (which should hold mappings to cDNA
+ * sequences)
+ * @param hconsensus
+ * the consensus data stores to be populated (one per column)
+ */
+ public static void calculateCdna(AlignmentI alignment,
+ Hashtable[] hconsensus)
+ {
+ final char gapCharacter = alignment.getGapCharacter();
+ Set mappings = alignment.getCodonFrames();
+ if (mappings == null || mappings.isEmpty())
+ {
+ return;
+ }
+
+ int cols = alignment.getWidth();
+ for (int col = 0; col < cols; col++)
+ {
+ // todo would prefer a Java bean for consensus data
+ Hashtable columnHash = new Hashtable();
+ // #seqs, #ungapped seqs, counts indexed by (codon encoded + 1)
+ int[] codonCounts = new int[66];
+ codonCounts[0] = alignment.getSequences().size();
+ int ungappedCount = 0;
+ for (SequenceI seq : alignment.getSequences())
+ {
+ if (seq.getCharAt(col) == gapCharacter)
+ {
+ continue;
+ }
+ char[] codon = MappingUtils.findCodonFor(seq, col, mappings);
+ int codonEncoded = CodingUtils.encodeCodon(codon);
+ if (codonEncoded >= 0)
+ {
+ codonCounts[codonEncoded + 2]++;
+ ungappedCount++;
+ }
+ }
+ codonCounts[1] = ungappedCount;
+ // todo: sort values here, save counts and codons?
+ columnHash.put(PROFILE, codonCounts);
+ hconsensus[col] = columnHash;
+ }
+ }
+
+ /**
+ * Derive displayable cDNA consensus annotation from computed consensus data.
+ *
+ * @param consensusAnnotation
+ * the annotation row to be populated for display
+ * @param consensusData
+ * the computed consensus data
+ * @param showProfileLogo
+ * if true show all symbols present at each position, else only the
+ * modal value
+ * @param nseqs
+ * the number of sequences in the alignment
+ */
+ public static void completeCdnaConsensus(
+ AlignmentAnnotation consensusAnnotation,
+ Hashtable[] consensusData, boolean showProfileLogo, int nseqs)
+ {
+ if (consensusAnnotation == null
+ || consensusAnnotation.annotations == null
+ || consensusAnnotation.annotations.length < consensusData.length)
+ {
+ // called with a bad alignment annotation row - wait for it to be
+ // initialised properly
+ return;
+ }
+
+ // ensure codon triplet scales with font size
+ consensusAnnotation.scaleColLabel = true;
+ for (int col = 0; col < consensusData.length; col++)
{
- if (((char[]) ca[c])[0] != '-')
+ Hashtable hci = consensusData[col];
+ if (hci == null)
{
- rtnval[rtnval[0]++] = ((char[]) ca[c])[0];
- rtnval[rtnval[0]] = (int) (profile[0][((char[]) ca[c])[0]] * 100f / profile[1][ignoreGapsInConsensusCalculation ? 1
- : 0]);
- rtnval[1] += rtnval[rtnval[0]++];
+ // gapped protein column?
+ continue;
}
+ // array holds #seqs, #ungapped, then codon counts indexed by codon
+ final int[] codonCounts = (int[]) hci.get(PROFILE);
+ int totalCount = 0;
+ StringBuilder mouseOver = new StringBuilder(32);
+
+ /*
+ * First pass - get total count and find the highest
+ */
+ final char[] codons = new char[codonCounts.length - 2];
+ for (int j = 2; j < codonCounts.length; j++)
+ {
+ final int codonCount = codonCounts[j];
+ codons[j - 2] = (char) (j - 2);
+ totalCount += codonCount;
+ }
+
+ /*
+ * Sort array of encoded codons by count ascending - so the modal value
+ * goes to the end; start by copying the count (dropping the first value)
+ */
+ int[] sortedCodonCounts = new int[codonCounts.length - 2];
+ System.arraycopy(codonCounts, 2, sortedCodonCounts, 0,
+ codonCounts.length - 2);
+ QuickSort.sort(sortedCodonCounts, codons);
+
+ int modalCodonEncoded = codons[codons.length - 1];
+ int modalCodonCount = sortedCodonCounts[codons.length - 1];
+ String modalCodon = String.valueOf(CodingUtils
+ .decodeCodon(modalCodonEncoded));
+ if (sortedCodonCounts.length > 1
+ && sortedCodonCounts[codons.length - 2] == modalCodonEncoded)
+ {
+ modalCodon = "+";
+ }
+ float pid = sortedCodonCounts[sortedCodonCounts.length - 1] * 100
+ / (float) totalCount;
+
+ /*
+ * todo ? Replace consensus hashtable with sorted arrays of codons and
+ * counts (non-zero only). Include total count in count array [0].
+ */
+
+ /*
+ * Scan sorted array backwards for most frequent values first.
+ */
+ for (int j = codons.length - 1; j >= 0; j--)
+ {
+ int codonCount = sortedCodonCounts[j];
+ if (codonCount == 0)
+ {
+ break;
+ }
+ int codonEncoded = codons[j];
+ final int pct = codonCount * 100 / totalCount;
+ String codon = String
+ .valueOf(CodingUtils.decodeCodon(codonEncoded));
+ Format fmt = getPercentageFormat(nseqs);
+ String formatted = fmt == null ? Integer.toString(pct) : fmt
+ .form(pct);
+ if (showProfileLogo || codonCount == modalCodonCount)
+ {
+ mouseOver.append(codon).append(": ").append(formatted)
+ .append("% ");
+ }
+ }
+
+ consensusAnnotation.annotations[col] = new Annotation(modalCodon,
+ mouseOver.toString(), ' ', pid);
}
- return rtnval;
}
}
diff --git a/src/jalview/analysis/AlignSeq.java b/src/jalview/analysis/AlignSeq.java
index 96c9b72..bd4cc22 100755
--- a/src/jalview/analysis/AlignSeq.java
+++ b/src/jalview/analysis/AlignSeq.java
@@ -804,19 +804,23 @@ public class AlignSeq
}
/**
- * DOCUMENT ME!
+ * Returns the given sequence with all of the given gap characters removed.
*
- * @param gapChar
- * DOCUMENT ME!
+ * @param gapChars
+ * a string of characters to be treated as gaps
* @param seq
- * DOCUMENT ME!
+ * the input sequence
*
- * @return DOCUMENT ME!
+ * @return
*/
- public static String extractGaps(String gapChar, String seq)
+ public static String extractGaps(String gapChars, String seq)
{
- StringTokenizer str = new StringTokenizer(seq, gapChar);
- StringBuffer newString = new StringBuffer();
+ if (gapChars == null || seq == null)
+ {
+ return null;
+ }
+ StringTokenizer str = new StringTokenizer(seq, gapChars);
+ StringBuilder newString = new StringBuilder(seq.length());
while (str.hasMoreTokens())
{
diff --git a/src/jalview/analysis/AlignmentSorter.java b/src/jalview/analysis/AlignmentSorter.java
index d1962c5..2fad332 100755
--- a/src/jalview/analysis/AlignmentSorter.java
+++ b/src/jalview/analysis/AlignmentSorter.java
@@ -20,10 +20,19 @@
*/
package jalview.analysis;
-import java.util.*;
-
-import jalview.datamodel.*;
-import jalview.util.*;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentOrder;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.SequenceNode;
+import jalview.util.Comparison;
+import jalview.util.MessageManager;
+import jalview.util.QuickSort;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* Routines for manipulating the order of a multiple sequence alignment TODO:
@@ -120,7 +129,7 @@ public class AlignmentSorter
seqs[i] = align.getSequenceAt(i);
}
- QuickSort.sort(scores, 0, scores.length - 1, seqs);
+ QuickSort.sort(scores, seqs);
setReverseOrder(align, seqs);
}
@@ -169,7 +178,7 @@ public class AlignmentSorter
* @param tmp
* sequences as a vector
*/
- private static void setOrder(AlignmentI align, Vector tmp)
+ private static void setOrder(AlignmentI align, List tmp)
{
setOrder(align, vectorSubsetToArray(tmp, align.getSequences()));
}
@@ -285,7 +294,7 @@ public class AlignmentSorter
{
// MAINTAINS ORIGNAL SEQUENCE ORDER,
// ORDERS BY GROUP SIZE
- Vector groups = new Vector();
+ List groups = new ArrayList();
if (groups.hashCode() != lastGroupHash)
{
@@ -303,11 +312,11 @@ public class AlignmentSorter
{
for (int j = 0; j < groups.size(); j++)
{
- SequenceGroup sg2 = (SequenceGroup) groups.elementAt(j);
+ SequenceGroup sg2 = groups.get(j);
if (sg.getSize() > sg2.getSize())
{
- groups.insertElementAt(sg, j);
+ groups.add(j, sg);
break;
}
@@ -315,22 +324,22 @@ public class AlignmentSorter
if (!groups.contains(sg))
{
- groups.addElement(sg);
+ groups.add(sg);
}
}
// NOW ADD SEQUENCES MAINTAINING ALIGNMENT ORDER
// /////////////////////////////////////////////
- Vector seqs = new Vector();
+ List seqs = new ArrayList();
for (int i = 0; i < groups.size(); i++)
{
- SequenceGroup sg = (SequenceGroup) groups.elementAt(i);
+ SequenceGroup sg = groups.get(i);
SequenceI[] orderedseqs = sg.getSequencesInOrder(align);
for (int j = 0; j < orderedseqs.length; j++)
{
- seqs.addElement(orderedseqs[j]);
+ seqs.add(orderedseqs[j]);
}
}
@@ -346,28 +355,8 @@ public class AlignmentSorter
}
/**
- * Converts Vector to array. java 1.18 does not have Vector.toArray()
- *
- * @param tmp
- * Vector of SequenceI objects
- *
- * @return array of Sequence[]
- */
- private static SequenceI[] vectorToArray(Vector tmp)
- {
- SequenceI[] seqs = new SequenceI[tmp.size()];
-
- for (int i = 0; i < tmp.size(); i++)
- {
- seqs[i] = (SequenceI) tmp.elementAt(i);
- }
-
- return seqs;
- }
-
- /**
* Select sequences in order from tmp that is present in mask, and any
- * remaining seqeunces in mask not in tmp
+ * remaining sequences in mask not in tmp
*
* @param tmp
* thread safe collection of sequences
@@ -379,6 +368,10 @@ public class AlignmentSorter
private static SequenceI[] vectorSubsetToArray(List tmp,
List mask)
{
+ // or?
+ // tmp2 = tmp.retainAll(mask);
+ // return tmp2.addAll(mask.removeAll(tmp2))
+
ArrayList seqs = new ArrayList();
int i, idx;
boolean[] tmask = new boolean[mask.size()];
@@ -421,7 +414,7 @@ public class AlignmentSorter
public static void sortBy(AlignmentI align, AlignmentOrder order)
{
// Get an ordered vector of sequences which may also be present in align
- Vector tmp = order.getOrder();
+ List tmp = order.getOrder();
if (lastOrder == order)
{
@@ -452,11 +445,12 @@ public class AlignmentSorter
*
* @return DOCUMENT ME!
*/
- private static Vector getOrderByTree(AlignmentI align, NJTree tree)
+ private static List getOrderByTree(AlignmentI align,
+ NJTree tree)
{
int nSeq = align.getHeight();
- Vector tmp = new Vector();
+ List tmp = new ArrayList();
tmp = _sortByTree(tree.getTopNode(), tmp, align.getSequences());
@@ -494,7 +488,7 @@ public class AlignmentSorter
*/
public static void sortByTree(AlignmentI align, NJTree tree)
{
- Vector tmp = getOrderByTree(align, tree);
+ List tmp = getOrderByTree(align, tree);
// tmp should properly permute align with tree.
if (lastTree != tree)
@@ -522,22 +516,22 @@ public class AlignmentSorter
*
* @param align
* DOCUMENT ME!
- * @param seqs
+ * @param tmp
* DOCUMENT ME!
*/
- private static void addStrays(AlignmentI align, Vector seqs)
+ private static void addStrays(AlignmentI align, List tmp)
{
int nSeq = align.getHeight();
for (int i = 0; i < nSeq; i++)
{
- if (!seqs.contains(align.getSequenceAt(i)))
+ if (!tmp.contains(align.getSequenceAt(i)))
{
- seqs.addElement(align.getSequenceAt(i));
+ tmp.add(align.getSequenceAt(i));
}
}
- if (nSeq != seqs.size())
+ if (nSeq != tmp.size())
{
System.err
.println("ERROR: Size still not right even after addStrays");
@@ -556,7 +550,8 @@ public class AlignmentSorter
*
* @return DOCUMENT ME!
*/
- private static Vector _sortByTree(SequenceNode node, Vector tmp,
+ private static List _sortByTree(SequenceNode node,
+ List tmp,
List seqset)
{
if (node == null)
@@ -577,7 +572,7 @@ public class AlignmentSorter
// seqset.size()==0 ||
// seqset.contains(tmp)))
{
- tmp.addElement(node.element());
+ tmp.add((SequenceI) node.element());
}
}
}
@@ -785,10 +780,6 @@ public class AlignmentSorter
for (int i = 0; i < seqs.length; i++)
{
SequenceFeature[] sf = seqs[i].getSequenceFeatures();
- if (sf == null && seqs[i].getDatasetSequence() != null)
- {
- sf = seqs[i].getDatasetSequence().getSequenceFeatures();
- }
if (sf == null)
{
sf = new SequenceFeature[0];
diff --git a/src/jalview/analysis/AlignmentUtils.java b/src/jalview/analysis/AlignmentUtils.java
index b55d58d..6f0125d 100644
--- a/src/jalview/analysis/AlignmentUtils.java
+++ b/src/jalview/analysis/AlignmentUtils.java
@@ -20,12 +20,30 @@
*/
package jalview.analysis;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+
+import jalview.datamodel.AlignedCodon;
+import jalview.datamodel.AlignedCodonFrame;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Mapping;
+import jalview.datamodel.SearchResults;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
-
-import java.util.ArrayList;
-import java.util.List;
+import jalview.schemes.ResidueProperties;
+import jalview.util.MapList;
/**
* grab bag of useful alignment manipulation operations Expect these to be
@@ -159,4 +177,1039 @@ public class AlignmentUtils
}
return result;
}
+
+ /**
+ * Returns a map of lists of sequences in the alignment, keyed by sequence
+ * name. For use in mapping between different alignment views of the same
+ * sequences.
+ *
+ * @see jalview.datamodel.AlignmentI#getSequencesByName()
+ */
+ public static Map> getSequencesByName(
+ AlignmentI al)
+ {
+ Map> theMap = new LinkedHashMap>();
+ for (SequenceI seq : al.getSequences())
+ {
+ String name = seq.getName();
+ if (name != null)
+ {
+ List seqs = theMap.get(name);
+ if (seqs == null)
+ {
+ seqs = new ArrayList();
+ theMap.put(name, seqs);
+ }
+ seqs.add(seq);
+ }
+ }
+ return theMap;
+ }
+
+ /**
+ * Build mapping of protein to cDNA alignment. Mappings are made between
+ * sequences where the cDNA translates to the protein sequence. Any new
+ * mappings are added to the protein alignment. Returns true if any mappings
+ * either already exist or were added, else false.
+ *
+ * @param proteinAlignment
+ * @param cdnaAlignment
+ * @return
+ */
+ public static boolean mapProteinToCdna(
+ final AlignmentI proteinAlignment,
+ final AlignmentI cdnaAlignment)
+ {
+ if (proteinAlignment == null || cdnaAlignment == null)
+ {
+ return false;
+ }
+
+ Set mappedDna = new HashSet();
+ Set mappedProtein = new HashSet();
+
+ /*
+ * First pass - map sequences where cross-references exist. This include
+ * 1-to-many mappings to support, for example, variant cDNA.
+ */
+ boolean mappingPerformed = mapProteinToCdna(proteinAlignment,
+ cdnaAlignment, mappedDna, mappedProtein, true);
+
+ /*
+ * Second pass - map sequences where no cross-references exist. This only
+ * does 1-to-1 mappings and assumes corresponding sequences are in the same
+ * order in the alignments.
+ */
+ mappingPerformed |= mapProteinToCdna(proteinAlignment, cdnaAlignment,
+ mappedDna, mappedProtein, false);
+ return mappingPerformed;
+ }
+
+ /**
+ * Make mappings between compatible sequences (where the cDNA translation
+ * matches the protein).
+ *
+ * @param proteinAlignment
+ * @param cdnaAlignment
+ * @param mappedDna
+ * a set of mapped DNA sequences (to add to)
+ * @param mappedProtein
+ * a set of mapped Protein sequences (to add to)
+ * @param xrefsOnly
+ * if true, only map sequences where xrefs exist
+ * @return
+ */
+ protected static boolean mapProteinToCdna(
+ final AlignmentI proteinAlignment,
+ final AlignmentI cdnaAlignment, Set mappedDna,
+ Set mappedProtein, boolean xrefsOnly)
+ {
+ boolean mappingPerformed = false;
+ List thisSeqs = proteinAlignment.getSequences();
+ for (SequenceI aaSeq : thisSeqs)
+ {
+ boolean proteinMapped = false;
+ AlignedCodonFrame acf = new AlignedCodonFrame();
+
+ for (SequenceI cdnaSeq : cdnaAlignment.getSequences())
+ {
+ /*
+ * Always try to map if sequences have xref to each other; this supports
+ * variant cDNA or alternative splicing for a protein sequence.
+ *
+ * If no xrefs, try to map progressively, assuming that alignments have
+ * mappable sequences in corresponding order. These are not
+ * many-to-many, as that would risk mixing species with similar cDNA
+ * sequences.
+ */
+ if (xrefsOnly && !CrossRef.haveCrossRef(aaSeq, cdnaSeq))
+ {
+ continue;
+ }
+
+ /*
+ * Don't map non-xrefd sequences more than once each. This heuristic
+ * allows us to pair up similar sequences in ordered alignments.
+ */
+ if (!xrefsOnly
+ && (mappedProtein.contains(aaSeq) || mappedDna
+ .contains(cdnaSeq)))
+ {
+ continue;
+ }
+ if (!mappingExists(proteinAlignment.getCodonFrames(),
+ aaSeq.getDatasetSequence(), cdnaSeq.getDatasetSequence()))
+ {
+ MapList map = mapProteinToCdna(aaSeq, cdnaSeq);
+ if (map != null)
+ {
+ acf.addMap(cdnaSeq, aaSeq, map);
+ mappingPerformed = true;
+ proteinMapped = true;
+ mappedDna.add(cdnaSeq);
+ mappedProtein.add(aaSeq);
+ }
+ }
+ }
+ if (proteinMapped)
+ {
+ proteinAlignment.addCodonFrame(acf);
+ }
+ }
+ return mappingPerformed;
+ }
+
+ /**
+ * Answers true if the mappings include one between the given (dataset)
+ * sequences.
+ */
+ public static boolean mappingExists(Set set,
+ SequenceI aaSeq, SequenceI cdnaSeq)
+ {
+ if (set != null)
+ {
+ for (AlignedCodonFrame acf : set)
+ {
+ if (cdnaSeq == acf.getDnaForAaSeq(aaSeq))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Build a mapping (if possible) of a protein to a cDNA sequence. The cDNA
+ * must be three times the length of the protein, possibly after ignoring
+ * start and/or stop codons, and must translate to the protein. Returns null
+ * if no mapping is determined.
+ *
+ * @param proteinSeqs
+ * @param cdnaSeq
+ * @return
+ */
+ public static MapList mapProteinToCdna(SequenceI proteinSeq,
+ SequenceI cdnaSeq)
+ {
+ /*
+ * Here we handle either dataset sequence set (desktop) or absent (applet).
+ * Use only the char[] form of the sequence to avoid creating possibly large
+ * String objects.
+ */
+ final SequenceI proteinDataset = proteinSeq.getDatasetSequence();
+ char[] aaSeqChars = proteinDataset != null ? proteinDataset
+ .getSequence() : proteinSeq.getSequence();
+ final SequenceI cdnaDataset = cdnaSeq.getDatasetSequence();
+ char[] cdnaSeqChars = cdnaDataset != null ? cdnaDataset.getSequence()
+ : cdnaSeq.getSequence();
+ if (aaSeqChars == null || cdnaSeqChars == null)
+ {
+ return null;
+ }
+
+ /*
+ * cdnaStart/End, proteinStartEnd are base 1 (for dataset sequence mapping)
+ */
+ final int mappedLength = 3 * aaSeqChars.length;
+ int cdnaLength = cdnaSeqChars.length;
+ int cdnaStart = 1;
+ int cdnaEnd = cdnaLength;
+ final int proteinStart = 1;
+ final int proteinEnd = aaSeqChars.length;
+
+ /*
+ * If lengths don't match, try ignoring stop codon.
+ */
+ if (cdnaLength != mappedLength && cdnaLength > 2)
+ {
+ String lastCodon = String.valueOf(cdnaSeqChars, cdnaLength - 3, 3)
+ .toUpperCase();
+ for (String stop : ResidueProperties.STOP)
+ {
+ if (lastCodon.equals(stop))
+ {
+ cdnaEnd -= 3;
+ cdnaLength -= 3;
+ break;
+ }
+ }
+ }
+
+ /*
+ * If lengths still don't match, try ignoring start codon.
+ */
+ if (cdnaLength != mappedLength
+ && cdnaLength > 2
+ && String.valueOf(cdnaSeqChars, 0, 3).toUpperCase()
+ .equals(
+ ResidueProperties.START))
+ {
+ cdnaStart += 3;
+ cdnaLength -= 3;
+ }
+
+ if (cdnaLength != mappedLength)
+ {
+ return null;
+ }
+ if (!translatesAs(cdnaSeqChars, cdnaStart - 1, aaSeqChars))
+ {
+ return null;
+ }
+ MapList map = new MapList(new int[]
+ { cdnaStart, cdnaEnd }, new int[]
+ { proteinStart, proteinEnd }, 3, 1);
+ return map;
+ }
+
+ /**
+ * Test whether the given cdna sequence, starting at the given offset,
+ * translates to the given amino acid sequence, using the standard translation
+ * table. Designed to fail fast i.e. as soon as a mismatch position is found.
+ *
+ * @param cdnaSeqChars
+ * @param cdnaStart
+ * @param aaSeqChars
+ * @return
+ */
+ protected static boolean translatesAs(char[] cdnaSeqChars, int cdnaStart,
+ char[] aaSeqChars)
+ {
+ int aaResidue = 0;
+ for (int i = cdnaStart; i < cdnaSeqChars.length - 2
+ && aaResidue < aaSeqChars.length; i += 3, aaResidue++)
+ {
+ String codon = String.valueOf(cdnaSeqChars, i, 3);
+ final String translated = ResidueProperties.codonTranslate(
+ codon);
+ /*
+ * ? allow X in protein to match untranslatable in dna ?
+ */
+ final char aaRes = aaSeqChars[aaResidue];
+ if ((translated == null || "STOP".equals(translated)) && aaRes == 'X')
+ {
+ continue;
+ }
+ if (translated == null
+ || !(aaRes == translated.charAt(0)))
+ {
+ // debug
+ // System.out.println(("Mismatch at " + i + "/" + aaResidue + ": "
+ // + codon + "(" + translated + ") != " + aaRes));
+ return false;
+ }
+ }
+ // fail if we didn't match all of the aa sequence
+ return (aaResidue == aaSeqChars.length);
+ }
+
+ /**
+ * Align sequence 'seq' to match the alignment of a mapped sequence. Note this
+ * currently assumes that we are aligning cDNA to match protein.
+ *
+ * @param seq
+ * the sequence to be realigned
+ * @param al
+ * the alignment whose sequence alignment is to be 'copied'
+ * @param gap
+ * character string represent a gap in the realigned sequence
+ * @param preserveUnmappedGaps
+ * @param preserveMappedGaps
+ * @return true if the sequence was realigned, false if it could not be
+ */
+ public static boolean alignSequenceAs(SequenceI seq, AlignmentI al,
+ String gap, boolean preserveMappedGaps,
+ boolean preserveUnmappedGaps)
+ {
+ /*
+ * Get any mappings from the source alignment to the target (dataset) sequence.
+ */
+ // TODO there may be one AlignedCodonFrame per dataset sequence, or one with
+ // all mappings. Would it help to constrain this?
+ List mappings = al.getCodonFrame(seq);
+ if (mappings == null || mappings.isEmpty())
+ {
+ return false;
+ }
+
+ /*
+ * Locate the aligned source sequence whose dataset sequence is mapped. We
+ * just take the first match here (as we can't align cDNA like more than one
+ * protein sequence).
+ */
+ SequenceI alignFrom = null;
+ AlignedCodonFrame mapping = null;
+ for (AlignedCodonFrame mp : mappings)
+ {
+ alignFrom = mp.findAlignedSequence(seq.getDatasetSequence(), al);
+ if (alignFrom != null)
+ {
+ mapping = mp;
+ break;
+ }
+ }
+
+ if (alignFrom == null)
+ {
+ return false;
+ }
+ alignSequenceAs(seq, alignFrom, mapping, gap, al.getGapCharacter(),
+ preserveMappedGaps, preserveUnmappedGaps);
+ return true;
+ }
+
+ /**
+ * Align sequence 'alignTo' the same way as 'alignFrom', using the mapping to
+ * match residues and codons. Flags control whether existing gaps in unmapped
+ * (intron) and mapped (exon) regions are preserved or not. Gaps linking intro
+ * and exon are only retained if both flags are set.
+ *
+ * @param alignTo
+ * @param alignFrom
+ * @param mapping
+ * @param myGap
+ * @param sourceGap
+ * @param preserveUnmappedGaps
+ * @param preserveMappedGaps
+ */
+ public static void alignSequenceAs(SequenceI alignTo,
+ SequenceI alignFrom,
+ AlignedCodonFrame mapping, String myGap, char sourceGap,
+ boolean preserveMappedGaps, boolean preserveUnmappedGaps)
+ {
+ // TODO generalise to work for Protein-Protein, dna-dna, dna-protein
+ final char[] thisSeq = alignTo.getSequence();
+ final char[] thatAligned = alignFrom.getSequence();
+ StringBuilder thisAligned = new StringBuilder(2 * thisSeq.length);
+
+ // aligned and dataset sequence positions, all base zero
+ int thisSeqPos = 0;
+ int sourceDsPos = 0;
+
+ int basesWritten = 0;
+ char myGapChar = myGap.charAt(0);
+ int ratio = myGap.length();
+
+ /*
+ * Traverse the aligned protein sequence.
+ */
+ int sourceGapMappedLength = 0;
+ boolean inExon = false;
+ for (char sourceChar : thatAligned)
+ {
+ if (sourceChar == sourceGap)
+ {
+ sourceGapMappedLength += ratio;
+ continue;
+ }
+
+ /*
+ * Found a residue. Locate its mapped codon (start) position.
+ */
+ sourceDsPos++;
+ // Note mapping positions are base 1, our sequence positions base 0
+ int[] mappedPos = mapping.getMappedRegion(alignTo, alignFrom,
+ sourceDsPos);
+ if (mappedPos == null)
+ {
+ /*
+ * Abort realignment if unmapped protein. Or could ignore it??
+ */
+ System.err.println("Can't align: no codon mapping to residue "
+ + sourceDsPos + "(" + sourceChar + ")");
+ return;
+ }
+
+ int mappedCodonStart = mappedPos[0]; // position (1...) of codon start
+ int mappedCodonEnd = mappedPos[mappedPos.length - 1]; // codon end pos
+ StringBuilder trailingCopiedGap = new StringBuilder();
+
+ /*
+ * Copy dna sequence up to and including this codon. Optionally, include
+ * gaps before the codon starts (in introns) and/or after the codon starts
+ * (in exons).
+ *
+ * Note this only works for 'linear' splicing, not reverse or interleaved.
+ * But then 'align dna as protein' doesn't make much sense otherwise.
+ */
+ int intronLength = 0;
+ while (basesWritten < mappedCodonEnd && thisSeqPos < thisSeq.length)
+ {
+ final char c = thisSeq[thisSeqPos++];
+ if (c != myGapChar)
+ {
+ basesWritten++;
+
+ if (basesWritten < mappedCodonStart)
+ {
+ /*
+ * Found an unmapped (intron) base. First add in any preceding gaps
+ * (if wanted).
+ */
+ if (preserveUnmappedGaps && trailingCopiedGap.length() > 0)
+ {
+ thisAligned.append(trailingCopiedGap.toString());
+ intronLength += trailingCopiedGap.length();
+ trailingCopiedGap = new StringBuilder();
+ }
+ intronLength++;
+ inExon = false;
+ }
+ else
+ {
+ final boolean startOfCodon = basesWritten == mappedCodonStart;
+ int gapsToAdd = calculateGapsToInsert(preserveMappedGaps,
+ preserveUnmappedGaps, sourceGapMappedLength, inExon,
+ trailingCopiedGap.length(), intronLength, startOfCodon);
+ for (int i = 0; i < gapsToAdd; i++)
+ {
+ thisAligned.append(myGapChar);
+ }
+ sourceGapMappedLength = 0;
+ inExon = true;
+ }
+ thisAligned.append(c);
+ trailingCopiedGap = new StringBuilder();
+ }
+ else
+ {
+ if (inExon && preserveMappedGaps)
+ {
+ trailingCopiedGap.append(myGapChar);
+ }
+ else if (!inExon && preserveUnmappedGaps)
+ {
+ trailingCopiedGap.append(myGapChar);
+ }
+ }
+ }
+ }
+
+ /*
+ * At end of protein sequence. Copy any remaining dna sequence, optionally
+ * including (intron) gaps. We do not copy trailing gaps in protein.
+ */
+ while (thisSeqPos < thisSeq.length)
+ {
+ final char c = thisSeq[thisSeqPos++];
+ if (c != myGapChar || preserveUnmappedGaps)
+ {
+ thisAligned.append(c);
+ }
+ }
+
+ /*
+ * All done aligning, set the aligned sequence.
+ */
+ alignTo.setSequence(new String(thisAligned));
+ }
+
+ /**
+ * Helper method to work out how many gaps to insert when realigning.
+ *
+ * @param preserveMappedGaps
+ * @param preserveUnmappedGaps
+ * @param sourceGapMappedLength
+ * @param inExon
+ * @param trailingCopiedGap
+ * @param intronLength
+ * @param startOfCodon
+ * @return
+ */
+ protected static int calculateGapsToInsert(boolean preserveMappedGaps,
+ boolean preserveUnmappedGaps, int sourceGapMappedLength,
+ boolean inExon, int trailingGapLength,
+ int intronLength, final boolean startOfCodon)
+ {
+ int gapsToAdd = 0;
+ if (startOfCodon)
+ {
+ /*
+ * Reached start of codon. Ignore trailing gaps in intron unless we are
+ * preserving gaps in both exon and intron. Ignore them anyway if the
+ * protein alignment introduces a gap at least as large as the intronic
+ * region.
+ */
+ if (inExon && !preserveMappedGaps)
+ {
+ trailingGapLength = 0;
+ }
+ if (!inExon && !(preserveMappedGaps && preserveUnmappedGaps))
+ {
+ trailingGapLength = 0;
+ }
+ if (inExon)
+ {
+ gapsToAdd = Math.max(sourceGapMappedLength, trailingGapLength);
+ }
+ else
+ {
+ if (intronLength + trailingGapLength <= sourceGapMappedLength)
+ {
+ gapsToAdd = sourceGapMappedLength - intronLength;
+ }
+ else
+ {
+ gapsToAdd = Math.min(intronLength + trailingGapLength
+ - sourceGapMappedLength, trailingGapLength);
+ }
+ }
+ }
+ else
+ {
+ /*
+ * second or third base of codon; check for any gaps in dna
+ */
+ if (!preserveMappedGaps)
+ {
+ trailingGapLength = 0;
+ }
+ gapsToAdd = Math.max(sourceGapMappedLength, trailingGapLength);
+ }
+ 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;
+ }
+
+ /**
+ * Realigns the given protein to match the alignment of the dna, using codon
+ * mappings to translate aligned codon positions to protein residues.
+ *
+ * @param protein
+ * the alignment whose sequences are realigned by this method
+ * @param dna
+ * the dna alignment whose alignment we are 'copying'
+ * @return the number of sequences that were realigned
+ */
+ public static int alignProteinAsDna(AlignmentI protein, AlignmentI dna)
+ {
+ Set mappings = protein.getCodonFrames();
+
+ /*
+ * Map will hold, for each aligned codon position e.g. [3, 5, 6], a map of
+ * {dnaSequence, {proteinSequence, codonProduct}} at that position. The
+ * comparator keeps the codon positions ordered.
+ */
+ Map> alignedCodons = new TreeMap>(
+ new CodonComparator());
+ for (SequenceI dnaSeq : dna.getSequences())
+ {
+ for (AlignedCodonFrame mapping : mappings)
+ {
+ Mapping seqMap = mapping.getMappingForSequence(dnaSeq);
+ SequenceI prot = mapping.findAlignedSequence(
+ dnaSeq.getDatasetSequence(), protein);
+ if (prot != null)
+ {
+ addCodonPositions(dnaSeq, prot, protein.getGapCharacter(),
+ seqMap, alignedCodons);
+ }
+ }
+ }
+ return alignProteinAs(protein, alignedCodons);
+ }
+
+ /**
+ * Update the aligned protein sequences to match the codon alignments given in
+ * the map.
+ *
+ * @param protein
+ * @param alignedCodons
+ * an ordered map of codon positions (columns), with sequence/peptide
+ * values present in each column
+ * @return
+ */
+ protected static int alignProteinAs(AlignmentI protein,
+ Map> alignedCodons)
+ {
+ /*
+ * Prefill aligned sequences with gaps before inserting aligned protein
+ * residues.
+ */
+ int alignedWidth = alignedCodons.size();
+ char[] gaps = new char[alignedWidth];
+ Arrays.fill(gaps, protein.getGapCharacter());
+ String allGaps = String.valueOf(gaps);
+ for (SequenceI seq : protein.getSequences())
+ {
+ seq.setSequence(allGaps);
+ }
+
+ int column = 0;
+ for (AlignedCodon codon : alignedCodons.keySet())
+ {
+ final Map columnResidues = alignedCodons.get(codon);
+ for (Entry entry : columnResidues
+ .entrySet())
+ {
+ // place translated codon at its column position in sequence
+ entry.getKey().getSequence()[column] = entry.getValue().charAt(0);
+ }
+ column++;
+ }
+ return 0;
+ }
+
+ /**
+ * Populate the map of aligned codons by traversing the given sequence
+ * mapping, locating the aligned positions of mapped codons, and adding those
+ * positions and their translation products to the map.
+ *
+ * @param dna
+ * the aligned sequence we are mapping from
+ * @param protein
+ * the sequence to be aligned to the codons
+ * @param gapChar
+ * the gap character in the dna sequence
+ * @param seqMap
+ * a mapping to a sequence translation
+ * @param alignedCodons
+ * the map we are building up
+ */
+ static void addCodonPositions(SequenceI dna, SequenceI protein,
+ char gapChar,
+ Mapping seqMap,
+ Map> alignedCodons)
+ {
+ Iterator codons = seqMap.getCodonIterator(dna, gapChar);
+ while (codons.hasNext())
+ {
+ AlignedCodon codon = codons.next();
+ Map seqProduct = alignedCodons.get(codon);
+ if (seqProduct == null)
+ {
+ seqProduct = new HashMap();
+ alignedCodons.put(codon, seqProduct);
+ }
+ seqProduct.put(protein, codon.product);
+ }
+ }
+
+ /**
+ * Returns true if a cDNA/Protein mapping either exists, or could be made,
+ * between at least one pair of sequences in the two alignments. Currently,
+ * the logic is:
+ *
+ *
One alignment must be nucleotide, and the other protein
+ *
At least one pair of sequences must be already mapped, or mappable
+ *
Mappable means the nucleotide translation matches the protein sequence
+ *
The translation may ignore start and stop codons if present in the
+ * nucleotide
+ *
+ *
+ * @param al1
+ * @param al2
+ * @return
+ */
+ public static boolean isMappable(AlignmentI al1, AlignmentI al2)
+ {
+ /*
+ * Require one nucleotide and one protein
+ */
+ if (al1.isNucleotide() == al2.isNucleotide())
+ {
+ return false;
+ }
+ AlignmentI dna = al1.isNucleotide() ? al1 : al2;
+ AlignmentI protein = dna == al1 ? al2 : al1;
+ Set mappings = protein.getCodonFrames();
+ for (SequenceI dnaSeq : dna.getSequences())
+ {
+ for (SequenceI proteinSeq : protein.getSequences())
+ {
+ if (isMappable(dnaSeq, proteinSeq, mappings))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the dna sequence is mapped, or could be mapped, to the
+ * protein sequence.
+ *
+ * @param dnaSeq
+ * @param proteinSeq
+ * @param mappings
+ * @return
+ */
+ public static boolean isMappable(SequenceI dnaSeq, SequenceI proteinSeq,
+ Set mappings)
+ {
+ SequenceI dnaDs = dnaSeq.getDatasetSequence() == null ? dnaSeq : dnaSeq.getDatasetSequence();
+ SequenceI proteinDs = proteinSeq.getDatasetSequence() == null ? proteinSeq
+ : proteinSeq.getDatasetSequence();
+
+ /*
+ * Already mapped?
+ */
+ for (AlignedCodonFrame mapping : mappings) {
+ if ( proteinDs == mapping.getAaForDnaSeq(dnaDs)) {
+ return true;
+ }
+ }
+
+ /*
+ * Just try to make a mapping (it is not yet stored), test whether
+ * successful.
+ */
+ return mapProteinToCdna(proteinDs, dnaDs) != null;
+ }
+
+ /**
+ * Finds any reference annotations associated with the sequences in
+ * sequenceScope, that are not already added to the alignment, and adds them
+ * to the 'candidates' map. Also populates a lookup table of annotation
+ * labels, keyed by calcId, for use in constructing tooltips or the like.
+ *
+ * @param sequenceScope
+ * the sequences to scan for reference annotations
+ * @param labelForCalcId
+ * (optional) map to populate with label for calcId
+ * @param candidates
+ * map to populate with annotations for sequence
+ * @param al
+ * the alignment to check for presence of annotations
+ */
+ public static void findAddableReferenceAnnotations(
+ List sequenceScope, Map labelForCalcId,
+ final Map> candidates,
+ AlignmentI al)
+ {
+ if (sequenceScope == null)
+ {
+ return;
+ }
+
+ /*
+ * For each sequence in scope, make a list of any annotations on the
+ * underlying dataset sequence which are not already on the alignment.
+ *
+ * Add to a map of { alignmentSequence, }
+ */
+ for (SequenceI seq : sequenceScope)
+ {
+ SequenceI dataset = seq.getDatasetSequence();
+ if (dataset == null)
+ {
+ continue;
+ }
+ AlignmentAnnotation[] datasetAnnotations = dataset.getAnnotation();
+ if (datasetAnnotations == null)
+ {
+ continue;
+ }
+ final List result = new ArrayList();
+ for (AlignmentAnnotation dsann : datasetAnnotations)
+ {
+ /*
+ * Find matching annotations on the alignment. If none is found, then
+ * add this annotation to the list of 'addable' annotations for this
+ * sequence.
+ */
+ final Iterable matchedAlignmentAnnotations = al
+ .findAnnotations(seq, dsann.getCalcId(),
+ dsann.label);
+ if (!matchedAlignmentAnnotations.iterator().hasNext())
+ {
+ result.add(dsann);
+ if (labelForCalcId != null)
+ {
+ labelForCalcId.put(dsann.getCalcId(), dsann.label);
+ }
+ }
+ }
+ /*
+ * Save any addable annotations for this sequence
+ */
+ if (!result.isEmpty())
+ {
+ candidates.put(seq, result);
+ }
+ }
+ }
+
+ /**
+ * Adds annotations to the top of the alignment annotations, in the same order
+ * as their related sequences.
+ *
+ * @param annotations
+ * the annotations to add
+ * @param alignment
+ * the alignment to add them to
+ * @param selectionGroup
+ * current selection group (or null if none)
+ */
+ public static void addReferenceAnnotations(
+ Map> annotations,
+ final AlignmentI alignment, final SequenceGroup selectionGroup)
+ {
+ for (SequenceI seq : annotations.keySet())
+ {
+ for (AlignmentAnnotation ann : annotations.get(seq))
+ {
+ AlignmentAnnotation copyAnn = new AlignmentAnnotation(ann);
+ int startRes = 0;
+ int endRes = ann.annotations.length;
+ if (selectionGroup != null)
+ {
+ startRes = selectionGroup.getStartRes();
+ endRes = selectionGroup.getEndRes();
+ }
+ copyAnn.restrict(startRes, endRes);
+
+ /*
+ * Add to the sequence (sets copyAnn.datasetSequence), unless the
+ * original annotation is already on the sequence.
+ */
+ if (!seq.hasAnnotation(ann))
+ {
+ seq.addAlignmentAnnotation(copyAnn);
+ }
+ // adjust for gaps
+ copyAnn.adjustForAlignment();
+ // add to the alignment and set visible
+ alignment.addAnnotation(copyAnn);
+ copyAnn.visible = true;
+ }
+ }
+ }
+
+ /**
+ * Set visibility of alignment annotations of specified types (labels), for
+ * specified sequences. This supports controls like
+ * "Show all secondary structure", "Hide all Temp factor", etc.
+ *
+ * @al the alignment to scan for annotations
+ * @param types
+ * the types (labels) of annotations to be updated
+ * @param forSequences
+ * if not null, only annotations linked to one of these sequences are
+ * in scope for update; if null, acts on all sequence annotations
+ * @param anyType
+ * if this flag is true, 'types' is ignored (label not checked)
+ * @param doShow
+ * if true, set visibility on, else set off
+ */
+ public static void showOrHideSequenceAnnotations(AlignmentI al,
+ Collection types, List forSequences,
+ boolean anyType, boolean doShow)
+ {
+ for (AlignmentAnnotation aa : al
+ .getAlignmentAnnotation())
+ {
+ if (anyType || types.contains(aa.label))
+ {
+ if ((aa.sequenceRef != null)
+ && (forSequences == null || forSequences
+ .contains(aa.sequenceRef)))
+ {
+ aa.visible = doShow;
+ }
+ }
+ }
+ }
}
diff --git a/src/jalview/analysis/CodingUtils.java b/src/jalview/analysis/CodingUtils.java
new file mode 100644
index 0000000..a434465
--- /dev/null
+++ b/src/jalview/analysis/CodingUtils.java
@@ -0,0 +1,119 @@
+package jalview.analysis;
+
+/**
+ * A utility class to provide encoding/decoding schemes for data.
+ *
+ * @author gmcarstairs
+ *
+ */
+public class CodingUtils
+{
+
+ /*
+ * Number of bits used when encoding codon characters. 2 is enough for ACGT.
+ * To accommodate more (e.g. ambiguity codes), simply increase this number
+ * (and adjust unit tests to match).
+ */
+ private static final int CODON_ENCODING_BITSHIFT = 2;
+
+ /**
+ * Encode a codon from e.g. ['A', 'G', 'C'] to a number in the range 0 - 63.
+ * Converts lower to upper case, U to T, then assembles a binary value by
+ * encoding A/C/G/T as 00/01/10/11 respectively and shifting.
+ *
+ * @param codon
+ * @return the encoded codon, or a negative number if unexpected characters
+ * found
+ */
+ public static int encodeCodon(char[] codon)
+ {
+ if (codon == null)
+ {
+ return -1;
+ }
+ return encodeCodon(codon[2])
+ + (encodeCodon(codon[1]) << CODON_ENCODING_BITSHIFT)
+ + (encodeCodon(codon[0]) << (2 * CODON_ENCODING_BITSHIFT));
+ }
+
+ /**
+ * Encodes aA/cC/gG/tTuU as 0/1/2/3 respectively. Returns Integer.MIN_VALUE (a
+ * large negative value) for any other character.
+ *
+ * @param c
+ * @return
+ */
+ public static int encodeCodon(char c)
+ {
+ int result = Integer.MIN_VALUE;
+ switch (c)
+ {
+ case 'A':
+ case 'a':
+ result = 0;
+ break;
+ case 'C':
+ case 'c':
+ result = 1;
+ break;
+ case 'G':
+ case 'g':
+ result = 2;
+ break;
+ case 'T':
+ case 't':
+ case 'U':
+ case 'u':
+ result = 3;
+ break;
+ }
+ return result;
+ }
+
+ /**
+ * Converts a binary encoded codon into an ['A', 'C', 'G'] (or 'T') triplet.
+ *
+ * The two low-order bits encode for A/C/G/T as 0/1/2/3, etc.
+ *
+ * @param encoded
+ * @return
+ */
+ public static char[] decodeCodon(int encoded)
+ {
+ char[] result = new char[3];
+ result[2] = decodeNucleotide(encoded & 3);
+ encoded = encoded >>> CODON_ENCODING_BITSHIFT;
+ result[1] = decodeNucleotide(encoded & 3);
+ encoded = encoded >>> CODON_ENCODING_BITSHIFT;
+ result[0] = decodeNucleotide(encoded & 3);
+ return result;
+ }
+
+ /**
+ * Convert value 0/1/2/3 to 'A'/'C'/'G'/'T'
+ *
+ * @param i
+ * @return
+ */
+ public static char decodeNucleotide(int i)
+ {
+ char result = '0';
+ switch (i)
+ {
+ case 0:
+ result = 'A';
+ break;
+ case 1:
+ result = 'C';
+ break;
+ case 2:
+ result = 'G';
+ break;
+ case 3:
+ result = 'T';
+ break;
+ }
+ return result;
+ }
+
+}
diff --git a/src/jalview/analysis/CodonComparator.java b/src/jalview/analysis/CodonComparator.java
new file mode 100644
index 0000000..fc196de
--- /dev/null
+++ b/src/jalview/analysis/CodonComparator.java
@@ -0,0 +1,91 @@
+package jalview.analysis;
+
+import jalview.datamodel.AlignedCodon;
+
+import java.util.Comparator;
+
+/**
+ * Implements rules for comparing two aligned codons, i.e. determining whether
+ * they should occupy the same position in a translated protein alignment, or
+ * one or the other should 'follow' (by preceded by a gap).
+ *
+ * @author gmcarstairs
+ *
+ */
+public final class CodonComparator implements Comparator
+{
+
+ @Override
+ public int compare(AlignedCodon ac1, AlignedCodon ac2)
+ {
+ if (ac1 == null || ac2 == null || ac1.equals(ac2))
+ {
+ return 0;
+ }
+
+ /**
+ *
+ * Case 1: if one starts before the other, and doesn't end after it, then it
+ * precedes. We ignore the middle base position here.
+ * A--GT
+ * -CT-G
+ *
+ * Case 2: if one ends after the other, and doesn't start before it, then it
+ * follows. We ignore the middle base position here.
+ * -TG-A
+ * G-TC
+ *
+ */
+ if (ac1.pos3 > ac2.pos3 && ac1.pos1 >= ac2.pos1)
+ {
+ return 1;
+ }
+ if (ac2.pos3 > ac1.pos3 && ac2.pos1 >= ac1.pos1)
+ {
+ return -1;
+ }
+
+ /*
+ * Case 3: if start and end match, compare middle base positions.
+ */
+ if (ac1.pos1 == ac2.pos1 && ac1.pos3 == ac2.pos3)
+ {
+ return Integer.compare(ac1.pos2, ac2.pos2);
+ }
+
+ /*
+ * That just leaves the 'enclosing' case - one codon starts after but ends
+ * before the other. If the middle bases don't match, use their comparison
+ * (majority vote).
+ */
+ int compareMiddles = Integer.compare(ac1.pos2, ac2.pos2);
+ if (compareMiddles != 0)
+ {
+ return compareMiddles;
+ }
+
+ /**
+ *
+ * Finally just leaves overlap with matching middle base, e.g.
+ * -A-A-A
+ * G--GG
+ * In this case the choice is arbitrary whether to compare based on
+ * first or last base position. We pick the first. Note this preserves
+ * symmetricality of the comparison.
+ *
+ */
+ return Integer.compare(ac1.pos1, ac2.pos1);
+ }
+}
diff --git a/src/jalview/analysis/CrossRef.java b/src/jalview/analysis/CrossRef.java
index f34b822..eed2d7e 100644
--- a/src/jalview/analysis/CrossRef.java
+++ b/src/jalview/analysis/CrossRef.java
@@ -20,21 +20,21 @@
*/
package jalview.analysis;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Vector;
-import java.util.Hashtable;
-
import jalview.datamodel.AlignedCodonFrame;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
-import jalview.datamodel.DBRefSource;
import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceI;
import jalview.ws.SequenceFetcher;
import jalview.ws.seqfetcher.ASequenceFetcher;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Vector;
+
/**
* Functions for cross-referencing sequence databases. user must first specify
* if cross-referencing from protein or dna (set dna==true)
@@ -230,7 +230,7 @@ public class CrossRef
{
Vector rseqs = new Vector();
Alignment ral = null;
- AlignedCodonFrame cf = new AlignedCodonFrame(0); // nominal width
+ AlignedCodonFrame cf = new AlignedCodonFrame(); // nominal width
for (int s = 0; s < seqs.length; s++)
{
SequenceI dss = seqs[s];
@@ -258,7 +258,9 @@ public class CrossRef
for (int r = 0; xrfs != null && r < xrfs.length; r++)
{
if (source != null && !source.equals(xrfs[r].getSource()))
+ {
continue;
+ }
if (xrfs[r].hasMap())
{
if (xrfs[r].getMap().getTo() != null)
@@ -291,7 +293,9 @@ public class CrossRef
{
found |= searchDataset(dss, xrfs[r], dataset, rseqs, cf); // ,false,!dna);
if (found)
+ {
xrfs[r] = null; // we've recovered seqs for this one.
+ }
}
}
}
@@ -328,7 +332,9 @@ public class CrossRef
for (int r = 0; r < xrfs.length; r++)
{
if (xrfs[r] != null)
+ {
t[l++] = xrfs[r];
+ }
}
xrfs = t;
try
@@ -432,7 +438,9 @@ public class CrossRef
{
boolean found = false;
if (lrfs == null)
+ {
return false;
+ }
for (int i = 0; i < lrfs.length; i++)
{
DBRefEntry xref = new DBRefEntry(lrfs[i]);
@@ -484,7 +492,9 @@ public class CrossRef
boolean found = false;
SequenceI[] typer = new SequenceI[1];
if (dataset == null)
+ {
return false;
+ }
if (dataset.getSequences() == null)
{
System.err.println("Empty dataset sequence set - NO VECTOR");
@@ -494,6 +504,7 @@ public class CrossRef
synchronized (ds = dataset.getSequences())
{
for (SequenceI nxt : ds)
+ {
if (nxt != null)
{
if (nxt.getDatasetSequence() != null)
@@ -566,11 +577,55 @@ public class CrossRef
}
}
+ }
}
return found;
}
/**
+ * Returns true if either sequence has a cross-reference to the other
+ *
+ * @param seq1
+ * @param seq2
+ * @return
+ */
+ public static boolean haveCrossRef(SequenceI seq1, SequenceI seq2)
+ {
+ return hasCrossRef(seq1, seq2) || hasCrossRef(seq2, seq1);
+ }
+
+ /**
+ * Returns true if seq1 has a cross-reference to seq2. Currently this assumes
+ * that sequence name is structured as Source|AccessId.
+ *
+ * @param seq1
+ * @param seq2
+ * @return
+ */
+ public static boolean hasCrossRef(SequenceI seq1, SequenceI seq2)
+ {
+ if (seq1 == null || seq2 == null)
+ {
+ return false;
+ }
+ String name = seq2.getName();
+ final DBRefEntry[] xrefs = seq1.getDBRef();
+ if (xrefs != null)
+ {
+ for (DBRefEntry xref : xrefs)
+ {
+ String xrefName = xref.getSource() + "|" + xref.getAccessionId();
+ // case-insensitive test, consistent with DBRefEntry.equalRef()
+ if (xrefName.equalsIgnoreCase(name))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
* precalculate different products that can be found for seqs in dataset and
* return them.
*
diff --git a/src/jalview/analysis/Dna.java b/src/jalview/analysis/Dna.java
index 00793be..ab606f7 100644
--- a/src/jalview/analysis/Dna.java
+++ b/src/jalview/analysis/Dna.java
@@ -20,120 +20,157 @@
*/
package jalview.analysis;
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.Vector;
-
+import jalview.api.AlignViewportI;
+import jalview.bin.Cache;
+import jalview.datamodel.AlignedCodon;
import jalview.datamodel.AlignedCodonFrame;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.Annotation;
import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
import jalview.datamodel.FeatureProperties;
+import jalview.datamodel.GraphLine;
import jalview.datamodel.Mapping;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
import jalview.schemes.ResidueProperties;
+import jalview.util.Comparison;
+import jalview.util.DBRefUtils;
import jalview.util.MapList;
import jalview.util.ShiftList;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
public class Dna
{
- /**
+ private static final String STOP_X = "X";
+
+ private static final Comparator comparator = new CodonComparator();
+
+ /*
+ * 'final' variables describe the inputs to the translation, which should not
+ * be modified.
+ */
+ final private List selection;
+
+ final private String[] seqstring;
+
+ final private int[] contigs;
+
+ final private char gapChar;
+
+ final private AlignmentAnnotation[] annotations;
+
+ final private int dnaWidth;
+
+ final private Alignment dataset;
+
+ /*
+ * Working variables for the translation.
*
- * @param cdp1
- * @param cdp2
- * @return -1 if cdp1 aligns before cdp2, 0 if in the same column or cdp2 is
- * null, +1 if after cdp2
+ * The width of the translation-in-progress protein alignment.
*/
- private static int compare_codonpos(int[] cdp1, int[] cdp2)
- {
- if (cdp2 == null
- || (cdp1[0] == cdp2[0] && cdp1[1] == cdp2[1] && cdp1[2] == cdp2[2]))
- return 0;
- if (cdp1[0] < cdp2[0] || cdp1[1] < cdp2[1] || cdp1[2] < cdp2[2])
- return -1; // one base in cdp1 precedes the corresponding base in the
- // other codon
- return 1; // one base in cdp1 appears after the corresponding base in the
- // other codon.
- }
+ private int aaWidth = 0;
- /**
- * DNA->mapped protein sequence alignment translation given set of sequences
- * 1. id distinct coding regions within selected region for each sequence 2.
- * generate peptides based on inframe (or given) translation or (optionally
- * and where specified) out of frame translations (annotated appropriately) 3.
- * align peptides based on codon alignment
+ /*
+ * This array will be built up so that position i holds the codon positions
+ * e.g. [7, 9, 10] that match column i (base 0) in the aligned translation.
+ * Note this implies a contract that if two codons do not align exactly, their
+ * translated products must occupy different column positions.
*/
+ private AlignedCodon[] alignedCodons;
+
/**
- * id potential products from dna 1. search for distinct products within
- * selected region for each selected sequence 2. group by associated DB type.
- * 3. return as form for input into above function
+ * Constructor given a viewport and the visible contigs.
+ *
+ * @param viewport
+ * @param visibleContigs
*/
+ public Dna(AlignViewportI viewport, int[] visibleContigs)
+ {
+ this.selection = Arrays.asList(viewport.getSequenceSelection());
+ this.seqstring = viewport.getViewAsString(true);
+ this.contigs = visibleContigs;
+ this.gapChar = viewport.getGapCharacter();
+ this.annotations = viewport.getAlignment().getAlignmentAnnotation();
+ this.dnaWidth = viewport.getAlignment().getWidth();
+ this.dataset = viewport.getAlignment().getDataset();
+ }
+
/**
+ * Test whether codon positions cdp1 should align before, with, or after cdp2.
+ * Returns zero if all positions match (or either argument is null). Returns
+ * -1 if any position in the first codon precedes the corresponding position
+ * in the second codon. Else returns +1 (some position in the second codon
+ * precedes the corresponding position in the first).
+ *
+ * Note this is not necessarily symmetric, for example:
+ *
+ *
compareCodonPos([2,5,6], [3,4,5]) returns -1
+ *
compareCodonPos([3,4,5], [2,5,6]) also returns -1
+ *
*
+ * @param ac1
+ * @param ac2
+ * @return
*/
+ public static final int compareCodonPos(AlignedCodon ac1, AlignedCodon ac2)
+ {
+ return comparator.compare(ac1, ac2);
+ // return jalview_2_8_2compare(ac1, ac2);
+ }
+
/**
- * create a new alignment of protein sequences by an inframe translation of
- * the provided NA sequences
+ * Codon comparison up to Jalview 2.8.2. This rule is sequence order dependent
+ * - see http://issues.jalview.org/browse/JAL-1635
*
- * @param selection
- * @param seqstring
- * @param viscontigs
- * @param gapCharacter
- * @param annotations
- * @param aWidth
- * @param dataset
- * destination dataset for translated sequences and mappings
+ * @param ac1
+ * @param ac2
* @return
*/
- public static AlignmentI CdnaTranslate(SequenceI[] selection,
- String[] seqstring, int viscontigs[], char gapCharacter,
- AlignmentAnnotation[] annotations, int aWidth, Alignment dataset)
+ private static int jalview_2_8_2compare(AlignedCodon ac1, AlignedCodon ac2)
{
- return CdnaTranslate(selection, seqstring, null, viscontigs,
- gapCharacter, annotations, aWidth, dataset);
+ if (ac1 == null || ac2 == null || (ac1.equals(ac2)))
+ {
+ return 0;
+ }
+ if (ac1.pos1 < ac2.pos1 || ac1.pos2 < ac2.pos2 || ac1.pos3 < ac2.pos3)
+ {
+ // one base in cdp1 precedes the corresponding base in the other codon
+ return -1;
+ }
+ // one base in cdp1 appears after the corresponding base in the other codon.
+ return 1;
}
/**
*
- * @param selection
- * @param seqstring
- * @param product
- * - array of DbRefEntry objects from which exon map in seqstring is
- * derived
- * @param viscontigs
- * @param gapCharacter
- * @param annotations
- * @param aWidth
- * @param dataset
* @return
*/
- public static AlignmentI CdnaTranslate(SequenceI[] selection,
- String[] seqstring, DBRefEntry[] product, int viscontigs[],
- char gapCharacter, AlignmentAnnotation[] annotations, int aWidth,
- Alignment dataset)
+ public AlignmentI translateCdna()
{
- AlignedCodonFrame codons = new AlignedCodonFrame(aWidth); // stores hash of
- // subsequent
- // positions for
- // each codon
- // start position
- // in alignment
- int s, sSize = selection.length;
- Vector pepseqs = new Vector();
+ AlignedCodonFrame acf = new AlignedCodonFrame();
+
+ alignedCodons = new AlignedCodon[dnaWidth];
+
+ int s;
+ int sSize = selection.size();
+ List pepseqs = new ArrayList();
for (s = 0; s < sSize; s++)
{
- SequenceI newseq = translateCodingRegion(selection[s], seqstring[s],
- viscontigs, codons, gapCharacter,
- (product != null) ? product[s] : null, false); // possibly
- // anonymous
- // product
+ SequenceI newseq = translateCodingRegion(selection.get(s),
+ seqstring[s], acf, pepseqs);
+
if (newseq != null)
{
- pepseqs.addElement(newseq);
+ pepseqs.add(newseq);
SequenceI ds = newseq;
if (dataset != null)
{
@@ -145,15 +182,15 @@ public class Dna
}
}
}
- if (codons.aaWidth == 0)
- return null;
- SequenceI[] newseqs = new SequenceI[pepseqs.size()];
- pepseqs.copyInto(newseqs);
+
+ SequenceI[] newseqs = pepseqs.toArray(new SequenceI[pepseqs.size()]);
AlignmentI al = new Alignment(newseqs);
- al.padGaps(); // ensure we look aligned.
+ // ensure we look aligned.
+ al.padGaps();
+ // link the protein translation to the DNA dataset
al.setDataset(dataset);
- translateAlignedAnnotations(annotations, al, codons);
- al.addCodonFrame(codons);
+ translateAlignedAnnotations(al, acf);
+ al.addCodonFrame(acf);
return al;
}
@@ -172,14 +209,13 @@ public class Dna
for (int gd = 0; gd < selection.length; gd++)
{
SequenceI dna = selection[gd];
- jalview.datamodel.DBRefEntry[] dnarefs = jalview.util.DBRefUtils
+ DBRefEntry[] dnarefs = DBRefUtils
.selectRefs(dna.getDBRef(),
jalview.datamodel.DBRefSource.DNACODINGDBS);
if (dnarefs != null)
{
// intersect with pep
- // intersect with pep
- Vector mappedrefs = new Vector();
+ List mappedrefs = new ArrayList();
DBRefEntry[] refs = dna.getDBRef();
for (int d = 0; d < refs.length; d++)
{
@@ -187,11 +223,10 @@ public class Dna
&& refs[d].getMap().getMap().getFromRatio() == 3
&& refs[d].getMap().getMap().getToRatio() == 1)
{
- mappedrefs.addElement(refs[d]); // add translated protein maps
+ mappedrefs.add(refs[d]); // add translated protein maps
}
}
- dnarefs = new DBRefEntry[mappedrefs.size()];
- mappedrefs.copyInto(dnarefs);
+ dnarefs = mappedrefs.toArray(new DBRefEntry[mappedrefs.size()]);
for (int d = 0; d < dnarefs.length; d++)
{
Mapping mp = dnarefs[d].getMap();
@@ -214,176 +249,107 @@ public class Dna
}
/**
- * generate a set of translated protein products from annotated sequenceI
+ * Translate nucleotide alignment annotations onto translated amino acid
+ * alignment using codon mapping codons
*
- * @param selection
- * @param viscontigs
- * @param gapCharacter
- * @param dataset
- * destination dataset for translated sequences
- * @param annotations
- * @param aWidth
- * @return
- */
- public static AlignmentI CdnaTranslate(SequenceI[] selection,
- int viscontigs[], char gapCharacter, Alignment dataset)
- {
- int alwidth = 0;
- Vector cdnasqs = new Vector();
- Vector cdnasqi = new Vector();
- Vector cdnaprod = new Vector();
- for (int gd = 0; gd < selection.length; gd++)
- {
- SequenceI dna = selection[gd];
- jalview.datamodel.DBRefEntry[] dnarefs = jalview.util.DBRefUtils
- .selectRefs(dna.getDBRef(),
- jalview.datamodel.DBRefSource.DNACODINGDBS);
- if (dnarefs != null)
- {
- // intersect with pep
- Vector mappedrefs = new Vector();
- DBRefEntry[] refs = dna.getDBRef();
- for (int d = 0; d < refs.length; d++)
- {
- if (refs[d].getMap() != null && refs[d].getMap().getMap() != null
- && refs[d].getMap().getMap().getFromRatio() == 3
- && refs[d].getMap().getMap().getToRatio() == 1)
- {
- mappedrefs.addElement(refs[d]); // add translated protein maps
- }
- }
- dnarefs = new DBRefEntry[mappedrefs.size()];
- mappedrefs.copyInto(dnarefs);
- for (int d = 0; d < dnarefs.length; d++)
- {
- Mapping mp = dnarefs[d].getMap();
- StringBuffer sqstr = new StringBuffer();
- if (mp != null)
- {
- Mapping intersect = mp.intersectVisContigs(viscontigs);
- // generate seqstring for this sequence based on mapping
-
- if (sqstr.length() > alwidth)
- alwidth = sqstr.length();
- cdnasqs.addElement(sqstr.toString());
- cdnasqi.addElement(dna);
- cdnaprod.addElement(intersect);
- }
- }
- }
- SequenceI[] cdna = new SequenceI[cdnasqs.size()];
- DBRefEntry[] prods = new DBRefEntry[cdnaprod.size()];
- String[] xons = new String[cdnasqs.size()];
- cdnasqs.copyInto(xons);
- cdnaprod.copyInto(prods);
- cdnasqi.copyInto(cdna);
- return CdnaTranslate(cdna, xons, prods, viscontigs, gapCharacter,
- null, alwidth, dataset);
- }
- return null;
- }
-
- /**
- * translate na alignment annotations onto translated amino acid alignment al
- * using codon mapping codons
- *
- * @param annotations
* @param al
- * @param codons
+ * the translated protein alignment
*/
- public static void translateAlignedAnnotations(
- AlignmentAnnotation[] annotations, AlignmentI al,
- AlignedCodonFrame codons)
+ protected void translateAlignedAnnotations(AlignmentI al,
+ AlignedCodonFrame acf)
{
- // //////////////////////////////
- // Copy annotations across
- //
// Can only do this for columns with consecutive codons, or where
// annotation is sequence associated.
- int pos, a, aSize;
if (annotations != null)
{
- for (int i = 0; i < annotations.length; i++)
+ for (AlignmentAnnotation annotation : annotations)
{
- // Skip any autogenerated annotation
- if (annotations[i].autoCalculated)
+ /*
+ * Skip hidden or autogenerated annotation. Also (for now), RNA
+ * secondary structure annotation. If we want to show this against
+ * protein we need a smarter way to 'translate' without generating
+ * invalid (unbalanced) structure annotation.
+ */
+ if (annotation.autoCalculated || !annotation.visible
+ || annotation.isRNA())
{
continue;
}
- aSize = codons.getaaWidth(); // aa alignment width.
- jalview.datamodel.Annotation[] anots = (annotations[i].annotations == null) ? null
- : new jalview.datamodel.Annotation[aSize];
+ int aSize = aaWidth;
+ Annotation[] anots = (annotation.annotations == null) ? null
+ : new Annotation[aSize];
if (anots != null)
{
- for (a = 0; a < aSize; a++)
+ for (int a = 0; a < aSize; a++)
{
// process through codon map.
- if (codons.codons[a] != null
- && codons.codons[a][0] == (codons.codons[a][2] - 2))
+ if (a < alignedCodons.length && alignedCodons[a] != null
+ && alignedCodons[a].pos1 == (alignedCodons[a].pos3 - 2))
{
- anots[a] = getCodonAnnotation(codons.codons[a],
- annotations[i].annotations);
+ anots[a] = getCodonAnnotation(alignedCodons[a],
+ annotation.annotations);
}
}
}
- jalview.datamodel.AlignmentAnnotation aa = new jalview.datamodel.AlignmentAnnotation(
- annotations[i].label, annotations[i].description, anots);
- aa.graph = annotations[i].graph;
- aa.graphGroup = annotations[i].graphGroup;
- aa.graphHeight = annotations[i].graphHeight;
- if (annotations[i].getThreshold() != null)
+ AlignmentAnnotation aa = new AlignmentAnnotation(annotation.label,
+ annotation.description, anots);
+ aa.graph = annotation.graph;
+ aa.graphGroup = annotation.graphGroup;
+ aa.graphHeight = annotation.graphHeight;
+ if (annotation.getThreshold() != null)
{
- aa.setThreshold(new jalview.datamodel.GraphLine(annotations[i]
+ aa.setThreshold(new GraphLine(annotation
.getThreshold()));
}
- if (annotations[i].hasScore)
+ if (annotation.hasScore)
{
- aa.setScore(annotations[i].getScore());
+ aa.setScore(annotation.getScore());
}
- if (annotations[i].sequenceRef != null)
+
+ final SequenceI seqRef = annotation.sequenceRef;
+ if (seqRef != null)
{
- SequenceI aaSeq = codons
- .getAaForDnaSeq(annotations[i].sequenceRef);
+ SequenceI aaSeq = acf.getAaForDnaSeq(seqRef);
if (aaSeq != null)
{
// aa.compactAnnotationArray(); // throw away alignment annotation
// positioning
aa.setSequenceRef(aaSeq);
- aa.createSequenceMapping(aaSeq, aaSeq.getStart(), true); // rebuild
- // mapping
+ // rebuild mapping
+ aa.createSequenceMapping(aaSeq, aaSeq.getStart(), true);
aa.adjustForAlignment();
aaSeq.addAlignmentAnnotation(aa);
}
-
}
al.addAnnotation(aa);
}
}
}
- private static Annotation getCodonAnnotation(int[] is,
+ private static Annotation getCodonAnnotation(AlignedCodon is,
Annotation[] annotations)
{
// Have a look at all the codon positions for annotation and put the first
// one found into the translated annotation pos.
int contrib = 0;
Annotation annot = null;
- for (int p = 0; p < 3; p++)
+ for (int p = 1; p <= 3; p++)
{
- if (annotations[is[p]] != null)
+ int dnaCol = is.getBaseColumn(p);
+ if (annotations[dnaCol] != null)
{
if (annot == null)
{
- annot = new Annotation(annotations[is[p]]);
+ annot = new Annotation(annotations[dnaCol]);
contrib = 1;
}
else
{
// merge with last
- Annotation cpy = new Annotation(annotations[is[p]]);
+ Annotation cpy = new Annotation(annotations[dnaCol]);
if (annot.colour == null)
{
annot.colour = cpy.colour;
@@ -407,7 +373,7 @@ public class Dna
}
if (contrib > 1)
{
- annot.value /= (float) contrib;
+ annot.value /= contrib;
}
return annot;
}
@@ -419,92 +385,72 @@ public class Dna
* sequence displayed under viscontigs visible columns
* @param seqstring
* ORF read in some global alignment reference frame
- * @param viscontigs
- * mapping from global reference frame to visible seqstring ORF read
- * @param codons
- * Definition of global ORF alignment reference frame
- * @param gapCharacter
- * @return sequence ready to be added to alignment.
- * @deprecated Use
- * {@link #translateCodingRegion(SequenceI,String,int[],AlignedCodonFrame,char,DBRefEntry,boolean)}
- * instead
- */
- public static SequenceI translateCodingRegion(SequenceI selection,
- String seqstring, int[] viscontigs, AlignedCodonFrame codons,
- char gapCharacter, DBRefEntry product)
- {
- return translateCodingRegion(selection, seqstring, viscontigs, codons,
- gapCharacter, product, false);
- }
-
- /**
- * Translate a na sequence
- *
- * @param selection
- * sequence displayed under viscontigs visible columns
- * @param seqstring
- * ORF read in some global alignment reference frame
- * @param viscontigs
- * mapping from global reference frame to visible seqstring ORF read
- * @param codons
+ * @param acf
* Definition of global ORF alignment reference frame
- * @param gapCharacter
- * @param starForStop
- * when true stop codons will translate as '*', otherwise as 'X'
+ * @param proteinSeqs
* @return sequence ready to be added to alignment.
*/
- public static SequenceI translateCodingRegion(SequenceI selection,
- String seqstring, int[] viscontigs, AlignedCodonFrame codons,
- char gapCharacter, DBRefEntry product, final boolean starForStop)
+ protected SequenceI translateCodingRegion(SequenceI selection,
+ String seqstring, AlignedCodonFrame acf,
+ List proteinSeqs)
{
- java.util.List skip = new ArrayList();
+ List skip = new ArrayList();
int skipint[] = null;
ShiftList vismapping = new ShiftList(); // map from viscontigs to seqstring
// intervals
- int vc, scontigs[] = new int[viscontigs.length];
+ int vc;
+ int[] scontigs = new int[contigs.length];
int npos = 0;
- for (vc = 0; vc < viscontigs.length; vc += 2)
+ for (vc = 0; vc < contigs.length; vc += 2)
{
if (vc == 0)
{
- vismapping.addShift(npos, viscontigs[vc]);
+ vismapping.addShift(npos, contigs[vc]);
}
else
{
// hidden region
- vismapping.addShift(npos, viscontigs[vc] - viscontigs[vc - 1] + 1);
+ vismapping.addShift(npos, contigs[vc] - contigs[vc - 1] + 1);
}
- scontigs[vc] = viscontigs[vc];
- scontigs[vc + 1] = viscontigs[vc + 1];
+ scontigs[vc] = contigs[vc];
+ scontigs[vc + 1] = contigs[vc + 1];
}
- StringBuffer protein = new StringBuffer();
- String seq = seqstring.replace('U', 'T');
+ // allocate a roughly sized buffer for the protein sequence
+ StringBuilder protein = new StringBuilder(seqstring.length() / 2);
+ String seq = seqstring.replace('U', 'T').replace('u', 'T');
char codon[] = new char[3];
- int cdp[] = new int[3], rf = 0, lastnpos = 0, nend;
+ int cdp[] = new int[3];
+ int rf = 0;
+ int lastnpos = 0;
+ int nend;
int aspos = 0;
int resSize = 0;
for (npos = 0, nend = seq.length(); npos < nend; npos++)
{
- if (!jalview.util.Comparison.isGap(seq.charAt(npos)))
+ if (!Comparison.isGap(seq.charAt(npos)))
{
cdp[rf] = npos; // store position
codon[rf++] = seq.charAt(npos); // store base
}
- // filled an RF yet ?
if (rf == 3)
{
+ /*
+ * Filled up a reading frame...
+ */
+ AlignedCodon alignedCodon = new AlignedCodon(cdp[0], cdp[1], cdp[2]);
String aa = ResidueProperties.codonTranslate(new String(codon));
rf = 0;
+ final String gapString = String.valueOf(gapChar);
if (aa == null)
{
- aa = String.valueOf(gapCharacter);
+ aa = gapString;
if (skipint == null)
{
skipint = new int[]
- { cdp[0], cdp[2] };
+ { alignedCodon.pos1, alignedCodon.pos3 /* cdp[0], cdp[2] */};
}
- skipint[1] = cdp[2];
+ skipint[1] = alignedCodon.pos3; // cdp[2];
}
else
{
@@ -599,52 +545,66 @@ public class Dna
}
if (aa.equals("STOP"))
{
- aa = starForStop ? "*" : "X";
+ aa = STOP_X;
}
resSize++;
}
- // insert/delete gaps prior to this codon - if necessary
boolean findpos = true;
while (findpos)
{
- // first ensure that the codons array is long enough.
- codons.checkCodonFrameWidth(aspos);
- // now check to see if we place the aa at the current aspos in the
- // protein alignment
- switch (Dna.compare_codonpos(cdp, codons.codons[aspos]))
+ /*
+ * Compare this codon's base positions with those currently aligned to
+ * this column in the translation.
+ */
+ final int compareCodonPos = compareCodonPos(alignedCodon,
+ alignedCodons[aspos]);
+ switch (compareCodonPos)
{
case -1:
- codons.insertAAGap(aspos, gapCharacter);
+
+ /*
+ * This codon should precede the mapped positions - need to insert a
+ * gap in all prior sequences.
+ */
+ insertAAGap(aspos, proteinSeqs);
findpos = false;
break;
+
case +1:
- // this aa appears after the aligned codons at aspos, so prefix it
- // with a gap
- aa = "" + gapCharacter + aa;
+
+ /*
+ * This codon belongs after the aligned codons at aspos. Prefix it
+ * with a gap and try the next position.
+ */
+ aa = gapString + aa;
aspos++;
- // if (aspos >= codons.aaWidth)
- // codons.aaWidth = aspos + 1;
- break; // check the next position for alignment
+ break;
+
case 0:
- // codon aligns at aspos position.
+
+ /*
+ * Exact match - codon 'belongs' at this translated position.
+ */
findpos = false;
}
}
- // codon aligns with all other sequence residues found at aspos
protein.append(aa);
lastnpos = npos;
- if (codons.codons[aspos] == null)
+ if (alignedCodons[aspos] == null)
{
// mark this column as aligning to this aligned reading frame
- codons.codons[aspos] = new int[]
- { cdp[0], cdp[1], cdp[2] };
+ alignedCodons[aspos] = alignedCodon;
+ }
+ else if (!alignedCodons[aspos].equals(alignedCodon))
+ {
+ throw new IllegalStateException("Tried to coalign "
+ + alignedCodons[aspos].toString() + " with "
+ + alignedCodon.toString());
}
- if (aspos >= codons.aaWidth)
+ if (aspos >= aaWidth)
{
// update maximum alignment width
- // (we can do this without calling checkCodonFrameWidth because it was
- // already done above)
- codons.setAaWidth(aspos);
+ aaWidth = aspos;
}
// ready for next translated reading frame alignment position (if any)
aspos++;
@@ -656,15 +616,14 @@ public class Dna
protein.toString());
if (rf != 0)
{
- if (jalview.bin.Cache.log != null)
+ final String errMsg = "trimming contigs for incomplete terminal codon.";
+ if (Cache.log != null)
{
- jalview.bin.Cache.log
- .debug("trimming contigs for incomplete terminal codon.");
+ Cache.log.debug(errMsg);
}
else
{
- System.err
- .println("trimming contigs for incomplete terminal codon.");
+ System.err.println(errMsg);
}
// map and trim contigs to ORF region
vc = scontigs.length - 1;
@@ -694,7 +653,9 @@ public class Dna
scontigs = t;
}
if (vc <= 0)
+ {
scontigs = null;
+ }
}
if (scontigs != null)
{
@@ -705,7 +666,9 @@ public class Dna
scontigs[vc] = selection.findPosition(scontigs[vc]); // not from 1!
scontigs[vc + 1] = selection.findPosition(scontigs[vc + 1]); // exclusive
if (scontigs[vc + 1] == selection.getEnd())
+ {
break;
+ }
}
// trim trailing empty intervals.
if ((vc + 2) < scontigs.length)
@@ -731,27 +694,19 @@ public class Dna
MapList map = new MapList(scontigs, new int[]
{ 1, resSize }, 3, 1);
- // update newseq as if it was generated as mapping from product
-
- if (product != null)
- {
- newseq.setName(product.getSource() + "|"
- + product.getAccessionId());
- if (product.getMap() != null)
- {
- // Mapping mp = product.getMap();
- // newseq.setStart(mp.getPosition(scontigs[0]));
- // newseq.setEnd(mp
- // .getPosition(scontigs[scontigs.length - 1]));
- }
- }
transferCodedFeatures(selection, newseq, map, null, null);
- SequenceI rseq = newseq.deriveSequence(); // construct a dataset
- // sequence for our new
- // peptide, regardless.
- // store a mapping (this actually stores a mapping between the dataset
- // sequences for the two sequences
- codons.addMap(selection, rseq, map);
+
+ /*
+ * Construct a dataset sequence for our new peptide.
+ */
+ SequenceI rseq = newseq.deriveSequence();
+
+ /*
+ * Store a mapping (between the dataset sequences for the two
+ * sequences).
+ */
+ // SIDE-EFFECT: acf stores the aligned sequence reseq; to remove!
+ acf.addMap(selection, rseq, map);
return rseq;
}
}
@@ -761,6 +716,53 @@ public class Dna
}
/**
+ * Insert a gap into the aligned proteins and the codon mapping array.
+ *
+ * @param pos
+ * @param proteinSeqs
+ * @return
+ */
+ protected void insertAAGap(int pos,
+ List proteinSeqs)
+ {
+ aaWidth++;
+ for (SequenceI seq : proteinSeqs)
+ {
+ seq.insertCharAt(pos, gapChar);
+ }
+
+ checkCodonFrameWidth();
+ if (pos < aaWidth)
+ {
+ aaWidth++;
+
+ /*
+ * Shift from [pos] to the end one to the right, and null out [pos]
+ */
+ System.arraycopy(alignedCodons, pos, alignedCodons, pos + 1,
+ alignedCodons.length - pos - 1);
+ alignedCodons[pos] = null;
+ }
+ }
+
+ /**
+ * Check the codons array can accommodate a single insertion, if not resize
+ * it.
+ */
+ protected void checkCodonFrameWidth()
+ {
+ if (alignedCodons[alignedCodons.length - 1] != null)
+ {
+ /*
+ * arraycopy insertion would bump a filled slot off the end, so expand.
+ */
+ AlignedCodon[] c = new AlignedCodon[alignedCodons.length + 10];
+ System.arraycopy(alignedCodons, 0, c, 0, alignedCodons.length);
+ alignedCodons = c;
+ }
+ }
+
+ /**
* Given a peptide newly translated from a dna sequence, copy over and set any
* features on the peptide from the DNA. If featureTypes is null, all features
* on the dna sequence are searched (rather than just the displayed ones), and
@@ -770,20 +772,19 @@ public class Dna
* @param pep
* @param map
* @param featureTypes
- * hash who's keys are the displayed feature type strings
+ * hash whose keys are the displayed feature type strings
* @param featureGroups
* hash where keys are feature groups and values are Boolean objects
* indicating if they are displayed.
*/
private static void transferCodedFeatures(SequenceI dna, SequenceI pep,
- MapList map, Hashtable featureTypes, Hashtable featureGroups)
+ MapList map, Map featureTypes,
+ Map featureGroups)
{
- SequenceFeature[] sf = (dna.getDatasetSequence() != null ? dna
- .getDatasetSequence() : dna).getSequenceFeatures();
+ SequenceFeature[] sfs = dna.getSequenceFeatures();
Boolean fgstate;
- jalview.datamodel.DBRefEntry[] dnarefs = jalview.util.DBRefUtils
- .selectRefs(dna.getDBRef(),
- jalview.datamodel.DBRefSource.DNACODINGDBS);
+ DBRefEntry[] dnarefs = DBRefUtils.selectRefs(dna.getDBRef(),
+ DBRefSource.DNACODINGDBS);
if (dnarefs != null)
{
// intersect with pep
@@ -795,16 +796,16 @@ public class Dna
}
}
}
- if (sf != null)
+ if (sfs != null)
{
- for (int f = 0; f < sf.length; f++)
+ for (SequenceFeature sf : sfs)
{
- fgstate = (featureGroups == null) ? null : ((Boolean) featureGroups
- .get(sf[f].featureGroup));
- if ((featureTypes == null || featureTypes.containsKey(sf[f]
- .getType())) && (fgstate == null || fgstate.booleanValue()))
+ fgstate = (featureGroups == null) ? null : featureGroups
+ .get(sf.featureGroup);
+ if ((featureTypes == null || featureTypes.containsKey(sf.getType()))
+ && (fgstate == null || fgstate.booleanValue()))
{
- if (FeatureProperties.isCodingFeature(null, sf[f].getType()))
+ if (FeatureProperties.isCodingFeature(null, sf.getType()))
{
// if (map.intersectsFrom(sf[f].begin, sf[f].end))
{
diff --git a/src/jalview/analysis/SequenceIdMatcher.java b/src/jalview/analysis/SequenceIdMatcher.java
index c3d7ac1..e6a4853 100755
--- a/src/jalview/analysis/SequenceIdMatcher.java
+++ b/src/jalview/analysis/SequenceIdMatcher.java
@@ -20,9 +20,12 @@
*/
package jalview.analysis;
-import java.util.*;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.SequenceI;
-import jalview.datamodel.*;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Vector;
/**
* Routines for approximate Sequence Id resolution by name using string
@@ -258,14 +261,20 @@ public class SequenceIdMatcher
}
}
+ @Override
public int hashCode()
{
return ((id.length() >= 4) ? id.substring(0, 4).hashCode() : id
.hashCode());
}
+ @Override
public boolean equals(Object s)
{
+ if (s == null)
+ {
+ return false;
+ }
if (s instanceof SeqIdName)
{
return this.equals((SeqIdName) s);
diff --git a/src/jalview/analysis/StructureFrequency.java b/src/jalview/analysis/StructureFrequency.java
index 65dd84a..3c8274e 100644
--- a/src/jalview/analysis/StructureFrequency.java
+++ b/src/jalview/analysis/StructureFrequency.java
@@ -20,10 +20,14 @@
*/
package jalview.analysis;
-import java.util.*;
-
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
import jalview.util.Format;
-import jalview.datamodel.*;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
/**
* Takes in a vector or array of sequences and column start and column end and
@@ -36,6 +40,8 @@ import jalview.datamodel.*;
*/
public class StructureFrequency
{
+ public static final int STRUCTURE_PROFILE_LENGTH = 74;
+
// No need to store 1000s of strings which are not
// visible to the user.
public static final String MAXCOUNT = "C";
@@ -187,6 +193,7 @@ public class StructureFrequency
// UPDATE this for new values
if (profile)
{
+ // TODO 1-dim array with jsize in [0], nongapped in [1]; or Pojo
residueHash.put(PROFILE, new int[][]
{ values, new int[]
{ jSize, (jSize - values['-']) } });
@@ -413,7 +420,7 @@ public class StructureFrequency
* ((c == 0) ? "" : "; ") + alphabet[c] + " " + ((int) tval) + "%"; } }
* else {
*/
- Object[] ca = new Object[625];
+ int[][] ca = new int[625][];
float[] vl = new float[625];
int x = 0;
for (int c = 65; c < 90; c++)
@@ -429,14 +436,18 @@ public class StructureFrequency
jalview.util.QuickSort.sort(vl, ca);
int p = 0;
+ /*
+ * profile[1] is {total, ungappedTotal}
+ */
+ final int divisor = profile[1][ignoreGapsInConsensusCalculation ? 1
+ : 0];
for (int c = 624; c > 0; c--)
{
if (vl[c] > 0)
{
- tval = (vl[c] * 100f / profile[1][ignoreGapsInConsensusCalculation ? 1
- : 0]);
- mouseOver += ((p == 0) ? "" : "; ") + (char) ((int[]) ca[c])[0]
- + (char) ((int[]) ca[c])[1] + " " + fmt.form(tval)
+ tval = (vl[c] * 100f / divisor);
+ mouseOver += ((p == 0) ? "" : "; ") + (char) ca[c][0]
+ + (char) ca[c][1] + " " + fmt.form(tval)
+ "%";
p++;
@@ -463,16 +474,19 @@ public class StructureFrequency
public static int[] extractProfile(Hashtable hconsensus,
boolean ignoreGapsInConsensusCalculation)
{
- int[] rtnval = new int[74]; // 2*(5*5)+2
+ int[] rtnval = new int[STRUCTURE_PROFILE_LENGTH]; // 2*(5*5)+2
int[][] profile = (int[][]) hconsensus.get(StructureFrequency.PROFILE);
int[][] pairs = (int[][]) hconsensus
.get(StructureFrequency.PAIRPROFILE);
if (profile == null)
+ {
return null;
+ }
// TODO fix the object length, also do it in completeConsensus
- Object[] ca = new Object[625];
+ // Object[] ca = new Object[625];
+ int[][] ca = new int[625][];
float[] vl = new float[625];
int x = 0;
for (int c = 65; c < 90; c++)
@@ -487,21 +501,28 @@ public class StructureFrequency
}
jalview.util.QuickSort.sort(vl, ca);
- rtnval[0] = 2;
+ int valuesCount = 0;
rtnval[1] = 0;
+ int offset = 2;
+ final int divisor = profile[1][ignoreGapsInConsensusCalculation ? 1 : 0];
for (int c = 624; c > 0; c--)
{
if (vl[c] > 0)
{
- rtnval[rtnval[0]++] = ((int[]) ca[c])[0];
- rtnval[rtnval[0]++] = ((int[]) ca[c])[1];
- rtnval[rtnval[0]] = (int) (vl[c] * 100f / profile[1][ignoreGapsInConsensusCalculation ? 1
- : 0]);
- rtnval[1] += rtnval[rtnval[0]++];
+ rtnval[offset++] = ca[c][0];
+ rtnval[offset++] = ca[c][1];
+ rtnval[offset] = (int) (vl[c] * 100f / divisor);
+ rtnval[1] += rtnval[offset++];
+ valuesCount++;
}
}
+ rtnval[0] = valuesCount;
- return rtnval;
+ // insert profile type code in position 0
+ int[] result = new int[rtnval.length + 1];
+ result[0] = AlignmentAnnotation.STRUCTURE_PROFILE;
+ System.arraycopy(rtnval, 0, result, 1, rtnval.length);
+ return result;
}
public static void main(String args[])
diff --git a/src/jalview/api/AlignViewportI.java b/src/jalview/api/AlignViewportI.java
index 6faa133..c49ee39 100644
--- a/src/jalview/api/AlignViewportI.java
+++ b/src/jalview/api/AlignViewportI.java
@@ -40,7 +40,7 @@ import java.util.Map;
* @author jimp
*
*/
-public interface AlignViewportI
+public interface AlignViewportI extends ViewStyleI
{
int getCharWidth();
@@ -75,11 +75,16 @@ public interface AlignViewportI
Hashtable[] getSequenceConsensusHash();
- Hashtable[] getRnaStructureConsensusHash();
+ /**
+ * Get consensus data table for the cDNA complement of this alignment (if any)
+ *
+ * @return
+ */
+ Hashtable[] getComplementConsensusHash();
- boolean getIgnoreGapsConsensus();
+ Hashtable[] getRnaStructureConsensusHash();
- boolean getCentreColumnLabels();
+ boolean isIgnoreGapsConsensus();
boolean isCalculationInProgress(AlignmentAnnotation alignmentAnnotation);
@@ -95,6 +100,13 @@ public interface AlignViewportI
AlignmentAnnotation getAlignmentConsensusAnnotation();
/**
+ * get the container for cDNA complement consensus annotation
+ *
+ * @return
+ */
+ AlignmentAnnotation getComplementConsensusAnnotation();
+
+ /**
* Test to see if viewport is still open and active
*
* @return true indicates that all references to viewport should be dropped
@@ -122,6 +134,13 @@ public interface AlignViewportI
void setSequenceConsensusHash(Hashtable[] hconsensus);
/**
+ * Set the cDNA complement consensus for the viewport
+ *
+ * @param hconsensus
+ */
+ void setComplementConsensusHash(Hashtable[] hconsensus);
+
+ /**
*
* @return the alignment annotatino row for the structure consensus
* calculation
@@ -320,10 +339,9 @@ public interface AlignViewportI
* first column (inclusive, from 0)
* @param max
* last column (exclusive)
- * @return int[][] range of {start,end} visible positions TODO: change to list
- * of int ranges
+ * @return int[][] range of {start,end} visible positions
*/
- int[][] getVisibleRegionBoundaries(int min, int max);
+ List getVisibleRegionBoundaries(int min, int max);
/**
* This method returns an array of new SequenceI objects derived from the
@@ -354,4 +372,45 @@ public interface AlignViewportI
boolean hasHiddenRows();
+ /**
+ *
+ * @return a copy of this view's current display settings
+ */
+ public ViewStyleI getViewStyle();
+
+ /**
+ * update the view's display settings with the given style set
+ *
+ * @param settingsForView
+ */
+ public void setViewStyle(ViewStyleI settingsForView);
+
+ /**
+ * Returns a viewport which holds the cDna for this (protein), or vice versa,
+ * or null if none is set.
+ *
+ * @return
+ */
+ AlignViewportI getCodingComplement();
+
+ /**
+ * Sets the viewport which holds the cDna for this (protein), or vice versa.
+ * Implementation should guarantee that the reciprocal relationship is always
+ * set, i.e. each viewport is the complement of the other.
+ */
+ void setCodingComplement(AlignViewportI sl);
+
+ /**
+ * Answers true if viewport hosts DNA/RNA, else false.
+ *
+ * @return
+ */
+ boolean isNucleotide();
+
+ /**
+ * Returns an id guaranteed to be unique for this viewport.
+ *
+ * @return
+ */
+ String getViewId();
}
diff --git a/src/jalview/api/AlignmentViewPanel.java b/src/jalview/api/AlignmentViewPanel.java
index 09ccbb4..f0fd2e1 100644
--- a/src/jalview/api/AlignmentViewPanel.java
+++ b/src/jalview/api/AlignmentViewPanel.java
@@ -32,6 +32,8 @@ import jalview.structure.StructureSelectionManager;
public interface AlignmentViewPanel extends OOMHandlerI
{
+ AlignViewportI getAlignViewport();
+
AlignmentI getAlignment();
StructureSelectionManager getStructureSelectionManager();
diff --git a/src/jalview/api/SplitContainerI.java b/src/jalview/api/SplitContainerI.java
new file mode 100644
index 0000000..b9c3121
--- /dev/null
+++ b/src/jalview/api/SplitContainerI.java
@@ -0,0 +1,38 @@
+package jalview.api;
+
+import jalview.datamodel.AlignmentI;
+
+/**
+ * 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);
+
+ /**
+ * Returns the alignment that is complementary to the one in the given
+ * AlignFrame, or null.
+ */
+ AlignmentI getComplement(Object af);
+
+ /**
+ * Returns the frame title for the alignment that is complementary to the one
+ * in the given AlignFrame, or null.
+ *
+ * @param af
+ * @return
+ */
+ String getComplementTitle(Object af);
+
+}
diff --git a/src/jalview/api/ViewStyleI.java b/src/jalview/api/ViewStyleI.java
new file mode 100644
index 0000000..8fa7f8f
--- /dev/null
+++ b/src/jalview/api/ViewStyleI.java
@@ -0,0 +1,202 @@
+package jalview.api;
+
+import java.awt.Color;
+
+public interface ViewStyleI
+{
+
+ void setColourAppliesToAllGroups(boolean b);
+
+ boolean getColourAppliesToAllGroups();
+
+ boolean getAbovePIDThreshold();
+
+ void setIncrement(int inc);
+
+ int getIncrement();
+
+ boolean getConservationSelected();
+
+ void setConservationSelected(boolean b);
+
+ void setShowHiddenMarkers(boolean show);
+
+ boolean getShowHiddenMarkers();
+
+ void setScaleRightWrapped(boolean b);
+
+ void setScaleLeftWrapped(boolean b);
+
+ void setScaleAboveWrapped(boolean b);
+
+ boolean getScaleLeftWrapped();
+
+ boolean getScaleAboveWrapped();
+
+ boolean getScaleRightWrapped();
+
+ void setAbovePIDThreshold(boolean b);
+
+ void setThreshold(int thresh);
+
+ int getThreshold();
+
+ boolean getShowJVSuffix();
+
+ void setShowJVSuffix(boolean b);
+
+ void setWrapAlignment(boolean state);
+
+ void setShowText(boolean state);
+
+ void setRenderGaps(boolean state);
+
+ boolean getColourText();
+
+ void setColourText(boolean state);
+
+ void setShowBoxes(boolean state);
+
+ boolean getWrapAlignment();
+
+ boolean getShowText();
+
+ int getWrappedWidth();
+
+ void setWrappedWidth(int w);
+
+ int getCharHeight();
+
+ void setCharHeight(int h);
+
+ int getCharWidth();
+
+ void setCharWidth(int w);
+
+ boolean getShowBoxes();
+
+ boolean getShowUnconserved();
+
+ void setShowUnconserved(boolean showunconserved);
+
+ boolean isDisplayReferenceSeq();
+
+ void setDisplayReferenceSeq(boolean displayReferenceSeq);
+
+ boolean isColourByReferenceSeq();
+
+ void setSeqNameItalics(boolean default1);
+
+ void setShowSequenceFeatures(boolean b);
+
+ boolean isShowSequenceFeatures();
+
+ boolean isRightAlignIds();
+
+ void setRightAlignIds(boolean rightAlignIds);
+
+ boolean isShowAnnotation();
+
+ void setShowAnnotation(boolean b);
+
+ void setShowSeqFeaturesHeight(boolean selected);
+
+ boolean isShowSequenceFeaturesHeight();
+
+ void setColourByReferenceSeq(boolean colourByReferenceSeq);
+
+ Color getTextColour();
+
+ Color getTextColour2();
+
+ int getThresholdTextColour();
+
+ boolean isConservationColourSelected();
+
+ boolean isRenderGaps();
+
+ boolean isShowColourText();
+
+ boolean isShowSeqFeaturesHeight();
+
+ void setConservationColourSelected(boolean conservationColourSelected);
+
+ void setShowColourText(boolean showColourText);
+
+ void setTextColour(Color textColour);
+
+ void setThresholdTextColour(int thresholdTextColour);
+
+ void setTextColour2(Color textColour2);
+
+ boolean isSeqNameItalics();
+
+ void setUpperCasebold(boolean upperCasebold);
+
+ boolean isUpperCasebold();
+
+ boolean sameStyle(ViewStyleI them);
+
+ void setFontName(String name);
+
+ void setFontStyle(int style);
+
+ void setFontSize(int size);
+
+ int getFontStyle();
+
+ String getFontName();
+
+ int getFontSize();
+
+ /**
+ * @return width of Sequence and Annotation ID margin. If less than zero, then
+ * width will be autocalculated
+ */
+ int getIdWidth();
+
+ /**
+ * Set width if
+ *
+ * @param i
+ */
+
+ void setIdWidth(int i);
+
+ /**
+ * centre columnar annotation labels in displayed alignment annotation
+ */
+ boolean isCentreColumnLabels();
+
+ /**
+ * centre columnar annotation labels in displayed alignment annotation
+ */
+ void setCentreColumnLabels(boolean centreColumnLabels);
+
+ /**
+ * enable or disable the display of Database Cross References in the sequence
+ * ID tooltip
+ */
+ void setShowDBRefs(boolean showdbrefs);
+
+ /**
+ *
+ * @return true if Database References are to be displayed on tooltips.
+ */
+ boolean isShowDBRefs();
+
+ /**
+ *
+ * @return true if Non-positional features are to be displayed on tooltips.
+ */
+ boolean isShowNPFeats();
+
+ /**
+ * enable or disable the display of Non-Positional sequence features in the
+ * sequence ID tooltip
+ *
+ * @param show
+ */
+ void setShowNPFeats(boolean shownpfeats);
+
+}
diff --git a/src/jalview/appletgui/APopupMenu.java b/src/jalview/appletgui/APopupMenu.java
index 1059863..d71fdd4 100644
--- a/src/jalview/appletgui/APopupMenu.java
+++ b/src/jalview/appletgui/APopupMenu.java
@@ -20,14 +20,33 @@
*/
package jalview.appletgui;
+import java.awt.CheckboxMenuItem;
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuItem;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.Vector;
+
import jalview.analysis.AAFrequency;
+import jalview.analysis.AlignmentAnnotationUtils;
+import jalview.analysis.AlignmentUtils;
import jalview.analysis.Conservation;
import jalview.commands.ChangeCaseCommand;
import jalview.commands.EditCommand;
import jalview.commands.EditCommand.Action;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.PDBEntry;
-import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
@@ -48,19 +67,11 @@ import jalview.schemes.ZappoColourScheme;
import jalview.util.MessageManager;
import jalview.util.UrlLink;
-import java.awt.CheckboxMenuItem;
-import java.awt.Frame;
-import java.awt.Menu;
-import java.awt.MenuItem;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.util.Vector;
-
public class APopupMenu extends java.awt.PopupMenu implements
ActionListener, ItemListener
{
+ private static final String ALL_ANNOTATIONS = "All";
+
Menu groupMenu = new Menu();
MenuItem editGroupName = new MenuItem();
@@ -111,12 +122,29 @@ public class APopupMenu extends java.awt.PopupMenu implements
CheckboxMenuItem displayNonconserved = new CheckboxMenuItem();
+ Menu seqShowAnnotationsMenu = new Menu(
+ MessageManager.getString("label.show_annotations"));
+
+ Menu seqHideAnnotationsMenu = new Menu(
+ MessageManager.getString("label.hide_annotations"));
+
+ MenuItem seqAddReferenceAnnotations = new MenuItem(
+ MessageManager.getString("label.add_reference_annotations"));
+
+ Menu groupShowAnnotationsMenu = new Menu(
+ MessageManager.getString("label.show_annotations"));
+
+ Menu groupHideAnnotationsMenu = new Menu(
+ MessageManager.getString("label.hide_annotations"));
+
+ MenuItem groupAddReferenceAnnotations = new MenuItem(
+ MessageManager.getString("label.add_reference_annotations"));
+
Menu editMenu = new Menu(MessageManager.getString("action.edit"));
- MenuItem copy = new MenuItem(
- MessageManager.getString("label.jalview_copy"));
+ MenuItem copy = new MenuItem(MessageManager.getString("action.copy"));
- MenuItem cut = new MenuItem(MessageManager.getString("label.jalview_cut"));
+ MenuItem cut = new MenuItem(MessageManager.getString("action.cut"));
MenuItem toUpper = new MenuItem(
MessageManager.getString("label.to_upper_case"));
@@ -154,7 +182,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
MenuItem makeReferenceSeq = new MenuItem();
- Sequence seq;
+ SequenceI seq;
MenuItem revealAll = new MenuItem();
@@ -167,7 +195,8 @@ public class APopupMenu extends java.awt.PopupMenu implements
Menu menu1 = new Menu();
- public APopupMenu(AlignmentPanel apanel, final Sequence seq, Vector links)
+ public APopupMenu(AlignmentPanel apanel, final SequenceI seq,
+ Vector links)
{
// /////////////////////////////////////////////////////////
// If this is activated from the sequence panel, the user may want to
@@ -196,12 +225,13 @@ public class APopupMenu extends java.awt.PopupMenu implements
outputmenu.add(item);
}
- SequenceGroup sg = ap.av.getSelectionGroup();
+ buildAnnotationSubmenus();
+ SequenceGroup sg = ap.av.getSelectionGroup();
if (sg != null && sg.getSize() > 0)
{
editGroupName.setLabel(MessageManager.formatMessage(
- "label.name_param", new String[]
+ "label.name_param", new Object[]
{ sg.getName() }));
showText.setState(sg.getDisplayText());
showColourText.setState(sg.getColourText());
@@ -228,10 +258,9 @@ public class APopupMenu extends java.awt.PopupMenu implements
if (links != null && links.size() > 0)
{
Menu linkMenu = new Menu(MessageManager.getString("action.link"));
- String link;
for (int i = 0; i < links.size(); i++)
{
- link = links.elementAt(i).toString();
+ String link = links.elementAt(i);
UrlLink urlLink = new UrlLink(link);
if (!urlLink.isValid())
{
@@ -361,7 +390,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
.getString("action.set_as_reference")); // );
}
repGroup.setLabel(MessageManager.formatMessage(
- "label.represent_group_with", new String[]
+ "label.represent_group_with", new Object[]
{ seq.getName() }));
}
else
@@ -391,6 +420,95 @@ public class APopupMenu extends java.awt.PopupMenu implements
}
/**
+ * Build menus for annotation types that may be shown or hidden, and for
+ * 'reference annotations' that may be added to the alignment.
+ */
+ private void buildAnnotationSubmenus()
+ {
+ /*
+ * First for the currently selected sequence (if there is one):
+ */
+ final List selectedSequence = (seq == null ? Collections
+ . emptyList() : Arrays.asList(seq));
+ buildAnnotationTypesMenus(seqShowAnnotationsMenu,
+ seqHideAnnotationsMenu, selectedSequence);
+ configureReferenceAnnotationsMenu(seqAddReferenceAnnotations,
+ selectedSequence);
+
+ /*
+ * and repeat for the current selection group (if there is one):
+ */
+ final List selectedGroup = (ap.av.getSelectionGroup() == null ? Collections
+ . emptyList() : ap.av.getSelectionGroup()
+ .getSequences());
+ buildAnnotationTypesMenus(groupShowAnnotationsMenu,
+ groupHideAnnotationsMenu, selectedGroup);
+ configureReferenceAnnotationsMenu(groupAddReferenceAnnotations,
+ selectedGroup);
+ }
+
+ /**
+ * Determine whether or not to enable 'add reference annotations' menu item.
+ * It is enable if there are any annotations, on any of the selected
+ * sequences, which are not yet on the alignment (visible or not).
+ *
+ * @param menu
+ * @param forSequences
+ */
+ private void configureReferenceAnnotationsMenu(MenuItem menuItem,
+ List forSequences)
+ {
+ menuItem.setEnabled(false);
+
+ /*
+ * Temporary store to hold distinct calcId / type pairs for the tooltip.
+ * Using TreeMap means calcIds are shown in alphabetical order.
+ */
+ Map tipEntries = new TreeMap();
+ final Map> candidates = new LinkedHashMap>();
+ AlignmentI al = this.ap.av.getAlignment();
+ AlignmentUtils.findAddableReferenceAnnotations(forSequences,
+ tipEntries, candidates, al);
+ if (!candidates.isEmpty())
+ {
+ StringBuilder tooltip = new StringBuilder(64);
+ tooltip.append(MessageManager.getString("label.add_annotations_for"));
+
+ /*
+ * Found annotations that could be added. Enable the menu item, and
+ * configure its action.
+ */
+ menuItem.setEnabled(true);
+
+ menuItem.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ addReferenceAnnotations_actionPerformed(candidates);
+ }
+ });
+ }
+ }
+
+ /**
+ * Add annotations to the sequences and to the alignment.
+ *
+ * @param candidates
+ * a map whose keys are sequences on the alignment, and values a list
+ * of annotations to add to each sequence
+ */
+ protected void addReferenceAnnotations_actionPerformed(
+ Map> candidates)
+ {
+ final SequenceGroup selectionGroup = this.ap.av.getSelectionGroup();
+ final AlignmentI alignment = this.ap.getAlignment();
+ AlignmentUtils.addReferenceAnnotations(candidates, alignment,
+ selectionGroup);
+ refresh();
+ }
+
+ /**
* add a show URL menu item to the given linkMenu
*
* @param linkMenu
@@ -591,7 +709,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
{
if (seq == null)
{
- seq = (Sequence) sg.getSequenceAt(0);
+ seq = sg.getSequenceAt(0);
}
EditNameDialog dialog = new EditNameDialog(seq.getSequenceAsString(
@@ -619,10 +737,9 @@ public class APopupMenu extends java.awt.PopupMenu implements
else if (source == toUpper || source == toLower || source == toggleCase)
{
SequenceGroup sg = ap.av.getSelectionGroup();
- Vector regions = new Vector();
if (sg != null)
{
- int[][] startEnd = ap.av.getVisibleRegionBoundaries(
+ List startEnd = ap.av.getVisibleRegionBoundaries(
sg.getStartRes(), sg.getEndRes() + 1);
String description;
@@ -708,15 +825,14 @@ public class APopupMenu extends java.awt.PopupMenu implements
Frame frame = new Frame();
frame.add(cap);
jalview.bin.JalviewLite.addFrame(frame, MessageManager.formatMessage(
- "label.selection_output_command", new String[]
+ "label.selection_output_command", new Object[]
{ e.getActionCommand() }), 600, 500);
// JBPNote: getSelectionAsNewSequence behaviour has changed - this method
// now returns a full copy of sequence data
// TODO consider using getSequenceSelection instead here
cap.setText(new jalview.io.AppletFormatAdapter().formatSequences(
- e.getActionCommand(),
- ap.av.showJVSuffix, ap.av, true));
+ e.getActionCommand(), ap.av.getShowJVSuffix(), ap.av, true));
}
@@ -740,7 +856,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
for (SequenceI seq : sequences)
{
contents.append(MessageManager.formatMessage(
- "label.annotation_for_displayid", new String[]
+ "label.annotation_for_displayid", new Object[]
{ seq.getDisplayId(true) }));
new SequenceAnnotationReport(null)
.createSequenceAnnotationReport(
@@ -759,7 +875,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
+ (sequences.length == 1 ? sequences[0].getDisplayId(true)
: "Selection"), 600, 500);
cap.setText(MessageManager.formatMessage("label.html_content",
- new String[]
+ new Object[]
{ contents.toString() }));
}
@@ -786,12 +902,12 @@ public class APopupMenu extends java.awt.PopupMenu implements
if (ap.av.applet.jmolAvailable)
{
- new jalview.appletgui.AppletJmol(entry, new Sequence[]
+ new jalview.appletgui.AppletJmol(entry, new SequenceI[]
{ seq }, null, ap, AppletFormatAdapter.URL);
}
else
{
- new MCview.AppletPDBViewer(entry, new Sequence[]
+ new MCview.AppletPDBViewer(entry, new SequenceI[]
{ seq }, null, ap, AppletFormatAdapter.URL);
}
@@ -804,7 +920,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
Frame frame = new Frame();
frame.add(cap);
jalview.bin.JalviewLite.addFrame(frame, MessageManager.formatMessage(
- "label.paste_pdb_file_for_sequence", new String[]
+ "label.paste_pdb_file_for_sequence", new Object[]
{ seq.getName() }), 400, 300);
}
}
@@ -848,7 +964,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
pdb.setLabel(MessageManager.getString("label.view_pdb_structure"));
hideSeqs.setLabel(MessageManager.getString("action.hide_sequences"));
repGroup.setLabel(MessageManager.formatMessage(
- "label.represent_group_with", new String[]
+ "label.represent_group_with", new Object[]
{ "" }));
revealAll.setLabel(MessageManager.getString("action.reveal_all"));
revealSeq.setLabel(MessageManager.getString("action.reveal_sequences"));
@@ -859,6 +975,9 @@ public class APopupMenu extends java.awt.PopupMenu implements
this.add(revealSeq);
this.add(revealAll);
// groupMenu.add(selSeqDetails);
+ groupMenu.add(groupShowAnnotationsMenu);
+ groupMenu.add(groupHideAnnotationsMenu);
+ groupMenu.add(groupAddReferenceAnnotations);
groupMenu.add(editMenu);
groupMenu.add(outputmenu);
groupMenu.add(sequenceFeature);
@@ -925,6 +1044,9 @@ public class APopupMenu extends java.awt.PopupMenu implements
editMenu.add(toLower);
toLower.addActionListener(this);
editMenu.add(toggleCase);
+ seqMenu.add(seqShowAnnotationsMenu);
+ seqMenu.add(seqHideAnnotationsMenu);
+ seqMenu.add(seqAddReferenceAnnotations);
seqMenu.add(sequenceName);
seqMenu.add(makeReferenceSeq);
// seqMenu.add(sequenceDetails);
@@ -1024,7 +1146,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
int threshold = SliderPanel.setPIDSliderSource(ap, sg.cs, getGroup()
.getName());
- sg.cs.setThreshold(threshold, ap.av.getIgnoreGapsConsensus());
+ sg.cs.setThreshold(threshold, ap.av.isIgnoreGapsConsensus());
SliderPanel.showPIDSlider();
@@ -1032,7 +1154,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
else
// remove PIDColouring
{
- sg.cs.setThreshold(0, ap.av.getIgnoreGapsConsensus());
+ sg.cs.setThreshold(0, ap.av.isIgnoreGapsConsensus());
}
refresh();
@@ -1205,4 +1327,109 @@ public class APopupMenu extends java.awt.PopupMenu implements
ap.av.sendSelection();
}
+ /**
+ * Add annotation types to 'Show annotations' and/or 'Hide annotations' menus.
+ * "All" is added first, followed by a separator. Then add any annotation
+ * types associated with the current selection. Separate menus are built for
+ * the selected sequence group (if any), and the selected sequence.
+ *
+ * Some annotation rows are always rendered together - these can be identified
+ * by a common graphGroup property > -1. Only one of each group will be marked
+ * as visible (to avoid duplication of the display). For such groups we add a
+ * composite type name, e.g.
+ *
+ * IUPredWS (Long), IUPredWS (Short)
+ *
+ * @param seq
+ */
+ protected void buildAnnotationTypesMenus(Menu showMenu, Menu hideMenu,
+ List forSequences)
+ {
+ showMenu.removeAll();
+ hideMenu.removeAll();
+
+ final List all = Arrays.asList(ALL_ANNOTATIONS);
+ addAnnotationTypeToShowHide(showMenu, forSequences, "", all, true, true);
+ addAnnotationTypeToShowHide(hideMenu, forSequences, "", all, true,
+ false);
+ showMenu.addSeparator();
+ hideMenu.addSeparator();
+
+ final AlignmentAnnotation[] annotations = ap.getAlignment()
+ .getAlignmentAnnotation();
+
+ /*
+ * Find shown/hidden annotations types, distinguished by source (calcId),
+ * and grouped by graphGroup. Using LinkedHashMap means we will retrieve in
+ * the insertion order, which is the order of the annotations on the
+ * alignment.
+ */
+ Map>> shownTypes = new LinkedHashMap>>();
+ Map>> hiddenTypes = new LinkedHashMap>>();
+ AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes,
+ hiddenTypes,
+ AlignmentAnnotationUtils.asList(annotations),
+ forSequences);
+
+ for (String calcId : hiddenTypes.keySet())
+ {
+ for (List type : hiddenTypes.get(calcId))
+ {
+ addAnnotationTypeToShowHide(showMenu, forSequences,
+ calcId, type, false, true);
+ }
+ }
+ // grey out 'show annotations' if none are hidden
+ showMenu.setEnabled(!hiddenTypes.isEmpty());
+
+ for (String calcId : shownTypes.keySet())
+ {
+ for (List type : shownTypes.get(calcId))
+ {
+ addAnnotationTypeToShowHide(hideMenu, forSequences,
+ calcId, type, false, false);
+ }
+ }
+ // grey out 'hide annotations' if none are shown
+ hideMenu.setEnabled(!shownTypes.isEmpty());
+ }
+
+ /**
+ * Add one annotation type to the 'Show Annotations' or 'Hide Annotations'
+ * menus.
+ *
+ * @param showOrHideMenu
+ * the menu to add to
+ * @param forSequences
+ * the sequences whose annotations may be shown or hidden
+ * @param calcId
+ * @param types
+ * the label to add
+ * @param allTypes
+ * if true this is a special label meaning 'All'
+ * @param actionIsShow
+ * if true, the select menu item action is to show the annotation
+ * type, else hide
+ */
+ protected void addAnnotationTypeToShowHide(Menu showOrHideMenu,
+ final List forSequences, String calcId,
+ final List types, final boolean allTypes,
+ final boolean actionIsShow)
+ {
+ String label = types.toString(); // [a, b, c]
+ label = label.substring(1, label.length() - 1);
+ final MenuItem item = new MenuItem(label);
+ item.addActionListener(new java.awt.event.ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ AlignmentUtils.showOrHideSequenceAnnotations(ap.getAlignment(), types,
+ forSequences, allTypes, actionIsShow);
+ refresh();
+ }
+ });
+ showOrHideMenu.add(item);
+ }
+
}
diff --git a/src/jalview/appletgui/AlignFrame.java b/src/jalview/appletgui/AlignFrame.java
index 623388b..3e919f6 100644
--- a/src/jalview/appletgui/AlignFrame.java
+++ b/src/jalview/appletgui/AlignFrame.java
@@ -20,9 +20,45 @@
*/
package jalview.appletgui;
+import java.awt.BorderLayout;
+import java.awt.Canvas;
+import java.awt.CheckboxMenuItem;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Label;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
import jalview.analysis.AlignmentSorter;
+import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
import jalview.api.AlignViewControllerGuiI;
import jalview.api.AlignViewControllerI;
+import jalview.api.AlignViewportI;
import jalview.api.FeatureRenderer;
import jalview.api.SequenceStructureBinding;
import jalview.bin.JalviewLite;
@@ -35,6 +71,7 @@ import jalview.commands.RemoveGapsCommand;
import jalview.commands.SlideSequencesCommand;
import jalview.commands.TrimRegionCommand;
import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentOrder;
import jalview.datamodel.ColumnSelection;
@@ -64,40 +101,9 @@ import jalview.schemes.TurnColourScheme;
import jalview.schemes.ZappoColourScheme;
import jalview.structure.StructureSelectionManager;
import jalview.structures.models.AAStructureBindingModel;
+import jalview.util.MappingUtils;
import jalview.util.MessageManager;
-import java.awt.BorderLayout;
-import java.awt.Canvas;
-import java.awt.CheckboxMenuItem;
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.Frame;
-import java.awt.Graphics;
-import java.awt.Label;
-import java.awt.Menu;
-import java.awt.MenuBar;
-import java.awt.MenuItem;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.awt.event.KeyEvent;
-import java.awt.event.KeyListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.io.IOException;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.util.Arrays;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
public class AlignFrame extends EmbmenuFrame implements ActionListener,
ItemListener, KeyListener, AlignViewControllerGuiI
{
@@ -113,9 +119,41 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
String jalviewServletURL;
- public AlignFrame(AlignmentI al, jalview.bin.JalviewLite applet,
+ /*
+ * Flag for showing autocalculated consensus above or below other consensus
+ * rows
+ */
+ private boolean showAutoCalculatedAbove;
+
+ private SequenceAnnotationOrder annotationSortOrder;
+
+ /**
+ * Constructor that creates the frame and adds it to the display.
+ *
+ * @param al
+ * @param applet
+ * @param title
+ * @param embedded
+ */
+ public AlignFrame(AlignmentI al, JalviewLite applet,
String title, boolean embedded)
{
+ this(al, applet, title, embedded, true);
+ }
+
+ /**
+ * Constructor that optionally allows the frame to be displayed or only
+ * created.
+ *
+ * @param al
+ * @param applet
+ * @param title
+ * @param embedded
+ * @param addToDisplay
+ */
+ public AlignFrame(AlignmentI al, JalviewLite applet,
+ String title, boolean embedded, boolean addToDisplay)
+ {
if (applet != null)
{
jalviewServletURL = applet.getParameter("APPLICATION_URL");
@@ -157,7 +195,6 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
viewport.updateConservation(alignPanel);
viewport.updateConsensus(alignPanel);
- annotationPanelMenuItem.setState(viewport.showAnnotation);
displayNonconservedMenuItem.setState(viewport.getShowUnconserved());
followMouseOverFlag.setState(viewport.getFollowHighlight());
showGroupConsensus.setState(viewport.isShowGroupConsensus());
@@ -166,8 +203,10 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
showSequenceLogo.setState(viewport.isShowSequenceLogo());
normSequenceLogo.setState(viewport.isNormaliseSequenceLogo());
applyToAllGroups.setState(viewport.getColourAppliesToAllGroups());
+ showAlignmentAnnotations.setState(viewport.isShowAnnotation());
+ showSequenceAnnotations.setState(viewport.isShowAnnotation());
- seqLimits.setState(viewport.showJVSuffix);
+ seqLimits.setState(viewport.getShowJVSuffix());
if (applet != null)
{
@@ -233,8 +272,19 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
alignPanel.annotationPanelHolder.addKeyListener(this);
alignPanel.annotationSpaceFillerHolder.addKeyListener(this);
alignPanel.alabels.addKeyListener(this);
- createAlignFrameWindow(embedded, title);
+ if (addToDisplay)
+ {
+ addToDisplay(embedded);
+ }
+ }
+
+ /**
+ * @param embedded
+ */
+ public void addToDisplay(boolean embedded)
+ {
+ createAlignFrameWindow(embedded);
validate();
alignPanel.adjustAnnotationHeight();
alignPanel.paintAlignment(true);
@@ -498,7 +548,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
}
case KeyEvent.VK_PAGE_UP:
- if (viewport.wrapAlignment)
+ if (viewport.getWrapAlignment())
{
alignPanel.scrollUp(true);
}
@@ -510,7 +560,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
break;
case KeyEvent.VK_PAGE_DOWN:
- if (viewport.wrapAlignment)
+ if (viewport.getWrapAlignment())
{
alignPanel.scrollUp(false);
}
@@ -690,111 +740,188 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
@Override
public void itemStateChanged(ItemEvent evt)
{
- if (evt.getSource() == displayNonconservedMenuItem)
+ final Object source = evt.getSource();
+ if (source == displayNonconservedMenuItem)
{
displayNonconservedMenuItem_actionPerformed();
}
- else if (evt.getSource() == colourTextMenuItem)
+ else if (source == colourTextMenuItem)
{
colourTextMenuItem_actionPerformed();
}
- else if (evt.getSource() == wrapMenuItem)
+ else if (source == wrapMenuItem)
{
wrapMenuItem_actionPerformed();
}
- else if (evt.getSource() == scaleAbove)
+ else if (source == scaleAbove)
{
viewport.setScaleAboveWrapped(scaleAbove.getState());
}
- else if (evt.getSource() == scaleLeft)
+ else if (source == scaleLeft)
{
viewport.setScaleLeftWrapped(scaleLeft.getState());
}
- else if (evt.getSource() == scaleRight)
+ else if (source == scaleRight)
{
viewport.setScaleRightWrapped(scaleRight.getState());
}
- else if (evt.getSource() == seqLimits)
+ else if (source == seqLimits)
{
seqLimits_itemStateChanged();
}
- else if (evt.getSource() == viewBoxesMenuItem)
+ else if (source == viewBoxesMenuItem)
{
viewport.setShowBoxes(viewBoxesMenuItem.getState());
}
- else if (evt.getSource() == viewTextMenuItem)
+ else if (source == viewTextMenuItem)
{
viewport.setShowText(viewTextMenuItem.getState());
}
- else if (evt.getSource() == renderGapsMenuItem)
+ else if (source == renderGapsMenuItem)
{
viewport.setRenderGaps(renderGapsMenuItem.getState());
}
- else if (evt.getSource() == annotationPanelMenuItem)
+ else if (source == annotationPanelMenuItem)
{
viewport.setShowAnnotation(annotationPanelMenuItem.getState());
alignPanel.setAnnotationVisible(annotationPanelMenuItem.getState());
}
- else if (evt.getSource() == sequenceFeatures)
+ else if (source == sequenceFeatures)
{
viewport.setShowSequenceFeatures(sequenceFeatures.getState());
alignPanel.seqPanel.seqCanvas.repaint();
}
- else if (evt.getSource() == conservationMenuItem)
+ else if (source == showAlignmentAnnotations)
+ {
+ setAnnotationsVisibility();
+ }
+ else if (source == showSequenceAnnotations)
+ {
+ setAnnotationsVisibility();
+ }
+ else if (source == sortAnnBySequence)
+ {
+ boolean newState = sortAnnBySequence.getState();
+ sortAnnByLabel.setState(false);
+ setAnnotationSortOrder(newState ? SequenceAnnotationOrder.SEQUENCE_AND_LABEL
+ : SequenceAnnotationOrder.NONE);
+ setViewportAnnotationOrder();
+ }
+ else if (source == sortAnnByLabel)
+ {
+ boolean newState = sortAnnByLabel.getState();
+ sortAnnBySequence.setState(false);
+ setAnnotationSortOrder(newState ? SequenceAnnotationOrder.LABEL_AND_SEQUENCE
+ : SequenceAnnotationOrder.NONE);
+ setViewportAnnotationOrder();
+ }
+ else if (source == showAutoFirst)
+ {
+ showAutoLast.setState(!showAutoFirst.getState());
+ setShowAutoCalculatedAbove(showAutoFirst.getState());
+ setViewportAnnotationOrder();
+ }
+ else if (source == showAutoLast)
+ {
+ showAutoFirst.setState(!showAutoLast.getState());
+ setShowAutoCalculatedAbove(showAutoFirst.getState());
+ setViewportAnnotationOrder();
+ }
+ else if (source == conservationMenuItem)
{
conservationMenuItem_actionPerformed();
}
- else if (evt.getSource() == abovePIDThreshold)
+ else if (source == abovePIDThreshold)
{
abovePIDThreshold_actionPerformed();
}
- else if (evt.getSource() == applyToAllGroups)
+ else if (source == applyToAllGroups)
{
viewport.setColourAppliesToAllGroups(applyToAllGroups.getState());
}
- else if (evt.getSource() == autoCalculate)
+ else if (source == autoCalculate)
{
viewport.autoCalculateConsensus = autoCalculate.getState();
}
- else if (evt.getSource() == sortByTree)
+ else if (source == sortByTree)
{
viewport.sortByTree = sortByTree.getState();
}
- else if (evt.getSource() == this.centreColumnLabelFlag)
+ else if (source == this.centreColumnLabelFlag)
{
centreColumnLabelFlag_stateChanged();
}
- else if (evt.getSource() == this.followMouseOverFlag)
+ else if (source == this.followMouseOverFlag)
{
mouseOverFlag_stateChanged();
}
- else if (evt.getSource() == showGroupConsensus)
+ else if (source == showGroupConsensus)
{
showGroupConsensus_actionPerformed();
}
- else if (evt.getSource() == showGroupConservation)
+ else if (source == showGroupConservation)
{
showGroupConservation_actionPerformed();
}
- else if (evt.getSource() == showSequenceLogo)
+ else if (source == showSequenceLogo)
{
showSequenceLogo_actionPerformed();
}
- else if (evt.getSource() == normSequenceLogo)
+ else if (source == normSequenceLogo)
{
normSequenceLogo_actionPerformed();
}
- else if (evt.getSource() == showConsensusHistogram)
+ else if (source == showConsensusHistogram)
{
showConsensusHistogram_actionPerformed();
}
- else if (evt.getSource() == applyAutoAnnotationSettings)
+ else if (source == applyAutoAnnotationSettings)
{
applyAutoAnnotationSettings_actionPerformed();
}
alignPanel.paintAlignment(true);
}
+ /**
+ * Set the visibility state of sequence-related and/or alignment-related
+ * annotations depending on checkbox selections. Repaint after calling.
+ *
+ * @param visible
+ */
+ private void setAnnotationsVisibility()
+ {
+ boolean showForAlignment = showAlignmentAnnotations.getState();
+ boolean showForSequences = showSequenceAnnotations.getState();
+ for (AlignmentAnnotation aa : alignPanel.getAlignment()
+ .getAlignmentAnnotation())
+ {
+ boolean visible = (aa.sequenceRef == null ? showForAlignment
+ : showForSequences);
+ aa.visible = visible;
+ }
+ alignPanel.validateAnnotationDimensions(false);
+ }
+
+ private void setAnnotationSortOrder(SequenceAnnotationOrder order)
+ {
+ this.annotationSortOrder = order;
+ }
+
+ /**
+ * Set flags on the viewport that control annotation ordering
+ */
+ private void setViewportAnnotationOrder()
+ {
+ this.alignPanel.av.setSortAnnotationsBy(this.annotationSortOrder);
+ this.alignPanel.av
+ .setShowAutocalculatedAbove(this.showAutoCalculatedAbove);
+ }
+
+ private void setShowAutoCalculatedAbove(boolean showAbove)
+ {
+ this.showAutoCalculatedAbove = showAbove;
+ }
+
private void mouseOverFlag_stateChanged()
{
viewport.followHighlight = followMouseOverFlag.getState();
@@ -1181,11 +1308,11 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
Frame frame = new Frame();
frame.add(cap);
jalview.bin.JalviewLite.addFrame(frame, MessageManager.formatMessage(
- "label.alignment_output_command", new String[]
+ "label.alignment_output_command", new Object[]
{ e.getActionCommand() }), 600, 500);
cap.setText(new AppletFormatAdapter().formatSequences(
e.getActionCommand(), viewport.getAlignment(),
- viewport.showJVSuffix));
+ viewport.getShowJVSuffix()));
}
public void loadAnnotations()
@@ -1403,12 +1530,12 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
void updateEditMenuBar()
{
- if (viewport.historyList.size() > 0)
+ if (viewport.getHistoryList().size() > 0)
{
undoMenuItem.setEnabled(true);
- CommandI command = (CommandI) viewport.historyList.peek();
+ CommandI command = viewport.getHistoryList().peek();
undoMenuItem.setLabel(MessageManager.formatMessage(
- "label.undo_command", new String[]
+ "label.undo_command", new Object[]
{ command.getDescription() }));
}
else
@@ -1417,13 +1544,13 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
undoMenuItem.setLabel(MessageManager.getString("action.undo"));
}
- if (viewport.redoList.size() > 0)
+ if (viewport.getRedoList().size() > 0)
{
redoMenuItem.setEnabled(true);
- CommandI command = (CommandI) viewport.redoList.peek();
+ CommandI command = viewport.getRedoList().peek();
redoMenuItem.setLabel(MessageManager.formatMessage(
- "label.redo_command", new String[]
+ "label.redo_command", new Object[]
{ command.getDescription() }));
}
else
@@ -1441,8 +1568,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
{
if (command.getSize() > 0)
{
- viewport.historyList.push(command);
- viewport.redoList.removeAllElements();
+ viewport.addToHistoryList(command);
+ viewport.clearRedoList();
updateEditMenuBar();
viewport.updateHiddenColumns();
}
@@ -1456,13 +1583,13 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
*/
protected void undoMenuItem_actionPerformed()
{
- if (viewport.historyList.size() < 1)
+ if (viewport.getHistoryList().isEmpty())
{
return;
}
- CommandI command = (CommandI) viewport.historyList.pop();
- viewport.redoList.push(command);
+ CommandI command = viewport.getHistoryList().pop();
+ viewport.addToRedoList(command);
command.undoCommand(null);
AlignViewport originalSource = getOriginatingSource(command);
@@ -1488,13 +1615,13 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
*/
protected void redoMenuItem_actionPerformed()
{
- if (viewport.redoList.size() < 1)
+ if (viewport.getRedoList().isEmpty())
{
return;
}
- CommandI command = (CommandI) viewport.redoList.pop();
- viewport.historyList.push(command);
+ CommandI command = viewport.getRedoList().pop();
+ viewport.addToHistoryList(command);
command.doCommand(null);
AlignViewport originalSource = getOriginatingSource(command);
@@ -1554,6 +1681,12 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
return originalSource;
}
+ /**
+ * Move the currently selected sequences up or down one position in the
+ * alignment
+ *
+ * @param up
+ */
public void moveSelectedSequences(boolean up)
{
SequenceGroup sg = viewport.getSelectionGroup();
@@ -1564,6 +1697,21 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
viewport.getAlignment().moveSelectedSequencesByOne(sg,
up ? null : viewport.getHiddenRepSequences(), up);
alignPanel.paintAlignment(true);
+
+ /*
+ * Also move cDNA/protein complement sequences
+ */
+ AlignViewportI complement = viewport.getCodingComplement();
+ if (complement != null)
+ {
+ SequenceGroup mappedSelection = MappingUtils.mapSequenceGroup(sg,
+ viewport, complement);
+ complement.getAlignment().moveSelectedSequencesByOne(mappedSelection,
+ up ? null : complement.getHiddenRepSequences(), up);
+ // TODO need to trigger a repaint of the complementary panel - how?
+ // would prefer to handle in SplitFrame but it is not overriding key
+ // listener chiz
+ }
}
synchronized void slideSequences(boolean right, int size)
@@ -1651,11 +1799,12 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
}
boolean appendHistoryItem = false;
- if (viewport.historyList != null && viewport.historyList.size() > 0
- && viewport.historyList.peek() instanceof SlideSequencesCommand)
+ Deque historyList = viewport.getHistoryList();
+ if (historyList != null && historyList.size() > 0
+ && historyList.peek() instanceof SlideSequencesCommand)
{
appendHistoryItem = ssc
- .appendSlideCommand((SlideSequencesCommand) viewport.historyList
+ .appendSlideCommand((SlideSequencesCommand) historyList
.peek());
}
@@ -1680,12 +1829,12 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
SequenceGroup sg = viewport.getSelectionGroup();
copiedSequences = new StringBuffer();
- Hashtable orderedSeqs = new Hashtable();
+ Map orderedSeqs = new HashMap();
for (int i = 0; i < sg.getSize(); i++)
{
SequenceI seq = sg.getSequenceAt(i);
int index = viewport.getAlignment().findIndex(seq);
- orderedSeqs.put(index + "", seq);
+ orderedSeqs.put(index, seq);
}
int index = 0, startRes, endRes;
@@ -1697,7 +1846,6 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
int hiddenOffset = viewport.getSelectionGroup().getStartRes();
for (int[] region : viewport.getColumnSelection().getHiddenColumns())
{
-
copiedHiddenColumns.addElement(new int[]
{ region[0] - hiddenOffset, region[1] - hiddenOffset });
}
@@ -1713,11 +1861,10 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
while (seq == null)
{
- if (orderedSeqs.containsKey(index + ""))
+ if (orderedSeqs.containsKey(index))
{
- seq = (SequenceI) orderedSeqs.get(index + "");
+ seq = orderedSeqs.get(index);
index++;
-
break;
}
else
@@ -2261,8 +2408,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
newaf.setTitle(title.toString());
- newaf.viewport.historyList = viewport.historyList;
- newaf.viewport.redoList = viewport.redoList;
+ newaf.viewport.setHistoryList(viewport.getHistoryList());
+ newaf.viewport.setRedoList(viewport.getRedoList());
return newaf;
}
@@ -2276,13 +2423,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
if (alignPanel != null
&& (fr = alignPanel.getFeatureRenderer()) != null)
{
- List gps = fr.getFeatureGroups();
- int p=0;
- String[] _gps = new String[gps.size()];
- for (Object gp:gps)
- {
- _gps[p++] = gp.toString();
- }
+ List gps = fr.getFeatureGroups();
+ String[] _gps = gps.toArray(new String[gps.size()]);
return _gps;
}
return null;
@@ -2301,13 +2443,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
if (alignPanel != null
&& (fr = alignPanel.getFeatureRenderer()) != null)
{
- List gps = fr.getGroups(visible);
- int p=0;
- String[] _gps = new String[gps.size()];
- for (Object gp:gps)
- {
- _gps[p++] = gp.toString();
- }
+ List gps = fr.getGroups(visible);
+ String[] _gps = gps.toArray(new String[gps.size()]);
return _gps;
}
return null;
@@ -2354,7 +2491,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
protected void displayNonconservedMenuItem_actionPerformed()
{
- viewport.setShowunconserved(displayNonconservedMenuItem.getState());
+ viewport.setShowUnconserved(displayNonconservedMenuItem.getState());
alignPanel.paintAlignment(true);
}
@@ -2839,15 +2976,6 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
MenuItem closeMenuItem = new MenuItem(
MessageManager.getString("action.close"));
- Menu editMenu = new Menu(MessageManager.getString("action.edit"));
-
- Menu viewMenu = new Menu(MessageManager.getString("action.view"));
-
- Menu colourMenu = new Menu(MessageManager.getString("action.colour"));
-
- Menu calculateMenu = new Menu(
- MessageManager.getString("action.calculate"));
-
MenuItem selectAllSequenceMenuItem = new MenuItem(
MessageManager.getString("action.select_all"));
@@ -2891,8 +3019,6 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
public Label statusBar = new Label();
- Menu outputTextboxMenu = new Menu();
-
MenuItem clustalColour = new MenuItem();
MenuItem zappoColour = new MenuItem();
@@ -2990,22 +3116,15 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
MenuItem modifyConservation = new MenuItem();
- CheckboxMenuItem autoCalculate = new CheckboxMenuItem(
- "Autocalculate Consensus", true);
+ CheckboxMenuItem autoCalculate = null;
CheckboxMenuItem sortByTree = new CheckboxMenuItem(
"Sort Alignment With New Tree", true);
Menu sortByTreeMenu = new Menu();
- Menu sort = new Menu();
-
- Menu calculate = new Menu();
-
MenuItem inputText = new MenuItem();
- Menu helpMenu = new Menu();
-
MenuItem documentation = new MenuItem();
MenuItem about = new MenuItem();
@@ -3016,8 +3135,6 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
CheckboxMenuItem followMouseOverFlag = new CheckboxMenuItem();
- Menu autoAnnMenu = new Menu();
-
CheckboxMenuItem showSequenceLogo = new CheckboxMenuItem();
CheckboxMenuItem applyAutoAnnotationSettings = new CheckboxMenuItem();
@@ -3030,18 +3147,27 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
CheckboxMenuItem normSequenceLogo = new CheckboxMenuItem();
+ /**
+ * Initialise menus and other items
+ *
+ * @throws Exception
+ */
private void jbInit() throws Exception
{
-
setMenuBar(alignFrameMenuBar);
- MenuItem item;
-
- // dynamically fill save as menu with available formats
+ /*
+ * Configure File menu items and actions
+ */
+ inputText
+ .setLabel(MessageManager.getString("label.input_from_textbox"));
+ inputText.addActionListener(this);
+ Menu outputTextboxMenu = new Menu(
+ MessageManager.getString("label.out_to_textbox"));
for (int i = 0; i < jalview.io.AppletFormatAdapter.WRITEABLE_FORMATS.length; i++)
{
- item = new MenuItem(
+ MenuItem item = new MenuItem(
jalview.io.AppletFormatAdapter.WRITEABLE_FORMATS[i]);
item.addActionListener(new java.awt.event.ActionListener()
@@ -3057,14 +3183,31 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
}
closeMenuItem.addActionListener(this);
loadApplication.addActionListener(this);
-
loadTree.addActionListener(this);
loadAnnotations.addActionListener(this);
outputFeatures.addActionListener(this);
outputAnnotations.addActionListener(this);
- selectAllSequenceMenuItem.addActionListener(this);
- deselectAllSequenceMenuItem.addActionListener(this);
- invertSequenceMenuItem.addActionListener(this);
+
+ /*
+ * Configure Edit menu items and actions
+ */
+ undoMenuItem.setEnabled(false);
+ undoMenuItem.setLabel(MessageManager.getString("action.undo"));
+ undoMenuItem.addActionListener(this);
+ redoMenuItem.setEnabled(false);
+ redoMenuItem.setLabel(MessageManager.getString("action.redo"));
+ redoMenuItem.addActionListener(this);
+ copy.setLabel(MessageManager.getString("action.copy"));
+ copy.addActionListener(this);
+ cut.setLabel(MessageManager.getString("action.cut"));
+ cut.addActionListener(this);
+ delete.setLabel(MessageManager.getString("action.delete"));
+ delete.addActionListener(this);
+ pasteMenu.setLabel(MessageManager.getString("action.paste"));
+ pasteNew.setLabel(MessageManager.getString("label.to_new_alignment"));
+ pasteNew.addActionListener(this);
+ pasteThis.setLabel(MessageManager.getString("label.to_this_alignment"));
+ pasteThis.addActionListener(this);
remove2LeftMenuItem.setLabel(MessageManager
.getString("action.remove_left"));
remove2LeftMenuItem.addActionListener(this);
@@ -3077,128 +3220,23 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
removeAllGapsMenuItem.setLabel(MessageManager
.getString("action.remove_all_gaps"));
removeAllGapsMenuItem.addActionListener(this);
- viewBoxesMenuItem.setLabel(MessageManager.getString("action.boxes"));
- viewBoxesMenuItem.setState(true);
- viewBoxesMenuItem.addItemListener(this);
- viewTextMenuItem.setLabel(MessageManager.getString("action.text"));
- viewTextMenuItem.setState(true);
- viewTextMenuItem.addItemListener(this);
- sortPairwiseMenuItem.setLabel(MessageManager
- .getString("action.by_pairwise_id"));
- sortPairwiseMenuItem.addActionListener(this);
- sortIDMenuItem.setLabel(MessageManager.getString("action.by_id"));
- sortIDMenuItem.addActionListener(this);
- sortLengthMenuItem.setLabel(MessageManager
- .getString("action.by_length"));
- sortLengthMenuItem.addActionListener(this);
- sortGroupMenuItem.setLabel(MessageManager.getString("action.by_group"));
- sortGroupMenuItem.addActionListener(this);
- removeRedundancyMenuItem.setLabel(MessageManager
- .getString("action.remove_redundancy").concat("..."));
+ removeRedundancyMenuItem.setLabel(MessageManager.getString(
+ "action.remove_redundancy").concat("..."));
removeRedundancyMenuItem.addActionListener(this);
- pairwiseAlignmentMenuItem.setLabel(MessageManager
- .getString("action.pairwise_alignment"));
- pairwiseAlignmentMenuItem.addActionListener(this);
- PCAMenuItem.setLabel(MessageManager
- .getString("label.principal_component_analysis"));
- PCAMenuItem.addActionListener(this);
- averageDistanceTreeMenuItem.setLabel(MessageManager
- .getString("label.average_distance_identity"));
- averageDistanceTreeMenuItem.addActionListener(this);
- neighbourTreeMenuItem.setLabel(MessageManager
- .getString("label.neighbour_joining_identity"));
- neighbourTreeMenuItem.addActionListener(this);
- statusBar.setBackground(Color.white);
- statusBar.setFont(new java.awt.Font("Verdana", 0, 11));
- statusBar.setText(MessageManager.getString("label.status_bar"));
- outputTextboxMenu.setLabel(MessageManager
- .getString("label.out_to_textbox"));
- clustalColour.setLabel(MessageManager.getString("label.clustalx"));
- clustalColour.addActionListener(this);
- zappoColour.setLabel(MessageManager.getString("label.zappo"));
- zappoColour.addActionListener(this);
- taylorColour.setLabel(MessageManager.getString("label.taylor"));
- taylorColour.addActionListener(this);
- hydrophobicityColour.setLabel(MessageManager
- .getString("label.hydrophobicity"));
- hydrophobicityColour.addActionListener(this);
- helixColour
- .setLabel(MessageManager.getString("label.helix_propensity"));
- helixColour.addActionListener(this);
- strandColour.setLabel(MessageManager
- .getString("label.strand_propensity"));
- strandColour.addActionListener(this);
- turnColour.setLabel(MessageManager.getString("label.turn_propensity"));
- turnColour.addActionListener(this);
- buriedColour.setLabel(MessageManager.getString("label.buried_index"));
- buriedColour.addActionListener(this);
- purinePyrimidineColour.setLabel(MessageManager
- .getString("label.purine_pyrimidine"));
- purinePyrimidineColour.addActionListener(this);
- RNAInteractionColour.setLabel(MessageManager
- .getString("label.rna_interaction"));
- RNAInteractionColour.addActionListener(this);
- RNAHelixColour.setLabel(MessageManager
- .getString("action.by_rna_helixes"));
- RNAHelixColour.addActionListener(this);
- userDefinedColour.setLabel(MessageManager
- .getString("action.user_defined"));
- userDefinedColour.addActionListener(this);
- PIDColour.setLabel(MessageManager
- .getString("label.percentage_identity"));
- PIDColour.addActionListener(this);
- BLOSUM62Colour.setLabel(MessageManager
- .getString("label.blosum62_score"));
- BLOSUM62Colour.addActionListener(this);
- tcoffeeColour
- .setLabel(MessageManager.getString("label.tcoffee_scores"));
- tcoffeeColour.setEnabled(false); // it will enabled only if a score file is
- // provided
- tcoffeeColour.addActionListener(this);
- avDistanceTreeBlosumMenuItem.setLabel(MessageManager
- .getString("label.average_distance_bloslum62"));
- avDistanceTreeBlosumMenuItem.addActionListener(this);
- njTreeBlosumMenuItem.setLabel(MessageManager
- .getString("label.neighbour_blosum62"));
- njTreeBlosumMenuItem.addActionListener(this);
- annotationPanelMenuItem.setLabel(MessageManager
- .getString("label.show_annotations"));
- annotationPanelMenuItem.addItemListener(this);
- colourTextMenuItem.setLabel(MessageManager
- .getString("label.colour_text"));
- colourTextMenuItem.addItemListener(this);
- displayNonconservedMenuItem.setLabel(MessageManager
- .getString("label.show_non_conversed"));
- displayNonconservedMenuItem.addItemListener(this);
- alProperties.addActionListener(this);
- overviewMenuItem.setLabel(MessageManager
- .getString("label.overview_window"));
- overviewMenuItem.addActionListener(this);
- undoMenuItem.setEnabled(false);
- undoMenuItem.setLabel(MessageManager.getString("action.undo"));
- undoMenuItem.addActionListener(this);
- redoMenuItem.setEnabled(false);
- redoMenuItem.setLabel(MessageManager.getString("action.redo"));
- redoMenuItem.addActionListener(this);
- conservationMenuItem.setLabel(MessageManager
- .getString("action.by_conservation"));
- conservationMenuItem.addItemListener(this);
- noColourmenuItem.setLabel(MessageManager.getString("label.none"));
- noColourmenuItem.addActionListener(this);
- wrapMenuItem.setLabel(MessageManager.getString("action.wrap"));
- wrapMenuItem.addItemListener(this);
- renderGapsMenuItem.setLabel(MessageManager
- .getString("action.show_gaps"));
- renderGapsMenuItem.setState(true);
- renderGapsMenuItem.addItemListener(this);
+ /*
+ * Configure Select menu items and actions
+ */
findMenuItem.setLabel(MessageManager.getString("action.find"));
findMenuItem.addActionListener(this);
- abovePIDThreshold.setLabel(MessageManager
- .getString("label.above_identity_threshold"));
- abovePIDThreshold.addItemListener(this);
- nucleotideColour.setLabel(MessageManager.getString("label.nucleotide"));
- nucleotideColour.addActionListener(this);
+ selectAllSequenceMenuItem.addActionListener(this);
+ deselectAllSequenceMenuItem.addActionListener(this);
+ invertSequenceMenuItem.setLabel(MessageManager
+ .getString("action.invert_sequence_selection"));
+ invertSequenceMenuItem.addActionListener(this);
+ invertColSel.setLabel(MessageManager
+ .getString("action.invert_column_selection"));
+ invertColSel.addActionListener(this);
deleteGroups.setLabel(MessageManager
.getString("action.undefine_groups"));
deleteGroups.addActionListener(this);
@@ -3207,88 +3245,18 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
grpsFromSelection.addActionListener(this);
createGroup.setLabel(MessageManager.getString("action.create_group"));
unGroup.setLabel(MessageManager.getString("action.remove_group"));
- copy.setLabel(MessageManager.getString("action.copy"));
- copy.addActionListener(this);
- cut.setLabel(MessageManager.getString("action.cut"));
- cut.addActionListener(this);
- delete.setLabel(MessageManager.getString("action.delete"));
- delete.addActionListener(this);
- pasteMenu.setLabel(MessageManager.getString("action.paste"));
- pasteNew.setLabel(MessageManager.getString("label.to_new_alignment"));
- pasteNew.addActionListener(this);
- pasteThis.setLabel(MessageManager.getString("label.to_this_alignment"));
- pasteThis.addActionListener(this);
- applyToAllGroups.setLabel(MessageManager
- .getString("label.apply_colour_to_all_groups"));
- applyToAllGroups.setState(true);
- applyToAllGroups.addItemListener(this);
- font.setLabel(MessageManager.getString("action.font"));
- font.addActionListener(this);
- scaleAbove.setLabel(MessageManager.getString("action.scale_above"));
- scaleAbove.setState(true);
- scaleAbove.setEnabled(false);
- scaleAbove.addItemListener(this);
- scaleLeft.setEnabled(false);
- scaleLeft.setState(true);
- scaleLeft.setLabel(MessageManager.getString("action.scale_left"));
- scaleLeft.addItemListener(this);
- scaleRight.setEnabled(false);
- scaleRight.setState(true);
- scaleRight.setLabel(MessageManager.getString("action.scale_right"));
- scaleRight.addItemListener(this);
- modifyPID.setLabel(MessageManager
- .getString("label.modify_identity_thereshold"));
- modifyPID.addActionListener(this);
- modifyConservation.setLabel(MessageManager
- .getString("label.modify_conservation_thereshold"));
- modifyConservation.addActionListener(this);
- sortByTreeMenu.setLabel(MessageManager
- .getString("action.by_tree_order"));
- sort.setLabel(MessageManager.getString("action.sort"));
- calculate.setLabel(MessageManager.getString("action.calculate_tree"));
- autoCalculate.addItemListener(this);
- sortByTree.addItemListener(this);
- inputText
- .setLabel(MessageManager.getString("label.input_from_textbox"));
- inputText.addActionListener(this);
- centreColumnLabelFlag.setLabel(MessageManager
- .getString("label.centre_column_labels"));
- centreColumnLabelFlag.addItemListener(this);
- followMouseOverFlag.setLabel(MessageManager
- .getString("label.automatic_scrolling"));
- followMouseOverFlag.addItemListener(this);
- helpMenu.setLabel(MessageManager.getString("action.help"));
- documentation.setLabel(MessageManager.getString("label.documentation"));
- documentation.addActionListener(this);
-
- about.setLabel(MessageManager.getString("label.about"));
- about.addActionListener(this);
- seqLimits.setState(true);
- seqLimits.setLabel(MessageManager
- .getString("label.show_sequence_limits"));
- seqLimits.addItemListener(this);
- featureSettings.setLabel(MessageManager
- .getString("label.feature_settings"));
- featureSettings.addActionListener(this);
- sequenceFeatures.setLabel(MessageManager
- .getString("label.sequence_features"));
- sequenceFeatures.addItemListener(this);
- sequenceFeatures.setState(false);
- annotationColour.setLabel(MessageManager
- .getString("action.by_annotation"));
- annotationColour.addActionListener(this);
-
annotationColumnSelection.setLabel("Select by Annotation");
annotationColumnSelection.addActionListener(this);
- invertSequenceMenuItem.setLabel(MessageManager
- .getString("action.invert_sequence_selection"));
- invertColSel.setLabel(MessageManager
- .getString("action.invert_column_selection"));
- menu1.setLabel(MessageManager.getString("action.show"));
+ /*
+ * Configure View menu items and actions
+ */
+ newView.setLabel(MessageManager.getString("action.new_view"));
+ newView.addActionListener(this);
+ Menu showMenu = new Menu(MessageManager.getString("action.show"));
showColumns.setLabel(MessageManager.getString("label.all_columns"));
showSeqs.setLabel(MessageManager.getString("label.all_sequences"));
- menu2.setLabel(MessageManager.getString("action.hide"));
+ Menu hideMenu = new Menu(MessageManager.getString("action.hide"));
hideColumns
.setLabel(MessageManager.getString("label.selected_columns"));
hideSequences.setLabel(MessageManager
@@ -3299,6 +3267,34 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
.getString("label.selected_region"));
showAllHidden.setLabel(MessageManager
.getString("label.all_sequences_columns"));
+ showColumns.addActionListener(this);
+ showSeqs.addActionListener(this);
+ hideColumns.addActionListener(this);
+ hideSequences.addActionListener(this);
+ hideAllButSelection.addActionListener(this);
+ hideAllSelection.addActionListener(this);
+ showAllHidden.addActionListener(this);
+ featureSettings.setLabel(MessageManager
+ .getString("label.feature_settings"));
+ featureSettings.addActionListener(this);
+ sequenceFeatures.setLabel(MessageManager
+ .getString("label.show_sequence_features"));
+ sequenceFeatures.addItemListener(this);
+ sequenceFeatures.setState(false);
+ followMouseOverFlag.setLabel(MessageManager
+ .getString("label.automatic_scrolling"));
+ followMouseOverFlag.addItemListener(this);
+ alProperties.addActionListener(this);
+ overviewMenuItem.setLabel(MessageManager
+ .getString("label.overview_window"));
+ overviewMenuItem.addActionListener(this);
+
+ /*
+ * Configure Annotations menu items and actions
+ */
+ annotationPanelMenuItem.setLabel(MessageManager
+ .getString("label.show_annotations"));
+ annotationPanelMenuItem.addItemListener(this);
showGroupConsensus.setLabel(MessageManager
.getString("label.group_consensus"));
showGroupConservation.setLabel(MessageManager
@@ -3312,58 +3308,243 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
applyAutoAnnotationSettings.setLabel(MessageManager
.getString("label.apply_all_groups"));
applyAutoAnnotationSettings.setState(true);
- autoAnnMenu.setLabel(MessageManager
- .getString("label.autocalculated_annotation"));
-
- invertColSel.addActionListener(this);
- showColumns.addActionListener(this);
- showSeqs.addActionListener(this);
- hideColumns.addActionListener(this);
- hideSequences.addActionListener(this);
- hideAllButSelection.addActionListener(this);
- hideAllSelection.addActionListener(this);
- showAllHidden.addActionListener(this);
+ Menu autoAnnMenu = new Menu(
+ MessageManager.getString("label.autocalculated_annotation"));
showGroupConsensus.addItemListener(this);
showGroupConservation.addItemListener(this);
showConsensusHistogram.addItemListener(this);
showSequenceLogo.addItemListener(this);
normSequenceLogo.addItemListener(this);
-
applyAutoAnnotationSettings.addItemListener(this);
- formatMenu.setLabel(MessageManager.getString("action.format"));
- selectMenu.setLabel(MessageManager.getString("action.select"));
- newView.setLabel(MessageManager.getString("action.new_view"));
- newView.addActionListener(this);
+ showAlignmentAnnotations = new CheckboxMenuItem(
+ MessageManager.getString("label.show_all_al_annotations"));
+ showSequenceAnnotations = new CheckboxMenuItem(
+ MessageManager.getString("label.show_all_seq_annotations"));
+ sortAnnBySequence = new CheckboxMenuItem(
+ MessageManager.getString("label.sort_annotations_by_sequence"));
+ sortAnnByLabel = new CheckboxMenuItem(
+ MessageManager.getString("label.sort_annotations_by_label"));
+ showAutoFirst = new CheckboxMenuItem(
+ MessageManager.getString("label.show_first"));
+ showAutoLast = new CheckboxMenuItem(
+ MessageManager.getString("label.show_last"));
+ showAlignmentAnnotations.addItemListener(this);
+ showSequenceAnnotations.addItemListener(this);
+ sortAnnBySequence.addItemListener(this);
+ sortAnnByLabel.addItemListener(this);
+ showAutoFirst.addItemListener(this);
+ showAutoLast.addItemListener(this);
+
+ /*
+ * Configure Format menu items and actions
+ */
+ font.setLabel(MessageManager.getString("action.font"));
+ font.addActionListener(this);
+ scaleAbove.setLabel(MessageManager.getString("action.scale_above"));
+ scaleAbove.setState(true);
+ scaleAbove.setEnabled(false);
+ scaleAbove.addItemListener(this);
+ scaleLeft.setEnabled(false);
+ scaleLeft.setState(true);
+ scaleLeft.setLabel(MessageManager.getString("action.scale_left"));
+ scaleLeft.addItemListener(this);
+ scaleRight.setEnabled(false);
+ scaleRight.setState(true);
+ scaleRight.setLabel(MessageManager.getString("action.scale_right"));
+ scaleRight.addItemListener(this);
+ viewBoxesMenuItem.setLabel(MessageManager.getString("action.boxes"));
+ viewBoxesMenuItem.setState(true);
+ viewBoxesMenuItem.addItemListener(this);
+ viewTextMenuItem.setLabel(MessageManager.getString("action.text"));
+ viewTextMenuItem.setState(true);
+ viewTextMenuItem.addItemListener(this);
+ colourTextMenuItem.setLabel(MessageManager
+ .getString("label.colour_text"));
+ colourTextMenuItem.addItemListener(this);
+ displayNonconservedMenuItem.setLabel(MessageManager
+ .getString("label.show_non_conversed"));
+ displayNonconservedMenuItem.addItemListener(this);
+ wrapMenuItem.setLabel(MessageManager.getString("action.wrap"));
+ wrapMenuItem.addItemListener(this);
+ renderGapsMenuItem.setLabel(MessageManager
+ .getString("action.show_gaps"));
+ renderGapsMenuItem.setState(true);
+ renderGapsMenuItem.addItemListener(this);
+ centreColumnLabelFlag.setLabel(MessageManager
+ .getString("label.centre_column_labels"));
+ centreColumnLabelFlag.addItemListener(this);
+ seqLimits.setState(true);
+ seqLimits.setLabel(MessageManager
+ .getString("label.show_sequence_limits"));
+ seqLimits.addItemListener(this);
+
+ /*
+ * Configure Colour menu items and actions
+ */
+ applyToAllGroups.setLabel(MessageManager
+ .getString("label.apply_colour_to_all_groups"));
+ applyToAllGroups.setState(true);
+ applyToAllGroups.addItemListener(this);
+ clustalColour.setLabel(MessageManager.getString("label.clustalx"));
+ clustalColour.addActionListener(this);
+ zappoColour.setLabel(MessageManager.getString("label.zappo"));
+ zappoColour.addActionListener(this);
+ taylorColour.setLabel(MessageManager.getString("label.taylor"));
+ taylorColour.addActionListener(this);
+ hydrophobicityColour.setLabel(MessageManager
+ .getString("label.hydrophobicity"));
+ hydrophobicityColour.addActionListener(this);
+ helixColour
+ .setLabel(MessageManager.getString("label.helix_propensity"));
+ helixColour.addActionListener(this);
+ strandColour.setLabel(MessageManager
+ .getString("label.strand_propensity"));
+ strandColour.addActionListener(this);
+ turnColour.setLabel(MessageManager.getString("label.turn_propensity"));
+ turnColour.addActionListener(this);
+ buriedColour.setLabel(MessageManager.getString("label.buried_index"));
+ buriedColour.addActionListener(this);
+ purinePyrimidineColour.setLabel(MessageManager
+ .getString("label.purine_pyrimidine"));
+ purinePyrimidineColour.addActionListener(this);
+ RNAInteractionColour.setLabel(MessageManager
+ .getString("label.rna_interaction"));
+ RNAInteractionColour.addActionListener(this);
+ RNAHelixColour.setLabel(MessageManager
+ .getString("action.by_rna_helixes"));
+ RNAHelixColour.addActionListener(this);
+ userDefinedColour.setLabel(MessageManager
+ .getString("action.user_defined"));
+ userDefinedColour.addActionListener(this);
+ PIDColour.setLabel(MessageManager
+ .getString("label.percentage_identity"));
+ PIDColour.addActionListener(this);
+ BLOSUM62Colour.setLabel(MessageManager
+ .getString("label.blosum62_score"));
+ BLOSUM62Colour.addActionListener(this);
+ tcoffeeColour
+ .setLabel(MessageManager.getString("label.tcoffee_scores"));
+ // it will be enabled only if a score file is provided
+ tcoffeeColour.setEnabled(false);
+ tcoffeeColour.addActionListener(this);
+ conservationMenuItem.setLabel(MessageManager
+ .getString("action.by_conservation"));
+ conservationMenuItem.addItemListener(this);
+ noColourmenuItem.setLabel(MessageManager.getString("label.none"));
+ noColourmenuItem.addActionListener(this);
+ abovePIDThreshold.setLabel(MessageManager
+ .getString("label.above_identity_threshold"));
+ abovePIDThreshold.addItemListener(this);
+ nucleotideColour.setLabel(MessageManager.getString("label.nucleotide"));
+ nucleotideColour.addActionListener(this);
+ modifyPID.setLabel(MessageManager
+ .getString("label.modify_identity_thereshold"));
+ modifyPID.addActionListener(this);
+ modifyConservation.setLabel(MessageManager
+ .getString("label.modify_conservation_thereshold"));
+ modifyConservation.addActionListener(this);
+ annotationColour.setLabel(MessageManager
+ .getString("action.by_annotation"));
+ annotationColour.addActionListener(this);
+
+ /*
+ * Configure Calculate menu items and actions
+ */
+ sortPairwiseMenuItem.setLabel(MessageManager
+ .getString("action.by_pairwise_id"));
+ sortPairwiseMenuItem.addActionListener(this);
+ sortIDMenuItem.setLabel(MessageManager.getString("action.by_id"));
+ sortIDMenuItem.addActionListener(this);
+ sortLengthMenuItem.setLabel(MessageManager
+ .getString("action.by_length"));
+ sortLengthMenuItem.addActionListener(this);
+ sortGroupMenuItem.setLabel(MessageManager.getString("action.by_group"));
+ sortGroupMenuItem.addActionListener(this);
+ pairwiseAlignmentMenuItem.setLabel(MessageManager
+ .getString("action.pairwise_alignment"));
+ pairwiseAlignmentMenuItem.addActionListener(this);
+ PCAMenuItem.setLabel(MessageManager
+ .getString("label.principal_component_analysis"));
+ PCAMenuItem.addActionListener(this);
+ autoCalculate = new CheckboxMenuItem(
+ MessageManager.getString("label.autocalculate_consensus"), true);
+ averageDistanceTreeMenuItem.setLabel(MessageManager
+ .getString("label.average_distance_identity"));
+ averageDistanceTreeMenuItem.addActionListener(this);
+ neighbourTreeMenuItem.setLabel(MessageManager
+ .getString("label.neighbour_joining_identity"));
+ neighbourTreeMenuItem.addActionListener(this);
+ avDistanceTreeBlosumMenuItem.setLabel(MessageManager
+ .getString("label.average_distance_bloslum62"));
+ avDistanceTreeBlosumMenuItem.addActionListener(this);
+ njTreeBlosumMenuItem.setLabel(MessageManager
+ .getString("label.neighbour_blosum62"));
+ njTreeBlosumMenuItem.addActionListener(this);
+ sortByTreeMenu.setLabel(MessageManager
+ .getString("action.by_tree_order"));
+ Menu sortMenu = new Menu(MessageManager.getString("action.sort"));
+ Menu calculateTreeMenu = new Menu(
+ MessageManager.getString("action.calculate_tree"));
+ autoCalculate.addItemListener(this);
+ sortByTree.addItemListener(this);
+
+ /*
+ * Configure Help menu items and actions
+ */
+ Menu helpMenu = new Menu(MessageManager.getString("action.help"));
+ documentation.setLabel(MessageManager.getString("label.documentation"));
+ documentation.addActionListener(this);
+ about.setLabel(MessageManager.getString("label.about"));
+ about.addActionListener(this);
+
+ /*
+ * Add top level menus to frame
+ */
alignFrameMenuBar.add(fileMenu);
+ Menu editMenu = new Menu(MessageManager.getString("action.edit"));
alignFrameMenuBar.add(editMenu);
+ Menu selectMenu = new Menu(MessageManager.getString("action.select"));
alignFrameMenuBar.add(selectMenu);
+ Menu viewMenu = new Menu(MessageManager.getString("action.view"));
alignFrameMenuBar.add(viewMenu);
+ Menu annotationsMenu = new Menu(
+ MessageManager.getString("action.annotations"));
+ alignFrameMenuBar.add(annotationsMenu);
+ Menu formatMenu = new Menu(MessageManager.getString("action.format"));
alignFrameMenuBar.add(formatMenu);
+ Menu colourMenu = new Menu(MessageManager.getString("action.colour"));
alignFrameMenuBar.add(colourMenu);
+ Menu calculateMenu = new Menu(
+ MessageManager.getString("action.calculate"));
alignFrameMenuBar.add(calculateMenu);
alignFrameMenuBar.add(helpMenu);
+ /*
+ * File menu
+ */
fileMenu.add(inputText);
fileMenu.add(loadTree);
fileMenu.add(loadAnnotations);
-
fileMenu.addSeparator();
fileMenu.add(outputTextboxMenu);
fileMenu.add(outputFeatures);
fileMenu.add(outputAnnotations);
-
if (jalviewServletURL != null)
{
fileMenu.add(loadApplication);
}
-
fileMenu.addSeparator();
fileMenu.add(closeMenuItem);
+ /*
+ * Edit menu
+ */
editMenu.add(undoMenuItem);
editMenu.add(redoMenuItem);
editMenu.add(cut);
editMenu.add(copy);
+ pasteMenu.add(pasteNew);
+ pasteMenu.add(pasteThis);
editMenu.add(pasteMenu);
editMenu.add(delete);
editMenu.addSeparator();
@@ -3372,21 +3553,38 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
editMenu.add(removeGappedColumnMenuItem);
editMenu.add(removeAllGapsMenuItem);
editMenu.add(removeRedundancyMenuItem);
+
+ /*
+ * Select menu
+ */
+ selectMenu.add(findMenuItem);
+ selectMenu.addSeparator();
+ selectMenu.add(selectAllSequenceMenuItem);
+ selectMenu.add(deselectAllSequenceMenuItem);
+ selectMenu.add(invertSequenceMenuItem);
+ selectMenu.add(invertColSel);
+ selectMenu.add(createGroup);
+ selectMenu.add(unGroup);
+ selectMenu.add(grpsFromSelection);
+ selectMenu.add(deleteGroups);
+ selectMenu.add(annotationColumnSelection);
+
+ /*
+ * View menu
+ */
viewMenu.add(newView);
viewMenu.addSeparator();
- viewMenu.add(menu1);
- viewMenu.add(menu2);
+ showMenu.add(showColumns);
+ showMenu.add(showSeqs);
+ showMenu.add(showAllHidden);
+ viewMenu.add(showMenu);
+ hideMenu.add(hideColumns);
+ hideMenu.add(hideSequences);
+ hideMenu.add(hideAllSelection);
+ hideMenu.add(hideAllButSelection);
+ viewMenu.add(hideMenu);
viewMenu.addSeparator();
viewMenu.add(followMouseOverFlag);
- viewMenu.add(annotationPanelMenuItem);
- autoAnnMenu.add(applyAutoAnnotationSettings);
- autoAnnMenu.add(showConsensusHistogram);
- autoAnnMenu.add(showSequenceLogo);
- autoAnnMenu.add(normSequenceLogo);
- autoAnnMenu.addSeparator();
- autoAnnMenu.add(showGroupConservation);
- autoAnnMenu.add(showGroupConsensus);
- viewMenu.add(autoAnnMenu);
viewMenu.addSeparator();
viewMenu.add(sequenceFeatures);
viewMenu.add(featureSettings);
@@ -3394,6 +3592,48 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
viewMenu.add(alProperties);
viewMenu.addSeparator();
viewMenu.add(overviewMenuItem);
+
+ /*
+ * Annotations menu
+ */
+ // annotationsMenu.add(annotationPanelMenuItem);
+ // annotationsMenu.addSeparator();
+ annotationsMenu.add(showAlignmentAnnotations);
+ annotationsMenu.add(showSequenceAnnotations);
+ annotationsMenu.add(sortAnnBySequence);
+ annotationsMenu.add(sortAnnByLabel);
+ annotationsMenu.addSeparator();
+ autoAnnMenu.add(showAutoFirst);
+ autoAnnMenu.add(showAutoLast);
+ autoAnnMenu.addSeparator();
+ autoAnnMenu.add(applyAutoAnnotationSettings);
+ autoAnnMenu.add(showConsensusHistogram);
+ autoAnnMenu.add(showSequenceLogo);
+ autoAnnMenu.add(normSequenceLogo);
+ autoAnnMenu.addSeparator();
+ autoAnnMenu.add(showGroupConservation);
+ autoAnnMenu.add(showGroupConsensus);
+ annotationsMenu.add(autoAnnMenu);
+
+ /*
+ * Format menu
+ */
+ formatMenu.add(font);
+ formatMenu.add(seqLimits);
+ formatMenu.add(wrapMenuItem);
+ formatMenu.add(scaleAbove);
+ formatMenu.add(scaleLeft);
+ formatMenu.add(scaleRight);
+ formatMenu.add(viewBoxesMenuItem);
+ formatMenu.add(viewTextMenuItem);
+ formatMenu.add(colourTextMenuItem);
+ formatMenu.add(displayNonconservedMenuItem);
+ formatMenu.add(renderGapsMenuItem);
+ formatMenu.add(centreColumnLabelFlag);
+
+ /*
+ * Colour menu
+ */
colourMenu.add(applyToAllGroups);
colourMenu.addSeparator();
colourMenu.add(noColourmenuItem);
@@ -3419,58 +3659,40 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
colourMenu.add(modifyPID);
colourMenu.add(annotationColour);
colourMenu.add(RNAHelixColour);
- calculateMenu.add(sort);
- calculateMenu.add(calculate);
+
+ /*
+ * Calculate menu
+ */
+ sortMenu.add(sortIDMenuItem);
+ sortMenu.add(sortLengthMenuItem);
+ sortMenu.add(sortByTreeMenu);
+ sortMenu.add(sortGroupMenuItem);
+ sortMenu.add(sortPairwiseMenuItem);
+ calculateMenu.add(sortMenu);
+ calculateTreeMenu.add(averageDistanceTreeMenuItem);
+ calculateTreeMenu.add(neighbourTreeMenuItem);
+ calculateTreeMenu.add(avDistanceTreeBlosumMenuItem);
+ calculateTreeMenu.add(njTreeBlosumMenuItem);
+ calculateMenu.add(calculateTreeMenu);
calculateMenu.addSeparator();
calculateMenu.add(pairwiseAlignmentMenuItem);
calculateMenu.add(PCAMenuItem);
calculateMenu.add(autoCalculate);
calculateMenu.add(sortByTree);
- this.add(statusBar, BorderLayout.SOUTH);
- pasteMenu.add(pasteNew);
- pasteMenu.add(pasteThis);
- sort.add(sortIDMenuItem);
- sort.add(sortLengthMenuItem);
- sort.add(sortByTreeMenu);
- sort.add(sortGroupMenuItem);
- sort.add(sortPairwiseMenuItem);
- calculate.add(averageDistanceTreeMenuItem);
- calculate.add(neighbourTreeMenuItem);
- calculate.add(avDistanceTreeBlosumMenuItem);
- calculate.add(njTreeBlosumMenuItem);
+
+ /*
+ * Help menu
+ */
helpMenu.add(documentation);
helpMenu.add(about);
- menu1.add(showColumns);
- menu1.add(showSeqs);
- menu1.add(showAllHidden);
- menu2.add(hideColumns);
- menu2.add(hideSequences);
- menu2.add(hideAllSelection);
- menu2.add(hideAllButSelection);
- formatMenu.add(font);
- formatMenu.add(seqLimits);
- formatMenu.add(wrapMenuItem);
- formatMenu.add(scaleAbove);
- formatMenu.add(scaleLeft);
- formatMenu.add(scaleRight);
- formatMenu.add(viewBoxesMenuItem);
- formatMenu.add(viewTextMenuItem);
- formatMenu.add(colourTextMenuItem);
- formatMenu.add(displayNonconservedMenuItem);
- formatMenu.add(renderGapsMenuItem);
- formatMenu.add(centreColumnLabelFlag);
- selectMenu.add(findMenuItem);
- selectMenu.addSeparator();
- selectMenu.add(selectAllSequenceMenuItem);
- selectMenu.add(deselectAllSequenceMenuItem);
- selectMenu.add(invertSequenceMenuItem);
- selectMenu.add(invertColSel);
- selectMenu.add(createGroup);
- selectMenu.add(unGroup);
- selectMenu.add(grpsFromSelection);
- selectMenu.add(deleteGroups);
- selectMenu.add(annotationColumnSelection);
+ /*
+ * Status bar
+ */
+ statusBar.setBackground(Color.white);
+ statusBar.setFont(new java.awt.Font("Verdana", 0, 11));
+ statusBar.setText(MessageManager.getString("label.status_bar"));
+ this.add(statusBar, BorderLayout.SOUTH);
}
public void setStatus(String string)
@@ -3488,14 +3710,10 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
MenuItem invertColSel = new MenuItem();
- Menu menu1 = new Menu();
-
MenuItem showColumns = new MenuItem();
MenuItem showSeqs = new MenuItem();
- Menu menu2 = new Menu();
-
MenuItem hideColumns = new MenuItem();
MenuItem hideSequences = new MenuItem();
@@ -3506,11 +3724,19 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
MenuItem showAllHidden = new MenuItem();
- Menu formatMenu = new Menu();
+ MenuItem newView = new MenuItem();
- Menu selectMenu = new Menu();
+ private CheckboxMenuItem showAlignmentAnnotations;
- MenuItem newView = new MenuItem();
+ private CheckboxMenuItem showSequenceAnnotations;
+
+ private CheckboxMenuItem sortAnnBySequence;
+
+ private CheckboxMenuItem sortAnnByLabel;
+
+ private CheckboxMenuItem showAutoFirst;
+
+ private CheckboxMenuItem showAutoLast;
/**
* Attach the alignFrame panels after embedding menus, if necessary. This used
@@ -3521,46 +3747,11 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
* true to attach the view to the applet area on the page rather than
* in a new window
*/
- public void createAlignFrameWindow(boolean reallyEmbedded, String title)
+ public void createAlignFrameWindow(boolean reallyEmbedded)
{
if (reallyEmbedded)
{
- // ////
- // Explicly build the embedded menu panel for the on-page applet
- //
- // view cannot be closed if its actually on the page
- fileMenu.remove(closeMenuItem);
- fileMenu.remove(3); // Remove Seperator
- embeddedMenu = makeEmbeddedPopupMenu(alignFrameMenuBar, "Arial",
- Font.PLAIN, 11, false); // use our own fonts.
- // and actually add the components to the applet area
- viewport.applet.setLayout(new BorderLayout());
- viewport.applet.add(embeddedMenu, BorderLayout.NORTH);
- viewport.applet.add(statusBar, BorderLayout.SOUTH);
- alignPanel.setSize(viewport.applet.getSize().width,
- viewport.applet.getSize().height - embeddedMenu.HEIGHT
- - statusBar.HEIGHT);
- viewport.applet.add(alignPanel, BorderLayout.CENTER);
- final AlignFrame me = this;
- viewport.applet.addFocusListener(new FocusListener()
- {
-
- @Override
- public void focusLost(FocusEvent e)
- {
- if (me.viewport.applet.currentAlignFrame == me)
- {
- me.viewport.applet.currentAlignFrame = null;
- }
- }
-
- @Override
- public void focusGained(FocusEvent e)
- {
- me.viewport.applet.currentAlignFrame = me;
- }
- });
- viewport.applet.validate();
+ embedAlignFrameInApplet(viewport.applet);
}
else
{
@@ -3569,19 +3760,69 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
//
if (embedMenuIfNeeded(alignPanel))
{
- // adjust for status bar height too
- alignPanel.setSize(getSize().width, getSize().height
- - statusBar.HEIGHT);
+ /*
+ * adjust for status bar height too. ? pointless as overridden by layout
+ * manager
+ */
+ alignPanel.setSize(getSize().width,
+ getSize().height - statusBar.getHeight());
}
add(statusBar, BorderLayout.SOUTH);
add(alignPanel, BorderLayout.CENTER);
// and register with the applet so it can pass external API calls to us
- jalview.bin.JalviewLite.addFrame(this, title, DEFAULT_WIDTH,
+ jalview.bin.JalviewLite.addFrame(this, this.getTitle(),
+ DEFAULT_WIDTH,
DEFAULT_HEIGHT);
}
}
/**
+ * Add the components of this AlignFrame to the applet container.
+ *
+ * @param theApplet
+ */
+ public void embedAlignFrameInApplet(final JalviewLite theApplet)
+ {
+ // ////
+ // Explicitly build the embedded menu panel for the on-page applet
+ //
+ // view cannot be closed if its actually on the page
+ fileMenu.remove(closeMenuItem);
+ fileMenu.remove(3); // Remove Separator
+ // construct embedded menu, using default font
+ embeddedMenu = makeEmbeddedPopupMenu(alignFrameMenuBar, false, false);
+ // and actually add the components to the applet area
+ theApplet.setLayout(new BorderLayout());
+ theApplet.add(embeddedMenu, BorderLayout.NORTH);
+ theApplet.add(statusBar, BorderLayout.SOUTH);
+ // TODO should size be left to the layout manager?
+ alignPanel.setSize(theApplet.getSize().width,
+ theApplet.getSize().height - embeddedMenu.getHeight()
+ - statusBar.getHeight());
+ theApplet.add(alignPanel, BorderLayout.CENTER);
+ final AlignFrame me = this;
+ theApplet.addFocusListener(new FocusListener()
+ {
+
+ @Override
+ public void focusLost(FocusEvent e)
+ {
+ if (theApplet.currentAlignFrame == me)
+ {
+ theApplet.currentAlignFrame = null;
+ }
+ }
+
+ @Override
+ public void focusGained(FocusEvent e)
+ {
+ theApplet.currentAlignFrame = me;
+ }
+ });
+ theApplet.validate();
+ }
+
+ /**
* create a new binding between structures in an existing jmol viewer instance
* and an alignpanel with sequences that have existing PDBFile entries. Note,
* this does not open a new Jmol window, or modify the display of the
diff --git a/src/jalview/appletgui/AlignViewport.java b/src/jalview/appletgui/AlignViewport.java
index 7cf7be0..2d38008 100644
--- a/src/jalview/appletgui/AlignViewport.java
+++ b/src/jalview/appletgui/AlignViewport.java
@@ -20,9 +20,12 @@
*/
package jalview.appletgui;
+import java.awt.Font;
+
import jalview.analysis.NJTree;
import jalview.api.AlignViewportI;
import jalview.bin.JalviewLite;
+import jalview.commands.CommandI;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.ColumnSelection;
import jalview.datamodel.Sequence;
@@ -30,15 +33,14 @@ import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.schemes.ColourSchemeProperty;
import jalview.schemes.UserColourScheme;
+import jalview.structure.CommandListener;
import jalview.structure.SelectionSource;
+import jalview.structure.StructureSelectionManager;
import jalview.structure.VamsasSource;
import jalview.viewmodel.AlignmentViewport;
-import java.awt.Font;
-import java.util.Stack;
-
public class AlignViewport extends AlignmentViewport implements
- AlignViewportI, SelectionSource, VamsasSource
+ AlignViewportI, SelectionSource, VamsasSource, CommandListener
{
int startRes;
@@ -50,54 +52,16 @@ public class AlignViewport extends AlignmentViewport implements
boolean cursorMode = false;
- boolean showJVSuffix = true;
-
- boolean showText = true;
-
- boolean showColourText = false;
-
- boolean showBoxes = true;
-
- boolean wrapAlignment = false;
-
- boolean renderGaps = true;
-
- boolean showAnnotation = true;
-
- boolean upperCasebold = false;
-
- int charHeight;
-
- int charWidth;
-
- int wrappedWidth;
-
Font font = new Font("SansSerif", Font.PLAIN, 10);
boolean validCharWidth = true;
- int threshold;
-
- int increment;
-
NJTree currentTree = null;
- boolean scaleAboveWrapped = true;
-
- boolean scaleLeftWrapped = true;
-
- boolean scaleRightWrapped = true;
-
- boolean showHiddenMarkers = true;
-
public jalview.bin.JalviewLite applet;
boolean MAC = false;
- Stack historyList = new Stack();
-
- Stack redoList = new Stack();
-
private AnnotationColumnChooser annotationColumnSelectionState;
public void finalize()
@@ -110,9 +74,10 @@ public class AlignViewport extends AlignmentViewport implements
public AlignViewport(AlignmentI al, JalviewLite applet)
{
+ super();
calculator = new jalview.workers.AlignCalcManager();
this.applet = applet;
- setAlignment(al);
+ alignment = al;
// we always pad gaps
this.setPadGaps(true);
this.startRes = 0;
@@ -175,10 +140,11 @@ public class AlignViewport extends AlignmentViewport implements
if (applet != null)
{
- showJVSuffix = applet.getDefaultParameter("showFullId", showJVSuffix);
+ setShowJVSuffix(applet.getDefaultParameter("showFullId",
+ getShowJVSuffix()));
- showAnnotation = applet.getDefaultParameter("showAnnotation",
- showAnnotation);
+ setShowAnnotation(applet.getDefaultParameter("showAnnotation",
+ isShowAnnotation()));
showConservation = applet.getDefaultParameter("showConservation",
showConservation);
@@ -188,15 +154,15 @@ public class AlignViewport extends AlignmentViewport implements
showConsensus = applet.getDefaultParameter("showConsensus",
showConsensus);
- showUnconserved = applet.getDefaultParameter("showUnconserved",
- showUnconserved);
+ setShowUnconserved(applet.getDefaultParameter("showUnconserved",
+ getShowUnconserved()));
String param = applet.getParameter("upperCase");
if (param != null)
{
if (param.equalsIgnoreCase("bold"))
{
- upperCasebold = true;
+ setUpperCasebold(true);
}
}
sortByTree = applet.getDefaultParameter("sortByTree", sortByTree);
@@ -272,7 +238,7 @@ public class AlignViewport extends AlignmentViewport implements
{
return null;
}
- StringBuffer seqs = new StringBuffer();
+ StringBuilder seqs = new StringBuilder(consensus.annotations.length);
for (int i = 0; i < consensus.annotations.length; i++)
{
if (consensus.annotations[i] != null)
@@ -368,13 +334,13 @@ public class AlignViewport extends AlignmentViewport implements
java.awt.FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font);
setCharHeight((int) (heightScale * fm.getHeight()));
- charWidth = (int) (widthScale * fm.charWidth('M'));
+ setCharWidth((int) (widthScale * fm.charWidth('M')));
- if (upperCasebold)
+ if (isUpperCasebold())
{
Font f2 = new Font(f.getName(), Font.BOLD, f.getSize());
fm = nullFrame.getGraphics().getFontMetrics(f2);
- charWidth = (int) (widthScale * (fm.stringWidth("MMMMMMMMMMM") / 10));
+ setCharWidth((int) (widthScale * (fm.stringWidth("MMMMMMMMMMM") / 10)));
}
}
@@ -383,98 +349,6 @@ public class AlignViewport extends AlignmentViewport implements
return font;
}
- public int getCharWidth()
- {
- return charWidth;
- }
-
- public void setCharHeight(int h)
- {
- this.charHeight = h;
- }
-
- public int getCharHeight()
- {
- return charHeight;
- }
-
- public void setWrappedWidth(int w)
- {
- this.wrappedWidth = w;
- }
-
- public int getwrappedWidth()
- {
- return wrappedWidth;
- }
-
- public AlignmentI getAlignment()
- {
- return alignment;
- }
-
- public void setAlignment(AlignmentI align)
- {
- this.alignment = align;
- }
-
- public void setWrapAlignment(boolean state)
- {
- wrapAlignment = state;
- }
-
- public void setShowText(boolean state)
- {
- showText = state;
- }
-
- public void setRenderGaps(boolean state)
- {
- renderGaps = state;
- }
-
- public boolean getColourText()
- {
- return showColourText;
- }
-
- public void setColourText(boolean state)
- {
- showColourText = state;
- }
-
- public void setShowBoxes(boolean state)
- {
- showBoxes = state;
- }
-
- public boolean getWrapAlignment()
- {
- return wrapAlignment;
- }
-
- public boolean getShowText()
- {
- return showText;
- }
-
- public boolean getShowBoxes()
- {
- return showBoxes;
- }
-
- public char getGapCharacter()
- {
- return getAlignment().getGapCharacter();
- }
-
- public void setGapCharacter(char gap)
- {
- if (getAlignment() != null)
- {
- getAlignment().setGapCharacter(gap);
- }
- }
public void resetSeqLimits(int height)
{
@@ -491,77 +365,6 @@ public class AlignViewport extends AlignmentViewport implements
return currentTree;
}
- public boolean getShowJVSuffix()
- {
- return showJVSuffix;
- }
-
- public void setShowJVSuffix(boolean b)
- {
- showJVSuffix = b;
- }
-
- public boolean getShowAnnotation()
- {
- return showAnnotation;
- }
-
- public void setShowAnnotation(boolean b)
- {
- showAnnotation = b;
- }
-
- public boolean getScaleAboveWrapped()
- {
- return scaleAboveWrapped;
- }
-
- public boolean getScaleLeftWrapped()
- {
- return scaleLeftWrapped;
- }
-
- public boolean getScaleRightWrapped()
- {
- return scaleRightWrapped;
- }
-
- public void setScaleAboveWrapped(boolean b)
- {
- scaleAboveWrapped = b;
- }
-
- public void setScaleLeftWrapped(boolean b)
- {
- scaleLeftWrapped = b;
- }
-
- public void setScaleRightWrapped(boolean b)
- {
- scaleRightWrapped = b;
- }
-
- public void setIgnoreGapsConsensus(boolean b)
- {
- ignoreGapsInConsensusCalculation = b;
- updateConsensus(null);
- if (globalColourScheme != null)
- {
- globalColourScheme.setThreshold(globalColourScheme.getThreshold(),
- ignoreGapsInConsensusCalculation);
-
- }
- }
-
- public boolean getShowHiddenMarkers()
- {
- return showHiddenMarkers;
- }
-
- public void setShowHiddenMarkers(boolean show)
- {
- showHiddenMarkers = show;
- }
boolean centreColumnLabels;
@@ -590,13 +393,25 @@ public class AlignViewport extends AlignmentViewport implements
public void sendSelection()
{
- jalview.structure.StructureSelectionManager
- .getStructureSelectionManager(applet).sendSelection(
+ getStructureSelectionManager().sendSelection(
new SequenceGroup(getSelectionGroup()),
new ColumnSelection(getColumnSelection()), this);
}
/**
+ * Returns an instance of the StructureSelectionManager scoped to this applet
+ * instance.
+ *
+ * @return
+ */
+ @Override
+ public StructureSelectionManager getStructureSelectionManager()
+ {
+ return jalview.structure.StructureSelectionManager
+ .getStructureSelectionManager(applet);
+ }
+
+ /**
* synthesize a column selection if none exists so it covers the given
* selection group. if wholewidth is false, no column selection is made if the
* selection group covers the whole alignment width.
@@ -659,4 +474,41 @@ public class AlignViewport extends AlignmentViewport implements
this.annotationColumnSelectionState = annotationColumnSelectionState;
}
+ @Override
+ public void mirrorCommand(CommandI command, boolean undo,
+ StructureSelectionManager ssm, VamsasSource source)
+ {
+ // TODO refactor so this can be pulled up to superclass or controller
+ /*
+ * Do nothing unless we are a 'complement' of the source. May replace this
+ * with direct calls not via SSM.
+ */
+ if (source instanceof AlignViewportI
+ && ((AlignViewportI) source).getCodingComplement() == this)
+ {
+ // ok to continue;
+ }
+ else
+ {
+ return;
+ }
+
+ CommandI mappedCommand = ssm.mapCommand(command, undo, getAlignment(),
+ getGapCharacter());
+ if (mappedCommand != null)
+ {
+ mappedCommand.doCommand(null);
+ firePropertyChange("alignment", null, getAlignment().getSequences());
+
+ // ap.scalePanelHolder.repaint();
+ // ap.repaint();
+ }
+ }
+
+ @Override
+ public VamsasSource getVamsasSource()
+ {
+ return this;
+ }
+
}
diff --git a/src/jalview/appletgui/AlignmentPanel.java b/src/jalview/appletgui/AlignmentPanel.java
index 7c4882a..c74914f 100644
--- a/src/jalview/appletgui/AlignmentPanel.java
+++ b/src/jalview/appletgui/AlignmentPanel.java
@@ -20,12 +20,6 @@
*/
package jalview.appletgui;
-import jalview.api.AlignmentViewPanel;
-import jalview.datamodel.AlignmentI;
-import jalview.datamodel.SearchResults;
-import jalview.datamodel.SequenceI;
-import jalview.structure.StructureSelectionManager;
-
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
@@ -39,6 +33,14 @@ import java.awt.event.AdjustmentListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
+import jalview.analysis.AnnotationSorter;
+import jalview.api.AlignViewportI;
+import jalview.api.AlignmentViewPanel;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SearchResults;
+import jalview.datamodel.SequenceI;
+import jalview.structure.StructureSelectionManager;
+
public class AlignmentPanel extends Panel implements AdjustmentListener,
AlignmentViewPanel
{
@@ -100,7 +102,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
sequenceHolderPanel.add(annotationPanelHolder, BorderLayout.SOUTH);
alabels = new AnnotationLabels(this);
- setAnnotationVisible(av.showAnnotation);
+ setAnnotationVisible(av.isShowAnnotation());
idPanelHolder.add(idPanel, BorderLayout.CENTER);
idSpaceFillerPanel1.add(idwidthAdjuster, BorderLayout.CENTER);
@@ -153,6 +155,11 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
});
}
+ @Override
+ public AlignViewportI getAlignViewport()
+ {
+ return av;
+ }
public SequenceRenderer getSequenceRenderer()
{
return seqPanel.seqCanvas.sr;
@@ -190,8 +197,9 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
idPanel.idCanvas.image = null;
FontMetrics fm = getFontMetrics(av.getFont());
- scalePanel.setSize(new Dimension(10, av.charHeight + fm.getDescent()));
- idwidthAdjuster.setSize(new Dimension(10, av.charHeight
+ scalePanel.setSize(new Dimension(10, av.getCharHeight()
+ + fm.getDescent()));
+ idwidthAdjuster.setSize(new Dimension(10, av.getCharHeight()
+ fm.getDescent()));
av.updateSequenceIdColours();
annotationPanel.image = null;
@@ -375,7 +383,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
{
start = ostart;
}
- if (!av.wrapAlignment)
+ if (!av.getWrapAlignment())
{
/*
* int spos=av.getStartRes(),sqpos=av.getStartSeq(); if ((startv =
@@ -449,7 +457,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
public void setAnnotationVisible(boolean b)
{
- if (!av.wrapAlignment)
+ if (!av.getWrapAlignment())
{
annotationSpaceFillerHolder.setVisible(b);
annotationPanelHolder.setVisible(b);
@@ -473,7 +481,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
// this is called after loading new annotation onto alignment
if (alignFrame.getSize().height == 0)
{
- System.out.println("NEEDS FIXING");
+ System.out
+ .println("adjustAnnotationHeight frame size zero NEEDS FIXING");
}
fontChanged();
validateAnnotationDimensions(true);
@@ -566,7 +575,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
annotationPanelHolder.setVisible(false);
annotationSpaceFillerHolder.setVisible(false);
}
- else if (av.showAnnotation)
+ else if (av.isShowAnnotation())
{
annotationPanelHolder.setVisible(true);
annotationSpaceFillerHolder.setVisible(true);
@@ -648,8 +657,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
}
;
- hextent = seqPanel.seqCanvas.getSize().width / av.charWidth;
- vextent = seqPanel.seqCanvas.getSize().height / av.charHeight;
+ hextent = seqPanel.seqCanvas.getSize().width / av.getCharWidth();
+ vextent = seqPanel.seqCanvas.getSize().height / av.getCharHeight();
if (hextent > width)
{
@@ -694,7 +703,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
av.setEndSeq(endSeq);
av.setStartRes(x);
- av.setEndRes((x + (seqPanel.seqCanvas.getSize().width / av.charWidth)) - 1);
+ av.setEndRes((x + (seqPanel.seqCanvas.getSize().width / av
+ .getCharWidth())) - 1);
hscroll.setValues(x, hextent, 0, width);
vscroll.setValues(y, vextent, 0, height);
@@ -776,7 +786,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
seqPanel.seqCanvas.fastPaint(scrollX, scrollY);
scalePanel.repaint();
- if (av.getShowAnnotation())
+ if (av.isShowAnnotation())
{
annotationPanel.fastPaint(av.getStartRes() - oldX);
}
@@ -792,8 +802,15 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
av.endSeq);
}
+ /**
+ * Repaint the alignment and annotations, and, optionally, any overview window
+ */
public void paintAlignment(boolean updateOverview)
{
+ final AnnotationSorter sorter = new AnnotationSorter(getAlignment(),
+ av.isShowAutocalculatedAbove());
+ sorter.sort(getAlignment().getAlignmentAnnotation(),
+ av.getSortAnnotationsBy());
repaint();
if (updateOverview)
@@ -847,9 +864,9 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
seqPanel.seqCanvas.repaint();
idPanel.idCanvas.repaint();
- if (!av.wrapAlignment)
+ if (!av.getWrapAlignment())
{
- if (av.showAnnotation)
+ if (av.isShowAnnotation())
{
alabels.repaint();
annotationPanel.repaint();
diff --git a/src/jalview/appletgui/AnnotationLabels.java b/src/jalview/appletgui/AnnotationLabels.java
index f288188..67faf11 100755
--- a/src/jalview/appletgui/AnnotationLabels.java
+++ b/src/jalview/appletgui/AnnotationLabels.java
@@ -20,13 +20,6 @@
*/
package jalview.appletgui;
-import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.Annotation;
-import jalview.datamodel.SequenceGroup;
-import jalview.datamodel.SequenceI;
-import jalview.util.MessageManager;
-import jalview.util.ParseHtmlBodyAndLinks;
-
import java.awt.Checkbox;
import java.awt.CheckboxMenuItem;
import java.awt.Color;
@@ -48,8 +41,17 @@ import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Vector;
+import jalview.analysis.AlignmentUtils;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.util.MessageManager;
+import jalview.util.ParseHtmlBodyAndLinks;
+
public class AnnotationLabels extends Panel implements ActionListener,
MouseListener, MouseMotionListener
{
@@ -211,6 +213,14 @@ public class AnnotationLabels extends Panel implements ActionListener,
}
}
+ refresh();
+ }
+
+ /**
+ * Adjust size and repaint
+ */
+ protected void refresh()
+ {
ap.annotationPanel.adjustPanelHeight();
setSize(getSize().width, ap.annotationPanel.getSize().height);
ap.validate();
@@ -311,8 +321,8 @@ public class AnnotationLabels extends Panel implements ActionListener,
.getSize(), f = ap.seqPanelHolder.getSize();
int dif = evt.getY() - oldY;
- dif /= ap.av.charHeight;
- dif *= ap.av.charHeight;
+ dif /= ap.av.getCharHeight();
+ dif *= ap.av.getCharHeight();
if ((d.height - dif) > 20 && (f.height + dif) > 20)
{
@@ -461,6 +471,32 @@ public class AnnotationLabels extends Panel implements ActionListener,
item = new MenuItem(HIDE);
item.addActionListener(this);
popup.add(item);
+
+ /*
+ * Hide all