From: gmungoc Date: Wed, 1 Mar 2017 14:38:50 +0000 (+0000) Subject: Merge branch 'features/JAL-2295setChimeraAttributes' into X-Git-Tag: Release_2_10_2~3^2~173 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=4762b29420ed4df01b55a8afe5ab05467aaf41a9;hp=-c;p=jalview.git Merge branch 'features/JAL-2295setChimeraAttributes' into merges/develop_JAL2295setChimeraAttributes Conflicts: src/jalview/ext/rbvi/chimera/ChimeraCommands.java src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java src/jalview/gui/ChimeraViewFrame.java test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java --- 4762b29420ed4df01b55a8afe5ab05467aaf41a9 diff --combined resources/lang/Messages.properties index f720f39,f1e371d..25f65ab --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@@ -61,6 -61,7 +61,6 @@@ action.set_as_reference = Set as Refere action.remove = Remove action.remove_redundancy = Remove Redundancy... action.pairwise_alignment = Pairwise Alignment -action.by_rna_helixes = By RNA Helices action.user_defined = User Defined... action.by_conservation = By Conservation action.wrap = Wrap @@@ -138,8 -139,7 +138,8 @@@ action.view_flanking_regions = Show fla label.view_flanking_regions = Show sequence data either side of the subsequences involved in this alignment label.structures_manager = Structures Manager label.nickname = Nickname: -label.url = URL: +label.url = URL +label.url\: = URL: label.input_file_url = Enter URL or Input File label.select_feature = Select feature label.name = Name @@@ -179,30 -179,27 +179,30 @@@ label.score_model_conservation = Physic label.score_model_enhconservation = Physicochemical property conservation label.status_bar = Status bar label.out_to_textbox = Output to Textbox -label.clustalx = Clustalx +# delete Clustal - use FileFormat name instead label.clustal = Clustal -label.zappo = Zappo -label.taylor = Taylor +# label.colourScheme_ as in JalviewColourScheme +label.colourScheme_clustal = Clustalx +label.colourScheme_blosum62 = BLOSUM62 Score +label.colourScheme_%_identity = Percentage Identity +label.colourScheme_zappo = Zappo +label.colourScheme_taylor = Taylor +label.colourScheme_hydrophobic = Hydrophobicity +label.colourScheme_helix_propensity = Helix Propensity +label.colourScheme_strand_propensity = Strand Propensity +label.colourScheme_turn_propensity = Turn Propensity +label.colourScheme_buried_index = Buried Index +label.colourScheme_purine/pyrimidine = Purine/Pyrimidine +label.colourScheme_nucleotide = Nucleotide +label.colourScheme_t-coffee_scores = T-Coffee Scores +label.colourScheme_rna_helices = By RNA Helices label.blc = BLC label.fasta = Fasta label.msf = MSF label.pfam = PFAM label.pileup = Pileup label.pir = PIR -label.hydrophobicity = Hydrophobicity -label.helix_propensity = Helix Propensity -label.strand_propensity = Strand Propensity -label.turn_propensity = Turn Propensity -label.buried_index = Buried Index -label.purine_pyrimidine = Purine/Pyrimidine -label.percentage_identity = Percentage Identity -label.blosum62 = BLOSUM62 -label.blosum62_score = BLOSUM62 Score -label.tcoffee_scores = T-Coffee Scores -label.average_distance_bloslum62 = Average Distance Using BLOSUM62 +label.average_distance_blosum62 = Average Distance Using BLOSUM62 label.neighbour_blosum62 = Neighbour Joining Using BLOSUM62 label.show_annotations = Show annotations label.hide_annotations = Hide annotations @@@ -214,7 -211,7 +214,7 @@@ label.hide_all = Hide al label.add_reference_annotations = Add reference annotations label.find_tip = Search alignment, selection or sequence ids for a subsequence (ignoring gaps).
Accepts regular expressions - search Help for 'regex' for details. label.colour_text = Colour Text -label.show_non_conversed = Show nonconserved +label.show_non_conserved = Show nonconserved label.overview_window = Overview Window label.none = None label.above_identity_threshold = Above Identity Threshold @@@ -326,7 -323,7 +326,7 @@@ label.size = Size label.style = Style: label.calculating = Calculating.... label.modify_conservation_visibility = Modify conservation visibility -label.colour_residues_above_occurence = Colour residues above % occurence +label.colour_residues_above_occurrence = Colour residues above % occurrence label.set_this_label_text = set this label text label.sequences_from = Sequences from {0} label.successfully_loaded_file = Successfully loaded file {0} @@@ -414,6 -411,7 +414,6 @@@ label.couldnt_import_as_vamsas_session label.vamsas_document_import_failed = Vamsas Document Import Failed label.couldnt_locate = Couldn't locate {0} label.url_not_found = URL not found -label.no_link_selected = No link selected label.new_sequence_url_link = New sequence URL link label.cannot_edit_annotations_in_wrapped_view = Cannot edit annotations in wrapped view label.wrapped_view_no_edit = Wrapped view - no edit @@@ -620,6 -618,6 +620,8 @@@ label.web_services = Web Service label.right_click_to_edit_currently_selected_parameter = Right click to edit currently selected parameter. label.let_jmol_manage_structure_colours = Let Jmol manage structure colours label.let_chimera_manage_structure_colours = Let Chimera manage structure colours ++label.fetch_chimera_attributes = Fetch Chimera attributes ++label.fetch_chimera_attributes_tip = Copy Chimera attribute to Jalview feature label.marks_leaves_tree_not_associated_with_sequence = Marks leaves of tree not associated with a sequence label.index_web_services_menu_by_host_site = Index web services in menu by the host site label.option_want_informed_web_service_URL_cannot_be_accessed_jalview_when_starts_up = Check this option if you want to be informed
when a web service URL cannot be accessed by Jalview
when it starts up @@@ -672,6 -670,8 +674,6 @@@ action.set_text_colour = Text Colour.. label.structure = Structure label.show_pdbstruct_dialog = 3D Structure Data... label.view_rna_structure = VARNA 2D Structure -label.clustalx_colours = Clustalx colours -label.above_identity_percentage = Above % Identity label.create_sequence_details_report_annotation_for = Annotation for {0} label.sequence_details_for = Sequence Details for {0} label.sequence_name = Sequence Name @@@ -716,13 -716,14 +718,15 @@@ label.colour_with_chimera = Colour wit label.align_structures = Align Structures label.jmol = Jmol label.chimera = Chimera + label.create_chimera_attributes = Write Jalview features + label.create_chimera_attributes_tip = Set Chimera residue attributes for visible features label.sort_alignment_by_tree = Sort Alignment By Tree label.mark_unlinked_leaves = Mark Unlinked Leaves label.associate_leaves_with = Associate Leaves With label.save_colour_scheme_with_unique_name_added_to_colour_menu = Save your colour scheme with a unique name and it will be added to the Colour menu label.case_sensitive = Case Sensitive -label.lower_case_colour = Lower Case Colour +label.lower_case_colour = Colour All Lower Case +label.lower_case_tip = Chosen colour applies to all lower case symbols label.index_by_host = Index by Host label.index_by_type = Index by Type label.enable_jabaws_services = Enable JABAWS Services @@@ -771,7 -772,7 +775,7 @@@ label.original_data_for_params = Origin label.points_for_params = Points for {0} label.transformed_points_for_params = Transformed points for {0} label.graduated_color_for_params = Graduated Feature Colour for {0} -label.select_backgroud_colour = Select Background Colour +label.select_background_colour = Select Background Colour label.invalid_font = Invalid Font label.separate_multiple_accession_ids = Enter one or more accession IDs separated by a semi-colon ";" label.separate_multiple_query_values = Enter one or more {0}s separated by a semi-colon ";" @@@ -961,6 -962,7 +965,6 @@@ error.implementation_error_maplist_is_n error.implementation_error_cannot_have_null_alignment = Implementation error: Cannot have null alignment property key error.implementation_error_null_fileparse = Implementation error. Null FileParse in copy constructor error.implementation_error_cannot_map_alignment_sequences = IMPLEMENTATION ERROR: Cannot map an alignment of sequences from different datasets into a single alignment in the vamsas document. -error.implementation_error_cannot_duplicate_colour_scheme = Serious implementation error: cannot duplicate colourscheme {0} error.implementation_error_structure_selection_manager_null = Implementation error. Structure selection manager's context is 'null' exception.ssm_context_is_null = SSM context is null error.idstring_seqstrings_only_one_per_sequence = idstrings and seqstrings contain one string each per sequence @@@ -1025,6 -1027,7 +1029,6 @@@ exception.replace_null_regex_pointer = exception.bad_pattern_to_regex_perl_code = bad pattern to Regex.perlCode: {0} exception.no_stub_implementation_for_interface = There is no stub implementation for the interface: {0} exception.cannot_set_endpoint_address_unknown_port = Cannot set Endpoint Address for Unknown Port {0} -exception.querying_matching_opening_parenthesis_for_non_closing_parenthesis = Querying matching opening parenthesis for non-closing parenthesis character {0} exception.mismatched_unseen_closing_char = Mismatched (unseen) closing character {0} exception.mismatched_closing_char = Mismatched closing character {0} exception.mismatched_opening_char = Mismatched opening character {0} at {1} @@@ -1035,6 -1038,7 +1039,6 @@@ exception.couldnt_parse_responde_from_a exception.application_test_npe = Application test: throwing an NullPointerException It should arrive at the console exception.overwriting_vamsas_id_binding = Overwriting vamsas id binding exception.overwriting_jalview_id_binding = Overwriting jalview id binding -error.implementation_error_unknown_file_format_string = Implementation error: Unknown file format string exception.failed_to_resolve_gzip_stream = Failed to resolve GZIP stream exception.problem_opening_file_also_tried = Problem opening {0} (also tried {1}) : {2} exception.problem_opening_file = Problem opening {0} : {1} @@@ -1230,6 -1234,7 +1234,6 @@@ action.export_hidden_columns = Export H action.export_hidden_sequences = Export Hidden Sequences action.export_features = Export Features label.export_settings = Export Settings -label.save_as_biojs_html = Save as BioJs HTML label.pdb_web-service_error = PDB Web-service Error label.structure_chooser_manual_association = Structure Chooser - Manual association label.structure_chooser_filter_time = Structure Chooser - Filter time ({0}) @@@ -1271,21 -1276,4 +1275,21 @@@ label.SEQUENCE_ID_no_longer_used = $SEQ label.SEQUENCE_ID_for_DB_ACCESSION1 = Please review your URL links in the 'Connections' tab of the Preferences window: label.SEQUENCE_ID_for_DB_ACCESSION2 = URL links using '$SEQUENCE_ID$' for DB accessions now use '$DB_ACCESSION$'. label.do_not_display_again = Do not display this message again +exception.url_cannot_have_miriam_id = {0} is a MIRIAM id and cannot be used as a custom url name +exception.url_cannot_have_duplicate_id = {0} cannot be used as a label for more than one line +label.filter = Filter text: +action.customfilter = Custom only +action.showall = Show All +label.insert = Insert: +action.seq_id = $SEQUENCE_ID$ +action.db_acc = $DB_ACCESSION$ +label.primary = Double Click +label.inmenu = In Menu +label.id = ID +label.database = Database +label.urltooltip = Only one url, which must use a sequence id, can be selected for the 'On Click' option +label.edit_sequence_url_link = Edit sequence URL link +warn.name_cannot_be_duplicate = User-defined URL names must be unique and cannot be MIRIAM ids +label.invalid_name = Invalid Name ! label.output_seq_details = Output Sequence Details to list all database references - label.urllinks = Links ++label.urllinks = Links diff --combined src/MCview/PDBChain.java index c40cdda,3c0a1f2..ba93046 --- a/src/MCview/PDBChain.java +++ b/src/MCview/PDBChain.java @@@ -39,6 -39,8 +39,8 @@@ import java.util.Vector public class PDBChain { + public static final String RESNUM_FEATURE = "RESNUM"; + /** * SequenceFeature group for PDB File features added to sequences */ @@@ -367,7 -369,7 +369,7 @@@ Residue tmpres = residues.lastElement(); Atom tmpat = tmpres.atoms.get(0); // Make A new SequenceFeature for the current residue numbering - SequenceFeature sf = new SequenceFeature("RESNUM", tmpat.resName + SequenceFeature sf = new SequenceFeature(RESNUM_FEATURE, tmpat.resName + ":" + tmpat.resNumIns + " " + pdbid + id, "", offset + count, offset + count, pdbid); resFeatures.addElement(sf); @@@ -516,12 -518,10 +518,12 @@@ try { index = ResidueProperties.aa3Hash.get(b.at1.resName).intValue(); - b.startCol = cs.findColour(ResidueProperties.aa[index].charAt(0)); + b.startCol = cs.findColour(ResidueProperties.aa[index].charAt(0), + 0, null, null, 0f); index = ResidueProperties.aa3Hash.get(b.at2.resName).intValue(); - b.endCol = cs.findColour(ResidueProperties.aa[index].charAt(0)); + b.endCol = cs.findColour(ResidueProperties.aa[index].charAt(0), 0, + null, null, 0f); } catch (Exception e) { diff --combined src/jalview/analysis/AlignmentUtils.java index ea96b3b,fbec4be..232cb5d --- a/src/jalview/analysis/AlignmentUtils.java +++ b/src/jalview/analysis/AlignmentUtils.java @@@ -42,6 -42,7 +42,7 @@@ import jalview.util.Comparison import jalview.util.DBRefUtils; import jalview.util.MapList; import jalview.util.MappingUtils; + import jalview.util.RangeComparator; import jalview.util.StringUtils; import java.io.UnsupportedEncodingException; @@@ -60,7 -61,6 +61,7 @@@ import java.util.Map import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.Set; +import java.util.SortedMap; import java.util.TreeMap; /** @@@ -2265,14 -2265,7 +2266,7 @@@ public class AlignmentUtil * ranges are assembled in order. Other cases should not use this method, * but instead construct an explicit mapping for CDS (e.g. EMBL parsing). */ - Collections.sort(result, new Comparator() - { - @Override - public int compare(int[] o1, int[] o2) - { - return Integer.compare(o1[0], o2[0]); - } - }); + Collections.sort(result, new RangeComparator(true)); return result; } @@@ -2841,7 -2834,7 +2835,7 @@@ * @param unmapped * @return */ - static Map> buildMappedColumnsMap( + static SortedMap> buildMappedColumnsMap( AlignmentI unaligned, AlignmentI aligned, List unmapped) { /* @@@ -2849,7 -2842,7 +2843,7 @@@ * {unalignedSequence, characterPerSequence} at that position. * TreeMap keeps the entries in ascending column order. */ - Map> map = new TreeMap>(); + SortedMap> map = new TreeMap>(); /* * record any sequences that have no mapping so can't be realigned diff --combined src/jalview/api/AlignViewportI.java index 2802684,7067328..634521c --- a/src/jalview/api/AlignViewportI.java +++ b/src/jalview/api/AlignViewportI.java @@@ -31,7 -31,6 +31,7 @@@ import jalview.datamodel.SearchResultsI import jalview.datamodel.SequenceCollectionI; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; +import jalview.renderer.ResidueShaderI; import jalview.schemes.ColourSchemeI; import java.awt.Color; @@@ -80,14 -79,6 +80,14 @@@ public interface AlignViewportI extend ColourSchemeI getGlobalColourScheme(); + /** + * Returns an object that describes colouring (including any thresholding or + * fading) of the alignment + * + * @return + */ + ResidueShaderI getResidueShading(); + AlignmentI getAlignment(); ColumnSelection getColumnSelection(); @@@ -119,6 -110,13 +119,13 @@@ AlignmentAnnotation getAlignmentConsensusAnnotation(); /** + * get the container for alignment gap annotation + * + * @return + */ + AlignmentAnnotation getAlignmentGapAnnotation(); + + /** * get the container for cDNA complement consensus annotation * * @return @@@ -166,7 -164,7 +173,7 @@@ /** * - * @return the alignment annotatino row for the structure consensus + * @return the alignment annotation row for the structure consensus * calculation */ AlignmentAnnotation getAlignmentStrucConsensusAnnotation(); @@@ -179,13 -177,11 +186,13 @@@ void setRnaStructureConsensusHash(Hashtable[] hStrucConsensus); /** - * set global colourscheme + * Sets the colour scheme for the background alignment (as distinct from + * sub-groups, which may have their own colour schemes). A null value is used + * for no residue colour (white). * - * @param rhc + * @param cs */ - void setGlobalColourScheme(ColourSchemeI rhc); + void setGlobalColourScheme(ColourSchemeI cs); Map getHiddenRepSequences(); diff --combined src/jalview/ext/rbvi/chimera/ChimeraCommands.java index 8f6b2f1,07c0015..c4aa2e7 --- a/src/jalview/ext/rbvi/chimera/ChimeraCommands.java +++ b/src/jalview/ext/rbvi/chimera/ChimeraCommands.java @@@ -23,6 -23,7 +23,7 @@@ package jalview.ext.rbvi.chimera import jalview.api.FeatureRenderer; import jalview.api.SequenceRenderer; import jalview.datamodel.AlignmentI; + import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.structure.StructureMapping; import jalview.structure.StructureMappingcommandSet; @@@ -32,11 -33,10 +33,10 @@@ import jalview.util.Comparison import java.awt.Color; import java.util.ArrayList; + import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; - import java.util.SortedMap; - import java.util.TreeMap; /** * Routines for generating Chimera commands for Jalview/Chimera binding @@@ -47,28 -47,34 +47,34 @@@ public class ChimeraCommands { + public static final String NAMESPACE_PREFIX = "jv_"; + /** - * utility to construct the commands to colour chains by the given alignment - * for passing to Chimera - * - * @returns Object[] { Object[] { , + * Constructs Chimera commands to colour residues as per the Jalview alignment * + * @param ssm + * @param files + * @param sequence + * @param sr + * @param fr + * @param alignment + * @return */ - public static StructureMappingcommandSet getColourBySequenceCommand( + public static StructureMappingcommandSet[] getColourBySequenceCommand( StructureSelectionManager ssm, String[] files, SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr, AlignmentI alignment) { - Map>>> colourMap = buildColoursMap( - ssm, files, sequence, sr, fr, alignment); - Map colourMap = buildColoursMap( - ssm, files, sequence, sr, fr, alignment); ++ Map colourMap = buildColoursMap(ssm, files, ++ sequence, sr, fr, alignment); List colourCommands = buildColourCommands(colourMap); StructureMappingcommandSet cs = new StructureMappingcommandSet( ChimeraCommands.class, null, - colourCommands.toArray(new String[0])); + colourCommands.toArray(new String[colourCommands.size()])); - return cs; + return new StructureMappingcommandSet[] { cs }; } /** @@@ -76,18 -82,18 +82,18 @@@ * 'color' commands (one per distinct colour used). The format of each command * is * - *
color colorname #modelnumber:range.chain e.g. color #00ff00 - * #0:2.B,4.B,9-12.B|#1:1.A,2-6.A,... - * - * @see http - * ://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec - * .html + *
+    * 
+ * color colorname #modelnumber:range.chain + * e.g. color #00ff00 #0:2.B,4.B,9-12.B|#1:1.A,2-6.A,... + *
+ *
* * @param colourMap * @return */ protected static List buildColourCommands( - Map>>> colourMap) + Map colourMap) { /* * This version concatenates all commands into a single String (semi-colon @@@ -97,8 -103,9 +103,9 @@@ List commands = new ArrayList(); StringBuilder sb = new StringBuilder(256); boolean firstColour = true; - for (Color colour : colourMap.keySet()) + for (Object key : colourMap.keySet()) { + Color colour = (Color) key; String colourCode = ColorUtils.toTkCode(colour); if (!firstColour) { @@@ -106,48 -113,63 +113,62 @@@ } sb.append("color ").append(colourCode).append(" "); firstColour = false; - boolean firstModelForColour = true; - final Map>> colourData = colourMap - .get(colour); - for (Integer model : colourData.keySet()) - final AtomSpecModel colourData = colourMap - .get(colour); ++ final AtomSpecModel colourData = colourMap.get(colour); + sb.append(colourData.getAtomSpec()); + } + commands.add(sb.toString()); + return commands; + } + + /** + * Traverses a map of { modelNumber, {chain, {list of from-to ranges} } } and + * builds a Chimera format atom spec + * + * @param modelAndChainRanges + */ + protected static String getAtomSpec( + Map>> modelAndChainRanges) + { + StringBuilder sb = new StringBuilder(128); + boolean firstModelForColour = true; + for (Integer model : modelAndChainRanges.keySet()) + { + boolean firstPositionForModel = true; + if (!firstModelForColour) { - boolean firstPositionForModel = true; - if (!firstModelForColour) - { - sb.append("|"); - } - firstModelForColour = false; - sb.append("#").append(model).append(":"); + sb.append("|"); + } + firstModelForColour = false; + sb.append("#").append(model).append(":"); - final Map> modelData = colourData.get(model); - for (String chain : modelData.keySet()) + final Map> modelData = modelAndChainRanges + .get(model); + for (String chain : modelData.keySet()) + { + boolean hasChain = !"".equals(chain.trim()); + for (int[] range : modelData.get(chain)) { - boolean hasChain = !"".equals(chain.trim()); - for (int[] range : modelData.get(chain)) + if (!firstPositionForModel) { - if (!firstPositionForModel) - { - sb.append(","); - } - if (range[0] == range[1]) - { - sb.append(range[0]); - } - else - { - sb.append(range[0]).append("-").append(range[1]); - } - if (hasChain) - { - sb.append(".").append(chain); - } - firstPositionForModel = false; + sb.append(","); + } + if (range[0] == range[1]) + { + sb.append(range[0]); + } + else + { + sb.append(range[0]).append("-").append(range[1]); + } + if (hasChain) + { + sb.append(".").append(chain); } + firstPositionForModel = false; } } } - commands.add(sb.toString()); - return commands; + return sb.toString(); } /** @@@ -162,12 -184,12 +183,12 @@@ * Ordering is by order of addition (for colours and positions), natural ordering (for models and chains) * */ - protected static Map>>> buildColoursMap( + protected static Map buildColoursMap( StructureSelectionManager ssm, String[] files, SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr, AlignmentI alignment) { - Map>>> colourMap = new LinkedHashMap>>>(); + Map colourMap = new LinkedHashMap(); Color lastColour = null; for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++) { @@@ -218,7 -240,7 +239,7 @@@ { if (startPos != -1) { - addRange(colourMap, lastColour, pdbfnum, startPos, + addColourRange(colourMap, lastColour, pdbfnum, startPos, lastPos, lastChain); } startPos = pos; @@@ -230,8 -252,8 +251,8 @@@ // final colour range if (lastColour != null) { - addColourRange(colourMap, lastColour, pdbfnum, startPos, - lastPos, lastChain); - addRange(colourMap, lastColour, pdbfnum, startPos, - lastPos, lastChain); ++ addColourRange(colourMap, lastColour, pdbfnum, startPos, lastPos, ++ lastChain); } // break; } @@@ -244,51 -266,258 +265,258 @@@ /** * Helper method to add one contiguous colour range to the colour map. * - * @param colourMap - * @param colour + * @param map + * @param key * @param model * @param startPos * @param endPos * @param chain */ - protected static void addColourRange( - Map>>> colourMap, - Color colour, int model, int startPos, int endPos, String chain) - protected static void addRange(Map map, ++ protected static void addColourRange(Map map, + Object key, int model, int startPos, int endPos, String chain) { /* * Get/initialize map of data for the colour */ - SortedMap>> colourData = colourMap - .get(colour); - if (colourData == null) + AtomSpecModel atomSpec = map.get(key); + if (atomSpec == null) { - colourMap - .put(colour, - colourData = new TreeMap>>()); + atomSpec = new AtomSpecModel(); + map.put(key, atomSpec); } - /* - * Get/initialize map of data for the colour and model - */ - Map> modelData = colourData.get(model); - if (modelData == null) + atomSpec.addRange(model, startPos, endPos, chain); + } + + /** + * Constructs and returns Chimera commands to set attributes on residues + * corresponding to features in Jalview. Attribute names are the Jalview + * feature type, with a "jv_" prefix. + * + * @param ssm + * @param files + * @param seqs + * @param fr + * @param alignment + * @return + */ + public static StructureMappingcommandSet getSetAttributeCommandsForFeatures( + StructureSelectionManager ssm, String[] files, + SequenceI[][] seqs, FeatureRenderer fr, AlignmentI alignment) + { + Map> featureMap = buildFeaturesMap( + ssm, files, seqs, fr, alignment); + + List commands = buildSetAttributeCommands(featureMap); + + StructureMappingcommandSet cs = new StructureMappingcommandSet( + ChimeraCommands.class, null, + commands.toArray(new String[commands.size()])); + + return cs; + } + + /** + *
+    * Helper method to build a map of 
+    *   { featureType, { feature value, AtomSpecModel } }
+    * 
+ * + * @param ssm + * @param files + * @param seqs + * @param fr + * @param alignment + * @return + */ + protected static Map> buildFeaturesMap( + StructureSelectionManager ssm, String[] files, + SequenceI[][] seqs, FeatureRenderer fr, AlignmentI alignment) + { + Map> theMap = new LinkedHashMap>(); + + List visibleFeatures = fr.getDisplayedFeatureTypes(); + if (visibleFeatures.isEmpty()) { - colourData.put(model, modelData = new TreeMap>()); + return theMap; } - + - /* - * Get/initialize map of data for colour, model and chain - */ - List chainData = modelData.get(chain); - if (chainData == null) + for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++) + { + StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]); + + if (mapping == null || mapping.length < 1) + { + continue; + } + + for (int seqNo = 0; seqNo < seqs[pdbfnum].length; seqNo++) + { + for (int m = 0; m < mapping.length; m++) + { + final SequenceI seq = seqs[pdbfnum][seqNo]; + int sp = alignment.findIndex(seq); + if (mapping[m].getSequence() == seq && sp > -1) + { + /* + * found a sequence with a mapping to a structure; + * now scan its features + */ + SequenceI asp = alignment.getSequenceAt(sp); + + scanSequenceFeatures(visibleFeatures, mapping[m], asp, theMap, + pdbfnum); + } + } + } + } + return theMap; + } + + /** + * Inspect features on the sequence; for each feature that is visible, + * determine its mapped ranges in the structure (if any) according to the + * given mapping, and add them to the map + * + * @param visibleFeatures + * @param mapping + * @param seq + * @param theMap + * @param modelNumber + */ + protected static void scanSequenceFeatures(List visibleFeatures, + StructureMapping mapping, SequenceI seq, + Map> theMap, int modelNumber) + { + SequenceFeature[] sfs = seq.getSequenceFeatures(); + if (sfs == null) + { + return; + } + + for (SequenceFeature sf : sfs) + { + String type = sf.getType(); + + /* + * Only copy visible features, don't copy any which originated + * from Chimera, and suppress uninteresting ones (e.g. RESNUM) + */ + boolean isFromViewer = JalviewChimeraBinding.CHIMERA_FEATURE_GROUP + .equals(sf.getFeatureGroup()); + if (isFromViewer || !visibleFeatures.contains(type)) + { + continue; + } + List mappedRanges = mapping.getPDBResNumRanges(sf.getBegin(), + sf.getEnd()); + + if (!mappedRanges.isEmpty()) + { + String value = sf.getDescription(); + if (value == null || value.length() == 0) + { + value = type; + } + float score = sf.getScore(); + if (score != 0f && !Float.isNaN(score)) + { + value = Float.toString(score); + } + Map featureValues = theMap.get(type); + if (featureValues == null) + { + featureValues = new HashMap(); + theMap.put(type, featureValues); + } + for (int[] range : mappedRanges) + { - addRange(featureValues, value, modelNumber, range[0], range[1], ++ addColourRange(featureValues, value, modelNumber, range[0], range[1], + mapping.getChain()); + } + } + } + } + + /** + * Traverse the map of features/values/models/chains/positions to construct a + * list of 'setattr' commands (one per distinct feature type and value). + *

+ * The format of each command is + * + *

+    * 
setattr r " " #modelnumber:range.chain + * e.g. setattr r jv:chain #0:2.B,4.B,9-12.B|#1:1.A,2-6.A,... + *
+ *
+ * + * @param featureMap + * @return + */ + protected static List buildSetAttributeCommands( + Map> featureMap) + { + List commands = new ArrayList(); + for (String featureType : featureMap.keySet()) { - modelData.put(chain, chainData = new ArrayList()); + String attributeName = makeAttributeName(featureType); + + /* + * clear down existing attributes for this feature + */ + // 'problem' - sets attribute to None on all residues - overkill? + // commands.add("~setattr r " + attributeName + " :*"); + + Map values = featureMap.get(featureType); + for (Object value : values.keySet()) + { + /* + * for each distinct value recorded for this feature type, + * add a command to set the attribute on the mapped residues + */ + StringBuilder sb = new StringBuilder(128); + sb.append("setattr r ").append(attributeName).append(" \"") + .append(value.toString()).append("\" "); + sb.append(values.get(value).getAtomSpec()); + commands.add(sb.toString()); + } } + return commands; + } + + /** + * Makes a prefixed and valid Chimera attribute name. A jv_ prefix is applied + * for a 'Jalview' namespace, and any non-alphanumeric character is converted + * to an underscore. + * + * @param featureType + * @return
+    * @see https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/setattr.html
+    * 
+ */ + protected static String makeAttributeName(String featureType) + { + StringBuilder sb = new StringBuilder(); + if (featureType != null) + { + for (char c : featureType.toCharArray()) + { + sb.append(Character.isLetterOrDigit(c) ? c : '_'); + } + } + String attName = NAMESPACE_PREFIX + sb.toString(); + /* - * Add the start/end positions + * Chimera treats an attribute name ending in 'color' as colour-valued; + * Jalview doesn't, so prevent this by appending an underscore */ - chainData.add(new int[] { startPos, endPos }); + if (attName.toUpperCase().endsWith("COLOR")) + { + attName += "_"; + } + + return attName; } } diff --combined src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java index b05c168,75ddc9c..2042ac4 --- a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java +++ b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java @@@ -28,6 -28,9 +28,9 @@@ import jalview.bin.Cache import jalview.datamodel.AlignmentI; import jalview.datamodel.ColumnSelection; import jalview.datamodel.PDBEntry; + import jalview.datamodel.SearchResultMatchI; + import jalview.datamodel.SearchResults; + import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.httpserver.AbstractRequestHandler; import jalview.io.DataSourceType; @@@ -40,8 -43,13 +43,13 @@@ import jalview.structures.models.AAStru import jalview.util.MessageManager; import java.awt.Color; + import java.io.File; + import java.io.FileOutputStream; + import java.io.IOException; + import java.io.PrintWriter; import java.net.BindException; import java.util.ArrayList; + import java.util.Collections; import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.List; @@@ -54,6 -62,8 +62,8 @@@ import ext.edu.ucsf.rbvi.strucviz2.Stru public abstract class JalviewChimeraBinding extends AAStructureBindingModel { + public static final String CHIMERA_FEATURE_GROUP = "Chimera"; + // Chimera clause to exclude alternate locations in atom selection private static final String NO_ALTLOCS = "&~@.B-Z&~@.2-9"; @@@ -93,19 -103,13 +103,11 @@@ */ private boolean loadingFinished = true; - public String fileLoadingError; - /* * Map of ChimeraModel objects keyed by PDB full local file name */ private Map> chimeraMaps = new LinkedHashMap>(); - /* - * the default or current model displayed if the model cannot be identified - * from the selection message - */ - private int frameNo = 0; - - private String lastCommand; - String lastHighlightCommand; /* @@@ -252,6 -256,18 +254,6 @@@ } /** - * Construct a title string for the viewer window based on the data Jalview - * knows about - * - * @param verbose - * @return - */ - public String getViewerTitle(boolean verbose) - { - return getViewerTitle("Chimera", verbose); - } - - /** * Tells Chimera to display only the specified chains * * @param toshow @@@ -304,7 -320,6 +306,6 @@@ chimeraListener.shutdown(); chimeraListener = null; } - lastCommand = null; viewer = null; if (chimeraMonitor != null) @@@ -314,7 -329,6 +315,7 @@@ releaseUIResources(); } + @Override public void colourByChain() { colourBySequence = false; @@@ -330,7 -344,6 +331,7 @@@ *
  • all others - white
  • * */ + @Override public void colourByCharge() { colourBySequence = false; @@@ -352,7 -365,6 +353,7 @@@ * @param _hiddenCols * an array of corresponding hidden columns for each alignment */ + @Override public void superposeStructures(AlignmentI[] _alignment, int[] _refStructure, ColumnSelection[] _hiddenCols) { @@@ -631,31 -643,42 +632,42 @@@ } /** - * Send a command to Chimera, and optionally log any responses. + * Send a command to Chimera, and optionally log and return any responses. + *

    + * Does nothing, and returns null, if the command is the same as the last one + * sent [why?]. * * @param command - * @param logResponse + * @param getResponse */ - public void sendChimeraCommand(final String command, boolean logResponse) + public List sendChimeraCommand(final String command, + boolean getResponse) { if (viewer == null) { // ? thread running after viewer shut down - return; + return null; } + List reply = null; viewerCommandHistory(false); - if (lastCommand == null || !lastCommand.equals(command)) + if (true /*lastCommand == null || !lastCommand.equals(command)*/) { // trim command or it may never find a match in the replyLog!! List lastReply = viewer.sendChimeraCommand(command.trim(), - logResponse); - if (logResponse && debug) + getResponse); + if (getResponse) { - log("Response from command ('" + command + "') was:\n" + lastReply); + reply = lastReply; + if (debug) + { + log("Response from command ('" + command + "') was:\n" + + lastReply); + } } } viewerCommandHistory(true); - lastCommand = command; + + return reply; } /** @@@ -669,37 -692,39 +681,37 @@@ String progressMsg); /** - * colour any structures associated with sequences in the given alignment - * using the getFeatureRenderer() and getSequenceRenderer() renderers but only - * if colourBySequence is enabled. + * Sends a set of colour commands to the structure viewer + * + * @param colourBySequenceCommands */ - public void colourBySequence(boolean showFeatures, - jalview.api.AlignmentViewPanel alignmentv) + @Override + protected void colourBySequence( + StructureMappingcommandSet[] colourBySequenceCommands) { - if (!colourBySequence || !loadingFinished) + for (StructureMappingcommandSet cpdbbyseq : colourBySequenceCommands) { - return; - } - if (getSsm() == null) - { - return; - } - String[] files = getPdbFile(); - - SequenceRenderer sr = getSequenceRenderer(alignmentv); - - FeatureRenderer fr = null; - if (showFeatures) - { - fr = getFeatureRenderer(alignmentv); + for (String command : cpdbbyseq.commands) + { + sendAsynchronousCommand(command, COLOURING_CHIMERA); + } } - AlignmentI alignment = alignmentv.getAlignment(); + } - StructureMappingcommandSet colourBySequenceCommands = ChimeraCommands - .getColourBySequenceCommand(getSsm(), files, getSequence(), sr, - fr, alignment); - for (String command : colourBySequenceCommands.commands) - { - sendAsynchronousCommand(command, COLOURING_CHIMERA); - } + /** + * @param files + * @param sr + * @param fr + * @param alignment + * @return + */ + @Override + protected StructureMappingcommandSet[] getColourBySequenceCommands( + String[] files, SequenceRenderer sr, FeatureRenderer fr, + AlignmentI alignment) + { + return ChimeraCommands.getColourBySequenceCommand(getSsm(), files, + getSequence(), sr, fr, alignment); } /** @@@ -729,19 -754,23 +741,20 @@@ // ////////////////////////// /** - * returns the current featureRenderer that should be used to colour the - * structures - * - * @param alignment - * - * @return - */ - public abstract FeatureRenderer getFeatureRenderer( - AlignmentViewPanel alignment); - - /** * instruct the Jalview binding to update the pdbentries vector if necessary * prior to matching the viewer's contents to the list of structure files * Jalview knows about. */ public abstract void refreshPdbEntries(); + /** + * map between index of model filename returned from getPdbFile and the first + * index of models from this file in the viewer. Note - this is not trimmed - + * use getPdbFile to get number of unique models. + */ + private int _modelFileNameMap[]; + ++ // //////////////////////////////// // /StructureListener @Override @@@ -757,6 -786,17 +770,6 @@@ } /** - * returns the current sequenceRenderer that should be used to colour the - * structures - * - * @param alignment - * - * @return - */ - public abstract SequenceRenderer getSequenceRenderer( - AlignmentViewPanel alignment); - - /** * Construct and send a command to highlight zero, one or more atoms. We do * this by sending an "rlabel" command to show the residue label at that * position. @@@ -837,59 -877,64 +850,64 @@@ * Parse model number, residue and chain for each selected position, * formatted as #0:123.A or #1.2:87.B (#model.submodel:residue.chain) */ + List atomSpecs = convertStructureResiduesToAlignment(selection); + + /* + * Broadcast the selection (which may be empty, if the user just cleared all + * selections) + */ + getSsm().mouseOverStructure(atomSpecs); + } + + /** + * Converts a list of Chimera atomspecs to a list of AtomSpec representing the + * corresponding residues (if any) in Jalview + * + * @param structureSelection + * @return + */ + protected List convertStructureResiduesToAlignment( + List structureSelection) + { List atomSpecs = new ArrayList(); - for (String atomSpec : selection) + for (String atomSpec : structureSelection) { - int colonPos = atomSpec.indexOf(":"); - if (colonPos == -1) - { - continue; // malformed - } - - int hashPos = atomSpec.indexOf("#"); - String modelSubmodel = atomSpec.substring(hashPos + 1, colonPos); - int dotPos = modelSubmodel.indexOf("."); - int modelId = 0; try { - modelId = Integer.valueOf(dotPos == -1 ? modelSubmodel - : modelSubmodel.substring(0, dotPos)); - } catch (NumberFormatException e) + AtomSpec spec = AtomSpec.fromChimeraAtomspec(atomSpec); + String pdbfilename = getPdbFileForModel(spec.getModelNumber()); + spec.setPdbFile(pdbfilename); + atomSpecs.add(spec); + } catch (IllegalArgumentException e) { - // ignore, default to model 0 + System.err.println("Failed to parse atomspec: " + atomSpec); } + } + return atomSpecs; + } - String residueChain = atomSpec.substring(colonPos + 1); - dotPos = residueChain.indexOf("."); - int pdbResNum = Integer.parseInt(dotPos == -1 ? residueChain - : residueChain.substring(0, dotPos)); - - String chainId = dotPos == -1 ? "" : residueChain - .substring(dotPos + 1); - - /* - * Work out the pdbfilename from the model number - */ - String pdbfilename = modelFileNames[frameNo]; - findfileloop: for (String pdbfile : this.chimeraMaps.keySet()) + /** + * @param modelId + * @return + */ + protected String getPdbFileForModel(int modelId) + { + /* + * Work out the pdbfilename from the model number + */ + String pdbfilename = modelFileNames[0]; + findfileloop: for (String pdbfile : this.chimeraMaps.keySet()) + { + for (ChimeraModel cm : chimeraMaps.get(pdbfile)) { - for (ChimeraModel cm : chimeraMaps.get(pdbfile)) + if (cm.getModelNumber() == modelId) { - if (cm.getModelNumber() == modelId) - { - pdbfilename = pdbfile; - break findfileloop; - } + pdbfilename = pdbfile; + break findfileloop; } } - atomSpecs.add(new AtomSpec(pdbfilename, chainId, pdbResNum, 0)); } - - /* - * Broadcast the selection (which may be empty, if the user just cleared all - * selections) - */ - getSsm().mouseOverStructure(atomSpecs); + return pdbfilename; } private void log(String message) @@@ -908,7 -953,6 +926,7 @@@ return loadNotifiesHandled; } + @Override public void setJalviewColourScheme(ColourSchemeI cs) { colourBySequence = false; @@@ -925,14 -969,12 +943,14 @@@ List residueSet = ResidueProperties.getResidues(isNucleotide(), false); - for (String res : residueSet) + for (String resName : residueSet) { - Color col = cs.findColour(res.charAt(0)); + char res = resName.length() == 3 ? ResidueProperties + .getSingleCharacterCode(resName) : resName.charAt(0); + Color col = cs.findColour(res, 0, null, null, 0f); command.append("color " + col.getRed() / normalise + "," + col.getGreen() / normalise + "," + col.getBlue() - / normalise + " ::" + res + ";"); + / normalise + " ::" + resName + ";"); } sendAsynchronousCommand(command.toString(), COLOURING_CHIMERA); @@@ -983,7 -1025,6 +1001,7 @@@ * .html * @param col */ + @Override public void setBackgroundColour(Color col) { viewerCommandHistory(false); @@@ -1036,6 -1077,18 +1054,18 @@@ } /** + * Returns a list of chains mapped in this viewer. Note this list is not + * currently scoped per structure. + * + * @return + */ + @Override + public List getChainNames() + { + return chainNames; + } + + /** * Send a 'focus' command to Chimera to recentre the visible display */ public void focusView() @@@ -1071,13 -1124,214 +1101,214 @@@ } } + /** + * Constructs and send commands to Chimera to set attributes on residues for + * features visible in Jalview + * + * @param avp + */ + public void sendFeaturesToViewer(AlignmentViewPanel avp) + { + // TODO refactor as required to pull up to an interface + AlignmentI alignment = avp.getAlignment(); + FeatureRenderer fr = getFeatureRenderer(avp); - @Override - public List getChainNames() + /* + * fr is null if feature display is turned off + */ + if (fr == null) + { + return; + } + + String[] files = getPdbFile(); + if (files == null) + { + return; + } + + StructureMappingcommandSet commandSet = ChimeraCommands + .getSetAttributeCommandsForFeatures(getSsm(), files, + getSequence(), fr, alignment); + String[] commands = commandSet.commands; + if (commands.length > 10) + { + sendCommandsByFile(commands); + } + else + { + for (String command : commands) + { + sendAsynchronousCommand(command, null); + } + } + } + + /** + * Write commands to a temporary file, and send a command to Chimera to open + * the file as a commands script. For use when sending a large number of + * separate commands would overload the REST interface mechanism. + * + * @param commands + */ + protected void sendCommandsByFile(String[] commands) { - return chainNames; + try + { + File tmp = File.createTempFile("chim", ".com"); + tmp.deleteOnExit(); + PrintWriter out = new PrintWriter(new FileOutputStream(tmp)); + for (String command : commands) + { + out.println(command); + } + out.flush(); + out.close(); + String path = tmp.getAbsolutePath(); + sendAsynchronousCommand("open cmd:" + path, null); + } catch (IOException e) + { + System.err + .println("Sending commands to Chimera via file failed with " + + e.getMessage()); + } } + /** + * Get Chimera residues which have the named attribute, find the mapped + * positions in the Jalview sequence(s), and set as sequence features + * + * @param attName + * @param alignmentPanel + */ + public void copyStructureAttributesToFeatures(String attName, + AlignmentViewPanel alignmentPanel) + { + // todo pull up to AAStructureBindingModel (and interface?) + + /* + * ask Chimera to list residues with the attribute, reporting its value + */ + // this alternative command + // list residues spec ':*/attName' attr attName + // doesn't report 'None' values (which is good), but + // fails for 'average.bfactor' (which is bad): + + String cmd = "list residues attr '" + attName + "'"; + List residues = sendChimeraCommand(cmd, true); + + boolean featureAdded = createFeaturesForAttributes(attName, residues); + if (featureAdded) + { + alignmentPanel.getFeatureRenderer().featuresAdded(); + } + } + + /** + * Create features in Jalview for the given attribute name and structure + * residues. + * + *

    +    * The residue list should be 0, 1 or more reply lines of the format: 
    +    *     residue id #0:5.A isHelix -155.000836316 index 5 
    +    * or 
    +    *     residue id #0:6.A isHelix None
    +    * 
    + * + * @param attName + * @param residues + * @return + */ + protected boolean createFeaturesForAttributes(String attName, + List residues) + { + boolean featureAdded = false; + String featureGroup = getViewerFeatureGroup(); + + for (String residue : residues) + { + AtomSpec spec = null; + String[] tokens = residue.split(" "); + if (tokens.length < 5) + { + continue; + } + String atomSpec = tokens[2]; + String attValue = tokens[4]; + + /* + * ignore 'None' (e.g. for phi) or 'False' (e.g. for isHelix) + */ + if ("None".equalsIgnoreCase(attValue) + || "False".equalsIgnoreCase(attValue)) + { + continue; + } + + try + { + spec = AtomSpec.fromChimeraAtomspec(atomSpec); + } catch (IllegalArgumentException e) + { + System.err.println("Problem parsing atomspec " + atomSpec); + continue; + } + + String chainId = spec.getChain(); + String description = attValue; + float score = Float.NaN; + try + { + score = Float.valueOf(attValue); + description = chainId; + } catch (NumberFormatException e) + { + // was not a float value + } + + String pdbFile = getPdbFileForModel(spec.getModelNumber()); + spec.setPdbFile(pdbFile); + + List atoms = Collections.singletonList(spec); + + /* + * locate the mapped position in the alignment (if any) + */ + SearchResults sr = getSsm() + .findAlignmentPositionsForStructurePositions(atoms); + + /* + * expect one matched alignment position, or none + * (if the structure position is not mapped) + */ + for (SearchResultMatchI m : sr.getResults()) + { + SequenceI seq = m.getSequence(); + int start = m.getStart(); + int end = m.getEnd(); + SequenceFeature sf = new SequenceFeature(attName, description, + start, end, score, featureGroup); + // todo: should SequenceFeature have an explicit property for chain? + // note: repeating the action shouldn't duplicate features + featureAdded |= seq.addSequenceFeature(sf); + } + } + return featureAdded; + } + + /** + * Answers the feature group name to apply to features created in Jalview from + * Chimera attributes + * + * @return + */ + protected String getViewerFeatureGroup() + { + // todo pull up to interface + return CHIMERA_FEATURE_GROUP; + } + + public Hashtable getChainFile() { return chainFile; diff --combined src/jalview/gui/AnnotationRowFilter.java index 166e1ad,1b036c1..7705bc3 --- a/src/jalview/gui/AnnotationRowFilter.java +++ b/src/jalview/gui/AnnotationRowFilter.java @@@ -26,6 -26,8 +26,8 @@@ import jalview.datamodel.SequenceGroup import jalview.schemes.AnnotationColourGradient; import jalview.util.MessageManager; + import java.awt.event.FocusAdapter; + import java.awt.event.FocusEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Vector; @@@ -134,6 -136,14 +136,14 @@@ public abstract class AnnotationRowFilt { this.av = av; this.ap = ap; + thresholdValue.addFocusListener(new FocusAdapter() + { + @Override + public void focusLost(FocusEvent e) + { + thresholdValue_actionPerformed(); + } + }); } public AnnotationRowFilter() @@@ -366,20 -376,23 +376,20 @@@ continue; } + AnnotationColourGradient scheme = null; if (currentColours.isSelected()) { - sg.cs = new AnnotationColourGradient(currentAnn, sg.cs, - selectedThresholdOption); - ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated - .isSelected()); - + scheme = new AnnotationColourGradient(currentAnn, + sg.getColourScheme(), selectedThresholdOption); } else { - sg.cs = new AnnotationColourGradient(currentAnn, + scheme = new AnnotationColourGradient(currentAnn, minColour.getBackground(), maxColour.getBackground(), selectedThresholdOption); - ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated - .isSelected()); } - + scheme.setSeqAssociated(seqAssociated.isSelected()); + sg.setColourScheme(scheme); } } return false; diff --combined src/jalview/gui/ChimeraViewFrame.java index 530f4fe,4c38898..9b0d85b --- a/src/jalview/gui/ChimeraViewFrame.java +++ b/src/jalview/gui/ChimeraViewFrame.java @@@ -21,32 -21,62 +21,39 @@@ package jalview.gui; import jalview.bin.Cache; -import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; -import jalview.datamodel.ColumnSelection; import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; + import jalview.ext.rbvi.chimera.ChimeraCommands; import jalview.ext.rbvi.chimera.JalviewChimeraBinding; import jalview.gui.StructureViewer.ViewerType; import jalview.io.DataSourceType; -import jalview.io.JalviewFileChooser; -import jalview.io.JalviewFileView; import jalview.io.StructureFile; -import jalview.schemes.BuriedColourScheme; -import jalview.schemes.ColourSchemeI; -import jalview.schemes.HelixColourScheme; -import jalview.schemes.HydrophobicColourScheme; -import jalview.schemes.PurinePyrimidineColourScheme; -import jalview.schemes.StrandColourScheme; -import jalview.schemes.TaylorColourScheme; -import jalview.schemes.TurnColourScheme; -import jalview.schemes.ZappoColourScheme; import jalview.structures.models.AAStructureBindingModel; +import jalview.util.BrowserLauncher; import jalview.util.MessageManager; import jalview.util.Platform; import jalview.ws.dbsources.Pdb; import java.awt.event.ActionEvent; + import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; + import java.awt.event.MouseAdapter; + import java.awt.event.MouseEvent; -import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.FileReader; import java.io.IOException; import java.io.InputStream; -import java.io.PrintWriter; import java.util.ArrayList; + import java.util.Collections; import java.util.List; import java.util.Random; -import java.util.Vector; import javax.swing.JCheckBoxMenuItem; -import javax.swing.JColorChooser; import javax.swing.JInternalFrame; + import javax.swing.JMenu; + import javax.swing.JMenuItem; -import javax.swing.JOptionPane; import javax.swing.event.InternalFrameAdapter; import javax.swing.event.InternalFrameEvent; -import javax.swing.event.MenuEvent; -import javax.swing.event.MenuListener; /** * GUI elements for handling an external chimera display @@@ -58,8 -88,8 +65,6 @@@ public class ChimeraViewFrame extends S { private JalviewChimeraBinding jmb; -- private boolean allChainsSelected = false; -- private IProgressIndicator progressBar = null; /* @@@ -74,21 -104,179 +79,113 @@@ /** * Initialise menu options. */ - private void initMenus() + @Override + protected void initMenus() { + super.initMenus(); + viewerActionMenu.setText(MessageManager.getString("label.chimera")); + viewerColour.setText(MessageManager .getString("label.colour_with_chimera")); viewerColour.setToolTipText(MessageManager .getString("label.let_chimera_manage_structure_colours")); - helpItem.setText(MessageManager.getString("label.chimera_help")); - seqColour.setSelected(jmb.isColourBySequence()); - viewerColour.setSelected(!jmb.isColourBySequence()); - if (_colourwith == null) - { - _colourwith = new Vector(); - } - if (_alignwith == null) - { - _alignwith = new Vector(); - } - - // save As not yet implemented - savemenu.setVisible(false); - ViewSelectionMenu seqColourBy = new ViewSelectionMenu( - MessageManager.getString("label.colour_by"), this, _colourwith, - new ItemListener() - { - @Override - public void itemStateChanged(ItemEvent e) - { - if (!seqColour.isSelected()) - { - seqColour.doClick(); - } - else - { - // update the Chimera display now. - seqColour_actionPerformed(null); - } - } - }); - viewMenu.add(seqColourBy); + helpItem.setText(MessageManager.getString("label.chimera_help")); + savemenu.setVisible(false); // not yet implemented viewMenu.add(fitToWindow); + - final ItemListener handler; - JMenu alpanels = new ViewSelectionMenu( - MessageManager.getString("label.superpose_with"), this, - _alignwith, handler = new ItemListener() - { - @Override - public void itemStateChanged(ItemEvent e) - { - alignStructs.setEnabled(_alignwith.size() > 0); - alignStructs.setToolTipText(MessageManager - .formatMessage( - "label.align_structures_using_linked_alignment_views", - new Object[] { new Integer(_alignwith - .size()).toString() })); - } - }); - handler.itemStateChanged(null); - viewerActionMenu.add(alpanels); - viewerActionMenu.addMenuListener(new MenuListener() - { - - @Override - public void menuSelected(MenuEvent e) - { - handler.itemStateChanged(null); - } - - @Override - public void menuDeselected(MenuEvent e) - { - // TODO Auto-generated method stub - } - - @Override - public void menuCanceled(MenuEvent e) - { - // TODO Auto-generated method stub - } - }); - + JMenuItem writeFeatures = new JMenuItem( + MessageManager.getString("label.create_chimera_attributes")); + writeFeatures.setToolTipText(MessageManager + .getString("label.create_chimera_attributes_tip")); + writeFeatures.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + sendFeaturesToChimera(); + } + }); + viewerActionMenu.add(writeFeatures); + - final JMenu fetchAttributes = new JMenu("Fetch Chimera attributes"); - fetchAttributes - .setToolTipText("Copy Chimera attribute to Jalview feature"); ++ final JMenu fetchAttributes = new JMenu( ++ MessageManager.getString("label.fetch_chimera_attributes")); ++ fetchAttributes.setToolTipText(MessageManager ++ .getString("label.fetch_chimera_attributes_tip")); + fetchAttributes.addMouseListener(new MouseAdapter() + { + + @Override + public void mouseEntered(MouseEvent e) + { + buildAttributesMenu(fetchAttributes); + } + }); + viewerActionMenu.add(fetchAttributes); + + } + + /** + * Query Chimera for its residue attribute names and add them as items off the + * attributes menu + * + * @param attributesMenu + */ + protected void buildAttributesMenu(JMenu attributesMenu) + { + List atts = jmb.sendChimeraCommand("list resattr", true); + if (atts == null) + { + return; + } + attributesMenu.removeAll(); + Collections.sort(atts); + for (String att : atts) + { + final String attName = att.split(" ")[1]; + + /* + * ignore 'jv_*' attributes, as these are Jalview features that have + * been transferred to residue attributes in Chimera! + */ + if (!attName.startsWith(ChimeraCommands.NAMESPACE_PREFIX)) + { + JMenuItem menuItem = new JMenuItem(attName); + menuItem.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + getChimeraAttributes(attName); + } + }); + attributesMenu.add(menuItem); + } + } + } + + /** + * Read residues in Chimera with the given attribute name, and set as features + * on the corresponding sequence positions (if any) + * + * @param attName + */ + protected void getChimeraAttributes(String attName) + { + jmb.copyStructureAttributesToFeatures(attName, getAlignmentPanel()); + } + + /** + * Send a command to Chimera to create residue attributes for Jalview features + *

    + * The syntax is: setattr r + *

    + * For example: setattr r jv:chain "Ferredoxin-1, Chloroplastic" #0:94.A + */ + protected void sendFeaturesToChimera() + { + jmb.sendFeaturesToViewer(getAlignmentPanel()); } /** @@@ -142,16 -330,23 +239,15 @@@ } } - /** - * Answers true if this viewer already involves the given PDB ID - */ - @Override - protected boolean hasPdbId(String pdbId) - { - return jmb.hasPdbId(pdbId); - } - private void openNewChimera(AlignmentPanel ap, PDBEntry[] pdbentrys, SequenceI[][] seqs) { createProgressBar(); - // FIXME extractChains needs pdbentries to match IDs to PDBEntry(s) on seqs jmb = new JalviewChimeraBindingModel(this, ap.getStructureSelectionManager(), pdbentrys, seqs, null); addAlignmentPanel(ap); useAlignmentPanelForColourbyseq(ap); + if (pdbentrys.length > 1) { alignAddedStructures = true; @@@ -269,10 -464,8 +365,10 @@@ */ void initChimera() { - Desktop.addInternalFrame(this, jmb.getViewerTitle("Chimera", true), - getBounds().width, getBounds().height); + jmb.setFinishedInit(false); - jalview.gui.Desktop.addInternalFrame(this, ++ Desktop.addInternalFrame(this, + jmb.getViewerTitle(getViewerName(), true), getBounds().width, + getBounds().height); if (!jmb.launchChimera()) { @@@ -294,13 -487,66 +390,11 @@@ + chimeraSessionFile); } } - jmb.setFinishedInit(true); jmb.startChimeraListener(); } - /** - * If the list is not empty, add menu items for 'All' and each individual - * chain to the "View | Show Chain" sub-menu. Multiple selections are allowed. - * - * @param chainNames - */ - @Override - void setChainMenuItems(List chainNames) - { - chainMenu.removeAll(); - if (chainNames == null || chainNames.isEmpty()) - { - return; - } - JMenuItem menuItem = new JMenuItem( - MessageManager.getString("label.all")); - menuItem.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent evt) - { - allChainsSelected = true; - for (int i = 0; i < chainMenu.getItemCount(); i++) - { - if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem) - { - ((JCheckBoxMenuItem) chainMenu.getItem(i)).setSelected(true); - } - } - showSelectedChains(); - allChainsSelected = false; - } - }); - - chainMenu.add(menuItem); - - for (String chainName : chainNames) - { - menuItem = new JCheckBoxMenuItem(chainName, true); - menuItem.addItemListener(new ItemListener() - { - @Override - public void itemStateChanged(ItemEvent evt) - { - if (!allChainsSelected) - { - showSelectedChains(); - } - } - }); - - chainMenu.add(menuItem); - } - } - - /** * Show only the selected chain(s) in the viewer */ @Override @@@ -338,8 -584,7 +432,8 @@@ { String prompt = MessageManager.formatMessage( "label.confirm_close_chimera", - new Object[] { jmb.getViewerTitle("Chimera", false) }); + new Object[] { jmb.getViewerTitle(getViewerName(), + false) }); prompt = JvSwingUtils.wrapTooltip(true, prompt); int confirm = JvOptionPane.showConfirmDialog(this, prompt, MessageManager.getString("label.close_viewer"), @@@ -450,6 -695,7 +544,7 @@@ if (files.length() > 0) { + jmb.setFinishedInit(false); if (!addingStructures) { try @@@ -469,7 -715,7 +564,7 @@@ try { int pos = filePDBpos.get(num).intValue(); - long startTime = startProgressBar("Chimera " + long startTime = startProgressBar(getViewerName() + " " + MessageManager.getString("status.opening_file_for") + " " + pe.getId()); jmb.openFile(pe); @@@ -507,6 -753,7 +602,7 @@@ } } } + jmb.refreshGUI(); jmb.setFinishedInit(true); jmb.setLoadingFromArchive(false); @@@ -634,6 -881,76 +730,6 @@@ } @Override - public void pdbFile_actionPerformed(ActionEvent actionEvent) - { - JalviewFileChooser chooser = new JalviewFileChooser( - jalview.bin.Cache.getProperty("LAST_DIRECTORY")); - - chooser.setFileView(new JalviewFileView()); - chooser.setDialogTitle(MessageManager.getString("label.save_pdb_file")); - chooser.setToolTipText(MessageManager.getString("action.save")); - - int value = chooser.showSaveDialog(this); - - if (value == JalviewFileChooser.APPROVE_OPTION) - { - BufferedReader in = null; - try - { - // TODO: cope with multiple PDB files in view - in = new BufferedReader(new FileReader(jmb.getPdbFile()[0])); - File outFile = chooser.getSelectedFile(); - - PrintWriter out = new PrintWriter(new FileOutputStream(outFile)); - String data; - while ((data = in.readLine()) != null) - { - if (!(data.indexOf("

    ") > -1 || data.indexOf("
    ") > -1)) - { - out.println(data); - } - } - out.close(); - } catch (Exception ex) - { - ex.printStackTrace(); - } finally - { - if (in != null) - { - try - { - in.close(); - } catch (IOException e) - { - e.printStackTrace(); - } - } - } - } - } - - @Override - public void viewMapping_actionPerformed(ActionEvent actionEvent) - { - jalview.gui.CutAndPasteTransfer cap = new jalview.gui.CutAndPasteTransfer(); - try - { - cap.appendText(jmb.printMappings()); - } catch (OutOfMemoryError e) - { - new OOMWarning( - "composing sequence-structure alignments for display in text box.", - e); - cap.dispose(); - return; - } - jalview.gui.Desktop.addInternalFrame(cap, - MessageManager.getString("label.pdb_sequence_mapping"), 550, - 600); - } - - @Override public void eps_actionPerformed(ActionEvent e) { throw new Error( @@@ -650,17 -967,237 +746,17 @@@ } @Override - public void viewerColour_actionPerformed(ActionEvent actionEvent) - { - if (viewerColour.isSelected()) - { - // disable automatic sequence colouring. - jmb.setColourBySequence(false); - } - } - - @Override - public void seqColour_actionPerformed(ActionEvent actionEvent) - { - jmb.setColourBySequence(seqColour.isSelected()); - if (_colourwith == null) - { - _colourwith = new Vector(); - } - if (jmb.isColourBySequence()) - { - if (!jmb.isLoadingFromArchive()) - { - if (_colourwith.size() == 0 && getAlignmentPanel() != null) - { - // Make the currently displayed alignment panel the associated view - _colourwith.add(getAlignmentPanel().alignFrame.alignPanel); - } - } - // Set the colour using the current view for the associated alignframe - for (AlignmentPanel ap : _colourwith) - { - jmb.colourBySequence(ap.av.isShowSequenceFeatures(), ap); - } - } - } - - @Override - public void chainColour_actionPerformed(ActionEvent actionEvent) - { - chainColour.setSelected(true); - jmb.colourByChain(); - } - - @Override - public void chargeColour_actionPerformed(ActionEvent actionEvent) - { - chargeColour.setSelected(true); - jmb.colourByCharge(); - } - - @Override - public void zappoColour_actionPerformed(ActionEvent actionEvent) - { - zappoColour.setSelected(true); - jmb.setJalviewColourScheme(new ZappoColourScheme()); - } - - @Override - public void taylorColour_actionPerformed(ActionEvent actionEvent) - { - taylorColour.setSelected(true); - jmb.setJalviewColourScheme(new TaylorColourScheme()); - } - - @Override - public void hydroColour_actionPerformed(ActionEvent actionEvent) - { - hydroColour.setSelected(true); - jmb.setJalviewColourScheme(new HydrophobicColourScheme()); - } - - @Override - public void helixColour_actionPerformed(ActionEvent actionEvent) - { - helixColour.setSelected(true); - jmb.setJalviewColourScheme(new HelixColourScheme()); - } - - @Override - public void strandColour_actionPerformed(ActionEvent actionEvent) - { - strandColour.setSelected(true); - jmb.setJalviewColourScheme(new StrandColourScheme()); - } - - @Override - public void turnColour_actionPerformed(ActionEvent actionEvent) - { - turnColour.setSelected(true); - jmb.setJalviewColourScheme(new TurnColourScheme()); - } - - @Override - public void buriedColour_actionPerformed(ActionEvent actionEvent) - { - buriedColour.setSelected(true); - jmb.setJalviewColourScheme(new BuriedColourScheme()); - } - - @Override - public void purinePyrimidineColour_actionPerformed(ActionEvent actionEvent) - { - setJalviewColourScheme(new PurinePyrimidineColourScheme()); - } - - @Override - public void userColour_actionPerformed(ActionEvent actionEvent) - { - userColour.setSelected(true); - new UserDefinedColours(this, null); - } - - @Override - public void backGround_actionPerformed(ActionEvent actionEvent) - { - java.awt.Color col = JColorChooser - .showDialog(this, MessageManager - .getString("label.select_backgroud_colour"), null); - if (col != null) - { - jmb.setBackgroundColour(col); - } - } - - @Override public void showHelp_actionPerformed(ActionEvent actionEvent) { try { - jalview.util.BrowserLauncher + BrowserLauncher .openURL("https://www.cgl.ucsf.edu/chimera/docs/UsersGuide"); -- } catch (Exception ex) ++ } catch (IOException ex) { } } - public void updateTitleAndMenus() - { - if (jmb.fileLoadingError != null && jmb.fileLoadingError.length() > 0) - { - repaint(); - return; - } - setChainMenuItems(jmb.getChainNames()); - - this.setTitle(jmb.getViewerTitle("Chimera", true)); - // if (jmb.getPdbFile().length > 1 && jmb.getSequence().length > 1) - // { - viewerActionMenu.setVisible(true); - // } - if (!jmb.isLoadingFromArchive()) - { - seqColour_actionPerformed(null); - } - } - - /* - * (non-Javadoc) - * - * @see - * jalview.jbgui.GStructureViewer#alignStructs_actionPerformed(java.awt.event - * .ActionEvent) - */ - @Override - protected void alignStructs_actionPerformed(ActionEvent actionEvent) - { - alignStructs_withAllAlignPanels(); - } - - private void alignStructs_withAllAlignPanels() - { - if (getAlignmentPanel() == null) - { - return; - } - - if (_alignwith.size() == 0) - { - _alignwith.add(getAlignmentPanel()); - } - - try - { - AlignmentI[] als = new Alignment[_alignwith.size()]; - ColumnSelection[] alc = new ColumnSelection[_alignwith.size()]; - int[] alm = new int[_alignwith.size()]; - int a = 0; - - for (AlignmentPanel ap : _alignwith) - { - als[a] = ap.av.getAlignment(); - alm[a] = -1; - alc[a++] = ap.av.getColumnSelection(); - } - jmb.superposeStructures(als, alm, alc); - } catch (Exception e) - { - StringBuffer sp = new StringBuffer(); - for (AlignmentPanel ap : _alignwith) - { - sp.append("'" + ap.alignFrame.getTitle() + "' "); - } - Cache.log.info("Couldn't align structures with the " + sp.toString() - + "associated alignment panels.", e); - } - } - - @Override - public void setJalviewColourScheme(ColourSchemeI ucs) - { - jmb.setJalviewColourScheme(ucs); - - } - - /** - * - * @param alignment - * @return first alignment panel displaying given alignment, or the default - * alignment panel - */ - public AlignmentPanel getAlignmentPanelFor(AlignmentI alignment) - { - for (AlignmentPanel ap : getAllAlignmentPanels()) - { - if (ap.av.getAlignment() == alignment) - { - return ap; - } - } - return getAlignmentPanel(); - } - @Override public AAStructureBindingModel getBinding() { @@@ -750,8 -1287,8 +846,15 @@@ } @Override - protected AAStructureBindingModel getBindingModel() + protected String getViewerName() { - return jmb; + return "Chimera"; + } ++ ++ @Override ++ public void updateTitleAndMenus() ++ { ++ super.updateTitleAndMenus(); ++ viewerActionMenu.setVisible(true); + } } diff --combined src/jalview/gui/JalviewChimeraBindingModel.java index a797872,bd890d9..a1f05bd --- a/src/jalview/gui/JalviewChimeraBindingModel.java +++ b/src/jalview/gui/JalviewChimeraBindingModel.java @@@ -28,6 -28,8 +28,8 @@@ import jalview.ext.rbvi.chimera.Jalview import jalview.io.DataSourceType; import jalview.structure.StructureSelectionManager; + import javax.swing.SwingUtilities; + public class JalviewChimeraBindingModel extends JalviewChimeraBinding { private ChimeraViewFrame cvf; @@@ -95,7 -97,7 +97,7 @@@ } if (!isLoadingFromArchive()) { - colourBySequence(ap.av.isShowSequenceFeatures(), ap); + colourBySequence(ap); } } @@@ -122,24 -124,25 +124,25 @@@ protected void sendAsynchronousCommand(final String command, final String progressMsg) { - Thread thread = new Thread(new Runnable() + final long handle = progressMsg == null ? 0 : cvf + .startProgressBar(progressMsg); + SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - long stm = cvf.startProgressBar(progressMsg); try { sendChimeraCommand(command, false); } finally { - cvf.stopProgressBar(null, stm); + if (progressMsg != null) + { + cvf.stopProgressBar(null, handle); + } } } }); - thread.start(); - } @Override diff --combined src/jalview/viewmodel/AlignmentViewport.java index 0c470fe,0cca5b4..94d0dd1 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@@ -20,6 -20,17 +20,17 @@@ */ package jalview.viewmodel; + import java.awt.Color; + import java.beans.PropertyChangeSupport; + import java.util.ArrayDeque; + import java.util.ArrayList; + import java.util.BitSet; + import java.util.Deque; + import java.util.HashMap; + import java.util.Hashtable; + import java.util.List; + import java.util.Map; + import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder; import jalview.analysis.Conservation; import jalview.api.AlignCalcManagerI; @@@ -42,9 -53,9 +53,9 @@@ import jalview.datamodel.Sequence import jalview.datamodel.SequenceCollectionI; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; -import jalview.schemes.Blosum62ColourScheme; +import jalview.renderer.ResidueShader; +import jalview.renderer.ResidueShaderI; import jalview.schemes.ColourSchemeI; -import jalview.schemes.PIDColourScheme; import jalview.structure.CommandListener; import jalview.structure.StructureSelectionManager; import jalview.structure.VamsasSource; @@@ -57,17 -68,6 +68,6 @@@ import jalview.workers.ComplementConsen import jalview.workers.ConsensusThread; import jalview.workers.StrucConsensusThread; - import java.awt.Color; - import java.beans.PropertyChangeSupport; - import java.util.ArrayDeque; - import java.util.ArrayList; - import java.util.BitSet; - import java.util.Deque; - import java.util.HashMap; - import java.util.Hashtable; - import java.util.List; - import java.util.Map; - /** * base class holding visualization and analysis attributes and common logic for * an active alignment view displayed in the GUI @@@ -597,7 -597,7 +597,7 @@@ public abstract class AlignmentViewpor protected boolean ignoreGapsInConsensusCalculation = false; - protected ColourSchemeI globalColourScheme = null; + protected ResidueShaderI residueShading; @Override public void setGlobalColourScheme(ColourSchemeI cs) @@@ -605,51 -605,74 +605,51 @@@ // TODO: logic refactored from AlignFrame changeColour - // TODO: autorecalc stuff should be changed to rely on the worker system // check to see if we should implement a changeColour(cs) method rather than - // put th logic in here + // put the logic in here // - means that caller decides if they want to just modify state and defer // calculation till later or to do all calculations in thread. // via changecolour - globalColourScheme = cs; - boolean recalc = false; + + /* + * only instantiate alignment colouring once, thereafter update it; + * this means that any conservation or PID threshold settings + * persist when the alignment colour scheme is changed + */ + if (residueShading == null) + { + residueShading = new ResidueShader(viewStyle); + } + residueShading.setColourScheme(cs); + + // TODO: do threshold and increment belong in ViewStyle or ResidueShader? + // ...problem: groups need these, but do not currently have a ViewStyle + if (cs != null) { - recalc = getConservationSelected(); - if (getAbovePIDThreshold() || cs instanceof PIDColourScheme - || cs instanceof Blosum62ColourScheme) - { - recalc = true; - cs.setThreshold(viewStyle.getThreshold(), - ignoreGapsInConsensusCalculation); - } - else + if (getConservationSelected()) { - cs.setThreshold(0, ignoreGapsInConsensusCalculation); + residueShading.setConservation(hconservation); } - if (recalc) - { - cs.setConsensus(hconsensus); - cs.setConservation(hconservation); - } - cs.setConservationApplied(getConservationSelected()); - cs.alignmentChanged(alignment, hiddenRepSequences); + residueShading.alignmentChanged(alignment, hiddenRepSequences); } + + /* + * if 'apply colour to all groups' is selected... do so + * (but don't transfer any colour threshold settings to groups) + */ if (getColourAppliesToAllGroups()) { for (SequenceGroup sg : getAlignment().getGroups()) { - if (cs == null) - { - sg.cs = null; - continue; - } - sg.cs = cs.applyTo(sg, getHiddenRepSequences()); - sg.setConsPercGaps(ConsPercGaps); - if (getAbovePIDThreshold() || cs instanceof PIDColourScheme - || cs instanceof Blosum62ColourScheme) - { - sg.cs.setThreshold(viewStyle.getThreshold(), - isIgnoreGapsConsensus()); - recalc = true; - } - else + /* + * retain any colour thresholds per group while + * changing choice of colour scheme (JAL-2386) + */ + sg.setColourScheme(cs); + if (cs != null) { - sg.cs.setThreshold(0, isIgnoreGapsConsensus()); - } - - if (getConservationSelected()) - { - sg.cs.setConservationApplied(true); - recalc = true; - } - else - { - sg.cs.setConservation(null); - // sg.cs.setThreshold(0, getIgnoreGapsConsensus()); - } - if (recalc) - { - sg.recalcConservation(); - } - else - { - sg.cs.alignmentChanged(sg, hiddenRepSequences); + sg.getGroupColourScheme() + .alignmentChanged(sg, hiddenRepSequences); } } } @@@ -658,20 -681,15 +658,22 @@@ @Override public ColourSchemeI getGlobalColourScheme() { - return globalColourScheme; + return residueShading == null ? null : residueShading + .getColourScheme(); + } + + @Override + public ResidueShaderI getResidueShading() + { + return residueShading; } protected AlignmentAnnotation consensus; protected AlignmentAnnotation complementConsensus; + protected AlignmentAnnotation gapcounts; + protected AlignmentAnnotation strucConsensus; protected AlignmentAnnotation conservation; @@@ -774,6 -792,12 +776,12 @@@ } @Override + public AlignmentAnnotation getAlignmentGapAnnotation() + { + return gapcounts; + } + + @Override public AlignmentAnnotation getComplementConsensusAnnotation() { return complementConsensus; @@@ -813,7 -837,7 +821,7 @@@ public void updateConsensus(final AlignmentViewPanel ap) { // see note in mantis : issue number 8585 - if (consensus == null || !autoCalculateConsensus) + if ((consensus == null || gapcounts == null) || !autoCalculateConsensus) { return; } @@@ -925,7 -949,7 +933,7 @@@ hconsensus = null; hcomplementConsensus = null; // colour scheme may hold reference to consensus - globalColourScheme = null; + residueShading = null; // TODO remove listeners from changeSupport? changeSupport = null; setAlignment(null); @@@ -1073,8 -1097,7 +1081,8 @@@ } /** - * Set the selection group for this window. + * Set the selection group for this window. Also sets the current alignment as + * the context for the group, if it does not already have one. * * @param sg * - group holding references to sequences in this alignment view @@@ -1084,10 -1107,6 +1092,10 @@@ public void setSelectionGroup(SequenceGroup sg) { selectionGroup = sg; + if (sg != null && sg.getContext() == null) + { + sg.setContext(alignment); + } } public void setHiddenColumns(ColumnSelection colsel) @@@ -1200,9 -1219,9 +1208,9 @@@ if (ap != null) { updateConsensus(ap); - if (globalColourScheme != null) + if (residueShading != null) { - globalColourScheme.setThreshold(globalColourScheme.getThreshold(), + residueShading.setThreshold(residueShading.getThreshold(), ignoreGapsInConsensusCalculation); } } @@@ -1838,7 -1857,7 +1846,7 @@@ selectionGroup.setEndRes(alWidth - 1); } - resetAllColourSchemes(); + updateAllColourSchemes(); calculator.restartWorkers(); // alignment.adjustSequenceAnnotations(); } @@@ -1846,17 -1865,17 +1854,17 @@@ /** * reset scope and do calculations for all applied colourschemes on alignment */ - void resetAllColourSchemes() + void updateAllColourSchemes() { - ColourSchemeI cs = globalColourScheme; - if (cs != null) + ResidueShaderI rs = residueShading; + if (rs != null) { - cs.alignmentChanged(alignment, hiddenRepSequences); + rs.alignmentChanged(alignment, hiddenRepSequences); - cs.setConsensus(hconsensus); - if (cs.conservationApplied()) + rs.setConsensus(hconsensus); + if (rs.conservationApplied()) { - cs.setConservation(Conservation.calculateConservation("All", + rs.setConservation(Conservation.calculateConservation("All", alignment.getSequences(), 0, alignment.getWidth(), false, getConsPercGaps(), false)); } @@@ -1892,6 -1911,11 +1900,11 @@@ consensus = new AlignmentAnnotation("Consensus", "PID", new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH); initConsensus(consensus); + gapcounts = new AlignmentAnnotation("Occupancy", + "Number of aligned positions", + new Annotation[1], 0f, alignment.getHeight(), + AlignmentAnnotation.BAR_GRAPH); + initGapCounts(gapcounts); initComplementConsensus(); } @@@ -1944,6 -1968,20 +1957,20 @@@ } } + // these should be extracted from the view model - style and settings for + // derived annotation + private void initGapCounts(AlignmentAnnotation counts) + { + counts.hasText = false; + counts.autoCalculated = true; + counts.graph = AlignmentAnnotation.BAR_GRAPH; + + if (showConsensus) + { + alignment.addAnnotation(counts); + } + } + private void initConservation() { if (showConservation) @@@ -2430,11 -2468,6 +2457,11 @@@ public void setViewStyle(ViewStyleI settingsForView) { viewStyle = new ViewStyle(settingsForView); + if (residueShading != null) + { + residueShading.setConservationApplied(settingsForView + .isConservationColourSelected()); + } } @Override @@@ -2819,7 -2852,6 +2846,6 @@@ */ private boolean selectionIsDefinedGroup = false; - @Override public boolean isSelectionDefinedGroup() { diff --combined src/jalview/workers/ConsensusThread.java index 0c7e69a,1cce3ff..284f1a1 --- a/src/jalview/workers/ConsensusThread.java +++ b/src/jalview/workers/ConsensusThread.java @@@ -28,7 -28,7 +28,7 @@@ import jalview.datamodel.AlignmentI import jalview.datamodel.Annotation; import jalview.datamodel.ProfilesI; import jalview.datamodel.SequenceI; -import jalview.schemes.ColourSchemeI; +import jalview.renderer.ResidueShaderI; public class ConsensusThread extends AlignCalcWorker { @@@ -50,7 -50,8 +50,8 @@@ try { AlignmentAnnotation consensus = getConsensusAnnotation(); - if (consensus == null || calcMan.isPending(this)) + AlignmentAnnotation gap = getGapAnnotation(); + if ((consensus == null && gap == null) || calcMan.isPending(this)) { calcMan.workerComplete(this); return; @@@ -117,6 -118,11 +118,11 @@@ { AlignmentAnnotation consensus = getConsensusAnnotation(); consensus.annotations = new Annotation[aWidth]; + AlignmentAnnotation gap = getGapAnnotation(); + if (gap != null) + { + gap.annotations = new Annotation[aWidth]; + } } /** @@@ -127,8 -133,8 +133,8 @@@ SequenceI[] aseqs = getSequences(); int width = alignment.getWidth(); - ProfilesI hconsensus = AAFrequency.calculate(aseqs, width, 0, - width, true); + ProfilesI hconsensus = AAFrequency.calculate(aseqs, width, 0, width, + true); alignViewport.setSequenceConsensusHash(hconsensus); setColourSchemeConsensus(hconsensus); @@@ -147,10 -153,11 +153,10 @@@ */ protected void setColourSchemeConsensus(ProfilesI hconsensus) { - ColourSchemeI globalColourScheme = alignViewport - .getGlobalColourScheme(); - if (globalColourScheme != null) + ResidueShaderI cs = alignViewport.getResidueShading(); + if (cs != null) { - globalColourScheme.setConsensus(hconsensus); + cs.setConsensus(hconsensus); } } @@@ -165,6 -172,16 +171,16 @@@ } /** + * Get the Gap annotation for the alignment + * + * @return + */ + protected AlignmentAnnotation getGapAnnotation() + { + return alignViewport.getAlignmentGapAnnotation(); + } + + /** * update the consensus annotation from the sequence profile data using * current visualization settings. */ @@@ -182,6 -199,11 +198,11 @@@ && hconsensus != null) { deriveConsensus(consensus, hconsensus); + AlignmentAnnotation gap = getGapAnnotation(); + if (gap != null) + { + deriveGap(gap, hconsensus); + } } } @@@ -200,13 -222,29 +221,29 @@@ long nseq = getSequences().length; AAFrequency.completeConsensus(consensusAnnotation, hconsensus, - hconsensus.getStartColumn(), - hconsensus.getEndColumn() + 1, + hconsensus.getStartColumn(), hconsensus.getEndColumn() + 1, alignViewport.isIgnoreGapsConsensus(), alignViewport.isShowSequenceLogo(), nseq); } /** + * Convert the computed consensus data into a gap annotation row for display. + * + * @param gapAnnotation + * the annotation to be populated + * @param hconsensus + * the computed consensus data + */ + protected void deriveGap(AlignmentAnnotation gapAnnotation, + ProfilesI hconsensus) + { + long nseq = getSequences().length; + AAFrequency.completeGapAnnot(gapAnnotation, hconsensus, + hconsensus.getStartColumn(), hconsensus.getEndColumn() + 1, + nseq); + } + + /** * Get the consensus data stored on the viewport. * * @return diff --combined test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java index ffb886c,70c6922..fb442e3 --- a/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java +++ b/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java @@@ -20,17 -20,16 +20,16 @@@ */ package jalview.ext.rbvi.chimera; - import static org.testng.AssertJUnit.assertEquals; - import static org.testng.AssertJUnit.assertTrue; + import static org.testng.Assert.assertEquals; + import static org.testng.Assert.assertTrue; import jalview.gui.JvOptionPane; import java.awt.Color; - import java.util.Arrays; + import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; - import java.util.SortedMap; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@@ -46,73 -45,107 +45,108 @@@ public class ChimeraCommandsTes } @Test(groups = { "Functional" }) public void testBuildColourCommands() { - Map>>> map = new LinkedHashMap>>>(); + Map map = new LinkedHashMap(); - ChimeraCommands.addRange(map, Color.blue, 0, 2, 5, "A"); - ChimeraCommands.addRange(map, Color.blue, 0, 7, 7, "B"); - ChimeraCommands.addRange(map, Color.blue, 0, 9, 23, "A"); - ChimeraCommands.addRange(map, Color.blue, 1, 1, 1, "A"); - ChimeraCommands.addRange(map, Color.blue, 1, 4, 7, "B"); - ChimeraCommands.addRange(map, Color.yellow, 1, 8, 8, "A"); - ChimeraCommands.addRange(map, Color.yellow, 1, 3, 5, "A"); - ChimeraCommands.addRange(map, Color.red, 0, 3, 5, "A"); - ChimeraCommands.addRange(map, Color.red, 0, 6, 9, "A"); + ChimeraCommands.addColourRange(map, Color.blue, 0, 2, 5, "A"); + ChimeraCommands.addColourRange(map, Color.blue, 0, 7, 7, "B"); + ChimeraCommands.addColourRange(map, Color.blue, 0, 9, 23, "A"); + ChimeraCommands.addColourRange(map, Color.blue, 1, 1, 1, "A"); + ChimeraCommands.addColourRange(map, Color.blue, 1, 4, 7, "B"); + ChimeraCommands.addColourRange(map, Color.yellow, 1, 8, 8, "A"); + ChimeraCommands.addColourRange(map, Color.yellow, 1, 3, 5, "A"); + ChimeraCommands.addColourRange(map, Color.red, 0, 3, 5, "A"); ++ ChimeraCommands.addColourRange(map, Color.red, 0, 6, 9, "A"); // Colours should appear in the Chimera command in the order in which - // they were added; within colour, by model, by chain, and positions as - // added + // they were added; within colour, by model, by chain, ranges in start order String command = ChimeraCommands.buildColourCommands(map).get(0); assertEquals( - "color #0000ff #0:2-5.A,9-23.A,7.B|#1:1.A,4-7.B; color #ffff00 #1:8.A,3-5.A; color #ff0000 #0:3-5.A", - command); + command, + "color #0000ff #0:2-5.A,9-23.A,7.B|#1:1.A,4-7.B; color #ffff00 #1:3-5.A,8.A; color #ff0000 #0:3-9.A"); + } + + @Test(groups = { "Functional" }) + public void testBuildSetAttributeCommands() + { + /* + * make a map of { featureType, {featureValue, {residue range specification } } } + */ + Map> featuresMap = new LinkedHashMap>(); + Map featureValues = new HashMap(); + + /* + * start with just one feature/value... + */ + featuresMap.put("chain", featureValues); - ChimeraCommands.addRange(featureValues, "X", 0, 8, 20, "A"); ++ ChimeraCommands.addColourRange(featureValues, "X", 0, 8, 20, "A"); + + List commands = ChimeraCommands + .buildSetAttributeCommands(featuresMap); + assertEquals(1, commands.size()); + + /* + * feature name gets a jv_ namespace prefix + * feature value is quoted in case it contains spaces + */ + assertEquals(commands.get(0), "setattr r jv_chain \"X\" #0:8-20.A"); + + // add same feature value, overlapping range - ChimeraCommands.addRange(featureValues, "X", 0, 3, 9, "A"); ++ ChimeraCommands.addColourRange(featureValues, "X", 0, 3, 9, "A"); + // same feature value, contiguous range - ChimeraCommands.addRange(featureValues, "X", 0, 21, 25, "A"); ++ ChimeraCommands.addColourRange(featureValues, "X", 0, 21, 25, "A"); + commands = ChimeraCommands.buildSetAttributeCommands(featuresMap); + assertEquals(1, commands.size()); + assertEquals(commands.get(0), "setattr r jv_chain \"X\" #0:3-25.A"); + + // same feature value and model, different chain - ChimeraCommands.addRange(featureValues, "X", 0, 21, 25, "B"); ++ ChimeraCommands.addColourRange(featureValues, "X", 0, 21, 25, "B"); + // same feature value and chain, different model - ChimeraCommands.addRange(featureValues, "X", 1, 26, 30, "A"); ++ ChimeraCommands.addColourRange(featureValues, "X", 1, 26, 30, "A"); + commands = ChimeraCommands.buildSetAttributeCommands(featuresMap); + assertEquals(1, commands.size()); + assertEquals(commands.get(0), + "setattr r jv_chain \"X\" #0:3-25.A,21-25.B|#1:26-30.A"); + + // same feature, different value - ChimeraCommands.addRange(featureValues, "Y", 0, 40, 50, "A"); ++ ChimeraCommands.addColourRange(featureValues, "Y", 0, 40, 50, "A"); + commands = ChimeraCommands.buildSetAttributeCommands(featuresMap); + assertEquals(2, commands.size()); + // commands are ordered by feature type but not by value + // so use contains to test for the expected command: + assertTrue(commands + .contains("setattr r jv_chain \"X\" #0:3-25.A,21-25.B|#1:26-30.A")); + assertTrue(commands.contains("setattr r jv_chain \"Y\" #0:40-50.A")); + + featuresMap.clear(); + featureValues.clear(); + featuresMap.put("side-chain binding!", featureValues); - ChimeraCommands.addRange(featureValues, "metal ion!", 0, 7, 15, "A"); ++ ChimeraCommands.addColourRange(featureValues, "metal ion!", 0, 7, 15, ++ "A"); + // feature names are sanitised to change space or hyphen to underscore + commands = ChimeraCommands.buildSetAttributeCommands(featuresMap); + assertTrue(commands + .contains("setattr r jv_side_chain_binding_ \"metal ion!\" #0:7-15.A")); + } + + /** + * Tests for the method that prefixes and sanitises a feature name so it can + * be used as a valid, namespaced attribute name in Chimera + */ + @Test(groups = { "Functional" }) + public void testMakeAttributeName() + { + assertEquals(ChimeraCommands.makeAttributeName(null), "jv_"); + assertEquals(ChimeraCommands.makeAttributeName(""), "jv_"); + assertEquals(ChimeraCommands.makeAttributeName("helix"), "jv_helix"); + assertEquals(ChimeraCommands.makeAttributeName("Hello World 24"), + "jv_Hello_World_24"); + assertEquals( + ChimeraCommands.makeAttributeName("!this is-a_very*{odd(name"), + "jv__this_is_a_very__odd_name"); + // name ending in color gets underscore appended + assertEquals(ChimeraCommands.makeAttributeName("helixColor"), + "jv_helixColor_"); } } diff --combined test/jalview/gui/AnnotationChooserTest.java index 38c1855,38c1855..cf97711 --- a/test/jalview/gui/AnnotationChooserTest.java +++ b/test/jalview/gui/AnnotationChooserTest.java @@@ -60,6 -60,6 +60,11 @@@ import org.testng.annotations.Test */ public class AnnotationChooserTest { ++ /* ++ * number of automatically computed annotation rows ++ * (Conservation, Quality, Consensus, Occupancy) ++ */ ++ private static final int AUTOCALCD = 4; @BeforeClass(alwaysRun = true) public void setUpJvOptionPane() @@@ -326,7 -326,7 +331,7 @@@ types = AnnotationChooser.getAnnotationTypes( parentPanel.getAlignment(), false); -- assertEquals("Not six annotation types", 6, types.size()); ++ assertEquals("Not six annotation types", 7, types.size()); assertTrue("IUPRED missing", types.contains("IUPRED")); assertTrue("JMol missing", types.contains("JMol")); assertTrue("Beauty missing", types.contains("Beauty")); @@@ -334,6 -334,6 +339,7 @@@ assertTrue("Consensus missing", types.contains("Consensus")); assertTrue("Quality missing", types.contains("Quality")); assertTrue("Conservation missing", types.contains("Conservation")); ++ assertTrue("Occupancy missing", types.contains("Occupancy")); } /** @@@ -357,18 -357,18 +363,19 @@@ AlignmentAnnotation[] anns = parentPanel.getAlignment() .getAlignmentAnnotation(); -- assertTrue(anns[5].visible); // JMol for seq3 -- assertTrue(anns[7].visible); // JMol for seq1 ++ assertTrue(anns[AUTOCALCD + 2].visible); // JMol for seq3 ++ assertTrue(anns[AUTOCALCD + 4].visible); // JMol for seq1 setSelected(getTypeCheckbox("JMol"), true); assertTrue(anns[0].visible); // Conservation assertTrue(anns[1].visible); // Quality assertTrue(anns[2].visible); // Consensus -- assertTrue(anns[3].visible); // IUPred for seq0 -- assertTrue(anns[4].visible); // Beauty -- assertFalse(anns[5].visible); // JMol for seq3 - not selected but hidden -- assertTrue(anns[6].visible); // IUPRED for seq2 -- assertFalse(anns[7].visible); // JMol for seq1 - selected and hidden ++ assertTrue(anns[3].visible); // Occupancy ++ assertTrue(anns[4].visible); // IUPred for seq0 ++ assertTrue(anns[5].visible); // Beauty ++ assertFalse(anns[6].visible); // JMol for seq3 - not selected but hidden ++ assertTrue(anns[7].visible); // IUPRED for seq2 ++ assertFalse(anns[8].visible); // JMol for seq1 - selected and hidden } /** @@@ -395,17 -395,17 +402,18 @@@ AlignmentAnnotation[] anns = parentPanel.getAlignment() .getAlignmentAnnotation(); -- assertTrue(anns[7].visible); // JMol for seq1 ++ assertTrue(anns[AUTOCALCD + 4].visible); // JMol for seq1 setSelected(getTypeCheckbox("JMol"), true); assertTrue(anns[0].visible); // Conservation assertTrue(anns[1].visible); // Quality assertTrue(anns[2].visible); // Consensus -- assertTrue(anns[3].visible); // IUPred for seq0 -- assertTrue(anns[4].visible); // Beauty -- assertTrue(anns[5].visible); // JMol for seq3 not in selection group -- assertTrue(anns[6].visible); // IUPRED for seq2 -- assertFalse(anns[7].visible); // JMol for seq1 in selection group ++ assertTrue(anns[3].visible); // Occupancy ++ assertTrue(anns[4].visible); // IUPred for seq0 ++ assertTrue(anns[5].visible); // Beauty ++ assertTrue(anns[6].visible); // JMol for seq3 not in selection group ++ assertTrue(anns[7].visible); // IUPRED for seq2 ++ assertFalse(anns[8].visible); // JMol for seq1 in selection group } /** @@@ -435,19 -435,19 +443,20 @@@ // select JMol - all hidden setSelected(typeCheckbox, true); -- assertFalse(anns[5].visible); // JMol for seq3 -- assertFalse(anns[7].visible); // JMol for seq1 ++ assertFalse(anns[AUTOCALCD + 2].visible); // JMol for seq3 ++ assertFalse(anns[AUTOCALCD + 4].visible); // JMol for seq1 // deselect JMol - all unhidden setSelected(typeCheckbox, false); assertTrue(anns[0].visible); // Conservation assertTrue(anns[1].visible); // Quality assertTrue(anns[2].visible); // Consensus -- assertTrue(anns[3].visible); // IUPred for seq0 -- assertTrue(anns[4].visible); // Beauty -- assertTrue(anns[5].visible); // JMol for seq3 -- assertTrue(anns[6].visible); // IUPRED for seq2 -- assertTrue(anns[7].visible); // JMol for seq1 ++ assertTrue(anns[3].visible); // Occupancy ++ assertTrue(anns[4].visible); // IUPred for seq0 ++ assertTrue(anns[5].visible); // Beauty ++ assertTrue(anns[6].visible); // JMol for seq3 ++ assertTrue(anns[7].visible); // IUPRED for seq2 ++ assertTrue(anns[8].visible); // JMol for seq1 } /** @@@ -510,18 -510,18 +519,19 @@@ setSelected(allSequencesCheckbox, true); setSelected(hideCheckbox, true); setSelected(getTypeCheckbox("JMol"), true); -- assertFalse(anns[5].visible); // JMol for seq3 -- assertFalse(anns[7].visible); // JMol for seq1 ++ assertFalse(anns[AUTOCALCD + 2].visible); // JMol for seq3 ++ assertFalse(anns[AUTOCALCD + 4].visible); // JMol for seq1 // ...now show them... setSelected(showCheckbox, true); assertTrue(anns[0].visible); // Conservation assertTrue(anns[1].visible); // Quality assertTrue(anns[2].visible); // Consensus -- assertTrue(anns[3].visible); // IUPred for seq0 -- assertTrue(anns[4].visible); // Beauty -- assertTrue(anns[5].visible); // JMol for seq3 -- assertTrue(anns[6].visible); // IUPRED for seq2 -- assertTrue(anns[7].visible); // JMol for seq1 ++ assertTrue(anns[3].visible); // Occupancy ++ assertTrue(anns[4].visible); // IUPred for seq0 ++ assertTrue(anns[5].visible); // Beauty ++ assertTrue(anns[6].visible); // JMol for seq3 ++ assertTrue(anns[7].visible); // IUPRED for seq2 ++ assertTrue(anns[8].visible); // JMol for seq1 } /** @@@ -551,19 -551,19 +561,20 @@@ setSelected(hideCheckbox, true); setSelected(getTypeCheckbox("JMol"), true); -- assertTrue(anns[5].visible); // JMol for seq3 -- assertFalse(anns[7].visible); // JMol for seq1 ++ assertTrue(anns[AUTOCALCD + 2].visible); // JMol for seq3 ++ assertFalse(anns[AUTOCALCD + 4].visible); // JMol for seq1 // ...now show them... setSelected(showCheckbox, true); assertTrue(anns[0].visible); // Conservation assertTrue(anns[1].visible); // Quality assertTrue(anns[2].visible); // Consensus -- assertTrue(anns[3].visible); // IUPred for seq0 -- assertTrue(anns[4].visible); // Beauty -- assertTrue(anns[5].visible); // JMol for seq3 -- assertTrue(anns[6].visible); // IUPRED for seq2 -- assertTrue(anns[7].visible); // JMol for seq1 ++ assertTrue(anns[3].visible); // Occupancy ++ assertTrue(anns[4].visible); // IUPred for seq0 ++ assertTrue(anns[5].visible); // Beauty ++ assertTrue(anns[6].visible); // JMol for seq3 ++ assertTrue(anns[7].visible); // IUPRED for seq2 ++ assertTrue(anns[8].visible); // JMol for seq1 } /** @@@ -592,19 -592,19 +603,20 @@@ final Checkbox typeCheckbox = getTypeCheckbox("JMol"); // select JMol - all shown setSelected(typeCheckbox, true); -- assertTrue(anns[5].visible); // JMol for seq3 -- assertTrue(anns[7].visible); // JMol for seq1 ++ assertTrue(anns[AUTOCALCD + 2].visible); // JMol for seq3 ++ assertTrue(anns[AUTOCALCD + 4].visible); // JMol for seq1 // deselect JMol - all hidden setSelected(typeCheckbox, false); assertTrue(anns[0].visible); // Conservation assertTrue(anns[1].visible); // Quality assertTrue(anns[2].visible); // Consensus -- assertTrue(anns[3].visible); // IUPred for seq0 -- assertTrue(anns[4].visible); // Beauty -- assertFalse(anns[5].visible); // JMol for seq3 -- assertTrue(anns[6].visible); // IUPRED for seq2 -- assertFalse(anns[7].visible); // JMol for seq1 ++ assertTrue(anns[3].visible); // Occupancy ++ assertTrue(anns[4].visible); // IUPred for seq0 ++ assertTrue(anns[5].visible); // Beauty ++ assertFalse(anns[6].visible); // JMol for seq3 ++ assertTrue(anns[7].visible); // IUPRED for seq2 ++ assertFalse(anns[8].visible); // JMol for seq1 } /** @@@ -633,19 -633,19 +645,20 @@@ // select JMol - should remain visible setSelected(getTypeCheckbox("JMol"), true); -- assertTrue(anns[5].visible); // JMol for seq3 -- assertTrue(anns[7].visible); // JMol for seq1 ++ assertTrue(anns[AUTOCALCD + 2].visible); // JMol for seq3 ++ assertTrue(anns[AUTOCALCD + 4].visible); // JMol for seq1 // deselect JMol - should be hidden for selected sequences only setSelected(getTypeCheckbox("JMol"), false); assertTrue(anns[0].visible); // Conservation assertTrue(anns[1].visible); // Quality assertTrue(anns[2].visible); // Consensus -- assertTrue(anns[3].visible); // IUPred for seq0 -- assertTrue(anns[4].visible); // Beauty -- assertTrue(anns[5].visible); // JMol for seq3 not in selection group -- assertTrue(anns[6].visible); // IUPRED for seq2 -- assertFalse(anns[7].visible); // JMol for seq1 in selection group ++ assertTrue(anns[3].visible); // Occupancy ++ assertTrue(anns[4].visible); // IUPred for seq0 ++ assertTrue(anns[5].visible); // Beauty ++ assertTrue(anns[6].visible); // JMol for seq3 not in selection group ++ assertTrue(anns[7].visible); // IUPRED for seq2 ++ assertFalse(anns[8].visible); // JMol for seq1 in selection group } /** @@@ -721,12 -721,12 +734,11 @@@ AlignmentAnnotation[] anns = parentPanel.getAlignment() .getAlignmentAnnotation(); -- // remember 3 annotations to skip (Conservation/Quality/Consensus) -- assertFalse(testee.isInActionScope(anns[3])); -- assertFalse(testee.isInActionScope(anns[4])); -- assertFalse(testee.isInActionScope(anns[5])); -- assertTrue(testee.isInActionScope(anns[6])); -- assertTrue(testee.isInActionScope(anns[7])); ++ assertFalse(testee.isInActionScope(anns[AUTOCALCD])); ++ assertFalse(testee.isInActionScope(anns[AUTOCALCD + 1])); ++ assertFalse(testee.isInActionScope(anns[AUTOCALCD + 2])); ++ assertTrue(testee.isInActionScope(anns[AUTOCALCD + 3])); ++ assertTrue(testee.isInActionScope(anns[AUTOCALCD + 4])); } /** @@@ -747,12 -747,12 +759,11 @@@ AlignmentAnnotation[] anns = parentPanel.getAlignment() .getAlignmentAnnotation(); -- // remember 3 annotations to skip (Conservation/Quality/Consensus) -- assertTrue(testee.isInActionScope(anns[3])); -- assertTrue(testee.isInActionScope(anns[4])); -- assertTrue(testee.isInActionScope(anns[5])); -- assertFalse(testee.isInActionScope(anns[6])); -- assertFalse(testee.isInActionScope(anns[7])); ++ assertTrue(testee.isInActionScope(anns[AUTOCALCD])); ++ assertTrue(testee.isInActionScope(anns[AUTOCALCD + 1])); ++ assertTrue(testee.isInActionScope(anns[AUTOCALCD + 2])); ++ assertFalse(testee.isInActionScope(anns[AUTOCALCD + 3])); ++ assertFalse(testee.isInActionScope(anns[AUTOCALCD + 4])); } /** @@@ -787,11 -787,11 +798,12 @@@ assertTrue(anns[0].visible); // Conservation assertTrue(anns[1].visible); // Quality assertTrue(anns[2].visible); // Consensus -- assertFalse(anns[3].visible); // IUPRED -- assertTrue(anns[4].visible); // Beauty (not seq-related) -- assertFalse(anns[5].visible); // JMol -- assertFalse(anns[6].visible); // IUPRED -- assertFalse(anns[7].visible); // JMol ++ assertTrue(anns[3].visible); // Occupancy ++ assertFalse(anns[4].visible); // IUPRED ++ assertTrue(anns[5].visible); // Beauty (not seq-related) ++ assertFalse(anns[6].visible); // JMol ++ assertFalse(anns[7].visible); // IUPRED ++ assertFalse(anns[8].visible); // JMol // reset - should all be visible testee.resetOriginalState();