From: Jim Procter Date: Wed, 16 Nov 2016 17:12:43 +0000 (+0000) Subject: Merge branch 'features/JAL-1723_sequenceReport' into develop X-Git-Tag: Release_2_10_1~11^2^2~3 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=d0d8e3e2f528581af454e5b2a51372a9f4677114;hp=9a0f307f1fea87200c2ce905073942570795c6cc;p=jalview.git Merge branch 'features/JAL-1723_sequenceReport' into develop Conflicts: resources/lang/Messages.properties resources/lang/Messages_es.properties src/jalview/io/SequenceAnnotationReport.java reconciled refactored report/ellipsis code with refactored URLLink code for generating dynamic links with ACCESSION_ID tokens --- diff --git a/THIRDPARTYLIBS b/THIRDPARTYLIBS index 31ad2f5..7d12783 100644 --- a/THIRDPARTYLIBS +++ b/THIRDPARTYLIBS @@ -58,4 +58,5 @@ Additional dependencies examples/javascript/deployJava.js : http://java.com/js/deployJava.js examples/javascript/jquery*.js : BSD license examples/javascript/jshashtable-2.1.js : Apache License +examples/javascript/facebox-1.3.js : MTI License - http://www.opensource.org/licenses/mit-license.php diff --git a/examples/javascript/facebox-1.3.js b/examples/javascript/facebox-1.3.js new file mode 100644 index 0000000..ad45310 --- /dev/null +++ b/examples/javascript/facebox-1.3.js @@ -0,0 +1,309 @@ +/* + * Facebox (for jQuery) + * version: 1.2 (05/05/2008) + * @requires jQuery v1.2 or later + * + * Examples at http://famspam.com/facebox/ + * + * Licensed under the MIT: + * http://www.opensource.org/licenses/mit-license.php + * + * Copyright 2007, 2008 Chris Wanstrath [ chris@ozmm.org ] + * + * Usage: + * + * jQuery(document).ready(function() { + * jQuery('a[rel*=facebox]').facebox() + * }) + * + * Terms + * Loads the #terms div in the box + * + * Terms + * Loads the terms.html page in the box + * + * Terms + * Loads the terms.png image in the box + * + * + * You can also use it programmatically: + * + * jQuery.facebox('some html') + * jQuery.facebox('some html', 'my-groovy-style') + * + * The above will open a facebox with "some html" as the content. + * + * jQuery.facebox(function($) { + * $.get('blah.html', function(data) { $.facebox(data) }) + * }) + * + * The above will show a loading screen before the passed function is called, + * allowing for a better ajaxy experience. + * + * The facebox function can also display an ajax page, an image, or the contents of a div: + * + * jQuery.facebox({ ajax: 'remote.html' }) + * jQuery.facebox({ ajax: 'remote.html' }, 'my-groovy-style') + * jQuery.facebox({ image: 'stairs.jpg' }) + * jQuery.facebox({ image: 'stairs.jpg' }, 'my-groovy-style') + * jQuery.facebox({ div: '#box' }) + * jQuery.facebox({ div: '#box' }, 'my-groovy-style') + * + * Want to close the facebox? Trigger the 'close.facebox' document event: + * + * jQuery(document).trigger('close.facebox') + * + * Facebox also has a bunch of other hooks: + * + * loading.facebox + * beforeReveal.facebox + * reveal.facebox (aliased as 'afterReveal.facebox') + * init.facebox + * afterClose.facebox + * + * Simply bind a function to any of these hooks: + * + * $(document).bind('reveal.facebox', function() { ...stuff to do after the facebox and contents are revealed... }) + * + */ +(function($) { + $.facebox = function(data, klass) { + $.facebox.loading() + + if (data.ajax) fillFaceboxFromAjax(data.ajax, klass) + else if (data.image) fillFaceboxFromImage(data.image, klass) + else if (data.div) fillFaceboxFromHref(data.div, klass) + else if ($.isFunction(data)) data.call($) + else $.facebox.reveal(data, klass) + } + + /* + * Public, $.facebox methods + */ + + $.extend($.facebox, { + settings: { + opacity : 0.2, + overlay : true, + loadingImage : 'https://raw.githubusercontent.com/jalview/biojson/gh-pages/images/loading.gif', + closeImage : 'https://raw.githubusercontent.com/jalview/biojson/gh-pages/images/cancel.png', + imageTypes : [ 'png', 'jpg', 'jpeg', 'gif' ], + faceboxHtml : '\ + ' + }, + + loading: function() { + init() + if ($('#facebox .loading').length == 1) return true + showOverlay() + + $('#facebox .content').empty() + $('#facebox .body').children().hide().end(). + append('
') + + $('#facebox').css({ + top: getPageScroll()[1] + (getPageHeight() / 10), + left: $(window).width() / 2 - 205 + }).show() + + $(document).bind('keydown.facebox', function(e) { + if (e.keyCode == 27) $.facebox.close() + return true + }) + $(document).trigger('loading.facebox') + }, + + reveal: function(data, klass) { + $(document).trigger('beforeReveal.facebox') + if (klass) $('#facebox .content').addClass(klass) + $('#facebox .content').append('
'+JSON.stringify(JSON.parse(data),null,4)+'
') + $('#facebox .loading').remove() + $('#facebox .body').children().fadeIn('normal') + $('#facebox').css('left', $(window).width() / 2 - ($('#facebox .popup').width() / 2)) + $(document).trigger('reveal.facebox').trigger('afterReveal.facebox') + }, + + close: function() { + $(document).trigger('close.facebox') + return false + } + }) + + /* + * Public, $.fn methods + */ + + $.fn.facebox = function(settings) { + if ($(this).length == 0) return + + init(settings) + + function clickHandler() { + $.facebox.loading(true) + + // support for rel="facebox.inline_popup" syntax, to add a class + // also supports deprecated "facebox[.inline_popup]" syntax + var klass = this.rel.match(/facebox\[?\.(\w+)\]?/) + if (klass) klass = klass[1] + + fillFaceboxFromHref(this.href, klass) + return false + } + + return this.bind('click.facebox', clickHandler) + } + + /* + * Private methods + */ + + // called one time to setup facebox on this page + function init(settings) { + if ($.facebox.settings.inited) return true + else $.facebox.settings.inited = true + + $(document).trigger('init.facebox') + makeCompatible() + + var imageTypes = $.facebox.settings.imageTypes.join('|') + $.facebox.settings.imageTypesRegexp = new RegExp('\.(' + imageTypes + ')$', 'i') + + if (settings) $.extend($.facebox.settings, settings) + $('body').append($.facebox.settings.faceboxHtml) + + var preload = [ new Image(), new Image() ] + preload[0].src = $.facebox.settings.closeImage + preload[1].src = $.facebox.settings.loadingImage + + $('#facebox').find('.b:first, .bl').each(function() { + preload.push(new Image()) + preload.slice(-1).src = $(this).css('background-image').replace(/url\((.+)\)/, '$1') + }) + + $('#facebox .close').click($.facebox.close) + $('#facebox .close_image').attr('src', $.facebox.settings.closeImage) + } + + // getPageScroll() by quirksmode.com + function getPageScroll() { + var xScroll, yScroll; + if (self.pageYOffset) { + yScroll = self.pageYOffset; + xScroll = self.pageXOffset; + } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict + yScroll = document.documentElement.scrollTop; + xScroll = document.documentElement.scrollLeft; + } else if (document.body) {// all other Explorers + yScroll = document.body.scrollTop; + xScroll = document.body.scrollLeft; + } + return new Array(xScroll,yScroll) + } + + // Adapted from getPageSize() by quirksmode.com + function getPageHeight() { + var windowHeight + if (self.innerHeight) { // all except Explorer + windowHeight = self.innerHeight; + } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode + windowHeight = document.documentElement.clientHeight; + } else if (document.body) { // other Explorers + windowHeight = document.body.clientHeight; + } + return windowHeight + } + + // Backwards compatibility + function makeCompatible() { + var $s = $.facebox.settings + + $s.loadingImage = $s.loading_image || $s.loadingImage + $s.closeImage = $s.close_image || $s.closeImage + $s.imageTypes = $s.image_types || $s.imageTypes + $s.faceboxHtml = $s.facebox_html || $s.faceboxHtml + } + + // Figures out what you want to display and displays it + // formats are: + // div: #id + // image: blah.extension + // ajax: anything else + function fillFaceboxFromHref(href, klass) { + // div + if (href.match(/#/)) { + var url = window.location.href.split('#')[0] + var target = href.replace(url,'') + if (target == '#') return + $.facebox.reveal($(target).html(), klass) + + // image + } else if (href.match($.facebox.settings.imageTypesRegexp)) { + fillFaceboxFromImage(href, klass) + // ajax + } else { + fillFaceboxFromAjax(href, klass) + } + } + + function fillFaceboxFromImage(href, klass) { + var image = new Image() + image.onload = function() { + $.facebox.reveal('
', klass) + } + image.src = href + } + + function fillFaceboxFromAjax(href, klass) { + $.get(href, function(data) { $.facebox.reveal(data, klass) }) + } + + function skipOverlay() { + return $.facebox.settings.overlay == false || $.facebox.settings.opacity === null + } + + function showOverlay() { + if (skipOverlay()) return + + if ($('#facebox_overlay').length == 0) + $("body").append('
') + + $('#facebox_overlay').hide().addClass("facebox_overlayBG") + .css('opacity', $.facebox.settings.opacity) + .click(function() { $(document).trigger('close.facebox') }) + .fadeIn(200) + return false + } + + function hideOverlay() { + if (skipOverlay()) return + + $('#facebox_overlay').fadeOut(200, function(){ + $("#facebox_overlay").removeClass("facebox_overlayBG") + $("#facebox_overlay").addClass("facebox_hide") + $("#facebox_overlay").remove() + }) + + return false + } + + /* + * Bindings + */ + + $(document).bind('close.facebox', function() { + $(document).unbind('keydown.facebox') + $('#facebox').fadeOut(function() { + $('#facebox .content').removeClass().addClass('content') + $('#facebox .loading').remove() + $(document).trigger('afterClose.facebox') + }) + hideOverlay() + }) + +})(jQuery); diff --git a/help/html/colourSchemes/abovePID.html b/help/html/colourSchemes/abovePID.html index 614764b..8adacc9 100755 --- a/help/html/colourSchemes/abovePID.html +++ b/help/html/colourSchemes/abovePID.html @@ -35,10 +35,10 @@ td { Colouring above a percentage identity threshold

Selecting this option causes the colour scheme to be applied to - only those residues that occur in that column more than a certain - percentage of the time. For instance selecting the threshold to be - 100 will only colour those columns with 100 % identity. This - threshold option can be applied to the Zappo, Taylor, Hydrophobicity - and User colour schemes.

+ only those residues that occur in that column at least a certain + percentage of the time. For instance, selecting the threshold to be + 100 will only colour those columns with 100% identity, and selecting 50 will shade residues appearing in least 50% of the rows (or sequences) in each column.

+

The percentage calculation may include or exclude gaps in the column, depending on the option selected for the consensus calculation.

+

With a threshold of 0, colouring is unchanged.

diff --git a/help/html/features/featuresFormat.html b/help/html/features/featuresFormat.html index ec1e093..fd6b99f 100755 --- a/help/html/features/featuresFormat.html +++ b/help/html/features/featuresFormat.html @@ -121,11 +121,12 @@ a colour the feature).

- If your sequence annotation is already available in GFF Format (see - gmod.org/wiki/GFF2), then - you can leave it as is, after first adding a line containing only + If your sequence annotation is already available in GFF2 (http://gmod.org/wiki/GFF2) or + GFF3 + (http://github.com/The-Sequence-Ontology/Specifications/blob/master/gff3.md) format, + then you can leave it as is, after first adding a line containing only 'GFF' after any Jalview feature colour definitions (this - mixed format capability was added in Jalview 2.6). Alternately, + mixed format capability was added in Jalview 2.6). Alternately, you can use Jalview's own sequence feature annotation format, which additionally allows HTML and URLs to be directly attached to each piece of annotation. diff --git a/help/html/features/search.html b/help/html/features/search.html index 9766782..796d623 100755 --- a/help/html/features/search.html +++ b/help/html/features/search.html @@ -73,7 +73,7 @@ td { the match. For example, a simple query like "ACDED" would match all occurences of that string, but "ACD+ED" matches both 'ACDDED' and 'ACDDDDDDDDED'. More usefully, the query - "[ILGVMA]{;5,}" would find stretches of small, hydrophobic + "[GVATC]{;5,}" would find stretches of small, hydrophobic amino acids of at least five residues in length.

The table below describes some of the regular expression syntax:
diff --git a/help/html/misc/aaproperties.html b/help/html/misc/aaproperties.html index 51274d7..b53f6ef 100755 --- a/help/html/misc/aaproperties.html +++ b/help/html/misc/aaproperties.html @@ -20,29 +20,39 @@ * The Jalview Authors are detailed in the 'AUTHORS' file. --> -Amino Acid Properties +Amino Acid Properties

Amino Acid Properties


- - - - +
-            ILVCAGMFYWHKREQDNSTPBZX-
-XXXXXXXXXXX·······X···XX Hydrophobic
-········XXXXXXXXXX·XXXXX Polar
-··XXXX·········XXXXX··XX Small
-···················X··XX Proline
-····XX···········X····XX Tiny
-XXX···················XX Aliphatic
-·······XXXX···········XX Aromatic
-··········XXX·········XX Positive
-·············X·X······XX Negative
-··········XXXX·X······XX Charged
-          
+ + + + + + + + + + +
ILVCAGMFYWHKREQDNSTPBZX-
XXXXXXXXXXXX······X···XXHydrophobic
········XXXXXXXXXXX·XXXXPolar
··XXXX·········XXXXX··XXSmall
···················X··XXProline
····XX···········X····XXTiny
XXX···················XXAliphatic
·······XXXX···········XXAromatic
··········XXX·········XXPositive
·············X·X······XXNegative
··········XXXX·X······XXCharged
+


From Livingstone, C. D. and Barton, G. J. (1993),
diff --git a/help/html/releases.html b/help/html/releases.html index 3fe08cb..40de3d4 100755 --- a/help/html/releases.html +++ b/help/html/releases.html @@ -47,6 +47,70 @@

+ 2.10.1
+ 22/11/2016
+
+ +
+ General + + Application + + Applet + + Build and deployment + +
+ + +
+ General + + Application + + Applet + + Build and deployment + + New Known Issues + +
+ + + +
2.10.0b1
25/10/2016
diff --git a/help/html/webServices/urllinks.html b/help/html/webServices/urllinks.html index 0a4c650..36c7c6b 100644 --- a/help/html/webServices/urllinks.html +++ b/help/html/webServices/urllinks.html @@ -28,7 +28,7 @@ and the desktop application are able to open URLs as 'popups' in your web browser.
Double-clicking on the ID of a sequence will open the first URL that can be generated from its sequence ID. - This is often the SRS site, but you can easily configure your own sequence URL links.

@@ -40,10 +40,10 @@

Configuring URL Links
URL links are defined in the "Connections" tab of the Jalview desktop - preferences, or specified as applet - parameters.
By default the item "SRS" is added + href="../features/preferences.html">Jalview desktop + preferences, or specified as applet + parameters.
By default the item "EMBL-EBI Search" is added to this link menu. This link will show a web page in your default browser with the selected sequence id as part of the URL.
In the preferences dialog box, click new to add a @@ -51,9 +51,9 @@ to remove it.
You can name the link, this will be displayed on a new menu item under the "Link" menu when you right click on a sequence id.
The URL string must contain a - token that can be replaced with a sequence ID. The simplest token is + token that can be replaced with a sequence ID or DB accession ID. The simplest token is "$SEQUENCE_ID$", which will be replaced by the chosen - sequence id when you click on it. + sequence id when you click on it.

eg.
UniRef100 = @@ -61,15 +61,22 @@ Swissprot = http://www.expasy.org/uniprot/$SEQUENCE_ID$

Links will also be made for any database cross references associated with the sequence where the database name exactly matches a URL link - name. In this case, the $SEQUENCE_ID$ string will be replaced with + name. In this case, the $DB_ACCESSION$ string will be replaced with the accession string for the database cross-reference, rather than - the sequence ID for the sequence (since Jalview 2.4). + the sequence ID for the sequence (since Jalview 2.10.1). +

+

+ If Jalview opens a project with links which include $SEQUENCE_ID$ tokens, it will present + the user with a warning message, as these links may need to be updated to use $DB_ACCESSION$, if + they were added before Jalview 2.10.1. The message lists the links which should be reviewed. + The warning can be turned off completely via a checkbox in the message dialog.

Regular Expression Substitution
A url may contain a string of the form $SEQUENCE_ID=/regular - expression/=$. In this case, the regular expression will be - applied to the full sequence ID string and the resulting match will + expression/=$ or $DB_ACCESSION=/regular expression/=$. + In this case, the regular expression will be + applied to the full sequence ID or DB accession ID string and the resulting match will be inserted into the URL. Groups of parentheses can be used to specify which regions of the regular expression will be used to generate the URL: diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index 1c52b63..01ba0ff 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -787,9 +787,9 @@ label.hide_columns_containing = Hide columns containing label.hide_columns_not_containing = Hide columns that do not contain option.trim_retrieved_seqs = Trim retrieved sequences label.trim_retrieved_sequences = When the reference sequence is longer than the sequence that you are working with, only keep the relevant subsequences. -label.use_sequence_id_1 = Use $SEQUENCE_ID$ or $SEQUENCE_ID=//=$ -label.use_sequence_id_2 = to embed sequence id in URL -label.use_sequence_id_3 = Use $SEQUENCE_NAME$ similarly to embed sequence name +label.use_sequence_id_1 = Use $DB_ACCESSION$ or $DB_ACCESSION=//=$ +label.use_sequence_id_2 = to embed accession id in URL +label.use_sequence_id_3 = Use $SEQUENCE_ID$ similarly to embed sequence id label.use_sequence_id_4 = label.ws_parameters_for = Parameters for {0} label.switch_server = Switch server @@ -1144,7 +1144,7 @@ warn.user_defined_width_requirements = The user defined width for the\nannotatio label.couldnt_create_sequence_fetcher = Couldn't create SequenceFetcher warn.couldnt_create_sequence_fetcher_client = Could not create the sequence fetcher client. Check error logs for details. warn.server_didnt_pass_validation = Service did not pass validation.\nCheck the Jalview Console for more details. -warn.url_must_contain = Sequence URL must contain $SEQUENCE_ID$ or a regex $SEQUENCE_ID=//=$ +warn.url_must_contain = Sequence URL must contain $SEQUENCE_ID$, $DB_ACCESSION$, or a regex warn.urls_not_contacted = URLs that could not be contacted warn.urls_no_jaba = URLs without any JABA Services info.validate_jabaws_server = Validate JabaWS Server ?\n(Look in console output for results) @@ -1268,4 +1268,8 @@ status.exporting_alignment_as_x_file = Exporting alignment as {0} file label.column = Column label.cant_map_cds = Unable to map CDS to protein\nCDS missing or incomplete label.operation_failed = Operation failed +label.SEQUENCE_ID_no_longer_used = $SEQUENCE_ID$ is no longer used for DB accessions +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 label.output_seq_details = Output Sequence Details to list all database references diff --git a/resources/lang/Messages_es.properties b/resources/lang/Messages_es.properties index 8009ae9..9c2436c 100644 --- a/resources/lang/Messages_es.properties +++ b/resources/lang/Messages_es.properties @@ -351,8 +351,8 @@ label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation = label.translation_failed = Translation Failed label.error_when_translating_sequences_submit_bug_report = Desafortunadamente, algo fue mal a la hora de traducir tus secuencias.\nPor favor, revisa la consola Jalview java \ny presenta un informe de error que incluya el seguimiento. label.implementation_error = Error de implementación: -label.automatically_associate_structure_files_with_sequences_same_name = Quieres asociar automáticamente los {0} ficheros structure con las secuencias del alineamiento que tengan el mismo nombre? -label.automatically_associate_structure_files_by_name = Asociar los ficheros structure por nombre automáticamente +label.automatically_associate_structure_files_with_sequences_same_name = Quieres asociar automáticamente los {0} ficheros estructura con las secuencias del alineamiento que tengan el mismo nombre? +label.automatically_associate_structure_files_by_name = Asociar los ficheros estructura por nombre automáticamente label.ignore_unmatched_dropped_files_info = Quieres ignorar los {0} ficheros cuyos nombres no coincidan con ningún IDs de las secuencias ? label.ignore_unmatched_dropped_files = Ignorar los ficheros sin coincidencias? label.enter_view_name = Introduzca un nombre para la vista @@ -720,10 +720,10 @@ label.select_columns_containing = Seleccione las columnas que contengan label.select_columns_not_containing = Seleccione las columnas que no contengan option.trim_retrieved_seqs = Ajustar las secuencias recuperadas label.trim_retrieved_sequences = Cuando la secuencia de referencia es más larga que la secuencia con la que está trabajando, sólo se mantienen las subsecuencias relevantes. -label.use_sequence_id_1 = Utilice $SEQUENCE_ID$ o $SEQUENCE_ID=//=$ -label.use_sequence_id_2 = para embeber el id de la secuencia en una URL -label.use_sequence_id_3 = Utilice $SEQUENCE_NAME$ de manera similar para embeber -label.use_sequence_id_4 = el nombre de la secuencia +label.use_sequence_id_1 = Utilice $DB_ACCESSION$ o $DB_ACCESSION=//=$ +label.use_sequence_id_2 = para embeber el ID de accesión en una URL +label.use_sequence_id_3 = Utilice $SEQUENCE_ID$ de manera similar para embeber +label.use_sequence_id_4 = el ID de la secuencia label.ws_parameters_for = Parámetros para {0} label.switch_server = Cambiar servidor label.open_jabaws_web_page = Abra el página principal del servidor JABAWS en un navegador web @@ -1070,7 +1070,7 @@ warn.user_defined_width_requirements = La anchura definida por el usuario para l label.couldnt_create_sequence_fetcher = No es posible crear SequenceFetcher warn.couldnt_create_sequence_fetcher_client = No es posible crear el cliente de recuperador de secuencias. Comprueba el fichero de log para más detalles. warn.server_didnt_pass_validation = El servicio no ha pasado la validaci\u00F3n.\nCompruebe la consola de Jalview para m\u00E1s detalles. -warn.url_must_contain = La URL de la secuencia debe contener $SEQUENCE_ID$ o un regex $SEQUENCE_ID=//=$ +warn.url_must_contain = La URL de la secuencia debe contener $SEQUENCE_ID$, $DB_ACCESSION$ o un regex info.validate_jabaws_server = \u00BFValidar el servidor JabaWS?\n(Consulte la consola de salida para obtener los resultados) label.test_server = ¿Probar servidor? info.you_want_jalview_to_find_uniprot_accessions = \u00BFDesea que Jalview encuentre\nUniprot Accession ids para los nombres de secuencias dados? @@ -1269,4 +1269,8 @@ status.exporting_alignment_as_x_file = Exportando alineamiento como fichero tipo label.column = Columna label.cant_map_cds = No se pudo mapear CDS a proteína\nDatos CDS faltantes o incompletos label.operation_failed = Operación fallada +label.SEQUENCE_ID_no_longer_used = $SEQUENCE_ID$ no se utiliza más para accesiones DB +label.SEQUENCE_ID_for_DB_ACCESSION1 = Por favor, revise sus URLs en la pestaña 'Conexiones' de la ventana de Preferencias: +label.SEQUENCE_ID_for_DB_ACCESSION2 = URL enlaza usando '$SEQUENCE_ID$' para accesiones DB ahora usar '$DB_ACCESSION$'. +label.do_not_display_again = No mostrar este mensaje de nuevo label.output_seq_details = Seleccionar Detalles de la secuencia para ver todas diff --git a/src/MCview/PDBChain.java b/src/MCview/PDBChain.java index 7774dac..783a4e2 100755 --- a/src/MCview/PDBChain.java +++ b/src/MCview/PDBChain.java @@ -31,6 +31,7 @@ import jalview.schemes.ColourSchemeI; import jalview.schemes.ResidueProperties; import jalview.structure.StructureImportSettings; import jalview.structure.StructureMapping; +import jalview.util.Comparison; import java.awt.Color; import java.util.List; @@ -146,7 +147,9 @@ public class PDBChain pdbpos++; } - if (as.astr1.charAt(i) == as.astr2.charAt(i)) + boolean sameResidue = Comparison.isSameResidue(as.astr1.charAt(i), + as.astr2.charAt(i), false); + if (sameResidue) { if (pdbpos >= residues.size()) { diff --git a/src/jalview/analysis/AAFrequency.java b/src/jalview/analysis/AAFrequency.java index 61e11c4..6bdffe1 100755 --- a/src/jalview/analysis/AAFrequency.java +++ b/src/jalview/analysis/AAFrequency.java @@ -20,12 +20,15 @@ */ package jalview.analysis; -import jalview.analysis.ResidueCount.SymbolCounts; import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; +import jalview.datamodel.Profile; +import jalview.datamodel.ProfileI; +import jalview.datamodel.ResidueCount; import jalview.datamodel.SequenceI; +import jalview.datamodel.ResidueCount.SymbolCounts; import jalview.ext.android.SparseIntArray; import jalview.util.Comparison; import jalview.util.Format; @@ -62,13 +65,13 @@ public class AAFrequency } } - public static final Profile[] calculate(List list, + public static final ProfileI[] calculate(List list, int start, int end) { return calculate(list, start, end, false); } - public static final Profile[] calculate(List sequences, + public static final ProfileI[] calculate(List sequences, int start, int end, boolean profile) { SequenceI[] seqs = new SequenceI[sequences.size()]; @@ -84,7 +87,7 @@ public class AAFrequency } } - Profile[] reply = new Profile[width]; + ProfileI[] reply = new ProfileI[width]; if (end >= width) { @@ -110,7 +113,7 @@ public class AAFrequency * if true, store all symbol counts */ public static final void calculate(final SequenceI[] sequences, - int start, int end, Profile[] result, boolean saveFullProfile) + int start, int end, ProfileI[] result, boolean saveFullProfile) { // long now = System.currentTimeMillis(); int seqCount = sequences.length; @@ -170,7 +173,7 @@ public class AAFrequency int maxCount = residueCounts.getModalCount(); String maxResidue = residueCounts.getResiduesForCount(maxCount); int gapCount = residueCounts.getGapCount(); - Profile profile = new Profile(seqCount, gapCount, maxCount, + ProfileI profile = new Profile(seqCount, gapCount, maxCount, maxResidue); if (saveFullProfile) @@ -231,7 +234,7 @@ public class AAFrequency * number of sequences */ public static void completeConsensus(AlignmentAnnotation consensus, - Profile[] profiles, int iStart, int width, boolean ignoreGaps, + ProfileI[] profiles, int iStart, int width, boolean ignoreGaps, boolean showSequenceLogo, long nseq) { // long now = System.currentTimeMillis(); @@ -249,7 +252,7 @@ public class AAFrequency for (int i = iStart; i < width; i++) { - Profile profile; + ProfileI profile; if (i >= profiles.length || ((profile = profiles[i]) == null)) { /* @@ -299,7 +302,7 @@ public class AAFrequency * the number of decimal places to format percentages to * @return */ - static String getTooltip(Profile profile, float pid, + static String getTooltip(ProfileI profile, float pid, boolean showSequenceLogo, boolean ignoreGaps, int dp) { ResidueCount counts = profile.getCounts(); @@ -350,7 +353,7 @@ public class AAFrequency * calculations * @return */ - public static int[] extractProfile(Profile profile, + public static int[] extractProfile(ProfileI profile, boolean ignoreGaps) { int[] rtnval = new int[64]; diff --git a/src/jalview/analysis/AlignSeq.java b/src/jalview/analysis/AlignSeq.java index 3ad3188..86bf721 100755 --- a/src/jalview/analysis/AlignSeq.java +++ b/src/jalview/analysis/AlignSeq.java @@ -620,7 +620,10 @@ public class AlignSeq { if ((i + (j * len)) < astr1.length()) { - if (astr1.charAt(i + (j * len)) == astr2.charAt(i + (j * len)) + boolean sameChar = Comparison.isSameResidue( + astr1.charAt(i + (j * len)), astr2.charAt(i + (j * len)), + false); + if (sameChar && !jalview.util.Comparison.isGap(astr1.charAt(i + (j * len)))) { diff --git a/src/jalview/analysis/Conservation.java b/src/jalview/analysis/Conservation.java index 8127747..7b9da46 100755 --- a/src/jalview/analysis/Conservation.java +++ b/src/jalview/analysis/Conservation.java @@ -22,25 +22,33 @@ package jalview.analysis; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.Annotation; +import jalview.datamodel.ResidueCount; +import jalview.datamodel.ResidueCount.SymbolCounts; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceI; -import jalview.ext.android.SparseIntArray; import jalview.schemes.ResidueProperties; +import jalview.util.Comparison; import java.awt.Color; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.TreeMap; import java.util.Vector; /** * Calculates conservation values for a given set of sequences - * - * @author $author$ - * @version $Revision$ */ public class Conservation { + /* + * need to have a minimum of 3% of sequences with a residue + * for it to be included in the conservation calculation + */ + private static final int THRESHOLD_PERCENT = 3; + + private static final int TOUPPERCASE = 'a' - 'A'; + SequenceI[] sequences; int start; @@ -54,6 +62,11 @@ public class Conservation boolean seqNumsChanged = false; // updated after any change via calcSeqNum; + /* + * a map per column with {property, conservation} where conservation value is + * 1 (property is conserved), 0 (absence of property is conserved) or -1 + * (property is not conserved i.e. column has residues with and without it) + */ Map[] total; boolean canonicaliseAa = true; // if true then conservation calculation will @@ -70,6 +83,9 @@ public class Conservation private Sequence consSequence; + /* + * percentage of residues in a column to qualify for counting conservation + */ private int threshold; private String name = ""; @@ -79,12 +95,10 @@ public class Conservation private String[] consSymbs; /** - * Creates a new Conservation object. + * Constructor using default threshold of 3% * * @param name * Name of conservation - * @param threshold - * to count the residues in residueHash(). commonly used value is 3 * @param sequences * sequences to be used in calculation * @param start @@ -92,6 +106,27 @@ public class Conservation * @param end * end residue position */ + public Conservation(String name, List sequences, int start, + int end) + { + this(name, THRESHOLD_PERCENT, sequences, start, end); + } + + /** + * Constructor + * + * @param name + * Name of conservation + * @param threshold + * percentage of sequences at or below which property conservation is + * ignored + * @param sequences + * sequences to be used in calculation + * @param start + * start column position + * @param end + * end column position + */ public Conservation(String name, int threshold, List sequences, int start, int end) { @@ -189,154 +224,187 @@ public class Conservation */ public void calculate() { - int jSize = sequences.length; - // int[] values; // Replaces residueHash - SparseIntArray values = new SparseIntArray(); + int height = sequences.length; total = new Map[maxLength]; - for (int i = start; i <= end; i++) + for (int column = start; column <= end; column++) + { + ResidueCount values = countResidues(column); + + /* + * percentage count at or below which we ignore residues + */ + int thresh = (threshold * height) / 100; + + /* + * check observed residues in column and record whether each + * physico-chemical property is conserved (+1), absence conserved (0), + * or not conserved (-1) + * Using TreeMap means properties are displayed in alphabetical order + */ + Map resultHash = new TreeMap(); + SymbolCounts symbolCounts = values.getSymbolCounts(); + char[] symbols = symbolCounts.symbols; + int[] counts = symbolCounts.values; + for (int j = 0; j < symbols.length; j++) + { + char c = symbols[j]; + if (counts[j] > thresh) + { + recordConservation(resultHash, String.valueOf(c)); + } + } + if (values.getGapCount() > thresh) + { + recordConservation(resultHash, "-"); + } + + if (total.length > 0) + { + total[column - start] = resultHash; + } + } + } + + /** + * Updates the conservation results for an observed residue + * + * @param resultMap + * a map of {property, conservation} where conservation value is +1 + * (all residues have the property), 0 (no residue has the property) + * or -1 (some do, some don't) + * @param res + */ + protected static void recordConservation(Map resultMap, + String res) + { + res = res.toUpperCase(); + for (Entry> property : ResidueProperties.propHash + .entrySet()) { - // values = new int[255]; - values.clear(); + String propertyName = property.getKey(); + Integer residuePropertyValue = property.getValue().get(res); - for (int j = 0; j < jSize; j++) + if (!resultMap.containsKey(propertyName)) { - if (sequences[j].getLength() > i) + /* + * first time we've seen this residue - note whether it has this property + */ + if (residuePropertyValue != null) { - char c = sequences[j].getCharAt(i); - - if (canonicaliseAa) - { // lookup the base aa code symbol - c = (char) ResidueProperties.aaIndex[sequences[j].getCharAt(i)]; - if (c > 20) - { - c = '-'; - } - else - { - // recover canonical aa symbol - c = ResidueProperties.aa[c].charAt(0); - } - } - else - { - // original behaviour - operate on ascii symbols directly - // No need to check if its a '-' - if (c == '.' || c == ' ') - { - c = '-'; - } - - c = toUpperCase(c); - } - // values[c]++; - values.add(c, 1); + resultMap.put(propertyName, residuePropertyValue); } else { - // values['-']++; - values.add('-', 1); + /* + * unrecognised residue - use default value for property + */ + resultMap.put(propertyName, property.getValue().get("-")); } } + else + { + Integer currentResult = resultMap.get(propertyName); + if (currentResult.intValue() != -1 + && !currentResult.equals(residuePropertyValue)) + { + /* + * property is unconserved - residues seen both with and without it + */ + resultMap.put(propertyName, Integer.valueOf(-1)); + } + } + } + } - // What is the count threshold to count the residues in residueHash() - int thresh = (threshold * jSize) / 100; + /** + * Counts residues (upper-cased) and gaps in the given column + * + * @param column + * @return + */ + protected ResidueCount countResidues(int column) + { + ResidueCount values = new ResidueCount(false); - // loop over all the found residues - // Hashtable resultHash = new Hashtable(); - Map resultHash = new TreeMap(); - // for (char v = '-'; v < 'Z'; v++) - for (int key = 0; key < values.size(); key++) + for (int row = 0; row < sequences.length; row++) + { + if (sequences[row].getLength() > column) { - char v = (char) values.keyAt(key); - // if (values[v] > thresh) - if (values.valueAt(key) > thresh) + char c = sequences[row].getCharAt(column); + if (canonicaliseAa) { - String res = String.valueOf(v); - - // Now loop over the properties - for (String type : ResidueProperties.propHash.keySet()) - { - Map ht = ResidueProperties.propHash.get(type); - - // Have we ticked this before? - if (!resultHash.containsKey(type)) - { - if (ht.containsKey(res)) - { - resultHash.put(type, ht.get(res)); - } - else - { - resultHash.put(type, ht.get("-")); - } - } - else if (!resultHash.get(type).equals(ht.get(res))) - { - resultHash.put(type, new Integer(-1)); - } - } + int index = ResidueProperties.aaIndex[c]; + c = index > 20 ? '-' : ResidueProperties.aa[index].charAt(0); + } + else + { + c = toUpperCase(c); + } + if (Comparison.isGap(c)) + { + values.addGap(); + } + else + { + values.add(c); } } - - if (total.length > 0) + else { - total[i - start] = resultHash; + values.addGap(); } } + return values; } - /***************************************************************************** - * count conservation for the j'th column of the alignment + /** + * Counts conservation and gaps for a column of the alignment * - * @return { gap count, conserved residue count} + * @return { 1 if fully conserved, else 0, gap count } */ - public int[] countConsNGaps(int j) + public int[] countConservationAndGaps(int column) { - int count = 0; - int cons = 0; - int nres = 0; - int[] r = new int[2]; - char f = '$'; - int i, iSize = sequences.length; - char c; + int gapCount = 0; + boolean fullyConserved = true; + int iSize = sequences.length; - for (i = 0; i < iSize; i++) + if (iSize == 0) + { + return new int[] { 0, 0 }; + } + + char lastRes = '0'; + for (int i = 0; i < iSize; i++) { - if (j >= sequences[i].getLength()) + if (column >= sequences[i].getLength()) { - count++; + gapCount++; continue; } - c = sequences[i].getCharAt(j); // gaps do not have upper/lower case + char c = sequences[i].getCharAt(column); // gaps do not have upper/lower case - if (jalview.util.Comparison.isGap((c))) + if (Comparison.isGap((c))) { - count++; + gapCount++; } else { c = toUpperCase(c); - nres++; - - if (nres == 1) + if (lastRes == '0') { - f = c; - cons++; + lastRes = c; } - else if (f == c) + if (c != lastRes) { - cons++; + fullyConserved = false; } } } - r[0] = (nres == cons) ? 1 : 0; - r[1] = count; - + int[] r = new int[] { fullyConserved ? 1 : 0, gapCount }; return r; } @@ -351,7 +419,7 @@ public class Conservation { if ('a' <= c && c <= 'z') { - c -= (32); // 32 = 'a' - 'A' + c -= TOUPPERCASE; } return c; } @@ -359,14 +427,17 @@ public class Conservation /** * Calculates the conservation sequence * - * @param consflag - * if true, positive conservation; false calculates negative - * conservation - * @param percentageGaps - * commonly used value is 25 + * @param positiveOnly + * if true, calculate positive conservation; else calculate both + * positive and negative conservation + * @param maxPercentageGaps + * the percentage of gaps in a column, at or above which no + * conservation is asserted */ - public void verdict(boolean consflag, float percentageGaps) + public void verdict(boolean positiveOnly, float maxPercentageGaps) { + // TODO call this at the end of calculate(), should not be a public method + StringBuilder consString = new StringBuilder(end); // NOTE THIS SHOULD CHECK IF THE CONSEQUENCE ALREADY @@ -379,56 +450,43 @@ public class Conservation consSymbs = new String[end - start + 1]; for (int i = start; i <= end; i++) { - int[] gapcons = countConsNGaps(i); + int[] gapcons = countConservationAndGaps(i); + boolean fullyConserved = gapcons[0] == 1; int totGaps = gapcons[1]; - float pgaps = ((float) totGaps * 100) / sequences.length; - StringBuilder positives = new StringBuilder(64); - StringBuilder negatives = new StringBuilder(32); - // consSymbs[i - start] = ""; + float pgaps = (totGaps * 100f) / sequences.length; - if (percentageGaps > pgaps) + if (maxPercentageGaps > pgaps) { Map resultHash = total[i - start]; - // Now find the verdict int count = 0; + StringBuilder positives = new StringBuilder(64); + StringBuilder negatives = new StringBuilder(32); for (String type : resultHash.keySet()) { int result = resultHash.get(type).intValue(); - // Do we want to count +ve conservation or +ve and -ve cons.? - if (consflag) + if (result == -1) { - if (result == 1) - { - // consSymbs[i - start] = type + " " + consSymbs[i - start]; - positives.append(positives.length() == 0 ? "" : " "); - positives.append(type); - count++; - } + /* + * not conserved (present or absent) + */ + continue; } - else + count++; + if (result == 1) { - if (result != -1) - { - if (result == 0) - { - /* - * add negatively conserved properties on the end - */ - // consSymbs[i - start] = consSymbs[i - start] + " !" + type; - negatives.append(negatives.length() == 0 ? "" : " "); - negatives.append("!").append(type); - } - else - { - /* - * put positively conserved properties on the front - */ - // consSymbs[i - start] = type + " " + consSymbs[i - start]; - positives.append(positives.length() == 0 ? "" : " "); - positives.append(type); - } - count++; - } + /* + * positively conserved property (all residues have it) + */ + positives.append(positives.length() == 0 ? "" : " "); + positives.append(type); + } + if (result == 0 && !positiveOnly) + { + /* + * absense of property is conserved (all residues lack it) + */ + negatives.append(negatives.length() == 0 ? "" : " "); + negatives.append("!").append(type); } } if (negatives.length() > 0) @@ -443,7 +501,7 @@ public class Conservation } else { - consString.append((gapcons[0] == 1) ? "*" : "+"); + consString.append(fullyConserved ? "*" : "+"); } } else @@ -747,29 +805,27 @@ public class Conservation * * @param name * - name of conservation - * @param threshold - * - minimum number of conserved residues needed to indicate - * conservation (typically 3) * @param seqs * @param start * first column in calculation window * @param end * last column in calculation window - * @param posOrNeg - * positive (true) or negative (false) conservation - * @param consPercGaps + * @param positiveOnly + * calculate positive (true) or positive and negative (false) + * conservation + * @param maxPercentGaps * percentage of gaps tolerated in column * @param calcQuality * flag indicating if alignment quality should be calculated * @return Conservation object ready for use in visualization */ public static Conservation calculateConservation(String name, - int threshold, List seqs, int start, int end, - boolean posOrNeg, int consPercGaps, boolean calcQuality) + List seqs, int start, int end, boolean positiveOnly, + int maxPercentGaps, boolean calcQuality) { - Conservation cons = new Conservation(name, threshold, seqs, start, end); + Conservation cons = new Conservation(name, seqs, start, end); cons.calculate(); - cons.verdict(posOrNeg, consPercGaps); + cons.verdict(positiveOnly, maxPercentGaps); if (calcQuality) { @@ -778,4 +834,24 @@ public class Conservation return cons; } + + /** + * Returns the computed tooltip (annotation description) for a given column. + * The tip is empty if the conservation score is zero, otherwise holds the + * conserved properties (and, optionally, properties whose absence is + * conserved). + * + * @param column + * @return + */ + String getTooltip(int column) + { + char[] sequence = getConsSequence().getSequence(); + char val = column < sequence.length ? sequence[column] : '-'; + boolean hasConservation = val != '-' && val != '0'; + int consp = column - start; + String tip = (hasConservation && consp > -1 && consp < consSymbs.length) ? consSymbs[consp] + : ""; + return tip; + } } diff --git a/src/jalview/api/AlignViewportI.java b/src/jalview/api/AlignViewportI.java index 70463e7..e30a052 100644 --- a/src/jalview/api/AlignViewportI.java +++ b/src/jalview/api/AlignViewportI.java @@ -21,12 +21,12 @@ package jalview.api; import jalview.analysis.Conservation; -import jalview.analysis.Profile; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentView; import jalview.datamodel.CigarArray; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.ProfileI; import jalview.datamodel.SequenceCollectionI; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; @@ -82,7 +82,7 @@ public interface AlignViewportI extends ViewStyleI ColumnSelection getColumnSelection(); - Profile[] getSequenceConsensusHash(); + ProfileI[] getSequenceConsensusHash(); /** * Get consensus data table for the cDNA complement of this alignment (if any) @@ -145,7 +145,7 @@ public interface AlignViewportI extends ViewStyleI * * @param hconsensus */ - void setSequenceConsensusHash(Profile[] hconsensus); + void setSequenceConsensusHash(ProfileI[] hconsensus); /** * Set the cDNA complement consensus for the viewport diff --git a/src/jalview/appletgui/APopupMenu.java b/src/jalview/appletgui/APopupMenu.java index 1544265..160224b 100644 --- a/src/jalview/appletgui/APopupMenu.java +++ b/src/jalview/appletgui/APopupMenu.java @@ -29,7 +29,6 @@ import jalview.commands.EditCommand; import jalview.commands.EditCommand.Action; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; -import jalview.datamodel.DBRefEntry; import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceGroup; @@ -59,6 +58,7 @@ import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -253,122 +253,9 @@ public class APopupMenu extends java.awt.PopupMenu implements if (links != null && links.size() > 0) { - Menu linkMenu = new Menu(MessageManager.getString("action.link")); - for (int i = 0; i < links.size(); i++) - { - String link = links.elementAt(i); - UrlLink urlLink = new UrlLink(link); - if (!urlLink.isValid()) - { - System.err.println(urlLink.getInvalidMessage()); - continue; - } - final String target = urlLink.getTarget(); // link.substring(0, - // link.indexOf("|")); - final String label = urlLink.getLabel(); - if (seq != null && urlLink.isDynamic()) - { - - // collect matching db-refs - DBRefEntry[] dbr = jalview.util.DBRefUtils.selectRefs( - seq.getDBRefs(), new String[] { target }); - // collect id string too - String id = seq.getName(); - String descr = seq.getDescription(); - if (descr != null && descr.length() < 1) - { - descr = null; - } - if (dbr != null) - { - for (int r = 0; r < dbr.length; r++) - { - if (id != null && dbr[r].getAccessionId().equals(id)) - { - // suppress duplicate link creation for the bare sequence ID - // string with this link - id = null; - } - // create Bare ID link for this RUL - String[] urls = urlLink.makeUrls(dbr[r].getAccessionId(), - true); - if (urls != null) - { - for (int u = 0; u < urls.length; u += 2) - { - addshowLink(linkMenu, label + "|" + urls[u], urls[u + 1]); - } - } - } - } - if (id != null) - { - // create Bare ID link for this RUL - String[] urls = urlLink.makeUrls(id, true); - if (urls != null) - { - for (int u = 0; u < urls.length; u += 2) - { - addshowLink(linkMenu, label, urls[u + 1]); - } - } - // addshowLink(linkMenu, target, url_pref + id + url_suff); - } - // Now construct URLs from description but only try to do it for regex - // URL links - if (descr != null && urlLink.getRegexReplace() != null) - { - // create link for this URL from description only if regex matches - String[] urls = urlLink.makeUrls(descr, true); - if (urls != null) - { - for (int u = 0; u < urls.length; u += 2) - { - addshowLink(linkMenu, label, urls[u + 1]); - } - } - } - } - else - { - addshowLink(linkMenu, target, urlLink.getUrl_prefix()); // link.substring(link.lastIndexOf("|")+1)); - } - /* - * final String url; - * - * if (link.indexOf("$SEQUENCE_ID$") > -1) { // Substitute SEQUENCE_ID - * string and any matching database reference accessions String url_pref - * = link.substring(link.indexOf("|") + 1, - * link.indexOf("$SEQUENCE_ID$")); - * - * String url_suff = link.substring(link.indexOf("$SEQUENCE_ID$") + 13); - * // collect matching db-refs DBRefEntry[] dbr = - * jalview.util.DBRefUtils.selectRefs(seq.getDBRef(), new - * String[]{target}); // collect id string too String id = - * seq.getName(); if (id.indexOf("|") > -1) { id = - * id.substring(id.lastIndexOf("|") + 1); } if (dbr!=null) { for (int - * r=0;r 0) - { - if (seq != null) - { - seqMenu.add(linkMenu); - } - else - { - add(linkMenu); - } - } + addFeatureLinks(seq, links); } + // TODO: add group link menu entry here if (seq != null) { @@ -414,6 +301,71 @@ public class APopupMenu extends java.awt.PopupMenu implements } /** + * Adds a 'Link' menu item with a sub-menu item for each hyperlink provided. + * + * @param seq + * @param links + */ + void addFeatureLinks(final SequenceI seq, List links) + { + Menu linkMenu = new Menu(MessageManager.getString("action.link")); + Map> linkset = new LinkedHashMap>(); + + for (String link : links) + { + UrlLink urlLink = null; + try + { + urlLink = new UrlLink(link); + } catch (Exception foo) + { + System.err.println("Exception for URLLink '" + link + "': " + + foo.getMessage()); + continue; + } + + if (!urlLink.isValid()) + { + System.err.println(urlLink.getInvalidMessage()); + continue; + } + + urlLink.createLinksFromSeq(seq, linkset); + } + + addshowLinks(linkMenu, linkset.values()); + + // disable link menu if there are no valid entries + if (linkMenu.getItemCount() > 0) + { + linkMenu.setEnabled(true); + } + else + { + linkMenu.setEnabled(false); + } + + if (seq != null) + { + seqMenu.add(linkMenu); + } + else + { + add(linkMenu); + } + + } + + private void addshowLinks(Menu linkMenu, Collection> linkset) + { + for (List linkstrset : linkset) + { + // split linkstr into label and url + addshowLink(linkMenu, linkstrset.get(1), linkstrset.get(3)); + } + } + + /** * Build menus for annotation types that may be shown or hidden, and for * 'reference annotations' that may be added to the alignment. */ @@ -1205,11 +1157,10 @@ public class APopupMenu extends java.awt.PopupMenu implements if (conservationMenuItem.getState()) { - - sg.cs.setConservation(Conservation.calculateConservation("Group", 3, - sg.getSequences(ap.av.getHiddenRepSequences()), 0, ap.av - .getAlignment().getWidth(), false, ap.av - .getConsPercGaps(), false)); + sg.cs.setConservation(Conservation.calculateConservation("Group", sg + .getSequences(ap.av.getHiddenRepSequences()), 0, ap.av + .getAlignment().getWidth(), false, ap.av.getConsPercGaps(), + false)); SliderPanel.setConservationSlider(ap, sg.cs, sg.getName()); SliderPanel.showConservationSlider(); } diff --git a/src/jalview/appletgui/AppletJmol.java b/src/jalview/appletgui/AppletJmol.java index b925284..133cc94 100644 --- a/src/jalview/appletgui/AppletJmol.java +++ b/src/jalview/appletgui/AppletJmol.java @@ -180,7 +180,7 @@ public class AppletJmol extends EmbmenuFrame implements this.ap = ap; jmb = new AppletJmolBinding(this, ap.getStructureSelectionManager(), new PDBEntry[] { pdbentry }, new SequenceI[][] { seq }, - new String[][] { chains }, protocol); + protocol); jmb.setColourBySequence(true); if (pdbentry.getId() == null || pdbentry.getId().length() < 1) { @@ -369,7 +369,7 @@ public class AppletJmol extends EmbmenuFrame implements jmb.loadInline(string); } - void setChainMenuItems(Vector chains) + void setChainMenuItems(List chains) { chainMenu.removeAll(); @@ -588,7 +588,7 @@ public class AppletJmol extends EmbmenuFrame implements repaint(); return; } - setChainMenuItems(jmb.chainNames); + setChainMenuItems(jmb.getChainNames()); jmb.colourBySequence(ap); setTitle(jmb.getViewerTitle()); diff --git a/src/jalview/appletgui/AppletJmolBinding.java b/src/jalview/appletgui/AppletJmolBinding.java index 6ec5b4d..3a36ed5 100644 --- a/src/jalview/appletgui/AppletJmolBinding.java +++ b/src/jalview/appletgui/AppletJmolBinding.java @@ -45,9 +45,9 @@ class AppletJmolBinding extends JalviewJmolBinding public AppletJmolBinding(AppletJmol appletJmol, StructureSelectionManager sSm, PDBEntry[] pdbentry, - SequenceI[][] seq, String[][] chains, String protocol) + SequenceI[][] seq, String protocol) { - super(sSm, pdbentry, seq, chains, protocol); + super(sSm, pdbentry, seq, protocol); appletJmolBinding = appletJmol; } @@ -113,12 +113,14 @@ class AppletJmolBinding extends JalviewJmolBinding appletJmolBinding.updateTitleAndMenus(); } + @Override public void updateColours(Object source) { AlignmentPanel ap = (AlignmentPanel) source; colourBySequence(ap); } + @Override public void showUrl(String url) { try @@ -143,6 +145,7 @@ class AppletJmolBinding extends JalviewJmolBinding // do nothing. } + @Override public void selectionChanged(BS arg0) { // TODO Auto-generated method stub diff --git a/src/jalview/appletgui/ExtJmol.java b/src/jalview/appletgui/ExtJmol.java index 929a871..5ffbaa4 100644 --- a/src/jalview/appletgui/ExtJmol.java +++ b/src/jalview/appletgui/ExtJmol.java @@ -49,11 +49,11 @@ public class ExtJmol extends JalviewJmolBinding private AlignmentPanel ap; protected ExtJmol(jalview.appletgui.AlignFrame alframe, - PDBEntry[] pdbentry, SequenceI[][] seq, String[][] chains, + PDBEntry[] pdbentry, SequenceI[][] seq, String protocol) { super(alframe.alignPanel.getStructureSelectionManager(), pdbentry, seq, - chains, protocol); + protocol); } public ExtJmol(Viewer viewer, AlignmentPanel alignPanel, @@ -64,6 +64,7 @@ public class ExtJmol extends JalviewJmolBinding notifyFileLoaded(null, null, null, null, 0); } + @Override public void updateColours(Object source) { @@ -71,6 +72,7 @@ public class ExtJmol extends JalviewJmolBinding } + @Override public void showUrl(String arg0) { showUrl(arg0, "jmol"); @@ -126,6 +128,7 @@ public class ExtJmol extends JalviewJmolBinding // ignore } + @Override public void selectionChanged(BS arg0) { System.out.println(arg0); diff --git a/src/jalview/appletgui/IdPanel.java b/src/jalview/appletgui/IdPanel.java index 2cb3060..182f20e 100755 --- a/src/jalview/appletgui/IdPanel.java +++ b/src/jalview/appletgui/IdPanel.java @@ -246,7 +246,14 @@ public class IdPanel extends Panel implements MouseListener, url = null; continue; } - ; + + if (urlLink.usesDBAccession()) + { + // this URL requires an accession id, not the name of a sequence + url = null; + continue; + } + if (!urlLink.isValid()) { System.err.println(urlLink.getInvalidMessage()); diff --git a/src/jalview/appletgui/TreeCanvas.java b/src/jalview/appletgui/TreeCanvas.java index 3b509e5..8292a5a 100755 --- a/src/jalview/appletgui/TreeCanvas.java +++ b/src/jalview/appletgui/TreeCanvas.java @@ -676,8 +676,8 @@ public class TreeCanvas extends Panel implements MouseListener, if (av.getGlobalColourScheme() != null && av.getGlobalColourScheme().conservationApplied()) { - Conservation c = new Conservation("Group", 3, - sg.getSequences(null), sg.getStartRes(), sg.getEndRes()); + Conservation c = new Conservation("Group", sg.getSequences(null), + sg.getStartRes(), sg.getEndRes()); c.calculate(); c.verdict(false, av.getConsPercGaps()); diff --git a/src/jalview/bin/Jalview.java b/src/jalview/bin/Jalview.java index 164ba27..bcb4e7b 100755 --- a/src/jalview/bin/Jalview.java +++ b/src/jalview/bin/Jalview.java @@ -51,6 +51,7 @@ import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.MalformedURLException; import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.security.AllPermission; import java.security.CodeSource; @@ -650,22 +651,29 @@ public class Jalview { File imageFile = new File(file); imageName = imageFile.getName(); - new HtmlSvgOutput(new File(file), af.alignPanel); + HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel); + htmlSVG.exportHTML(file); + System.out.println("Creating HTML image: " + file); continue; } else if (format.equalsIgnoreCase("biojsmsa")) { - BioJsHTMLOutput.updateBioJS(); + if (file == null) + { + System.err.println("The output html file must not be null"); + return; + } try { - Thread.sleep(1500); - } catch (InterruptedException e) + BioJsHTMLOutput + .refreshVersionInfo(BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY); + } catch (URISyntaxException e) { e.printStackTrace(); } - BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel, af); - bjs.exportJalviewAlignmentAsBioJsHtmlFile(file); + BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel); + bjs.exportHTML(file); System.out.println("Creating BioJS MSA Viwer HTML file: " + file); continue; diff --git a/src/jalview/datamodel/PDBEntry.java b/src/jalview/datamodel/PDBEntry.java index 6a6ccd0..9c3a8e7 100755 --- a/src/jalview/datamodel/PDBEntry.java +++ b/src/jalview/datamodel/PDBEntry.java @@ -121,16 +121,6 @@ public class PDBEntry { } - /** - * Constructor given file path and PDB id. - * - * @param filePath - */ - // public PDBEntry(String filePath, String pdbId) - // { - // this.file = filePath; - // this.id = pdbId; - // } public PDBEntry(String pdbId, String chain, PDBEntry.Type type, String filePath) diff --git a/src/jalview/analysis/Profile.java b/src/jalview/datamodel/Profile.java similarity index 59% rename from src/jalview/analysis/Profile.java rename to src/jalview/datamodel/Profile.java index d94d031..5464596 100644 --- a/src/jalview/analysis/Profile.java +++ b/src/jalview/datamodel/Profile.java @@ -1,22 +1,21 @@ -package jalview.analysis; +package jalview.datamodel; /** - * A data bean to hold the result of computing a profile for a column of an - * alignment + * A profile for one column of an alignment * * @author gmcarstairs * */ -public class Profile +public class Profile implements ProfileI { /* - * counts of keys (chars) + * an object holding counts of symbols in the profile */ private ResidueCount counts; /* - * the number of sequences in the profile + * the number of sequences (gapped or not) in the profile */ private int height; @@ -57,24 +56,19 @@ public class Profile this.modalResidue = modalRes; } - /** - * Set the full profile of counts - * - * @param residueCounts + /* (non-Javadoc) + * @see jalview.datamodel.ProfileI#setCounts(jalview.datamodel.ResidueCount) */ + @Override public void setCounts(ResidueCount residueCounts) { this.counts = residueCounts; } - /** - * Returns the percentage identity of the profile, i.e. the highest proportion - * of conserved (equal) symbols. The percentage is as a fraction of all - * sequences, or only ungapped sequences if flag ignoreGaps is set true. - * - * @param ignoreGaps - * @return + /* (non-Javadoc) + * @see jalview.datamodel.ProfileI#getPercentageIdentity(boolean) */ + @Override public float getPercentageIdentity(boolean ignoreGaps) { if (height == 0) @@ -93,63 +87,55 @@ public class Profile return pid; } - /** - * Returns the full symbol counts for this profile - * - * @return + /* (non-Javadoc) + * @see jalview.datamodel.ProfileI#getCounts() */ + @Override public ResidueCount getCounts() { return counts; } - /** - * Returns the number of sequences in the profile - * - * @return + /* (non-Javadoc) + * @see jalview.datamodel.ProfileI#getHeight() */ + @Override public int getHeight() { return height; } - /** - * Returns the number of sequences in the profile which had a gap character - * (or were too short to be included in this column's profile) - * - * @return + /* (non-Javadoc) + * @see jalview.datamodel.ProfileI#getGapped() */ + @Override public int getGapped() { return gapped; } - /** - * Returns the highest count for any symbol(s) in the profile - * - * @return + /* (non-Javadoc) + * @see jalview.datamodel.ProfileI#getMaxCount() */ + @Override public int getMaxCount() { return maxCount; } - /** - * Returns the symbol (or concatenated symbols) which have the highest count - * in the profile, or an empty string if there were no symbols counted - * - * @return + /* (non-Javadoc) + * @see jalview.datamodel.ProfileI#getModalResidue() */ + @Override public String getModalResidue() { return modalResidue; } - /** - * Answers the number of non-gapped sequences in the profile - * - * @return + /* (non-Javadoc) + * @see jalview.datamodel.ProfileI#getNonGapped() */ + @Override public int getNonGapped() { return height - gapped; diff --git a/src/jalview/datamodel/ProfileI.java b/src/jalview/datamodel/ProfileI.java new file mode 100644 index 0000000..cf2b394 --- /dev/null +++ b/src/jalview/datamodel/ProfileI.java @@ -0,0 +1,67 @@ +package jalview.datamodel; + +public interface ProfileI +{ + + /** + * Set the full profile of counts + * + * @param residueCounts + */ + public abstract void setCounts(ResidueCount residueCounts); + + /** + * Returns the percentage identity of the profile, i.e. the highest proportion + * of conserved (equal) symbols. The percentage is as a fraction of all + * sequences, or only ungapped sequences if flag ignoreGaps is set true. + * + * @param ignoreGaps + * @return + */ + public abstract float getPercentageIdentity(boolean ignoreGaps); + + /** + * Returns the full symbol counts for this profile + * + * @return + */ + public abstract ResidueCount getCounts(); + + /** + * Returns the number of sequences in the profile + * + * @return + */ + public abstract int getHeight(); + + /** + * Returns the number of sequences in the profile which had a gap character + * (or were too short to be included in this column's profile) + * + * @return + */ + public abstract int getGapped(); + + /** + * Returns the highest count for any symbol(s) in the profile + * + * @return + */ + public abstract int getMaxCount(); + + /** + * Returns the symbol (or concatenated symbols) which have the highest count + * in the profile, or an empty string if there were no symbols counted + * + * @return + */ + public abstract String getModalResidue(); + + /** + * Answers the number of non-gapped sequences in the profile + * + * @return + */ + public abstract int getNonGapped(); + +} \ No newline at end of file diff --git a/src/jalview/analysis/ResidueCount.java b/src/jalview/datamodel/ResidueCount.java similarity index 99% rename from src/jalview/analysis/ResidueCount.java rename to src/jalview/datamodel/ResidueCount.java index 75decf2..0d0348c 100644 --- a/src/jalview/analysis/ResidueCount.java +++ b/src/jalview/datamodel/ResidueCount.java @@ -1,4 +1,4 @@ -package jalview.analysis; +package jalview.datamodel; import jalview.util.Comparison; import jalview.util.Format; @@ -95,7 +95,7 @@ public class ResidueCount /* * keeps track of the maximum count value recorded - * (if this class every allows decrements, would need to + * (if this class ever allows decrements, would need to * calculate this on request instead) */ int maxCount; diff --git a/src/jalview/datamodel/SequenceFeature.java b/src/jalview/datamodel/SequenceFeature.java index c75d6f2..0baa78e 100755 --- a/src/jalview/datamodel/SequenceFeature.java +++ b/src/jalview/datamodel/SequenceFeature.java @@ -208,7 +208,9 @@ public class SequenceFeature } SequenceFeature sf = (SequenceFeature) o; - if (begin != sf.begin || end != sf.end || score != sf.score) + boolean sameScore = Float.isNaN(score) ? Float.isNaN(sf.score) + : score == sf.score; + if (begin != sf.begin || end != sf.end || !sameScore) { return false; } diff --git a/src/jalview/datamodel/SequenceGroup.java b/src/jalview/datamodel/SequenceGroup.java index 98fd8f2..ca90003 100755 --- a/src/jalview/datamodel/SequenceGroup.java +++ b/src/jalview/datamodel/SequenceGroup.java @@ -22,7 +22,6 @@ package jalview.datamodel; import jalview.analysis.AAFrequency; import jalview.analysis.Conservation; -import jalview.analysis.Profile; import jalview.schemes.ColourSchemeI; import java.awt.Color; @@ -528,7 +527,7 @@ public class SequenceGroup implements AnnotatedCollectionI boolean upd = false; try { - Profile[] cnsns = AAFrequency.calculate(sequences, startRes, + ProfileI[] cnsns = AAFrequency.calculate(sequences, startRes, endRes + 1, showSequenceLogo); if (consensus != null) { @@ -544,8 +543,8 @@ public class SequenceGroup implements AnnotatedCollectionI if ((conservation != null) || (cs != null && cs.conservationApplied())) { - Conservation c = new Conservation(groupName, 3, sequences, - startRes, endRes + 1); + Conservation c = new Conservation(groupName, sequences, startRes, + endRes + 1); c.calculate(); c.verdict(false, consPercGaps); if (conservation != null) @@ -600,9 +599,9 @@ public class SequenceGroup implements AnnotatedCollectionI c.completeAnnotations(conservation, null, startRes, endRes + 1); } - public Profile[] consensusData = null; + public ProfileI[] consensusData = null; - private void _updateConsensusRow(Profile[] cnsns, long nseq) + private void _updateConsensusRow(ProfileI[] cnsns, long nseq) { if (consensus == null) { diff --git a/src/jalview/ext/jmol/JalviewJmolBinding.java b/src/jalview/ext/jmol/JalviewJmolBinding.java index fbac400..56287a9 100644 --- a/src/jalview/ext/jmol/JalviewJmolBinding.java +++ b/src/jalview/ext/jmol/JalviewJmolBinding.java @@ -74,7 +74,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel Vector atomsPicked = new Vector(); - public Vector chainNames; + private List chainNames; Hashtable chainFile; @@ -99,10 +99,10 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel public Viewer viewer; public JalviewJmolBinding(StructureSelectionManager ssm, - PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains, + PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String protocol) { - super(ssm, pdbentry, sequenceIs, chains, protocol); + super(ssm, pdbentry, sequenceIs, protocol); /* * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(), * "jalviewJmol", ap.av.applet .getDocumentBase(), @@ -1083,7 +1083,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel fileLoadingError = null; String[] oldmodels = modelFileNames; modelFileNames = null; - chainNames = new Vector(); + chainNames = new ArrayList(); chainFile = new Hashtable(); boolean notifyLoaded = false; String[] modelfilenames = getPdbFile(); @@ -1143,6 +1143,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel for (int pe = 0; pe < getPdbCount(); pe++) { boolean matches = false; + addSequence(pe, getSequence()[pe]); if (fileName == null) { if (false) @@ -1194,7 +1195,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel String chid = new String(pdb.getId() + ":" + pdb.getChains().elementAt(i).id); chainFile.put(chid, fileName); - chainNames.addElement(chid); + chainNames.add(chid); } notifyLoaded = true; } @@ -1242,6 +1243,12 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel setLoadingFromArchive(false); } + @Override + public List getChainNames() + { + return chainNames; + } + public void notifyNewPickingModeMeasurement(int iatom, String strMeasure) { notifyAtomPicked(iatom, strMeasure, null); diff --git a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java index 7ba9186..4a9bf5f 100644 --- a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java +++ b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java @@ -40,6 +40,7 @@ import jalview.util.MessageManager; import java.awt.Color; import java.net.BindException; import java.util.ArrayList; +import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -63,6 +64,9 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel private static final String ALPHACARBON = "CA"; + private List chainNames = new ArrayList(); + + private Hashtable chainFile = new Hashtable(); /* * Object through which we talk to Chimera */ @@ -191,10 +195,9 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel * @param protocol */ public JalviewChimeraBinding(StructureSelectionManager ssm, - PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains, - String protocol) + PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String protocol) { - super(ssm, pdbentry, sequenceIs, chains, protocol); + super(ssm, pdbentry, sequenceIs, protocol); viewer = new ChimeraManager( new ext.edu.ucsf.rbvi.strucviz2.StructureManager(true)); } @@ -244,11 +247,14 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel boolean first = true; for (String chain : toshow) { + int modelNumber = getModelNoForChain(chain); + String showChainCmd = modelNumber == -1 ? "" : modelNumber + ":." + + chain.split(":")[1]; if (!first) { cmd.append(","); } - cmd.append(":.").append(chain); + cmd.append(showChainCmd); first = false; } @@ -257,7 +263,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel * window, but it looks more helpful not to (easier to relate chains to the * whole) */ - final String command = "~display #*; ~ribbon #*; ribbon " + final String command = "~display #*; ~ribbon #*; ribbon :" + cmd.toString(); sendChimeraCommand(command, false); } @@ -758,18 +764,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel { return new String[0]; } - // if (modelFileNames == null) - // { - // Collection chimodels = viewer.getChimeraModels(); - // _modelFileNameMap = new int[chimodels.size()]; - // int j = 0; - // for (ChimeraModel chimodel : chimodels) - // { - // String mdlName = chimodel.getModelName(); - // } - // modelFileNames = new String[j]; - // // System.arraycopy(mset, 0, modelFileNames, 0, j); - // } return chimeraMaps.keySet().toArray( modelFileNames = new String[chimeraMaps.size()]); @@ -1067,28 +1061,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel * * @return */ - public List getChainNames() - { - List names = new ArrayList(); - String[][] allNames = getChains(); - if (allNames != null) - { - for (String[] chainsForPdb : allNames) - { - if (chainsForPdb != null) - { - for (String chain : chainsForPdb) - { - if (chain != null && !names.contains(chain)) - { - names.add(chain); - } - } - } - } - } - return names; - } /** * Send a 'focus' command to Chimera to recentre the visible display @@ -1125,4 +1097,31 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel sm.highlightStructure(this, seq, positions); } } + + + @Override + public List getChainNames() + { + return chainNames; + } + + public Hashtable getChainFile() + { + return chainFile; + } + + public List getChimeraModelByChain(String chain) + { + return chimeraMaps.get(chainFile.get(chain)); + } + + public int getModelNoForChain(String chain) + { + List foundModels = getChimeraModelByChain(chain); + if (foundModels != null && !foundModels.isEmpty()) + { + return foundModels.get(0).getModelNumber(); + } + return -1; + } } diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index e8b865b..1372749 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -71,6 +71,7 @@ import jalview.io.JalviewFileChooser; import jalview.io.JalviewFileView; import jalview.io.JnetAnnotationMaker; import jalview.io.NewickFile; +import jalview.io.StructureFile; import jalview.io.TCoffeeScoreFile; import jalview.jbgui.GAlignFrame; import jalview.schemes.Blosum62ColourScheme; @@ -1340,14 +1341,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override protected void htmlMenuItem_actionPerformed(ActionEvent e) { - new HtmlSvgOutput(null, alignPanel); + HtmlSvgOutput htmlSVG = new HtmlSvgOutput(alignPanel); + htmlSVG.exportHTML(null); } @Override public void bioJSMenuItem_actionPerformed(ActionEvent e) { - BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel, this); - bjs.exportJalviewAlignmentAsBioJsHtmlFile(null); + BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel); + bjs.exportHTML(null); } public void createImageMap(File file, String image) @@ -4885,8 +4887,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } if (type != null) { - if (type.equalsIgnoreCase("PDB") - || type.equalsIgnoreCase("mmCIF")) + if (StructureFile.isStructureFile(type)) { filesmatched.add(new Object[] { file, protocol, mtch }); continue; diff --git a/src/jalview/gui/AlignmentPanel.java b/src/jalview/gui/AlignmentPanel.java index 4db029c..9f1162f 100644 --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@ -956,11 +956,11 @@ public class AlignmentPanel extends GAlignmentPanel implements if (av.getWrapAlignment()) { - return printWrappedAlignment(pg, pwidth, pheight, pi); + return printWrappedAlignment(pwidth, pheight, pi, pg); } else { - return printUnwrapped(pg, pwidth, pheight, pi); + return printUnwrapped(pwidth, pheight, pi, pg); } } @@ -981,16 +981,28 @@ public class AlignmentPanel extends GAlignmentPanel implements * @throws PrinterException * DOCUMENT ME! */ - public int printUnwrapped(Graphics pg, int pwidth, int pheight, int pi) + public int printUnwrapped(int pwidth, int pheight, int pi, + Graphics... pg) throws PrinterException { + boolean isMultiGraphics = pg.length > 1; + int G0 = 0; // Graphic index of idPanel graphics in multi-graphics mode or + // entire graphics for non mulit-graphics mode + int G1 = 0; // Graphic index of alignmentPanel graphics for multi-graphics + // mode + if (isMultiGraphics) + { + G0 = 0; + G1 = 1; + } + int idWidth = getVisibleIdWidth(false); FontMetrics fm = getFontMetrics(av.getFont()); int scaleHeight = av.getCharHeight() + fm.getDescent(); - pg.setColor(Color.white); - pg.fillRect(0, 0, pwidth, pheight); - pg.setFont(av.getFont()); + pg[G0].setColor(Color.white); + pg[G0].fillRect(0, 0, pwidth, pheight); + pg[G0].setFont(av.getFont()); // ////////////////////////////////// // / How many sequences and residues can we fit on a printable page? @@ -1047,17 +1059,31 @@ public class AlignmentPanel extends GAlignmentPanel implements } // draw Scale - pg.translate(idWidth, 0); - getScalePanel().drawScale(pg, startRes, endRes, pwidth - idWidth, - scaleHeight); - pg.translate(-idWidth, scaleHeight); + if (isMultiGraphics) + { + pg[G1].translate(0, 0); + getScalePanel().drawScale(pg[G1], startRes, endRes, + pwidth - idWidth, scaleHeight); + pg[G1].translate(-idWidth, scaleHeight); + } + else + { + pg[G0].translate(idWidth, 0); + getScalePanel().drawScale(pg[G0], startRes, endRes, pwidth - idWidth, + scaleHeight); + pg[G0].translate(-idWidth, scaleHeight); + } // ////////////// // Draw the ids Color currentColor = null; Color currentTextColor = null; - pg.setFont(getIdPanel().getIdCanvas().getIdfont()); + if (isMultiGraphics) + { + pg[G0].translate(0, scaleHeight); + } + pg[G0].setFont(getIdPanel().getIdCanvas().getIdfont()); SequenceI seq; for (int i = startSeq; i < endSeq; i++) @@ -1075,45 +1101,70 @@ public class AlignmentPanel extends GAlignmentPanel implements currentTextColor = Color.black; } - pg.setColor(currentColor); - pg.fillRect(0, (i - startSeq) * av.getCharHeight(), idWidth, + pg[G0].setColor(currentColor); + pg[G0].fillRect(0, (i - startSeq) * av.getCharHeight(), idWidth, av.getCharHeight()); - pg.setColor(currentTextColor); + pg[G0].setColor(currentTextColor); int xPos = 0; if (av.isRightAlignIds()) { - fm = pg.getFontMetrics(); + fm = pg[G0].getFontMetrics(); xPos = idWidth - fm.stringWidth(seq.getDisplayId(av.getShowJVSuffix())) - 4; } - pg.drawString(seq.getDisplayId(av.getShowJVSuffix()), xPos, + pg[G0].drawString(seq.getDisplayId(av.getShowJVSuffix()), xPos, (((i - startSeq) * av.getCharHeight()) + av.getCharHeight()) - (av.getCharHeight() / 5)); } - pg.setFont(av.getFont()); + pg[G0].setFont(av.getFont()); + // draw main sequence panel - pg.translate(idWidth, 0); - getSeqPanel().seqCanvas.drawPanel(pg, startRes, endRes, startSeq, - endSeq, 0); + pg[G0].translate(idWidth, 0); + if (isMultiGraphics) + { + pg[G1].translate(idWidth, 0); + getSeqPanel().seqCanvas.drawPanel(pg[G1], startRes, endRes, + startSeq, endSeq, 0); + } + else + { + getSeqPanel().seqCanvas.drawPanel(pg[G0], startRes, endRes, startSeq, + endSeq, 0); + } if (av.isShowAnnotation() && (endSeq == av.getAlignment().getHeight())) { - // draw annotation - need to offset for current scroll position + // draw annotation label - need to offset for current scroll position int offset = -getAlabels().getScrollOffset(); - pg.translate(0, offset); - pg.translate(-idWidth - 3, (endSeq - startSeq) * av.getCharHeight() - + 3); - getAlabels().drawComponent(pg, idWidth); - pg.translate(idWidth + 3, 0); - getAnnotationPanel().renderer.drawComponent(getAnnotationPanel(), av, - pg, -1, startRes, endRes + 1); - pg.translate(0, -offset); + pg[G0].translate(0, offset); + pg[G0].translate(-idWidth - 3, + (endSeq - startSeq) * av.getCharHeight() + 3); + getAlabels().drawComponent(pg[G0], idWidth); + pg[G0].translate(idWidth + 3, 0); + pg[G0].translate(0, -offset); + if (isMultiGraphics) + { + // draw annotation - need to offset for current scroll position + pg[G1].translate(0, offset); + pg[G1].translate(-idWidth - 3, + (endSeq - startSeq) * av.getCharHeight() + 3); + pg[G1].translate(idWidth + 3, 0); + getAnnotationPanel().renderer.drawComponent(getAnnotationPanel(), + av, pg[G1], -1, startRes, endRes + 1); + pg[G1].translate(0, -offset); + } + else + { + getAnnotationPanel().renderer.drawComponent(getAnnotationPanel(), + av, pg[G0], -1, startRes, endRes + 1); + pg[G0].translate(0, -offset); + } } return Printable.PAGE_EXISTS; @@ -1136,8 +1187,8 @@ public class AlignmentPanel extends GAlignmentPanel implements * @throws PrinterException * DOCUMENT ME! */ - public int printWrappedAlignment(Graphics pg, int pwidth, int pheight, - int pi) throws PrinterException + public int printWrappedAlignment(int pwidth, int pheight, int pi, + Graphics pg) throws PrinterException { int annotationHeight = 0; AnnotationLabels labels = null; @@ -1316,8 +1367,9 @@ public class AlignmentPanel extends GAlignmentPanel implements { if (im.getGraphics() != null) { - printWrappedAlignment(im.getGraphics(), aDimension.getWidth(), - aDimension.getHeight() + boarderBottomOffset, 0); + printWrappedAlignment(aDimension.getWidth(), + aDimension.getHeight() + boarderBottomOffset, 0, + im.getGraphics()); im.writeImage(); } } @@ -1325,8 +1377,8 @@ public class AlignmentPanel extends GAlignmentPanel implements { if (im.getGraphics() != null) { - printUnwrapped(im.getGraphics(), aDimension.getWidth(), - aDimension.getHeight(), 0); + printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), + 0, im.getGraphics()); im.writeImage(); } } diff --git a/src/jalview/gui/AppJmol.java b/src/jalview/gui/AppJmol.java index 1c0dfe6..d7e8305 100644 --- a/src/jalview/gui/AppJmol.java +++ b/src/jalview/gui/AppJmol.java @@ -50,7 +50,6 @@ import java.awt.Font; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.io.BufferedReader; @@ -67,7 +66,6 @@ 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.JPanel; import javax.swing.JSplitPane; @@ -131,7 +129,7 @@ public class AppJmol extends StructureViewerBase // / TODO: check if protocol is needed to be set, and if chains are // autodiscovered. jmb = new AppJmolBinding(this, ap.getStructureSelectionManager(), - pdbentrys, seqs, null, null); + pdbentrys, seqs, null); jmb.setLoadingFromArchive(true); addAlignmentPanel(ap); @@ -301,7 +299,7 @@ public class AppJmol extends StructureViewerBase { progressBar = ap.alignFrame; jmb = new AppJmolBinding(this, ap.getStructureSelectionManager(), - pdbentrys, seqs, null, null); + pdbentrys, seqs, null); addAlignmentPanel(ap); useAlignmentPanelForColourbyseq(ap); if (pdbentrys.length > 1) @@ -394,57 +392,12 @@ public class AppJmol extends StructureViewerBase jmb.setFinishedInit(true); } - void setChainMenuItems(Vector chains) - { - chainMenu.removeAll(); - if (chains == null) - { - 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); - } - } - centerViewer(); - allChainsSelected = false; - } - }); - - chainMenu.add(menuItem); - - for (String chain : chains) - { - menuItem = new JCheckBoxMenuItem(chain, true); - menuItem.addItemListener(new ItemListener() - { - @Override - public void itemStateChanged(ItemEvent evt) - { - if (!allChainsSelected) - { - centerViewer(); - } - } - }); - chainMenu.add(menuItem); - } - } boolean allChainsSelected = false; - void centerViewer() + @Override + void showSelectedChains() { Vector toshow = new Vector(); for (int i = 0; i < chainMenu.getItemCount(); i++) @@ -1075,7 +1028,7 @@ public class AppJmol extends StructureViewerBase repaint(); return; } - setChainMenuItems(jmb.chainNames); + setChainMenuItems(jmb.getChainNames()); this.setTitle(jmb.getViewerTitle()); if (jmb.getPdbFile().length > 1 && jmb.getSequence().length > 1) diff --git a/src/jalview/gui/AppJmolBinding.java b/src/jalview/gui/AppJmolBinding.java index 1c54a5e..546890e 100644 --- a/src/jalview/gui/AppJmolBinding.java +++ b/src/jalview/gui/AppJmolBinding.java @@ -41,10 +41,9 @@ public class AppJmolBinding extends JalviewJmolBinding private FeatureRenderer fr = null; public AppJmolBinding(AppJmol appJmol, StructureSelectionManager sSm, - PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains, - String protocol) + PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String protocol) { - super(sSm, pdbentry, sequenceIs, chains, protocol); + super(sSm, pdbentry, sequenceIs, protocol); appJmolWindow = appJmol; } @@ -113,6 +112,7 @@ public class AppJmolBinding extends JalviewJmolBinding // appJmolWindow.repaint(); javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { appJmolWindow.updateTitleAndMenus(); @@ -121,6 +121,7 @@ public class AppJmolBinding extends JalviewJmolBinding }); } + @Override public void updateColours(Object source) { AlignmentPanel ap = (AlignmentPanel) source; @@ -144,6 +145,7 @@ public class AppJmolBinding extends JalviewJmolBinding // msWalltime); } + @Override public void showUrl(String url) { showUrl(url, "jmol"); diff --git a/src/jalview/gui/ChimeraViewFrame.java b/src/jalview/gui/ChimeraViewFrame.java index ce719d0..fe12f40 100644 --- a/src/jalview/gui/ChimeraViewFrame.java +++ b/src/jalview/gui/ChimeraViewFrame.java @@ -31,6 +31,7 @@ import jalview.gui.StructureViewer.ViewerType; import jalview.io.AppletFormatAdapter; import jalview.io.JalviewFileChooser; import jalview.io.JalviewFileView; +import jalview.io.StructureFile; import jalview.schemes.BuriedColourScheme; import jalview.schemes.ColourSchemeI; import jalview.schemes.HelixColourScheme; @@ -46,7 +47,6 @@ 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.io.BufferedReader; @@ -66,7 +66,6 @@ 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; @@ -248,10 +247,8 @@ public class ChimeraViewFrame extends StructureViewerBase { createProgressBar(); // FIXME extractChains needs pdbentries to match IDs to PDBEntry(s) on seqs - String[][] chains = extractChains(seqs); jmb = new JalviewChimeraBindingModel(this, - ap.getStructureSelectionManager(), pdbentrys, seqs, chains, - null); + ap.getStructureSelectionManager(), pdbentrys, seqs, null); addAlignmentPanel(ap); useAlignmentPanelForColourbyseq(ap); if (pdbentrys.length > 1) @@ -278,41 +275,7 @@ public class ChimeraViewFrame extends StructureViewerBase } - /** - * Retrieve chains for sequences by inspecting their PDB refs. The hope is - * that the first will be to the sequence's own chain. Really need a more - * managed way of doing this. - * - * @param seqs - * @return - */ - protected String[][] extractChains(SequenceI[][] seqs) - { - String[][] chains = new String[seqs.length][]; - for (int i = 0; i < seqs.length; i++) - { - chains[i] = new String[seqs[i].length]; - int seqno = 0; - for (SequenceI seq : seqs[i]) - { - String chain = null; - if (seq.getDatasetSequence() != null) - { - Vector pdbrefs = seq.getDatasetSequence() - .getAllPDBEntries(); - if (pdbrefs != null && pdbrefs.size() > 0) - { - // FIXME: SequenceI.PDBEntry[0] chain mapping used for - // ChimeraViewFrame. Is this even used ??? - chain = pdbrefs.get(0).getChainCode(); - } - } - chains[i][seqno++] = chain; - } - } - return chains; - } /** * Create a new viewer from saved session state data including Chimera session @@ -437,63 +400,11 @@ public class ChimeraViewFrame extends StructureViewerBase 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 - */ - 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 void showSelectedChains() { List toshow = new ArrayList(); @@ -569,6 +480,7 @@ public class ChimeraViewFrame extends StructureViewerBase List filePDB = new ArrayList(); List filePDBpos = new ArrayList(); PDBEntry thePdbEntry = null; + StructureFile pdb = null; try { String[] curfiles = jmb.getPdbFile(); // files currently in viewer @@ -677,8 +589,9 @@ public class ChimeraViewFrame extends StructureViewerBase stopProgressBar("", startTime); } // Explicitly map to the filename used by Chimera ; - jmb.getSsm().setMapping(jmb.getSequence()[pos], + pdb = jmb.getSsm().setMapping(jmb.getSequence()[pos], jmb.getChains()[pos], pe.getFile(), protocol); + stashFoundChains(pdb, pe.getFile()); } catch (OutOfMemoryError oomerror) { new OOMWarning( @@ -694,6 +607,7 @@ public class ChimeraViewFrame extends StructureViewerBase } } } + jmb.refreshGUI(); jmb.setFinishedInit(true); jmb.setLoadingFromArchive(false); @@ -729,6 +643,17 @@ public class ChimeraViewFrame extends StructureViewerBase * @return * @throws Exception */ + + private void stashFoundChains(StructureFile pdb, String file) + { + for (int i = 0; i < pdb.getChains().size(); i++) + { + String chid = new String(pdb.getId() + ":" + + pdb.getChains().elementAt(i).id); + jmb.getChainNames().add(chid); + jmb.getChainFile().put(chid, file); + } + } private String fetchPdbFile(PDBEntry processingEntry) throws Exception { // FIXME: this is duplicated code with Jmol frame ? diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index 3f457ea..28606f1 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -20,6 +20,9 @@ */ package jalview.gui; +import static jalview.util.UrlConstants.EMBLEBI_STRING; +import static jalview.util.UrlConstants.SEQUENCE_ID; + import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; import jalview.bin.Cache; @@ -75,6 +78,7 @@ import java.net.URL; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; +import java.util.ListIterator; import java.util.StringTokenizer; import java.util.Vector; import java.util.concurrent.ExecutorService; @@ -82,9 +86,12 @@ import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import javax.swing.AbstractAction; +import javax.swing.Box; +import javax.swing.BoxLayout; import javax.swing.DefaultDesktopManager; import javax.swing.DesktopManager; import javax.swing.JButton; +import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDesktopPane; @@ -382,6 +389,8 @@ public class Desktop extends jalview.jbgui.GDesktop implements showNews.setVisible(false); + checkURLLinks(); + this.addWindowListener(new WindowAdapter() { @Override @@ -2256,6 +2265,84 @@ public class Desktop extends jalview.jbgui.GDesktop implements new Thread(jvq).start(); } + public void checkURLLinks() + { + // Thread off the URL link checker + addDialogThread(new Runnable() + { + @Override + public void run() + { + if (Cache.getDefault("CHECKURLLINKS", true)) + { + // check what the actual links are - if it's just the default don't + // bother with the warning + Vector links = Preferences.sequenceURLLinks; + + // only need to check links if there is one with a + // SEQUENCE_ID which is not the default EMBL_EBI link + ListIterator li = links.listIterator(); + boolean check = false; + List urls = new ArrayList(); + while (li.hasNext()) + { + String link = li.next(); + if (link.contains(SEQUENCE_ID) && !link.equals(EMBLEBI_STRING)) + { + check = true; + int barPos = link.indexOf("|"); + String urlMsg = barPos == -1 ? link : link.substring(0, + barPos) + ": " + link.substring(barPos + 1); + urls.add(new JLabel(urlMsg)); + } + } + if (!check) + { + return; + } + + // ask user to check in case URL links use old style tokens + // ($SEQUENCE_ID$ for sequence id _or_ accession id) + JPanel msgPanel = new JPanel(); + msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS)); + msgPanel.add(Box.createVerticalGlue()); + JLabel msg = new JLabel( + MessageManager + .getString("label.SEQUENCE_ID_for_DB_ACCESSION1")); + JLabel msg2 = new JLabel( + MessageManager + .getString("label.SEQUENCE_ID_for_DB_ACCESSION2")); + msgPanel.add(msg); + for (JLabel url : urls) + { + msgPanel.add(url); + } + msgPanel.add(msg2); + + final JCheckBox jcb = new JCheckBox( + MessageManager.getString("label.do_not_display_again")); + jcb.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + // update Cache settings for "don't show this again" + boolean showWarningAgain = !jcb.isSelected(); + Cache.setProperty("CHECKURLLINKS", + Boolean.valueOf(showWarningAgain).toString()); + } + }); + msgPanel.add(jcb); + + JOptionPane.showMessageDialog(Desktop.desktop, msgPanel, + MessageManager + .getString("label.SEQUENCE_ID_no_longer_used"), + JOptionPane.WARNING_MESSAGE); + } + } + }); + } + /** * Proxy class for JDesktopPane which optionally displays the current memory * usage and highlights the desktop area with a red bar if free memory runs diff --git a/src/jalview/gui/IdPanel.java b/src/jalview/gui/IdPanel.java index 161c787..6a20872 100755 --- a/src/jalview/gui/IdPanel.java +++ b/src/jalview/gui/IdPanel.java @@ -225,7 +225,14 @@ public class IdPanel extends JPanel implements MouseListener, url = null; continue; } - ; + + if (urlLink.usesDBAccession()) + { + // this URL requires an accession id, not the name of a sequence + url = null; + continue; + } + if (!urlLink.isValid()) { jalview.bin.Cache.log.error(urlLink.getInvalidMessage()); diff --git a/src/jalview/gui/Jalview2XML.java b/src/jalview/gui/Jalview2XML.java index 1c90889..bc5e1d8 100644 --- a/src/jalview/gui/Jalview2XML.java +++ b/src/jalview/gui/Jalview2XML.java @@ -3401,8 +3401,8 @@ public class Jalview2XML } if (jGroup.getConsThreshold() != 0) { - Conservation c = new Conservation("All", 3, - sg.getSequences(null), 0, sg.getWidth() - 1); + Conservation c = new Conservation("All", sg.getSequences(null), + 0, sg.getWidth() - 1); c.calculate(); c.verdict(false, 25); sg.cs.setConservation(c); diff --git a/src/jalview/gui/Jalview2XML_V1.java b/src/jalview/gui/Jalview2XML_V1.java index f8a296f..3b39be7 100755 --- a/src/jalview/gui/Jalview2XML_V1.java +++ b/src/jalview/gui/Jalview2XML_V1.java @@ -359,8 +359,8 @@ public class Jalview2XML_V1 if (groups[i].getConsThreshold() != 0) { - Conservation c = new Conservation("All", 3, - sg.getSequences(null), 0, sg.getWidth() - 1); + Conservation c = new Conservation("All", sg.getSequences(null), + 0, sg.getWidth() - 1); c.calculate(); c.verdict(false, 25); sg.cs.setConservation(c); diff --git a/src/jalview/gui/JalviewChimeraBindingModel.java b/src/jalview/gui/JalviewChimeraBindingModel.java index 7a54732..78ab68d 100644 --- a/src/jalview/gui/JalviewChimeraBindingModel.java +++ b/src/jalview/gui/JalviewChimeraBindingModel.java @@ -32,11 +32,12 @@ public class JalviewChimeraBindingModel extends JalviewChimeraBinding private FeatureRenderer fr = null; + public JalviewChimeraBindingModel(ChimeraViewFrame chimeraViewFrame, StructureSelectionManager ssm, PDBEntry[] pdbentry, - SequenceI[][] sequenceIs, String[][] chains, String protocol) + SequenceI[][] sequenceIs, String protocol) { - super(ssm, pdbentry, sequenceIs, chains, protocol); + super(ssm, pdbentry, sequenceIs, protocol); cvf = chimeraViewFrame; } @@ -72,6 +73,7 @@ public class JalviewChimeraBindingModel extends JalviewChimeraBinding { javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { cvf.updateTitleAndMenus(); @@ -80,6 +82,7 @@ public class JalviewChimeraBindingModel extends JalviewChimeraBinding }); } + @Override public void updateColours(Object source) { AlignmentPanel ap = (AlignmentPanel) source; @@ -113,6 +116,7 @@ public class JalviewChimeraBindingModel extends JalviewChimeraBinding * Send an asynchronous command to Chimera, in a new thread, optionally with * an 'in progress' message in a progress bar somewhere */ + @Override protected void sendAsynchronousCommand(final String command, final String progressMsg) { @@ -135,4 +139,6 @@ public class JalviewChimeraBindingModel extends JalviewChimeraBinding thread.start(); } + + } diff --git a/src/jalview/gui/PopupMenu.java b/src/jalview/gui/PopupMenu.java index 3b79fdc..5825382 100644 --- a/src/jalview/gui/PopupMenu.java +++ b/src/jalview/gui/PopupMenu.java @@ -54,7 +54,6 @@ import jalview.schemes.TaylorColourScheme; import jalview.schemes.TurnColourScheme; import jalview.schemes.UserColourScheme; import jalview.schemes.ZappoColourScheme; -import jalview.util.DBRefUtils; import jalview.util.GroupUrlLink; import jalview.util.GroupUrlLink.UrlStringTooLongException; import jalview.util.MessageManager; @@ -63,8 +62,8 @@ import jalview.util.UrlLink; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Hashtable; import java.util.LinkedHashMap; @@ -617,7 +616,8 @@ public class PopupMenu extends JPopupMenu void addFeatureLinks(final SequenceI seq, List links) { JMenu linkMenu = new JMenu(MessageManager.getString("action.link")); - List linkset = new ArrayList(); + Map> linkset = new LinkedHashMap>(); + for (String link : links) { UrlLink urlLink = null; @@ -629,80 +629,28 @@ public class PopupMenu extends JPopupMenu Cache.log.error("Exception for URLLink '" + link + "'", foo); continue; } - ; + if (!urlLink.isValid()) { Cache.log.error(urlLink.getInvalidMessage()); continue; } - final String label = urlLink.getLabel(); - - // collect id string too - String id = seq.getName(); - String descr = seq.getDescription(); - if (descr != null && descr.length() < 1) - { - descr = null; - } - if (seq != null && urlLink.usesSeqId()) // link is ID - { - // collect matching db-refs - DBRefEntry[] dbr = DBRefUtils.selectRefs(seq.getDBRefs(), - new String[] { urlLink.getTarget() }); - - // if there are any dbrefs which match up with the link - if (dbr != null) - { - for (int r = 0; r < dbr.length; r++) - { - if (id != null && dbr[r].getAccessionId().equals(id)) - { - // suppress duplicate link creation for the bare sequence ID - // string with this link - id = null; - } - // create Bare ID link for this URL - createBareURLLink(urlLink, dbr[r].getAccessionId(), linkset, - linkMenu, label, true); - } - } + urlLink.createLinksFromSeq(seq, linkset); + } - // Create urls from description but only for URL links which are regex - // links - if (descr != null && urlLink.getRegexReplace() != null) - { - // create link for this URL from description where regex matches - createBareURLLink(urlLink, descr, linkset, linkMenu, label, false); - } - - } - else if (seq != null && !urlLink.usesSeqId()) // link is name - { - if (id != null) - { - // create Bare ID link for this URL - createBareURLLink(urlLink, id, linkset, linkMenu, label, false); - } - // Create urls from description but only for URL links which are regex - // links - if (descr != null && urlLink.getRegexReplace() != null) - { - // create link for this URL from description where regex matches - createBareURLLink(urlLink, descr, linkset, linkMenu, label, false); - } - } - else - { - if (!linkset.contains(label + "|" + urlLink.getUrl_prefix())) - { - linkset.add(label + "|" + urlLink.getUrl_prefix()); - // Add a non-dynamic link - addshowLink(linkMenu, label, urlLink.getUrl_prefix()); - } - } + addshowLinks(linkMenu, linkset.values()); + // disable link menu if there are no valid entries + if (linkMenu.getItemCount() > 0) + { + linkMenu.setEnabled(true); } + else + { + linkMenu.setEnabled(false); + } + if (sequence != null) { sequenceMenu.add(linkMenu); @@ -711,36 +659,11 @@ public class PopupMenu extends JPopupMenu { add(linkMenu); } - } - /* - * Create a bare URL Link - */ - private void createBareURLLink(UrlLink urlLink, String id, - List linkset, JMenu linkMenu, String label, - Boolean addSepToLabel) - { - String[] urls = urlLink.makeUrls(id, true); - if (urls != null) - { - for (int u = 0; u < urls.length; u += 2) - { - if (!linkset.contains(urls[u] + "|" + urls[u + 1])) - { - linkset.add(urls[u] + "|" + urls[u + 1]); - if (addSepToLabel) - { - addshowLink(linkMenu, label + "|" + urls[u], urls[u + 1]); - } - else - { - addshowLink(linkMenu, label, urls[u + 1]); - } - } - } - } } + + /** * Add annotation types to 'Show annotations' and/or 'Hide annotations' menus. * "All" is added first, followed by a separator. Then add any annotation @@ -1015,6 +938,15 @@ public class PopupMenu extends JPopupMenu } } + private void addshowLinks(JMenu linkMenu, Collection> linkset) + { + for (List linkstrset : linkset) + { + // split linkstr into label and url + addshowLink(linkMenu, linkstrset.get(1), linkstrset.get(3)); + } + } + /** * add a show URL menu item to the given linkMenu * @@ -2047,7 +1979,7 @@ public class PopupMenu extends JPopupMenu if (conservationMenuItem.isSelected()) { // JBPNote: Conservation name shouldn't be i18n translated - Conservation c = new Conservation("Group", 3, sg.getSequences(ap.av + Conservation c = new Conservation("Group", sg.getSequences(ap.av .getHiddenRepSequences()), sg.getStartRes(), sg.getEndRes() + 1); diff --git a/src/jalview/gui/Preferences.java b/src/jalview/gui/Preferences.java index b57b951..3bffd3a 100755 --- a/src/jalview/gui/Preferences.java +++ b/src/jalview/gui/Preferences.java @@ -20,10 +20,9 @@ */ package jalview.gui; +import static jalview.util.UrlConstants.DB_ACCESSION; import static jalview.util.UrlConstants.EMBLEBI_STRING; -import static jalview.util.UrlConstants.OLD_EMBLEBI_STRING; import static jalview.util.UrlConstants.SEQUENCE_ID; -import static jalview.util.UrlConstants.SEQUENCE_NAME; import static jalview.util.UrlConstants.SRS_STRING; import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder; @@ -127,10 +126,10 @@ public class Preferences extends GPreferences String name = st.nextToken(); String url = st.nextToken(); // check for '|' within a regex - int rxstart = url.indexOf("$" + SEQUENCE_ID + "$"); + int rxstart = url.indexOf("$" + DB_ACCESSION + "$"); if (rxstart == -1) { - rxstart = url.indexOf("$" + SEQUENCE_NAME + "$"); + rxstart = url.indexOf("$" + SEQUENCE_ID + "$"); } while (rxstart == -1 && url.indexOf("/=$") == -1) { @@ -149,12 +148,6 @@ public class Preferences extends GPreferences { sequenceURLLinks.setElementAt(EMBLEBI_STRING, srsPos); } - // upgrade old EMBL-EBI link - int emblPos = sequenceURLLinks.indexOf(OLD_EMBLEBI_STRING); - if (emblPos > -1) - { - sequenceURLLinks.setElementAt(EMBLEBI_STRING, emblPos); - } } /** @@ -574,6 +567,7 @@ public class Preferences extends GPreferences else { Cache.applicationProperties.remove("SEQUENCE_LINKS"); + sequenceURLLinks.clear(); } Cache.applicationProperties.setProperty("USE_PROXY", diff --git a/src/jalview/gui/StructureViewerBase.java b/src/jalview/gui/StructureViewerBase.java index 7df42fd..4715e48 100644 --- a/src/jalview/gui/StructureViewerBase.java +++ b/src/jalview/gui/StructureViewerBase.java @@ -30,10 +30,15 @@ import jalview.structures.models.AAStructureBindingModel; import jalview.util.MessageManager; import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; import java.util.ArrayList; import java.util.List; import java.util.Vector; +import javax.swing.JCheckBoxMenuItem; import javax.swing.JMenuItem; import javax.swing.JOptionPane; @@ -76,6 +81,8 @@ public abstract class StructureViewerBase extends GStructureViewer protected Thread worker = null; + protected boolean allChainsSelected = false; + /** * * @param ap2 @@ -152,6 +159,7 @@ public abstract class StructureViewerBase extends GStructureViewer this.ap = alp; } + @Override public AlignmentPanel[] getAllAlignmentPanels() { AlignmentPanel[] t, list = new AlignmentPanel[0]; @@ -291,6 +299,7 @@ public abstract class StructureViewerBase extends GStructureViewer // queue. new Thread(new Runnable() { + @Override public void run() { while (worker != null && worker.isAlive() && _started) @@ -492,4 +501,55 @@ public abstract class StructureViewerBase extends GStructureViewer } return finished; } + + 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 chain : chainNames) + { + menuItem = new JCheckBoxMenuItem(chain, true); + menuItem.addItemListener(new ItemListener() + { + @Override + public void itemStateChanged(ItemEvent evt) + { + if (!allChainsSelected) + { + showSelectedChains(); + } + } + }); + + chainMenu.add(menuItem); + } + } + + abstract void showSelectedChains(); + } diff --git a/src/jalview/gui/TreeCanvas.java b/src/jalview/gui/TreeCanvas.java index 0e513f7..84fd82f 100755 --- a/src/jalview/gui/TreeCanvas.java +++ b/src/jalview/gui/TreeCanvas.java @@ -1017,8 +1017,8 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, if (aps[a].av.getGlobalColourScheme() != null && aps[a].av.getGlobalColourScheme().conservationApplied()) { - Conservation c = new Conservation("Group", 3, - sg.getSequences(null), sg.getStartRes(), sg.getEndRes()); + Conservation c = new Conservation("Group", sg.getSequences(null), + sg.getStartRes(), sg.getEndRes()); c.calculate(); c.verdict(false, aps[a].av.getConsPercGaps()); sg.cs.setConservation(c); diff --git a/src/jalview/io/AnnotationFile.java b/src/jalview/io/AnnotationFile.java index 34fdabe..61a30f8 100755 --- a/src/jalview/io/AnnotationFile.java +++ b/src/jalview/io/AnnotationFile.java @@ -1637,9 +1637,8 @@ public class AnnotationFile else if (key.equalsIgnoreCase("consThreshold")) { sg.cs.setConservationInc(Integer.parseInt(value)); - Conservation c = new Conservation("Group", 3, - sg.getSequences(null), sg.getStartRes(), - sg.getEndRes() + 1); + Conservation c = new Conservation("Group", sg.getSequences(null), + sg.getStartRes(), sg.getEndRes() + 1); c.calculate(); c.verdict(false, 25); // TODO: refer to conservation percent threshold diff --git a/src/jalview/io/BioJsHTMLOutput.java b/src/jalview/io/BioJsHTMLOutput.java index 817f75c..1be97f5 100644 --- a/src/jalview/io/BioJsHTMLOutput.java +++ b/src/jalview/io/BioJsHTMLOutput.java @@ -20,11 +20,8 @@ */ package jalview.io; -import jalview.api.AlignExportSettingI; -import jalview.api.AlignmentViewPanel; -import jalview.datamodel.AlignmentExportData; import jalview.exceptions.NoFileSelectedException; -import jalview.gui.IProgressIndicator; +import jalview.gui.AlignmentPanel; import jalview.gui.OOMWarning; import jalview.json.binding.biojs.BioJSReleasePojo; import jalview.json.binding.biojs.BioJSRepositoryPojo; @@ -42,15 +39,8 @@ import java.net.URL; import java.util.Objects; import java.util.TreeMap; -public class BioJsHTMLOutput +public class BioJsHTMLOutput extends HTMLOutput { - private AlignmentViewPanel ap; - - private long pSessionId; - - private IProgressIndicator pIndicator; - - private boolean headless; private static File currentBJSTemplateFile; @@ -67,91 +57,38 @@ public class BioJsHTMLOutput "biojs_template_git_repo", "https://raw.githubusercontent.com/jalview/exporter-templates/master/biojs/package.json"); - public BioJsHTMLOutput(AlignmentViewPanel ap, - IProgressIndicator pIndicator) + public BioJsHTMLOutput(AlignmentPanel ap) { - if (ap != null) - { - this.ap = ap; - this.pSessionId = System.currentTimeMillis(); - this.pIndicator = pIndicator; - this.headless = (System.getProperty("java.awt.headless") != null && System - .getProperty("java.awt.headless").equals("true")); - } + super(ap); } - public void exportJalviewAlignmentAsBioJsHtmlFile(String outputFile) + @Override + public void exportHTML(String outputFile) { - // String outputFile = null; + exportStarted(); try { + if (outputFile == null) { outputFile = getOutputFile(); } - AlignExportSettingI exportSettings = new AlignExportSettingI() - { - @Override - public boolean isExportHiddenSequences() - { - return true; - } + generatedFile = new File(outputFile); - @Override - public boolean isExportHiddenColumns() - { - return true; - } - - @Override - public boolean isExportAnnotations() - { - return true; - } - - @Override - public boolean isExportFeatures() - { - return true; - } - - @Override - public boolean isExportGroups() - { - return true; - } - - @Override - public boolean isCancelled() - { - return false; - } - - }; - AlignmentExportData exportData = jalview.gui.AlignFrame - .getAlignmentForExport(JSONFile.FILE_DESC, - ap.getAlignViewport(), exportSettings); - String bioJSON = new FormatAdapter(ap, exportData.getSettings()) - .formatSequences(JSONFile.FILE_DESC, exportData - .getAlignment(), exportData.getOmitHidden(), - exportData.getStartEndPostions(), ap - .getAlignViewport().getColumnSelection()); - - String bioJSTemplateString = getBioJsTemplateAsString(); + String bioJSON = getBioJSONData(); + String bioJSTemplateString = HTMLOutput.readFileAsString(getCurrentBJSTemplateFile()); String generatedBioJsWithJalviewAlignmentAsJson = bioJSTemplateString .replaceAll("#sequenceData#", bioJSON).toString(); PrintWriter out = new java.io.PrintWriter(new java.io.FileWriter( - outputFile)); + generatedFile)); out.print(generatedBioJsWithJalviewAlignmentAsJson); out.flush(); out.close(); - jalview.util.BrowserLauncher.openURL("file:///" + outputFile); - if (pIndicator != null && !headless) - { - pIndicator.setProgressBar(MessageManager.formatMessage( - "status.export_complete", "BioJS"), pSessionId); - } + exportCompleted(); + setProgressMessage(MessageManager.formatMessage( + "status.export_complete", "BioJS")); + } catch (NoFileSelectedException ex) { // do noting if no file was selected @@ -162,94 +99,15 @@ public class BioJsHTMLOutput new OOMWarning("Creating Image for " + outputFile, err); } catch (Exception e) { - if (pIndicator != null && !headless) - { - pIndicator.setProgressBar(MessageManager.formatMessage( - "info.error_creating_file", "HTML"), pSessionId); - } + setProgressMessage(MessageManager.formatMessage( + "info.error_creating_file", "HTML")); e.printStackTrace(); } } - public String getOutputFile() throws NoFileSelectedException - { - String selectedFile = null; - if (pIndicator != null && !headless) - { - pIndicator.setProgressBar(MessageManager.formatMessage( - "status.waiting_for_user_to_select_output_file", "HTML"), - pSessionId); - } - - JalviewFileChooser jvFileChooser = new JalviewFileChooser( - jalview.bin.Cache.getProperty("LAST_DIRECTORY"), - new String[] { "html" }, new String[] { "HTML files" }, - "HTML files"); - jvFileChooser.setFileView(new JalviewFileView()); - jvFileChooser.setDialogTitle(MessageManager - .getString("label.save_as_biojs_html")); - jvFileChooser.setToolTipText(MessageManager.getString("action.save")); - int fileChooserOpt = jvFileChooser.showSaveDialog(null); - if (fileChooserOpt == JalviewFileChooser.APPROVE_OPTION) - { - jalview.bin.Cache.setProperty("LAST_DIRECTORY", jvFileChooser - .getSelectedFile().getParent()); - selectedFile = jvFileChooser.getSelectedFile().getPath(); - } - else - { - pIndicator.setProgressBar(MessageManager.formatMessage( - "status.cancelled_image_export_operation", "BioJS"), - pSessionId); - throw new NoFileSelectedException("No file was selected."); - } - return selectedFile; - } - - public static String getBioJsTemplateAsString() throws IOException - { - InputStreamReader isReader = null; - BufferedReader buffReader = null; - StringBuilder sb = new StringBuilder(); - Objects.requireNonNull(getCurrentBJSTemplateFile(), - "BioJsTemplate File not initialized!"); - @SuppressWarnings("deprecation") - URL url = getCurrentBJSTemplateFile().toURL(); - if (url != null) - { - try - { - isReader = new InputStreamReader(url.openStream()); - buffReader = new BufferedReader(isReader); - String line; - String lineSeparator = System.getProperty("line.separator"); - while ((line = buffReader.readLine()) != null) - { - sb.append(line).append(lineSeparator); - } - - } catch (Exception ex) - { - ex.printStackTrace(); - } finally - { - if (isReader != null) - { - isReader.close(); - } - - if (buffReader != null) - { - buffReader.close(); - } - } - } - return sb.toString(); - } - - public static void refreshBioJSVersionsInfo(String dirName) + public static void refreshVersionInfo(String dirName) throws URISyntaxException { File directory = new File(BJS_TEMPLATES_LOCAL_DIRECTORY); @@ -297,7 +155,7 @@ public class BioJsHTMLOutput BioJSRepositoryPojo release = new BioJSRepositoryPojo( gitRepoPkgJson); syncUpdates(BJS_TEMPLATES_LOCAL_DIRECTORY, release); - refreshBioJSVersionsInfo(BJS_TEMPLATES_LOCAL_DIRECTORY); + refreshVersionInfo(BJS_TEMPLATES_LOCAL_DIRECTORY); } } catch (URISyntaxException e) { @@ -418,4 +276,22 @@ public class BioJsHTMLOutput BioJsHTMLOutput.bioJsMSAVersions = bioJsMSAVersions; } + @Override + public boolean isEmbedData() + { + return true; + } + + @Override + public boolean isLaunchInBrowserAfterExport() + { + return true; + } + + @Override + public File getExportedFile() + { + return generatedFile; + } + } diff --git a/src/jalview/io/HTMLOutput.java b/src/jalview/io/HTMLOutput.java index df0dc06..a422a38 100755 --- a/src/jalview/io/HTMLOutput.java +++ b/src/jalview/io/HTMLOutput.java @@ -20,283 +20,143 @@ */ package jalview.io; -import jalview.datamodel.AlignmentI; -import jalview.datamodel.SequenceI; -import jalview.gui.AlignViewport; +import jalview.api.AlignExportSettingI; +import jalview.datamodel.AlignmentExportData; +import jalview.exceptions.NoFileSelectedException; import jalview.gui.AlignmentPanel; -import jalview.gui.FeatureRenderer; -import jalview.gui.SequenceRenderer; +import jalview.gui.IProgressIndicator; import jalview.util.MessageManager; -import java.awt.Color; -import java.awt.Font; -import java.io.PrintWriter; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.Objects; -public class HTMLOutput + +public abstract class HTMLOutput { - AlignViewport av; + protected AlignmentPanel ap; - SequenceRenderer sr; + protected long pSessionId; - jalview.renderer.seqfeatures.FeatureRenderer fr; + protected IProgressIndicator pIndicator; - Color color; + protected File generatedFile; - public HTMLOutput(AlignmentPanel ap, SequenceRenderer sr, - FeatureRenderer fr1) + public HTMLOutput(AlignmentPanel ap) { - this.av = ap.av; - this.sr = sr; - - fr = new FeatureRenderer(ap); - fr.transferSettings(fr1); - - JalviewFileChooser chooser = new JalviewFileChooser( - jalview.bin.Cache.getProperty("LAST_DIRECTORY"), - new String[] { "html" }, new String[] { "HTML files" }, - "HTML files"); - - chooser.setFileView(new JalviewFileView()); - chooser.setDialogTitle(MessageManager.getString("label.save_as_html")); - chooser.setToolTipText(MessageManager.getString("action.save")); - - int value = chooser.showSaveDialog(null); - - if (value == JalviewFileChooser.APPROVE_OPTION) + if (ap != null) { - String choice = chooser.getSelectedFile().getPath(); - jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser - .getSelectedFile().getParent()); - - try - { - PrintWriter out = new java.io.PrintWriter(new java.io.FileWriter( - choice)); - out.println(""); - out.println(""); - out.println(""); - - if (av.getWrapAlignment()) - { - drawWrappedAlignment(out); - } - else - { - drawUnwrappedAlignment(out); - } - - out.println("\n\n"); - out.close(); - jalview.util.BrowserLauncher.openURL("file:///" + choice); - } catch (Exception ex) - { - ex.printStackTrace(); - } + this.ap = ap; + this.pIndicator = ap.alignFrame; } } - void drawUnwrappedAlignment(PrintWriter out) - { - out.println("
\n"); - out.println("\n"); - - // //////////// - SequenceI seq; - AlignmentI alignment = av.getAlignment(); - - // draws the top row, the measure rule - out.println(""); - int i = 0; - - for (i = 10; i < (alignment.getWidth() - 10); i += 10) + public String getBioJSONData() + { + if (!isEmbedData()) { - out.println(""); + return null; } - - out.println(""); - out.println(""); - - for (i = 0; i < alignment.getHeight(); i++) + AlignExportSettingI exportSettings = new AlignExportSettingI() { - seq = alignment.getSequenceAt(i); - - String id = seq.getDisplayId(av.getShowJVSuffix()); - - out.println(""); - - for (int res = 0; res < seq.getLength(); res++) + @Override + public boolean isExportHiddenSequences() { - if (!jalview.util.Comparison.isGap(seq.getCharAt(res))) - { - color = sr.getResidueBoxColour(seq, res); - - color = fr.findFeatureColour(color, seq, res); - } - else - { - color = Color.white; - } - - if (color.getRGB() < -1) - { - out.println(""); - } - else - { - out.println(""); - } + return true; } - out.println(""); - } - - // //////////// - out.println("
" + i + "
|
" + i - + "
|
" + id + "  " - + seq.getCharAt(res) + "" + seq.getCharAt(res) + "
"); - out.println("
"); - } - - void drawWrappedAlignment(PrintWriter out) - { - // ////////////////////////////////// - // / How many sequences and residues can we fit on a printable page? - AlignmentI al = av.getAlignment(); - SequenceI seq; - String r; - String g; - String b; - - out.println("
\n"); - out.println("\n"); - - for (int startRes = 0; startRes < al.getWidth(); startRes += av - .getWrappedWidth()) - { - int endRes = startRes + av.getWrappedWidth(); - - if (endRes > al.getWidth()) + @Override + public boolean isExportHiddenColumns() { - endRes = al.getWidth(); + return true; } - if (av.getScaleAboveWrapped()) + @Override + public boolean isExportAnnotations() { - out.println(""); - - if (av.getScaleLeftWrapped()) - { - out.println(""); - } - else - { - out.println(""); - } - - for (int i = startRes + 10; i < endRes; i += 10) - { - out.println(""); - } - - out.println(""); + return true; } - int startPos, endPos; - for (int s = 0; s < al.getHeight(); s++) + @Override + public boolean isExportFeatures() { - out.println(""); - seq = al.getSequenceAt(s); - - startPos = seq.findPosition(startRes); - endPos = seq.findPosition(endRes) - 1; + return true; + } - String id = seq.getDisplayId(av.getShowJVSuffix()); + @Override + public boolean isExportGroups() + { + return true; + } - out.println(""); + @Override + public boolean isCancelled() + { + return false; + } - if (av.getScaleLeftWrapped()) - { - if (startPos > seq.getEnd() || endPos == 0) - { - out.println(""); - } - else - { - out.println(""); - } - } + }; + AlignmentExportData exportData = jalview.gui.AlignFrame + .getAlignmentForExport(JSONFile.FILE_DESC, + ap.getAlignViewport(), exportSettings); + String bioJSON = new FormatAdapter(ap, exportData.getSettings()) + .formatSequences(JSONFile.FILE_DESC, exportData.getAlignment(), + exportData.getOmitHidden(), exportData + .getStartEndPostions(), ap.getAlignViewport() + .getColumnSelection()); + return bioJSON; + } - for (int res = startRes; res < endRes; res++) + /** + * Read a template file content as string + * + * @param file + * - the file to be read + * @return File content as String + * @throws IOException + */ + public static String readFileAsString(File file) throws IOException + { + InputStreamReader isReader = null; + BufferedReader buffReader = null; + StringBuilder sb = new StringBuilder(); + Objects.requireNonNull(file, "File must not be null!"); + @SuppressWarnings("deprecation") + URL url = file.toURL(); + if (url != null) + { + try + { + isReader = new InputStreamReader(url.openStream()); + buffReader = new BufferedReader(isReader); + String line; + String lineSeparator = System.getProperty("line.separator"); + while ((line = buffReader.readLine()) != null) { - if (!jalview.util.Comparison.isGap(seq.getCharAt(res))) - { - color = sr.getResidueBoxColour(seq, res); - - color = fr.findFeatureColour(color, seq, res); - } - else - { - color = Color.white; - } - - if (color.getRGB() < -1) - { - out.println(""); - } - else - { - out.println(""); - } - + sb.append(line).append(lineSeparator); } - - if (av.getScaleRightWrapped() - && endRes < startRes + av.getWrappedWidth()) + + } catch (Exception ex) + { + ex.printStackTrace(); + } finally + { + if (isReader != null) { - out.println(""); + isReader.close(); } - - if (av.getScaleRightWrapped() && startPos < endPos) + + if (buffReader != null) { - out.println(""); + buffReader.close(); } - - out.println(""); - } - - if (endRes < al.getWidth()) - { - out.println(""); } } - - out.println("
  " + i + "
|
" + id + "   " + startPos + "  " - + seq.getCharAt(res) + "" + seq.getCharAt(res) + "" - + "   " + endPos + "  
"); - out.println("
"); + return sb.toString(); } public static String getImageMapHTML() @@ -386,4 +246,125 @@ public class HTMLOutput + "initToolTips(); //-->\n"); } + + public String getOutputFile() throws NoFileSelectedException + { + String selectedFile = null; + if (pIndicator != null && !isHeadless()) + { + pIndicator.setProgressBar(MessageManager.formatMessage( + "status.waiting_for_user_to_select_output_file", "HTML"), + pSessionId); + } + + JalviewFileChooser jvFileChooser = new JalviewFileChooser( + jalview.bin.Cache.getProperty("LAST_DIRECTORY"), + new String[] { "html" }, new String[] { "HTML files" }, + "HTML files"); + jvFileChooser.setFileView(new JalviewFileView()); + + jvFileChooser.setDialogTitle(MessageManager + .getString("label.save_as_biojs_html")); + jvFileChooser.setToolTipText(MessageManager.getString("action.save")); + + int fileChooserOpt = jvFileChooser.showSaveDialog(null); + if (fileChooserOpt == JalviewFileChooser.APPROVE_OPTION) + { + jalview.bin.Cache.setProperty("LAST_DIRECTORY", jvFileChooser + .getSelectedFile().getParent()); + selectedFile = jvFileChooser.getSelectedFile().getPath(); + } + else + { + pIndicator.setProgressBar(MessageManager.formatMessage( + "status.cancelled_image_export_operation", "BioJS"), + pSessionId); + throw new NoFileSelectedException("No file was selected."); + } + return selectedFile; + } + + protected void setProgressMessage(String message) + { + if (pIndicator != null && !isHeadless()) + { + pIndicator.setProgressBar(message, pSessionId); + } + else + { + System.out.println(message); + } + } + + /** + * Answers true if HTML export is invoke in headless mode or false otherwise + * + * @return + */ + protected boolean isHeadless() + { + return System.getProperty("java.awt.headless") != null + && System.getProperty("java.awt.headless").equals("true"); + } + + /** + * This method provides implementation of consistent behaviour which should + * occur before a HTML file export. It MUST be called at the start of the + * exportHTML() method implementation. + */ + protected void exportStarted() + { + pSessionId = System.currentTimeMillis(); + } + + /** + * This method provides implementation of consistent behaviour which should + * occur after a HTML file export. It MUST be called at the end of the + * exportHTML() method implementation. + */ + protected void exportCompleted() + { + if (isLaunchInBrowserAfterExport() && !isHeadless()) + { + try + { + jalview.util.BrowserLauncher + .openURL("file:///" + getExportedFile()); + } catch (IOException e) + { + e.printStackTrace(); + } + } + } + + /** + * if this answers true then BioJSON data will be embedded to the exported + * HTML file otherwise it won't be embedded. + * + * @return + */ + public abstract boolean isEmbedData(); + + /** + * if this answers true then the generated HTML file is opened for viewing in + * a browser after its generation otherwise it won't be opened in a browser + * + * @return + */ + public abstract boolean isLaunchInBrowserAfterExport(); + + /** + * handle to the generated HTML file + * + * @return + */ + public abstract File getExportedFile(); + + /** + * This is the main method to handle the HTML generation. + * + * @param outputFile + * the file path of the generated HTML + */ + public abstract void exportHTML(String outputFile); } diff --git a/src/jalview/io/HtmlSvgOutput.java b/src/jalview/io/HtmlSvgOutput.java index decb06f..e60824a 100644 --- a/src/jalview/io/HtmlSvgOutput.java +++ b/src/jalview/io/HtmlSvgOutput.java @@ -20,91 +20,49 @@ */ package jalview.io; -import jalview.api.AlignExportSettingI; -import jalview.api.FeatureRenderer; -import jalview.datamodel.AlignmentExportData; -import jalview.datamodel.SequenceI; -import jalview.gui.AlignViewport; import jalview.gui.AlignmentPanel; import jalview.gui.HTMLOptions; -import jalview.gui.IProgressIndicator; import jalview.gui.OOMWarning; import jalview.math.AlignmentDimension; import jalview.util.MessageManager; -import java.awt.Color; -import java.awt.FontMetrics; import java.awt.Graphics; -import java.awt.print.Printable; import java.awt.print.PrinterException; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import org.jfree.graphics2d.svg.SVGGraphics2D; import org.jfree.graphics2d.svg.SVGHints; -public class HtmlSvgOutput +public class HtmlSvgOutput extends HTMLOutput { - AlignViewport av; - FeatureRenderer fr; + private File generatedFile; - AlignmentPanel ap; - - private IProgressIndicator pIndicator; - - private long pSessionId; - - private boolean headless; - - public HtmlSvgOutput(File file, AlignmentPanel ap) + public HtmlSvgOutput(AlignmentPanel ap) { - this.av = ap.av; - this.ap = ap; - fr = ap.cloneFeatureRenderer(); - generateHtmlSvgOutput(file); + super(ap); } - public void generateHtmlSvgOutput(File file) + @Override + public void exportHTML(String file) { - pIndicator = ap.alignFrame; - pSessionId = System.currentTimeMillis(); + exportStarted(); try { - headless = (System.getProperty("java.awt.headless") != null && System - .getProperty("java.awt.headless").equals("true")); if (file == null) { - setProgressMessage(MessageManager.formatMessage( - "status.waiting_for_user_to_select_output_file", "HTML")); - JalviewFileChooser chooser = getHTMLChooser(); - chooser.setFileView(new jalview.io.JalviewFileView()); - chooser.setDialogTitle(ap.alignFrame.getTitle()); - chooser.setToolTipText(MessageManager.getString("action.save")); - int value = chooser.showSaveDialog(ap.alignFrame); - - if (value == jalview.io.JalviewFileChooser.APPROVE_OPTION) - { - jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser - .getSelectedFile().getParent()); - file = chooser.getSelectedFile(); - ap.alignFrame.repaint(); - } - else - { - setProgressMessage(MessageManager.formatMessage( - "status.cancelled_image_export_operation", "HTML")); - return; - } + file = getOutputFile(); } + generatedFile = new File(file); } catch (Exception e) { - pIndicator.setProgressBar(MessageManager.formatMessage( - "info.error_creating_file", "HTML"), pSessionId); + setProgressMessage(MessageManager.formatMessage( + "info.error_creating_file", "HTML")); e.printStackTrace(); return; } - final File fileX = file; new Thread() { @Override @@ -116,9 +74,11 @@ public class HtmlSvgOutput setProgressMessage(MessageManager.formatMessage( "status.exporting_alignment_as_x_file", "HTML")); AlignmentDimension aDimension = ap.getAlignmentDimension(); - SVGGraphics2D g1 = new SVGGraphics2D(aDimension.getWidth(), + SVGGraphics2D idPanelGraphics = new SVGGraphics2D( + aDimension.getWidth(), aDimension.getHeight()); - SVGGraphics2D g2 = new SVGGraphics2D(aDimension.getWidth(), + SVGGraphics2D alignPanelGraphics = new SVGGraphics2D( + aDimension.getWidth(), aDimension.getHeight()); String renderStyle = jalview.bin.Cache.getDefault( @@ -127,8 +87,7 @@ public class HtmlSvgOutput // If we need to prompt, and if the GUI is visible then // Prompt for rendering style if (renderStyle.equalsIgnoreCase("Prompt each time") - && !(System.getProperty("java.awt.headless") != null && System - .getProperty("java.awt.headless").equals("true"))) + && !isHeadless()) { HTMLOptions svgOption = new HTMLOptions(); renderStyle = svgOption.getValue(); @@ -143,100 +102,44 @@ public class HtmlSvgOutput if (renderStyle.equalsIgnoreCase("Lineart")) { - g1.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE, + idPanelGraphics.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE, SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR); - g2.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE, + alignPanelGraphics.setRenderingHint( + SVGHints.KEY_DRAW_STRING_TYPE, SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR); } - if (av.getWrapAlignment()) + if (ap.av.getWrapAlignment()) { printWrapped(aDimension.getWidth(), aDimension.getHeight(), 0, - g1, g2); + alignPanelGraphics); } else { printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), 0, - g1, g2); + idPanelGraphics, alignPanelGraphics); } - String titleSvgData = g1.getSVGDocument(); - String alignSvgData = g2.getSVGDocument(); - String jsonData = null; - boolean isEmbbedBioJSON = Boolean.valueOf(jalview.bin.Cache - .getDefault("EXPORT_EMBBED_BIOJSON", "true")); - if (isEmbbedBioJSON) - { - AlignExportSettingI exportSettings = new AlignExportSettingI() - { - @Override - public boolean isExportHiddenSequences() - { - return true; - } - - @Override - public boolean isExportHiddenColumns() - { - return true; - } - - @Override - public boolean isExportAnnotations() - { - return true; - } - - @Override - public boolean isExportFeatures() - { - return true; - } - - @Override - public boolean isExportGroups() - { - return true; - } - - @Override - public boolean isCancelled() - { - return false; - } - - }; - AlignmentExportData exportData = jalview.gui.AlignFrame - .getAlignmentForExport(JSONFile.FILE_DESC, av, - exportSettings); - jsonData = new FormatAdapter(ap, exportData.getSettings()) - .formatSequences(JSONFile.FILE_DESC, - exportData.getAlignment(), - exportData.getOmitHidden(), - exportData.getStartEndPostions(), - av.getColumnSelection()); - } - String htmlData = getHtml(titleSvgData, alignSvgData, jsonData, - av.getWrapAlignment()); - FileOutputStream out = new FileOutputStream(fileX); + String idPanelSvgData = idPanelGraphics.getSVGDocument(); + String alignPanelSvgData = alignPanelGraphics.getSVGDocument(); + String jsonData = getBioJSONData(); + String htmlData = getHtml(idPanelSvgData, alignPanelSvgData, jsonData, + ap.av.getWrapAlignment()); + FileOutputStream out = new FileOutputStream(generatedFile); out.write(htmlData.getBytes()); out.flush(); out.close(); - if (!(System.getProperty("java.awt.headless") != null && System - .getProperty("java.awt.headless").equals("true"))) - { - jalview.util.BrowserLauncher.openURL("file:///" + fileX); - } + exportCompleted(); } catch (OutOfMemoryError err) { System.out.println("########################\n" - + "OUT OF MEMORY " + fileX + "\n" + + "OUT OF MEMORY " + generatedFile + "\n" + "########################"); - new OOMWarning("Creating Image for " + fileX, err); + new OOMWarning("Creating Image for " + generatedFile, err); } catch (Exception e) { e.printStackTrace(); - pIndicator.setProgressBar(MessageManager.formatMessage( - "info.error_creating_file", "HTML"), pSessionId); + setProgressMessage(MessageManager.formatMessage( + "info.error_creating_file", "HTML")); } setProgressMessage(MessageManager.formatMessage( "status.export_complete", "HTML")); @@ -245,17 +148,6 @@ public class HtmlSvgOutput } - private void setProgressMessage(String message) - { - if (pIndicator != null && !headless) - { - pIndicator.setProgressBar(message, pSessionId); - } - else - { - System.out.println(message); - } - } static JalviewFileChooser getHTMLChooser() { @@ -269,138 +161,13 @@ public class HtmlSvgOutput public int printUnwrapped(int pwidth, int pheight, int pi, Graphics... pg) throws PrinterException { - int idWidth = ap.getVisibleIdWidth(false); - FontMetrics fm = ap.getFontMetrics(av.getFont()); - int scaleHeight = av.getCharHeight() + fm.getDescent(); - - pg[0].setColor(Color.white); - pg[0].fillRect(0, 0, pwidth, pheight); - pg[0].setFont(av.getFont()); - - // ////////////////////////////////// - // / How many sequences and residues can we fit on a printable page? - int totalRes = (pwidth - idWidth) / av.getCharWidth(); - int totalSeq = (pheight - scaleHeight) / av.getCharHeight() - 1; - int pagesWide = (av.getAlignment().getWidth() / totalRes) + 1; - - // /////////////////////////// - // / Only print these sequences and residues on this page - int startRes; - - // /////////////////////////// - // / Only print these sequences and residues on this page - int endRes; - - // /////////////////////////// - // / Only print these sequences and residues on this page - int startSeq; - - // /////////////////////////// - // / Only print these sequences and residues on this page - int endSeq; - startRes = (pi % pagesWide) * totalRes; - endRes = (startRes + totalRes) - 1; - - if (endRes > (av.getAlignment().getWidth() - 1)) - { - endRes = av.getAlignment().getWidth() - 1; - } - startSeq = (pi / pagesWide) * totalSeq; - endSeq = startSeq + totalSeq; - if (endSeq > av.getAlignment().getHeight()) - { - endSeq = av.getAlignment().getHeight(); - } - int pagesHigh = ((av.getAlignment().getHeight() / totalSeq) + 1) - * pheight; - if (av.isShowAnnotation()) - { - pagesHigh += ap.getAnnotationPanel().adjustPanelHeight() + 3; - } - pagesHigh /= pheight; - if (pi >= (pagesWide * pagesHigh)) - { - return Printable.NO_SUCH_PAGE; - } - - // draw Scale - pg[1].translate(0, 0); - ap.getScalePanel().drawScale(pg[1], startRes, endRes, pwidth - idWidth, - scaleHeight); - pg[1].translate(-idWidth, scaleHeight); - - // ////////////// - // Draw the ids - Color currentColor = null; - Color currentTextColor = null; - pg[0].translate(0, scaleHeight); - pg[0].setFont(ap.getIdPanel().getIdCanvas().getIdfont()); - SequenceI seq; - for (int i = startSeq; i < endSeq; i++) - { - seq = av.getAlignment().getSequenceAt(i); - if ((av.getSelectionGroup() != null) - && av.getSelectionGroup().getSequences(null).contains(seq)) - { - currentColor = Color.gray; - currentTextColor = Color.black; - } - else - { - currentColor = av.getSequenceColour(seq); - currentTextColor = Color.black; - } - pg[0].setColor(currentColor); - pg[0].fillRect(0, (i - startSeq) * av.getCharHeight(), idWidth, - av.getCharHeight()); - pg[0].setColor(currentTextColor); - int xPos = 0; - if (av.isRightAlignIds()) - { - fm = pg[0].getFontMetrics(); - xPos = idWidth - - fm.stringWidth(seq.getDisplayId(av.getShowJVSuffix())) - - 4; - } - pg[0].drawString(seq.getDisplayId(av.getShowJVSuffix()), xPos, - (((i - startSeq) * av.getCharHeight()) + av.getCharHeight()) - - (av.getCharHeight() / 5)); - } - pg[0].setFont(av.getFont()); - pg[0].translate(idWidth, 0); - - // draw main sequence panel - pg[1].translate(idWidth, 0); - ap.getSeqPanel().seqCanvas.drawPanel(pg[1], startRes, endRes, startSeq, - endSeq, 0); - if (av.isShowAnnotation() && (endSeq == av.getAlignment().getHeight())) - { - // draw annotation label - need to offset for current scroll position - int offset = -ap.getAlabels().getScrollOffset(); - pg[0].translate(0, offset); - pg[0].translate(-idWidth - 3, - (endSeq - startSeq) * av.getCharHeight() + 3); - ap.getAlabels().drawComponent(pg[0], idWidth); - pg[0].translate(idWidth + 3, 0); - pg[0].translate(0, -offset); - - // draw annotation - need to offset for current scroll position - pg[1].translate(0, offset); - pg[1].translate(-idWidth - 3, - (endSeq - startSeq) * av.getCharHeight() + 3); - pg[1].translate(idWidth + 3, 0); - ap.getAnnotationPanel().renderer.drawComponent( - ap.getAnnotationPanel(), av, pg[1], -1, startRes, endRes + 1); - pg[1].translate(0, -offset); - } - - return Printable.PAGE_EXISTS; + return ap.printUnwrapped(pwidth, pheight, pi, pg); } public int printWrapped(int pwidth, int pheight, int pi, Graphics... pg) throws PrinterException { - return ap.printWrappedAlignment(pg[1], pwidth, pheight, pi); + return ap.printWrappedAlignment(pwidth, pheight, pi, pg[0]); } private String getHtml(String titleSvg, String alignmentSvg, @@ -506,266 +273,37 @@ public class HtmlSvgOutput // jquery facebox for displaying raw BioJSON data"); if (jsonData != null) { - htmlSvg.append("/* Facebox (for jQuery)\n"); - htmlSvg.append("* version: 1.3\n"); - htmlSvg.append(" * @requires jQuery v1.2 or later\n"); - htmlSvg.append(" * @homepage https://github.com/defunkt/facebox\n"); - htmlSvg.append(" * Licensed under the MIT:\n"); - htmlSvg.append(" * http://www.opensource.org/licenses/mit-license.php\n"); - htmlSvg.append(" * Copyright Forever Chris Wanstrath, Kyle Neath\n"); - htmlSvg.append(" * Usage:\n"); - htmlSvg.append(" * jQuery(document).ready(function() {\n"); - htmlSvg.append(" * jQuery('a[rel*=facebox]').facebox()\n"); - htmlSvg.append(" * })\n"); - htmlSvg.append(" * Terms\n"); - htmlSvg.append(" * Loads the #terms div in the box\n"); - htmlSvg.append(" * Terms\n"); - htmlSvg.append(" * Loads the terms.html page in the box\n"); - htmlSvg.append(" * Terms\n"); - htmlSvg.append(" * Loads the terms.png image in the box\n"); - htmlSvg.append(" * You can also use it programmatically:\n"); - htmlSvg.append(" * jQuery.facebox('some html')\n"); - htmlSvg.append(" * jQuery.facebox('some html', 'my-groovy-style')\n"); - htmlSvg.append(" * The above will open a facebox with \"some html\" as the content.\n"); - htmlSvg.append(" * jQuery.facebox(function($) {\n"); - htmlSvg.append(" * $.get('blah.html', function(data) { $.facebox(data) })\n"); - htmlSvg.append(" * })\n"); - htmlSvg.append(" * The above will show a loading screen before the passed function is called,\n"); - htmlSvg.append(" * allowing for a better ajaxy experience.\n"); - htmlSvg.append(" * The facebox function can also display an ajax page, an image, or the contents of a div:\n"); - htmlSvg.append(" * jQuery.facebox({ ajax: 'remote.html' })\n"); - htmlSvg.append(" * jQuery.facebox({ ajax: 'remote.html' }, 'my-groovy-style')\n"); - htmlSvg.append(" * jQuery.facebox({ image: 'stairs.jpg' })\n"); - htmlSvg.append(" * jQuery.facebox({ image: 'stairs.jpg' }, 'my-groovy-style')\n"); - htmlSvg.append(" * jQuery.facebox({ div: '#box' })\n"); - htmlSvg.append(" * jQuery.facebox({ div: '#box' }, 'my-groovy-style')\n"); - htmlSvg.append(" * Want to close the facebox? Trigger the 'close.facebox' document event:\n"); - htmlSvg.append(" * jQuery(document).trigger('close.facebox')\n"); - htmlSvg.append(" * Facebox also has a bunch of other hooks:\n"); - htmlSvg.append(" * loading.facebox\n"); - htmlSvg.append(" * beforeReveal.facebox\n"); - htmlSvg.append(" * reveal.facebox (aliased as 'afterReveal.facebox')\n"); - htmlSvg.append(" * init.facebox\n"); - htmlSvg.append(" * afterClose.facebox\n"); - htmlSvg.append(" * Simply bind a function to any of these hooks:\n"); - htmlSvg.append(" * $(document).bind('reveal.facebox', function() { ...stuff to do after the facebox and contents are revealed... })\n"); - htmlSvg.append(" *\n"); - htmlSvg.append(" */\n"); - htmlSvg.append("(function($) {\n"); - htmlSvg.append(" $.facebox = function(data, klass) {\n"); - htmlSvg.append(" $.facebox.loading()\n"); - htmlSvg.append(" if (data.ajax) fillFaceboxFromAjax(data.ajax, klass)\n"); - htmlSvg.append(" else if (data.image) fillFaceboxFromImage(data.image, klass)\n"); - htmlSvg.append(" else if (data.div) fillFaceboxFromHref(data.div, klass)\n"); - htmlSvg.append(" else if ($.isFunction(data)) data.call($)\n"); - htmlSvg.append(" else $.facebox.reveal(data, klass)\n"); - htmlSvg.append(" }\n"); - - htmlSvg.append(" $.extend($.facebox, {\n"); - htmlSvg.append(" settings: {\n"); - htmlSvg.append(" opacity : 0.2,\n"); - htmlSvg.append(" overlay : true,\n"); - htmlSvg.append(" loadingImage : 'https://raw.githubusercontent.com/jalview/biojson/gh-pages/images/loading.gif',\n"); - htmlSvg.append(" closeImage : 'https://raw.githubusercontent.com/jalview/biojson/gh-pages/images/cancel.png',\n"); - htmlSvg.append(" imageTypes : [ 'png', 'jpg', 'jpeg', 'gif' ],\n"); - htmlSvg.append(" faceboxHtml : '

"); - htmlSvg.append("
"); - htmlSvg.append("
"); - htmlSvg.append("
"); - htmlSvg.append(" "); - htmlSvg.append("
"); - htmlSvg.append("
'\n"); - htmlSvg.append(" }, \n"); - htmlSvg.append(" loading: function() {\n"); - htmlSvg.append(" init()\n"); - htmlSvg.append(" if ($('#facebox .loading').length == 1) return true\n"); - htmlSvg.append(" showOverlay() \n"); - htmlSvg.append(" $('#facebox .content').empty().\n"); - htmlSvg.append(" append('
')\n"); - htmlSvg.append(" $('#facebox').show().css({\n"); - htmlSvg.append(" top: getPageScroll()[1] + (getPageHeight() / 10),\n"); - htmlSvg.append(" left: $(window).width() / 2 - ($('#facebox .popup').outerWidth() / 2)\n"); - htmlSvg.append(" }) \n"); - htmlSvg.append(" $(document).bind('keydown.facebox', function(e) {\n"); - htmlSvg.append(" if (e.keyCode == 27) $.facebox.close()\n"); - htmlSvg.append(" return true\n"); - htmlSvg.append(" })\n"); - htmlSvg.append(" $(document).trigger('loading.facebox')\n"); - htmlSvg.append(" },\n"); - htmlSvg.append(" reveal: function(data, klass) {\n"); - htmlSvg.append(" $(document).trigger('beforeReveal.facebox')\n"); - htmlSvg.append(" if (klass) $('#facebox .content').addClass(klass)\n"); - htmlSvg.append(" $('#facebox .content').empty().append('
'+JSON.stringify(JSON.parse(data),null,4)+'
')\n"); - htmlSvg.append(" $('#facebox .popup').children().fadeIn('normal')\n"); - htmlSvg.append(" $('#facebox').css('left', $(window).width() / 2 - ($('#facebox .popup').outerWidth() / 2))\n"); - htmlSvg.append(" $(document).trigger('reveal.facebox').trigger('afterReveal.facebox')\n"); - htmlSvg.append(" }, \n"); - htmlSvg.append(" close: function() {\n"); - htmlSvg.append(" $(document).trigger('close.facebox')\n"); - htmlSvg.append(" return false\n"); - htmlSvg.append(" }\n"); - htmlSvg.append(" })\n"); - htmlSvg.append(" $.fn.facebox = function(settings) {\n"); - htmlSvg.append(" if ($(this).length == 0) return \n"); - htmlSvg.append(" init(settings) \n"); - htmlSvg.append(" function clickHandler() {\n"); - htmlSvg.append(" $.facebox.loading(true) \n"); - htmlSvg.append(" // support for rel=\"facebox.inline_popup\" syntax, to add a class\n"); - htmlSvg.append(" // also supports deprecated \"facebox[.inline_popup]\" syntax\n"); - htmlSvg.append(" var klass = this.rel.match(/facebox\\[?\\.(\\w+)\\]?/)\n"); - htmlSvg.append(" if (klass) klass = klass[1]\n"); - htmlSvg.append(" fillFaceboxFromHref(this.href, klass)\n"); - htmlSvg.append(" return false\n"); - htmlSvg.append(" } \n"); - htmlSvg.append(" return this.bind('click.facebox', clickHandler)\n"); - htmlSvg.append(" }\n"); - htmlSvg.append(" // called one time to setup facebox on this page\n"); - htmlSvg.append(" function init(settings) {\n"); - htmlSvg.append(" if ($.facebox.settings.inited) return true\n"); - htmlSvg.append(" else $.facebox.settings.inited = true\n"); - htmlSvg.append(" $(document).trigger('init.facebox')\n"); - htmlSvg.append(" makeCompatible()\n"); - htmlSvg.append(" var imageTypes = $.facebox.settings.imageTypes.join('|')\n"); - htmlSvg.append(" $.facebox.settings.imageTypesRegexp = new RegExp('\\\\.(' + imageTypes + ')(\\\\?.*)?$', 'i')\n"); - - htmlSvg.append(" if (settings) $.extend($.facebox.settings, settings)\n"); - htmlSvg.append(" $('body').append($.facebox.settings.faceboxHtml)\n"); - - htmlSvg.append(" var preload = [ new Image(), new Image() ]\n"); - htmlSvg.append(" preload[0].src = $.facebox.settings.closeImage\n"); - htmlSvg.append(" preload[1].src = $.facebox.settings.loadingImage\n"); - - htmlSvg.append(" $('#facebox').find('.b:first, .bl').each(function() {\n"); - htmlSvg.append(" preload.push(new Image())\n"); - htmlSvg.append(" preload.slice(-1).src = $(this).css('background-image').replace(/url\\((.+)\\)/, '$1')\n"); - htmlSvg.append(" })\n"); - - htmlSvg.append(" $('#facebox .close')\n"); - htmlSvg.append(" .click($.facebox.close)\n"); - htmlSvg.append(" .append('')\n"); - htmlSvg.append(" }\n"); - - htmlSvg.append(" // getPageScroll() by quirksmode.com\n"); - htmlSvg.append(" function getPageScroll() {\n"); - htmlSvg.append(" var xScroll, yScroll;\n"); - htmlSvg.append(" if (self.pageYOffset) {\n"); - htmlSvg.append(" yScroll = self.pageYOffset;\n"); - htmlSvg.append(" xScroll = self.pageXOffset;\n"); - htmlSvg.append(" } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict\n"); - htmlSvg.append(" yScroll = document.documentElement.scrollTop;\n"); - htmlSvg.append(" xScroll = document.documentElement.scrollLeft;\n"); - htmlSvg.append(" } else if (document.body) {// all other Explorers\n"); - htmlSvg.append(" yScroll = document.body.scrollTop;\n"); - htmlSvg.append(" xScroll = document.body.scrollLeft;\n"); - htmlSvg.append(" }\n"); - htmlSvg.append(" return new Array(xScroll,yScroll)\n"); - htmlSvg.append(" }\n"); - - // Adapted from getPageSize() by quirksmode.com"); - htmlSvg.append(" function getPageHeight() {\n"); - htmlSvg.append(" var windowHeight\n"); - htmlSvg.append(" if (self.innerHeight) { // all except Explorer\n"); - htmlSvg.append(" windowHeight = self.innerHeight;\n"); - htmlSvg.append(" } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode\n"); - htmlSvg.append(" windowHeight = document.documentElement.clientHeight;\n"); - htmlSvg.append(" } else if (document.body) { // other Explorers\n"); - htmlSvg.append(" windowHeight = document.body.clientHeight;\n"); - htmlSvg.append(" }\n"); - htmlSvg.append(" return windowHeight\n"); - htmlSvg.append(" }\n"); - - htmlSvg.append(" // Backwards compatibility\n"); - htmlSvg.append(" function makeCompatible() {\n"); - htmlSvg.append(" var $s = $.facebox.settings \n"); - htmlSvg.append(" $s.loadingImage = $s.loading_image || $s.loadingImage\n"); - htmlSvg.append(" $s.closeImage = $s.close_image || $s.closeImage\n"); - htmlSvg.append(" $s.imageTypes = $s.image_types || $s.imageTypes\n"); - htmlSvg.append(" $s.faceboxHtml = $s.facebox_html || $s.faceboxHtml\n"); - htmlSvg.append(" }\n"); - - htmlSvg.append(" // Figures out what you want to display and displays it\n"); - htmlSvg.append(" // formats are:\n"); - htmlSvg.append(" // div: #id\n"); - htmlSvg.append(" // image: blah.extension\n"); - htmlSvg.append(" // ajax: anything else\n"); - htmlSvg.append(" function fillFaceboxFromHref(href, klass) {\n"); - htmlSvg.append(" // div\n"); - htmlSvg.append(" if (href.match(/#/)) {\n"); - htmlSvg.append(" var url = window.location.href.split('#')[0]\n"); - htmlSvg.append(" var target = href.replace(url,'')\n"); - htmlSvg.append(" if (target == '#') return\n"); - htmlSvg.append(" $.facebox.reveal($(target).html(), klass)\n"); - - htmlSvg.append(" // image\n"); - htmlSvg.append(" } else if (href.match($.facebox.settings.imageTypesRegexp)) {\n"); - htmlSvg.append(" fillFaceboxFromImage(href, klass)\n"); - htmlSvg.append(" // ajax\n"); - htmlSvg.append(" } else {\n"); - htmlSvg.append(" fillFaceboxFromAjax(href, klass)\n"); - htmlSvg.append(" }\n"); - htmlSvg.append(" }\n"); - - htmlSvg.append(" function fillFaceboxFromImage(href, klass) {\n"); - htmlSvg.append(" var image = new Image()\n"); - htmlSvg.append(" image.onload = function() {\n"); - htmlSvg.append(" $.facebox.reveal('
', klass)\n"); - htmlSvg.append(" }\n"); - htmlSvg.append(" image.src = href\n"); - htmlSvg.append(" }\n"); - - htmlSvg.append(" function fillFaceboxFromAjax(href, klass) {\n"); - htmlSvg.append(" $.facebox.jqxhr = $.get(href, function(data) { $.facebox.reveal(data, klass) })\n"); - htmlSvg.append(" }\n"); - - htmlSvg.append(" function skipOverlay() {\n"); - htmlSvg.append(" return $.facebox.settings.overlay == false || $.facebox.settings.opacity === null\n"); - htmlSvg.append(" }\n"); - - htmlSvg.append(" function showOverlay() {\n"); - htmlSvg.append(" if (skipOverlay()) return\n"); - - htmlSvg.append(" if ($('#facebox_overlay').length == 0)\n"); - htmlSvg.append(" $(\"body\").append('
')\n"); - - htmlSvg.append(" $('#facebox_overlay').hide().addClass(\"facebox_overlayBG\")\n"); - htmlSvg.append(" .css('opacity', $.facebox.settings.opacity)\n"); - htmlSvg.append(" .click(function() { $(document).trigger('close.facebox') })\n"); - htmlSvg.append(" .fadeIn(200)\n"); - htmlSvg.append(" return false\n"); - htmlSvg.append(" }\n"); - - htmlSvg.append(" function hideOverlay() {\n"); - htmlSvg.append(" if (skipOverlay()) return \n"); - htmlSvg.append(" $('#facebox_overlay').fadeOut(200, function(){\n"); - htmlSvg.append(" $(\"#facebox_overlay\").removeClass(\"facebox_overlayBG\")\n"); - htmlSvg.append(" $(\"#facebox_overlay\").addClass(\"facebox_hide\")\n"); - htmlSvg.append(" $(\"#facebox_overlay\").remove()\n"); - htmlSvg.append(" }) \n"); - htmlSvg.append(" return false\n"); - htmlSvg.append(" }\n"); - - htmlSvg.append(" $(document).bind('close.facebox', function() {\n"); - htmlSvg.append(" if ($.facebox.jqxhr) {\n"); - htmlSvg.append(" $.facebox.jqxhr.abort()\n"); - htmlSvg.append(" $.facebox.jqxhr = null\n"); - htmlSvg.append(" }\n"); - htmlSvg.append(" $(document).unbind('keydown.facebox')\n"); - htmlSvg.append(" $('#facebox').fadeOut(function() {\n"); - htmlSvg.append(" $('#facebox .content').removeClass().addClass('content')\n"); - htmlSvg.append(" $('#facebox .loading').remove()\n"); - htmlSvg.append(" $(document).trigger('afterClose.facebox')\n"); - htmlSvg.append(" })\n"); - htmlSvg.append(" hideOverlay()\n"); - htmlSvg.append(" })\n"); - - htmlSvg.append("})(jQuery);\n"); - + File faceBoxJsFile = new File("examples/javascript/facebox-1.3.js"); + try + { + htmlSvg.append(HTMLOutput.readFileAsString(faceBoxJsFile)); + } catch (IOException e) + { + e.printStackTrace(); + } } htmlSvg.append("\n"); htmlSvg.append(""); return htmlSvg.toString(); } + + @Override + public boolean isEmbedData() + { + return Boolean.valueOf(jalview.bin.Cache.getDefault( + "EXPORT_EMBBED_BIOJSON", "true")); + } + + @Override + public boolean isLaunchInBrowserAfterExport() + { + return true; + } + + @Override + public File getExportedFile() + { + return generatedFile; + } } diff --git a/src/jalview/io/SequenceAnnotationReport.java b/src/jalview/io/SequenceAnnotationReport.java index 59daa87..850b1dc 100644 --- a/src/jalview/io/SequenceAnnotationReport.java +++ b/src/jalview/io/SequenceAnnotationReport.java @@ -25,13 +25,13 @@ import jalview.datamodel.DBRefSource; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.io.gff.GffConstants; -import jalview.util.DBRefUtils; import jalview.util.MessageManager; import jalview.util.UrlLink; -import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Comparator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -266,16 +266,17 @@ public class SequenceAnnotationReport { try { - for (String[] urllink : createLinksFrom(null, urlstring)) + for (List urllink : createLinksFrom(null, urlstring)) { sb.append("
" - + (urllink[0].toLowerCase().equals( - urllink[1].toLowerCase()) ? urllink[0] - : (urllink[0] + ":" + urllink[1])) + + (urllink.get(0).toLowerCase() + .equals(urllink.get(1).toLowerCase()) ? urllink + .get(0) : (urllink.get(0) + ":" + urllink + .get(1))) + "
"); } } catch (Exception x) @@ -294,125 +295,22 @@ public class SequenceAnnotationReport * * @param seq * @param link - * @return String[][] { String[] { link target, link label, dynamic component - * inserted (if any), url }} + * @return Collection< List > { List { link target, link + * label, dynamic component inserted (if any), url }} */ - String[][] createLinksFrom(SequenceI seq, String link) + Collection> createLinksFrom(SequenceI seq, String link) { - List urlSets = new ArrayList(); - List uniques = new ArrayList(); + Map> urlSets = new LinkedHashMap>(); UrlLink urlLink = new UrlLink(link); if (!urlLink.isValid()) { System.err.println(urlLink.getInvalidMessage()); return null; } - final String target = urlLink.getTarget(); // link.substring(0, - // link.indexOf("|")); - final String label = urlLink.getLabel(); - if (seq != null && urlLink.isDynamic()) - { - urlSets.addAll(createDynamicLinks(seq, urlLink, uniques)); - } - else - { - String unq = label + "|" + urlLink.getUrl_prefix(); - if (!uniques.contains(unq)) - { - uniques.add(unq); - urlSets.add(new String[] { target, label, null, - urlLink.getUrl_prefix() }); - } - } - - return urlSets.toArray(new String[][] {}); - } - /** - * Formats and returns a list of dynamic href links - * - * @param seq - * @param urlLink - * @param uniques - */ - List createDynamicLinks(SequenceI seq, UrlLink urlLink, - List uniques) - { - List result = new ArrayList(); - final String target = urlLink.getTarget(); - final String label = urlLink.getLabel(); + urlLink.createLinksFromSeq(seq, urlSets); - // collect matching db-refs - DBRefEntry[] dbr = DBRefUtils.selectRefs(seq.getDBRefs(), - new String[] { target }); - // collect id string too - String id = seq.getName(); - String descr = seq.getDescription(); - if (descr != null && descr.length() < 1) - { - descr = null; - } - if (dbr != null) - { - for (int r = 0; r < dbr.length; r++) - { - if (id != null && dbr[r].getAccessionId().equals(id)) - { - // suppress duplicate link creation for the bare sequence ID - // string with this link - id = null; - } - // create Bare ID link for this URL - String[] urls = urlLink.makeUrls(dbr[r].getAccessionId(), true); - if (urls != null) - { - for (int u = 0; u < urls.length; u += 2) - { - String unq = urls[u] + "|" + urls[u + 1]; - if (!uniques.contains(unq)) - { - result.add(new String[] { target, label, urls[u], urls[u + 1] }); - uniques.add(unq); - } - } - } - } - } - if (id != null) - { - // create Bare ID link for this URL - String[] urls = urlLink.makeUrls(id, true); - if (urls != null) - { - for (int u = 0; u < urls.length; u += 2) - { - String unq = urls[u] + "|" + urls[u + 1]; - if (!uniques.contains(unq)) - { - result.add(new String[] { target, label, urls[u], urls[u + 1] }); - uniques.add(unq); - } - } - } - } - if (descr != null && urlLink.getRegexReplace() != null) - { - // create link for this URL from description only if regex matches - String[] urls = urlLink.makeUrls(descr, true); - if (urls != null) - { - for (int u = 0; u < urls.length; u += 2) - { - String unq = urls[u] + "|" + urls[u + 1]; - if (!uniques.contains(unq)) - { - result.add(new String[] { target, label, urls[u], urls[u + 1] }); - uniques.add(unq); - } - } - } - } - return result; + return urlSets.values(); } public void createSequenceAnnotationReport(final StringBuilder tip, diff --git a/src/jalview/io/StructureFile.java b/src/jalview/io/StructureFile.java index 26c202c..97b246f 100644 --- a/src/jalview/io/StructureFile.java +++ b/src/jalview/io/StructureFile.java @@ -45,6 +45,11 @@ public abstract class StructureFile extends AlignFile private String id; + public enum StructureFileType + { + PDB, MMCIF, MMTF + }; + private PDBEntry.Type dbRefType; /** @@ -484,4 +489,20 @@ public abstract class StructureFile extends AlignFile { this.pdbIdAvailable = pdbIdAvailable; } + + public static boolean isStructureFile(String fileType) + { + if (fileType == null) + { + return false; + } + for (StructureFileType sfType : StructureFileType.values()) + { + if (sfType.name().equalsIgnoreCase(fileType)) + { + return true; + } + } + return false; + } } diff --git a/src/jalview/jbgui/GSequenceLink.java b/src/jalview/jbgui/GSequenceLink.java index b27752e..2689946 100755 --- a/src/jalview/jbgui/GSequenceLink.java +++ b/src/jalview/jbgui/GSequenceLink.java @@ -67,7 +67,7 @@ public class GSequenceLink extends Panel } }); urlTB.setFont(JvSwingUtils.getLabelFont()); - urlTB.setText("http://www."); + urlTB.setText("http://"); urlTB.setBounds(new Rectangle(78, 40, 309, 23)); urlTB.addKeyListener(new KeyAdapter() { diff --git a/src/jalview/renderer/AnnotationRenderer.java b/src/jalview/renderer/AnnotationRenderer.java index ed758c5..d7ae950 100644 --- a/src/jalview/renderer/AnnotationRenderer.java +++ b/src/jalview/renderer/AnnotationRenderer.java @@ -22,13 +22,13 @@ package jalview.renderer; import jalview.analysis.AAFrequency; import jalview.analysis.CodingUtils; -import jalview.analysis.Profile; import jalview.analysis.Rna; import jalview.analysis.StructureFrequency; import jalview.api.AlignViewportI; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.Annotation; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.ProfileI; import jalview.schemes.ColourSchemeI; import jalview.schemes.ResidueProperties; import jalview.util.Platform; @@ -74,7 +74,7 @@ public class AnnotationRenderer private ColumnSelection columnSelection; - private Profile[] hconsensus; + private ProfileI[] hconsensus; private Hashtable[] complementConsensus; diff --git a/src/jalview/schemes/ColourSchemeI.java b/src/jalview/schemes/ColourSchemeI.java index 165ece9..fb71686 100755 --- a/src/jalview/schemes/ColourSchemeI.java +++ b/src/jalview/schemes/ColourSchemeI.java @@ -20,8 +20,8 @@ */ package jalview.schemes; -import jalview.analysis.Profile; import jalview.datamodel.AnnotatedCollectionI; +import jalview.datamodel.ProfileI; import jalview.datamodel.SequenceCollectionI; import jalview.datamodel.SequenceI; @@ -53,7 +53,7 @@ public interface ColourSchemeI /** * assign the given consensus profile for the colourscheme */ - public void setConsensus(Profile[] hconsensus); + public void setConsensus(ProfileI[] hconsensus); /** * assign the given conservation to the colourscheme diff --git a/src/jalview/schemes/FollowerColourScheme.java b/src/jalview/schemes/FollowerColourScheme.java index 0dcf960..86fce4e 100644 --- a/src/jalview/schemes/FollowerColourScheme.java +++ b/src/jalview/schemes/FollowerColourScheme.java @@ -21,7 +21,7 @@ package jalview.schemes; import jalview.analysis.Conservation; -import jalview.analysis.Profile; +import jalview.datamodel.ProfileI; /** * Colourscheme that takes its colours from some other colourscheme @@ -40,7 +40,7 @@ public class FollowerColourScheme extends ResidueColourScheme } @Override - public void setConsensus(Profile[] consensus) + public void setConsensus(ProfileI[] consensus) { if (colourScheme != null) { diff --git a/src/jalview/schemes/ResidueColourScheme.java b/src/jalview/schemes/ResidueColourScheme.java index a15ca20..31b8320 100755 --- a/src/jalview/schemes/ResidueColourScheme.java +++ b/src/jalview/schemes/ResidueColourScheme.java @@ -21,8 +21,8 @@ package jalview.schemes; import jalview.analysis.Conservation; -import jalview.analysis.Profile; import jalview.datamodel.AnnotatedCollectionI; +import jalview.datamodel.ProfileI; import jalview.datamodel.SequenceCollectionI; import jalview.datamodel.SequenceI; import jalview.util.ColorUtils; @@ -54,7 +54,7 @@ public class ResidueColourScheme implements ColourSchemeI /* * Consensus data indexed by column */ - Profile[] consensus; + ProfileI[] consensus; /* * Conservation string as a char array @@ -234,7 +234,7 @@ public class ResidueColourScheme implements ColourSchemeI * DOCUMENT ME! */ @Override - public void setConsensus(Profile[] consensus) + public void setConsensus(ProfileI[] consensus) { if (consensus == null) { diff --git a/src/jalview/schemes/ResidueProperties.java b/src/jalview/schemes/ResidueProperties.java index 90a7952..4d46279 100755 --- a/src/jalview/schemes/ResidueProperties.java +++ b/src/jalview/schemes/ResidueProperties.java @@ -222,10 +222,14 @@ public class ResidueProperties purinepyrimidineIndex['n'] = 2; } + private static final Integer ONE = Integer.valueOf(1); + + private static final Integer ZERO = Integer.valueOf(0); + static { - aa3Hash.put("ALA", Integer.valueOf(0)); - aa3Hash.put("ARG", Integer.valueOf(1)); + aa3Hash.put("ALA", ZERO); + aa3Hash.put("ARG", ONE); aa3Hash.put("ASN", Integer.valueOf(2)); aa3Hash.put("ASP", Integer.valueOf(3)); // D aa3Hash.put("CYS", Integer.valueOf(4)); @@ -910,267 +914,267 @@ public class ResidueProperties static { - hydrophobic.put("I", Integer.valueOf(1)); - hydrophobic.put("L", Integer.valueOf(1)); - hydrophobic.put("V", Integer.valueOf(1)); - hydrophobic.put("C", Integer.valueOf(1)); - hydrophobic.put("A", Integer.valueOf(1)); - hydrophobic.put("G", Integer.valueOf(1)); - hydrophobic.put("M", Integer.valueOf(1)); - hydrophobic.put("F", Integer.valueOf(1)); - hydrophobic.put("Y", Integer.valueOf(1)); - hydrophobic.put("W", Integer.valueOf(1)); - hydrophobic.put("H", Integer.valueOf(1)); - hydrophobic.put("K", Integer.valueOf(1)); - hydrophobic.put("X", Integer.valueOf(1)); - hydrophobic.put("-", Integer.valueOf(1)); - hydrophobic.put("*", Integer.valueOf(1)); - hydrophobic.put("R", Integer.valueOf(0)); - hydrophobic.put("E", Integer.valueOf(0)); - hydrophobic.put("Q", Integer.valueOf(0)); - hydrophobic.put("D", Integer.valueOf(0)); - hydrophobic.put("N", Integer.valueOf(0)); - hydrophobic.put("S", Integer.valueOf(0)); - hydrophobic.put("T", Integer.valueOf(0)); - hydrophobic.put("P", Integer.valueOf(0)); + hydrophobic.put("I", ONE); + hydrophobic.put("L", ONE); + hydrophobic.put("V", ONE); + hydrophobic.put("C", ONE); + hydrophobic.put("A", ONE); + hydrophobic.put("G", ONE); + hydrophobic.put("M", ONE); + hydrophobic.put("F", ONE); + hydrophobic.put("Y", ONE); + hydrophobic.put("W", ONE); + hydrophobic.put("H", ONE); + hydrophobic.put("K", ONE); + hydrophobic.put("X", ONE); + hydrophobic.put("-", ONE); + hydrophobic.put("*", ONE); + hydrophobic.put("R", ZERO); + hydrophobic.put("E", ZERO); + hydrophobic.put("Q", ZERO); + hydrophobic.put("D", ZERO); + hydrophobic.put("N", ZERO); + hydrophobic.put("S", ZERO); + hydrophobic.put("T", ONE); + hydrophobic.put("P", ZERO); } static { - polar.put("Y", Integer.valueOf(1)); - polar.put("W", Integer.valueOf(1)); - polar.put("H", Integer.valueOf(1)); - polar.put("K", Integer.valueOf(1)); - polar.put("R", Integer.valueOf(1)); - polar.put("E", Integer.valueOf(1)); - polar.put("Q", Integer.valueOf(1)); - polar.put("D", Integer.valueOf(1)); - polar.put("N", Integer.valueOf(1)); - polar.put("S", Integer.valueOf(1)); - polar.put("T", Integer.valueOf(1)); - polar.put("X", Integer.valueOf(1)); - polar.put("-", Integer.valueOf(1)); - polar.put("*", Integer.valueOf(1)); - polar.put("I", Integer.valueOf(0)); - polar.put("L", Integer.valueOf(0)); - polar.put("V", Integer.valueOf(0)); - polar.put("C", Integer.valueOf(0)); - polar.put("A", Integer.valueOf(0)); - polar.put("G", Integer.valueOf(0)); - polar.put("M", Integer.valueOf(0)); - polar.put("F", Integer.valueOf(0)); - polar.put("P", Integer.valueOf(0)); + polar.put("Y", ONE); + polar.put("W", ONE); + polar.put("H", ONE); + polar.put("K", ONE); + polar.put("R", ONE); + polar.put("E", ONE); + polar.put("Q", ONE); + polar.put("D", ONE); + polar.put("N", ONE); + polar.put("S", ONE); + polar.put("T", ONE); + polar.put("X", ONE); + polar.put("-", ONE); + polar.put("*", ONE); + polar.put("I", ZERO); + polar.put("L", ZERO); + polar.put("V", ZERO); + polar.put("C", ZERO); + polar.put("A", ZERO); + polar.put("G", ZERO); + polar.put("M", ZERO); + polar.put("F", ZERO); + polar.put("P", ZERO); } static { - small.put("I", Integer.valueOf(0)); - small.put("L", Integer.valueOf(0)); - small.put("V", Integer.valueOf(1)); - small.put("C", Integer.valueOf(1)); - small.put("A", Integer.valueOf(1)); - small.put("G", Integer.valueOf(1)); - small.put("M", Integer.valueOf(0)); - small.put("F", Integer.valueOf(0)); - small.put("Y", Integer.valueOf(0)); - small.put("W", Integer.valueOf(0)); - small.put("H", Integer.valueOf(0)); - small.put("K", Integer.valueOf(0)); - small.put("R", Integer.valueOf(0)); - small.put("E", Integer.valueOf(0)); - small.put("Q", Integer.valueOf(0)); - small.put("D", Integer.valueOf(1)); - small.put("N", Integer.valueOf(1)); - small.put("S", Integer.valueOf(1)); - small.put("T", Integer.valueOf(1)); - small.put("P", Integer.valueOf(1)); - small.put("-", Integer.valueOf(1)); - small.put("*", Integer.valueOf(1)); + small.put("I", ZERO); + small.put("L", ZERO); + small.put("V", ONE); + small.put("C", ONE); + small.put("A", ONE); + small.put("G", ONE); + small.put("M", ZERO); + small.put("F", ZERO); + small.put("Y", ZERO); + small.put("W", ZERO); + small.put("H", ZERO); + small.put("K", ZERO); + small.put("R", ZERO); + small.put("E", ZERO); + small.put("Q", ZERO); + small.put("D", ONE); + small.put("N", ONE); + small.put("S", ONE); + small.put("T", ONE); + small.put("P", ONE); + small.put("-", ONE); + small.put("*", ONE); } static { - positive.put("I", Integer.valueOf(0)); - positive.put("L", Integer.valueOf(0)); - positive.put("V", Integer.valueOf(0)); - positive.put("C", Integer.valueOf(0)); - positive.put("A", Integer.valueOf(0)); - positive.put("G", Integer.valueOf(0)); - positive.put("M", Integer.valueOf(0)); - positive.put("F", Integer.valueOf(0)); - positive.put("Y", Integer.valueOf(0)); - positive.put("W", Integer.valueOf(0)); - positive.put("H", Integer.valueOf(1)); - positive.put("K", Integer.valueOf(1)); - positive.put("R", Integer.valueOf(1)); - positive.put("E", Integer.valueOf(0)); - positive.put("Q", Integer.valueOf(0)); - positive.put("D", Integer.valueOf(0)); - positive.put("N", Integer.valueOf(0)); - positive.put("S", Integer.valueOf(0)); - positive.put("T", Integer.valueOf(0)); - positive.put("P", Integer.valueOf(0)); - positive.put("-", Integer.valueOf(1)); - positive.put("*", Integer.valueOf(1)); + positive.put("I", ZERO); + positive.put("L", ZERO); + positive.put("V", ZERO); + positive.put("C", ZERO); + positive.put("A", ZERO); + positive.put("G", ZERO); + positive.put("M", ZERO); + positive.put("F", ZERO); + positive.put("Y", ZERO); + positive.put("W", ZERO); + positive.put("H", ONE); + positive.put("K", ONE); + positive.put("R", ONE); + positive.put("E", ZERO); + positive.put("Q", ZERO); + positive.put("D", ZERO); + positive.put("N", ZERO); + positive.put("S", ZERO); + positive.put("T", ZERO); + positive.put("P", ZERO); + positive.put("-", ONE); + positive.put("*", ONE); } static { - negative.put("I", Integer.valueOf(0)); - negative.put("L", Integer.valueOf(0)); - negative.put("V", Integer.valueOf(0)); - negative.put("C", Integer.valueOf(0)); - negative.put("A", Integer.valueOf(0)); - negative.put("G", Integer.valueOf(0)); - negative.put("M", Integer.valueOf(0)); - negative.put("F", Integer.valueOf(0)); - negative.put("Y", Integer.valueOf(0)); - negative.put("W", Integer.valueOf(0)); - negative.put("H", Integer.valueOf(0)); - negative.put("K", Integer.valueOf(0)); - negative.put("R", Integer.valueOf(0)); - negative.put("E", Integer.valueOf(1)); - negative.put("Q", Integer.valueOf(0)); - negative.put("D", Integer.valueOf(1)); - negative.put("N", Integer.valueOf(0)); - negative.put("S", Integer.valueOf(0)); - negative.put("T", Integer.valueOf(0)); - negative.put("P", Integer.valueOf(0)); - negative.put("-", Integer.valueOf(1)); - negative.put("*", Integer.valueOf(1)); + negative.put("I", ZERO); + negative.put("L", ZERO); + negative.put("V", ZERO); + negative.put("C", ZERO); + negative.put("A", ZERO); + negative.put("G", ZERO); + negative.put("M", ZERO); + negative.put("F", ZERO); + negative.put("Y", ZERO); + negative.put("W", ZERO); + negative.put("H", ZERO); + negative.put("K", ZERO); + negative.put("R", ZERO); + negative.put("E", ONE); + negative.put("Q", ZERO); + negative.put("D", ONE); + negative.put("N", ZERO); + negative.put("S", ZERO); + negative.put("T", ZERO); + negative.put("P", ZERO); + negative.put("-", ONE); + negative.put("*", ONE); } static { - charged.put("I", Integer.valueOf(0)); - charged.put("L", Integer.valueOf(0)); - charged.put("V", Integer.valueOf(0)); - charged.put("C", Integer.valueOf(0)); - charged.put("A", Integer.valueOf(0)); - charged.put("G", Integer.valueOf(0)); - charged.put("M", Integer.valueOf(0)); - charged.put("F", Integer.valueOf(0)); - charged.put("Y", Integer.valueOf(0)); - charged.put("W", Integer.valueOf(0)); - charged.put("H", Integer.valueOf(1)); - charged.put("K", Integer.valueOf(1)); - charged.put("R", Integer.valueOf(1)); - charged.put("E", Integer.valueOf(1)); - charged.put("Q", Integer.valueOf(0)); - charged.put("D", Integer.valueOf(1)); - charged.put("N", Integer.valueOf(0)); // Asparagine is polar but not + charged.put("I", ZERO); + charged.put("L", ZERO); + charged.put("V", ZERO); + charged.put("C", ZERO); + charged.put("A", ZERO); + charged.put("G", ZERO); + charged.put("M", ZERO); + charged.put("F", ZERO); + charged.put("Y", ZERO); + charged.put("W", ZERO); + charged.put("H", ONE); + charged.put("K", ONE); + charged.put("R", ONE); + charged.put("E", ONE); + charged.put("Q", ZERO); + charged.put("D", ONE); + charged.put("N", ZERO); // Asparagine is polar but not // charged. // Alternative would be charged and // negative (in basic form)? - charged.put("S", Integer.valueOf(0)); - charged.put("T", Integer.valueOf(0)); - charged.put("P", Integer.valueOf(0)); - charged.put("-", Integer.valueOf(1)); - charged.put("*", Integer.valueOf(1)); + charged.put("S", ZERO); + charged.put("T", ZERO); + charged.put("P", ZERO); + charged.put("-", ONE); + charged.put("*", ONE); } static { - aromatic.put("I", Integer.valueOf(0)); - aromatic.put("L", Integer.valueOf(0)); - aromatic.put("V", Integer.valueOf(0)); - aromatic.put("C", Integer.valueOf(0)); - aromatic.put("A", Integer.valueOf(0)); - aromatic.put("G", Integer.valueOf(0)); - aromatic.put("M", Integer.valueOf(0)); - aromatic.put("F", Integer.valueOf(1)); - aromatic.put("Y", Integer.valueOf(1)); - aromatic.put("W", Integer.valueOf(1)); - aromatic.put("H", Integer.valueOf(1)); - aromatic.put("K", Integer.valueOf(0)); - aromatic.put("R", Integer.valueOf(0)); - aromatic.put("E", Integer.valueOf(0)); - aromatic.put("Q", Integer.valueOf(0)); - aromatic.put("D", Integer.valueOf(0)); - aromatic.put("N", Integer.valueOf(0)); - aromatic.put("S", Integer.valueOf(0)); - aromatic.put("T", Integer.valueOf(0)); - aromatic.put("P", Integer.valueOf(0)); - aromatic.put("-", Integer.valueOf(1)); - aromatic.put("*", Integer.valueOf(1)); + aromatic.put("I", ZERO); + aromatic.put("L", ZERO); + aromatic.put("V", ZERO); + aromatic.put("C", ZERO); + aromatic.put("A", ZERO); + aromatic.put("G", ZERO); + aromatic.put("M", ZERO); + aromatic.put("F", ONE); + aromatic.put("Y", ONE); + aromatic.put("W", ONE); + aromatic.put("H", ONE); + aromatic.put("K", ZERO); + aromatic.put("R", ZERO); + aromatic.put("E", ZERO); + aromatic.put("Q", ZERO); + aromatic.put("D", ZERO); + aromatic.put("N", ZERO); + aromatic.put("S", ZERO); + aromatic.put("T", ZERO); + aromatic.put("P", ZERO); + aromatic.put("-", ONE); + aromatic.put("*", ONE); } static { - aliphatic.put("I", Integer.valueOf(1)); - aliphatic.put("L", Integer.valueOf(1)); - aliphatic.put("V", Integer.valueOf(1)); - aliphatic.put("C", Integer.valueOf(0)); - aliphatic.put("A", Integer.valueOf(0)); - aliphatic.put("G", Integer.valueOf(0)); - aliphatic.put("M", Integer.valueOf(0)); - aliphatic.put("F", Integer.valueOf(0)); - aliphatic.put("Y", Integer.valueOf(0)); - aliphatic.put("W", Integer.valueOf(0)); - aliphatic.put("H", Integer.valueOf(0)); - aliphatic.put("K", Integer.valueOf(0)); - aliphatic.put("R", Integer.valueOf(0)); - aliphatic.put("E", Integer.valueOf(0)); - aliphatic.put("Q", Integer.valueOf(0)); - aliphatic.put("D", Integer.valueOf(0)); - aliphatic.put("N", Integer.valueOf(0)); - aliphatic.put("S", Integer.valueOf(0)); - aliphatic.put("T", Integer.valueOf(0)); - aliphatic.put("P", Integer.valueOf(0)); - aliphatic.put("-", Integer.valueOf(1)); - aliphatic.put("*", Integer.valueOf(1)); + aliphatic.put("I", ONE); + aliphatic.put("L", ONE); + aliphatic.put("V", ONE); + aliphatic.put("C", ZERO); + aliphatic.put("A", ZERO); + aliphatic.put("G", ZERO); + aliphatic.put("M", ZERO); + aliphatic.put("F", ZERO); + aliphatic.put("Y", ZERO); + aliphatic.put("W", ZERO); + aliphatic.put("H", ZERO); + aliphatic.put("K", ZERO); + aliphatic.put("R", ZERO); + aliphatic.put("E", ZERO); + aliphatic.put("Q", ZERO); + aliphatic.put("D", ZERO); + aliphatic.put("N", ZERO); + aliphatic.put("S", ZERO); + aliphatic.put("T", ZERO); + aliphatic.put("P", ZERO); + aliphatic.put("-", ONE); + aliphatic.put("*", ONE); } static { - tiny.put("I", Integer.valueOf(0)); - tiny.put("L", Integer.valueOf(0)); - tiny.put("V", Integer.valueOf(0)); - tiny.put("C", Integer.valueOf(0)); - tiny.put("A", Integer.valueOf(1)); - tiny.put("G", Integer.valueOf(1)); - tiny.put("M", Integer.valueOf(0)); - tiny.put("F", Integer.valueOf(0)); - tiny.put("Y", Integer.valueOf(0)); - tiny.put("W", Integer.valueOf(0)); - tiny.put("H", Integer.valueOf(0)); - tiny.put("K", Integer.valueOf(0)); - tiny.put("R", Integer.valueOf(0)); - tiny.put("E", Integer.valueOf(0)); - tiny.put("Q", Integer.valueOf(0)); - tiny.put("D", Integer.valueOf(0)); - tiny.put("N", Integer.valueOf(0)); - tiny.put("S", Integer.valueOf(1)); - tiny.put("T", Integer.valueOf(0)); - tiny.put("P", Integer.valueOf(0)); - tiny.put("-", Integer.valueOf(1)); - tiny.put("*", Integer.valueOf(1)); + tiny.put("I", ZERO); + tiny.put("L", ZERO); + tiny.put("V", ZERO); + tiny.put("C", ZERO); + tiny.put("A", ONE); + tiny.put("G", ONE); + tiny.put("M", ZERO); + tiny.put("F", ZERO); + tiny.put("Y", ZERO); + tiny.put("W", ZERO); + tiny.put("H", ZERO); + tiny.put("K", ZERO); + tiny.put("R", ZERO); + tiny.put("E", ZERO); + tiny.put("Q", ZERO); + tiny.put("D", ZERO); + tiny.put("N", ZERO); + tiny.put("S", ONE); + tiny.put("T", ZERO); + tiny.put("P", ZERO); + tiny.put("-", ONE); + tiny.put("*", ONE); } static { - proline.put("I", Integer.valueOf(0)); - proline.put("L", Integer.valueOf(0)); - proline.put("V", Integer.valueOf(0)); - proline.put("C", Integer.valueOf(0)); - proline.put("A", Integer.valueOf(0)); - proline.put("G", Integer.valueOf(0)); - proline.put("M", Integer.valueOf(0)); - proline.put("F", Integer.valueOf(0)); - proline.put("Y", Integer.valueOf(0)); - proline.put("W", Integer.valueOf(0)); - proline.put("H", Integer.valueOf(0)); - proline.put("K", Integer.valueOf(0)); - proline.put("R", Integer.valueOf(0)); - proline.put("E", Integer.valueOf(0)); - proline.put("Q", Integer.valueOf(0)); - proline.put("D", Integer.valueOf(0)); - proline.put("N", Integer.valueOf(0)); - proline.put("S", Integer.valueOf(0)); - proline.put("T", Integer.valueOf(0)); - proline.put("P", Integer.valueOf(1)); - proline.put("-", Integer.valueOf(1)); - proline.put("*", Integer.valueOf(1)); + proline.put("I", ZERO); + proline.put("L", ZERO); + proline.put("V", ZERO); + proline.put("C", ZERO); + proline.put("A", ZERO); + proline.put("G", ZERO); + proline.put("M", ZERO); + proline.put("F", ZERO); + proline.put("Y", ZERO); + proline.put("W", ZERO); + proline.put("H", ZERO); + proline.put("K", ZERO); + proline.put("R", ZERO); + proline.put("E", ZERO); + proline.put("Q", ZERO); + proline.put("D", ZERO); + proline.put("N", ZERO); + proline.put("S", ZERO); + proline.put("T", ZERO); + proline.put("P", ONE); + proline.put("-", ONE); + proline.put("*", ONE); } static diff --git a/src/jalview/structure/StructureSelectionManager.java b/src/jalview/structure/StructureSelectionManager.java index 7e691be..cad2303 100644 --- a/src/jalview/structure/StructureSelectionManager.java +++ b/src/jalview/structure/StructureSelectionManager.java @@ -391,7 +391,7 @@ public class StructureSelectionManager registerPDBFile(pdb.getId().trim(), pdbFile); } // if PDBId is unavailable then skip SIFTS mapping execution path - isMapUsingSIFTs = pdb.isPPDBIdAvailable(); + isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable(); } catch (Exception ex) { diff --git a/src/jalview/structures/models/AAStructureBindingModel.java b/src/jalview/structures/models/AAStructureBindingModel.java index b00f1bc..5dc3465 100644 --- a/src/jalview/structures/models/AAStructureBindingModel.java +++ b/src/jalview/structures/models/AAStructureBindingModel.java @@ -135,19 +135,14 @@ public abstract class AAStructureBindingModel extends * @param protocol */ public AAStructureBindingModel(StructureSelectionManager ssm, - PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains, + PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String protocol) { this.ssm = ssm; this.sequence = sequenceIs; this.nucleotide = Comparison.isNucleotide(sequenceIs); - this.chains = chains; this.pdbEntry = pdbentry; this.protocol = protocol; - if (chains == null) - { - this.chains = new String[pdbentry.length][]; - } } public StructureSelectionManager getSsm() @@ -674,4 +669,12 @@ public abstract class AAStructureBindingModel extends { this.finishedInit = fi; } + + /** + * Returns a list of chains mapped in this viewer. + * + * @return + */ + public abstract List getChainNames(); + } diff --git a/src/jalview/util/Comparison.java b/src/jalview/util/Comparison.java index 0beb45b..1326647 100644 --- a/src/jalview/util/Comparison.java +++ b/src/jalview/util/Comparison.java @@ -415,4 +415,29 @@ public class Comparison .size()]); return isNucleotide(oneDArray); } + + /** + * Compares two residues either case sensitively or case insensitively + * depending on the caseSensitive flag + * + * @param c1 + * first char + * @param c2 + * second char to compare with + * @param caseSensitive + * if true comparison will be case sensitive otherwise its not + * @return + */ + public static boolean isSameResidue(char c1, char c2, + boolean caseSensitive) + { + if (caseSensitive) + { + return (c1 == c2); + } + else + { + return Character.toUpperCase(c1) == Character.toUpperCase(c2); + } + } } diff --git a/src/jalview/util/DBRefUtils.java b/src/jalview/util/DBRefUtils.java index e6aa472..04cb75e 100755 --- a/src/jalview/util/DBRefUtils.java +++ b/src/jalview/util/DBRefUtils.java @@ -100,14 +100,14 @@ public class DBRefUtils HashSet srcs = new HashSet(); for (String src : sources) { - srcs.add(src); + srcs.add(src.toUpperCase()); } List res = new ArrayList(); for (DBRefEntry dbr : dbrefs) { String source = getCanonicalName(dbr.getSource()); - if (srcs.contains(source)) + if (srcs.contains(source.toUpperCase())) { res.add(dbr); } diff --git a/src/jalview/util/Format.java b/src/jalview/util/Format.java index 7121985..389afcd 100755 --- a/src/jalview/util/Format.java +++ b/src/jalview/util/Format.java @@ -26,6 +26,8 @@ */ package jalview.util; +import java.util.Arrays; + /** * DOCUMENT ME! * @@ -664,30 +666,22 @@ public class Format } /** - * DOCUMENT ME! + * Returns a string consisting of n repeats of character c * * @param c - * DOCUMENT ME! * @param n - * DOCUMENT ME! * - * @return DOCUMENT ME! + * @return */ - private static String repeat(char c, int n) + static String repeat(char c, int n) { if (n <= 0) { return ""; } - - StringBuffer s = new StringBuffer(n); - - for (int i = 0; i < n; i++) - { - s.append(c); - } - - return s.toString(); + char[] chars = new char[n]; + Arrays.fill(chars, c); + return new String(chars); } /** @@ -959,7 +953,27 @@ public class Format */ public static void appendPercentage(StringBuilder sb, float value, int dp) { - sb.append((int) value); + /* + * rounding first + */ + double d = value; + long factor = 1L; + for (int i = 0; i < dp; i++) + { + factor *= 10; + } + d *= factor; + d += 0.5; + + /* + * integer part + */ + value = (float) (d / factor); + sb.append((long) value); + + /* + * decimal places + */ if (dp > 0) { sb.append("."); diff --git a/src/jalview/util/Platform.java b/src/jalview/util/Platform.java index 3fb384f..49dc7ff 100644 --- a/src/jalview/util/Platform.java +++ b/src/jalview/util/Platform.java @@ -30,6 +30,10 @@ import java.awt.event.MouseEvent; */ public class Platform { + private static Boolean isAMac = null; + + private static Boolean isHeadless = null; + /** * sorry folks - Macs really are different * @@ -37,15 +41,21 @@ public class Platform */ public static boolean isAMac() { - return java.lang.System.getProperty("os.name").indexOf("Mac") > -1; + if (isAMac == null) + { + isAMac = System.getProperty("os.name").indexOf("Mac") > -1; + } + return isAMac.booleanValue(); } public static boolean isHeadless() { - String hdls = java.lang.System.getProperty("java.awt.headless"); - - return hdls != null && hdls.equals("true"); + if (isHeadless == null) + { + isHeadless = "true".equals(System.getProperty("java.awt.headless")); + } + return isHeadless; } /** @@ -89,8 +99,28 @@ public class Platform */ public static boolean isControlDown(MouseEvent e) { - if (isAMac()) + boolean aMac = isAMac(); + return isControlDown(e, aMac); + } + + /** + * Overloaded version of method (to allow unit testing) + * + * @param e + * @param aMac + * @return + */ + protected static boolean isControlDown(MouseEvent e, boolean aMac) + { + if (aMac) { + /* + * answer false for right mouse button + */ + if (e.isPopupTrigger()) + { + return false; + } return (Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() & e .getModifiers()) != 0; // could we use e.isMetaDown() here? diff --git a/src/jalview/util/UrlConstants.java b/src/jalview/util/UrlConstants.java index ce6d980..1910bff 100644 --- a/src/jalview/util/UrlConstants.java +++ b/src/jalview/util/UrlConstants.java @@ -29,22 +29,17 @@ public class UrlConstants /* * Sequence ID string */ - public static final String SEQUENCE_ID = "SEQUENCE_ID"; + public static final String DB_ACCESSION = "DB_ACCESSION"; /* * Sequence Name string */ - public static final String SEQUENCE_NAME = "SEQUENCE_NAME"; - - /* - * Default sequence URL link string for EMBL-EBI search - */ - public static final String EMBLEBI_STRING = "EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_NAME$"; + public static final String SEQUENCE_ID = "SEQUENCE_ID"; /* * Default sequence URL link string for EMBL-EBI search */ - public static final String OLD_EMBLEBI_STRING = "EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$"; + public static final String EMBLEBI_STRING = "EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$"; /* * Default sequence URL link string for SRS diff --git a/src/jalview/util/UrlLink.java b/src/jalview/util/UrlLink.java index 872f432..3ee6432 100644 --- a/src/jalview/util/UrlLink.java +++ b/src/jalview/util/UrlLink.java @@ -20,9 +20,15 @@ */ package jalview.util; +import static jalview.util.UrlConstants.DB_ACCESSION; import static jalview.util.UrlConstants.SEQUENCE_ID; -import static jalview.util.UrlConstants.SEQUENCE_NAME; +import jalview.datamodel.DBRefEntry; +import jalview.datamodel.SequenceI; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; import java.util.Vector; public class UrlLink @@ -33,19 +39,33 @@ public class UrlLink * Jalview 2.4 extension allows regular expressions to be used to parse ID * strings and replace the result in the URL. Regex's operate on the whole ID * string given to the matchURL method, if no regex is supplied, then only - * text following the first pipe symbol will be susbstituted. Usage + * text following the first pipe symbol will be substituted. Usage * documentation todo. */ - private String url_suffix, url_prefix, target, label, regexReplace; + + // Internal constants + private static final String SEP = "|"; + + private static final String DELIM = "$"; + + private String urlSuffix; + + private String urlPrefix; + + private String target; + + private String label; + + private String regexReplace; private boolean dynamic = false; - private boolean uses_seq_id = false; + private boolean usesDBaccession = false; private String invalidMessage = null; /** - * parse the given linkString of the form '