From: Jim Procter Date: Mon, 15 May 2017 16:37:43 +0000 (+0100) Subject: Merge branch 'bug/JAL-2507_rnasecstrstockholm' into develop X-Git-Tag: Release_2_10_2~3^2~88 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=4ff9ae2e29a4dc41fb5101a5e336809f097b88ae;hp=2e52440728d6a0f9a6c998a80e545387ef964d10;p=jalview.git Merge branch 'bug/JAL-2507_rnasecstrstockholm' into develop --- diff --git a/examples/groovy/featureCounter.groovy b/examples/groovy/featureCounter.groovy deleted file mode 100644 index 9059dd0..0000000 --- a/examples/groovy/featureCounter.groovy +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) - * Copyright (C) $$Year-Rel$$ The Jalview Authors - * - * This file is part of Jalview. - * - * Jalview is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 - * of the License, or (at your option) any later version. - * - * Jalview is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Jalview. If not, see . - * The Jalview Authors are detailed in the 'AUTHORS' file. - */ - -import jalview.workers.FeatureCounterI; -import jalview.workers.AlignmentAnnotationFactory; - -/* - * Example script that registers two alignment annotation calculators - * - one that counts residues in a column with Pfam annotation - * - one that counts only charged residues with Pfam annotation - * - * To try: - * 1. load uniref50.fa from the examples folder - * 2. load features onto it from from examples/exampleFeatures.txt - * 3. Open this script in the Groovy console. - * 4. Either execute this script from the console, or via Calculate->Run Groovy Script - - * To explore further, try changing this script to count other kinds of occurrences of - * residue and sequence features at columns in an alignment. - */ - -/* - * A closure that returns true for any Charged residue - */ -def isCharged = { residue -> - switch(residue) { - case ['D', 'd', 'E', 'e', 'H', 'h', 'K', 'k', 'R', 'r']: - return true - } - false -} - -/* - * A closure that returns 1 if sequence features include type 'Pfam', else 0 - * Argument should be a list of SequenceFeature - */ -def hasPfam = { features -> - for (sf in features) - { - /* - * Here we inspect the type of the sequence feature. - * You can also test sf.description, sf.score, sf.featureGroup, - * sf.strand, sf.phase, sf.begin, sf.end - * or sf.getValue(attributeName) for GFF 'column 9' properties - */ - if ("Pfam".equals(sf.type)) - { - return true - } - } - false -} - -/* - * Closure that computes an annotation based on - * presence of particular residues and features - * Parameters are - * - the name (label) for the alignment annotation - * - the description (tooltip) for the annotation - * - a closure (groovy function) that tests whether to include a residue - * - a closure that tests whether to increment count based on sequence features - */ -def getColumnCounter = { name, desc, acceptResidue, acceptFeatures -> - [ - getName: { name }, - getDescription: { desc }, - getMinColour: { [0, 255, 255] }, // cyan - getMaxColour: { [0, 0, 255] }, // blue - count: - { res, feats -> - def c = 0 - if (acceptResidue.call(res)) - { - if (acceptFeatures.call(feats)) - { - c++ - } - } - c - } - ] as FeatureCounterI -} - -/* - * Define an annotation row that counts any residue with Pfam domain annotation - */ -def pfamAnnotation = getColumnCounter("Pfam", "Count of residues with Pfam domain annotation", {true}, hasPfam) - -/* - * Define an annotation row that counts charged residues with Pfam domain annotation - */ -def chargedPfamAnnotation = getColumnCounter("Pfam charged", "Count of charged residues with Pfam domain annotation", isCharged, hasPfam) - -/* - * Register the annotations - */ -AlignmentAnnotationFactory.newCalculator(pfamAnnotation) -AlignmentAnnotationFactory.newCalculator(chargedPfamAnnotation) diff --git a/examples/groovy/featuresCounter.groovy b/examples/groovy/featuresCounter.groovy new file mode 100644 index 0000000..dc4c97c --- /dev/null +++ b/examples/groovy/featuresCounter.groovy @@ -0,0 +1,73 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ + +import jalview.workers.AlignmentAnnotationFactory; +import jalview.workers.FeatureSetCounterI; + +/* + * Example script to compute two alignment annotations + * - count of Phosphorylation features + * - count of Turn features + * To try this, first load example file uniref50.fa and load on features file + * exampleFeatures.txt, before running this script + * + * The script only needs to be run once - it will be registered by Jalview + * and recalculated automatically when the alignment changes. + * + * Note: The feature api provided by 2.10.2 is not compatible with scripts + * that worked with earlier Jalview versions. Apologies for the inconvenience. + */ + +def annotator = + [ + getNames: { ['Phosphorylation', 'Turn'] as String[] }, + getDescriptions: { ['Count of Phosphorylation features', 'Count of Turn features'] as String[] }, + getMinColour: { [0, 255, 255] as int[] }, // cyan + getMaxColour: { [0, 0, 255] as int[] }, // blue + count: + { res, feats -> + int phos + int turn + for (sf in feats) + { + /* + * Here we inspect the type of the sequence feature. + * You can also test sf.description, sf.score, sf.featureGroup, + * sf.strand, sf.phase, sf.begin, sf.end + * or sf.getValue(attributeName) for GFF 'column 9' properties + */ + if (sf.type.contains('TURN')) + { + turn++ + } + if (sf.type.contains('PHOSPHORYLATION')) + { + phos++ + } + } + [phos, turn] as int[] + } + ] as FeatureSetCounterI + +/* + * Register the annotation calculator with Jalview + */ +AlignmentAnnotationFactory.newCalculator(annotator) diff --git a/examples/groovy/multipleFeatureAnnotations.groovy b/examples/groovy/multipleFeatureAnnotations.groovy deleted file mode 100644 index 592c7f5..0000000 --- a/examples/groovy/multipleFeatureAnnotations.groovy +++ /dev/null @@ -1,110 +0,0 @@ -import jalview.workers.AlignmentAnnotationFactory; -import jalview.workers.AnnotationProviderI; -import jalview.datamodel.AlignmentAnnotation; -import jalview.datamodel.Annotation; -import jalview.util.ColorUtils; -import jalview.util.Comparison; -import java.awt.Color; - -/* - * Example script to compute two alignment annotations - * - count of Phosphorylation features - * - count of Turn features - * To try this, first load example file uniref50.fa and load on features file - * exampleFeatures.txt, before running this script - * - * The script only needs to be run once - it will be registered by Jalview - * and recalculated automatically when the alignment changes. - */ - -/* - * A closure that returns true if value includes "PHOSPHORYLATION" - */ -def phosCounter = { type -> type.contains("PHOSPHORYLATION") } - -/* - * A closure that returns true if value includes "TURN" - */ -def turnCounter = { type -> type.contains("TURN") } - -/* - * A closure that computes and returns an array of Annotation values, - * one for each column of the alignment - */ -def getAnnotations(al, fr, counter) -{ - def width = al.width - def counts = new int[width] - def max = 0 - - /* - * count features in each column, record the maximum value - */ - for (col = 0 ; col < width ; col++) - { - def count = 0 - for (row = 0 ; row < al.height ; row++) - { - seq = al.getSequenceAt(row) - if (seq != null && col < seq.getLength()) - { - def res = seq.getCharAt(col) - if (!Comparison.isGap(res)) - { - pos = seq.findPosition(col) - features = fr.findFeaturesAtRes(seq, pos) - for (feature in features) - { - if (counter.call(feature.type)) - { - count++ - } - } - } - } - } - counts[col] = count - if (count > max) - { - max = count - } - } - - /* - * make the Annotation objects, with a graduated colour scale - * (from min value to max value) for the histogram bars - */ - def zero = '0' as char - def anns = new Annotation[width] - for (col = 0 ; col < width ; col++) - { - def c = counts[col] - if (c > 0) - { - Color color = ColorUtils.getGraduatedColour(c, 0, Color.cyan, - max, Color.blue) - anns[col] = AlignmentAnnotationFactory.newAnnotation(String.valueOf(c), - String.valueOf(c), zero, c, color) - } - } - anns -} - -/* - * Define the method that performs the calculations, and builds two - * AlignmentAnnotation objects - */ -def annotator = - [ calculateAnnotation: { al, fr -> - def phosAnns = getAnnotations(al, fr, phosCounter) - def ann1 = AlignmentAnnotationFactory.newAlignmentAnnotation("Phosphorylation", "Count of Phosphorylation features", phosAnns) - def turnAnns = getAnnotations(al, fr, turnCounter) - def ann2 = AlignmentAnnotationFactory.newAlignmentAnnotation("Turn", "Count of Turn features", turnAnns) - return [ann1, ann2] - } - ] as AnnotationProviderI - -/* - * Register the annotation calculator with Jalview - */ -AlignmentAnnotationFactory.newCalculator(annotator) diff --git a/examples/groovy/visibleFeaturesCounter.groovy b/examples/groovy/visibleFeaturesCounter.groovy new file mode 100644 index 0000000..b3180f8 --- /dev/null +++ b/examples/groovy/visibleFeaturesCounter.groovy @@ -0,0 +1,89 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +import jalview.bin.Jalview +import jalview.workers.FeatureSetCounterI +import jalview.workers.AlignmentAnnotationFactory + +/* + * Demonstration of FeatureSetCounterI + * compute annotation tracks counting number of displayed + * features of each type in each column + */ + +/* + * discover features on the current view + */ + +def featuresDisp=Jalview.currentAlignFrame.currentView.featuresDisplayed +if (featuresDisp == null) { + print 'Need at least one feature visible on alignment' +} +def visibleFeatures=featuresDisp.visibleFeatures.toList() +assert 'java.util.ArrayList' == visibleFeatures.class.name + +/* + * A closure that returns an array of features present + * for each feature type in visibleFeatures + * Argument 'features' will be a list of SequenceFeature + */ +def getCounts = + { features -> + int[] obs = new int[visibleFeatures.size] + for (sf in features) + { + /* + * Here we inspect the type of the sequence feature. + * You can also test sf.description, sf.score, sf.featureGroup, + * sf.strand, sf.phase, sf.begin, sf.end + * or sf.getValue(attributeName) for GFF 'column 9' properties + */ + int pos = 0 + for (type in visibleFeatures) + { + if (type.equals(sf.type)) + { + obs[pos]++ + } + pos++ + } + } + obs +} + +/* + * Define something that counts each visible feature type + */ +def columnSetCounter = + [ + getNames: { visibleFeatures as String[] }, + getDescriptions: { visibleFeatures as String[] }, + getMinColour: { [0, 255, 255] as int[] }, // cyan + getMaxColour: { [0, 0, 255] as int[] }, // blue + count: + { res, feats -> + getCounts.call(feats) + } + ] as FeatureSetCounterI + +/* + * and register the counter + */ +AlignmentAnnotationFactory.newCalculator(columnSetCounter) diff --git a/help/help.jhm b/help/help.jhm index 984c2d1..ac8fc3f 100755 --- a/help/help.jhm +++ b/help/help.jhm @@ -75,6 +75,7 @@ + @@ -130,7 +131,7 @@ - + @@ -158,4 +159,6 @@ + + diff --git a/help/helpTOC.xml b/help/helpTOC.xml index 482ccdf..db47351 100755 --- a/help/helpTOC.xml +++ b/help/helpTOC.xml @@ -24,6 +24,9 @@ + + + @@ -132,7 +135,7 @@ - + @@ -157,7 +160,7 @@ - + diff --git a/help/html/features/groovy.html b/help/html/features/groovy.html index 254f92e..d9bf76e 100644 --- a/help/html/features/groovy.html +++ b/help/html/features/groovy.html @@ -108,7 +108,7 @@ print currentAlFrame.getTitle(); simplified the alignment analysis programming interface in Jalview 2.10 to make it easy for you to add your own dynamic annotation tracks with Groovy. Have a look at the featureCounter.groovy + href="../groovy/featuresCounter.html">featuresCounter.groovy example for more information.

diff --git a/help/html/features/overview.html b/help/html/features/overview.html index 9d36a1c..4f26592 100755 --- a/help/html/features/overview.html +++ b/help/html/features/overview.html @@ -31,6 +31,11 @@

The red box indicates the currently viewed region of the alignment, this may be moved by clicking and dragging with the mouse.

+

Right-click (or CMD-Click) to open the + overview's popup menu. This provides an option to include hidden + regions in the overview (shown as dark-grey rows and columns).

+ The option to include/exclude hidden regions in the + overview was introduced in Jalview 2.10.2.

diff --git a/help/html/features/splitView.html b/help/html/features/splitView.html index 03b993c..3862c39 100644 --- a/help/html/features/splitView.html +++ b/help/html/features/splitView.html @@ -67,7 +67,11 @@ alignments, the "Format→Font" menu option has an option 'Scale protein residues to codons'. This option will make each protein residue the same width as a DNA - codon (so the alignments 'line up' vertically) + codon (so the alignments 'line up' vertically).

+ The 'Use same + font for cDNA and peptide' checkbox, when enabled, ensures that font or + font-size changes in either the cDNA or Protein alignment will also + be mirrored. (Added in 2.10.2)
  • "View→Protein" (in the cDNA panel) or "View→Nucleotide" (in the protein panel) diff --git a/help/html/groovy/featureCounter.html b/help/html/groovy/featureCounter.html deleted file mode 100644 index 2ebaf45..0000000 --- a/help/html/groovy/featureCounter.html +++ /dev/null @@ -1,269 +0,0 @@ - - - -Extending Jalview with Groovy - Feature Counter Example - - -

    - Extending Jalview with Groovy - A customisable - feature counter

    The groovy script below shows how to - add a new calculation track to a Jalview alignment window. -

    -

    As currently written, it will add two tracks to a protein - alignment view which count Pfam features in each column, and ones - where a charge residue also occur.

    -

    To try it for yourself:

    -
      -
    1. Copy and paste it into the groovy script console
    2. -
    3. Load the example Feredoxin project (the one that opens by - default when you first launched Jalview)
    4. -
    5. Select Calculations→Execute Groovy - Script from the alignment window's menu bar to run the script on - the current view. -
    6. -
    -
    http://www.jalview.org/examples/groovy/featureCounter.groovy - - rendered with hilite.me - -
    -
    -/*
    - * Jalview - A Sequence Alignment Editor and Viewer (Version 2.10)
    - * Copyright (C) 2016 The Jalview Authors
    - * 
    - * This file is part of Jalview.
    - * 
    - * Jalview is free software: you can redistribute it and/or
    - * modify it under the terms of the GNU General Public License 
    - * as published by the Free Software Foundation, either version 3
    - * of the License, or (at your option) any later version.
    - *  
    - * Jalview is distributed in the hope that it will be useful, but 
    - * WITHOUT ANY WARRANTY; without even the implied warranty 
    - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
    - * PURPOSE.  See the GNU General Public License for more details.
    - * 
    - * You should have received a copy of the GNU General Public License
    - * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
    - * The Jalview Authors are detailed in the 'AUTHORS' file.
    - */
    - 
    -import jalview.workers.FeatureCounterI;
    -import jalview.workers.AlignmentAnnotationFactory;
    -
    -/*
    - * Example script that registers two alignment annotation calculators
    - * - one that counts residues in a column with Pfam annotation
    - * - one that counts only charged residues with Pfam annotation
    - *
    - * To try:
    - * 1. load uniref50.fa from the examples folder
    - * 2. load features onto it from from examples/exampleFeatures.txt
    - * 3. Open this script in the Groovy console.
    - * 4. Either execute this script from the console, or via Calculate->Run Groovy Script
    - 
    - * To explore further, try changing this script to count other kinds of occurrences of 
    - * residue and sequence features at columns in an alignment.
    - */
    -
    -/*
    - * A closure that returns true for any Charged residue
    - */
    -def isCharged = { residue ->
    -    switch(residue) {
    -        case ['D', 'd', 'E', 'e', 'H', 'h', 'K', 'k', 'R', 'r']:
    -            return true
    -    }
    -    false
    -} 
    -
    -/*
    - * A closure that returns 1 if sequence features include type 'Pfam', else 0
    - * Argument should be a list of SequenceFeature 
    - */
    -def hasPfam = { features -> 
    -    for (sf in features)
    -    {
    -        /*
    -         * Here we inspect the type of the sequence feature.
    -         * You can also test sf.description, sf.score, sf.featureGroup,
    -         * sf.strand, sf.phase, sf.begin, sf.end
    -         * or sf.getValue(attributeName) for GFF 'column 9' properties
    -         */
    -        if ("Pfam".equals(sf.type))
    -        {
    -            return true
    -        }
    -    }
    -    false
    -}
    -
    -/*
    - * Closure that computes an annotation based on 
    - * presence of particular residues and features
    - * Parameters are
    - * - the name (label) for the alignment annotation
    - * - the description (tooltip) for the annotation
    - * - a closure (groovy function) that tests whether to include a residue
    - * - a closure that tests whether to increment count based on sequence features  
    - */
    -def getColumnCounter = { name, desc, acceptResidue, acceptFeatures ->
    -    [
    -     getName: { name }, 
    -     getDescription: { desc },
    -     getMinColour: { [0, 255, 255] }, // cyan
    -     getMaxColour: { [0, 0, 255] }, // blue
    -     count: 
    -         { res, feats -> 
    -            def c = 0
    -            if (acceptResidue.call(res))
    -            {
    -                if (acceptFeatures.call(feats))
    -                {
    -                    c++
    -                }
    -            }
    -            c
    -         }
    -     ] as FeatureCounterI
    -}
    -
    -/*
    - * Define an annotation row that counts any residue with Pfam domain annotation
    - */
    -def pfamAnnotation = getColumnCounter("Pfam", "Count of residues with Pfam domain annotation", {true}, hasPfam)
    -
    -/*
    - * Define an annotation row that counts charged residues with Pfam domain annotation
    - */
    -def chargedPfamAnnotation = getColumnCounter("Pfam charged", "Count of charged residues with Pfam domain annotation", isCharged, hasPfam)
    -
    -/*
    - * Register the annotations
    - */
    -AlignmentAnnotationFactory.newCalculator(pfamAnnotation) 
    -AlignmentAnnotationFactory.newCalculator(chargedPfamAnnotation)
    -
    -
    - - diff --git a/help/html/groovy/featuresCounter.html b/help/html/groovy/featuresCounter.html new file mode 100644 index 0000000..3b6705b --- /dev/null +++ b/help/html/groovy/featuresCounter.html @@ -0,0 +1,123 @@ + + + +Extending Jalview with Groovy - Feature Counter Example + + +

    + Extending Jalview with Groovy - A customisable + feature counter

    The groovy script below shows how to + add a new calculation track to a Jalview alignment window. +

    +

    As currently written, it will add two tracks to a protein + alignment view which count Pfam features in each column, and ones + where a charge residue also occur.

    +

    To try it for yourself:

    +
      +
    1. Copy and paste it into the groovy script console
    2. +
    3. Load the example Feredoxin project (the one that opens by + default when you first launched Jalview)
    4. +
    5. Select Calculations→Execute Groovy + Script from the alignment window's menu bar to run the script on + the current view. +
    6. +
    + Please note: The 2.10.2 feature counting interface is not compatible with earlier versions.

    + http://www.jalview.org/examples/groovy/featuresCounter.groovy + - rendered with hilite.me +
    /*
    + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
    + * Copyright (C) $$Year-Rel$$ The Jalview Authors
    + * 
    + * This file is part of Jalview.
    + * 
    + * Jalview is free software: you can redistribute it and/or
    + * modify it under the terms of the GNU General Public License 
    + * as published by the Free Software Foundation, either version 3
    + * of the License, or (at your option) any later version.
    + *  
    + * Jalview is distributed in the hope that it will be useful, but 
    + * WITHOUT ANY WARRANTY; without even the implied warranty 
    + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
    + * PURPOSE.  See the GNU General Public License for more details.
    + * 
    + * You should have received a copy of the GNU General Public License
    + * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
    + * The Jalview Authors are detailed in the 'AUTHORS' file.
    + */
    +
    +import jalview.workers.AlignmentAnnotationFactory;
    +import jalview.workers.FeatureSetCounterI;
    +
    +/*
    + * Example script to compute two alignment annotations
    + * - count of Phosphorylation features
    + * - count of Turn features
    + * To try this, first load example file uniref50.fa and load on features file
    + * exampleFeatures.txt, before running this script
    + *
    + * The script only needs to be run once - it will be registered by Jalview
    + * and recalculated automatically when the alignment changes.
    + * 
    + * Note: The feature api provided by 2.10.2 is not compatible with scripts
    + * that worked with earlier Jalview versions. Apologies for the inconvenience.
    + */
    + 
    +def annotator = 
    +    [
    +     getNames: { ['Phosphorylation', 'Turn'] as String[] }, 
    +     getDescriptions:  { ['Count of Phosphorylation features', 'Count of Turn features'] as String[] },
    +     getMinColour: { [0, 255, 255] as int[] }, // cyan
    +     getMaxColour: { [0, 0, 255] as int[] }, // blue
    +     count: 
    +         { res, feats -> 
    +                int phos
    +                int turn
    +                for (sf in feats)
    +                {
    + 		          /*
    +		           * Here we inspect the type of the sequence feature.
    +		           * You can also test sf.description, sf.score, sf.featureGroup,
    +		           * sf.strand, sf.phase, sf.begin, sf.end
    +		           * or sf.getValue(attributeName) for GFF 'column 9' properties
    +		           */
    +		           if (sf.type.contains('TURN'))
    +                   {
    +                      turn++
    +                   }
    +                   if (sf.type.contains('PHOSPHORYLATION'))
    +                   {
    +                      phos++
    +                   }
    +                }
    +                [phos, turn] as int[]
    +         }
    +     ] as FeatureSetCounterI
    +    
    +/*
    + * Register the annotation calculator with Jalview
    + */
    +AlignmentAnnotationFactory.newCalculator(annotator) 
    +
    + + diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index 88bb376..f6eeb26 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -1225,6 +1225,7 @@ label.configure_displayed_columns = Customise Displayed Options label.start_jalview = Start Jalview label.biojs_html_export = BioJS label.scale_as_cdna = Scale protein residues to codons +label.font_as_cdna = Use same font for cDNA and peptide label.scale_protein_to_cdna = Scale Protein to cDNA label.scale_protein_to_cdna_tip = Make protein residues same width as codons in split frame views info.select_annotation_row = Select Annotation Row @@ -1300,9 +1301,10 @@ warn.name_cannot_be_duplicate = User-defined URL names must be unique and cannot label.invalid_name = Invalid Name ! label.output_seq_details = Output Sequence Details to list all database references label.urllinks = Links +label.togglehidden = Show hidden regions label.quality_descr = Alignment Quality based on Blosum62 scores label.conservation_descr = Conservation of total alignment less than {0}% gaps label.consensus_descr = PID label.complement_consensus_descr = PID for cDNA label.strucconsensus_descr = PID for base pairs -label.occupancy_descr = Number of aligned positions \ No newline at end of file +label.occupancy_descr = Number of aligned positions diff --git a/resources/lang/Messages_es.properties b/resources/lang/Messages_es.properties index 28c0eaa..ad4d2c4 100644 --- a/resources/lang/Messages_es.properties +++ b/resources/lang/Messages_es.properties @@ -1152,6 +1152,7 @@ label.open_split_window=Abrir ventana dividida label.open_split_window?=¿Quieres abrir ventana dividida, con cDNA y proteína vinculadas? status.searching_for_pdb_structures=Buscando Estructuras PDB label.scale_as_cdna=Adaptar residuos proteicos a los codones +label.font_as_cdna=Utilizar la misma fuente para nucleotídos y proteicos action.export_hidden_sequences=Exportar Secuencias Ocultas action.export_hidden_columns=Exportar Columnas Ocultas label.found_structures_summary=Resumen de Estructuras Encontradas @@ -1170,6 +1171,7 @@ label.find=Buscar label.select_pdb_file=Seleccionar Fichero PDB label.structures_filter=Filtro de Estructuras label.scale_protein_to_cdna=Adaptar proteína a cDNA +label.scale_protein_to_cdna_tip=Hacer a los residuos de proteínas de la misma anchura que los codones en ventanas divididas status.loading_cached_pdb_entries=Cargando Entradas PDB en Caché label.select=Seleccionar : label.select_by_annotation=Seleccionar/Ocultar Columnas por Anotación @@ -1189,7 +1191,6 @@ label.let_chimera_manage_structure_colours=Deja que Chimera maneje colores de es label.fetch_chimera_attributes = Buscar atributos desde Chimera label.fetch_chimera_attributes_tip = Copiar atributo de Chimera a característica de Jalview label.view_rna_structure=Estructura 2D VARNA -label.scale_protein_to_cdna_tip=Hacer a los residuos de proteínas de la misma anchura que los codones en ventanas divididas label.colour_with_chimera=Colorear con Chimera label.superpose_structures = Superponer estructuras error.superposition_failed = Superposición fallido: {0} @@ -1306,3 +1307,4 @@ label.consensus_descr = % Identidad label.complement_consensus_descr = % Identidad para cDNA label.strucconsensus_descr = % Identidad para pares de bases label.occupancy_descr = Número de posiciones alineadas +label.togglehidden = Show hidden regions diff --git a/src/jalview/api/AlignViewportI.java b/src/jalview/api/AlignViewportI.java index 8b07340..9e6d1c0 100644 --- a/src/jalview/api/AlignViewportI.java +++ b/src/jalview/api/AlignViewportI.java @@ -36,6 +36,7 @@ import jalview.schemes.ColourSchemeI; import jalview.viewmodel.ViewportRanges; import java.awt.Color; +import java.awt.Font; import java.util.Hashtable; import java.util.List; import java.util.Map; @@ -470,4 +471,27 @@ public interface AlignViewportI extends ViewStyleI * @return search results or null */ SearchResultsI getSearchResults(); + + /** + * Updates view settings with the given font. You may need to call + * AlignmentPanel.fontChanged to update the layout geometry. + * + * @param setGrid + * when true, charWidth/height is set according to font metrics + */ + void setFont(Font newFont, boolean b); + + /** + * Answers true if split screen protein and cDNA use the same font + * + * @return + */ + boolean isProteinFontAsCdna(); + + /** + * Set the flag for whether split screen protein and cDNA use the same font + * + * @return + */ + void setProteinFontAsCdna(boolean b); } diff --git a/src/jalview/api/AlignmentColsCollectionI.java b/src/jalview/api/AlignmentColsCollectionI.java new file mode 100644 index 0000000..603da98 --- /dev/null +++ b/src/jalview/api/AlignmentColsCollectionI.java @@ -0,0 +1,13 @@ +package jalview.api; + +public interface AlignmentColsCollectionI extends Iterable +{ + /** + * Answers if the column at the given position is hidden. + * + * @param c + * the column index to check + * @return true if the column at the position is hidden + */ + public boolean isHidden(int c); +} diff --git a/src/jalview/api/AlignmentRowsCollectionI.java b/src/jalview/api/AlignmentRowsCollectionI.java new file mode 100644 index 0000000..09b039d --- /dev/null +++ b/src/jalview/api/AlignmentRowsCollectionI.java @@ -0,0 +1,24 @@ +package jalview.api; + +import jalview.datamodel.SequenceI; + +public interface AlignmentRowsCollectionI extends Iterable +{ + /** + * Answers if the sequence at the given position is hidden. + * + * @param r + * the row index to check + * @return true if the sequence at r is hidden + */ + public boolean isHidden(int r); + + /** + * Answers the sequence at the given position in the alignment + * + * @param r + * the row index to locate + * @return the sequence + */ + public SequenceI getSequence(int r); +} diff --git a/src/jalview/api/ComplexAlignFile.java b/src/jalview/api/ComplexAlignFile.java index 2bf2782..1b579ad 100644 --- a/src/jalview/api/ComplexAlignFile.java +++ b/src/jalview/api/ComplexAlignFile.java @@ -20,7 +20,7 @@ */ package jalview.api; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceI; /** @@ -50,7 +50,7 @@ public interface ComplexAlignFile * * @return */ - public ColumnSelection getColumnSelection(); + public HiddenColumns getHiddenColumns(); /** * Retrieves hidden sequences from a complex file parser diff --git a/src/jalview/api/ViewStyleI.java b/src/jalview/api/ViewStyleI.java index db82dcf..2b554ea 100644 --- a/src/jalview/api/ViewStyleI.java +++ b/src/jalview/api/ViewStyleI.java @@ -257,4 +257,18 @@ public interface ViewStyleI * @return */ void setScaleProteinAsCdna(boolean b); + + /** + * Answers true if split screen protein and cDNA use the same font + * + * @return + */ + boolean isProteinFontAsCdna(); + + /** + * Set the flag for whether split screen protein and cDNA use the same font + * + * @return + */ + void setProteinFontAsCdna(boolean b); } diff --git a/src/jalview/appletgui/AlignFrame.java b/src/jalview/appletgui/AlignFrame.java index cd1e1a9..f914108 100644 --- a/src/jalview/appletgui/AlignFrame.java +++ b/src/jalview/appletgui/AlignFrame.java @@ -46,6 +46,7 @@ import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentOrder; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceGroup; @@ -172,14 +173,14 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, } public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs, - ColumnSelection columnSelection, JalviewLite applet, + HiddenColumns hidden, JalviewLite applet, String title, boolean embedded) { - this(al, hiddenSeqs, columnSelection, applet, title, embedded, true); + this(al, hiddenSeqs, hidden, applet, title, embedded, true); } public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs, - ColumnSelection columnSelection, JalviewLite applet, + HiddenColumns hidden, JalviewLite applet, String title, boolean embedded, boolean addToDisplay) { if (applet != null) @@ -222,9 +223,9 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, { viewport.hideSequence(hiddenSeqs); } - if (columnSelection != null) + if (hidden != null) { - viewport.setColumnSelection(columnSelection); + viewport.getAlignment().setHiddenColumns(hidden); } viewport.setScaleAboveWrapped(scaleAbove.getState()); @@ -1927,7 +1928,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, { copiedHiddenColumns = new Vector(); int hiddenOffset = viewport.getSelectionGroup().getStartRes(); - for (int[] region : viewport.getColumnSelection().getHiddenColumns()) + for (int[] region : viewport.getAlignment().getHiddenColumns() + .getHiddenRegions()) { copiedHiddenColumns.addElement(new int[] { region[0] - hiddenOffset, region[1] - hiddenOffset }); @@ -4207,9 +4209,10 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, * @param csel * - columns to be selected on the alignment */ - public void select(SequenceGroup sel, ColumnSelection csel) + public void select(SequenceGroup sel, ColumnSelection csel, + HiddenColumns hidden) { - alignPanel.seqPanel.selection(sel, csel, null); + alignPanel.seqPanel.selection(sel, csel, hidden, null); } public void scrollTo(int row, int column) diff --git a/src/jalview/appletgui/AlignViewport.java b/src/jalview/appletgui/AlignViewport.java index afe57e0..9629a5f 100644 --- a/src/jalview/appletgui/AlignViewport.java +++ b/src/jalview/appletgui/AlignViewport.java @@ -27,6 +27,7 @@ import jalview.bin.JalviewLite; import jalview.commands.CommandI; import jalview.datamodel.AlignmentI; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SearchResults; import jalview.datamodel.SearchResultsI; import jalview.datamodel.Sequence; @@ -39,9 +40,9 @@ import jalview.structure.SelectionSource; import jalview.structure.StructureSelectionManager; import jalview.structure.VamsasSource; import jalview.viewmodel.AlignmentViewport; -import jalview.viewmodel.ViewportRanges; import java.awt.Font; +import java.awt.FontMetrics; public class AlignViewport extends AlignmentViewport implements SelectionSource @@ -71,11 +72,10 @@ public class AlignViewport extends AlignmentViewport implements public AlignViewport(AlignmentI al, JalviewLite applet) { - super(); + super(al); calculator = new jalview.workers.AlignCalcManager(); this.applet = applet; - alignment = al; - ranges = new ViewportRanges(this.alignment); + // we always pad gaps this.setPadGaps(true); @@ -129,7 +129,7 @@ public class AlignViewport extends AlignmentViewport implements } } } - setFont(font); + setFont(font, true); MAC = new jalview.util.Platform().isAMac(); @@ -272,7 +272,11 @@ public class AlignViewport extends AlignmentViewport implements private float heightScale = 1, widthScale = 1; - public void setFont(Font f) + /** + * {@inheritDoc} + */ + @Override + public void setFont(Font f, boolean setGrid) { font = f; if (nullFrame == null) @@ -281,14 +285,17 @@ public class AlignViewport extends AlignmentViewport implements nullFrame.addNotify(); } - java.awt.FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font); - setCharHeight((int) (heightScale * fm.getHeight())); - setCharWidth((int) (widthScale * fm.charWidth('M'))); + if (setGrid) + { + FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font); + setCharHeight((int) (heightScale * fm.getHeight())); + setCharWidth((int) (widthScale * fm.charWidth('M'))); + } if (isUpperCasebold()) { Font f2 = new Font(f.getName(), Font.BOLD, f.getSize()); - fm = nullFrame.getGraphics().getFontMetrics(f2); + FontMetrics fm = nullFrame.getGraphics().getFontMetrics(f2); setCharWidth((int) (widthScale * (fm.stringWidth("MMMMMMMMMMM") / 10))); } } @@ -336,7 +343,8 @@ public class AlignViewport extends AlignmentViewport implements { getStructureSelectionManager().sendSelection( new SequenceGroup(getSelectionGroup()), - new ColumnSelection(getColumnSelection()), this); + new ColumnSelection(getColumnSelection()), + new HiddenColumns(getAlignment().getHiddenColumns()), this); } /** diff --git a/src/jalview/appletgui/AlignmentPanel.java b/src/jalview/appletgui/AlignmentPanel.java index 3ae0394..458ed54 100644 --- a/src/jalview/appletgui/AlignmentPanel.java +++ b/src/jalview/appletgui/AlignmentPanel.java @@ -419,11 +419,12 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, int start = -1; if (av.hasHiddenColumns()) { - start = av.getColumnSelection().findColumnPosition(ostart); - end = av.getColumnSelection().findColumnPosition(end); + AlignmentI al = av.getAlignment(); + start = al.getHiddenColumns().findColumnPosition(ostart); + end = al.getHiddenColumns().findColumnPosition(end); if (start == end) { - if (!scrollToNearest && !av.getColumnSelection().isVisible(ostart)) + if (!scrollToNearest && !al.getHiddenColumns().isVisible(ostart)) { // don't scroll - position isn't visible return false; @@ -725,7 +726,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, if (av.hasHiddenColumns()) { - width = av.getColumnSelection().findColumnPosition(width); + width = av.getAlignment().getHiddenColumns() + .findColumnPosition(width); } if (x < 0) { @@ -748,8 +750,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, if ((hextent + x) > width) { - System.err.println("hextent was " + hextent + " and x was " + x); - + // System.err.println("hextent was " + hextent + " and x was " + x); + // x = width - hextent; } @@ -1009,7 +1011,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, if (av.hasHiddenColumns()) { - maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1; + maxwidth = av.getAlignment().getHiddenColumns() + .findColumnPosition(maxwidth) - 1; } int canvasWidth = seqPanel.seqCanvas diff --git a/src/jalview/appletgui/AnnotationColumnChooser.java b/src/jalview/appletgui/AnnotationColumnChooser.java index 25ff293..60775d3 100644 --- a/src/jalview/appletgui/AnnotationColumnChooser.java +++ b/src/jalview/appletgui/AnnotationColumnChooser.java @@ -21,7 +21,7 @@ package jalview.appletgui; import jalview.datamodel.AlignmentAnnotation; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.schemes.AnnotationColourGradient; import jalview.util.MessageManager; import jalview.viewmodel.annotationfilter.AnnotationFilterParameter; @@ -110,7 +110,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements private int actionOption = ACTION_OPTION_SELECT; - private ColumnSelection oldColumnSelection; + private HiddenColumns oldHiddenColumns; public AnnotationColumnChooser() { @@ -140,7 +140,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements { return; } - setOldColumnSelection(av.getColumnSelection()); + setOldHiddenColumns(av.getAlignment().getHiddenColumns()); adjusting = true; Vector list = new Vector(); int index = 1; @@ -289,26 +289,26 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements @SuppressWarnings("unchecked") public void reset() { - if (this.getOldColumnSelection() != null) + if (this.getOldHiddenColumns() != null) { av.getColumnSelection().clear(); if (av.getAnnotationColumnSelectionState() != null) { - ColumnSelection oldSelection = av + HiddenColumns oldHidden = av .getAnnotationColumnSelectionState() - .getOldColumnSelection(); - if (oldSelection != null && oldSelection.getHiddenColumns() != null - && !oldSelection.getHiddenColumns().isEmpty()) + .getOldHiddenColumns(); + if (oldHidden != null && oldHidden.getHiddenRegions() != null + && !oldHidden.getHiddenRegions().isEmpty()) { - for (Iterator itr = oldSelection.getHiddenColumns() + for (Iterator itr = oldHidden.getHiddenRegions() .iterator(); itr.hasNext();) { int positions[] = itr.next(); av.hideColumns(positions[0], positions[1]); } } - av.setColumnSelection(oldSelection); + av.getAlignment().setHiddenColumns(oldHidden); } ap.paintAlignment(true); } @@ -518,16 +518,16 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements ap.paintAlignment(true); } - public ColumnSelection getOldColumnSelection() + public HiddenColumns getOldHiddenColumns() { - return oldColumnSelection; + return oldHiddenColumns; } - public void setOldColumnSelection(ColumnSelection currentColumnSelection) + public void setOldHiddenColumns(HiddenColumns currentHiddenColumns) { - if (currentColumnSelection != null) + if (currentHiddenColumns != null) { - this.oldColumnSelection = new ColumnSelection(currentColumnSelection); + this.oldHiddenColumns = new HiddenColumns(currentHiddenColumns); } } diff --git a/src/jalview/appletgui/AnnotationLabels.java b/src/jalview/appletgui/AnnotationLabels.java index ad74b25..307301d 100755 --- a/src/jalview/appletgui/AnnotationLabels.java +++ b/src/jalview/appletgui/AnnotationLabels.java @@ -839,7 +839,8 @@ public class AnnotationLabels extends Panel implements ActionListener, if (av.hasHiddenColumns()) { jalview.appletgui.AlignFrame.copiedHiddenColumns = new Vector(); - for (int[] region : av.getColumnSelection().getHiddenColumns()) + for (int[] region : av.getAlignment().getHiddenColumns() + .getHiddenRegions()) { jalview.appletgui.AlignFrame.copiedHiddenColumns .addElement(new int[] { region[0], region[1] }); diff --git a/src/jalview/appletgui/AnnotationPanel.java b/src/jalview/appletgui/AnnotationPanel.java index 0ec7adf..5026ee4 100755 --- a/src/jalview/appletgui/AnnotationPanel.java +++ b/src/jalview/appletgui/AnnotationPanel.java @@ -165,7 +165,7 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI, { for (int index : av.getColumnSelection().getSelected()) { - if (av.getColumnSelection().isVisible(index)) + if (av.getAlignment().getHiddenColumns().isVisible(index)) { anot[index] = null; } @@ -189,7 +189,7 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI, { // TODO: JAL-2001 - provide a fast method to list visible selected // columns - if (!av.getColumnSelection().isVisible(index)) + if (!av.getAlignment().getHiddenColumns().isVisible(index)) { continue; } @@ -211,7 +211,7 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI, for (int index : av.getColumnSelection().getSelected()) { - if (!av.getColumnSelection().isVisible(index)) + if (!av.getAlignment().getHiddenColumns().isVisible(index)) { continue; } @@ -271,7 +271,7 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI, for (int index : av.getColumnSelection().getSelected()) { - if (!av.getColumnSelection().isVisible(index)) + if (!av.getAlignment().getHiddenColumns().isVisible(index)) { continue; } @@ -467,7 +467,8 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI, if (av.hasHiddenColumns()) { - column = av.getColumnSelection().adjustForHiddenColumns(column); + column = av.getAlignment().getHiddenColumns() + .adjustForHiddenColumns(column); } if (row > -1 && column < aa[row].annotations.length diff --git a/src/jalview/appletgui/CutAndPasteTransfer.java b/src/jalview/appletgui/CutAndPasteTransfer.java index c658734..1e806a5 100644 --- a/src/jalview/appletgui/CutAndPasteTransfer.java +++ b/src/jalview/appletgui/CutAndPasteTransfer.java @@ -25,7 +25,7 @@ import jalview.api.ComplexAlignFile; import jalview.api.FeaturesSourceI; import jalview.bin.JalviewLite; import jalview.datamodel.AlignmentI; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.io.AlignmentFileReaderI; @@ -257,8 +257,8 @@ public class CutAndPasteTransfer extends Panel implements ActionListener, if (source instanceof ComplexAlignFile) { - ColumnSelection colSel = ((ComplexAlignFile) source) - .getColumnSelection(); + HiddenColumns colSel = ((ComplexAlignFile) source) + .getHiddenColumns(); SequenceI[] hiddenSeqs = ((ComplexAlignFile) source) .getHiddenSequences(); boolean showSeqFeatures = ((ComplexAlignFile) source) diff --git a/src/jalview/appletgui/FontChooser.java b/src/jalview/appletgui/FontChooser.java index 59f6957..991fb96 100644 --- a/src/jalview/appletgui/FontChooser.java +++ b/src/jalview/appletgui/FontChooser.java @@ -20,7 +20,6 @@ */ package jalview.appletgui; -import jalview.api.ViewStyleI; import jalview.util.MessageManager; import java.awt.BorderLayout; @@ -59,6 +58,8 @@ public class FontChooser extends Panel implements ItemListener private Checkbox scaleAsCdna = new Checkbox(); + private Checkbox fontAsCdna = new Checkbox(); + private Button ok = new Button(); private Button cancel = new Button(); @@ -69,10 +70,20 @@ public class FontChooser extends Panel implements ItemListener private Font oldFont; + private Font oldComplementFont; + private int oldCharWidth = 0; + /* + * the state of 'scale protein to cDNA' on opening the dialog + */ private boolean oldScaleProtein = false; + /* + * the state of 'same font for protein and cDNA' on opening the dialog + */ + boolean oldMirrorFont; + private Font lastSelected = null; private int lastSelStyle = 0; @@ -83,6 +94,8 @@ public class FontChooser extends Panel implements ItemListener private Frame frame; + boolean inSplitFrame = false; + /** * Constructor for a TreePanel font chooser * @@ -112,8 +125,9 @@ public class FontChooser extends Panel implements ItemListener { this.ap = ap; oldFont = ap.av.getFont(); - oldCharWidth = ap.av.getViewStyle().getCharWidth(); - oldScaleProtein = ap.av.getViewStyle().isScaleProteinAsCdna(); + oldCharWidth = ap.av.getCharWidth(); + oldScaleProtein = ap.av.isScaleProteinAsCdna(); + oldMirrorFont = ap.av.isProteinFontAsCdna(); try { @@ -152,7 +166,7 @@ public class FontChooser extends Panel implements ItemListener this.frame = new Frame(); frame.add(this); jalview.bin.JalviewLite.addFrame(frame, - MessageManager.getString("action.change_font"), 440, 115); + MessageManager.getString("action.change_font"), 440, 145); init = false; } @@ -160,6 +174,7 @@ public class FontChooser extends Panel implements ItemListener /** * Actions on change of font name, size or style. */ + @Override public void itemStateChanged(ItemEvent evt) { final Object source = evt.getSource(); @@ -179,6 +194,29 @@ public class FontChooser extends Panel implements ItemListener { scaleAsCdna_actionPerformed(); } + else if (source == fontAsCdna) + { + mirrorFont_actionPerformed(); + } + } + + /** + * Action on checking or unchecking 'use same font across split screen' + * option. When checked, the font settings are copied to the other half of the + * split screen. When unchecked, the other half is restored to its initial + * settings. + */ + protected void mirrorFont_actionPerformed() + { + boolean selected = fontAsCdna.getState(); + ap.av.setProteinFontAsCdna(selected); + ap.av.getCodingComplement().setProteinFontAsCdna(selected); + + if (!selected) + { + ap.av.getCodingComplement().setFont(oldComplementFont, true); + } + changeFont(); } /** @@ -205,18 +243,23 @@ public class FontChooser extends Panel implements ItemListener if (ap != null) { ap.av.setScaleProteinAsCdna(oldScaleProtein); + ap.av.setProteinFontAsCdna(oldMirrorFont); + if (ap.av.getCodingComplement() != null) { ap.av.getCodingComplement().setScaleProteinAsCdna(oldScaleProtein); - ap.alignFrame.getSplitFrame().repaint(); + ap.av.getCodingComplement().setProteinFontAsCdna(oldMirrorFont); + ap.av.getCodingComplement().setFont(oldComplementFont, true); + SplitFrame splitFrame = ap.alignFrame.getSplitFrame(); + splitFrame.adjustLayout(); + splitFrame.getComplement(ap.alignFrame).alignPanel.fontChanged(); + splitFrame.repaint(); } - ap.av.setFont(oldFont); - ViewStyleI style = ap.av.getViewStyle(); - if (style.getCharWidth() != oldCharWidth) + ap.av.setFont(oldFont, true); + if (ap.av.getCharWidth() != oldCharWidth) { - style.setCharWidth(oldCharWidth); - ap.av.setViewStyle(style); + ap.av.setCharWidth(oldCharWidth); } ap.paintAlignment(true); } @@ -276,8 +319,23 @@ public class FontChooser extends Panel implements ItemListener } else if (ap != null) { - ap.av.setFont(newFont); + ap.av.setFont(newFont, true); ap.fontChanged(); + + /* + * and change font in other half of split frame if any + */ + if (inSplitFrame) + { + if (fontAsCdna.getState()) + { + ap.av.getCodingComplement().setFont(newFont, true); + } + SplitFrame splitFrame = ap.alignFrame.getSplitFrame(); + splitFrame.adjustLayout(); + splitFrame.getComplement(ap.alignFrame).alignPanel.fontChanged(); + splitFrame.repaint(); + } } // remember last selected lastSelected = newFont; @@ -344,6 +402,11 @@ public class FontChooser extends Panel implements ItemListener scaleAsCdna.addItemListener(this); scaleAsCdna.setState(ap.av.isScaleProteinAsCdna()); + fontAsCdna.setLabel(MessageManager.getString("label.font_as_cdna")); + fontAsCdna.setFont(VERDANA_11PT); + fontAsCdna.addItemListener(this); + fontAsCdna.setState(ap.av.isProteinFontAsCdna()); + ok.setFont(VERDANA_11PT); ok.setLabel(MessageManager.getString("action.ok")); ok.addActionListener(new ActionListener() @@ -388,7 +451,8 @@ public class FontChooser extends Panel implements ItemListener stylePanel.add(fontStyle, BorderLayout.CENTER); sizePanel.add(sizeLabel, BorderLayout.WEST); sizePanel.add(fontSize, BorderLayout.CENTER); - scalePanel.add(scaleAsCdna, BorderLayout.CENTER); + scalePanel.add(scaleAsCdna, BorderLayout.NORTH); + scalePanel.add(fontAsCdna, BorderLayout.SOUTH); okCancelPanel.add(ok, null); okCancelPanel.add(cancel, null); @@ -402,6 +466,9 @@ public class FontChooser extends Panel implements ItemListener this.add(optionsPanel, BorderLayout.NORTH); if (ap.alignFrame.getSplitFrame() != null) { + inSplitFrame = true; + oldComplementFont = ((AlignViewport) ap.av.getCodingComplement()) + .getFont(); this.add(scalePanel, BorderLayout.CENTER); } this.add(okCancelPanel, BorderLayout.SOUTH); @@ -416,9 +483,7 @@ public class FontChooser extends Panel implements ItemListener ap.av.setScaleProteinAsCdna(scaleAsCdna.getState()); ap.av.getCodingComplement().setScaleProteinAsCdna( scaleAsCdna.getState()); - ap.alignFrame.getSplitFrame().adjustLayout(); - ap.paintAlignment(true); - ap.alignFrame.getSplitFrame().repaint(); + changeFont(); } } diff --git a/src/jalview/appletgui/IdCanvas.java b/src/jalview/appletgui/IdCanvas.java index abcbd70..db9e661 100755 --- a/src/jalview/appletgui/IdCanvas.java +++ b/src/jalview/appletgui/IdCanvas.java @@ -218,7 +218,8 @@ public class IdCanvas extends Panel if (av.hasHiddenColumns()) { - maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1; + maxwidth = av.getAlignment().getHiddenColumns() + .findColumnPosition(maxwidth) - 1; } int annotationHeight = 0; diff --git a/src/jalview/appletgui/OverviewCanvas.java b/src/jalview/appletgui/OverviewCanvas.java new file mode 100644 index 0000000..23e82df --- /dev/null +++ b/src/jalview/appletgui/OverviewCanvas.java @@ -0,0 +1,167 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.appletgui; + +import jalview.renderer.OverviewRenderer; +import jalview.viewmodel.OverviewDimensions; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Image; + +public class OverviewCanvas extends Component +{ + // This is set true if the alignment view changes whilst + // the overview is being calculated + private volatile boolean restart = false; + + private volatile boolean updaterunning = false; + + private OverviewDimensions od; + + private Image miniMe; + + private Image offscreen; + + private AlignViewport av; + + // Can set different properties in this seqCanvas than + // main visible SeqCanvas + private SequenceRenderer sr; + + private jalview.renderer.seqfeatures.FeatureRenderer fr; + + private Frame nullFrame; + + public OverviewCanvas(OverviewDimensions overviewDims, + AlignViewport alignvp) + { + od = overviewDims; + av = alignvp; + + nullFrame = new Frame(); + nullFrame.addNotify(); + + sr = new SequenceRenderer(av); + sr.graphics = nullFrame.getGraphics(); + sr.renderGaps = false; + sr.forOverview = true; + fr = new jalview.renderer.seqfeatures.FeatureRenderer(av); + } + + /** + * Update the overview dimensions object used by the canvas (e.g. if we change + * from showing hidden columns to hiding them or vice versa) + * + * @param overviewDims + */ + public void resetOviewDims(OverviewDimensions overviewDims) + { + od = overviewDims; + } + + /** + * Signals to drawing code that the associated alignment viewport has changed + * and a redraw will be required + */ + public boolean restartDraw() + { + synchronized (this) + { + if (updaterunning) + { + restart = true; + } + else + { + updaterunning = true; + } + return restart; + } + } + + public void draw(boolean showSequenceFeatures, boolean showAnnotation, + FeatureRenderer transferRenderer) + { + miniMe = null; + + if (showSequenceFeatures) + { + fr.transferSettings(transferRenderer); + } + + setPreferredSize(new Dimension(od.getWidth(), od.getHeight())); + + OverviewRenderer or = new OverviewRenderer(sr, fr, od); + miniMe = nullFrame.createImage(od.getWidth(), od.getHeight()); + offscreen = nullFrame.createImage(od.getWidth(), od.getHeight()); + + miniMe = or.draw(od.getRows(av.getAlignment()), + od.getColumns(av.getAlignment())); + + Graphics mg = miniMe.getGraphics(); + + // checks for conservation annotation to make sure overview works for DNA + // too + if (showAnnotation) + { + mg.translate(0, od.getSequencesHeight()); + or.drawGraph(mg, av.getAlignmentConservationAnnotation(), + av.getCharWidth(), od.getGraphHeight(), + od.getColumns(av.getAlignment())); + mg.translate(0, -od.getSequencesHeight()); + } + System.gc(); + + if (restart) + { + restart = false; + draw(showSequenceFeatures, showAnnotation, transferRenderer); + } + else + { + updaterunning = false; + } + } + + @Override + public void update(Graphics g) + { + paint(g); + } + + @Override + public void paint(Graphics g) + { + Graphics og = offscreen.getGraphics(); + if (miniMe != null) + { + og.drawImage(miniMe, 0, 0, this); + og.setColor(Color.red); + od.drawBox(og); + g.drawImage(offscreen, 0, 0, this); + } + } + +} diff --git a/src/jalview/appletgui/OverviewPanel.java b/src/jalview/appletgui/OverviewPanel.java index 3ef2936..b933d30 100755 --- a/src/jalview/appletgui/OverviewPanel.java +++ b/src/jalview/appletgui/OverviewPanel.java @@ -20,18 +20,22 @@ */ package jalview.appletgui; -import jalview.datamodel.SequenceI; -import jalview.renderer.seqfeatures.FeatureColourFinder; +import jalview.util.MessageManager; +import jalview.util.Platform; import jalview.viewmodel.OverviewDimensions; +import jalview.viewmodel.OverviewDimensionsHideHidden; +import jalview.viewmodel.OverviewDimensionsShowHidden; -import java.awt.Color; +import java.awt.BorderLayout; +import java.awt.CheckboxMenuItem; import java.awt.Dimension; -import java.awt.Frame; -import java.awt.Graphics; -import java.awt.Image; import java.awt.Panel; +import java.awt.PopupMenu; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; +import java.awt.event.InputEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; @@ -41,45 +45,29 @@ public class OverviewPanel extends Panel implements Runnable, { private OverviewDimensions od; - private Image miniMe; - - private Image offscreen; + private OverviewCanvas oviewCanvas; private AlignViewport av; private AlignmentPanel ap; - private boolean resizing = false; - - // This is set true if the user resizes whilst - // the overview is being calculated - private boolean resizeAgain = false; - - // Can set different properties in this seqCanvas than - // main visible SeqCanvas - private SequenceRenderer sr; + private boolean showHidden = true; - private FeatureRenderer fr; - - private Frame nullFrame; + private boolean updateRunning = false; public OverviewPanel(AlignmentPanel alPanel) { this.av = alPanel.av; this.ap = alPanel; setLayout(null); - nullFrame = new Frame(); - nullFrame.addNotify(); - - sr = new SequenceRenderer(av); - sr.graphics = nullFrame.getGraphics(); - sr.renderGaps = false; - sr.forOverview = true; - fr = new FeatureRenderer(av); - od = new OverviewDimensions(av.getRanges(), + od = new OverviewDimensionsShowHidden(av.getRanges(), (av.isShowAnnotation() && av.getSequenceConsensusHash() != null)); + oviewCanvas = new OverviewCanvas(od, av); + setLayout(new BorderLayout()); + add(oviewCanvas, BorderLayout.CENTER); + setSize(new Dimension(od.getWidth(), od.getHeight())); addComponentListener(new ComponentAdapter() { @@ -116,6 +104,10 @@ public class OverviewPanel extends Panel implements Runnable, @Override public void mouseClicked(MouseEvent evt) { + if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) + { + showPopupMenu(evt); + } } @Override @@ -143,11 +135,20 @@ public class OverviewPanel extends Panel implements Runnable, private void mouseAction(MouseEvent evt) { - od.updateViewportFromMouse(evt.getX(), evt.getY(), av.getAlignment() - .getHiddenSequences(), av.getColumnSelection(), av - .getRanges()); - ap.setScrollValues(od.getScrollCol(), od.getScrollRow()); - ap.paintAlignment(false); + if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) + { + if (!Platform.isAMac()) + { + showPopupMenu(evt); + } + } + else + { + od.updateViewportFromMouse(evt.getX(), evt.getY(), av.getAlignment() + .getHiddenSequences(), av.getAlignment().getHiddenColumns()); + ap.setScrollValues(od.getScrollCol(), od.getScrollRow()); + ap.paintAlignment(false); + } } /** @@ -155,19 +156,6 @@ public class OverviewPanel extends Panel implements Runnable, */ public void updateOverviewImage() { - if (resizing) - { - resizeAgain = true; - return; - } - - if (av.isShowSequenceFeatures()) - { - fr.transferSettings(ap.seqPanel.seqCanvas.fr); - } - - resizing = true; - if ((getSize().width > 0) && (getSize().height > 0)) { od.setWidth(getSize().width); @@ -175,156 +163,30 @@ public class OverviewPanel extends Panel implements Runnable, } setSize(new Dimension(od.getWidth(), od.getHeight())); + synchronized (this) + { + if (updateRunning) + { + oviewCanvas.restartDraw(); + return; + } + + updateRunning = true; + } Thread thread = new Thread(this); thread.start(); repaint(); + updateRunning = false; } @Override public void run() { - miniMe = null; - - if (av.isShowSequenceFeatures()) - { - fr.transferSettings(ap.seqPanel.seqCanvas.getFeatureRenderer()); - } - - if (getSize().width > 0 && getSize().height > 0) - { - od.setWidth(getSize().width); - od.setHeight(getSize().height); - } - - setSize(new Dimension(od.getWidth(), od.getHeight())); - - miniMe = nullFrame.createImage(od.getWidth(), od.getHeight()); - offscreen = nullFrame.createImage(od.getWidth(), od.getHeight()); - - Graphics mg = miniMe.getGraphics(); - - int alwidth = av.getAlignment().getWidth(); - int alheight = av.getAlignment().getAbsoluteHeight(); - float sampleCol = alwidth / (float) od.getWidth(); - float sampleRow = alheight / (float) od.getSequencesHeight(); - - buildImage(sampleRow, sampleCol, mg); - - // check for conservation annotation to make sure overview works for DNA too - if (av.isShowAnnotation() - && (av.getAlignmentConservationAnnotation() != null)) - { - for (int col = 0; col < od.getWidth() && !resizeAgain; col++) - { - mg.translate(col, od.getSequencesHeight()); - ap.annotationPanel.renderer.drawGraph(mg, - av.getAlignmentConservationAnnotation(), - av.getAlignmentConservationAnnotation().annotations, - (int) (sampleCol) + 1, od.getGraphHeight(), - (int) (col * sampleCol), (int) (col * sampleCol) + 1); - mg.translate(-col, -od.getSequencesHeight()); - } - } - System.gc(); - - resizing = false; - + oviewCanvas.draw(av.isShowSequenceFeatures(), + (av.isShowAnnotation() && av + .getAlignmentConservationAnnotation() != null), + ap.seqPanel.seqCanvas.getFeatureRenderer()); setBoxPosition(); - - if (resizeAgain) - { - resizeAgain = false; - updateOverviewImage(); - } - } - - /* - * Build the overview panel image - */ - private void buildImage(float sampleRow, float sampleCol, Graphics mg) - { - int lastcol = 0; - int lastrow = 0; - int xstart = 0; - int ystart = 0; - Color color = Color.yellow; - int sameRow = 0; - int sameCol = 0; - - SequenceI seq = null; - FeatureColourFinder finder = new FeatureColourFinder(fr); - - final boolean hasHiddenCols = av.hasHiddenColumns(); - boolean hiddenRow = false; - - for (int row = 0; row <= od.getSequencesHeight() && !resizeAgain; row++) - { - if ((int) (row * sampleRow) == lastrow) - { - sameRow++; - } - else - { - // get the sequence which would be at alignment index 'lastrow' if no - // columns were hidden, and determine whether it is hidden or not - hiddenRow = av.getAlignment().isHidden(lastrow); - seq = av.getAlignment().getSequenceAtAbsoluteIndex(lastrow); - - for (int col = 0; col < od.getWidth(); col++) - { - if ((int) (col * sampleCol) == lastcol - && (int) (row * sampleRow) == lastrow) - { - sameCol++; - } - else - { - lastcol = (int) (col * sampleCol); - - color = getColumnColourFromSequence(seq, hiddenRow, - hasHiddenCols, lastcol, finder); - - mg.setColor(color); - if (sameCol == 1 && sameRow == 1) - { - mg.drawLine(xstart, ystart, xstart, ystart); - } - else - { - mg.fillRect(xstart, ystart, sameCol, sameRow); - } - - xstart = col; - sameCol = 1; - } - } - lastrow = (int) (row * sampleRow); - ystart = row; - sameRow = 1; - } - } - } - - /* - * Find the colour of a sequence at a specified column position - */ - private Color getColumnColourFromSequence( - jalview.datamodel.SequenceI seq, boolean hiddenRow, - boolean hasHiddenCols, int lastcol, FeatureColourFinder finder) - { - Color color = Color.white; - if (seq.getLength() > lastcol) - { - color = sr.getResidueColour(seq, lastcol, finder); - } - - if (hiddenRow - || (hasHiddenCols && !av.getColumnSelection() - .isVisible(lastcol))) - { - color = color.darker().darker(); - } - return color; } /** @@ -335,27 +197,54 @@ public class OverviewPanel extends Panel implements Runnable, public void setBoxPosition() { od.setBoxPosition(av.getAlignment() - .getHiddenSequences(), av.getColumnSelection(), av.getRanges()); +.getHiddenSequences(), av + .getAlignment().getHiddenColumns()); repaint(); } - @Override - public void update(Graphics g) + /* + * Displays the popup menu and acts on user input + */ + private void showPopupMenu(MouseEvent e) { - paint(g); + PopupMenu popup = new PopupMenu(); + ItemListener menuListener = new ItemListener() + { + @Override + public void itemStateChanged(ItemEvent e) + { + toggleHiddenColumns(); + } + }; + CheckboxMenuItem item = new CheckboxMenuItem( + MessageManager.getString("label.togglehidden")); + item.setState(showHidden); + popup.add(item); + item.addItemListener(menuListener); + this.add(popup); + popup.show(this, e.getX(), e.getY()); } - @Override - public void paint(Graphics g) + /* + * Toggle overview display between showing hidden columns and hiding hidden columns + */ + private void toggleHiddenColumns() { - Graphics og = offscreen.getGraphics(); - if (miniMe != null) + if (showHidden) + { + showHidden = false; + od = new OverviewDimensionsHideHidden(av.getRanges(), + (av.isShowAnnotation() && av + .getAlignmentConservationAnnotation() != null)); + } + else { - og.drawImage(miniMe, 0, 0, this); - og.setColor(Color.red); - od.drawBox(og); - g.drawImage(offscreen, 0, 0, this); + showHidden = true; + od = new OverviewDimensionsShowHidden(av.getRanges(), + (av.isShowAnnotation() && av + .getAlignmentConservationAnnotation() != null)); } + oviewCanvas.resetOviewDims(od); + updateOverviewImage(); } - } diff --git a/src/jalview/appletgui/PCAPanel.java b/src/jalview/appletgui/PCAPanel.java index 2d77c59..5dc57f9 100644 --- a/src/jalview/appletgui/PCAPanel.java +++ b/src/jalview/appletgui/PCAPanel.java @@ -25,7 +25,7 @@ import jalview.analysis.scoremodels.SimilarityParams; import jalview.api.analysis.ScoreModelI; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentView; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SeqCigar; import jalview.datamodel.SequenceI; import jalview.util.MessageManager; @@ -281,7 +281,7 @@ public class PCAPanel extends EmbmenuFrame implements Runnable, } ; Object[] alAndColsel = pcaModel.getSeqtrings() - .getAlignmentAndColumnSelection(gc); + .getAlignmentAndHiddenColumns(gc); if (alAndColsel != null && alAndColsel[0] != null) { @@ -289,7 +289,8 @@ public class PCAPanel extends EmbmenuFrame implements Runnable, AlignFrame af = new AlignFrame(al, av.applet, "Original Data for PCA", false); - af.viewport.setHiddenColumns((ColumnSelection) alAndColsel[1]); + af.viewport.getAlignment().setHiddenColumns( + (HiddenColumns) alAndColsel[1]); } } diff --git a/src/jalview/appletgui/ScalePanel.java b/src/jalview/appletgui/ScalePanel.java index 15d82a5..22b4e3a 100755 --- a/src/jalview/appletgui/ScalePanel.java +++ b/src/jalview/appletgui/ScalePanel.java @@ -21,6 +21,7 @@ package jalview.appletgui; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceGroup; import jalview.renderer.ScaleRenderer; import jalview.renderer.ScaleRenderer.ScaleMark; @@ -81,7 +82,7 @@ public class ScalePanel extends Panel implements MouseMotionListener, if (av.hasHiddenColumns()) { - res = av.getColumnSelection().adjustForHiddenColumns(x); + res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(x); } else { @@ -170,7 +171,7 @@ public class ScalePanel extends Panel implements MouseMotionListener, }); pop.add(item); - if (av.getColumnSelection().hasManyHiddenColumns()) + if (av.getAlignment().getHiddenColumns().hasManyHiddenColumns()) { item = new MenuItem(MessageManager.getString("action.reveal_all")); item.addActionListener(new ActionListener() @@ -239,7 +240,8 @@ public class ScalePanel extends Panel implements MouseMotionListener, if (av.hasHiddenColumns()) { - res = av.getColumnSelection().adjustForHiddenColumns(res); + res = av.getAlignment().getHiddenColumns() + .adjustForHiddenColumns(res); } if (!stretchingGroup) @@ -280,7 +282,7 @@ public class ScalePanel extends Panel implements MouseMotionListener, int res = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes(); res = Math.max(0, res); - res = cs.adjustForHiddenColumns(res); + res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(res); res = Math.min(res, av.getAlignment().getWidth() - 1); min = Math.min(res, min); max = Math.max(res, max); @@ -329,10 +331,11 @@ public class ScalePanel extends Panel implements MouseMotionListener, int res = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes(); - res = av.getColumnSelection().adjustForHiddenColumns(res); + res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(res); reveal = null; - for (int[] region : av.getColumnSelection().getHiddenColumns()) + for (int[] region : av.getAlignment().getHiddenColumns() + .getHiddenRegions()) { if (res + 1 == region[0] || res - 1 == region[1]) { @@ -370,21 +373,22 @@ public class ScalePanel extends Panel implements MouseMotionListener, // Fill the selected columns ColumnSelection cs = av.getColumnSelection(); + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); int avCharWidth = av.getCharWidth(); int avcharHeight = av.getCharHeight(); if (cs != null) { gg.setColor(new Color(220, 0, 0)); - boolean hasHiddenColumns = cs.hasHiddenColumns(); + boolean hasHiddenColumns = hidden.hasHiddenColumns(); for (int sel : cs.getSelected()) { // TODO: JAL-2001 - provide a fast method to list visible selected in a // given range if (hasHiddenColumns) { - if (cs.isVisible(sel)) + if (hidden.isVisible(sel)) { - sel = cs.findColumnPosition(sel); + sel = hidden.findColumnPosition(sel); } else { @@ -443,10 +447,10 @@ public class ScalePanel extends Panel implements MouseMotionListener, if (av.getShowHiddenMarkers()) { int widthx = 1 + endx - startx; - for (int i = 0; i < cs.getHiddenColumns().size(); i++) + for (int i = 0; i < hidden.getHiddenRegions().size(); i++) { - res = cs.findHiddenRegionPosition(i) - startx; + res = hidden.findHiddenRegionPosition(i) - startx; if (res < 0 || res > widthx) { diff --git a/src/jalview/appletgui/SeqCanvas.java b/src/jalview/appletgui/SeqCanvas.java index 89df11f..39382c5 100755 --- a/src/jalview/appletgui/SeqCanvas.java +++ b/src/jalview/appletgui/SeqCanvas.java @@ -21,6 +21,7 @@ package jalview.appletgui; import jalview.datamodel.AlignmentI; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SearchResultsI; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; @@ -123,14 +124,17 @@ public class SeqCanvas extends Panel ypos += avcharHeight; if (av.hasHiddenColumns()) { - startx = av.getColumnSelection().adjustForHiddenColumns(startx); - endx = av.getColumnSelection().adjustForHiddenColumns(endx); + startx = av.getAlignment().getHiddenColumns() + .adjustForHiddenColumns(startx); + endx = av.getAlignment().getHiddenColumns() + .adjustForHiddenColumns(endx); } int maxwidth = av.getAlignment().getWidth(); if (av.hasHiddenColumns()) { - maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1; + maxwidth = av.getAlignment().getHiddenColumns() + .findColumnPosition(maxwidth) - 1; } // WEST SCALE @@ -170,7 +174,8 @@ public class SeqCanvas extends Panel if (av.hasHiddenColumns()) { - endx = av.getColumnSelection().adjustForHiddenColumns(endx); + endx = av.getAlignment().getHiddenColumns() + .adjustForHiddenColumns(endx); } SequenceI seq; @@ -440,7 +445,8 @@ public class SeqCanvas extends Panel if (av.hasHiddenColumns()) { - maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1; + maxwidth = av.getAlignment().getHiddenColumns() + .findColumnPosition(maxwidth) - 1; } while ((ypos <= canvasHeight) && (startRes < maxwidth)) @@ -474,12 +480,13 @@ public class SeqCanvas extends Panel } if (av.hasHiddenColumns() && av.getShowHiddenMarkers()) { + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); g.setColor(Color.blue); int res; - for (int i = 0; i < av.getColumnSelection().getHiddenColumns() + for (int i = 0; i < hidden.getHiddenRegions() .size(); i++) { - res = av.getColumnSelection().findHiddenRegionPosition(i) + res = hidden.findHiddenRegionPosition(i) - startRes; if (res < 0 || res > endx - startRes) @@ -558,7 +565,8 @@ public class SeqCanvas extends Panel if (av.hasHiddenColumns()) { - for (int[] region : av.getColumnSelection().getHiddenColumns()) + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); + for (int[] region : hidden.getHiddenRegions()) { int hideStart = region[0]; int hideEnd = region[1]; diff --git a/src/jalview/appletgui/SeqPanel.java b/src/jalview/appletgui/SeqPanel.java index 60c53dd..fcae97c 100644 --- a/src/jalview/appletgui/SeqPanel.java +++ b/src/jalview/appletgui/SeqPanel.java @@ -25,6 +25,7 @@ import jalview.commands.EditCommand; import jalview.commands.EditCommand.Action; import jalview.datamodel.AlignmentI; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SearchResultMatchI; import jalview.datamodel.SearchResults; import jalview.datamodel.SearchResultsI; @@ -180,19 +181,22 @@ public class SeqPanel extends Panel implements MouseMotionListener, seqCanvas.cursorX += dx; seqCanvas.cursorY += dy; if (av.hasHiddenColumns() - && !av.getColumnSelection().isVisible(seqCanvas.cursorX)) + && !av.getAlignment().getHiddenColumns() + .isVisible(seqCanvas.cursorX)) { int original = seqCanvas.cursorX - dx; int maxWidth = av.getAlignment().getWidth(); - while (!av.getColumnSelection().isVisible(seqCanvas.cursorX) + while (!av.getAlignment().getHiddenColumns() + .isVisible(seqCanvas.cursorX) && seqCanvas.cursorX < maxWidth && seqCanvas.cursorX > 0) { seqCanvas.cursorX += dx; } if (seqCanvas.cursorX >= maxWidth - || !av.getColumnSelection().isVisible(seqCanvas.cursorX)) + || !av.getAlignment().getHiddenColumns() + .isVisible(seqCanvas.cursorX)) { seqCanvas.cursorX = original; } @@ -228,6 +232,7 @@ public class SeqPanel extends Panel implements MouseMotionListener, else { ViewportRanges ranges = av.getRanges(); + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); while (seqCanvas.cursorY < ranges.getStartSeq()) { ap.scrollUp(true); @@ -236,8 +241,8 @@ public class SeqPanel extends Panel implements MouseMotionListener, { ap.scrollUp(false); } - while (seqCanvas.cursorX < av.getColumnSelection() - .adjustForHiddenColumns(ranges.getStartRes())) + while (seqCanvas.cursorX < hidden.adjustForHiddenColumns(ranges + .getStartRes())) { if (!ap.scrollRight(false)) @@ -245,8 +250,8 @@ public class SeqPanel extends Panel implements MouseMotionListener, break; } } - while (seqCanvas.cursorX > av.getColumnSelection() - .adjustForHiddenColumns(ranges.getEndRes())) + while (seqCanvas.cursorX > hidden.adjustForHiddenColumns(ranges + .getEndRes())) { if (!ap.scrollRight(true)) { @@ -638,7 +643,8 @@ public class SeqPanel extends Panel implements MouseMotionListener, if (av.hasHiddenColumns()) { - res = av.getColumnSelection().adjustForHiddenColumns(res); + res = av.getAlignment().getHiddenColumns() + .adjustForHiddenColumns(res); } return res; @@ -959,7 +965,9 @@ public class SeqPanel extends Panel implements MouseMotionListener, fontSize = 1; } - av.setFont(new Font(av.font.getName(), av.font.getStyle(), fontSize)); + av.setFont( + new Font(av.font.getName(), av.font.getStyle(), fontSize), + true); av.setCharWidth(oldWidth); } else @@ -1131,8 +1139,10 @@ public class SeqPanel extends Panel implements MouseMotionListener, if (av.hasHiddenColumns()) { fixedColumns = true; - int y1 = av.getColumnSelection().getHiddenBoundaryLeft(startres); - int y2 = av.getColumnSelection().getHiddenBoundaryRight(startres); + int y1 = av.getAlignment().getHiddenColumns() + .getHiddenBoundaryLeft(startres); + int y2 = av.getAlignment().getHiddenColumns() + .getHiddenBoundaryRight(startres); if ((insertGap && startres > y1 && lastres < y1) || (!insertGap && startres < y2 && lastres > y2)) @@ -1203,8 +1213,8 @@ public class SeqPanel extends Panel implements MouseMotionListener, { if (sg.getSize() == av.getAlignment().getHeight()) { - if ((av.hasHiddenColumns() && startres < av - .getColumnSelection().getHiddenBoundaryRight(startres))) + if ((av.hasHiddenColumns() && startres < av.getAlignment() + .getHiddenColumns().getHiddenBoundaryRight(startres))) { endEditing(); return; @@ -1787,7 +1797,7 @@ public class SeqPanel extends Panel implements MouseMotionListener, */ @Override public void selection(SequenceGroup seqsel, ColumnSelection colsel, - SelectionSource source) + HiddenColumns hidden, SelectionSource source) { // TODO: fix this hack - source of messages is align viewport, but SeqPanel // handles selection messages... @@ -1804,7 +1814,7 @@ public class SeqPanel extends Panel implements MouseMotionListener, * Check for selection in a view of which this one is a dna/protein * complement. */ - if (selectionFromTranslation(seqsel, colsel, source)) + if (selectionFromTranslation(seqsel, colsel, hidden, source)) { return; } @@ -1870,15 +1880,16 @@ public class SeqPanel extends Panel implements MouseMotionListener, } else { - av.getColumnSelection().setElementsFrom(colsel); + av.getColumnSelection().setElementsFrom(colsel, + av.getAlignment().getHiddenColumns()); } } repaint |= av.isColSelChanged(true); } if (copycolsel && av.hasHiddenColumns() - && (av.getColumnSelection() == null || av.getColumnSelection() - .getHiddenColumns() == null)) + && (av.getColumnSelection() == null || av.getAlignment() + .getHiddenColumns().getHiddenRegions() == null)) { System.err.println("Bad things"); } @@ -1938,7 +1949,8 @@ public class SeqPanel extends Panel implements MouseMotionListener, * @param source */ protected boolean selectionFromTranslation(SequenceGroup seqsel, - ColumnSelection colsel, SelectionSource source) + ColumnSelection colsel, HiddenColumns hidden, + SelectionSource source) { if (!(source instanceof AlignViewportI)) { @@ -1961,9 +1973,13 @@ public class SeqPanel extends Panel implements MouseMotionListener, /* * Map column selection */ - ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv, - av); + // ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv, + // av); + ColumnSelection cs = new ColumnSelection(); + HiddenColumns hs = new HiddenColumns(); + MappingUtils.mapColumnSelection(colsel, hidden, sourceAv, av, cs, hs); av.setColumnSelection(cs); + av.getAlignment().setHiddenColumns(hs); ap.scalePanelHolder.repaint(); ap.repaint(); diff --git a/src/jalview/appletgui/TreePanel.java b/src/jalview/appletgui/TreePanel.java index 8b1f79c..c7bf6aa 100644 --- a/src/jalview/appletgui/TreePanel.java +++ b/src/jalview/appletgui/TreePanel.java @@ -28,7 +28,7 @@ import jalview.analysis.scoremodels.ScoreModels; import jalview.analysis.scoremodels.SimilarityParams; import jalview.api.analysis.ScoreModelI; import jalview.datamodel.Alignment; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceI; import jalview.io.NewickFile; import jalview.util.MessageManager; @@ -152,7 +152,7 @@ public class TreePanel extends EmbmenuFrame implements ActionListener, } Object[] alAndColsel = tree.getOriginalData() - .getAlignmentAndColumnSelection(gc); + .getAlignmentAndHiddenColumns(gc); if (alAndColsel != null && alAndColsel[0] != null) { @@ -160,7 +160,8 @@ public class TreePanel extends EmbmenuFrame implements ActionListener, AlignFrame af = new AlignFrame(al, av.applet, "Original Data for Tree", false); - af.viewport.setHiddenColumns((ColumnSelection) alAndColsel[1]); + af.viewport.getAlignment().setHiddenColumns( + (HiddenColumns) alAndColsel[1]); } } else diff --git a/src/jalview/bin/JalviewLite.java b/src/jalview/bin/JalviewLite.java index 7fa5147..dbc707d 100644 --- a/src/jalview/bin/JalviewLite.java +++ b/src/jalview/bin/JalviewLite.java @@ -31,6 +31,7 @@ import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentOrder; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceGroup; @@ -485,7 +486,8 @@ public class JalviewLite extends Applet implements @Override public void run() { - alf.select(sel, csel); + alf.select(sel, csel, alf.getAlignViewport().getAlignment() + .getHiddenColumns()); } }); } @@ -2273,9 +2275,9 @@ public class JalviewLite extends Applet implements SequenceI repseq = alignFrame.viewport.getAlignment() .getSequenceAt(0); alignFrame.viewport.getAlignment().setSeqrep(repseq); - ColumnSelection cs = new ColumnSelection(); + HiddenColumns cs = new HiddenColumns(); cs.hideInsertionsFor(repseq); - alignFrame.viewport.setColumnSelection(cs); + alignFrame.viewport.getAlignment().setHiddenColumns(cs); alignFrame.alignPanel.fontChanged(); alignFrame.alignPanel.setScrollValues(0, 0); result = true; diff --git a/src/jalview/datamodel/Alignment.java b/src/jalview/datamodel/Alignment.java index 8371036..fcb6109 100755 --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@ -62,6 +62,8 @@ public class Alignment implements AlignmentI HiddenSequences hiddenSequences; + HiddenColumns hiddenCols; + public Hashtable alignmentProperties; private List codonFrameList; @@ -70,6 +72,7 @@ public class Alignment implements AlignmentI { groups = Collections.synchronizedList(new ArrayList()); hiddenSequences = new HiddenSequences(this); + hiddenCols = new HiddenColumns(); codonFrameList = new ArrayList(); nucleotide = Comparison.isNucleotide(seqs); @@ -125,7 +128,7 @@ public class Alignment implements AlignmentI public Alignment(SeqCigar[] alseqs) { SequenceI[] seqs = SeqCigar.createAlignmentSequences(alseqs, - gapCharacter, new ColumnSelection(), null); + gapCharacter, new HiddenColumns(), null); initAlignment(seqs); } @@ -1327,6 +1330,12 @@ public class Alignment implements AlignmentI } @Override + public HiddenColumns getHiddenColumns() + { + return hiddenCols; + } + + @Override public CigarArray getCompactAlignment() { synchronized (sequences) @@ -1944,4 +1953,10 @@ public class Alignment implements AlignmentI } return new int[] { startPos, endPos }; } + + @Override + public void setHiddenColumns(HiddenColumns cols) + { + hiddenCols = cols; + } } diff --git a/src/jalview/datamodel/AlignmentAnnotation.java b/src/jalview/datamodel/AlignmentAnnotation.java index 543958e..1594f2b 100755 --- a/src/jalview/datamodel/AlignmentAnnotation.java +++ b/src/jalview/datamodel/AlignmentAnnotation.java @@ -20,6 +20,10 @@ */ package jalview.datamodel; +import jalview.analysis.Rna; +import jalview.analysis.SecStrConsensus.SimpleBP; +import jalview.analysis.WUSSParseException; + import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -28,10 +32,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -import jalview.analysis.Rna; -import jalview.analysis.SecStrConsensus.SimpleBP; -import jalview.analysis.WUSSParseException; - /** * DOCUMENT ME! * @@ -1150,14 +1150,14 @@ public class AlignmentAnnotation * @param colSel */ public AlignmentAnnotation(AlignmentAnnotation alignmentAnnotation, - ColumnSelection colSel) + HiddenColumns hidden) { this(alignmentAnnotation); if (annotations == null) { return; } - colSel.makeVisibleAnnotation(this); + hidden.makeVisibleAnnotation(this); } public void setPadGaps(boolean padgaps, char gapchar) diff --git a/src/jalview/datamodel/AlignmentI.java b/src/jalview/datamodel/AlignmentI.java index 2abb1f8..2e61f9d 100755 --- a/src/jalview/datamodel/AlignmentI.java +++ b/src/jalview/datamodel/AlignmentI.java @@ -358,6 +358,8 @@ public interface AlignmentI extends AnnotatedCollectionI HiddenSequences getHiddenSequences(); + HiddenColumns getHiddenColumns(); + /** * Compact representation of alignment * @@ -587,4 +589,6 @@ public interface AlignmentI extends AnnotatedCollectionI */ public int[] getVisibleStartAndEndIndex(List hiddenCols); + public void setHiddenColumns(HiddenColumns cols); + } diff --git a/src/jalview/datamodel/AlignmentView.java b/src/jalview/datamodel/AlignmentView.java index 1e34036..5058dcf 100644 --- a/src/jalview/datamodel/AlignmentView.java +++ b/src/jalview/datamodel/AlignmentView.java @@ -141,13 +141,14 @@ public class AlignmentView * the view */ public AlignmentView(AlignmentI alignment, - ColumnSelection columnSelection, SequenceGroup selection, + HiddenColumns hidden, + SequenceGroup selection, boolean hasHiddenColumns, boolean selectedRegionOnly, boolean recordGroups) { // refactored from AlignViewport.getAlignmentView(selectedOnly); this(new jalview.datamodel.CigarArray(alignment, - (hasHiddenColumns ? columnSelection : null), + (hasHiddenColumns ? hidden : null), (selectedRegionOnly ? selection : null)), (selectedRegionOnly && selection != null) ? selection .getStartRes() : 0); @@ -330,13 +331,13 @@ public class AlignmentView * char * @return Object[] { SequenceI[], ColumnSelection} */ - public Object[] getAlignmentAndColumnSelection(char gapCharacter) + public Object[] getAlignmentAndHiddenColumns(char gapCharacter) { - ColumnSelection colsel = new ColumnSelection(); + HiddenColumns hidden = new HiddenColumns(); return new Object[] { - SeqCigar.createAlignmentSequences(sequences, gapCharacter, colsel, - contigs), colsel }; + SeqCigar.createAlignmentSequences(sequences, gapCharacter, hidden, + contigs), hidden }; } /** @@ -710,7 +711,8 @@ public class AlignmentView if (contigs != null && contigs.length > 0) { SequenceI[] alignment = new SequenceI[sequences.length]; - ColumnSelection columnselection = new ColumnSelection(); + // ColumnSelection columnselection = new ColumnSelection(); + HiddenColumns hidden = new HiddenColumns(); if (contigs != null && contigs.length > 0) { int start = 0; @@ -823,7 +825,7 @@ public class AlignmentView } } // mark hidden segment as hidden in the new alignment - columnselection.hideColumns(nwidth, nwidth + contigs[contig + 2] + hidden.hideColumns(nwidth, nwidth + contigs[contig + 2] - 1); nwidth += contigs[contig + 2]; } @@ -901,7 +903,7 @@ public class AlignmentView } } } - return new Object[] { alignment, columnselection }; + return new Object[] { alignment, hidden }; } else { @@ -920,7 +922,7 @@ public class AlignmentView } else { - return getAlignmentAndColumnSelection(gapCharacter); + return getAlignmentAndHiddenColumns(gapCharacter); } } } @@ -1135,7 +1137,7 @@ public class AlignmentView } public static void testSelectionViews(AlignmentI alignment, - ColumnSelection csel, SequenceGroup selection) + HiddenColumns hidden, SequenceGroup selection) { System.out.println("Testing standard view creation:\n"); AlignmentView view = null; @@ -1143,7 +1145,7 @@ public class AlignmentView { System.out .println("View with no hidden columns, no limit to selection, no groups to be collected:"); - view = new AlignmentView(alignment, csel, selection, false, false, + view = new AlignmentView(alignment, hidden, selection, false, false, false); summariseAlignmentView(view, System.out); @@ -1157,7 +1159,7 @@ public class AlignmentView { System.out .println("View with no hidden columns, no limit to selection, and all groups to be collected:"); - view = new AlignmentView(alignment, csel, selection, false, false, + view = new AlignmentView(alignment, hidden, selection, false, false, true); summariseAlignmentView(view, System.out); } catch (Exception e) @@ -1170,7 +1172,7 @@ public class AlignmentView { System.out .println("View with no hidden columns, limited to selection and no groups to be collected:"); - view = new AlignmentView(alignment, csel, selection, false, true, + view = new AlignmentView(alignment, hidden, selection, false, true, false); summariseAlignmentView(view, System.out); } catch (Exception e) @@ -1183,7 +1185,7 @@ public class AlignmentView { System.out .println("View with no hidden columns, limited to selection, and all groups to be collected:"); - view = new AlignmentView(alignment, csel, selection, false, true, + view = new AlignmentView(alignment, hidden, selection, false, true, true); summariseAlignmentView(view, System.out); } catch (Exception e) @@ -1196,7 +1198,7 @@ public class AlignmentView { System.out .println("View *with* hidden columns, no limit to selection, no groups to be collected:"); - view = new AlignmentView(alignment, csel, selection, true, false, + view = new AlignmentView(alignment, hidden, selection, true, false, false); summariseAlignmentView(view, System.out); } catch (Exception e) @@ -1209,7 +1211,7 @@ public class AlignmentView { System.out .println("View *with* hidden columns, no limit to selection, and all groups to be collected:"); - view = new AlignmentView(alignment, csel, selection, true, false, + view = new AlignmentView(alignment, hidden, selection, true, false, true); summariseAlignmentView(view, System.out); } catch (Exception e) @@ -1222,7 +1224,7 @@ public class AlignmentView { System.out .println("View *with* hidden columns, limited to selection and no groups to be collected:"); - view = new AlignmentView(alignment, csel, selection, true, true, + view = new AlignmentView(alignment, hidden, selection, true, true, false); summariseAlignmentView(view, System.out); } catch (Exception e) @@ -1235,7 +1237,8 @@ public class AlignmentView { System.out .println("View *with* hidden columns, limited to selection, and all groups to be collected:"); - view = new AlignmentView(alignment, csel, selection, true, true, true); + view = new AlignmentView(alignment, hidden, selection, true, true, + true); summariseAlignmentView(view, System.out); } catch (Exception e) { diff --git a/src/jalview/datamodel/AllColsCollection.java b/src/jalview/datamodel/AllColsCollection.java new file mode 100644 index 0000000..f84ba95 --- /dev/null +++ b/src/jalview/datamodel/AllColsCollection.java @@ -0,0 +1,52 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import jalview.api.AlignmentColsCollectionI; + +import java.util.Iterator; + +public class AllColsCollection implements AlignmentColsCollectionI +{ + int start; + int end; + + HiddenColumns hidden; + + public AllColsCollection(int s, int e, AlignmentI al) + { + start = s; + end = e; + hidden = al.getHiddenColumns(); + } + + @Override + public Iterator iterator() + { + return new AllColsIterator(start,end,hidden); + } + + @Override + public boolean isHidden(int c) + { + return !hidden.isVisible(c); + } +} diff --git a/src/jalview/datamodel/AllColsIterator.java b/src/jalview/datamodel/AllColsIterator.java new file mode 100644 index 0000000..c7a0bb1 --- /dev/null +++ b/src/jalview/datamodel/AllColsIterator.java @@ -0,0 +1,73 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * An iterator which iterates over all columns or rows in an alignment, whether + * hidden or visible. + * + * @author kmourao + * + */ +public class AllColsIterator implements Iterator +{ + private int last; + + private int next; + + private int current; + + public AllColsIterator(int firstcol, int lastcol, HiddenColumns hiddenCols) + { + last = lastcol; + next = firstcol; + current = firstcol; + } + + @Override + public boolean hasNext() + { + return current + 1 <= last; + } + + @Override + public Integer next() + { + if (current + 1 > last) + { + throw new NoSuchElementException(); + } + current = next; + next++; + + return current; + } + + @Override + public void remove() + { + throw new UnsupportedOperationException(); + } +} + diff --git a/src/jalview/datamodel/AllRowsCollection.java b/src/jalview/datamodel/AllRowsCollection.java new file mode 100644 index 0000000..502ace4 --- /dev/null +++ b/src/jalview/datamodel/AllRowsCollection.java @@ -0,0 +1,63 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import jalview.api.AlignmentRowsCollectionI; + +import java.util.Iterator; + +public class AllRowsCollection implements AlignmentRowsCollectionI +{ + int start; + + int end; + + AlignmentI alignment; + + HiddenSequences hidden; + + public AllRowsCollection(int s, int e, AlignmentI al) + { + start = s; + end = e; + alignment = al; + hidden = al.getHiddenSequences(); + } + + @Override + public Iterator iterator() + { + return new AllRowsIterator(start, end, alignment); + } + + @Override + public boolean isHidden(int seq) + { + return hidden.isHidden(seq); + } + + @Override + public SequenceI getSequence(int seq) + { + return alignment.getSequenceAtAbsoluteIndex(seq); + } +} + diff --git a/src/jalview/datamodel/AllRowsIterator.java b/src/jalview/datamodel/AllRowsIterator.java new file mode 100644 index 0000000..aefed60 --- /dev/null +++ b/src/jalview/datamodel/AllRowsIterator.java @@ -0,0 +1,77 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * An iterator which iterates over all columns or rows in an alignment, whether + * hidden or visible. + * + * @author kmourao + * + */ +public class AllRowsIterator implements Iterator +{ + private int last; + + private int next; + + private int current; + + private AlignmentI al; + + public AllRowsIterator(int firstrow, int lastrow, AlignmentI alignment) + { + last = lastrow; + current = firstrow; + next = firstrow; + al = alignment; + } + + @Override + public boolean hasNext() + { + return current + 1 <= last; + } + + @Override + public Integer next() + { + if (current + 1 > last) + { + throw new NoSuchElementException(); + } + current = next; + next++; + + return current; + } + + @Override + public void remove() + { + throw new UnsupportedOperationException(); + } +} + + diff --git a/src/jalview/datamodel/CigarArray.java b/src/jalview/datamodel/CigarArray.java index f6e5862..aab82a1 100644 --- a/src/jalview/datamodel/CigarArray.java +++ b/src/jalview/datamodel/CigarArray.java @@ -20,6 +20,8 @@ */ package jalview.datamodel; +import htsjdk.samtools.Cigar; + import java.util.List; public class CigarArray extends CigarBase @@ -85,12 +87,12 @@ public class CigarArray extends CigarBase * @param columnSelection * @param selectionGroup */ - public CigarArray(AlignmentI alignment, ColumnSelection columnSelection, + public CigarArray(AlignmentI alignment, HiddenColumns hidden, SequenceGroup selectionGroup) { this(constructSeqCigarArray(alignment, selectionGroup)); constructFromAlignment(alignment, - columnSelection != null ? columnSelection.getHiddenColumns() + hidden != null ? hidden.getHiddenRegions() : null, selectionGroup); } diff --git a/src/jalview/datamodel/ColumnSelection.java b/src/jalview/datamodel/ColumnSelection.java index 97bc5a3..eb2d174 100644 --- a/src/jalview/datamodel/ColumnSelection.java +++ b/src/jalview/datamodel/ColumnSelection.java @@ -20,8 +20,6 @@ */ package jalview.datamodel; -import jalview.util.Comparison; -import jalview.util.ShiftList; import jalview.viewmodel.annotationfilter.AnnotationFilterParameter; import jalview.viewmodel.annotationfilter.AnnotationFilterParameter.SearchableAnnotationField; @@ -29,7 +27,6 @@ import java.util.ArrayList; import java.util.BitSet; import java.util.Collections; import java.util.List; -import java.util.Vector; /** * Data class holding the selected columns and hidden column ranges for a view. @@ -268,12 +265,6 @@ public class ColumnSelection IntList selection = new IntList(); - /* - * list of hidden column [start, end] ranges; the list is maintained in - * ascending start column order - */ - Vector hiddenColumns; - /** * Add a column to the selection * @@ -350,1100 +341,137 @@ public class ColumnSelection } /** - * - * @param col - * index to search for in column selection - * - * @return true if col is selected - */ - public boolean contains(int col) - { - return (col > -1) ? selection.isSelected(col) : false; - } - - /** - * Answers true if no columns are selected, else false - */ - public boolean isEmpty() - { - return selection == null || selection.isEmpty(); - } - - /** - * rightmost selected column - * - * @return rightmost column in alignment that is selected - */ - public int getMax() - { - if (selection.isEmpty()) - { - return -1; - } - return selection.getMaxColumn(); - } - - /** - * Leftmost column in selection - * - * @return column index of leftmost column in selection - */ - public int getMin() - { - if (selection.isEmpty()) - { - return 1000000000; - } - return selection.getMinColumn(); - } - - /** - * propagate shift in alignment columns to column selection - * - * @param start - * beginning of edit - * @param left - * shift in edit (+ve for removal, or -ve for inserts) - */ - public List compensateForEdit(int start, int change) - { - List deletedHiddenColumns = null; - selection.compensateForEdits(start, change); - - if (hiddenColumns != null) - { - deletedHiddenColumns = new ArrayList(); - int hSize = hiddenColumns.size(); - for (int i = 0; i < hSize; i++) - { - int[] region = hiddenColumns.elementAt(i); - if (region[0] > start && start + change > region[1]) - { - deletedHiddenColumns.add(region); - - hiddenColumns.removeElementAt(i); - i--; - hSize--; - continue; - } - - if (region[0] > start) - { - region[0] -= change; - region[1] -= change; - } - - if (region[0] < 0) - { - region[0] = 0; - } - - } - - this.revealHiddenColumns(0); - } - - return deletedHiddenColumns; - } - - /** - * propagate shift in alignment columns to column selection special version of - * compensateForEdit - allowing for edits within hidden regions - * - * @param start - * beginning of edit - * @param left - * shift in edit (+ve for removal, or -ve for inserts) - */ - private void compensateForDelEdits(int start, int change) - { - - selection.compensateForEdits(start, change); - - if (hiddenColumns != null) - { - for (int i = 0; i < hiddenColumns.size(); i++) - { - int[] region = hiddenColumns.elementAt(i); - if (region[0] >= start) - { - region[0] -= change; - } - if (region[1] >= start) - { - region[1] -= change; - } - if (region[1] < region[0]) - { - hiddenColumns.removeElementAt(i--); - } - - if (region[0] < 0) - { - region[0] = 0; - } - if (region[1] < 0) - { - region[1] = 0; - } - } - } - } - - /** - * Adjust hidden column boundaries based on a series of column additions or - * deletions in visible regions. - * - * @param shiftrecord - * @return - */ - public ShiftList compensateForEdits(ShiftList shiftrecord) - { - if (shiftrecord != null) - { - final List shifts = shiftrecord.getShifts(); - if (shifts != null && shifts.size() > 0) - { - int shifted = 0; - for (int i = 0, j = shifts.size(); i < j; i++) - { - int[] sh = shifts.get(i); - // compensateForEdit(shifted+sh[0], sh[1]); - compensateForDelEdits(shifted + sh[0], sh[1]); - shifted -= sh[1]; - } - } - return shiftrecord.getInverse(); - } - return null; - } - - /** - * removes intersection of position,length ranges in deletions from the - * start,end regions marked in intervals. - * - * @param shifts - * @param intervals - * @return - */ - private boolean pruneIntervalVector(final List shifts, - Vector intervals) - { - boolean pruned = false; - int i = 0, j = intervals.size() - 1, s = 0, t = shifts.size() - 1; - int hr[] = intervals.elementAt(i); - int sr[] = shifts.get(s); - while (i <= j && s <= t) - { - boolean trailinghn = hr[1] >= sr[0]; - if (!trailinghn) - { - if (i < j) - { - hr = intervals.elementAt(++i); - } - else - { - i++; - } - continue; - } - int endshift = sr[0] + sr[1]; // deletion ranges - -ve means an insert - if (endshift < hr[0] || endshift < sr[0]) - { // leadinghc disjoint or not a deletion - if (s < t) - { - sr = shifts.get(++s); - } - else - { - s++; - } - continue; - } - boolean leadinghn = hr[0] >= sr[0]; - boolean leadinghc = hr[0] < endshift; - boolean trailinghc = hr[1] < endshift; - if (leadinghn) - { - if (trailinghc) - { // deleted hidden region. - intervals.removeElementAt(i); - pruned = true; - j--; - if (i <= j) - { - hr = intervals.elementAt(i); - } - continue; - } - if (leadinghc) - { - hr[0] = endshift; // clip c terminal region - leadinghn = !leadinghn; - pruned = true; - } - } - if (!leadinghn) - { - if (trailinghc) - { - if (trailinghn) - { - hr[1] = sr[0] - 1; - pruned = true; - } - } - else - { - // sr contained in hr - if (s < t) - { - sr = shifts.get(++s); - } - else - { - s++; - } - continue; - } - } - } - return pruned; // true if any interval was removed or modified by - // operations. - } - - /** - * remove any hiddenColumns or selected columns and shift remaining based on a - * series of position, range deletions. - * - * @param deletions - */ - public void pruneDeletions(ShiftList deletions) - { - if (deletions != null) - { - final List shifts = deletions.getShifts(); - if (shifts != null && shifts.size() > 0) - { - // delete any intervals intersecting. - if (hiddenColumns != null) - { - pruneIntervalVector(shifts, hiddenColumns); - if (hiddenColumns != null && hiddenColumns.size() == 0) - { - hiddenColumns = null; - } - } - if (selection != null && selection.size() > 0) - { - selection.pruneColumnList(shifts); - if (selection != null && selection.size() == 0) - { - selection = null; - } - } - // and shift the rest. - this.compensateForEdits(deletions); - } - } - } - - /** - * This Method is used to return all the HiddenColumn regions - * - * @return empty list or List of hidden column intervals - */ - public List getHiddenColumns() - { - return hiddenColumns == null ? Collections. emptyList() - : hiddenColumns; - } - - /** - * Return absolute column index for a visible column index - * - * @param column - * int column index in alignment view (count from zero) - * @return alignment column index for column - */ - public int adjustForHiddenColumns(int column) - { - int result = column; - if (hiddenColumns != null) - { - for (int i = 0; i < hiddenColumns.size(); i++) - { - int[] region = hiddenColumns.elementAt(i); - if (result >= region[0]) - { - result += region[1] - region[0] + 1; - } - } - } - return result; - } - - /** - * Use this method to find out where a column will appear in the visible - * alignment when hidden columns exist. If the column is not visible, then the - * left-most visible column will always be returned. - * - * @param hiddenColumn - * the column index in the full alignment including hidden columns - * @return the position of the column in the visible alignment - */ - public int findColumnPosition(int hiddenColumn) - { - int result = hiddenColumn; - if (hiddenColumns != null) - { - int index = 0; - int[] region; - do - { - region = hiddenColumns.elementAt(index++); - if (hiddenColumn > region[1]) - { - result -= region[1] + 1 - region[0]; - } - } while ((hiddenColumn > region[1]) && (index < hiddenColumns.size())); - - if (hiddenColumn >= region[0] && hiddenColumn <= region[1]) - { - // Here the hidden column is within a region, so - // we want to return the position of region[0]-1, adjusted for any - // earlier hidden columns. - // Calculate the difference between the actual hidden col position - // and region[0]-1, and then subtract from result to convert result from - // the adjusted hiddenColumn value to the adjusted region[0]-1 value - - // However, if the region begins at 0 we cannot return region[0]-1 - // just return 0 - if (region[0] == 0) - { - return 0; - } - else - { - return result - (hiddenColumn - region[0] + 1); - } - } - } - return result; // return the shifted position after removing hidden columns. - } - - /** - * Find the visible column which is a given visible number of columns to the - * left of another visible column. i.e. for a startColumn x, the column which - * is distance 1 away will be column x-1. - * - * @param visibleDistance - * the number of visible columns to offset by - * @param startColumn - * the column to start from - * @return the position of the column in the visible alignment - */ - public int subtractVisibleColumns(int visibleDistance, int startColumn) - { - int distance = visibleDistance; - - // in case startColumn is in a hidden region, move it to the left - int start = adjustForHiddenColumns(findColumnPosition(startColumn)); - - // get index of hidden region to left of start - int index = getHiddenIndexLeft(start); - if (index == -1) - { - // no hidden regions to left of startColumn - return start - distance; - } - - // walk backwards through the alignment subtracting the counts of visible - // columns from distance - int[] region; - int gap = 0; - int nextstart = start; - - while ((index > -1) && (distance - gap > 0)) - { - // subtract the gap to right of region from distance - distance -= gap; - start = nextstart; - - // calculate the next gap - region = hiddenColumns.get(index); - gap = start - region[1]; - - // set start to just to left of current region - nextstart = region[0] - 1; - index--; - } - - if (distance - gap > 0) - { - // fell out of loop because there are no more hidden regions - distance -= gap; - return nextstart - distance; - } - return start - distance; - - } - - /** - * Use this method to determine where the next hiddenRegion starts - * - * @param hiddenRegion - * index of hidden region (counts from 0) - * @return column number in visible view - */ - public int findHiddenRegionPosition(int hiddenRegion) - { - int result = 0; - if (hiddenColumns != null) - { - int index = 0; - int gaps = 0; - do - { - int[] region = hiddenColumns.elementAt(index); - if (hiddenRegion == 0) - { - return region[0]; - } - - gaps += region[1] + 1 - region[0]; - result = region[1] + 1; - index++; - } while (index <= hiddenRegion); - - result -= gaps; - } - - return result; - } - - /** - * THis method returns the rightmost limit of a region of an alignment with - * hidden columns. In otherwords, the next hidden column. - * - * @param index - * int - */ - public int getHiddenBoundaryRight(int alPos) - { - if (hiddenColumns != null) - { - int index = 0; - do - { - int[] region = hiddenColumns.elementAt(index); - if (alPos < region[0]) - { - return region[0]; - } - - index++; - } while (index < hiddenColumns.size()); - } - - return alPos; - - } - - /** - * This method returns the leftmost limit of a region of an alignment with - * hidden columns. In otherwords, the previous hidden column. - * - * @param index - * int - */ - public int getHiddenBoundaryLeft(int alPos) - { - if (hiddenColumns != null) - { - int index = hiddenColumns.size() - 1; - do - { - int[] region = hiddenColumns.elementAt(index); - if (alPos > region[1]) - { - return region[1]; - } - - index--; - } while (index > -1); - } - - return alPos; - - } - - /** - * This method returns the index of the hidden region to the left of a column - * position. If the column is in a hidden region it returns the index of the - * region to the left. If there is no hidden region to the left it returns -1. - * - * @param pos - * int - */ - private int getHiddenIndexLeft(int pos) - { - if (hiddenColumns != null) - { - int index = hiddenColumns.size() - 1; - do - { - int[] region = hiddenColumns.elementAt(index); - if (pos > region[1]) - { - return index; - } - - index--; - } while (index > -1); - } - - return -1; - - } - - public void hideSelectedColumns() - { - synchronized (selection) - { - for (int[] selregions : selection.getRanges()) - { - hideColumns(selregions[0], selregions[1]); - } - selection.clear(); - } - - } - - /** - * Adds the specified column range to the hidden columns - * - * @param start - * @param end - */ - public void hideColumns(int start, int end) - { - if (hiddenColumns == null) - { - hiddenColumns = new Vector(); - } - - /* - * traverse existing hidden ranges and insert / amend / append as - * appropriate - */ - for (int i = 0; i < hiddenColumns.size(); i++) - { - int[] region = hiddenColumns.elementAt(i); - - if (end < region[0] - 1) - { - /* - * insert discontiguous preceding range - */ - hiddenColumns.insertElementAt(new int[] { start, end }, i); - return; - } - - if (end <= region[1]) - { - /* - * new range overlaps existing, or is contiguous preceding it - adjust - * start column - */ - region[0] = Math.min(region[0], start); - return; - } - - if (start <= region[1] + 1) - { - /* - * new range overlaps existing, or is contiguous following it - adjust - * start and end columns - */ - region[0] = Math.min(region[0], start); - region[1] = Math.max(region[1], end); - - /* - * also update or remove any subsequent ranges - * that are overlapped - */ - while (i < hiddenColumns.size() - 1) - { - int[] nextRegion = hiddenColumns.get(i + 1); - if (nextRegion[0] > end + 1) - { - /* - * gap to next hidden range - no more to update - */ - break; - } - region[1] = Math.max(nextRegion[1], end); - hiddenColumns.remove(i + 1); - } - return; - } - } - - /* - * remaining case is that the new range follows everything else - */ - hiddenColumns.addElement(new int[] { start, end }); - } - - /** - * Hides the specified column and any adjacent selected columns - * - * @param res - * int - */ - public void hideColumns(int col) - { - /* - * deselect column (whether selected or not!) - */ - removeElement(col); - - /* - * find adjacent selected columns - */ - int min = col - 1, max = col + 1; - while (contains(min)) - { - removeElement(min); - min--; - } - - while (contains(max)) - { - removeElement(max); - max++; - } - - /* - * min, max are now the closest unselected columns - */ - min++; - max--; - if (min > max) - { - min = max; - } - - hideColumns(min, max); - } - - /** - * Unhides, and adds to the selection list, all hidden columns - */ - public void revealAllHiddenColumns() - { - if (hiddenColumns != null) - { - for (int i = 0; i < hiddenColumns.size(); i++) - { - int[] region = hiddenColumns.elementAt(i); - for (int j = region[0]; j < region[1] + 1; j++) - { - addElement(j); - } - } - } - - hiddenColumns = null; - } - - /** - * Reveals, and marks as selected, the hidden column range with the given - * start column - * - * @param start - */ - public void revealHiddenColumns(int start) - { - for (int i = 0; i < hiddenColumns.size(); i++) - { - int[] region = hiddenColumns.elementAt(i); - if (start == region[0]) - { - for (int j = region[0]; j < region[1] + 1; j++) - { - addElement(j); - } - - hiddenColumns.removeElement(region); - break; - } - } - if (hiddenColumns.size() == 0) - { - hiddenColumns = null; - } - } - - public boolean isVisible(int column) - { - if (hiddenColumns != null) - { - for (int[] region : hiddenColumns) - { - if (column >= region[0] && column <= region[1]) - { - return false; - } - } - } - - return true; - } - - /** - * Copy constructor - * - * @param copy - */ - public ColumnSelection(ColumnSelection copy) - { - if (copy != null) - { - selection = new IntList(copy.selection); - if (copy.hiddenColumns != null) - { - hiddenColumns = new Vector(copy.hiddenColumns.size()); - for (int i = 0, j = copy.hiddenColumns.size(); i < j; i++) - { - int[] rh, cp; - rh = copy.hiddenColumns.elementAt(i); - if (rh != null) - { - cp = new int[rh.length]; - System.arraycopy(rh, 0, cp, 0, rh.length); - hiddenColumns.addElement(cp); - } - } - } - } - } - - /** - * ColumnSelection + * + * @param col + * index to search for in column selection + * + * @return true if col is selected */ - public ColumnSelection() + public boolean contains(int col) { + return (col > -1) ? selection.isSelected(col) : false; } - public String[] getVisibleSequenceStrings(int start, int end, - SequenceI[] seqs) + /** + * Answers true if no columns are selected, else false + */ + public boolean isEmpty() { - int i, iSize = seqs.length; - String selections[] = new String[iSize]; - if (hiddenColumns != null && hiddenColumns.size() > 0) - { - for (i = 0; i < iSize; i++) - { - StringBuffer visibleSeq = new StringBuffer(); - List regions = getHiddenColumns(); - - int blockStart = start, blockEnd = end; - int[] region; - int hideStart, hideEnd; - - for (int j = 0; j < regions.size(); j++) - { - region = regions.get(j); - hideStart = region[0]; - hideEnd = region[1]; - - if (hideStart < start) - { - continue; - } - - blockStart = Math.min(blockStart, hideEnd + 1); - blockEnd = Math.min(blockEnd, hideStart); - - if (blockStart > blockEnd) - { - break; - } - - visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd)); - - blockStart = hideEnd + 1; - blockEnd = end; - } - - if (end > blockStart) - { - visibleSeq.append(seqs[i].getSequence(blockStart, end)); - } + return selection == null || selection.isEmpty(); + } - selections[i] = visibleSeq.toString(); - } - } - else + /** + * rightmost selected column + * + * @return rightmost column in alignment that is selected + */ + public int getMax() + { + if (selection.isEmpty()) { - for (i = 0; i < iSize; i++) - { - selections[i] = seqs[i].getSequenceAsString(start, end); - } + return -1; } - - return selections; + return selection.getMaxColumn(); } /** - * return all visible segments between the given start and end boundaries + * Leftmost column in selection * - * @param start - * (first column inclusive from 0) - * @param end - * (last column - not inclusive) - * @return int[] {i_start, i_end, ..} where intervals lie in - * start<=i_start<=i_end 0) + if (selection.isEmpty()) { - List visiblecontigs = new ArrayList(); - List regions = getHiddenColumns(); - - int vstart = start; - int[] region; - int hideStart, hideEnd; - - for (int j = 0; vstart < end && j < regions.size(); j++) - { - region = regions.get(j); - hideStart = region[0]; - hideEnd = region[1]; - - if (hideEnd < vstart) - { - continue; - } - if (hideStart > vstart) - { - visiblecontigs.add(new int[] { vstart, hideStart - 1 }); - } - vstart = hideEnd + 1; - } + return 1000000000; + } + return selection.getMinColumn(); + } - if (vstart < end) - { - visiblecontigs.add(new int[] { vstart, end - 1 }); - } - int[] vcontigs = new int[visiblecontigs.size() * 2]; - for (int i = 0, j = visiblecontigs.size(); i < j; i++) + public void hideSelectedColumns(AlignmentI al) + { + synchronized (selection) + { + for (int[] selregions : selection.getRanges()) { - int[] vc = visiblecontigs.get(i); - visiblecontigs.set(i, null); - vcontigs[i * 2] = vc[0]; - vcontigs[i * 2 + 1] = vc[1]; + al.getHiddenColumns().hideColumns(selregions[0], selregions[1]); } - visiblecontigs.clear(); - return vcontigs; - } - else - { - return new int[] { start, end - 1 }; + selection.clear(); } + } + /** - * Locate the first and last position visible for this sequence. if seq isn't - * visible then return the position of the left and right of the hidden - * boundary region, and the corresponding alignment column indices for the - * extent of the sequence + * Hides the specified column and any adjacent selected columns * - * @param seq - * @return int[] { visible start, visible end, first seqpos, last seqpos, - * alignment index for seq start, alignment index for seq end } + * @param res + * int */ - public int[] locateVisibleBoundsOfSequence(SequenceI seq) + public void hideSelectedColumns(int col, HiddenColumns hidden) { - int fpos = seq.getStart(), lpos = seq.getEnd(); - int start = 0; + /* + * deselect column (whether selected or not!) + */ + removeElement(col); - if (hiddenColumns == null || hiddenColumns.size() == 0) + /* + * find adjacent selected columns + */ + int min = col - 1, max = col + 1; + while (contains(min)) { - int ifpos = seq.findIndex(fpos) - 1, ilpos = seq.findIndex(lpos) - 1; - return new int[] { ifpos, ilpos, fpos, lpos, ifpos, ilpos }; + removeElement(min); + min--; } - // Simply walk along the sequence whilst watching for hidden column - // boundaries - List regions = getHiddenColumns(); - int spos = fpos, lastvispos = -1, rcount = 0, hideStart = seq - .getLength(), hideEnd = -1; - int visPrev = 0, visNext = 0, firstP = -1, lastP = -1; - boolean foundStart = false; - for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd() - && p < pLen; p++) + while (contains(max)) { - if (!Comparison.isGap(seq.getCharAt(p))) - { - // keep track of first/last column - // containing sequence data regardless of visibility - if (firstP == -1) - { - firstP = p; - } - lastP = p; - // update hidden region start/end - while (hideEnd < p && rcount < regions.size()) - { - int[] region = regions.get(rcount++); - visPrev = visNext; - visNext += region[0] - visPrev; - hideStart = region[0]; - hideEnd = region[1]; - } - if (hideEnd < p) - { - hideStart = seq.getLength(); - } - // update visible boundary for sequence - if (p < hideStart) - { - if (!foundStart) - { - fpos = spos; - start = p; - foundStart = true; - } - lastvispos = p; - lpos = spos; - } - // look for next sequence position - spos++; - } + removeElement(max); + max++; } - if (foundStart) + + /* + * min, max are now the closest unselected columns + */ + min++; + max--; + if (min > max) { - return new int[] { findColumnPosition(start), - findColumnPosition(lastvispos), fpos, lpos, firstP, lastP }; + min = max; } - // otherwise, sequence was completely hidden - return new int[] { visPrev, visNext, 0, 0, firstP, lastP }; + + hidden.hideColumns(min, max); } + + + + /** - * delete any columns in alignmentAnnotation that are hidden (including - * sequence associated annotation). + * Copy constructor * - * @param alignmentAnnotation + * @param copy */ - public void makeVisibleAnnotation(AlignmentAnnotation alignmentAnnotation) + public ColumnSelection(ColumnSelection copy) { - makeVisibleAnnotation(-1, -1, alignmentAnnotation); + if (copy != null) + { + selection = new IntList(copy.selection); + } } /** - * delete any columns in alignmentAnnotation that are hidden (including - * sequence associated annotation). - * - * @param start - * remove any annotation to the right of this column - * @param end - * remove any annotation to the left of this column - * @param alignmentAnnotation - * the annotation to operate on + * ColumnSelection */ - public void makeVisibleAnnotation(int start, int end, - AlignmentAnnotation alignmentAnnotation) + public ColumnSelection() { - if (alignmentAnnotation.annotations == null) - { - return; - } - if (start == end && end == -1) - { - start = 0; - end = alignmentAnnotation.annotations.length; - } - if (hiddenColumns != null && hiddenColumns.size() > 0) - { - // then mangle the alignmentAnnotation annotation array - Vector annels = new Vector(); - Annotation[] els = null; - List regions = getHiddenColumns(); - int blockStart = start, blockEnd = end; - int[] region; - int hideStart, hideEnd, w = 0; - - for (int j = 0; j < regions.size(); j++) - { - region = regions.get(j); - hideStart = region[0]; - hideEnd = region[1]; - - if (hideStart < start) - { - continue; - } - - blockStart = Math.min(blockStart, hideEnd + 1); - blockEnd = Math.min(blockEnd, hideStart); + } - if (blockStart > blockEnd) - { - break; - } - annels.addElement(els = new Annotation[blockEnd - blockStart]); - System.arraycopy(alignmentAnnotation.annotations, blockStart, els, - 0, els.length); - w += els.length; - blockStart = hideEnd + 1; - blockEnd = end; - } - if (end > blockStart) - { - annels.addElement(els = new Annotation[end - blockStart + 1]); - if ((els.length + blockStart) <= alignmentAnnotation.annotations.length) - { - // copy just the visible segment of the annotation row - System.arraycopy(alignmentAnnotation.annotations, blockStart, - els, 0, els.length); - } - else - { - // copy to the end of the annotation row - System.arraycopy(alignmentAnnotation.annotations, blockStart, - els, 0, - (alignmentAnnotation.annotations.length - blockStart)); - } - w += els.length; - } - if (w == 0) - { - return; - } - alignmentAnnotation.annotations = new Annotation[w]; - w = 0; - for (Annotation[] chnk : annels) - { - System.arraycopy(chnk, 0, alignmentAnnotation.annotations, w, - chnk.length); - w += chnk.length; - } - } - else - { - alignmentAnnotation.restrict(start, end); - } - } /** * Invert the column selection from first to end-1. leaves hiddenColumns @@ -1452,9 +480,9 @@ public class ColumnSelection * @param first * @param end */ - public void invertColumnSelection(int first, int width) + public void invertColumnSelection(int first, int width, AlignmentI al) { - boolean hasHidden = hiddenColumns != null && hiddenColumns.size() > 0; + boolean hasHidden = al.getHiddenColumns().hasHidden(); for (int i = first; i < width; i++) { if (contains(i)) @@ -1463,7 +491,7 @@ public class ColumnSelection } else { - if (!hasHidden || isVisible(i)) + if (!hasHidden || al.getHiddenColumns().isVisible(i)) { addElement(i); } @@ -1472,195 +500,41 @@ public class ColumnSelection } /** - * add in any unselected columns from the given column selection, excluding - * any that are hidden. - * - * @param colsel - */ - public void addElementsFrom(ColumnSelection colsel) - { - if (colsel != null && !colsel.isEmpty()) - { - for (Integer col : colsel.getSelected()) - { - if (hiddenColumns != null && isVisible(col.intValue())) - { - selection.add(col); - } - } - } - } - - /** - * set the selected columns the given column selection, excluding any columns - * that are hidden. + * set the selected columns to the given column selection, excluding any + * columns that are hidden. * * @param colsel */ - public void setElementsFrom(ColumnSelection colsel) + public void setElementsFrom(ColumnSelection colsel, + HiddenColumns hiddenColumns) { selection = new IntList(); if (colsel.selection != null && colsel.selection.size() > 0) { - if (hiddenColumns != null && hiddenColumns.size() > 0) + if (hiddenColumns.hasHidden()) { // only select visible columns in this columns selection - addElementsFrom(colsel); - } - else - { - // add everything regardless for (Integer col : colsel.getSelected()) { - addElement(col); - } - } - } - } - - /** - * Add gaps into the sequences aligned to profileseq under the given - * AlignmentView - * - * @param profileseq - * @param al - * - alignment to have gaps inserted into it - * @param input - * - alignment view where sequence corresponding to profileseq is - * first entry - * @return new Column selection for new alignment view, with insertions into - * profileseq marked as hidden. - */ - public static ColumnSelection propagateInsertions(SequenceI profileseq, - AlignmentI al, AlignmentView input) - { - int profsqpos = 0; - - // return propagateInsertions(profileseq, al, ) - char gc = al.getGapCharacter(); - Object[] alandcolsel = input.getAlignmentAndColumnSelection(gc); - ColumnSelection nview = (ColumnSelection) alandcolsel[1]; - SequenceI origseq = ((SequenceI[]) alandcolsel[0])[profsqpos]; - nview.propagateInsertions(profileseq, al, origseq); - return nview; - } - - /** - * - * @param profileseq - * - sequence in al which corresponds to origseq - * @param al - * - alignment which is to have gaps inserted into it - * @param origseq - * - sequence corresponding to profileseq which defines gap map for - * modifying al - */ - public void propagateInsertions(SequenceI profileseq, AlignmentI al, - SequenceI origseq) - { - char gc = al.getGapCharacter(); - // recover mapping between sequence's non-gap positions and positions - // mapping to view. - pruneDeletions(ShiftList.parseMap(origseq.gapMap())); - int[] viscontigs = getVisibleContigs(0, profileseq.getLength()); - int spos = 0; - int offset = 0; - // input.pruneDeletions(ShiftList.parseMap(((SequenceI[]) - // alandcolsel[0])[0].gapMap())) - // add profile to visible contigs - for (int v = 0; v < viscontigs.length; v += 2) - { - if (viscontigs[v] > spos) - { - StringBuffer sb = new StringBuffer(); - for (int s = 0, ns = viscontigs[v] - spos; s < ns; s++) - { - sb.append(gc); - } - for (int s = 0, ns = al.getHeight(); s < ns; s++) - { - SequenceI sqobj = al.getSequenceAt(s); - if (sqobj != profileseq) + if (hiddenColumns != null + && hiddenColumns.isVisible(col.intValue())) { - String sq = al.getSequenceAt(s).getSequenceAsString(); - if (sq.length() <= spos + offset) - { - // pad sequence - int diff = spos + offset - sq.length() - 1; - if (diff > 0) - { - // pad gaps - sq = sq + sb; - while ((diff = spos + offset - sq.length() - 1) > 0) - { - // sq = sq - // + ((diff >= sb.length()) ? sb.toString() : sb - // .substring(0, diff)); - if (diff >= sb.length()) - { - sq += sb.toString(); - } - else - { - char[] buf = new char[diff]; - sb.getChars(0, diff, buf, 0); - sq += buf.toString(); - } - } - } - sq += sb.toString(); - } - else - { - al.getSequenceAt(s).setSequence( - sq.substring(0, spos + offset) + sb.toString() - + sq.substring(spos + offset)); - } + selection.add(col); } } - // offset+=sb.length(); - } - spos = viscontigs[v + 1] + 1; - } - if ((offset + spos) < profileseq.getLength()) - { - // pad the final region with gaps. - StringBuffer sb = new StringBuffer(); - for (int s = 0, ns = profileseq.getLength() - spos - offset; s < ns; s++) - { - sb.append(gc); } - for (int s = 0, ns = al.getHeight(); s < ns; s++) + else { - SequenceI sqobj = al.getSequenceAt(s); - if (sqobj == profileseq) - { - continue; - } - String sq = sqobj.getSequenceAsString(); - // pad sequence - int diff = origseq.getLength() - sq.length(); - while (diff > 0) + // add everything regardless + for (Integer col : colsel.getSelected()) { - // sq = sq - // + ((diff >= sb.length()) ? sb.toString() : sb - // .substring(0, diff)); - if (diff >= sb.length()) - { - sq += sb.toString(); - } - else - { - char[] buf = new char[diff]; - sb.getChars(0, diff, buf, 0); - sq += buf.toString(); - } - diff = origseq.getLength() - sq.length(); + addElement(col); } } } } + /** * * @return true if there are columns marked @@ -1670,45 +544,13 @@ public class ColumnSelection return (selection != null && selection.size() > 0); } - /** - * - * @return true if there are columns hidden - */ - public boolean hasHiddenColumns() - { - return hiddenColumns != null && hiddenColumns.size() > 0; - } - - /** - * - * @return true if there are more than one set of columns hidden - */ - public boolean hasManyHiddenColumns() - { - return hiddenColumns != null && hiddenColumns.size() > 1; - } - /** - * mark the columns corresponding to gap characters as hidden in the column - * selection - * - * @param sr - */ - public void hideInsertionsFor(SequenceI sr) - { - List inserts = sr.getInsertions(); - for (int[] r : inserts) - { - hideColumns(r[0], r[1]); - } - } public boolean filterAnnotations(Annotation[] annotations, AnnotationFilterParameter filterParams) { // JBPNote - this method needs to be refactored to become independent of // viewmodel package - this.revealAllHiddenColumns(); this.clear(); int count = 0; do @@ -1791,21 +633,12 @@ public class ColumnSelection } /** - * Returns a hashCode built from selected columns and hidden column ranges + * Returns a hashCode built from selected columns ranges */ @Override public int hashCode() { - int hashCode = selection.hashCode(); - if (hiddenColumns != null) - { - for (int[] hidden : hiddenColumns) - { - hashCode = 31 * hashCode + hidden[0]; - hashCode = 31 * hashCode + hidden[1]; - } - } - return hashCode; + return selection.hashCode(); } /** @@ -1836,27 +669,6 @@ public class ColumnSelection return false; } - /* - * check hidden columns are either both null, or match - */ - if (this.hiddenColumns == null) - { - return (that.hiddenColumns == null); - } - if (that.hiddenColumns == null - || that.hiddenColumns.size() != this.hiddenColumns.size()) - { - return false; - } - int i = 0; - for (int[] thisRange : hiddenColumns) - { - int[] thatRange = that.hiddenColumns.get(i++); - if (thisRange[0] != thatRange[0] || thisRange[1] != thatRange[1]) - { - return false; - } - } return true; } diff --git a/src/jalview/datamodel/HiddenColumns.java b/src/jalview/datamodel/HiddenColumns.java new file mode 100644 index 0000000..2edb3f1 --- /dev/null +++ b/src/jalview/datamodel/HiddenColumns.java @@ -0,0 +1,1264 @@ +package jalview.datamodel; + +import jalview.util.Comparison; +import jalview.util.ShiftList; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Vector; + +public class HiddenColumns +{ + /* + * list of hidden column [start, end] ranges; the list is maintained in + * ascending start column order + */ + private Vector hiddenColumns; + + /** + * This Method is used to return all the HiddenColumn regions + * + * @return empty list or List of hidden column intervals + */ + public List getHiddenRegions() + { + return hiddenColumns == null ? Collections. emptyList() + : hiddenColumns; + } + + /** + * Find the number of hidden columns + * + * @return number of hidden columns + */ + public int getSize() + { + int size = 0; + if (hasHidden()) + { + for (int[] range : hiddenColumns) + { + size += range[1] - range[0] + 1; + } + } + return size; + } + + /** + * Answers if there are any hidden columns + * + * @return true if there are hidden columns + */ + public boolean hasHidden() + { + return (hiddenColumns != null) && (!hiddenColumns.isEmpty()); + } + + @Override + public boolean equals(Object obj) + { + if (!(obj instanceof HiddenColumns)) + { + return false; + } + HiddenColumns that = (HiddenColumns) obj; + + /* + * check hidden columns are either both null, or match + */ + if (this.hiddenColumns == null) + { + return (that.hiddenColumns == null); + } + if (that.hiddenColumns == null + || that.hiddenColumns.size() != this.hiddenColumns.size()) + { + return false; + } + int i = 0; + for (int[] thisRange : hiddenColumns) + { + int[] thatRange = that.hiddenColumns.get(i++); + if (thisRange[0] != thatRange[0] || thisRange[1] != thatRange[1]) + { + return false; + } + } + return true; + } + + /** + * Return absolute column index for a visible column index + * + * @param column + * int column index in alignment view (count from zero) + * @return alignment column index for column + */ + public int adjustForHiddenColumns(int column) + { + int result = column; + if (hiddenColumns != null) + { + for (int i = 0; i < hiddenColumns.size(); i++) + { + int[] region = hiddenColumns.elementAt(i); + if (result >= region[0]) + { + result += region[1] - region[0] + 1; + } + } + } + return result; + } + + /** + * Use this method to find out where a column will appear in the visible + * alignment when hidden columns exist. If the column is not visible, then the + * left-most visible column will always be returned. + * + * @param hiddenColumn + * the column index in the full alignment including hidden columns + * @return the position of the column in the visible alignment + */ + public int findColumnPosition(int hiddenColumn) + { + int result = hiddenColumn; + if (hiddenColumns != null) + { + int index = 0; + int[] region; + do + { + region = hiddenColumns.elementAt(index++); + if (hiddenColumn > region[1]) + { + result -= region[1] + 1 - region[0]; + } + } while ((hiddenColumn > region[1]) && (index < hiddenColumns.size())); + + if (hiddenColumn >= region[0] && hiddenColumn <= region[1]) + { + // Here the hidden column is within a region, so + // we want to return the position of region[0]-1, adjusted for any + // earlier hidden columns. + // Calculate the difference between the actual hidden col position + // and region[0]-1, and then subtract from result to convert result from + // the adjusted hiddenColumn value to the adjusted region[0]-1 value + + // However, if the region begins at 0 we cannot return region[0]-1 + // just return 0 + if (region[0] == 0) + { + return 0; + } + else + { + return result - (hiddenColumn - region[0] + 1); + } + } + } + return result; // return the shifted position after removing hidden columns. + } + + /** + * Find the visible column which is a given visible number of columns to the + * left of another visible column. i.e. for a startColumn x, the column which + * is distance 1 away will be column x-1. + * + * @param visibleDistance + * the number of visible columns to offset by + * @param startColumn + * the column to start from + * @return the position of the column in the visible alignment + */ + public int subtractVisibleColumns(int visibleDistance, int startColumn) + { + int distance = visibleDistance; + + // in case startColumn is in a hidden region, move it to the left + int start = adjustForHiddenColumns(findColumnPosition(startColumn)); + + // get index of hidden region to left of start + int index = getHiddenIndexLeft(start); + if (index == -1) + { + // no hidden regions to left of startColumn + return start - distance; + } + + // walk backwards through the alignment subtracting the counts of visible + // columns from distance + int[] region; + int gap = 0; + int nextstart = start; + + while ((index > -1) && (distance - gap > 0)) + { + // subtract the gap to right of region from distance + distance -= gap; + start = nextstart; + + // calculate the next gap + region = hiddenColumns.get(index); + gap = start - region[1]; + + // set start to just to left of current region + nextstart = region[0] - 1; + index--; + } + + if (distance - gap > 0) + { + // fell out of loop because there are no more hidden regions + distance -= gap; + return nextstart - distance; + } + return start - distance; + + } + + /** + * Use this method to determine where the next hiddenRegion starts + * + * @param hiddenRegion + * index of hidden region (counts from 0) + * @return column number in visible view + */ + public int findHiddenRegionPosition(int hiddenRegion) + { + int result = 0; + if (hiddenColumns != null) + { + int index = 0; + int gaps = 0; + do + { + int[] region = hiddenColumns.elementAt(index); + if (hiddenRegion == 0) + { + return region[0]; + } + + gaps += region[1] + 1 - region[0]; + result = region[1] + 1; + index++; + } while (index <= hiddenRegion); + + result -= gaps; + } + + return result; + } + + /** + * This method returns the rightmost limit of a region of an alignment with + * hidden columns. In otherwords, the next hidden column. + * + * @param index + * int + */ + public int getHiddenBoundaryRight(int alPos) + { + if (hiddenColumns != null) + { + int index = 0; + do + { + int[] region = hiddenColumns.elementAt(index); + if (alPos < region[0]) + { + return region[0]; + } + + index++; + } while (index < hiddenColumns.size()); + } + + return alPos; + + } + + /** + * This method returns the leftmost limit of a region of an alignment with + * hidden columns. In otherwords, the previous hidden column. + * + * @param index + * int + */ + public int getHiddenBoundaryLeft(int alPos) + { + if (hiddenColumns != null) + { + int index = hiddenColumns.size() - 1; + do + { + int[] region = hiddenColumns.elementAt(index); + if (alPos > region[1]) + { + return region[1]; + } + + index--; + } while (index > -1); + } + + return alPos; + + } + + /** + * This method returns the index of the hidden region to the left of a column + * position. If the column is in a hidden region it returns the index of the + * region to the left. If there is no hidden region to the left it returns -1. + * + * @param pos + * int + */ + private int getHiddenIndexLeft(int pos) + { + if (hiddenColumns != null) + { + int index = hiddenColumns.size() - 1; + do + { + int[] region = hiddenColumns.elementAt(index); + if (pos > region[1]) + { + return index; + } + + index--; + } while (index > -1); + } + + return -1; + + } + + /** + * Adds the specified column range to the hidden columns + * + * @param start + * @param end + */ + public void hideColumns(int start, int end) + { + if (hiddenColumns == null) + { + hiddenColumns = new Vector(); + } + + /* + * traverse existing hidden ranges and insert / amend / append as + * appropriate + */ + for (int i = 0; i < hiddenColumns.size(); i++) + { + int[] region = hiddenColumns.elementAt(i); + + if (end < region[0] - 1) + { + /* + * insert discontiguous preceding range + */ + hiddenColumns.insertElementAt(new int[] { start, end }, i); + return; + } + + if (end <= region[1]) + { + /* + * new range overlaps existing, or is contiguous preceding it - adjust + * start column + */ + region[0] = Math.min(region[0], start); + return; + } + + if (start <= region[1] + 1) + { + /* + * new range overlaps existing, or is contiguous following it - adjust + * start and end columns + */ + region[0] = Math.min(region[0], start); + region[1] = Math.max(region[1], end); + + /* + * also update or remove any subsequent ranges + * that are overlapped + */ + while (i < hiddenColumns.size() - 1) + { + int[] nextRegion = hiddenColumns.get(i + 1); + if (nextRegion[0] > end + 1) + { + /* + * gap to next hidden range - no more to update + */ + break; + } + region[1] = Math.max(nextRegion[1], end); + hiddenColumns.remove(i + 1); + } + return; + } + } + + /* + * remaining case is that the new range follows everything else + */ + hiddenColumns.addElement(new int[] { start, end }); + } + + public boolean isVisible(int column) + { + if (hiddenColumns != null) + { + for (int[] region : hiddenColumns) + { + if (column >= region[0] && column <= region[1]) + { + return false; + } + } + } + + return true; + } + + /** + * ColumnSelection + */ + public HiddenColumns() + { + } + + /** + * Copy constructor + * + * @param copy + */ + public HiddenColumns(HiddenColumns copy) + { + if (copy != null) + { + if (copy.hiddenColumns != null) + { + hiddenColumns = new Vector(copy.hiddenColumns.size()); + for (int i = 0, j = copy.hiddenColumns.size(); i < j; i++) + { + int[] rh, cp; + rh = copy.hiddenColumns.elementAt(i); + if (rh != null) + { + cp = new int[rh.length]; + System.arraycopy(rh, 0, cp, 0, rh.length); + hiddenColumns.addElement(cp); + } + } + } + } + } + + /** + * propagate shift in alignment columns to column selection + * + * @param start + * beginning of edit + * @param left + * shift in edit (+ve for removal, or -ve for inserts) + */ + public List compensateForEdit(int start, int change, + ColumnSelection sel) + { + List deletedHiddenColumns = null; + + if (hiddenColumns != null) + { + deletedHiddenColumns = new ArrayList(); + int hSize = hiddenColumns.size(); + for (int i = 0; i < hSize; i++) + { + int[] region = hiddenColumns.elementAt(i); + if (region[0] > start && start + change > region[1]) + { + deletedHiddenColumns.add(region); + + hiddenColumns.removeElementAt(i); + i--; + hSize--; + continue; + } + + if (region[0] > start) + { + region[0] -= change; + region[1] -= change; + } + + if (region[0] < 0) + { + region[0] = 0; + } + + } + + this.revealHiddenColumns(0, sel); + } + + return deletedHiddenColumns; + } + + /** + * propagate shift in alignment columns to column selection special version of + * compensateForEdit - allowing for edits within hidden regions + * + * @param start + * beginning of edit + * @param left + * shift in edit (+ve for removal, or -ve for inserts) + */ + public void compensateForDelEdits(int start, int change) + { + if (hiddenColumns != null) + { + for (int i = 0; i < hiddenColumns.size(); i++) + { + int[] region = hiddenColumns.elementAt(i); + if (region[0] >= start) + { + region[0] -= change; + } + if (region[1] >= start) + { + region[1] -= change; + } + if (region[1] < region[0]) + { + hiddenColumns.removeElementAt(i--); + } + + if (region[0] < 0) + { + region[0] = 0; + } + if (region[1] < 0) + { + region[1] = 0; + } + } + } + } + + /** + * return all visible segments between the given start and end boundaries + * + * @param start + * (first column inclusive from 0) + * @param end + * (last column - not inclusive) + * @return int[] {i_start, i_end, ..} where intervals lie in + * start<=i_start<=i_end 0) + { + List visiblecontigs = new ArrayList(); + List regions = getHiddenRegions(); + + int vstart = start; + int[] region; + int hideStart, hideEnd; + + for (int j = 0; vstart < end && j < regions.size(); j++) + { + region = regions.get(j); + hideStart = region[0]; + hideEnd = region[1]; + + if (hideEnd < vstart) + { + continue; + } + if (hideStart > vstart) + { + visiblecontigs.add(new int[] { vstart, hideStart - 1 }); + } + vstart = hideEnd + 1; + } + + if (vstart < end) + { + visiblecontigs.add(new int[] { vstart, end - 1 }); + } + int[] vcontigs = new int[visiblecontigs.size() * 2]; + for (int i = 0, j = visiblecontigs.size(); i < j; i++) + { + int[] vc = visiblecontigs.get(i); + visiblecontigs.set(i, null); + vcontigs[i * 2] = vc[0]; + vcontigs[i * 2 + 1] = vc[1]; + } + visiblecontigs.clear(); + return vcontigs; + } + else + { + return new int[] { start, end - 1 }; + } + } + + public String[] getVisibleSequenceStrings(int start, int end, + SequenceI[] seqs) + { + int i, iSize = seqs.length; + String selections[] = new String[iSize]; + if (hiddenColumns != null && hiddenColumns.size() > 0) + { + for (i = 0; i < iSize; i++) + { + StringBuffer visibleSeq = new StringBuffer(); + List regions = getHiddenRegions(); + + int blockStart = start, blockEnd = end; + int[] region; + int hideStart, hideEnd; + + for (int j = 0; j < regions.size(); j++) + { + region = regions.get(j); + hideStart = region[0]; + hideEnd = region[1]; + + if (hideStart < start) + { + continue; + } + + blockStart = Math.min(blockStart, hideEnd + 1); + blockEnd = Math.min(blockEnd, hideStart); + + if (blockStart > blockEnd) + { + break; + } + + visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd)); + + blockStart = hideEnd + 1; + blockEnd = end; + } + + if (end > blockStart) + { + visibleSeq.append(seqs[i].getSequence(blockStart, end)); + } + + selections[i] = visibleSeq.toString(); + } + } + else + { + for (i = 0; i < iSize; i++) + { + selections[i] = seqs[i].getSequenceAsString(start, end); + } + } + + return selections; + } + + /** + * Locate the first and last position visible for this sequence. if seq isn't + * visible then return the position of the left and right of the hidden + * boundary region, and the corresponding alignment column indices for the + * extent of the sequence + * + * @param seq + * @return int[] { visible start, visible end, first seqpos, last seqpos, + * alignment index for seq start, alignment index for seq end } + */ + public int[] locateVisibleBoundsOfSequence(SequenceI seq) + { + int fpos = seq.getStart(), lpos = seq.getEnd(); + int start = 0; + + if (hiddenColumns == null || hiddenColumns.size() == 0) + { + int ifpos = seq.findIndex(fpos) - 1, ilpos = seq.findIndex(lpos) - 1; + return new int[] { ifpos, ilpos, fpos, lpos, ifpos, ilpos }; + } + + // Simply walk along the sequence whilst watching for hidden column + // boundaries + List regions = getHiddenRegions(); + int spos = fpos, lastvispos = -1, rcount = 0, hideStart = seq + .getLength(), hideEnd = -1; + int visPrev = 0, visNext = 0, firstP = -1, lastP = -1; + boolean foundStart = false; + for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd() + && p < pLen; p++) + { + if (!Comparison.isGap(seq.getCharAt(p))) + { + // keep track of first/last column + // containing sequence data regardless of visibility + if (firstP == -1) + { + firstP = p; + } + lastP = p; + // update hidden region start/end + while (hideEnd < p && rcount < regions.size()) + { + int[] region = regions.get(rcount++); + visPrev = visNext; + visNext += region[0] - visPrev; + hideStart = region[0]; + hideEnd = region[1]; + } + if (hideEnd < p) + { + hideStart = seq.getLength(); + } + // update visible boundary for sequence + if (p < hideStart) + { + if (!foundStart) + { + fpos = spos; + start = p; + foundStart = true; + } + lastvispos = p; + lpos = spos; + } + // look for next sequence position + spos++; + } + } + if (foundStart) + { + return new int[] { findColumnPosition(start), + findColumnPosition(lastvispos), fpos, lpos, firstP, lastP }; + } + // otherwise, sequence was completely hidden + return new int[] { visPrev, visNext, 0, 0, firstP, lastP }; + } + + /** + * delete any columns in alignmentAnnotation that are hidden (including + * sequence associated annotation). + * + * @param alignmentAnnotation + */ + public void makeVisibleAnnotation(AlignmentAnnotation alignmentAnnotation) + { + makeVisibleAnnotation(-1, -1, alignmentAnnotation); + } + + /** + * delete any columns in alignmentAnnotation that are hidden (including + * sequence associated annotation). + * + * @param start + * remove any annotation to the right of this column + * @param end + * remove any annotation to the left of this column + * @param alignmentAnnotation + * the annotation to operate on + */ + public void makeVisibleAnnotation(int start, int end, + AlignmentAnnotation alignmentAnnotation) + { + if (alignmentAnnotation.annotations == null) + { + return; + } + if (start == end && end == -1) + { + start = 0; + end = alignmentAnnotation.annotations.length; + } + if (hiddenColumns != null && hiddenColumns.size() > 0) + { + // then mangle the alignmentAnnotation annotation array + Vector annels = new Vector(); + Annotation[] els = null; + List regions = getHiddenRegions(); + int blockStart = start, blockEnd = end; + int[] region; + int hideStart, hideEnd, w = 0; + + for (int j = 0; j < regions.size(); j++) + { + region = regions.get(j); + hideStart = region[0]; + hideEnd = region[1]; + + if (hideStart < start) + { + continue; + } + + blockStart = Math.min(blockStart, hideEnd + 1); + blockEnd = Math.min(blockEnd, hideStart); + + if (blockStart > blockEnd) + { + break; + } + + annels.addElement(els = new Annotation[blockEnd - blockStart]); + System.arraycopy(alignmentAnnotation.annotations, blockStart, els, + 0, els.length); + w += els.length; + blockStart = hideEnd + 1; + blockEnd = end; + } + + if (end > blockStart) + { + annels.addElement(els = new Annotation[end - blockStart + 1]); + if ((els.length + blockStart) <= alignmentAnnotation.annotations.length) + { + // copy just the visible segment of the annotation row + System.arraycopy(alignmentAnnotation.annotations, blockStart, + els, 0, els.length); + } + else + { + // copy to the end of the annotation row + System.arraycopy(alignmentAnnotation.annotations, blockStart, + els, 0, + (alignmentAnnotation.annotations.length - blockStart)); + } + w += els.length; + } + if (w == 0) + { + return; + } + + alignmentAnnotation.annotations = new Annotation[w]; + w = 0; + + for (Annotation[] chnk : annels) + { + System.arraycopy(chnk, 0, alignmentAnnotation.annotations, w, + chnk.length); + w += chnk.length; + } + } + else + { + alignmentAnnotation.restrict(start, end); + } + } + + /** + * + * @return true if there are columns hidden + */ + public boolean hasHiddenColumns() + { + return hiddenColumns != null && hiddenColumns.size() > 0; + } + + /** + * + * @return true if there are more than one set of columns hidden + */ + public boolean hasManyHiddenColumns() + { + return hiddenColumns != null && hiddenColumns.size() > 1; + } + + /** + * mark the columns corresponding to gap characters as hidden in the column + * selection + * + * @param sr + */ + public void hideInsertionsFor(SequenceI sr) + { + List inserts = sr.getInsertions(); + for (int[] r : inserts) + { + hideColumns(r[0], r[1]); + } + } + + /** + * Unhides, and adds to the selection list, all hidden columns + */ + public void revealAllHiddenColumns(ColumnSelection sel) + { + if (hiddenColumns != null) + { + for (int i = 0; i < hiddenColumns.size(); i++) + { + int[] region = hiddenColumns.elementAt(i); + for (int j = region[0]; j < region[1] + 1; j++) + { + sel.addElement(j); + } + } + } + + hiddenColumns = null; + } + + /** + * Reveals, and marks as selected, the hidden column range with the given + * start column + * + * @param start + */ + public void revealHiddenColumns(int start, ColumnSelection sel) + { + for (int i = 0; i < hiddenColumns.size(); i++) + { + int[] region = hiddenColumns.elementAt(i); + if (start == region[0]) + { + for (int j = region[0]; j < region[1] + 1; j++) + { + sel.addElement(j); + } + + hiddenColumns.removeElement(region); + break; + } + } + if (hiddenColumns.size() == 0) + { + hiddenColumns = null; + } + } + + /** + * removes intersection of position,length ranges in deletions from the + * start,end regions marked in intervals. + * + * @param shifts + * @param intervals + * @return + */ + private boolean pruneIntervalVector(final List shifts, + Vector intervals) + { + boolean pruned = false; + int i = 0, j = intervals.size() - 1, s = 0, t = shifts.size() - 1; + int hr[] = intervals.elementAt(i); + int sr[] = shifts.get(s); + while (i <= j && s <= t) + { + boolean trailinghn = hr[1] >= sr[0]; + if (!trailinghn) + { + if (i < j) + { + hr = intervals.elementAt(++i); + } + else + { + i++; + } + continue; + } + int endshift = sr[0] + sr[1]; // deletion ranges - -ve means an insert + if (endshift < hr[0] || endshift < sr[0]) + { // leadinghc disjoint or not a deletion + if (s < t) + { + sr = shifts.get(++s); + } + else + { + s++; + } + continue; + } + boolean leadinghn = hr[0] >= sr[0]; + boolean leadinghc = hr[0] < endshift; + boolean trailinghc = hr[1] < endshift; + if (leadinghn) + { + if (trailinghc) + { // deleted hidden region. + intervals.removeElementAt(i); + pruned = true; + j--; + if (i <= j) + { + hr = intervals.elementAt(i); + } + continue; + } + if (leadinghc) + { + hr[0] = endshift; // clip c terminal region + leadinghn = !leadinghn; + pruned = true; + } + } + if (!leadinghn) + { + if (trailinghc) + { + if (trailinghn) + { + hr[1] = sr[0] - 1; + pruned = true; + } + } + else + { + // sr contained in hr + if (s < t) + { + sr = shifts.get(++s); + } + else + { + s++; + } + continue; + } + } + } + return pruned; // true if any interval was removed or modified by + // operations. + } + + /** + * remove any hiddenColumns or selected columns and shift remaining based on a + * series of position, range deletions. + * + * @param deletions + */ + public void pruneDeletions(List shifts) + { + // delete any intervals intersecting. + if (hiddenColumns != null) + { + pruneIntervalVector(shifts, hiddenColumns); + if (hiddenColumns != null && hiddenColumns.size() == 0) + { + hiddenColumns = null; + } + } + } + + /** + * Add gaps into the sequences aligned to profileseq under the given + * AlignmentView + * + * @param profileseq + * @param al + * - alignment to have gaps inserted into it + * @param input + * - alignment view where sequence corresponding to profileseq is + * first entry + * @return new HiddenColumns for new alignment view, with insertions into + * profileseq marked as hidden. + */ + public static HiddenColumns propagateInsertions(SequenceI profileseq, + AlignmentI al, AlignmentView input) + { + int profsqpos = 0; + + char gc = al.getGapCharacter(); + Object[] alandhidden = input.getAlignmentAndHiddenColumns(gc); + HiddenColumns nview = (HiddenColumns) alandhidden[1]; + SequenceI origseq = ((SequenceI[]) alandhidden[0])[profsqpos]; + nview.propagateInsertions(profileseq, al, origseq); + return nview; + } + + /** + * + * @param profileseq + * - sequence in al which corresponds to origseq + * @param al + * - alignment which is to have gaps inserted into it + * @param origseq + * - sequence corresponding to profileseq which defines gap map for + * modifying al + */ + private void propagateInsertions(SequenceI profileseq, AlignmentI al, + SequenceI origseq) + { + char gc = al.getGapCharacter(); + // recover mapping between sequence's non-gap positions and positions + // mapping to view. + pruneDeletions(ShiftList.parseMap(origseq.gapMap())); + int[] viscontigs = al.getHiddenColumns().getVisibleContigs(0, + profileseq.getLength()); + int spos = 0; + int offset = 0; + + // add profile to visible contigs + for (int v = 0; v < viscontigs.length; v += 2) + { + if (viscontigs[v] > spos) + { + StringBuffer sb = new StringBuffer(); + for (int s = 0, ns = viscontigs[v] - spos; s < ns; s++) + { + sb.append(gc); + } + for (int s = 0, ns = al.getHeight(); s < ns; s++) + { + SequenceI sqobj = al.getSequenceAt(s); + if (sqobj != profileseq) + { + String sq = al.getSequenceAt(s).getSequenceAsString(); + if (sq.length() <= spos + offset) + { + // pad sequence + int diff = spos + offset - sq.length() - 1; + if (diff > 0) + { + // pad gaps + sq = sq + sb; + while ((diff = spos + offset - sq.length() - 1) > 0) + { + // sq = sq + // + ((diff >= sb.length()) ? sb.toString() : sb + // .substring(0, diff)); + if (diff >= sb.length()) + { + sq += sb.toString(); + } + else + { + char[] buf = new char[diff]; + sb.getChars(0, diff, buf, 0); + sq += buf.toString(); + } + } + } + sq += sb.toString(); + } + else + { + al.getSequenceAt(s).setSequence( + sq.substring(0, spos + offset) + sb.toString() + + sq.substring(spos + offset)); + } + } + } + // offset+=sb.length(); + } + spos = viscontigs[v + 1] + 1; + } + if ((offset + spos) < profileseq.getLength()) + { + // pad the final region with gaps. + StringBuffer sb = new StringBuffer(); + for (int s = 0, ns = profileseq.getLength() - spos - offset; s < ns; s++) + { + sb.append(gc); + } + for (int s = 0, ns = al.getHeight(); s < ns; s++) + { + SequenceI sqobj = al.getSequenceAt(s); + if (sqobj == profileseq) + { + continue; + } + String sq = sqobj.getSequenceAsString(); + // pad sequence + int diff = origseq.getLength() - sq.length(); + while (diff > 0) + { + // sq = sq + // + ((diff >= sb.length()) ? sb.toString() : sb + // .substring(0, diff)); + if (diff >= sb.length()) + { + sq += sb.toString(); + } + else + { + char[] buf = new char[diff]; + sb.getChars(0, diff, buf, 0); + sq += buf.toString(); + } + diff = origseq.getLength() - sq.length(); + } + } + } + } + + /** + * remove any hiddenColumns or selected columns and shift remaining based on a + * series of position, range deletions. + * + * @param deletions + */ + private void pruneDeletions(ShiftList deletions) + { + if (deletions != null) + { + final List shifts = deletions.getShifts(); + if (shifts != null && shifts.size() > 0) + { + pruneDeletions(shifts); + + // and shift the rest. + this.compensateForEdits(deletions); + } + } + } + + /** + * Adjust hidden column boundaries based on a series of column additions or + * deletions in visible regions. + * + * @param shiftrecord + * @return + */ + private ShiftList compensateForEdits(ShiftList shiftrecord) + { + if (shiftrecord != null) + { + final List shifts = shiftrecord.getShifts(); + if (shifts != null && shifts.size() > 0) + { + int shifted = 0; + for (int i = 0, j = shifts.size(); i < j; i++) + { + int[] sh = shifts.get(i); + compensateForDelEdits(shifted + sh[0], sh[1]); + shifted -= sh[1]; + } + } + return shiftrecord.getInverse(); + } + return null; + } + + /** + * Returns a hashCode built from hidden column ranges + */ + public int hashCode(int hc) + { + int hashCode = hc; + if (hiddenColumns != null) + { + for (int[] hidden : hiddenColumns) + { + hashCode = 31 * hashCode + hidden[0]; + hashCode = 31 * hashCode + hidden[1]; + } + } + return hashCode; + } + +} diff --git a/src/jalview/datamodel/HiddenSequences.java b/src/jalview/datamodel/HiddenSequences.java index 6950c28..1daaf43 100755 --- a/src/jalview/datamodel/HiddenSequences.java +++ b/src/jalview/datamodel/HiddenSequences.java @@ -403,4 +403,20 @@ public class HiddenSequences return false; } + + /** + * Answers if a sequence is hidden + * + * @param seq + * (absolute) index to test + * @return true if sequence at index seq is hidden + */ + public boolean isHidden(int seq) + { + if (hiddenSequences != null) + { + return (hiddenSequences[seq] != null); + } + return false; + } } diff --git a/src/jalview/datamodel/SeqCigar.java b/src/jalview/datamodel/SeqCigar.java index 98b0de5..9cc7b4a 100644 --- a/src/jalview/datamodel/SeqCigar.java +++ b/src/jalview/datamodel/SeqCigar.java @@ -494,18 +494,18 @@ public class SeqCigar extends CigarSimple /** * create an alignment from the given array of cigar sequences and gap * character, and marking the given segments as visible in the given - * columselection. + * hiddenColumns. * * @param alseqs * @param gapCharacter - * @param colsel - * - columnSelection where hidden regions are marked + * @param hidden + * - hiddenColumns where hidden regions are marked * @param segments * - visible regions of alignment * @return SequenceI[] */ public static SequenceI[] createAlignmentSequences(SeqCigar[] alseqs, - char gapCharacter, ColumnSelection colsel, int[] segments) + char gapCharacter, HiddenColumns hidden, int[] segments) { SequenceI[] seqs = new SequenceI[alseqs.length]; StringBuffer[] g_seqs = new StringBuffer[alseqs.length]; @@ -577,7 +577,7 @@ public class SeqCigar extends CigarSimple if (segments == null) { // add a hidden column for this deletion - colsel.hideColumns(inspos, inspos + insert.length - 1); + hidden.hideColumns(inspos, inspos + insert.length - 1); } } } @@ -598,7 +598,7 @@ public class SeqCigar extends CigarSimple { // int start=shifts.shift(segments[i]-1)+1; // int end=shifts.shift(segments[i]+segments[i+1]-1)-1; - colsel.hideColumns(segments[i + 1], segments[i + 1] + hidden.hideColumns(segments[i + 1], segments[i + 1] + segments[i + 2] - 1); } } diff --git a/src/jalview/datamodel/VisibleColsCollection.java b/src/jalview/datamodel/VisibleColsCollection.java new file mode 100644 index 0000000..86233ab --- /dev/null +++ b/src/jalview/datamodel/VisibleColsCollection.java @@ -0,0 +1,53 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import jalview.api.AlignmentColsCollectionI; + +import java.util.Iterator; + +public class VisibleColsCollection implements AlignmentColsCollectionI +{ + int start; + int end; + + HiddenColumns hidden; + + public VisibleColsCollection(int s, int e, AlignmentI al) + { + start = s; + end = e; + hidden = al.getHiddenColumns(); + } + + @Override + public Iterator iterator() + { + return new VisibleColsIterator(start, end, hidden); + } + + @Override + public boolean isHidden(int c) + { + return false; + } + +} diff --git a/src/jalview/datamodel/VisibleColsIterator.java b/src/jalview/datamodel/VisibleColsIterator.java new file mode 100644 index 0000000..70de1e3 --- /dev/null +++ b/src/jalview/datamodel/VisibleColsIterator.java @@ -0,0 +1,131 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +/** + * An iterator which iterates over all visible columns in an alignment + * + * @author kmourao + * + */ +public class VisibleColsIterator implements Iterator +{ + private int last; + + private int current; + + private int next; + + private List hidden; + + private int lasthiddenregion; + + public VisibleColsIterator(int firstcol, int lastcol, + HiddenColumns hiddenCols) + { + last = lastcol; + current = firstcol; + next = firstcol; + hidden = hiddenCols.getHiddenRegions(); + lasthiddenregion = -1; + + if (hidden != null) + { + int i = 0; + for (i = 0; i < hidden.size(); ++i) + { + if (current >= hidden.get(i)[0] && current <= hidden.get(i)[1]) + { + // current is hidden, move to right + current = hidden.get(i)[1] + 1; + next = current; + } + if (current < hidden.get(i)[0]) + { + break; + } + } + lasthiddenregion = i - 1; + + for (i = hidden.size() - 1; i >= 0; --i) + { + if (last >= hidden.get(i)[0] && last <= hidden.get(i)[1]) + { + // last is hidden, move to left + last = hidden.get(i)[0] - 1; + } + if (last > hidden.get(i)[1]) + { + break; + } + } + } + } + + @Override + public boolean hasNext() + { + return next <= last; + } + + @Override + public Integer next() + { + if (next > last) + { + throw new NoSuchElementException(); + } + current = next; + if ((hidden != null) && (lasthiddenregion + 1 < hidden.size())) + { + // still some more hidden regions + if (next + 1 < hidden.get(lasthiddenregion + 1)[0]) + { + // next+1 is still before the next hidden region + next++; + } + else if ((next + 1 >= hidden.get(lasthiddenregion + 1)[0]) + && (next + 1 <= hidden.get(lasthiddenregion + 1)[1])) + { + // next + 1 is in the next hidden region + next = hidden.get(lasthiddenregion + 1)[1] + 1; + lasthiddenregion++; + } + } + else + { + // finished with hidden regions, just increment normally + next++; + } + return current; + } + + @Override + public void remove() + { + throw new UnsupportedOperationException(); + } +} + diff --git a/src/jalview/datamodel/VisibleRowsCollection.java b/src/jalview/datamodel/VisibleRowsCollection.java new file mode 100644 index 0000000..ce8e8da --- /dev/null +++ b/src/jalview/datamodel/VisibleRowsCollection.java @@ -0,0 +1,60 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import jalview.api.AlignmentRowsCollectionI; + +import java.util.Iterator; + +public class VisibleRowsCollection implements AlignmentRowsCollectionI +{ + int start; + + int end; + + AlignmentI alignment; + + public VisibleRowsCollection(int s, int e, AlignmentI al) + { + start = s; + end = e; + alignment = al; + } + + @Override + public Iterator iterator() + { + return new VisibleRowsIterator(start, end, alignment); + } + + @Override + public boolean isHidden(int seq) + { + return false; + } + + @Override + public SequenceI getSequence(int seq) + { + return alignment.getSequenceAtAbsoluteIndex(seq); + } +} + diff --git a/src/jalview/datamodel/VisibleRowsIterator.java b/src/jalview/datamodel/VisibleRowsIterator.java new file mode 100644 index 0000000..a9c782d --- /dev/null +++ b/src/jalview/datamodel/VisibleRowsIterator.java @@ -0,0 +1,99 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * An iterator which iterates over all visible rows in an alignment + * + * @author kmourao + * + */ +public class VisibleRowsIterator implements Iterator +{ + private int last; + + private int current; + + private int next; + + private HiddenSequences hidden; + + private AlignmentI al; + + /** + * Create an iterator for all visible rows in the alignment + * + * @param firstrow + * absolute row index to start from + * @param lastrow + * absolute row index to end at + * @param alignment + * alignment to work with + */ + public VisibleRowsIterator(int firstrow, int lastrow, AlignmentI alignment) + { + al = alignment; + current = firstrow; + last = lastrow; + hidden = al.getHiddenSequences(); + while (last > current && hidden.isHidden(last)) + { + last--; + } + current = firstrow; + while (current < last && hidden.isHidden(current)) + { + current++; + } + next = current; + } + + @Override + public boolean hasNext() + { + return next <= last; + } + + @Override + public Integer next() + { + if (next > last) + { + throw new NoSuchElementException(); + } + current = next; + do + { + next++; + } while (next <= last && hidden.isHidden(next)); + return current; + } + + @Override + public void remove() + { + throw new UnsupportedOperationException(); + } +} + diff --git a/src/jalview/ext/jmol/JalviewJmolBinding.java b/src/jalview/ext/jmol/JalviewJmolBinding.java index 94df99a..00fd679 100644 --- a/src/jalview/ext/jmol/JalviewJmolBinding.java +++ b/src/jalview/ext/jmol/JalviewJmolBinding.java @@ -24,7 +24,7 @@ import jalview.api.AlignmentViewPanel; import jalview.api.FeatureRenderer; import jalview.api.SequenceRenderer; import jalview.datamodel.AlignmentI; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.io.DataSourceType; @@ -222,11 +222,11 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel * TODO */ public void superposeStructures(AlignmentI alignment, int refStructure, - ColumnSelection hiddenCols) + HiddenColumns hiddenCols) { superposeStructures(new AlignmentI[] { alignment }, new int[] { refStructure }, - new ColumnSelection[] { hiddenCols }); + new HiddenColumns[] { hiddenCols }); } /** @@ -234,7 +234,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel */ @Override public String superposeStructures(AlignmentI[] _alignment, - int[] _refStructure, ColumnSelection[] _hiddenCols) + int[] _refStructure, HiddenColumns[] _hiddenCols) { while (viewer.isScriptExecuting()) { @@ -278,7 +278,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel { int refStructure = _refStructure[a]; AlignmentI alignment = _alignment[a]; - ColumnSelection hiddenCols = _hiddenCols[a]; + HiddenColumns hiddenCols = _hiddenCols[a]; if (a > 0 && selectioncom.length() > 0 && !selectioncom.substring(selectioncom.length() - 1).equals( diff --git a/src/jalview/ext/jmol/JmolCommands.java b/src/jalview/ext/jmol/JmolCommands.java index 23e0a6f..3e7ca59 100644 --- a/src/jalview/ext/jmol/JmolCommands.java +++ b/src/jalview/ext/jmol/JmolCommands.java @@ -25,7 +25,7 @@ import jalview.api.AlignmentViewPanel; import jalview.api.FeatureRenderer; import jalview.api.SequenceRenderer; import jalview.datamodel.AlignmentI; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceI; import jalview.renderer.seqfeatures.FeatureColourFinder; import jalview.structure.StructureMapping; @@ -61,7 +61,7 @@ public class JmolCommands FeatureRenderer fr = viewPanel.getFeatureRenderer(); FeatureColourFinder finder = new FeatureColourFinder(fr); AlignViewportI viewport = viewPanel.getAlignViewport(); - ColumnSelection cs = viewport.getColumnSelection(); + HiddenColumns cs = viewport.getAlignment().getHiddenColumns(); AlignmentI al = viewport.getAlignment(); List cset = new ArrayList(); diff --git a/src/jalview/ext/rbvi/chimera/ChimeraCommands.java b/src/jalview/ext/rbvi/chimera/ChimeraCommands.java index 95757fd..62aaa1c 100644 --- a/src/jalview/ext/rbvi/chimera/ChimeraCommands.java +++ b/src/jalview/ext/rbvi/chimera/ChimeraCommands.java @@ -25,7 +25,7 @@ import jalview.api.AlignmentViewPanel; import jalview.api.FeatureRenderer; import jalview.api.SequenceRenderer; import jalview.datamodel.AlignmentI; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.renderer.seqfeatures.FeatureColourFinder; @@ -194,7 +194,7 @@ public class ChimeraCommands FeatureRenderer fr = viewPanel.getFeatureRenderer(); FeatureColourFinder finder = new FeatureColourFinder(fr); AlignViewportI viewport = viewPanel.getAlignViewport(); - ColumnSelection cs = viewport.getColumnSelection(); + HiddenColumns cs = viewport.getAlignment().getHiddenColumns(); AlignmentI al = viewport.getAlignment(); Map colourMap = new LinkedHashMap(); Color lastColour = null; diff --git a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java index ffce90c..870c4fe 100644 --- a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java +++ b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java @@ -25,7 +25,7 @@ import jalview.api.SequenceRenderer; import jalview.api.structures.JalviewStructureDisplayI; import jalview.bin.Cache; import jalview.datamodel.AlignmentI; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; import jalview.datamodel.SearchResultMatchI; import jalview.datamodel.SearchResultsI; @@ -337,7 +337,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel */ @Override public String superposeStructures(AlignmentI[] _alignment, - int[] _refStructure, ColumnSelection[] _hiddenCols) + int[] _refStructure, HiddenColumns[] _hiddenCols) { StringBuilder allComs = new StringBuilder(128); String[] files = getPdbFile(); @@ -353,7 +353,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel { int refStructure = _refStructure[a]; AlignmentI alignment = _alignment[a]; - ColumnSelection hiddenCols = _hiddenCols[a]; + HiddenColumns hiddenCols = _hiddenCols[a]; if (refStructure >= files.length) { diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 016ee85..4073e3e 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -53,6 +53,7 @@ import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentOrder; import jalview.datamodel.AlignmentView; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.HiddenSequences; import jalview.datamodel.PDBEntry; import jalview.datamodel.SeqCigar; @@ -233,7 +234,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * @param height * height of frame. */ - public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns, + public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns, int width, int height) { this(al, hiddenColumns, width, height, null); @@ -250,7 +251,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * @param sequenceSetId * (may be null) */ - public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns, + public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns, int width, int height, String sequenceSetId) { this(al, hiddenColumns, width, height, sequenceSetId, null); @@ -269,7 +270,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * @param viewId * (may be null) */ - public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns, + public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns, int width, int height, String sequenceSetId, String viewId) { setSize(width, height); @@ -288,7 +289,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs, - ColumnSelection hiddenColumns, int width, int height) + HiddenColumns hiddenColumns, int width, int height) { setSize(width, height); @@ -1192,8 +1193,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, exportData.getAlignment(), // class cast exceptions will // occur in the distant future exportData.getOmitHidden(), exportData.getStartEndPostions(), - f.getCacheSuffixDefault(format), - viewport.getColumnSelection()); + f.getCacheSuffixDefault(format), viewport.getAlignment() + .getHiddenColumns()); if (output == null) { @@ -1271,8 +1272,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, cap.setText(new FormatAdapter(alignPanel, exportData.getSettings()) .formatSequences(format, exportData.getAlignment(), exportData.getOmitHidden(), - exportData.getStartEndPostions(), - viewport.getColumnSelection())); + exportData + .getStartEndPostions(), viewport + .getAlignment().getHiddenColumns())); Desktop.addInternalFrame(cap, MessageManager.formatMessage( "label.alignment_output_command", new Object[] { e.getActionCommand() }), 600, 500); @@ -1321,8 +1323,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, alignmentToExport = viewport.getAlignment(); } alignmentStartEnd = alignmentToExport - .getVisibleStartAndEndIndex(viewport.getColumnSelection() - .getHiddenColumns()); + .getVisibleStartAndEndIndex(viewport.getAlignment() + .getHiddenColumns() + .getHiddenRegions()); AlignmentExportData ed = new AlignmentExportData(alignmentToExport, omitHidden, alignmentStartEnd, settings); return ed; @@ -1886,7 +1889,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, hiddenColumns = new ArrayList(); int hiddenOffset = viewport.getSelectionGroup().getStartRes(), hiddenCutoff = viewport .getSelectionGroup().getEndRes(); - for (int[] region : viewport.getColumnSelection().getHiddenColumns()) + for (int[] region : viewport.getAlignment().getHiddenColumns() + .getHiddenRegions()) { if (region[0] >= hiddenOffset && region[1] <= hiddenCutoff) { @@ -4655,9 +4659,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, viewport.getAlignment(), 0, false); SequenceI repseq = viewport.getAlignment().getSequenceAt(0); viewport.getAlignment().setSeqrep(repseq); - ColumnSelection cs = new ColumnSelection(); + HiddenColumns cs = new HiddenColumns(); cs.hideInsertionsFor(repseq); - viewport.setColumnSelection(cs); + viewport.getAlignment().setHiddenColumns(cs); isAnnotation = true; } // else if (IdentifyFile.FeaturesFile.equals(format)) diff --git a/src/jalview/gui/AlignViewport.java b/src/jalview/gui/AlignViewport.java index f22a911..6409b56 100644 --- a/src/jalview/gui/AlignViewport.java +++ b/src/jalview/gui/AlignViewport.java @@ -35,6 +35,7 @@ import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; import jalview.datamodel.SearchResults; import jalview.datamodel.SearchResultsI; @@ -51,12 +52,12 @@ import jalview.structure.StructureSelectionManager; import jalview.structure.VamsasSource; import jalview.util.MessageManager; import jalview.viewmodel.AlignmentViewport; -import jalview.viewmodel.ViewportRanges; import jalview.ws.params.AutoCalcSetting; import java.awt.Container; import java.awt.Dimension; import java.awt.Font; +import java.awt.FontMetrics; import java.awt.Rectangle; import java.util.ArrayList; import java.util.Hashtable; @@ -105,7 +106,7 @@ public class AlignViewport extends AlignmentViewport implements */ public AlignViewport(AlignmentI al) { - setAlignment(al); + super(al); init(); } @@ -123,6 +124,7 @@ public class AlignViewport extends AlignmentViewport implements public AlignViewport(AlignmentI al, String seqsetid, String viewid) { + super(al); sequenceSetID = seqsetid; viewId = viewid; // TODO remove these once 2.4.VAMSAS release finished @@ -135,8 +137,8 @@ public class AlignViewport extends AlignmentViewport implements { Cache.log.debug("Setting viewport's view id : " + viewId); } - setAlignment(al); init(); + } /** @@ -147,12 +149,12 @@ public class AlignViewport extends AlignmentViewport implements * @param hiddenColumns * ColumnSelection */ - public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns) + public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns) { - setAlignment(al); + super(al); if (hiddenColumns != null) { - colSel = hiddenColumns; + al.setHiddenColumns(hiddenColumns); } init(); } @@ -165,7 +167,7 @@ public class AlignViewport extends AlignmentViewport implements * @param seqsetid * (may be null) */ - public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns, + public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns, String seqsetid) { this(al, hiddenColumns, seqsetid, null); @@ -181,9 +183,10 @@ public class AlignViewport extends AlignmentViewport implements * @param viewid * (may be null) */ - public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns, + public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns, String seqsetid, String viewid) { + super(al); sequenceSetID = seqsetid; viewId = viewid; // TODO remove these once 2.4.VAMSAS release finished @@ -196,10 +199,10 @@ public class AlignViewport extends AlignmentViewport implements { Cache.log.debug("Setting viewport's view id : " + viewId); } - setAlignment(al); + if (hiddenColumns != null) { - colSel = hiddenColumns; + al.setHiddenColumns(hiddenColumns); } init(); } @@ -238,7 +241,6 @@ public class AlignViewport extends AlignmentViewport implements void init() { - ranges = new ViewportRanges(this.alignment); applyViewProperties(); String fontName = Cache.getDefault("FONT_NAME", "SansSerif"); @@ -350,23 +352,19 @@ public class AlignViewport extends AlignmentViewport implements boolean validCharWidth; /** - * update view settings with the given font. You may need to call - * alignPanel.fontChanged to update the layout geometry - * - * @param setGrid - * when true, charWidth/height is set according to font mentrics + * {@inheritDoc} */ + @Override public void setFont(Font f, boolean setGrid) { font = f; Container c = new Container(); - java.awt.FontMetrics fm = c.getFontMetrics(font); - int w = viewStyle.getCharWidth(), ww = fm.charWidth('M'), h = viewStyle - .getCharHeight(); if (setGrid) { + FontMetrics fm = c.getFontMetrics(font); + int ww = fm.charWidth('M'); setCharHeight(fm.getHeight()); setCharWidth(ww); } @@ -529,7 +527,7 @@ public class AlignViewport extends AlignmentViewport implements { end = alignment.getWidth(); } - viscontigs = colSel.getVisibleContigs(start, end); + viscontigs = alignment.getHiddenColumns().getVisibleContigs(start, end); return viscontigs; } @@ -599,7 +597,9 @@ public class AlignViewport extends AlignmentViewport implements jalview.structure.StructureSelectionManager .getStructureSelectionManager(Desktop.instance).sendSelection( new SequenceGroup(getSelectionGroup()), - new ColumnSelection(getColumnSelection()), this); + new ColumnSelection(getColumnSelection()), + new HiddenColumns(getAlignment().getHiddenColumns()), + this); } /** diff --git a/src/jalview/gui/AlignmentPanel.java b/src/jalview/gui/AlignmentPanel.java index 04de50b..885d79d 100644 --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@ -25,6 +25,7 @@ import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; import jalview.bin.Cache; import jalview.datamodel.AlignmentI; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SearchResultsI; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceGroup; @@ -402,11 +403,12 @@ public class AlignmentPanel extends GAlignmentPanel implements } if (av.hasHiddenColumns()) { - start = av.getColumnSelection().findColumnPosition(start); - end = av.getColumnSelection().findColumnPosition(end); + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); + start = hidden.findColumnPosition(start); + end = hidden.findColumnPosition(end); if (start == end) { - if (!av.getColumnSelection().isVisible(r[0])) + if (!hidden.isVisible(r[0])) { // don't scroll - position isn't visible return false; @@ -711,7 +713,8 @@ public class AlignmentPanel extends GAlignmentPanel implements if (av.hasHiddenColumns()) { // reset the width to exclude hidden columns - width = av.getColumnSelection().findColumnPosition(width); + width = av.getAlignment().getHiddenColumns() + .findColumnPosition(width); } hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth(); @@ -924,7 +927,8 @@ public class AlignmentPanel extends GAlignmentPanel implements if (av.hasHiddenColumns()) { - maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1; + maxwidth = av.getAlignment().getHiddenColumns() + .findColumnPosition(maxwidth) - 1; } int canvasWidth = getSeqPanel().seqCanvas @@ -1212,7 +1216,8 @@ public class AlignmentPanel extends GAlignmentPanel implements int maxwidth = av.getAlignment().getWidth(); if (av.hasHiddenColumns()) { - maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1; + maxwidth = av.getAlignment().getHiddenColumns() + .findColumnPosition(maxwidth) - 1; } int resWidth = getSeqPanel().seqCanvas.getWrappedCanvasWidth(pwidth @@ -1406,7 +1411,8 @@ public class AlignmentPanel extends GAlignmentPanel implements int maxwidth = av.getAlignment().getWidth(); if (av.hasHiddenColumns()) { - maxwidth = av.getColumnSelection().findColumnPosition(maxwidth); + maxwidth = av.getAlignment().getHiddenColumns() + .findColumnPosition(maxwidth); } int height = ((av.getAlignment().getHeight() + 1) * av.getCharHeight()) @@ -1636,7 +1642,8 @@ public class AlignmentPanel extends GAlignmentPanel implements int maxwidth = av.getAlignment().getWidth(); if (av.hasHiddenColumns()) { - maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1; + maxwidth = av.getAlignment().getHiddenColumns() + .findColumnPosition(maxwidth) - 1; } int height = ((maxwidth / chunkWidth) + 1) * cHeight; diff --git a/src/jalview/gui/AnnotationColumnChooser.java b/src/jalview/gui/AnnotationColumnChooser.java index 999d217..96299e7 100644 --- a/src/jalview/gui/AnnotationColumnChooser.java +++ b/src/jalview/gui/AnnotationColumnChooser.java @@ -21,7 +21,7 @@ package jalview.gui; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.schemes.AnnotationColourGradient; import jalview.util.MessageManager; import jalview.viewmodel.annotationfilter.AnnotationFilterParameter; @@ -86,7 +86,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements private int actionOption = ACTION_OPTION_SELECT; - private ColumnSelection oldColumnSelection; + private HiddenColumns oldHiddenColumns; protected int MIN_WIDTH = 420; @@ -110,7 +110,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements { return; } - setOldColumnSelection(av.getColumnSelection()); + setOldHiddenColumns(av.getAlignment().getHiddenColumns()); adjusting = true; setAnnotations(new JComboBox(getAnnotationItems(false))); @@ -236,26 +236,26 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements @Override protected void reset() { - if (this.getOldColumnSelection() != null) + if (this.getOldHiddenColumns() != null) { av.getColumnSelection().clear(); if (av.getAnnotationColumnSelectionState() != null) { - ColumnSelection oldSelection = av + HiddenColumns oldHidden = av .getAnnotationColumnSelectionState() - .getOldColumnSelection(); - if (oldSelection != null && oldSelection.getHiddenColumns() != null - && !oldSelection.getHiddenColumns().isEmpty()) + .getOldHiddenColumns(); + if (oldHidden != null && oldHidden.getHiddenRegions() != null + && !oldHidden.getHiddenRegions().isEmpty()) { - for (Iterator itr = oldSelection.getHiddenColumns() + for (Iterator itr = oldHidden.getHiddenRegions() .iterator(); itr.hasNext();) { int positions[] = itr.next(); av.hideColumns(positions[0], positions[1]); } } - av.setColumnSelection(oldSelection); + av.getAlignment().setHiddenColumns(oldHidden); } ap.paintAlignment(true); } @@ -408,17 +408,16 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements ap.paintAlignment(true); } - - public ColumnSelection getOldColumnSelection() + public HiddenColumns getOldHiddenColumns() { - return oldColumnSelection; + return oldHiddenColumns; } - public void setOldColumnSelection(ColumnSelection currentColumnSelection) + public void setOldHiddenColumns(HiddenColumns currentHiddenColumns) { - if (currentColumnSelection != null) + if (currentHiddenColumns != null) { - this.oldColumnSelection = new ColumnSelection(currentColumnSelection); + this.oldHiddenColumns = new HiddenColumns(currentHiddenColumns); } } diff --git a/src/jalview/gui/AnnotationLabels.java b/src/jalview/gui/AnnotationLabels.java index c9535d0..8ca1a4e 100755 --- a/src/jalview/gui/AnnotationLabels.java +++ b/src/jalview/gui/AnnotationLabels.java @@ -947,12 +947,14 @@ public class AnnotationLabels extends JPanel implements MouseListener, Alignment ds = new Alignment(dseqs); if (av.hasHiddenColumns()) { - omitHidden = av.getColumnSelection().getVisibleSequenceStrings(0, + omitHidden = av.getAlignment().getHiddenColumns() + .getVisibleSequenceStrings(0, sq.getLength(), seqs); } int[] alignmentStartEnd = new int[] { 0, ds.getWidth() - 1 }; - List hiddenCols = av.getColumnSelection().getHiddenColumns(); + List hiddenCols = av.getAlignment().getHiddenColumns() + .getHiddenRegions(); if (hiddenCols != null) { alignmentStartEnd = av.getAlignment().getVisibleStartAndEndIndex( @@ -968,7 +970,8 @@ public class AnnotationLabels extends JPanel implements MouseListener, if (av.hasHiddenColumns()) { hiddenColumns = new ArrayList(); - for (int[] region : av.getColumnSelection().getHiddenColumns()) + for (int[] region : av.getAlignment().getHiddenColumns() + .getHiddenRegions()) { hiddenColumns.add(new int[] { region[0], region[1] }); } diff --git a/src/jalview/gui/AnnotationPanel.java b/src/jalview/gui/AnnotationPanel.java index 84f3e6c..919356f 100755 --- a/src/jalview/gui/AnnotationPanel.java +++ b/src/jalview/gui/AnnotationPanel.java @@ -23,6 +23,7 @@ package jalview.gui; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.Annotation; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceI; import jalview.renderer.AnnotationRenderer; import jalview.renderer.AwtRenderPanelI; @@ -290,7 +291,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, { for (int index : av.getColumnSelection().getSelected()) { - if (av.getColumnSelection().isVisible(index)) + if (av.getAlignment().getHiddenColumns().isVisible(index)) { anot[index] = null; } @@ -314,7 +315,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, for (int index : av.getColumnSelection().getSelected()) { - if (!av.getColumnSelection().isVisible(index)) + if (!av.getAlignment().getHiddenColumns().isVisible(index)) { continue; } @@ -337,7 +338,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, for (int index : av.getColumnSelection().getSelected()) { - if (!av.getColumnSelection().isVisible(index)) + if (!av.getAlignment().getHiddenColumns().isVisible(index)) { continue; } @@ -397,7 +398,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, } for (int index : av.getColumnSelection().getSelected()) { - if (!av.getColumnSelection().isVisible(index)) + if (!av.getAlignment().getHiddenColumns().isVisible(index)) { continue; } @@ -440,6 +441,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, StringBuilder collatedInput = new StringBuilder(64); String last = ""; ColumnSelection viscols = av.getColumnSelection(); + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); /* * the selection list (read-only view) is in selection order, not @@ -450,7 +452,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, for (int index : selected) { // always check for current display state - just in case - if (!viscols.isVisible(index)) + if (!hidden.isVisible(index)) { continue; } @@ -712,7 +714,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, if (av.hasHiddenColumns()) { - column = av.getColumnSelection().adjustForHiddenColumns(column); + column = av.getAlignment().getHiddenColumns() + .adjustForHiddenColumns(column); } AlignmentAnnotation ann = aa[row]; diff --git a/src/jalview/gui/AppVarna.java b/src/jalview/gui/AppVarna.java index f4a4f4d..a50de77 100644 --- a/src/jalview/gui/AppVarna.java +++ b/src/jalview/gui/AppVarna.java @@ -23,6 +23,7 @@ package jalview.gui; import jalview.analysis.AlignSeq; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.RnaViewerModel; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; @@ -400,7 +401,7 @@ public class AppVarna extends JInternalFrame implements SelectionListener, @Override public void selection(SequenceGroup seqsel, ColumnSelection colsel, - SelectionSource source) + HiddenColumns hidden, SelectionSource source) { if (source != ap.av) { diff --git a/src/jalview/gui/CutAndPasteTransfer.java b/src/jalview/gui/CutAndPasteTransfer.java index 7a0b0af..a5aa9eb 100644 --- a/src/jalview/gui/CutAndPasteTransfer.java +++ b/src/jalview/gui/CutAndPasteTransfer.java @@ -28,7 +28,7 @@ import jalview.api.FeaturesDisplayedI; import jalview.api.FeaturesSourceI; import jalview.bin.Jalview; import jalview.datamodel.AlignmentI; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceI; import jalview.io.AlignmentFileReaderI; import jalview.io.AppletFormatAdapter; @@ -284,8 +284,8 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer AlignFrame af; if (source instanceof ComplexAlignFile) { - ColumnSelection colSel = ((ComplexAlignFile) source) - .getColumnSelection(); + HiddenColumns hidden = ((ComplexAlignFile) source) + .getHiddenColumns(); SequenceI[] hiddenSeqs = ((ComplexAlignFile) source) .getHiddenSequences(); boolean showSeqFeatures = ((ComplexAlignFile) source) @@ -294,7 +294,7 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer .getGlobalColourScheme(); FeaturesDisplayedI fd = ((ComplexAlignFile) source) .getDisplayedFeatures(); - af = new AlignFrame(al, hiddenSeqs, colSel, + af = new AlignFrame(al, hiddenSeqs, hidden, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); af.getViewport().setShowSequenceFeatures(showSeqFeatures); af.getViewport().setFeaturesDisplayed(fd); diff --git a/src/jalview/gui/FontChooser.java b/src/jalview/gui/FontChooser.java index 8220aea..06f29e9 100755 --- a/src/jalview/gui/FontChooser.java +++ b/src/jalview/gui/FontChooser.java @@ -26,12 +26,10 @@ import jalview.util.MessageManager; import java.awt.Font; import java.awt.FontMetrics; -import java.awt.event.ActionEvent; import java.awt.geom.Rectangle2D; import javax.swing.JInternalFrame; import javax.swing.JLayeredPane; -import javax.swing.JOptionPane; /** * DOCUMENT ME! @@ -50,8 +48,22 @@ public class FontChooser extends GFontChooser */ Font oldFont; + /* + * The font on opening the dialog (to be restored on Cancel) + * on the other half of a split frame (if applicable) + */ + Font oldComplementFont; + + /* + * the state of 'scale protein as cDNA' on opening the dialog + */ boolean oldProteinScale; + /* + * the state of 'same font for protein and cDNA' on opening the dialog + */ + boolean oldMirrorFont; + boolean init = true; JInternalFrame frame; @@ -63,34 +75,37 @@ public class FontChooser extends GFontChooser private boolean lastSelMono = false; + private boolean oldSmoothFont; + + private boolean oldComplementSmooth; + /** - * Creates a new FontChooser object. + * Creates a new FontChooser for a tree panel * - * @param ap - * DOCUMENT ME! + * @param treePanel */ - public FontChooser(TreePanel tp) + public FontChooser(TreePanel treePanel) { - this.tp = tp; - ap = tp.treeCanvas.ap; - oldFont = tp.getTreeFont(); + this.tp = treePanel; + ap = treePanel.treeCanvas.ap; + oldFont = treePanel.getTreeFont(); defaultButton.setVisible(false); smoothFont.setEnabled(false); init(); } /** - * Creates a new FontChooser object. + * Creates a new FontChooser for an alignment panel * - * @param ap - * DOCUMENT ME! + * @param alignPanel */ - public FontChooser(AlignmentPanel ap) + public FontChooser(AlignmentPanel alignPanel) { - oldFont = ap.av.getFont(); - oldProteinScale = ap.av.isScaleProteinAsCdna(); - - this.ap = ap; + oldFont = alignPanel.av.getFont(); + oldProteinScale = alignPanel.av.isScaleProteinAsCdna(); + oldMirrorFont = alignPanel.av.isProteinFontAsCdna(); + oldSmoothFont = alignPanel.av.antiAlias; + this.ap = alignPanel; init(); } @@ -103,14 +118,19 @@ public class FontChooser extends GFontChooser /* * Enable 'scale protein as cDNA' in a SplitFrame view. The selection is - * stored in the ViewStyle of both dna and protein Viewport + * stored in the ViewStyle of both dna and protein Viewport. Also enable + * checkbox for copy font changes to other half of split frame. */ - scaleAsCdna.setEnabled(false); - if (ap.av.getCodingComplement() != null) + boolean inSplitFrame = ap.av.getCodingComplement() != null; + if (inSplitFrame) { - scaleAsCdna.setEnabled(true); + oldComplementFont = ((AlignViewport) ap.av.getCodingComplement()) + .getFont(); + oldComplementSmooth = ((AlignViewport) ap.av.getCodingComplement()).antiAlias; scaleAsCdna.setVisible(true); scaleAsCdna.setSelected(ap.av.isScaleProteinAsCdna()); + fontAsCdna.setVisible(true); + fontAsCdna.setSelected(ap.av.isProteinFontAsCdna()); } if (tp != null) @@ -122,7 +142,7 @@ public class FontChooser extends GFontChooser else { Desktop.addInternalFrame(frame, - MessageManager.getString("action.change_font"), 380, 200, + MessageManager.getString("action.change_font"), 380, 220, false); } @@ -158,11 +178,19 @@ public class FontChooser extends GFontChooser } @Override - public void smoothFont_actionPerformed(ActionEvent e) + protected void smoothFont_actionPerformed() { ap.av.antiAlias = smoothFont.isSelected(); ap.getAnnotationPanel().image = null; ap.paintAlignment(true); + if (ap.av.getCodingComplement() != null && ap.av.isProteinFontAsCdna()) + { + ((AlignViewport) ap.av.getCodingComplement()).antiAlias = ap.av.antiAlias; + SplitFrame sv = (SplitFrame) ap.alignFrame.getSplitViewContainer(); + sv.adjustLayout(); + sv.repaint(); + } + } /** @@ -172,7 +200,7 @@ public class FontChooser extends GFontChooser * DOCUMENT ME! */ @Override - protected void ok_actionPerformed(ActionEvent e) + protected void ok_actionPerformed() { try { @@ -197,26 +225,32 @@ public class FontChooser extends GFontChooser * DOCUMENT ME! */ @Override - protected void cancel_actionPerformed(ActionEvent e) + protected void cancel_actionPerformed() { if (ap != null) { ap.av.setFont(oldFont, true); ap.av.setScaleProteinAsCdna(oldProteinScale); + ap.av.setProteinFontAsCdna(oldMirrorFont); + ap.av.antiAlias = oldSmoothFont; ap.paintAlignment(true); - if (scaleAsCdna.isEnabled()) + + if (scaleAsCdna.isVisible() && scaleAsCdna.isEnabled()) { - ap.av.setScaleProteinAsCdna(oldProteinScale); ap.av.getCodingComplement().setScaleProteinAsCdna(oldProteinScale); + ap.av.getCodingComplement().setProteinFontAsCdna(oldMirrorFont); + ((AlignViewport) ap.av.getCodingComplement()).antiAlias = oldComplementSmooth; + ap.av.getCodingComplement().setFont(oldComplementFont, true); + SplitFrame splitFrame = (SplitFrame) ap.alignFrame + .getSplitViewContainer(); + splitFrame.adjustLayout(); + splitFrame.repaint(); } } else if (tp != null) { tp.setTreeFont(oldFont); } - fontName.setSelectedItem(oldFont.getName()); - fontSize.setSelectedItem(oldFont.getSize()); - fontStyle.setSelectedIndex(oldFont.getStyle()); try { @@ -287,6 +321,29 @@ public class FontChooser extends GFontChooser { ap.av.setFont(newFont, true); ap.fontChanged(); + + /* + * adjust other half of split frame if any, if either same + * font, or proportionate scaling, is selected + */ + if (fontAsCdna.isEnabled()) + { + if (fontAsCdna.isSelected()) + { + /* + * copy the font + */ + ap.av.getCodingComplement().setFont(newFont, true); + } + + /* + * adjust layout for font change / reset / sizing + */ + SplitFrame splitFrame = (SplitFrame) ap.alignFrame + .getSplitViewContainer(); + splitFrame.adjustLayout(); + splitFrame.repaint(); + } } monospaced.setSelected(mw == iw); @@ -299,13 +356,10 @@ public class FontChooser extends GFontChooser } /** - * DOCUMENT ME! - * - * @param e - * DOCUMENT ME! + * Updates on change of selected font name */ @Override - protected void fontName_actionPerformed(ActionEvent e) + protected void fontName_actionPerformed() { if (init) { @@ -316,13 +370,10 @@ public class FontChooser extends GFontChooser } /** - * DOCUMENT ME! - * - * @param e - * DOCUMENT ME! + * Updates on change of selected font size */ @Override - protected void fontSize_actionPerformed(ActionEvent e) + protected void fontSize_actionPerformed() { if (init) { @@ -333,13 +384,10 @@ public class FontChooser extends GFontChooser } /** - * DOCUMENT ME! - * - * @param e - * DOCUMENT ME! + * Updates on change of selected font style */ @Override - protected void fontStyle_actionPerformed(ActionEvent e) + protected void fontStyle_actionPerformed() { if (init) { @@ -352,11 +400,9 @@ public class FontChooser extends GFontChooser /** * Make selected settings the defaults by storing them (via Cache class) in * the .jalview_properties file (the file is only written when Jalview exits) - * - * @param e */ @Override - public void defaultButton_actionPerformed(ActionEvent e) + public void defaultButton_actionPerformed() { Cache.setProperty("FONT_NAME", fontName.getSelectedItem().toString()); Cache.setProperty("FONT_STYLE", fontStyle.getSelectedIndex() + ""); @@ -372,7 +418,7 @@ public class FontChooser extends GFontChooser * characters */ @Override - protected void scaleAsCdna_actionPerformed(ActionEvent e) + protected void scaleAsCdna_actionPerformed() { ap.av.setScaleProteinAsCdna(scaleAsCdna.isSelected()); ap.av.getCodingComplement().setScaleProteinAsCdna( @@ -381,7 +427,28 @@ public class FontChooser extends GFontChooser .getSplitViewContainer(); splitFrame.adjustLayout(); splitFrame.repaint(); - // ap.paintAlignment(true); - // TODO would like to repaint + } + + /** + * Turn on/off mirroring of font across split frame. If turning on, also + * copies the current font across the split frame. If turning off, restores + * the other half of the split frame to its initial font. + */ + @Override + protected void mirrorFonts_actionPerformed() + { + boolean selected = fontAsCdna.isSelected(); + ap.av.setProteinFontAsCdna(selected); + ap.av.getCodingComplement().setProteinFontAsCdna(selected); + + /* + * reset other half of split frame if turning option off + */ + if (!selected) + { + ap.av.getCodingComplement().setFont(oldComplementFont, true); + } + + changeFont(); } } diff --git a/src/jalview/gui/IdCanvas.java b/src/jalview/gui/IdCanvas.java index aad0776..1b79f54 100755 --- a/src/jalview/gui/IdCanvas.java +++ b/src/jalview/gui/IdCanvas.java @@ -290,7 +290,8 @@ public class IdCanvas extends JPanel if (av.hasHiddenColumns()) { - maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1; + maxwidth = av.getAlignment().getHiddenColumns() + .findColumnPosition(maxwidth) - 1; } int annotationHeight = 0; diff --git a/src/jalview/gui/Jalview2XML.java b/src/jalview/gui/Jalview2XML.java index 02136f9..6361caf 100644 --- a/src/jalview/gui/Jalview2XML.java +++ b/src/jalview/gui/Jalview2XML.java @@ -1413,17 +1413,18 @@ public class Jalview2XML if (av.hasHiddenColumns()) { - if (av.getColumnSelection() == null - || av.getColumnSelection().getHiddenColumns() == null) + jalview.datamodel.HiddenColumns hidden = av.getAlignment() + .getHiddenColumns(); + if (hidden == null || hidden.getHiddenRegions() == null) { warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this."); } else { - for (int c = 0; c < av.getColumnSelection().getHiddenColumns() + for (int c = 0; c < hidden.getHiddenRegions() .size(); c++) { - int[] region = av.getColumnSelection().getHiddenColumns() + int[] region = hidden.getHiddenRegions() .get(c); HiddenColumns hc = new HiddenColumns(); hc.setStart(region[0]); diff --git a/src/jalview/gui/OverviewCanvas.java b/src/jalview/gui/OverviewCanvas.java new file mode 100644 index 0000000..6f9fbbf --- /dev/null +++ b/src/jalview/gui/OverviewCanvas.java @@ -0,0 +1,182 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.gui; + +import jalview.api.AlignViewportI; +import jalview.renderer.OverviewRenderer; +import jalview.viewmodel.OverviewDimensions; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.image.BufferedImage; + +import javax.swing.JComponent; + +public class OverviewCanvas extends JComponent +{ + private static final Color TRANS_GREY = new Color(100, 100, 100, 25); + + // This is set true if the alignment view changes whilst + // the overview is being calculated + private volatile boolean restart = false; + + private volatile boolean updaterunning = false; + + private BufferedImage miniMe; + + private BufferedImage lastMiniMe = null; + + // Can set different properties in this seqCanvas than + // main visible SeqCanvas + private SequenceRenderer sr; + + private jalview.renderer.seqfeatures.FeatureRenderer fr; + + private OverviewDimensions od; + + private AlignViewportI av; + + public OverviewCanvas(OverviewDimensions overviewDims, + AlignViewportI alignvp) + { + od = overviewDims; + av = alignvp; + + sr = new SequenceRenderer(av); + sr.renderGaps = false; + sr.forOverview = true; + fr = new jalview.renderer.seqfeatures.FeatureRenderer(av); + } + + /** + * Update the overview dimensions object used by the canvas (e.g. if we change + * from showing hidden columns to hiding them or vice versa) + * + * @param overviewDims + */ + public void resetOviewDims(OverviewDimensions overviewDims) + { + od = overviewDims; + } + + /** + * Signals to drawing code that the associated alignment viewport has changed + * and a redraw will be required + */ + public boolean restartDraw() + { + synchronized (this) + { + if (updaterunning) + { + restart = true; + } + else + { + updaterunning = true; + } + return restart; + } + } + + /** + * Draw the overview sequences + * + * @param showSequenceFeatures + * true if sequence features are to be shown + * @param showAnnotation + * true if the annotation is to be shown + * @param transferRenderer + * the renderer to transfer feature colouring from + */ + public void draw(boolean showSequenceFeatures, boolean showAnnotation, + FeatureRenderer transferRenderer) + { + miniMe = null; + + if (showSequenceFeatures) + { + fr.transferSettings(transferRenderer); + } + + setPreferredSize(new Dimension(od.getWidth(), od.getHeight())); + + OverviewRenderer or = new OverviewRenderer(sr, fr, od); + miniMe = or.draw(od.getRows(av.getAlignment()), + od.getColumns(av.getAlignment())); + + Graphics mg = miniMe.getGraphics(); + + if (showAnnotation) + { + mg.translate(0, od.getSequencesHeight()); + or.drawGraph(mg, av.getAlignmentConservationAnnotation(), + av.getCharWidth(), od.getGraphHeight(), + od.getColumns(av.getAlignment())); + mg.translate(0, -od.getSequencesHeight()); + } + System.gc(); + + if (restart) + { + restart = false; + draw(showSequenceFeatures, showAnnotation, transferRenderer); + } + else + { + updaterunning = false; + lastMiniMe = miniMe; + } + } + + @Override + public void paintComponent(Graphics g) + { + if (restart) + { + if (lastMiniMe == null) + { + g.setColor(Color.white); + g.fillRect(0, 0, getWidth(), getHeight()); + } + else + { + g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this); + } + g.setColor(TRANS_GREY); + g.fillRect(0, 0, getWidth(), getHeight()); + } + else if (lastMiniMe != null) + { + g.drawImage(lastMiniMe, 0, 0, this); + if (lastMiniMe != miniMe) + { + g.setColor(TRANS_GREY); + g.fillRect(0, 0, getWidth(), getHeight()); + } + } + + g.setColor(Color.red); + od.drawBox(g); + } + +} diff --git a/src/jalview/gui/OverviewPanel.java b/src/jalview/gui/OverviewPanel.java index c530fdc..a6c3960 100755 --- a/src/jalview/gui/OverviewPanel.java +++ b/src/jalview/gui/OverviewPanel.java @@ -20,22 +20,26 @@ */ package jalview.gui; -import jalview.datamodel.SequenceI; -import jalview.renderer.AnnotationRenderer; -import jalview.renderer.seqfeatures.FeatureColourFinder; +import jalview.util.MessageManager; +import jalview.util.Platform; import jalview.viewmodel.OverviewDimensions; +import jalview.viewmodel.OverviewDimensionsHideHidden; +import jalview.viewmodel.OverviewDimensionsShowHidden; -import java.awt.Color; +import java.awt.BorderLayout; import java.awt.Dimension; -import java.awt.Graphics; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; -import java.awt.image.BufferedImage; +import javax.swing.JCheckBoxMenuItem; import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.SwingUtilities; /** * Panel displaying an overview of the full alignment, with an interactive box @@ -46,32 +50,17 @@ import javax.swing.JPanel; */ public class OverviewPanel extends JPanel implements Runnable { - private static final Color TRANS_GREY = new Color(100, 100, 100, 25); - - private final AnnotationRenderer renderer = new AnnotationRenderer(); - private OverviewDimensions od; - private BufferedImage miniMe; - - private BufferedImage lastMiniMe = null; + private OverviewCanvas oviewCanvas; private AlignViewport av; private AlignmentPanel ap; - // - private boolean resizing = false; - - // This is set true if the user resizes whilst - // the overview is being calculated - private boolean resizeAgain = false; + private JCheckBoxMenuItem displayToggle; - // Can set different properties in this seqCanvas than - // main visible SeqCanvas - private SequenceRenderer sr; - - jalview.renderer.seqfeatures.FeatureRenderer fr; + private boolean showHidden = true; /** * Creates a new OverviewPanel object. @@ -83,17 +72,15 @@ public class OverviewPanel extends JPanel implements Runnable { this.av = alPanel.av; this.ap = alPanel; - setLayout(null); - - sr = new SequenceRenderer(av); - sr.renderGaps = false; - sr.forOverview = true; - fr = new FeatureRenderer(ap); - od = new OverviewDimensions(av.getRanges(), + od = new OverviewDimensionsShowHidden(av.getRanges(), (av.isShowAnnotation() && av .getAlignmentConservationAnnotation() != null)); + oviewCanvas = new OverviewCanvas(od, av); + setLayout(new BorderLayout()); + add(oviewCanvas, BorderLayout.CENTER); + addComponentListener(new ComponentAdapter() { @Override @@ -112,11 +99,12 @@ public class OverviewPanel extends JPanel implements Runnable @Override public void mouseDragged(MouseEvent evt) { - if (!av.getWrapAlignment()) + if (!SwingUtilities.isRightMouseButton(evt) + && !av.getWrapAlignment()) { od.updateViewportFromMouse(evt.getX(), evt.getY(), av - .getAlignment().getHiddenSequences(), av - .getColumnSelection(), av.getRanges()); + .getAlignment().getHiddenSequences(), av.getAlignment() + .getHiddenColumns()); ap.setScrollValues(od.getScrollCol(), od.getScrollRow()); } } @@ -127,191 +115,116 @@ public class OverviewPanel extends JPanel implements Runnable @Override public void mousePressed(MouseEvent evt) { - if (!av.getWrapAlignment()) + if (SwingUtilities.isRightMouseButton(evt)) + { + if (!Platform.isAMac()) + { + showPopupMenu(evt); + } + } + else if (!av.getWrapAlignment()) { od.updateViewportFromMouse(evt.getX(), evt.getY(), av - .getAlignment().getHiddenSequences(), av - .getColumnSelection(), av.getRanges()); + .getAlignment().getHiddenSequences(), av.getAlignment() + .getHiddenColumns()); ap.setScrollValues(od.getScrollCol(), od.getScrollRow()); } } + + @Override + public void mouseClicked(MouseEvent evt) + { + if (SwingUtilities.isRightMouseButton(evt)) + { + showPopupMenu(evt); + } + } }); + updateOverviewImage(); } - /** - * Updates the overview image when the related alignment panel is updated + /* + * Displays the popup menu and acts on user input */ - public void updateOverviewImage() - { - if (resizing) - { - resizeAgain = true; - return; - } - - resizing = true; - - if ((getWidth() > 0) && (getHeight() > 0)) - { - od.setWidth(getWidth()); - od.setHeight(getHeight()); - } - - setPreferredSize(new Dimension(od.getWidth(), od.getHeight())); - - Thread thread = new Thread(this); - thread.start(); - repaint(); - } - - @Override - public void run() + private void showPopupMenu(MouseEvent e) { - miniMe = null; - - if (av.isShowSequenceFeatures()) - { - fr.transferSettings(ap.getSeqPanel().seqCanvas.getFeatureRenderer()); - } - - // why do we need to set preferred size again? was set in - // updateOverviewImage - setPreferredSize(new Dimension(od.getWidth(), od.getHeight())); - - miniMe = new BufferedImage(od.getWidth(), od.getHeight(), - BufferedImage.TYPE_INT_RGB); - - Graphics mg = miniMe.getGraphics(); - mg.setColor(Color.orange); - mg.fillRect(0, 0, od.getWidth(), miniMe.getHeight()); - - // calculate sampleCol and sampleRow - // alignment width is max number of residues/bases - // alignment height is number of sequences - int alwidth = av.getAlignment().getWidth(); - int alheight = av.getAlignment().getAbsoluteHeight(); - - // sampleCol or sampleRow is the width/height allocated to each residue - // in particular, sometimes we may need more than one row/col of the - // BufferedImage allocated - // sampleCol is how much of a residue to assign to each pixel - // sampleRow is how many sequences to assign to each pixel - float sampleCol = alwidth / (float) od.getWidth(); - float sampleRow = alheight / (float) od.getSequencesHeight(); - - buildImage(sampleRow, sampleCol); - - // check for conservation annotation to make sure overview works for DNA too - if (av.isShowAnnotation() - && (av.getAlignmentConservationAnnotation() != null)) + JPopupMenu popup = new JPopupMenu(); + ActionListener menuListener = new ActionListener() { - renderer.updateFromAlignViewport(av); - for (int col = 0; col < od.getWidth() && !resizeAgain; col++) + @Override + public void actionPerformed(ActionEvent event) { - mg.translate(col, od.getSequencesHeight()); - renderer.drawGraph(mg, av.getAlignmentConservationAnnotation(), - av.getAlignmentConservationAnnotation().annotations, - (int) (sampleCol) + 1, od.getGraphHeight(), - (int) (col * sampleCol), (int) (col * sampleCol) + 1); - mg.translate(-col, -od.getSequencesHeight()); - + // switch on/off the hidden columns view + toggleHiddenColumns(); + displayToggle.setSelected(showHidden); } - } - System.gc(); - - resizing = false; - - if (resizeAgain) - { - resizeAgain = false; - updateOverviewImage(); - } - else - { - lastMiniMe = miniMe; - } - - setBoxPosition(); + }; + displayToggle = new JCheckBoxMenuItem( + MessageManager.getString("label.togglehidden")); + displayToggle.setEnabled(true); + displayToggle.setSelected(showHidden); + popup.add(displayToggle); + displayToggle.addActionListener(menuListener); + popup.show(this, e.getX(), e.getY()); } /* - * Build the overview panel image + * Toggle overview display between showing hidden columns and hiding hidden columns */ - private void buildImage(float sampleRow, float sampleCol) + private void toggleHiddenColumns() { - int lastcol = -1; - int lastrow = -1; - int rgbColour = Color.white.getRGB(); - - SequenceI seq = null; - FeatureColourFinder finder = new FeatureColourFinder(fr); - - final boolean hasHiddenCols = av.hasHiddenColumns(); - boolean hiddenRow = false; - // get hidden row and hidden column map once at beginning. - // clone featureRenderer settings to avoid race conditions... if state is - // updated just need to refresh again - for (int row = 0; row < od.getSequencesHeight() && !resizeAgain; row++) + if (showHidden) { - boolean doCopy = true; - int currentrow = (int) (row * sampleRow); - if (currentrow != lastrow) - { - doCopy = false; - - lastrow = currentrow; - - // get the sequence which would be at alignment index 'lastrow' if no - // rows were hidden, and determine whether it is hidden or not - hiddenRow = av.getAlignment().isHidden(lastrow); - seq = av.getAlignment().getSequenceAtAbsoluteIndex(lastrow); - } - - for (int col = 0; col < od.getWidth() && !resizeAgain; col++) - { - if (doCopy) - { - rgbColour = miniMe.getRGB(col, row - 1); - } - else if ((int) (col * sampleCol) != lastcol - || (int) (row * sampleRow) != lastrow) - { - lastcol = (int) (col * sampleCol); - rgbColour = getColumnColourFromSequence(seq, hiddenRow, - hasHiddenCols, lastcol, finder); - } - // else we just use the color we already have , so don't need to set it - - miniMe.setRGB(col, row, rgbColour); - } + showHidden = false; + od = new OverviewDimensionsHideHidden(av.getRanges(), + (av.isShowAnnotation() && av + .getAlignmentConservationAnnotation() != null)); + } + else + { + showHidden = true; + od = new OverviewDimensionsShowHidden(av.getRanges(), + (av.isShowAnnotation() && av + .getAlignmentConservationAnnotation() != null)); } + oviewCanvas.resetOviewDims(od); + updateOverviewImage(); } - /* - * Find the colour of a sequence at a specified column position + /** + * Updates the overview image when the related alignment panel is updated */ - private int getColumnColourFromSequence( - jalview.datamodel.SequenceI seq, - boolean hiddenRow, boolean hasHiddenCols, int lastcol, - FeatureColourFinder finder) + public void updateOverviewImage() { - Color color = Color.white; - - if ((seq != null) && (seq.getLength() > lastcol)) + if ((getWidth() > 0) && (getHeight() > 0)) { - color = sr.getResidueColour(seq, lastcol, finder); + od.setWidth(getWidth()); + od.setHeight(getHeight()); } + + setPreferredSize(new Dimension(od.getWidth(), od.getHeight())); - if (hiddenRow - || (hasHiddenCols && !av.getColumnSelection() - .isVisible(lastcol))) + if (oviewCanvas.restartDraw()) { - color = color.darker().darker(); + return; } - return color.getRGB(); + Thread thread = new Thread(this); + thread.start(); + repaint(); + + } + + @Override + public void run() + { + oviewCanvas.draw(av.isShowSequenceFeatures(), + (av.isShowAnnotation() && av + .getAlignmentConservationAnnotation() != null), ap + .getSeqPanel().seqCanvas.getFeatureRenderer()); + setBoxPosition(); } /** @@ -321,40 +234,8 @@ public class OverviewPanel extends JPanel implements Runnable */ public void setBoxPosition() { - od.setBoxPosition(av.getAlignment() - .getHiddenSequences(), av.getColumnSelection(), av.getRanges()); + od.setBoxPosition(av.getAlignment().getHiddenSequences(), av + .getAlignment().getHiddenColumns()); repaint(); } - - - @Override - public void paintComponent(Graphics g) - { - if (resizing || resizeAgain) - { - if (lastMiniMe == null) - { - g.setColor(Color.white); - g.fillRect(0, 0, getWidth(), getHeight()); - } - else - { - g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this); - } - g.setColor(TRANS_GREY); - g.fillRect(0, 0, getWidth(), getHeight()); - } - else if (lastMiniMe != null) - { - g.drawImage(lastMiniMe, 0, 0, this); - if (lastMiniMe != miniMe) - { - g.setColor(TRANS_GREY); - g.fillRect(0, 0, getWidth(), getHeight()); - } - } - - g.setColor(Color.red); - od.drawBox(g); - } } diff --git a/src/jalview/gui/PCAPanel.java b/src/jalview/gui/PCAPanel.java index e9ba1e7..d8e6b06 100644 --- a/src/jalview/gui/PCAPanel.java +++ b/src/jalview/gui/PCAPanel.java @@ -27,7 +27,7 @@ import jalview.api.analysis.SimilarityParamsI; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentView; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceI; import jalview.jbgui.GPCAPanel; import jalview.util.MessageManager; @@ -406,7 +406,7 @@ public class PCAPanel extends GPCAPanel implements Runnable, } ; Object[] alAndColsel = pcaModel.getSeqtrings() - .getAlignmentAndColumnSelection(gc); + .getAlignmentAndHiddenColumns(gc); if (alAndColsel != null && alAndColsel[0] != null) { @@ -423,8 +423,8 @@ public class PCAPanel extends GPCAPanel implements Runnable, if (true) { // make a new frame! - AlignFrame af = new AlignFrame(al, - (ColumnSelection) alAndColsel[1], AlignFrame.DEFAULT_WIDTH, + AlignFrame af = new AlignFrame(al, (HiddenColumns) alAndColsel[1], + AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); // >>>This is a fix for the moment, until a better solution is diff --git a/src/jalview/gui/PopupMenu.java b/src/jalview/gui/PopupMenu.java index 1685721..09e3263 100644 --- a/src/jalview/gui/PopupMenu.java +++ b/src/jalview/gui/PopupMenu.java @@ -31,8 +31,8 @@ import jalview.commands.EditCommand.Action; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; -import jalview.datamodel.ColumnSelection; import jalview.datamodel.DBRefEntry; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceFeature; @@ -1446,13 +1446,21 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener { if (sequence != null) { - ColumnSelection cs = ap.av.getColumnSelection(); - if (cs == null) + /* ColumnSelection cs = ap.av.getColumnSelection(); + if (cs == null) + { + cs = new ColumnSelection(); + } + cs.hideInsertionsFor(sequence); + ap.av.setColumnSelection(cs);*/ + + HiddenColumns hidden = ap.av.getAlignment().getHiddenColumns(); + if (hidden == null) { - cs = new ColumnSelection(); + hidden = new HiddenColumns(); } - cs.hideInsertionsFor(sequence); - ap.av.setColumnSelection(cs); + hidden.hideInsertionsFor(sequence); + ap.av.getAlignment().setHiddenColumns(hidden); } refresh(); } diff --git a/src/jalview/gui/ScalePanel.java b/src/jalview/gui/ScalePanel.java index de21be6..90f7cd2 100755 --- a/src/jalview/gui/ScalePanel.java +++ b/src/jalview/gui/ScalePanel.java @@ -21,6 +21,7 @@ package jalview.gui; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.renderer.ScaleRenderer; @@ -106,7 +107,7 @@ public class ScalePanel extends JPanel implements MouseMotionListener, if (av.hasHiddenColumns()) { - x = av.getColumnSelection().adjustForHiddenColumns(x); + x = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(x); } if (x >= av.getAlignment().getWidth()) @@ -172,7 +173,7 @@ public class ScalePanel extends JPanel implements MouseMotionListener, }); pop.add(item); - if (av.getColumnSelection().hasHiddenColumns()) + if (av.getAlignment().getHiddenColumns().hasHiddenColumns()) { item = new JMenuItem(MessageManager.getString("action.reveal_all")); item.addActionListener(new ActionListener() @@ -287,7 +288,8 @@ public class ScalePanel extends JPanel implements MouseMotionListener, if (av.hasHiddenColumns()) { - res = av.getColumnSelection().adjustForHiddenColumns(res); + res = av.getAlignment().getHiddenColumns() + .adjustForHiddenColumns(res); } if (res >= av.getAlignment().getWidth()) @@ -337,11 +339,12 @@ public class ScalePanel extends JPanel implements MouseMotionListener, { mouseDragging = true; ColumnSelection cs = av.getColumnSelection(); + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); int res = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes(); res = Math.max(0, res); - res = cs.adjustForHiddenColumns(res); + res = hidden.adjustForHiddenColumns(res); res = Math.min(res, av.getAlignment().getWidth() - 1); min = Math.min(res, min); max = Math.max(res, max); @@ -394,11 +397,12 @@ public class ScalePanel extends JPanel implements MouseMotionListener, int res = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes(); - res = av.getColumnSelection().adjustForHiddenColumns(res); + res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(res); - if (av.getColumnSelection().getHiddenColumns() != null) + if (av.getAlignment().getHiddenColumns().getHiddenRegions() != null) { - for (int[] region : av.getColumnSelection().getHiddenColumns()) + for (int[] region : av.getAlignment().getHiddenColumns() + .getHiddenRegions()) { if (res + 1 == region[0] || res - 1 == region[1]) { @@ -446,7 +450,9 @@ public class ScalePanel extends JPanel implements MouseMotionListener, // Fill the selected columns ColumnSelection cs = av.getColumnSelection(); - int avCharWidth = av.getCharWidth(), avCharHeight = av.getCharHeight(); + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); + int avCharWidth = av.getCharWidth(); + int avCharHeight = av.getCharHeight(); if (cs != null) { @@ -459,9 +465,9 @@ public class ScalePanel extends JPanel implements MouseMotionListener, if (av.hasHiddenColumns()) { - if (cs.isVisible(sel)) + if (hidden.isVisible(sel)) { - sel = cs.findColumnPosition(sel); + sel = hidden.findColumnPosition(sel); } else { @@ -488,13 +494,13 @@ public class ScalePanel extends JPanel implements MouseMotionListener, // draw any hidden column markers gg.setColor(Color.blue); int res; - if (av.getShowHiddenMarkers() - && av.getColumnSelection().getHiddenColumns() != null) + + if (av.getShowHiddenMarkers() && hidden.getHiddenRegions() != null) { - for (int i = 0; i < av.getColumnSelection().getHiddenColumns() + for (int i = 0; i < hidden.getHiddenRegions() .size(); i++) { - res = av.getColumnSelection().findHiddenRegionPosition(i) + res = hidden.findHiddenRegionPosition(i) - startx; if (res < 0 || res > widthx) diff --git a/src/jalview/gui/SeqCanvas.java b/src/jalview/gui/SeqCanvas.java index 64e5fdc..c2a2ccb 100755 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@ -21,6 +21,7 @@ package jalview.gui; import jalview.datamodel.AlignmentI; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SearchResultsI; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; @@ -165,14 +166,17 @@ public class SeqCanvas extends JComponent if (av.hasHiddenColumns()) { - startx = av.getColumnSelection().adjustForHiddenColumns(startx); - endx = av.getColumnSelection().adjustForHiddenColumns(endx); + startx = av.getAlignment().getHiddenColumns() + .adjustForHiddenColumns(startx); + endx = av.getAlignment().getHiddenColumns() + .adjustForHiddenColumns(endx); } int maxwidth = av.getAlignment().getWidth(); if (av.hasHiddenColumns()) { - maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1; + maxwidth = av.getAlignment().getHiddenColumns() + .findColumnPosition(maxwidth) - 1; } // WEST SCALE @@ -224,7 +228,8 @@ public class SeqCanvas extends JComponent if (av.hasHiddenColumns()) { - endx = av.getColumnSelection().adjustForHiddenColumns(endx); + endx = av.getAlignment().getHiddenColumns() + .adjustForHiddenColumns(endx); } SequenceI seq; @@ -515,7 +520,8 @@ public class SeqCanvas extends JComponent if (av.hasHiddenColumns()) { - maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1; + maxwidth = av.getAlignment().getHiddenColumns() + .findColumnPosition(maxwidth) - 1; } while ((ypos <= canvasHeight) && (startRes < maxwidth)) @@ -553,11 +559,10 @@ public class SeqCanvas extends JComponent { g.setColor(Color.blue); int res; - for (int i = 0; i < av.getColumnSelection().getHiddenColumns() - .size(); i++) + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); + for (int i = 0; i < hidden.getHiddenRegions().size(); i++) { - res = av.getColumnSelection().findHiddenRegionPosition(i) - - startRes; + res = hidden.findHiddenRegionPosition(i) - startRes; if (res < 0 || res > endx - startRes) { @@ -654,7 +659,8 @@ public class SeqCanvas extends JComponent } else { - List regions = av.getColumnSelection().getHiddenColumns(); + List regions = av.getAlignment().getHiddenColumns() + .getHiddenRegions(); int screenY = 0; int blockStart = startRes; diff --git a/src/jalview/gui/SeqPanel.java b/src/jalview/gui/SeqPanel.java index 1432fcb..a2c2bd9 100644 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@ -27,6 +27,7 @@ import jalview.commands.EditCommand.Action; import jalview.commands.EditCommand.Edit; import jalview.datamodel.AlignmentI; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SearchResultMatchI; import jalview.datamodel.SearchResults; import jalview.datamodel.SearchResultsI; @@ -233,7 +234,8 @@ public class SeqPanel extends JPanel implements MouseListener, if (av.hasHiddenColumns()) { - res = av.getColumnSelection().adjustForHiddenColumns(res); + res = av.getAlignment().getHiddenColumns() + .adjustForHiddenColumns(res); } return res; @@ -339,20 +341,23 @@ public class SeqPanel extends JPanel implements MouseListener, { seqCanvas.cursorX += dx; seqCanvas.cursorY += dy; + + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); + if (av.hasHiddenColumns() - && !av.getColumnSelection().isVisible(seqCanvas.cursorX)) + && !hidden.isVisible(seqCanvas.cursorX)) { int original = seqCanvas.cursorX - dx; int maxWidth = av.getAlignment().getWidth(); - while (!av.getColumnSelection().isVisible(seqCanvas.cursorX) + while (!hidden.isVisible(seqCanvas.cursorX) && seqCanvas.cursorX < maxWidth && seqCanvas.cursorX > 0) { seqCanvas.cursorX += dx; } if (seqCanvas.cursorX >= maxWidth - || !av.getColumnSelection().isVisible(seqCanvas.cursorX)) + || !hidden.isVisible(seqCanvas.cursorX)) { seqCanvas.cursorX = original; } @@ -392,22 +397,23 @@ public class SeqPanel extends JPanel implements MouseListener, { ap.scrollUp(true); } - while (seqCanvas.cursorY + 1 > av.getRanges().getEndSeq()) + while (seqCanvas.cursorY > av.getRanges().getEndSeq()) { ap.scrollUp(false); } if (!av.getWrapAlignment()) { - while (seqCanvas.cursorX < av.getColumnSelection() - .adjustForHiddenColumns(av.getRanges().getStartRes())) + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); + while (seqCanvas.cursorX < hidden.adjustForHiddenColumns(av + .getRanges().getStartRes())) { if (!ap.scrollRight(false)) { break; } } - while (seqCanvas.cursorX > av.getColumnSelection() - .adjustForHiddenColumns(av.getRanges().getEndRes())) + while (seqCanvas.cursorX > hidden.adjustForHiddenColumns(av + .getRanges().getEndRes())) { if (!ap.scrollRight(true)) { @@ -945,30 +951,36 @@ public class SeqPanel extends JPanel implements MouseListener, } /** - * DOCUMENT ME! - * - * @param evt - * DOCUMENT ME! + * {@inheritDoc} */ @Override public void mouseDragged(MouseEvent evt) { if (mouseWheelPressed) { + boolean inSplitFrame = ap.av.getCodingComplement() != null; + boolean copyChanges = inSplitFrame && av.isProteinFontAsCdna(); + int oldWidth = av.getCharWidth(); // Which is bigger, left-right or up-down? if (Math.abs(evt.getY() - lastMousePress.getY()) > Math.abs(evt .getX() - lastMousePress.getX())) { + /* + * on drag up or down, decrement or increment font size + */ int fontSize = av.font.getSize(); + boolean fontChanged = false; if (evt.getY() < lastMousePress.getY()) { + fontChanged = true; fontSize--; } else if (evt.getY() > lastMousePress.getY()) { + fontChanged = true; fontSize++; } @@ -977,24 +989,56 @@ public class SeqPanel extends JPanel implements MouseListener, fontSize = 1; } - av.setFont( - new Font(av.font.getName(), av.font.getStyle(), fontSize), - true); - av.setCharWidth(oldWidth); - ap.fontChanged(); + if (fontChanged) + { + Font newFont = new Font(av.font.getName(), av.font.getStyle(), + fontSize); + av.setFont(newFont, true); + av.setCharWidth(oldWidth); + ap.fontChanged(); + if (copyChanges) + { + ap.av.getCodingComplement().setFont(newFont, true); + SplitFrame splitFrame = (SplitFrame) ap.alignFrame + .getSplitViewContainer(); + splitFrame.adjustLayout(); + splitFrame.repaint(); + } + } } else { + /* + * on drag left or right, decrement or increment character width + */ + int newWidth = 0; if (evt.getX() < lastMousePress.getX() && av.getCharWidth() > 1) { - av.setCharWidth(av.getCharWidth() - 1); + newWidth = av.getCharWidth() - 1; + av.setCharWidth(newWidth); } else if (evt.getX() > lastMousePress.getX()) { - av.setCharWidth(av.getCharWidth() + 1); + newWidth = av.getCharWidth() + 1; + av.setCharWidth(newWidth); + } + if (newWidth > 0) + { + ap.paintAlignment(false); + if (copyChanges) + { + /* + * need to ensure newWidth is set on cdna, regardless of which + * panel the mouse drag happened in; protein will compute its + * character width as 1:1 or 3:1 + */ + av.getCodingComplement().setCharWidth(newWidth); + SplitFrame splitFrame = (SplitFrame) ap.alignFrame + .getSplitViewContainer(); + splitFrame.adjustLayout(); + splitFrame.repaint(); + } } - - ap.paintAlignment(false); } FontMetrics fm = getFontMetrics(av.getFont()); @@ -1144,8 +1188,10 @@ public class SeqPanel extends JPanel implements MouseListener, if (av.hasHiddenColumns()) { fixedColumns = true; - int y1 = av.getColumnSelection().getHiddenBoundaryLeft(startres); - int y2 = av.getColumnSelection().getHiddenBoundaryRight(startres); + int y1 = av.getAlignment().getHiddenColumns() + .getHiddenBoundaryLeft(startres); + int y2 = av.getAlignment().getHiddenColumns() + .getHiddenBoundaryRight(startres); if ((insertGap && startres > y1 && lastres < y1) || (!insertGap && startres < y2 && lastres > y2)) @@ -1220,8 +1266,8 @@ public class SeqPanel extends JPanel implements MouseListener, { if (sg.getSize() == av.getAlignment().getHeight()) { - if ((av.hasHiddenColumns() && startres < av - .getColumnSelection().getHiddenBoundaryRight(startres))) + if ((av.hasHiddenColumns() && startres < av.getAlignment() + .getHiddenColumns().getHiddenBoundaryRight(startres))) { endEditing(); return; @@ -1957,7 +2003,7 @@ public class SeqPanel extends JPanel implements MouseListener, */ @Override public void selection(SequenceGroup seqsel, ColumnSelection colsel, - SelectionSource source) + HiddenColumns hidden, SelectionSource source) { // TODO: fix this hack - source of messages is align viewport, but SeqPanel // handles selection messages... @@ -1993,7 +2039,7 @@ public class SeqPanel extends JPanel implements MouseListener, * Check for selection in a view of which this one is a dna/protein * complement. */ - if (selectionFromTranslation(seqsel, colsel, source)) + if (selectionFromTranslation(seqsel, colsel, hidden, source)) { return; } @@ -2056,7 +2102,8 @@ public class SeqPanel extends JPanel implements MouseListener, } else { - av.getColumnSelection().setElementsFrom(colsel); + av.getColumnSelection().setElementsFrom(colsel, + av.getAlignment().getHiddenColumns()); } } av.isColSelChanged(true); @@ -2065,8 +2112,8 @@ public class SeqPanel extends JPanel implements MouseListener, if (copycolsel && av.hasHiddenColumns() - && (av.getColumnSelection() == null || av.getColumnSelection() - .getHiddenColumns() == null)) + && (av.getAlignment().getHiddenColumns() == null || av + .getAlignment().getHiddenColumns().getHiddenRegions() == null)) { System.err.println("Bad things"); } @@ -2095,7 +2142,8 @@ public class SeqPanel extends JPanel implements MouseListener, * @param source */ protected boolean selectionFromTranslation(SequenceGroup seqsel, - ColumnSelection colsel, SelectionSource source) + ColumnSelection colsel, HiddenColumns hidden, + SelectionSource source) { if (!(source instanceof AlignViewportI)) { @@ -2118,9 +2166,13 @@ public class SeqPanel extends JPanel implements MouseListener, /* * Map column selection */ - ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv, - av); + // ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv, + // av); + ColumnSelection cs = new ColumnSelection(); + HiddenColumns hs = new HiddenColumns(); + MappingUtils.mapColumnSelection(colsel, hidden, sourceAv, av, cs, hs); av.setColumnSelection(cs); + av.getAlignment().setHiddenColumns(hs); // lastly, update any dependent dialogs if (ap.getCalculationDialog() != null) diff --git a/src/jalview/gui/SequenceRenderer.java b/src/jalview/gui/SequenceRenderer.java index 91c3f0f..36825ea 100755 --- a/src/jalview/gui/SequenceRenderer.java +++ b/src/jalview/gui/SequenceRenderer.java @@ -20,6 +20,7 @@ */ package jalview.gui; +import jalview.api.AlignViewportI; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.renderer.ResidueShaderI; @@ -34,7 +35,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer { final static int CHAR_TO_UPPER = 'A' - 'a'; - AlignViewport av; + AlignViewportI av; FontMetrics fm; @@ -57,7 +58,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer * * @param viewport */ - public SequenceRenderer(AlignViewport viewport) + public SequenceRenderer(AlignViewportI viewport) { this.av = viewport; } @@ -181,7 +182,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer drawBoxes(seq, start, end, y1); - if (av.validCharWidth) + if (av.isValidCharWidth()) { drawText(seq, start, end, y1); } diff --git a/src/jalview/gui/SplitFrame.java b/src/jalview/gui/SplitFrame.java index 6c849c3..1d929e6 100644 --- a/src/jalview/gui/SplitFrame.java +++ b/src/jalview/gui/SplitFrame.java @@ -21,7 +21,6 @@ package jalview.gui; import jalview.api.SplitContainerI; -import jalview.api.ViewStyleI; import jalview.datamodel.AlignmentI; import jalview.jbgui.GAlignFrame; import jalview.jbgui.GSplitFrame; @@ -189,10 +188,8 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI : (!bottomAlignment.isNucleotide() ? bottomViewport : null); if (protein != null && cdna != null) { - ViewStyleI vs = protein.getViewStyle(); - int scale = vs.isScaleProteinAsCdna() ? 3 : 1; - vs.setCharWidth(scale * cdna.getViewStyle().getCharWidth()); - protein.setViewStyle(vs); + int scale = protein.isScaleProteinAsCdna() ? 3 : 1; + protein.setCharWidth(scale * cdna.getViewStyle().getCharWidth()); } } diff --git a/src/jalview/gui/StructureChooser.java b/src/jalview/gui/StructureChooser.java index ee22ae4..3e516a6 100644 --- a/src/jalview/gui/StructureChooser.java +++ b/src/jalview/gui/StructureChooser.java @@ -53,7 +53,6 @@ import java.util.Vector; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; -import javax.swing.JOptionPane; import javax.swing.table.AbstractTableModel; /** @@ -542,26 +541,26 @@ public class StructureChooser extends GStructureChooser implements if (haveData) { cmb_filterOption.addItem(new FilterOption("Best Quality", - "overall_quality", VIEWS_FILTER)); + "overall_quality", VIEWS_FILTER, false)); cmb_filterOption.addItem(new FilterOption("Best Resolution", - "resolution", VIEWS_FILTER)); + "resolution", VIEWS_FILTER, false)); cmb_filterOption.addItem(new FilterOption("Most Protein Chain", - "number_of_protein_chains", VIEWS_FILTER)); + "number_of_protein_chains", VIEWS_FILTER, false)); cmb_filterOption.addItem(new FilterOption("Most Bound Molecules", - "number_of_bound_molecules", VIEWS_FILTER)); + "number_of_bound_molecules", VIEWS_FILTER, false)); cmb_filterOption.addItem(new FilterOption("Most Polymer Residues", - "number_of_polymer_residues", VIEWS_FILTER)); + "number_of_polymer_residues", VIEWS_FILTER, true)); } cmb_filterOption.addItem(new FilterOption("Enter PDB Id", "-", - VIEWS_ENTER_ID)); + VIEWS_ENTER_ID, false)); cmb_filterOption.addItem(new FilterOption("From File", "-", - VIEWS_FROM_FILE)); - FilterOption cachedOption = new FilterOption("Cached PDB Entries", "-", - VIEWS_LOCAL_PDB); - cmb_filterOption.addItem(cachedOption); + VIEWS_FROM_FILE, false)); - if (/*!haveData &&*/cachedPDBExists) + if (cachedPDBExists) { + FilterOption cachedOption = new FilterOption("Cached PDB Entries", + "-", VIEWS_LOCAL_PDB, false); + cmb_filterOption.addItem(cachedOption); cmb_filterOption.setSelectedItem(cachedOption); } diff --git a/src/jalview/gui/StructureViewerBase.java b/src/jalview/gui/StructureViewerBase.java index d7f7c31..e37627d 100644 --- a/src/jalview/gui/StructureViewerBase.java +++ b/src/jalview/gui/StructureViewerBase.java @@ -23,7 +23,7 @@ package jalview.gui; import jalview.bin.Cache; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.gui.StructureViewer.ViewerType; @@ -812,7 +812,7 @@ public abstract class StructureViewerBase extends GStructureViewer try { AlignmentI[] als = new Alignment[_alignwith.size()]; - ColumnSelection[] alc = new ColumnSelection[_alignwith.size()]; + HiddenColumns[] alc = new HiddenColumns[_alignwith.size()]; int[] alm = new int[_alignwith.size()]; int a = 0; @@ -820,7 +820,7 @@ public abstract class StructureViewerBase extends GStructureViewer { als[a] = ap.av.getAlignment(); alm[a] = -1; - alc[a++] = ap.av.getColumnSelection(); + alc[a++] = ap.av.getAlignment().getHiddenColumns(); } reply = getBinding().superposeStructures(als, alm, alc); if (reply != null) diff --git a/src/jalview/gui/TreePanel.java b/src/jalview/gui/TreePanel.java index 9dd805e..35998eb 100755 --- a/src/jalview/gui/TreePanel.java +++ b/src/jalview/gui/TreePanel.java @@ -35,8 +35,8 @@ import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentView; import jalview.datamodel.BinaryNode; -import jalview.datamodel.ColumnSelection; import jalview.datamodel.DBRefEntry; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.NodeTransformI; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; @@ -432,8 +432,7 @@ public class TreePanel extends GTreePanel { } - Object[] alAndColsel = originalData - .getAlignmentAndColumnSelection(gc); + Object[] alAndColsel = originalData.getAlignmentAndHiddenColumns(gc); if (alAndColsel != null && alAndColsel[0] != null) { @@ -450,8 +449,8 @@ public class TreePanel extends GTreePanel if (true) { // make a new frame! - AlignFrame af = new AlignFrame(al, - (ColumnSelection) alAndColsel[1], AlignFrame.DEFAULT_WIDTH, + AlignFrame af = new AlignFrame(al, (HiddenColumns) alAndColsel[1], + AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); // >>>This is a fix for the moment, until a better solution is diff --git a/src/jalview/gui/VamsasApplication.java b/src/jalview/gui/VamsasApplication.java index 75ddba5..d58cb5a 100644 --- a/src/jalview/gui/VamsasApplication.java +++ b/src/jalview/gui/VamsasApplication.java @@ -23,6 +23,7 @@ package jalview.gui; import jalview.bin.Cache; import jalview.datamodel.AlignmentI; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.io.VamsasAppDatastore; @@ -43,7 +44,6 @@ import java.util.IdentityHashMap; import java.util.Iterator; import javax.swing.JInternalFrame; -import javax.swing.JOptionPane; import uk.ac.vamsas.client.ClientHandle; import uk.ac.vamsas.client.IClient; @@ -821,7 +821,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource { // TODO: rationalise : can only clear a selection over a // referred to object - ssm.sendSelection(null, null, me); + ssm.sendSelection(null, null, null, me); return; } Class type = null; @@ -955,7 +955,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource } if (send) { - ssm.sendSelection(jselection, colsel, me); + ssm.sendSelection(jselection, colsel, null, me); } // discard message. for (int c = 0; c < jvobjs.length; c++) @@ -1004,7 +1004,8 @@ public class VamsasApplication implements SelectionSource, VamsasSource @Override public void selection(SequenceGroup seqsel, - ColumnSelection colsel, SelectionSource source) + ColumnSelection colsel, HiddenColumns hidden, + SelectionSource source) { if (vobj2jv == null) { @@ -1079,7 +1080,9 @@ public class VamsasApplication implements SelectionSource, VamsasSource } else { - int[] intervals = colsel.getVisibleContigs( + // int[] intervals = colsel.getVisibleContigs( + // seqsel.getStartRes(), seqsel.getEndRes() + 1); + int[] intervals = hidden.getVisibleContigs( seqsel.getStartRes(), seqsel.getEndRes() + 1); for (int iv = 0; iv < intervals.length; iv += 2) { diff --git a/src/jalview/io/AnnotationFile.java b/src/jalview/io/AnnotationFile.java index ef903e3..c3e71da 100755 --- a/src/jalview/io/AnnotationFile.java +++ b/src/jalview/io/AnnotationFile.java @@ -27,6 +27,7 @@ import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; import jalview.datamodel.ColumnSelection; import jalview.datamodel.GraphLine; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.HiddenSequences; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; @@ -114,14 +115,12 @@ public class AnnotationFile public final HiddenSequences hidseqs; - public final ColumnSelection hiddencols; - - // public final Vector visibleGroups; + public final HiddenColumns hiddencols; public final Hashtable hiddenRepSeqs; public ViewDef(String vname, HiddenSequences hseqs, - ColumnSelection hcols, Hashtable hRepSeqs) + HiddenColumns hcols, Hashtable hRepSeqs) { this.viewname = vname; this.hidseqs = hseqs; @@ -142,7 +141,8 @@ public class AnnotationFile */ public String printAnnotations(AlignmentAnnotation[] annotations, List list, Hashtable properties, - ColumnSelection cs, AlignmentI al, ViewDef view) + HiddenColumns cs, + AlignmentI al, ViewDef view) { if (view != null) { @@ -171,7 +171,7 @@ public class AnnotationFile if (cs != null && cs.hasHiddenColumns()) { text.append("VIEW_HIDECOLS\t"); - List hc = cs.getHiddenColumns(); + List hc = cs.getHiddenRegions(); boolean comma = false; for (int[] r : hc) { @@ -666,15 +666,21 @@ public class AnnotationFile String file, DataSourceType protocol) { ColumnSelection colSel = viewport.getColumnSelection(); + HiddenColumns hidden = viewport.getAlignment().getHiddenColumns(); if (colSel == null) { colSel = new ColumnSelection(); } - boolean rslt = readAnnotationFile(viewport.getAlignment(), colSel, + if (hidden == null) + { + hidden = new HiddenColumns(); + } + boolean rslt = readAnnotationFile(viewport.getAlignment(), hidden, file, protocol); - if (rslt && (colSel.hasSelectedColumns() || colSel.hasHiddenColumns())) + if (rslt && (colSel.hasSelectedColumns() || hidden.hasHiddenColumns())) { viewport.setColumnSelection(colSel); + viewport.getAlignment().setHiddenColumns(hidden); } return rslt; @@ -686,7 +692,7 @@ public class AnnotationFile return readAnnotationFile(al, null, file, sourceType); } - public boolean readAnnotationFile(AlignmentI al, ColumnSelection colSel, + public boolean readAnnotationFile(AlignmentI al, HiddenColumns hidden, String file, DataSourceType sourceType) { BufferedReader in = null; @@ -715,7 +721,7 @@ public class AnnotationFile } if (in != null) { - return parseAnnotationFrom(al, colSel, in); + return parseAnnotationFrom(al, hidden, in); } } catch (Exception ex) @@ -738,7 +744,7 @@ public class AnnotationFile private static String GRAPHLINE = "GRAPHLINE", COMBINE = "COMBINE"; - public boolean parseAnnotationFrom(AlignmentI al, ColumnSelection colSel, + public boolean parseAnnotationFrom(AlignmentI al, HiddenColumns hidden, BufferedReader in) throws Exception { nlinesread = 0; @@ -949,11 +955,11 @@ public class AnnotationFile { if (st.hasMoreTokens()) { - if (colSel == null) + if (hidden == null) { - colSel = new ColumnSelection(); + hidden = new HiddenColumns(); } - parseHideCols(colSel, st.nextToken()); + parseHideCols(hidden, st.nextToken()); } modified = true; continue; @@ -967,7 +973,7 @@ public class AnnotationFile } if (sr != null) { - if (colSel == null) + if (hidden == null) { System.err .println("Cannot process HIDE_INSERTIONS without an alignment view: Ignoring line: " @@ -976,7 +982,7 @@ public class AnnotationFile else { // consider deferring this till after the file has been parsed ? - colSel.hideInsertionsFor(sr); + hidden.hideInsertionsFor(sr); } } modified = true; @@ -1182,7 +1188,7 @@ public class AnnotationFile return modified; } - private void parseHideCols(ColumnSelection colSel, String nextToken) + private void parseHideCols(HiddenColumns hidden, String nextToken) { StringTokenizer inval = new StringTokenizer(nextToken, ","); while (inval.hasMoreTokens()) @@ -1194,7 +1200,7 @@ public class AnnotationFile from = to = Integer.parseInt(range); if (from >= 0) { - colSel.hideColumns(from, to); + hidden.hideColumns(from, to); } } else @@ -1210,7 +1216,7 @@ public class AnnotationFile } if (from > 0 && to >= from) { - colSel.hideColumns(from, to); + hidden.hideColumns(from, to); } } } @@ -1789,7 +1795,7 @@ public class AnnotationFile return printAnnotations(viewport.isShowAnnotation() ? viewport .getAlignment().getAlignmentAnnotation() : null, viewport .getAlignment().getGroups(), viewport.getAlignment() - .getProperties(), viewport.getColumnSelection(), + .getProperties(), viewport.getAlignment().getHiddenColumns(), viewport.getAlignment(), null); } diff --git a/src/jalview/io/FileLoader.java b/src/jalview/io/FileLoader.java index 4f83ab1..7c6d181 100755 --- a/src/jalview/io/FileLoader.java +++ b/src/jalview/io/FileLoader.java @@ -27,7 +27,7 @@ import jalview.api.FeaturesSourceI; import jalview.bin.Cache; import jalview.bin.Jalview; import jalview.datamodel.AlignmentI; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; @@ -372,8 +372,8 @@ public class FileLoader implements Runnable if (source instanceof ComplexAlignFile) { - ColumnSelection colSel = ((ComplexAlignFile) source) - .getColumnSelection(); + HiddenColumns colSel = ((ComplexAlignFile) source) + .getHiddenColumns(); SequenceI[] hiddenSeqs = ((ComplexAlignFile) source) .getHiddenSequences(); String colourSchemeName = ((ComplexAlignFile) source) diff --git a/src/jalview/io/FormatAdapter.java b/src/jalview/io/FormatAdapter.java index d9dd79d..f09e8a0 100755 --- a/src/jalview/io/FormatAdapter.java +++ b/src/jalview/io/FormatAdapter.java @@ -26,7 +26,7 @@ import jalview.bin.Cache; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; @@ -165,14 +165,14 @@ public class FormatAdapter extends AppletFormatAdapter } public String formatSequences(FileFormatI format, AlignmentI alignment, - String[] omitHidden, int[] exportRange, ColumnSelection colSel) + String[] omitHidden, int[] exportRange, HiddenColumns hidden) { return formatSequences(format, alignment, omitHidden, exportRange, - getCacheSuffixDefault(format), colSel, null); + getCacheSuffixDefault(format), hidden, null); } /** - * hack function to replace seuqences with visible sequence strings before + * hack function to replace sequences with visible sequence strings before * generating a string of the alignment in the given format. * * @param format @@ -185,15 +185,15 @@ public class FormatAdapter extends AppletFormatAdapter */ public String formatSequences(FileFormatI format, AlignmentI alignment, String[] omitHidden, int[] exportRange, boolean suffix, - ColumnSelection colSel) + HiddenColumns hidden) { return formatSequences(format, alignment, omitHidden, exportRange, - suffix, colSel, null); + suffix, hidden, null); } public String formatSequences(FileFormatI format, AlignmentI alignment, String[] omitHidden, int[] exportRange, boolean suffix, - ColumnSelection colSel, SequenceGroup selgp) + HiddenColumns hidden, SequenceGroup selgp) { if (omitHidden != null) { @@ -211,12 +211,12 @@ public class FormatAdapter extends AppletFormatAdapter AlignmentAnnotation na = new AlignmentAnnotation(ala[i]); if (selgp != null) { - colSel.makeVisibleAnnotation(selgp.getStartRes(), + hidden.makeVisibleAnnotation(selgp.getStartRes(), selgp.getEndRes(), na); } else { - colSel.makeVisibleAnnotation(na); + hidden.makeVisibleAnnotation(na); } alv.addAnnotation(na); } diff --git a/src/jalview/io/HTMLOutput.java b/src/jalview/io/HTMLOutput.java index 68f3e2c..77006db 100755 --- a/src/jalview/io/HTMLOutput.java +++ b/src/jalview/io/HTMLOutput.java @@ -91,8 +91,8 @@ public abstract class HTMLOutput implements Runnable String bioJSON = new FormatAdapter(ap, exportData.getSettings()) .formatSequences(FileFormat.Json, exportData.getAlignment(), exportData.getOmitHidden(), exportData - .getStartEndPostions(), ap.getAlignViewport() - .getColumnSelection()); +.getStartEndPostions(), ap.getAlignViewport() + .getAlignment().getHiddenColumns()); return bioJSON; } diff --git a/src/jalview/io/HtmlFile.java b/src/jalview/io/HtmlFile.java index af3fb5d..9256278 100644 --- a/src/jalview/io/HtmlFile.java +++ b/src/jalview/io/HtmlFile.java @@ -24,7 +24,7 @@ package jalview.io; import jalview.api.ComplexAlignFile; import jalview.api.FeatureSettingsModelI; import jalview.api.FeaturesDisplayedI; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceI; import java.io.IOException; @@ -44,7 +44,7 @@ public class HtmlFile extends AlignFile implements ComplexAlignFile private boolean showSeqFeatures; - private ColumnSelection columnSelection; + private HiddenColumns hiddenColumns; private SequenceI[] hiddenSequences; @@ -111,7 +111,7 @@ public class HtmlFile extends AlignFile implements ComplexAlignFile this.showSeqFeatures = jsonFile.isShowSeqFeatures(); this.globalColourScheme = jsonFile.getGlobalColourScheme(); this.hiddenSequences = jsonFile.getHiddenSequences(); - this.columnSelection = jsonFile.getColumnSelection(); + this.hiddenColumns = jsonFile.getHiddenColumns(); this.displayedFeatures = jsonFile.getDisplayedFeatures(); } catch (Exception e) { @@ -149,14 +149,14 @@ public class HtmlFile extends AlignFile implements ComplexAlignFile } @Override - public ColumnSelection getColumnSelection() + public HiddenColumns getHiddenColumns() { - return columnSelection; + return hiddenColumns; } - public void setColumnSelection(ColumnSelection columnSelection) + public void setHiddenColumns(HiddenColumns hidden) { - this.columnSelection = columnSelection; + this.hiddenColumns = hidden; } @Override diff --git a/src/jalview/io/JSONFile.java b/src/jalview/io/JSONFile.java index 20148b4..816346a 100644 --- a/src/jalview/io/JSONFile.java +++ b/src/jalview/io/JSONFile.java @@ -32,7 +32,7 @@ import jalview.bin.BuildDetails; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.HiddenSequences; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceFeature; @@ -84,9 +84,7 @@ public class JSONFile extends AlignFile implements ComplexAlignFile private FeatureRenderer fr; - private List hiddenColumns; - - private ColumnSelection columnSelection; + private HiddenColumns hiddenColumns; private List hiddenSeqRefs; @@ -281,8 +279,9 @@ public class JSONFile extends AlignFile implements ComplexAlignFile // hidden column business if (getViewport().hasHiddenColumns()) { - List hiddenCols = getViewport().getColumnSelection() - .getHiddenColumns(); + List hiddenCols = getViewport().getAlignment() + .getHiddenColumns() + .getHiddenRegions(); StringBuilder hiddenColsBuilder = new StringBuilder(); for (int[] range : hiddenCols) { @@ -667,12 +666,12 @@ public class JSONFile extends AlignFile implements ComplexAlignFile String hiddenCols = (String) jvSettingsJson.get("hiddenCols"); if (hiddenCols != null && !hiddenCols.isEmpty()) { - columnSelection = new ColumnSelection(); + hiddenColumns = new HiddenColumns(); String[] rangeStrings = hiddenCols.split(";"); for (String rangeString : rangeStrings) { String[] range = rangeString.split("-"); - columnSelection.hideColumns(Integer.valueOf(range[0]), + hiddenColumns.hideColumns(Integer.valueOf(range[0]), Integer.valueOf(range[1])); } } @@ -791,20 +790,15 @@ public class JSONFile extends AlignFile implements ComplexAlignFile return annotations; } - public List getHiddenColumns() - { - return hiddenColumns; - } - @Override - public ColumnSelection getColumnSelection() + public HiddenColumns getHiddenColumns() { - return columnSelection; + return hiddenColumns; } - public void setColumnSelection(ColumnSelection columnSelection) + public void setHiddenColumns(HiddenColumns hidden) { - this.columnSelection = columnSelection; + this.hiddenColumns = hidden; } @Override diff --git a/src/jalview/javascript/JsSelectionSender.java b/src/jalview/javascript/JsSelectionSender.java index dc08b59..fdf8b58 100644 --- a/src/jalview/javascript/JsSelectionSender.java +++ b/src/jalview/javascript/JsSelectionSender.java @@ -23,6 +23,7 @@ package jalview.javascript; import jalview.appletgui.AlignFrame; import jalview.bin.JalviewLite; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceGroup; import jalview.structure.SelectionSource; @@ -44,7 +45,7 @@ public class JsSelectionSender extends JSFunctionExec implements @Override public void selection(SequenceGroup seqsel, ColumnSelection colsel, - SelectionSource source) + HiddenColumns hidden, SelectionSource source) { // System.err.println("Testing selection event relay to jsfunction:"+_listener); try diff --git a/src/jalview/jbgui/GAlignFrame.java b/src/jalview/jbgui/GAlignFrame.java index 58034d9..88cc0a8 100755 --- a/src/jalview/jbgui/GAlignFrame.java +++ b/src/jalview/jbgui/GAlignFrame.java @@ -1853,12 +1853,6 @@ public class GAlignFrame extends JInternalFrame // selectMenu.add(listenToViewSelections); } - protected void configureSelectMenu() - { - // TODO Auto-generated method stub - - } - /** * Constructs the entries on the Colour menu (but does not add them to the * menu). diff --git a/src/jalview/jbgui/GFontChooser.java b/src/jalview/jbgui/GFontChooser.java index 8c893a2..5c15e80 100755 --- a/src/jalview/jbgui/GFontChooser.java +++ b/src/jalview/jbgui/GFontChooser.java @@ -63,6 +63,8 @@ public class GFontChooser extends JPanel protected JCheckBox scaleAsCdna = new JCheckBox(); + protected JCheckBox fontAsCdna = new JCheckBox(); + /** * Creates a new GFontChooser object. */ @@ -98,9 +100,10 @@ public class GFontChooser extends JPanel fontSize.setPreferredSize(new Dimension(50, 21)); fontSize.addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(ActionEvent e) { - fontSize_actionPerformed(e); + fontSize_actionPerformed(); } }); @@ -109,9 +112,10 @@ public class GFontChooser extends JPanel fontStyle.setPreferredSize(new Dimension(90, 21)); fontStyle.addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(ActionEvent e) { - fontStyle_actionPerformed(e); + fontStyle_actionPerformed(); } }); @@ -132,9 +136,10 @@ public class GFontChooser extends JPanel fontName.setPreferredSize(new Dimension(180, 21)); fontName.addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(ActionEvent e) { - fontName_actionPerformed(e); + fontName_actionPerformed(); } }); @@ -142,9 +147,10 @@ public class GFontChooser extends JPanel ok.setFont(VERDANA_11PT); ok.addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(ActionEvent e) { - ok_actionPerformed(e); + ok_actionPerformed(); } }); @@ -152,9 +158,10 @@ public class GFontChooser extends JPanel cancel.setFont(VERDANA_11PT); cancel.addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(ActionEvent e) { - cancel_actionPerformed(e); + cancel_actionPerformed(); } }); @@ -162,37 +169,57 @@ public class GFontChooser extends JPanel defaultButton.setText(MessageManager.getString("label.set_as_default")); defaultButton.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { - defaultButton_actionPerformed(e); + defaultButton_actionPerformed(); } }); smoothFont.setFont(JvSwingUtils.getLabelFont()); smoothFont.setOpaque(false); smoothFont.setText(MessageManager.getString("label.anti_alias_fonts")); - smoothFont.setBounds(new Rectangle(41, 65, 260, 23)); + smoothFont.setBounds(new Rectangle(1, 65, 300, 23)); smoothFont.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { - smoothFont_actionPerformed(e); + smoothFont_actionPerformed(); } }); /* - * Scale protein as cDNA is only visible in SplitFrame protein alignment + * Scale protein as cDNA is only visible in SplitFrame */ scaleAsCdna.setVisible(false); scaleAsCdna.setFont(JvSwingUtils.getLabelFont()); scaleAsCdna.setOpaque(false); scaleAsCdna.setText(MessageManager.getString("label.scale_as_cdna")); - scaleAsCdna.setBounds(new Rectangle(41, 85, 260, 23)); + scaleAsCdna.setBounds(new Rectangle(1, 85, 300, 23)); scaleAsCdna.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) + { + scaleAsCdna_actionPerformed(); + } + }); + + /* + * Same font for cDNA/peptide is only visible in SplitFrame + */ + fontAsCdna.setVisible(false); + fontAsCdna.setFont(JvSwingUtils.getLabelFont()); + fontAsCdna.setOpaque(false); + fontAsCdna.setText(MessageManager.getString("label.font_as_cdna")); + fontAsCdna.setBounds(new Rectangle(1, 105, 350, 23)); + fontAsCdna.addActionListener(new ActionListener() + { + @Override public void actionPerformed(ActionEvent e) { - scaleAsCdna_actionPerformed(e); + mirrorFonts_actionPerformed(); } }); @@ -239,85 +266,53 @@ public class GFontChooser extends JPanel */ JPanel jPanel4 = new JPanel(); jPanel4.setOpaque(false); - jPanel4.setBounds(new Rectangle(24, 112, 300, 35)); + jPanel4.setBounds(new Rectangle(24, 132, 300, 35)); jPanel4.add(defaultButton); jPanel4.add(ok); jPanel4.add(cancel); this.add(smoothFont); this.add(scaleAsCdna); + this.add(fontAsCdna); this.add(jPanel3, null); this.add(jPanel2, null); this.add(jPanel4); this.add(jPanel1, null); } - protected void scaleAsCdna_actionPerformed(ActionEvent e) + protected void mirrorFonts_actionPerformed() { } - /** - * DOCUMENT ME! - * - * @param e - * DOCUMENT ME! - */ - protected void ok_actionPerformed(ActionEvent e) + protected void scaleAsCdna_actionPerformed() { } - /** - * DOCUMENT ME! - * - * @param e - * DOCUMENT ME! - */ - protected void cancel_actionPerformed(ActionEvent e) + protected void ok_actionPerformed() { } - /** - * DOCUMENT ME! - * - * @param e - * DOCUMENT ME! - */ - protected void fontName_actionPerformed(ActionEvent e) + protected void cancel_actionPerformed() { } - /** - * DOCUMENT ME! - * - * @param e - * DOCUMENT ME! - */ - protected void fontSize_actionPerformed(ActionEvent e) + protected void fontName_actionPerformed() { } - /** - * DOCUMENT ME! - * - * @param e - * DOCUMENT ME! - */ - protected void fontStyle_actionPerformed(ActionEvent e) + protected void fontSize_actionPerformed() { } - /** - * DOCUMENT ME! - * - * @param e - * DOCUMENT ME! - */ - public void defaultButton_actionPerformed(ActionEvent e) + protected void fontStyle_actionPerformed() { } - public void smoothFont_actionPerformed(ActionEvent e) + public void defaultButton_actionPerformed() { + } + protected void smoothFont_actionPerformed() + { } } diff --git a/src/jalview/jbgui/GStructureChooser.java b/src/jalview/jbgui/GStructureChooser.java index 3a064d2..041fefd 100644 --- a/src/jalview/jbgui/GStructureChooser.java +++ b/src/jalview/jbgui/GStructureChooser.java @@ -33,6 +33,7 @@ import jalview.util.MessageManager; import java.awt.BorderLayout; import java.awt.CardLayout; +import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.GridLayout; @@ -54,11 +55,14 @@ import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.JLabel; +import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; +import javax.swing.JSeparator; import javax.swing.JTabbedPane; import javax.swing.JTable; import javax.swing.JTextField; +import javax.swing.ListCellRenderer; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; @@ -488,6 +492,19 @@ public abstract class GStructureChooser extends JPanel implements }); cmb_filterOption.addItemListener(this); + + // add CustomComboSeparatorsRenderer to filter option combo-box + cmb_filterOption.setRenderer(new CustomComboSeparatorsRenderer( + (ListCellRenderer) cmb_filterOption.getRenderer()) + { + @Override + protected boolean addSeparatorAfter(JList list, FilterOption value, + int index) + { + return value.isAddSeparatorAfter(); + } + }); + chk_invertFilter.addItemListener(this); pnl_actions.add(chk_rememberSettings); @@ -643,11 +660,28 @@ public abstract class GStructureChooser extends JPanel implements private String view; - public FilterOption(String name, String value, String view) + private boolean addSeparatorAfter; + + /** + * Model for structure filter option + * + * @param name + * - the name of the Option + * @param value + * - the value of the option + * @param view + * - the category of the filter option + * @param addSeparatorAfter + * - if true, a horizontal separator is rendered immediately after + * this filter option, otherwise + */ + public FilterOption(String name, String value, String view, + boolean addSeparatorAfter) { this.name = name; this.value = value; this.view = view; + this.addSeparatorAfter = addSeparatorAfter; } public String getName() @@ -685,6 +719,16 @@ public abstract class GStructureChooser extends JPanel implements { return this.name; } + + public boolean isAddSeparatorAfter() + { + return addSeparatorAfter; + } + + public void setAddSeparatorAfter(boolean addSeparatorAfter) + { + this.addSeparatorAfter = addSeparatorAfter; + } } /** @@ -800,6 +844,54 @@ public abstract class GStructureChooser extends JPanel implements return cmb_filterOption; } + /** + * Custom ListCellRenderer for adding a separator between different categories + * of structure chooser filter option drop-down. + * + * @author tcnofoegbu + * + */ + public abstract class CustomComboSeparatorsRenderer implements + ListCellRenderer + { + private ListCellRenderer regent; + + private JPanel separatorPanel = new JPanel(new BorderLayout()); + + private JSeparator jSeparator = new JSeparator(); + + public CustomComboSeparatorsRenderer(ListCellRenderer listCellRenderer) + { + this.regent = listCellRenderer; + } + + @Override + public Component getListCellRendererComponent(JList list, + Object value, + int index, boolean isSelected, boolean cellHasFocus) + { + + Component comp = regent.getListCellRendererComponent(list, value, + index, isSelected, cellHasFocus); + if (index != -1 + && addSeparatorAfter(list, (FilterOption) value, index)) + { + separatorPanel.removeAll(); + separatorPanel.add(comp, BorderLayout.CENTER); + separatorPanel.add(jSeparator, BorderLayout.SOUTH); + return separatorPanel; + } + else + { + return comp; + } + } + + protected abstract boolean addSeparatorAfter(JList list, + FilterOption value, + int index); + } + protected abstract void stateChanged(ItemEvent e); protected abstract void ok_ActionPerformed(); @@ -816,4 +908,4 @@ public abstract class GStructureChooser extends JPanel implements public abstract void tabRefresh(); public abstract void validateSelections(); -} +} \ No newline at end of file diff --git a/src/jalview/renderer/AnnotationRenderer.java b/src/jalview/renderer/AnnotationRenderer.java index 3a27c7d..518c179 100644 --- a/src/jalview/renderer/AnnotationRenderer.java +++ b/src/jalview/renderer/AnnotationRenderer.java @@ -28,6 +28,7 @@ import jalview.api.AlignViewportI; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.Annotation; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.ProfilesI; import jalview.schemes.ColourSchemeI; import jalview.schemes.NucleotideColourScheme; @@ -75,6 +76,8 @@ public class AnnotationRenderer ResidueShaderI profcolour = null; private ColumnSelection columnSelection; + + private HiddenColumns hiddenColumns; private ProfilesI hconsensus; @@ -327,6 +330,7 @@ public class AnnotationRenderer profcolour = new ResidueShader(col); } columnSelection = av.getColumnSelection(); + hiddenColumns = av.getAlignment().getHiddenColumns(); hconsensus = av.getSequenceConsensusHash(); complementConsensus = av.getComplementConsensusHash(); hStrucConsensus = av.getRnaStructureConsensusHash(); @@ -589,7 +593,7 @@ hconsensus.get(column), { if (hasHiddenColumns) { - column = columnSelection.adjustForHiddenColumns(startRes + x); + column = hiddenColumns.adjustForHiddenColumns(startRes + x); if (column > row_annotations.length - 1) { break; @@ -1231,7 +1235,7 @@ hconsensus.get(column), column = sRes + x; if (hasHiddenColumns) { - column = columnSelection.adjustForHiddenColumns(column); + column = hiddenColumns.adjustForHiddenColumns(column); } if (column > aaMax) @@ -1310,7 +1314,7 @@ hconsensus.get(column), column = sRes + x; if (hasHiddenColumns) { - column = columnSelection.adjustForHiddenColumns(column); + column = hiddenColumns.adjustForHiddenColumns(column); } if (column > aaMax) diff --git a/src/jalview/renderer/OverviewRenderer.java b/src/jalview/renderer/OverviewRenderer.java new file mode 100644 index 0000000..9291ca6 --- /dev/null +++ b/src/jalview/renderer/OverviewRenderer.java @@ -0,0 +1,208 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.renderer; + +import jalview.api.AlignmentColsCollectionI; +import jalview.api.AlignmentRowsCollectionI; +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.Annotation; +import jalview.datamodel.SequenceI; +import jalview.renderer.seqfeatures.FeatureColourFinder; +import jalview.renderer.seqfeatures.FeatureRenderer; +import jalview.viewmodel.OverviewDimensions; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.image.BufferedImage; + +public class OverviewRenderer +{ + private FeatureColourFinder finder; + + private jalview.api.SequenceRenderer sr; + + // image to render on + private BufferedImage miniMe; + + // raw number of pixels to allocate to each column + private float pixelsPerCol; + + // raw number of pixels to allocate to each row + private float pixelsPerSeq; + + public OverviewRenderer(jalview.api.SequenceRenderer seqRenderer, + FeatureRenderer fr, OverviewDimensions od) + // FeatureColourFinder colfinder, OverviewDimensions od) + { + sr = seqRenderer; + finder = new FeatureColourFinder(fr); // colfinder; + + pixelsPerCol = od.getPixelsPerCol(); + pixelsPerSeq = od.getPixelsPerSeq(); + miniMe = new BufferedImage(od.getWidth(), od.getHeight(), + BufferedImage.TYPE_INT_RGB); + } + + /** + * Draw alignment rows and columns onto an image + * + * @param rit + * Iterator over rows to be drawn + * @param cit + * Iterator over columns to be drawn + * @return image containing the drawing + */ + public BufferedImage draw(AlignmentRowsCollectionI rows, + AlignmentColsCollectionI cols) + { + int rgbcolor = Color.white.getRGB(); + int seqIndex = 0; + int pixelRow = 0; + for (int alignmentRow : rows) + { + // get details of this alignment row + boolean hidden = rows.isHidden(alignmentRow); + SequenceI seq = rows.getSequence(alignmentRow); + + // calculate where this row extends to in pixels + int endRow = Math.min(Math.round((seqIndex + 1) * pixelsPerSeq) - 1, + miniMe.getHeight() - 1); + + int colIndex = 0; + int pixelCol = 0; + for (int alignmentCol : cols) + { + // calculate where this column extends to in pixels + int endCol = Math.min( + Math.round((colIndex + 1) * pixelsPerCol) - 1, + miniMe.getWidth() - 1); + + // don't do expensive colour determination if we're not going to use it + // NB this is important to avoid performance issues in the overview + // panel + if (pixelCol <= endCol) + { + // determine the colour based on the sequence and column position + rgbcolor = getColumnColourFromSequence(seq, + hidden || cols.isHidden(alignmentCol), alignmentCol, + finder); + + // fill in the appropriate number of pixels + for (int row = pixelRow; row <= endRow; ++row) + { + for (int col = pixelCol; col <= endCol; ++col) + { + miniMe.setRGB(col, row, rgbcolor); + } + } + + pixelCol = endCol + 1; + } + colIndex++; + } + pixelRow = endRow + 1; + seqIndex++; + } + return miniMe; + } + + /* + * Find the colour of a sequence at a specified column position + */ + private int getColumnColourFromSequence(jalview.datamodel.SequenceI seq, + boolean isHidden, int lastcol, FeatureColourFinder fcfinder) + { + Color color = Color.white; + + if ((seq != null) && (seq.getLength() > lastcol)) + { + color = sr.getResidueColour(seq, lastcol, fcfinder); + } + + if (isHidden) + { + color = color.darker().darker(); + } + + return color.getRGB(); + } + + /** + * Draw the alignment annotation in the overview panel + * + * @param g + * the graphics object to draw on + * @param anno + * alignment annotation information + * @param charWidth + * alignment character width value + * @param y + * y-position for the annotation graph + * @param cols + * the collection of columns used in the overview panel + */ + public void drawGraph(Graphics g, AlignmentAnnotation anno, int charWidth, + int y, AlignmentColsCollectionI cols) + { + Annotation[] annotations = anno.annotations; + g.setColor(Color.white); + g.fillRect(0, 0, miniMe.getWidth(), y); + + int height; + int colIndex = 0; + int pixelCol = 0; + for (int alignmentCol : cols) + { + if (alignmentCol >= annotations.length) + { + break; // no more annotations to draw here + } + else + { + int endCol = Math.min( + Math.round((colIndex + 1) * pixelsPerCol) - 1, + miniMe.getWidth() - 1); + + if (annotations[alignmentCol] != null) + { + if (annotations[alignmentCol].colour == null) + { + g.setColor(Color.black); + } + else + { + g.setColor(annotations[alignmentCol].colour); + } + + height = (int) ((annotations[alignmentCol].value / anno.graphMax) * y); + if (height > y) + { + height = y; + } + + g.fillRect(pixelCol, y - height, endCol - pixelCol + 1, height); + } + pixelCol = endCol + 1; + colIndex++; + } + } + } +} diff --git a/src/jalview/renderer/ScaleRenderer.java b/src/jalview/renderer/ScaleRenderer.java index 82536d4..9fec256 100644 --- a/src/jalview/renderer/ScaleRenderer.java +++ b/src/jalview/renderer/ScaleRenderer.java @@ -73,7 +73,7 @@ public class ScaleRenderer { // find bounds and set origin appopriately // locate first visible position for this sequence - int[] refbounds = av.getColumnSelection() + int[] refbounds = av.getAlignment().getHiddenColumns() .locateVisibleBoundsOfSequence(refSeq); refSp = refbounds[0]; @@ -96,12 +96,14 @@ public class ScaleRenderer { if (refSeq == null) { - iadj = av.getColumnSelection().adjustForHiddenColumns(i - 1) + 1; + iadj = av.getAlignment().getHiddenColumns() + .adjustForHiddenColumns(i - 1) + 1; string = String.valueOf(iadj); } else { - iadj = av.getColumnSelection().adjustForHiddenColumns(i - 1); + iadj = av.getAlignment().getHiddenColumns() + .adjustForHiddenColumns(i - 1); refN = refSeq.findPosition(iadj); // TODO show bounds if position is a gap // - ie L--R -> "1L|2R" for diff --git a/src/jalview/structure/SelectionListener.java b/src/jalview/structure/SelectionListener.java index 2877d46..fe878ce 100644 --- a/src/jalview/structure/SelectionListener.java +++ b/src/jalview/structure/SelectionListener.java @@ -38,5 +38,7 @@ public interface SelectionListener * - source of the selection event */ public void selection(jalview.datamodel.SequenceGroup seqsel, - jalview.datamodel.ColumnSelection colsel, SelectionSource source); + jalview.datamodel.ColumnSelection colsel, + jalview.datamodel.HiddenColumns hidden, + SelectionSource source); } diff --git a/src/jalview/structure/StructureSelectionManager.java b/src/jalview/structure/StructureSelectionManager.java index 0990b56..72da7ae 100644 --- a/src/jalview/structure/StructureSelectionManager.java +++ b/src/jalview/structure/StructureSelectionManager.java @@ -29,6 +29,7 @@ import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; import jalview.datamodel.SearchResults; import jalview.datamodel.SearchResultsI; @@ -1201,13 +1202,14 @@ public class StructureSelectionManager public synchronized void sendSelection( jalview.datamodel.SequenceGroup selection, - jalview.datamodel.ColumnSelection colsel, SelectionSource source) + jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden, + SelectionSource source) { for (SelectionListener slis : sel_listeners) { if (slis != source) { - slis.selection(selection, colsel, source); + slis.selection(selection, colsel, hidden, source); } } } diff --git a/src/jalview/structures/models/AAStructureBindingModel.java b/src/jalview/structures/models/AAStructureBindingModel.java index 84475fe..b336e45 100644 --- a/src/jalview/structures/models/AAStructureBindingModel.java +++ b/src/jalview/structures/models/AAStructureBindingModel.java @@ -25,7 +25,7 @@ import jalview.api.SequenceRenderer; import jalview.api.StructureSelectionManagerProvider; import jalview.api.structures.JalviewStructureDisplayI; import jalview.datamodel.AlignmentI; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.io.DataSourceType; @@ -716,8 +716,8 @@ public abstract class AAStructureBindingModel extends * an array of corresponding hidden columns for each alignment * @return */ - public abstract String superposeStructures(AlignmentI[] alignments, int[] structureIndices, - ColumnSelection[] hiddenCols); + public abstract String superposeStructures(AlignmentI[] alignments, + int[] structureIndices, HiddenColumns[] hiddenCols); public abstract void setBackgroundColour(Color col); diff --git a/src/jalview/util/MappingUtils.java b/src/jalview/util/MappingUtils.java index 2e30132..926ccc7 100644 --- a/src/jalview/util/MappingUtils.java +++ b/src/jalview/util/MappingUtils.java @@ -31,6 +31,7 @@ import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentOrder; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SearchResultMatchI; import jalview.datamodel.SearchResults; import jalview.datamodel.SearchResultsI; @@ -508,18 +509,20 @@ public final class MappingUtils * @param mapTo * @return */ - public static ColumnSelection mapColumnSelection(ColumnSelection colsel, - AlignViewportI mapFrom, AlignViewportI mapTo) + public static void mapColumnSelection(ColumnSelection colsel, + HiddenColumns hiddencols, AlignViewportI mapFrom, + AlignViewportI mapTo, ColumnSelection newColSel, + HiddenColumns newHidden) { boolean targetIsNucleotide = mapTo.isNucleotide(); AlignViewportI protein = targetIsNucleotide ? mapFrom : mapTo; List codonFrames = protein.getAlignment() .getCodonFrames(); - ColumnSelection mappedColumns = new ColumnSelection(); + // ColumnSelection mappedColumns = new ColumnSelection(); if (colsel == null) { - return mappedColumns; + return; // mappedColumns; } char fromGapChar = mapFrom.getAlignment().getGapCharacter(); @@ -533,16 +536,16 @@ public final class MappingUtils for (Integer sel : colsel.getSelected()) { - mapColumn(sel.intValue(), codonFrames, mappedColumns, fromSequences, + mapColumn(sel.intValue(), codonFrames, newColSel, fromSequences, toSequences, fromGapChar); } - for (int[] hidden : colsel.getHiddenColumns()) + for (int[] hidden : hiddencols.getHiddenRegions()) { - mapHiddenColumns(hidden, codonFrames, mappedColumns, fromSequences, + mapHiddenColumns(hidden, codonFrames, newHidden, fromSequences, toSequences, fromGapChar); } - return mappedColumns; + return; // mappedColumns; } /** @@ -557,7 +560,7 @@ public final class MappingUtils * @param fromGapChar */ protected static void mapHiddenColumns(int[] hidden, - List mappings, ColumnSelection mappedColumns, + List mappings, HiddenColumns mappedColumns, List fromSequences, List toSequences, char fromGapChar) { diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java index fa3a8a7..cdf0758 100644 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@ -20,17 +20,6 @@ */ package jalview.viewmodel; -import java.awt.Color; -import java.beans.PropertyChangeSupport; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.BitSet; -import java.util.Deque; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; - import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder; import jalview.analysis.Conservation; import jalview.api.AlignCalcManagerI; @@ -46,6 +35,7 @@ import jalview.datamodel.AlignmentView; import jalview.datamodel.Annotation; import jalview.datamodel.CigarArray; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.HiddenSequences; import jalview.datamodel.ProfilesI; import jalview.datamodel.SearchResultsI; @@ -69,6 +59,17 @@ import jalview.workers.ComplementConsensusThread; import jalview.workers.ConsensusThread; import jalview.workers.StrucConsensusThread; +import java.awt.Color; +import java.beans.PropertyChangeSupport; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Deque; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; + /** * base class holding visualization and analysis attributes and common logic for * an active alignment view displayed in the GUI @@ -79,7 +80,7 @@ import jalview.workers.StrucConsensusThread; public abstract class AlignmentViewport implements AlignViewportI, CommandListener, VamsasSource { - protected ViewportRanges ranges; + final protected ViewportRanges ranges; protected ViewStyleI viewStyle = new ViewStyle(); @@ -96,6 +97,17 @@ public abstract class AlignmentViewport implements AlignViewportI, protected Deque redoList = new ArrayDeque(); /** + * alignment displayed in the viewport. Please use get/setter + */ + protected AlignmentI alignment; + + public AlignmentViewport(AlignmentI al) + { + setAlignment(al); + ranges = new ViewportRanges(al); + } + + /** * @param name * @see jalview.api.ViewStyleI#setFontName(java.lang.String) */ @@ -555,10 +567,7 @@ public abstract class AlignmentViewport implements AlignViewportI, viewStyle.setSeqNameItalics(default1); } - /** - * alignment displayed in the viewport. Please use get/setter - */ - protected AlignmentI alignment; + @Override public AlignmentI getAlignment() @@ -600,7 +609,7 @@ public abstract class AlignmentViewport implements AlignViewportI, protected boolean ignoreGapsInConsensusCalculation = false; - protected ResidueShaderI residueShading; + protected ResidueShaderI residueShading = new ResidueShader(); @Override public void setGlobalColourScheme(ColourSchemeI cs) @@ -1101,9 +1110,10 @@ public abstract class AlignmentViewport implements AlignViewportI, } } - public void setHiddenColumns(ColumnSelection colsel) + public void setHiddenColumns(HiddenColumns hidden) { - this.colSel = colsel; + this.alignment.setHiddenColumns(hidden); + // this.colSel = colsel; } @Override @@ -1150,7 +1160,8 @@ public abstract class AlignmentViewport implements AlignViewportI, @Override public boolean hasHiddenColumns() { - return colSel != null && colSel.hasHiddenColumns(); + return colSel != null + && alignment.getHiddenColumns().hasHiddenColumns(); } public void updateHiddenColumns() @@ -1347,7 +1358,7 @@ public abstract class AlignmentViewport implements AlignViewportI, return; } - colSel.hideSelectedColumns(); + colSel.hideSelectedColumns(alignment); setSelectionGroup(null); isColSelChanged(true); } @@ -1356,24 +1367,24 @@ public abstract class AlignmentViewport implements AlignViewportI, { if (start == end) { - colSel.hideColumns(start); + colSel.hideSelectedColumns(start, alignment.getHiddenColumns()); } else { - colSel.hideColumns(start, end); + alignment.getHiddenColumns().hideColumns(start, end); } isColSelChanged(true); } public void showColumn(int col) { - colSel.revealHiddenColumns(col); + alignment.getHiddenColumns().revealHiddenColumns(col, colSel); isColSelChanged(true); } public void showAllHiddenColumns() { - colSel.revealAllHiddenColumns(); + alignment.getHiddenColumns().revealAllHiddenColumns(colSel); isColSelChanged(true); } @@ -1595,7 +1606,7 @@ public abstract class AlignmentViewport implements AlignViewportI, @Override public void invertColumnSelection() { - colSel.invertColumnSelection(0, alignment.getWidth()); + colSel.invertColumnSelection(0, alignment.getWidth(), alignment); } @Override @@ -1643,7 +1654,7 @@ public abstract class AlignmentViewport implements AlignViewportI, @Override public CigarArray getViewAsCigars(boolean selectedRegionOnly) { - return new CigarArray(alignment, colSel, + return new CigarArray(alignment, alignment.getHiddenColumns(), (selectedRegionOnly ? selectionGroup : null)); } @@ -1658,8 +1669,10 @@ public abstract class AlignmentViewport implements AlignViewportI, public jalview.datamodel.AlignmentView getAlignmentView( boolean selectedOnly, boolean markGroups) { - return new AlignmentView(alignment, colSel, selectionGroup, - colSel != null && colSel.hasHiddenColumns(), selectedOnly, + return new AlignmentView(alignment, alignment.getHiddenColumns(), + selectionGroup, alignment.getHiddenColumns() != null + && alignment.getHiddenColumns().hasHiddenColumns(), + selectedOnly, markGroups); } @@ -1703,9 +1716,11 @@ public abstract class AlignmentViewport implements AlignViewportI, } selection = new String[iSize]; - if (colSel != null && colSel.hasHiddenColumns()) + if (alignment.getHiddenColumns() != null + && alignment.getHiddenColumns().hasHiddenColumns()) { - selection = colSel.getVisibleSequenceStrings(start, end, seqs); + selection = alignment.getHiddenColumns().getVisibleSequenceStrings( + start, end, seqs); } else { @@ -1727,14 +1742,15 @@ public abstract class AlignmentViewport implements AlignViewportI, do { - if (colSel != null && colSel.hasHiddenColumns()) + HiddenColumns hidden = alignment.getHiddenColumns(); + if (hidden != null && hidden.hasHiddenColumns()) { if (start == 0) { - start = colSel.adjustForHiddenColumns(start); + start = hidden.adjustForHiddenColumns(start); } - end = colSel.getHiddenBoundaryRight(start); + end = hidden.getHiddenBoundaryRight(start); if (start == end) { end = max; @@ -1747,10 +1763,10 @@ public abstract class AlignmentViewport implements AlignViewportI, regions.add(new int[] { start, end }); - if (colSel != null && colSel.hasHiddenColumns()) + if (hidden != null && hidden.hasHiddenColumns()) { - start = colSel.adjustForHiddenColumns(end); - start = colSel.getHiddenBoundaryLeft(start) + 1; + start = hidden.adjustForHiddenColumns(end); + start = hidden.getHiddenBoundaryLeft(start) + 1; } } while (end < max); @@ -1772,12 +1788,13 @@ public abstract class AlignmentViewport implements AlignViewportI, AlignmentAnnotation clone = new AlignmentAnnotation(annot); if (selectedOnly && selectionGroup != null) { - colSel.makeVisibleAnnotation(selectionGroup.getStartRes(), + alignment.getHiddenColumns().makeVisibleAnnotation( + selectionGroup.getStartRes(), selectionGroup.getEndRes(), clone); } else { - colSel.makeVisibleAnnotation(clone); + alignment.getHiddenColumns().makeVisibleAnnotation(clone); } ala.add(clone); } @@ -2658,6 +2675,18 @@ public abstract class AlignmentViewport implements AlignViewportI, viewStyle.setScaleProteinAsCdna(b); } + @Override + public boolean isProteinFontAsCdna() + { + return viewStyle.isProteinFontAsCdna(); + } + + @Override + public void setProteinFontAsCdna(boolean b) + { + viewStyle.setProteinFontAsCdna(b); + } + /** * @return true if view should scroll to show the highlighted region of a * sequence diff --git a/src/jalview/viewmodel/OverviewDimensions.java b/src/jalview/viewmodel/OverviewDimensions.java index 43680b5..a837d53 100644 --- a/src/jalview/viewmodel/OverviewDimensions.java +++ b/src/jalview/viewmodel/OverviewDimensions.java @@ -20,60 +20,35 @@ */ package jalview.viewmodel; -import jalview.datamodel.ColumnSelection; +import jalview.api.AlignmentColsCollectionI; +import jalview.api.AlignmentRowsCollectionI; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.HiddenSequences; import java.awt.Graphics; -public class OverviewDimensions +public abstract class OverviewDimensions { - // Default width and height values - private static final int DEFAULT_GRAPH_HEIGHT = 20; - - private static final int MAX_WIDTH = 400; - - private static final int MIN_WIDTH = 120; - - private static final int MIN_SEQ_HEIGHT = 40; - - private static final int MAX_SEQ_HEIGHT = 300; - - // width of the overview panel - private int width; - - // height of sequences part of the overview panel - private int sequencesHeight; - - // height of the graphs part of the overview panel - private int graphHeight = DEFAULT_GRAPH_HEIGHT; - - // dimensions of box outlining current extent of view in alignment panel - // location of left side of box - private int boxX = -1; - - // location of bottom of box - private int boxY = -1; + protected static final int MAX_WIDTH = 400; + protected static final int MIN_WIDTH = 120; + protected static final int MIN_SEQ_HEIGHT = 40; + protected static final int MAX_SEQ_HEIGHT = 300; - // width of box - private int boxWidth = -1; - - // height of box - private int boxHeight = -1; - - // scroll position in viewport corresponding to boxX - private int scrollCol = -1; + private static final int DEFAULT_GRAPH_HEIGHT = 20; - // scroll position in viewport corresponding to boxY - private int scrollRow = -1; + protected int width; + protected int sequencesHeight; + protected int graphHeight = DEFAULT_GRAPH_HEIGHT; + protected int boxX = -1; + protected int boxY = -1; + protected int boxWidth = -1; + protected int boxHeight = -1; + protected int scrollCol = -1; + protected int scrollRow = -1; + protected int alwidth; + protected int alheight; - /** - * Create an OverviewDimensions object - * - * @param ranges - * positional properties of the viewport - * @param showAnnotationPanel - * true if the annotation panel is to be shown, false otherwise - */ public OverviewDimensions(ViewportRanges ranges, boolean showAnnotationPanel) { @@ -111,159 +86,6 @@ public class OverviewDimensions } /** - * Check box dimensions and scroll positions and correct if necessary - * - * @param mousex - * x position in overview panel - * @param mousey - * y position in overview panel - * @param hiddenSeqs - * hidden sequences - * @param hiddenCols - * hidden columns - * @param ranges - * viewport position properties - */ - public void updateViewportFromMouse(int mousex, int mousey, - HiddenSequences hiddenSeqs, ColumnSelection hiddenCols, - ViewportRanges ranges) - { - int x = mousex; - int y = mousey; - - int alwidth = ranges.getAbsoluteAlignmentWidth(); - int alheight = ranges.getAbsoluteAlignmentHeight(); - - if (x < 0) - { - x = 0; - } - - if (y < 0) - { - y = 0; - } - - // - // Convert x value to residue position - // - - // need to determine where scrollCol should be, given x - // to do this also need to know width of viewport, and some hidden column - // correction - - // convert x to residues - this is an absolute position - int xAsRes = Math.round((float) x * alwidth / width); - - // get viewport width in residues - int vpwidth = ranges.getEndRes() - ranges.getStartRes() + 1; - - // get where x should be when accounting for hidden cols - // if x is in a hidden col region, shift to left - but we still need - // absolute position - // so convert back after getting visible region position - int visXAsRes = hiddenCols.findColumnPosition(xAsRes); - - // check in case we went off the edge of the alignment - int visAlignWidth = hiddenCols.findColumnPosition(alwidth - 1); - if (visXAsRes + vpwidth - 1 > visAlignWidth) - { - // went past the end of the alignment, adjust backwards - - // if last position was before the end of the alignment, need to update - if ((scrollCol + vpwidth - 1) < visAlignWidth) - { - visXAsRes = hiddenCols.findColumnPosition(hiddenCols - .subtractVisibleColumns(vpwidth - 1, alwidth - 1)); - } - else - { - visXAsRes = scrollCol; - } - } - - // - // Convert y value to sequence position - // - - // convert y to residues - int yAsSeq = Math.round((float) y * alheight / sequencesHeight); - - // get viewport height in sequences - // add 1 because height includes both endSeq and startSeq - int vpheight = ranges.getEndSeq() - ranges.getStartSeq() + 1; - - // get where y should be when accounting for hidden rows - // if y is in a hidden row region, shift up - but we still need absolute - // position, - // so convert back after getting visible region position - yAsSeq = hiddenSeqs.adjustForHiddenSeqs(hiddenSeqs - .findIndexWithoutHiddenSeqs(yAsSeq)); - - // check in case we went off the edge of the alignment - int visAlignHeight = hiddenSeqs.findIndexWithoutHiddenSeqs(alheight); - int visYAsRes = hiddenSeqs.findIndexWithoutHiddenSeqs(yAsSeq); - if (visYAsRes + vpheight - 1 > visAlignHeight) - { - // went past the end of the alignment, adjust backwards - if ((scrollRow + vpheight - 1) < visAlignHeight) - { - visYAsRes = hiddenSeqs.findIndexWithoutHiddenSeqs(hiddenSeqs - .subtractVisibleRows(vpheight - 1, alheight - 1)); - } - else - { - visYAsRes = scrollRow; - } - } - - // update scroll values - scrollCol = visXAsRes; - scrollRow = visYAsRes; - - } - - /** - * Update the overview panel box when the associated alignment panel is - * changed - * - * @param hiddenSeqs - * hidden sequences - * @param hiddenCols - * hidden columns - * @param ranges - * viewport position properties - */ - public void setBoxPosition(HiddenSequences hiddenSeqs, - ColumnSelection hiddenCols, ViewportRanges ranges) - { - int alwidth = ranges.getAbsoluteAlignmentWidth(); - int alheight = ranges.getAbsoluteAlignmentHeight(); - - // work with absolute values of startRes and endRes - int startRes = hiddenCols.adjustForHiddenColumns(ranges.getStartRes()); - int endRes = hiddenCols.adjustForHiddenColumns(ranges.getEndRes()); - - // work with absolute values of startSeq and endSeq - int startSeq = hiddenSeqs.adjustForHiddenSeqs(ranges.getStartSeq()); - int endSeq = hiddenSeqs.adjustForHiddenSeqs(ranges.getEndSeq()); - - // boxX, boxY is the x,y location equivalent to startRes, startSeq - boxX = Math.round((float) startRes * width / alwidth); - boxY = Math.round((float) startSeq * sequencesHeight / alheight); - - // boxWidth is the width in residues translated to pixels - // since the box includes both the start and end residues, add 1 to the - // difference - boxWidth = Math - .round((float) (endRes - startRes + 1) * width / alwidth); - // boxHeight is the height in sequences translated to pixels - boxHeight = Math.round((float) (endSeq - startSeq + 1) - * sequencesHeight - / alheight); - } - - /** * Draw the overview panel's viewport box on a graphics object * * @param g @@ -285,42 +107,26 @@ public class OverviewDimensions return scrollRow; } - // TODO should be removed, when unit test has mock Graphics object available - // to check boxX/boxY public int getBoxX() { return boxX; } - // TODO should be removed, when unit test has mock Graphics object available - // to check boxX/boxY public int getBoxY() { return boxY; } - // TODO should be removed, when unit test has mock Graphics object available public int getBoxWidth() { return boxWidth; } - // TODO should be removed, when unit test has mock Graphics object available public int getBoxHeight() { return boxHeight; } - public void setWidth(int w) - { - width = w; - } - - public void setHeight(int h) - { - sequencesHeight = h - graphHeight; - } - public int getWidth() { return width; @@ -340,4 +146,94 @@ public class OverviewDimensions { return graphHeight; } -} + + public float getPixelsPerCol() + { + resetAlignmentDims(); + return (float) width / alwidth; + } + + public float getPixelsPerSeq() + { + resetAlignmentDims(); + return (float) sequencesHeight / alheight; + } + + public void setWidth(int w) + { + width = w; + } + + public void setHeight(int h) + { + sequencesHeight = h - graphHeight; + } + + /** + * Update the viewport location from a mouse click in the overview panel + * + * @param mousex + * x location of mouse + * @param mousey + * y location of mouse + * @param hiddenSeqs + * the alignment's hidden sequences + * @param hiddenCols + * the alignment's hidden columns + */ + public abstract void updateViewportFromMouse(int mousex, int mousey, + HiddenSequences hiddenSeqs, HiddenColumns hiddenCols); + + /** + * Set the overview panel's box position to match the viewport + * + * @param hiddenSeqs + * the alignment's hidden sequences + * @param hiddenCols + * the alignment's hidden columns + */ + public abstract void setBoxPosition(HiddenSequences hiddenSeqs, + HiddenColumns hiddenCols); + + /** + * Get the collection of columns used by this overview dimensions object + * + * @param hiddenCols + * the alignment's hidden columns + * @return a column collection + */ + public abstract AlignmentColsCollectionI getColumns(AlignmentI al); + + /** + * Get the collection of rows used by this overview dimensions object + * + * @param al + * the alignment + * @return a row collection + */ + public abstract AlignmentRowsCollectionI getRows(AlignmentI al); + + /** + * Updates overview dimensions to account for current alignment dimensions + */ + protected abstract void resetAlignmentDims(); + + protected void setBoxPosition(int startRes, int endRes, int startSeq, + int endSeq) + { + resetAlignmentDims(); + + // boxX, boxY is the x,y location equivalent to startRes, startSeq + boxX = Math.round((float) startRes * width / alwidth); + boxY = Math.round((float) startSeq * sequencesHeight / alheight); + + // boxWidth is the width in residues translated to pixels + // since the box includes both the start and end residues, add 1 to the + // difference + boxWidth = Math + .round((float) (endRes - startRes + 1) * width / alwidth); + // boxHeight is the height in sequences translated to pixels + boxHeight = Math.round((float) (endSeq - startSeq + 1) + * sequencesHeight / alheight); + } +} \ No newline at end of file diff --git a/src/jalview/viewmodel/OverviewDimensionsHideHidden.java b/src/jalview/viewmodel/OverviewDimensionsHideHidden.java new file mode 100644 index 0000000..b03f9ac --- /dev/null +++ b/src/jalview/viewmodel/OverviewDimensionsHideHidden.java @@ -0,0 +1,137 @@ +package jalview.viewmodel; + +import jalview.api.AlignmentColsCollectionI; +import jalview.api.AlignmentRowsCollectionI; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.HiddenSequences; +import jalview.datamodel.VisibleColsCollection; +import jalview.datamodel.VisibleRowsCollection; + +public class OverviewDimensionsHideHidden extends OverviewDimensions +{ + private ViewportRanges ranges; + + public OverviewDimensionsHideHidden(ViewportRanges vpranges, + boolean showAnnotationPanel) + { + super(vpranges, showAnnotationPanel); + ranges = vpranges; + resetAlignmentDims(); + } + + @Override + public void updateViewportFromMouse(int mousex, int mousey, + HiddenSequences hiddenSeqs, HiddenColumns hiddenCols) + { + resetAlignmentDims(); + + int x = mousex; + int y = mousey; + + if (x < 0) + { + x = 0; + } + + if (y < 0) + { + y = 0; + } + + // + // Convert x value to residue position + // + + // need to determine where scrollCol should be, given x + // to do this also need to know width of viewport, and some hidden column + // correction + + // convert x to residues - this is an absolute position + int xAsRes = Math.round((float) x * alwidth / width); + + // get viewport width in residues + int vpwidth = ranges.getEndRes() - ranges.getStartRes() + 1; + + if (xAsRes + vpwidth > alwidth) + { + // went past the end of the alignment, adjust backwards + + // if last position was before the end of the alignment, need to update + if ((scrollCol + vpwidth - 1) < alwidth) + { + xAsRes = alwidth - vpwidth; + } + else + { + xAsRes = scrollCol; + } + } + + + // + // Convert y value to sequence position + // + + // convert y to residues + int yAsSeq = Math.round((float) y * alheight / sequencesHeight); + + // get viewport height in sequences + // add 1 because height includes both endSeq and startSeq + int vpheight = ranges.getEndSeq() - ranges.getStartSeq() + 1; + + if (yAsSeq + vpheight > alheight) + { + // went past the end of the alignment, adjust backwards + if ((scrollRow + vpheight - 1) < alheight) + { + yAsSeq = alheight - vpheight; + } + else + { + yAsSeq = scrollRow; + } + } + + // update scroll values + scrollCol = xAsRes; + scrollRow = yAsSeq; + + } + + @Override + public void setBoxPosition(HiddenSequences hiddenSeqs, + HiddenColumns hiddenCols) + { + // work with visible values of startRes and endRes + int startRes = ranges.getStartRes(); + int endRes = ranges.getEndRes(); + + // work with visible values of startSeq and endSeq + int startSeq = ranges.getStartSeq(); + int endSeq = ranges.getEndSeq(); + + setBoxPosition(startRes, endRes, startSeq, endSeq); + } + + @Override + public AlignmentColsCollectionI getColumns(AlignmentI al) + { + return new VisibleColsCollection(0, + ranges.getAbsoluteAlignmentWidth() - 1, al); + } + + @Override + public AlignmentRowsCollectionI getRows(AlignmentI al) + { + return new VisibleRowsCollection(0, + ranges.getAbsoluteAlignmentHeight() - 1, al); + } + + @Override + protected void resetAlignmentDims() + { + alwidth = ranges.getVisibleAlignmentWidth(); + alheight = ranges.getVisibleAlignmentHeight(); + } +} diff --git a/src/jalview/viewmodel/OverviewDimensionsShowHidden.java b/src/jalview/viewmodel/OverviewDimensionsShowHidden.java new file mode 100644 index 0000000..b897189 --- /dev/null +++ b/src/jalview/viewmodel/OverviewDimensionsShowHidden.java @@ -0,0 +1,211 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.viewmodel; + +import jalview.api.AlignmentColsCollectionI; +import jalview.api.AlignmentRowsCollectionI; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.AllColsCollection; +import jalview.datamodel.AllRowsCollection; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.HiddenSequences; + +public class OverviewDimensionsShowHidden extends OverviewDimensions +{ + private ViewportRanges ranges; + + /** + * Create an OverviewDimensions object + * + * @param ranges + * positional properties of the viewport + * @param showAnnotationPanel + * true if the annotation panel is to be shown, false otherwise + */ + public OverviewDimensionsShowHidden(ViewportRanges vpranges, + boolean showAnnotationPanel) + { + super(vpranges, showAnnotationPanel); + ranges = vpranges; + resetAlignmentDims(); + } + + /** + * Check box dimensions and scroll positions and correct if necessary + * + * @param mousex + * x position in overview panel + * @param mousey + * y position in overview panel + * @param hiddenSeqs + * hidden sequences + * @param hiddenCols + * hidden columns + * @param ranges + * viewport position properties + */ + @Override + public void updateViewportFromMouse(int mousex, int mousey, + HiddenSequences hiddenSeqs, HiddenColumns hiddenCols) + { + int x = mousex; + int y = mousey; + + resetAlignmentDims(); + + if (x < 0) + { + x = 0; + } + + if (y < 0) + { + y = 0; + } + + // + // Convert x value to residue position + // + + // need to determine where scrollCol should be, given x + // to do this also need to know width of viewport, and some hidden column + // correction + + // convert x to residues - this is an absolute position + int xAsRes = Math.round((float) x * alwidth / width); + + // get viewport width in residues + int vpwidth = ranges.getEndRes() - ranges.getStartRes() + 1; + + // get where x should be when accounting for hidden cols + // if x is in a hidden col region, shift to left - but we still need + // absolute position + // so convert back after getting visible region position + int visXAsRes = hiddenCols.findColumnPosition(xAsRes); + + // check in case we went off the edge of the alignment + int visAlignWidth = hiddenCols.findColumnPosition(alwidth - 1); + if (visXAsRes + vpwidth - 1 > visAlignWidth) + { + // went past the end of the alignment, adjust backwards + + // if last position was before the end of the alignment, need to update + if ((scrollCol + vpwidth - 1) < visAlignWidth) + { + visXAsRes = hiddenCols.findColumnPosition(hiddenCols + .subtractVisibleColumns(vpwidth - 1, alwidth - 1)); + } + else + { + visXAsRes = scrollCol; + } + } + + // + // Convert y value to sequence position + // + + // convert y to residues + int yAsSeq = Math.round((float) y * alheight / sequencesHeight); + + // get viewport height in sequences + // add 1 because height includes both endSeq and startSeq + int vpheight = ranges.getEndSeq() - ranges.getStartSeq() + 1; + + // get where y should be when accounting for hidden rows + // if y is in a hidden row region, shift up - but we still need absolute + // position, + // so convert back after getting visible region position + yAsSeq = hiddenSeqs.adjustForHiddenSeqs(hiddenSeqs + .findIndexWithoutHiddenSeqs(yAsSeq)); + + // check in case we went off the edge of the alignment + int visAlignHeight = hiddenSeqs.findIndexWithoutHiddenSeqs(alheight); + int visYAsSeq = hiddenSeqs.findIndexWithoutHiddenSeqs(yAsSeq); + if (visYAsSeq + vpheight - 1 > visAlignHeight) + { + // went past the end of the alignment, adjust backwards + if ((scrollRow + vpheight - 1) < visAlignHeight) + { + visYAsSeq = hiddenSeqs.findIndexWithoutHiddenSeqs(hiddenSeqs + .subtractVisibleRows(vpheight - 1, alheight - 1)); + } + else + { + visYAsSeq = scrollRow; + } + } + + // update scroll values + scrollCol = visXAsRes; + scrollRow = visYAsSeq; + + } + + /** + * Update the overview panel box when the associated alignment panel is + * changed + * + * @param hiddenSeqs + * hidden sequences + * @param hiddenCols + * hidden columns + * @param ranges + * viewport position properties + */ + @Override + public void setBoxPosition(HiddenSequences hiddenSeqs, + HiddenColumns hiddenCols) + { + // work with absolute values of startRes and endRes + int startRes = hiddenCols + .adjustForHiddenColumns(ranges.getStartRes()); + int endRes = hiddenCols.adjustForHiddenColumns(ranges.getEndRes()); + + // work with absolute values of startSeq and endSeq + int startSeq = hiddenSeqs.adjustForHiddenSeqs(ranges.getStartSeq()); + int endSeq = hiddenSeqs.adjustForHiddenSeqs(ranges.getEndSeq()); + + setBoxPosition(startRes, endRes, startSeq, endSeq); + } + + @Override + public AlignmentColsCollectionI getColumns(AlignmentI al) + { + return new AllColsCollection(0, + ranges.getAbsoluteAlignmentWidth() - 1, al); + } + + @Override + public AlignmentRowsCollectionI getRows(AlignmentI al) + { + return new AllRowsCollection(0, + ranges.getAbsoluteAlignmentHeight() - 1, + al); + } + + @Override + protected void resetAlignmentDims() + { + alwidth = ranges.getAbsoluteAlignmentWidth(); + alheight = ranges.getAbsoluteAlignmentHeight(); + } +} diff --git a/src/jalview/viewmodel/ViewportRanges.java b/src/jalview/viewmodel/ViewportRanges.java index c91d2d9..fc163e0 100644 --- a/src/jalview/viewmodel/ViewportRanges.java +++ b/src/jalview/viewmodel/ViewportRanges.java @@ -79,6 +79,22 @@ public class ViewportRanges extends ViewportProperties } /** + * Get alignment width in cols, excluding hidden cols + */ + public int getVisibleAlignmentWidth() + { + return al.getWidth() - al.getHiddenColumns().getSize(); + } + + /** + * Get alignment height in rows, excluding hidden rows + */ + public int getVisibleAlignmentHeight() + { + return al.getHeight(); + } + + /** * Set first residue visible in the viewport * * @param res diff --git a/src/jalview/viewmodel/styles/ViewStyle.java b/src/jalview/viewmodel/styles/ViewStyle.java index 14a1bde..f01047d 100644 --- a/src/jalview/viewmodel/styles/ViewStyle.java +++ b/src/jalview/viewmodel/styles/ViewStyle.java @@ -168,6 +168,12 @@ public class ViewStyle implements ViewStyleI */ private boolean scaleProteinAsCdna = true; + /* + * if true, font changes to protein or cDNA are applied to both + * sides of a split screen + */ + private boolean proteinFontAsCdna = true; + /** * Copy constructor * @@ -195,6 +201,7 @@ public class ViewStyle implements ViewStyleI setScaleAboveWrapped(vs.getScaleAboveWrapped()); setScaleLeftWrapped(vs.getScaleLeftWrapped()); setScaleProteinAsCdna(vs.isScaleProteinAsCdna()); + setProteinFontAsCdna(vs.isProteinFontAsCdna()); setScaleRightWrapped(vs.getScaleRightWrapped()); setSeqNameItalics(vs.isSeqNameItalics()); setShowAnnotation(vs.isShowAnnotation()); @@ -255,6 +262,7 @@ public class ViewStyle implements ViewStyleI && getScaleAboveWrapped() == vs.getScaleAboveWrapped() && getScaleLeftWrapped() == vs.getScaleLeftWrapped() && isScaleProteinAsCdna() == vs.isScaleProteinAsCdna() + && isProteinFontAsCdna() == vs.isProteinFontAsCdna() && getScaleRightWrapped() == vs.getScaleRightWrapped() && isSeqNameItalics() == vs.isSeqNameItalics() && isShowAnnotation() == vs.isShowAnnotation() @@ -1094,4 +1102,16 @@ public class ViewStyle implements ViewStyleI { this.scaleProteinAsCdna = b; } + + @Override + public boolean isProteinFontAsCdna() + { + return proteinFontAsCdna; + } + + @Override + public void setProteinFontAsCdna(boolean b) + { + proteinFontAsCdna = b; + } } diff --git a/src/jalview/workers/AlignmentAnnotationFactory.java b/src/jalview/workers/AlignmentAnnotationFactory.java index beee1eb..b0392d4 100644 --- a/src/jalview/workers/AlignmentAnnotationFactory.java +++ b/src/jalview/workers/AlignmentAnnotationFactory.java @@ -48,35 +48,17 @@ public class AlignmentAnnotationFactory * @param counter * provider of feature counts per alignment position */ - public static void newCalculator(FeatureCounterI counter) + public static void newCalculator(FeatureSetCounterI counter) { - // TODO need an interface for AlignFrame by which to access - // its AlignViewportI and AlignmentViewPanel AlignmentViewPanel currentAlignFrame = Jalview.getCurrentAlignFrame().alignPanel; - if (currentAlignFrame != null) - { - newCalculator(currentAlignFrame.getAlignViewport(), - currentAlignFrame, counter); - } - else + if (currentAlignFrame == null) { System.err .println("Can't register calculator as no alignment window has focus"); + return; } - } - - /** - * Constructs and registers a new alignment annotation worker - * - * @param viewport - * @param panel - * @param counter - * provider of feature counts per alignment position - */ - public static void newCalculator(AlignViewportI viewport, - AlignmentViewPanel panel, FeatureCounterI counter) - { - new ColumnCounterWorker(viewport, panel, counter); + new ColumnCounterSetWorker(currentAlignFrame.getAlignViewport(), + currentAlignFrame, counter); } /** @@ -92,8 +74,8 @@ public class AlignmentAnnotationFactory AlignFrame currentAlignFrame = Jalview.getCurrentAlignFrame(); if (currentAlignFrame != null) { - newCalculator(currentAlignFrame.getViewport(), currentAlignFrame - .getAlignPanels().get(0), calculator); + new AnnotationWorker(currentAlignFrame.getViewport(), + currentAlignFrame.getAlignPanels().get(0), calculator); } else { diff --git a/src/jalview/workers/ColumnCounterWorker.java b/src/jalview/workers/ColumnCounterSetWorker.java similarity index 61% rename from src/jalview/workers/ColumnCounterWorker.java rename to src/jalview/workers/ColumnCounterSetWorker.java index dd56aaf..6c5707d 100644 --- a/src/jalview/workers/ColumnCounterWorker.java +++ b/src/jalview/workers/ColumnCounterSetWorker.java @@ -36,16 +36,16 @@ import java.util.ArrayList; import java.util.List; /** - * A class to compute an alignment annotation with column counts of any - * properties of interest of positions in an alignment.
    + * A class to compute alignment annotations with column counts for a set of + * properties of interest on positions in an alignment.
    * This is designed to be extensible, by supplying to the constructor an object - * that computes a count for each residue position, based on the residue value - * and any sequence features at that position. + * that computes a vector of counts for each residue position, based on the + * residue and and sequence features at that position. * */ -class ColumnCounterWorker extends AlignCalcWorker +class ColumnCounterSetWorker extends AlignCalcWorker { - FeatureCounterI counter; + FeatureSetCounterI counter; /** * Constructor registers the annotation for the given alignment frame @@ -53,8 +53,8 @@ class ColumnCounterWorker extends AlignCalcWorker * @param af * @param counter */ - public ColumnCounterWorker(AlignViewportI viewport, - AlignmentViewPanel panel, FeatureCounterI counter) + public ColumnCounterSetWorker(AlignViewportI viewport, + AlignmentViewPanel panel, FeatureSetCounterI counter) { super(viewport, panel); ourAnnots = new ArrayList(); @@ -69,6 +69,7 @@ class ColumnCounterWorker extends AlignCalcWorker @Override public void run() { + boolean annotationAdded = false; try { calcMan.notifyStart(this); @@ -93,7 +94,7 @@ class ColumnCounterWorker extends AlignCalcWorker { try { - computeAnnotations(); + annotationAdded = computeAnnotations(); } catch (IndexOutOfBoundsException x) { // probable race condition. just finish and return without any fuss. @@ -111,7 +112,10 @@ class ColumnCounterWorker extends AlignCalcWorker if (ap != null) { - ap.adjustAnnotationHeight(); + if (annotationAdded) + { + ap.adjustAnnotationHeight(); + } ap.paintAlignment(true); } @@ -120,8 +124,10 @@ class ColumnCounterWorker extends AlignCalcWorker /** * Scan each column of the alignment to calculate a count by feature type. Set * the count as the value of the alignment annotation for that feature type. + * + * @return */ - void computeAnnotations() + boolean computeAnnotations() { FeatureRenderer fr = new FeatureRenderer(alignViewport); // TODO use the commented out code once JAL-2075 is fixed @@ -130,56 +136,90 @@ class ColumnCounterWorker extends AlignCalcWorker // AlignmentView alignmentView = alignViewport.getAlignmentView(false); // AlignmentI alignment = alignmentView.getVisibleAlignment(' '); - // int width = alignmentView.getWidth(); + int rows = counter.getNames().length; + int width = alignment.getWidth(); int height = alignment.getHeight(); - int[] counts = new int[width]; - int max = 0; + int[][] counts = new int[width][rows]; + int max[] = new int[rows]; + for (int crow = 0; crow < rows; crow++) + { + max[crow] = 0; + } + + int[] minC = counter.getMinColour(); + int[] maxC = counter.getMaxColour(); + Color minColour = new Color(minC[0], minC[1], minC[2]); + Color maxColour = new Color(maxC[0], maxC[1], maxC[2]); for (int col = 0; col < width; col++) { - int count = 0; + int[] count = counts[col]; + for (int crow = 0; crow < rows; crow++) + { + count[crow] = 0; + } for (int row = 0; row < height; row++) { - count += countFeaturesAt(alignment, col, row, fr); + int[] colcount = countFeaturesAt(alignment, col, row, fr); + if (colcount != null) + { + for (int crow = 0; crow < rows; crow++) + { + count[crow] += colcount[crow]; + } + } } counts[col] = count; - max = Math.max(count, max); + for (int crow = 0; crow < rows; crow++) + { + max[crow] = Math.max(count[crow], max[crow]); + } } - Annotation[] anns = new Annotation[width]; - /* - * add non-zero counts as annotations - */ - for (int i = 0; i < counts.length; i++) + boolean annotationAdded = false; + + for (int anrow = 0; anrow < rows; anrow++) { - int count = counts[i]; - if (count > 0) + Annotation[] anns = new Annotation[width]; + /* + * add non-zero counts as annotations + */ + for (int i = 0; i < counts.length; i++) { - Color color = ColorUtils.getGraduatedColour(count, 0, Color.cyan, - max, Color.blue); - String str = String.valueOf(count); - anns[i] = new Annotation(str, str, '0', count, color); + int count = counts[i][anrow]; + if (count > 0) + { + Color color = ColorUtils.getGraduatedColour(count, 0, minColour, + max[anrow], maxColour); + String str = String.valueOf(count); + anns[i] = new Annotation(str, str, '0', count, color); + } } - } - /* - * construct or update the annotation - */ - AlignmentAnnotation ann = alignViewport.getAlignment() - .findOrCreateAnnotation(counter.getName(), - counter.getDescription(), false, null, null); - ann.description = counter.getDescription(); - ann.showAllColLabels = true; - ann.scaleColLabel = true; - ann.graph = AlignmentAnnotation.BAR_GRAPH; - ann.annotations = anns; - setGraphMinMax(ann, anns); - ann.validateRangeAndDisplay(); - if (!ourAnnots.contains(ann)) - { - ourAnnots.add(ann); + /* + * construct or update the annotation + */ + String description = counter.getDescriptions()[anrow]; + if (!alignment.findAnnotation(description).iterator().hasNext()) + { + annotationAdded = true; + } + AlignmentAnnotation ann = alignment.findOrCreateAnnotation( + counter.getNames()[anrow], description, false, null, null); + ann.description = description; + ann.showAllColLabels = true; + ann.scaleColLabel = true; + ann.graph = AlignmentAnnotation.BAR_GRAPH; + ann.annotations = anns; + setGraphMinMax(ann, anns); + ann.validateRangeAndDisplay(); + if (!ourAnnots.contains(ann)) + { + ourAnnots.add(ann); + } } + return annotationAdded; } /** @@ -191,22 +231,22 @@ class ColumnCounterWorker extends AlignCalcWorker * @param row * @param fr */ - int countFeaturesAt(AlignmentI alignment, int col, int row, + int[] countFeaturesAt(AlignmentI alignment, int col, int row, FeatureRenderer fr) { SequenceI seq = alignment.getSequenceAt(row); if (seq == null) { - return 0; + return null; } if (col >= seq.getLength()) { - return 0;// sequence doesn't extend this far + return null;// sequence doesn't extend this far } char res = seq.getCharAt(col); if (Comparison.isGap(res)) { - return 0; + return null; } int pos = seq.findPosition(col); @@ -216,7 +256,7 @@ class ColumnCounterWorker extends AlignCalcWorker // NB have to adjust pos if using AlignmentView.getVisibleAlignment // see JAL-2075 List features = fr.findFeaturesAtRes(seq, pos); - int count = this.counter.count(String.valueOf(res), features); + int[] count = this.counter.count(String.valueOf(res), features); return count; } diff --git a/src/jalview/workers/FeatureCounterI.java b/src/jalview/workers/FeatureSetCounterI.java similarity index 76% rename from src/jalview/workers/FeatureCounterI.java rename to src/jalview/workers/FeatureSetCounterI.java index 3a080ec..e14952f 100644 --- a/src/jalview/workers/FeatureCounterI.java +++ b/src/jalview/workers/FeatureSetCounterI.java @@ -18,6 +18,7 @@ * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ + package jalview.workers; import jalview.datamodel.SequenceFeature; @@ -25,15 +26,16 @@ import jalview.datamodel.SequenceFeature; import java.util.List; /** - * An interface for a type that returns counts of any value of interest at a - * sequence position that can be determined from the sequence character and any - * features present at that position + * An interface for a type that returns counts (per computed annotation type) of + * any value of interest at a sequence position that can be determined from the + * sequence character and any features present at that position * */ -public interface FeatureCounterI +public interface FeatureSetCounterI { /** - * Returns a count of some property of interest, for example + * Returns counts (per annotation type) of some properties of interest, for + * example *
      *
    • the number of variant features at the position
    • *
    • the number of Cath features of status 'True Positive'
    • @@ -46,22 +48,22 @@ public interface FeatureCounterI * @param a * list of any sequence features which include the position */ - int count(String residue, List features); + int[] count(String residue, List features); /** - * Returns a name for the annotation that this is counting, for use as the - * displayed label + * Returns names for the annotations that this is counting, for use as the + * displayed labels * * @return */ - String getName(); + String[] getNames(); /** - * Returns a description for the annotation, for display as a tooltip + * Returns descriptions for the annotations, for display as tooltips * * @return */ - String getDescription(); + String[] getDescriptions(); /** * Returns the colour (as [red, green, blue] values in the range 0-255) to use diff --git a/src/jalview/ws/jws1/JPredThread.java b/src/jalview/ws/jws1/JPredThread.java index e685d00..b0210d8 100644 --- a/src/jalview/ws/jws1/JPredThread.java +++ b/src/jalview/ws/jws1/JPredThread.java @@ -27,7 +27,7 @@ import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentView; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; import jalview.gui.Desktop; @@ -114,7 +114,7 @@ class JPredThread extends JWS1Thread implements WSClientI return null; } AlignmentI al = null; - ColumnSelection alcsel = null; + HiddenColumns alhidden = null; int FirstSeq = -1; // the position of the query sequence in Alignment al JpredResult result = (JpredResult) this.result; @@ -141,10 +141,10 @@ class JPredThread extends JWS1Thread implements WSClientI if (predMap != null) { Object[] alandcolsel = input - .getAlignmentAndColumnSelection(getGapChar()); + .getAlignmentAndHiddenColumns(getGapChar()); sqs = (SequenceI[]) alandcolsel[0]; al = new Alignment(sqs); - alcsel = (ColumnSelection) alandcolsel[1]; + alhidden = (HiddenColumns) alandcolsel[1]; } else { @@ -192,7 +192,7 @@ class JPredThread extends JWS1Thread implements WSClientI { char gc = getGapChar(); SequenceI[] sqs = (SequenceI[]) input - .getAlignmentAndColumnSelection(gc)[0]; + .getAlignmentAndHiddenColumns(gc)[0]; if (this.msaIndex >= sqs.length) { throw new Error( @@ -237,7 +237,7 @@ class JPredThread extends JWS1Thread implements WSClientI { // Adjust input view for gaps // propagate insertions into profile - alcsel = ColumnSelection.propagateInsertions(profileseq, al, + alhidden = HiddenColumns.propagateInsertions(profileseq, al, input); } } @@ -252,7 +252,7 @@ class JPredThread extends JWS1Thread implements WSClientI alant.sequenceRef); } } - return new Object[] { al, alcsel }; // , FirstSeq, noMsa}; + return new Object[] { al, alhidden }; // , FirstSeq, noMsa}; } /** @@ -625,7 +625,7 @@ class JPredThread extends JWS1Thread implements WSClientI if (res[1] != null) { af = new AlignFrame((Alignment) res[0], - (ColumnSelection) res[1], AlignFrame.DEFAULT_WIDTH, + (HiddenColumns) res[1], AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); } else @@ -651,7 +651,8 @@ class JPredThread extends JWS1Thread implements WSClientI */ af = new AlignFrame((Alignment) res[0], - (ColumnSelection) res[1], AlignFrame.DEFAULT_WIDTH, + (HiddenColumns) res[1], + AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); } Desktop.addInternalFrame(af, altitle, AlignFrame.DEFAULT_WIDTH, diff --git a/src/jalview/ws/jws1/MsaWSThread.java b/src/jalview/ws/jws1/MsaWSThread.java index e4247f7..72d41c9 100644 --- a/src/jalview/ws/jws1/MsaWSThread.java +++ b/src/jalview/ws/jws1/MsaWSThread.java @@ -26,7 +26,7 @@ import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentOrder; import jalview.datamodel.AlignmentView; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; import jalview.gui.Desktop; @@ -632,7 +632,7 @@ class MsaWSThread extends JWS1Thread implements WSClientI orders[j] = null; } SequenceI[] alignment = (SequenceI[]) newview[0]; - ColumnSelection columnselection = (ColumnSelection) newview[1]; + HiddenColumns hidden = (HiddenColumns) newview[1]; Alignment al = new Alignment(alignment); // TODO: add 'provenance' property to alignment from the method notes // accompanying each subjob @@ -646,7 +646,7 @@ class MsaWSThread extends JWS1Thread implements WSClientI if (newFrame) { - AlignFrame af = new AlignFrame(al, columnselection, + AlignFrame af = new AlignFrame(al, hidden, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); // initialise with same renderer settings as in parent alignframe. diff --git a/src/jalview/ws/jws2/MsaWSThread.java b/src/jalview/ws/jws2/MsaWSThread.java index e425624..2187f46 100644 --- a/src/jalview/ws/jws2/MsaWSThread.java +++ b/src/jalview/ws/jws2/MsaWSThread.java @@ -26,7 +26,7 @@ import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentOrder; import jalview.datamodel.AlignmentView; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; @@ -961,7 +961,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI orders[j] = null; } SequenceI[] alignment = (SequenceI[]) newview[0]; - ColumnSelection columnselection = (ColumnSelection) newview[1]; + HiddenColumns hidden = (HiddenColumns) newview[1]; Alignment al = new Alignment(alignment); // TODO: add 'provenance' property to alignment from the method notes if (lastProgram != null) @@ -979,7 +979,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI if (newFrame) { - displayInNewFrame(al, alorders, columnselection); + displayInNewFrame(al, alorders, hidden); } else @@ -1000,9 +1000,9 @@ class MsaWSThread extends AWS2Thread implements WSClientI * @param columnselection */ protected void displayInNewFrame(AlignmentI al, - List alorders, ColumnSelection columnselection) + List alorders, HiddenColumns hidden) { - AlignFrame af = new AlignFrame(al, columnselection, + AlignFrame af = new AlignFrame(al, hidden, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); // initialise with same renderer settings as in parent alignframe. diff --git a/src/jalview/ws/rest/RestClient.java b/src/jalview/ws/rest/RestClient.java index 7fbae89..27f5271 100644 --- a/src/jalview/ws/rest/RestClient.java +++ b/src/jalview/ws/rest/RestClient.java @@ -259,7 +259,8 @@ public class RestClient extends WSClient implements WSClientI, { // intersect groups with selected region _input = new AlignmentView(av.getAlignment(), - av.getColumnSelection(), av.getSelectionGroup(), + av.getAlignment() + .getHiddenColumns(), av.getSelectionGroup(), av.hasHiddenColumns(), true, true); viewTitle = MessageManager.formatMessage( "label.select_visible_region_of", @@ -272,7 +273,8 @@ public class RestClient extends WSClient implements WSClientI, { // use selected region to partition alignment _input = new AlignmentView(av.getAlignment(), - av.getColumnSelection(), av.getSelectionGroup(), + av.getAlignment() + .getHiddenColumns(), av.getSelectionGroup(), av.hasHiddenColumns(), false, true); } viewTitle = MessageManager.formatMessage( @@ -286,7 +288,8 @@ public class RestClient extends WSClient implements WSClientI, { // just take selected region intersection _input = new AlignmentView(av.getAlignment(), - av.getColumnSelection(), av.getSelectionGroup(), + av.getAlignment() + .getHiddenColumns(), av.getSelectionGroup(), av.hasHiddenColumns(), true, true); viewTitle = MessageManager.formatMessage( "label.select_visible_region_of", @@ -300,7 +303,8 @@ public class RestClient extends WSClient implements WSClientI, { // standard alignment view without selection present _input = new AlignmentView(av.getAlignment(), - av.getColumnSelection(), null, av.hasHiddenColumns(), false, + av.getAlignment() + .getHiddenColumns(), null, av.hasHiddenColumns(), false, true); viewTitle = "" + (av.hasHiddenColumns() ? (new StringBuffer(" ") diff --git a/src/jalview/ws/rest/RestJobThread.java b/src/jalview/ws/rest/RestJobThread.java index 75d2cd4..0592426 100644 --- a/src/jalview/ws/rest/RestJobThread.java +++ b/src/jalview/ws/rest/RestJobThread.java @@ -26,7 +26,7 @@ import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentOrder; import jalview.datamodel.Annotation; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; @@ -173,9 +173,13 @@ public class RestJobThread extends AWSThread private String getStage(Stage stg) { if (stg == Stage.SUBMIT) + { return "submitting "; + } if (stg == Stage.POLL) + { return "checking status of "; + } return (" being confused about "); } @@ -609,7 +613,7 @@ public class RestJobThread extends AWSThread // total number of distinct alignment sets generated by job set. int numAlSets = 0, als = 0; List destAls = new ArrayList(); - List destColsel = new ArrayList(); + List destColsel = new ArrayList(); List> trees = new ArrayList>(); do @@ -715,7 +719,7 @@ public class RestJobThread extends AWSThread RestJob rj = (RestJob) jobs[nrj]; int contigs[] = input.getVisibleContigs(); AlignmentI destAl = null; - jalview.datamodel.ColumnSelection destCs = null; + jalview.datamodel.HiddenColumns destHCs = null; // Resolve destAl for this data. if (als == 0 && rj.isInputContextModified()) { @@ -731,7 +735,7 @@ public class RestJobThread extends AWSThread if (!restClient.isAlignmentModified() && merge) { destAl = restClient.av.getAlignment(); - destCs = restClient.av.getColumnSelection(); + destHCs = restClient.av.getAlignment().getHiddenColumns(); resultDest .add(restClient.isShowResultsInNewView() ? AddDataTo.newView : AddDataTo.currentView); @@ -742,15 +746,15 @@ public class RestJobThread extends AWSThread newAlignment = true; // recreate the input alignment data Object[] idat = input - .getAlignmentAndColumnSelection(gapCharacter); + .getAlignmentAndHiddenColumns(gapCharacter); destAl = new Alignment((SequenceI[]) idat[0]); - destCs = (ColumnSelection) idat[1]; + destHCs = (HiddenColumns) idat[1]; resultDest.add(AddDataTo.newAlignment); // but do not add to the alignment panel list - since we need to // create a whole new alignFrame set. } destAls.add(destAl); - destColsel.add(destCs); + destColsel.add(destHCs); } } else @@ -769,7 +773,7 @@ public class RestJobThread extends AWSThread // recover reference to last alignment created for this rest frame // ready for extension destAl = destAls.get(als); - destCs = destColsel.get(als); + destHCs = destColsel.get(als); } else { @@ -798,12 +802,12 @@ public class RestJobThread extends AWSThread newview = input.getUpdatedView(rseqs, orders, gapCharacter); } destAl = new Alignment((SequenceI[]) newview[0]); - destCs = (ColumnSelection) newview[1]; + destHCs = (HiddenColumns) newview[1]; newAlignment = true; // TODO create alignment from result data with propagated // references. destAls.add(destAl); - destColsel.add(destCs); + destColsel.add(destHCs); resultDest.add(AddDataTo.newAlignment); throw new Error( MessageManager @@ -1043,7 +1047,7 @@ public class RestJobThread extends AWSThread for (AddDataTo action : resultDest) { AlignmentI destal; - ColumnSelection destcs; + HiddenColumns destcs; String alTitle = MessageManager.formatMessage( "label.webservice_job_title_on", new String[] { restClient.service.details.Action, diff --git a/test/jalview/analysis/DnaTest.java b/test/jalview/analysis/DnaTest.java index 2e21d9c..d2fa99a 100644 --- a/test/jalview/analysis/DnaTest.java +++ b/test/jalview/analysis/DnaTest.java @@ -28,7 +28,7 @@ import jalview.api.AlignViewportI; import jalview.datamodel.AlignedCodon; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceI; import jalview.gui.AlignViewport; @@ -133,7 +133,7 @@ public class DnaTest AlignmentI alf = new FormatAdapter().readFile( JAL_1312_example_align_fasta, DataSourceType.PASTE, FileFormat.Fasta); - ColumnSelection cs = new ColumnSelection(); + HiddenColumns cs = new HiddenColumns(); AlignViewportI av = new AlignViewport(alf, cs); Dna dna = new Dna(av, new int[] { 0, alf.getWidth() - 1 }); AlignmentI translated = dna.translateCdna(); @@ -157,7 +157,7 @@ public class DnaTest int vwidth = 15; for (int ipos = 0; ipos + vwidth < alf.getWidth(); ipos += vwidth) { - ColumnSelection cs = new ColumnSelection(); + HiddenColumns cs = new HiddenColumns(); if (ipos > 0) { cs.hideColumns(0, ipos - 1); @@ -188,7 +188,7 @@ public class DnaTest { AlignmentI alf = new FormatAdapter().readFile(fasta, DataSourceType.PASTE, FileFormat.Fasta); - ColumnSelection cs = new ColumnSelection(); + HiddenColumns cs = new HiddenColumns(); AlignViewportI av = new AlignViewport(alf, cs); Dna dna = new Dna(av, new int[] { 0, alf.getWidth() - 1 }); AlignmentI translated = dna.translateCdna(); @@ -208,7 +208,7 @@ public class DnaTest { AlignmentI alf = new FormatAdapter().readFile(fasta, DataSourceType.PASTE, FileFormat.Fasta); - ColumnSelection cs = new ColumnSelection(); + HiddenColumns cs = new HiddenColumns(); cs.hideColumns(6, 14); // hide codons 3/4/5 cs.hideColumns(24, 35); // hide codons 9-12 cs.hideColumns(177, 191); // hide codons 60-64 @@ -296,7 +296,7 @@ public class DnaTest */ AlignmentI cdna = new AlignmentGenerator(true) .generate(12, 8, 97, 5, 5); - ColumnSelection cs = new ColumnSelection(); + HiddenColumns cs = new HiddenColumns(); AlignViewportI av = new AlignViewport(cdna, cs); Dna dna = new Dna(av, new int[] { 0, cdna.getWidth() - 1 }); AlignmentI translated = dna.translateCdna(); @@ -542,7 +542,7 @@ public class DnaTest assertEquals(seqDs, al.getSequenceAt(0).getDatasetSequence() .getSequenceAsString()); - ColumnSelection cs = new ColumnSelection(); + HiddenColumns cs = new HiddenColumns(); AlignViewportI av = new AlignViewport(al, cs); Dna testee = new Dna(av, new int[] { 0, al.getWidth() - 1 }); AlignmentI reversed = testee.reverseCdna(false); diff --git a/test/jalview/datamodel/AllColsIteratorTest.java b/test/jalview/datamodel/AllColsIteratorTest.java new file mode 100644 index 0000000..fbb20be --- /dev/null +++ b/test/jalview/datamodel/AllColsIteratorTest.java @@ -0,0 +1,85 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import static org.testng.Assert.assertTrue; + +import java.util.NoSuchElementException; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class AllColsIteratorTest +{ + HiddenColumns hiddenCols; + + @BeforeClass + public void setup() + { + hiddenCols = new HiddenColumns(); + hiddenCols.hideColumns(2,4); + } + + + /* + * Test iterator iterates through collection correctly + */ + @Test(groups = { "Functional" }) + public void testHasNextAndNext() + { + AllColsIterator it = new AllColsIterator(0, 3, hiddenCols); + int count = 0; + while (it.hasNext()) + { + it.next(); + count++; + } + assertTrue(count == 4, "hasNext() is false after 4 iterations"); + } + + /* + * Test iterator throws NoSuchElementException at end of iteration + */ + @Test( + groups = { "Functional" }, + expectedExceptions = { NoSuchElementException.class }) + public void testLastNext() throws NoSuchElementException + { + AllColsIterator it = new AllColsIterator(0, 3, hiddenCols); + while (it.hasNext()) + { + it.next(); + } + it.next(); + } + + /* + * Test iterator throws UnsupportedOperationException on call to remove + */ + @Test( + groups = { "Functional" }, + expectedExceptions = { UnsupportedOperationException.class }) + public void testRemove() throws UnsupportedOperationException + { + AllColsIterator it = new AllColsIterator(0, 3, hiddenCols); + it.remove(); + } +} diff --git a/test/jalview/datamodel/AllRowsIteratorTest.java b/test/jalview/datamodel/AllRowsIteratorTest.java new file mode 100644 index 0000000..fd1d29d --- /dev/null +++ b/test/jalview/datamodel/AllRowsIteratorTest.java @@ -0,0 +1,113 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import static org.testng.Assert.assertTrue; + +import jalview.analysis.AlignmentGenerator; + +import java.util.Hashtable; +import java.util.NoSuchElementException; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class AllRowsIteratorTest +{ + AlignmentI al; + + Hashtable hiddenRepSequences = new Hashtable(); + + @BeforeClass + public void setup() + { + // create random alignment + AlignmentGenerator gen = new AlignmentGenerator(false); + al = gen.generate(20, 15, 123, 5, 5); + if (!hiddenRepSequences.isEmpty()) + { + al.getHiddenSequences().showAll(hiddenRepSequences); + } + hideSequences(2, 4); + } + + /* + * Test iterator iterates through collection correctly + */ + @Test(groups = { "Functional" }) + public void testHasNextAndNext() + { + AllRowsIterator it = new AllRowsIterator(0, 3, al); + int count = 0; + while (it.hasNext()) + { + it.next(); + count++; + } + assertTrue(count == 4, "hasNext() is false after 4 iterations"); + } + + /* + * Test iterator throws NoSuchElementException at end of iteration + */ + @Test( + groups = { "Functional" }, + expectedExceptions = { NoSuchElementException.class }) + public void testLastNext() throws NoSuchElementException + { + AllRowsIterator it = new AllRowsIterator(0, 3, al); + while (it.hasNext()) + { + it.next(); + } + it.next(); + } + + /* + * Test iterator throws UnsupportedOperationException on call to remove + */ + @Test( + groups = { "Functional" }, + expectedExceptions = { UnsupportedOperationException.class }) + public void testRemove() throws UnsupportedOperationException + { + AllRowsIterator it = new AllRowsIterator(0, 3, al); + it.remove(); + } + + + /* + * Hide sequences between start and end + */ + private void hideSequences(int start, int end) + { + SequenceI[] allseqs = al.getSequencesArray(); + SequenceGroup theseSeqs = new SequenceGroup(); + + for (int i = start; i <= end; i++) + { + theseSeqs.addSequence(allseqs[i], false); + al.getHiddenSequences().hideSequence(allseqs[i]); + } + + hiddenRepSequences.put(allseqs[start], theseSeqs); + } +} diff --git a/test/jalview/datamodel/ColumnSelectionTest.java b/test/jalview/datamodel/ColumnSelectionTest.java index 4d3f611..7237e63 100644 --- a/test/jalview/datamodel/ColumnSelectionTest.java +++ b/test/jalview/datamodel/ColumnSelectionTest.java @@ -22,10 +22,10 @@ package jalview.datamodel; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertFalse; -import static org.testng.AssertJUnit.assertSame; import static org.testng.AssertJUnit.assertTrue; import static org.testng.AssertJUnit.fail; +import jalview.analysis.AlignmentGenerator; import jalview.gui.JvOptionPane; import java.util.Arrays; @@ -59,6 +59,30 @@ public class ColumnSelectionTest assertEquals("[2, 5, 3]", sel.toString()); } + @Test(groups = { "Functional" }) + public void testSetElementsFrom() + { + ColumnSelection fromcs = new ColumnSelection(); + ColumnSelection tocs = new ColumnSelection(); + HiddenColumns hidden = new HiddenColumns(); + + fromcs.addElement(2); + fromcs.addElement(3); + fromcs.addElement(5); + + tocs.setElementsFrom(fromcs, hidden); + assertTrue(tocs.equals(fromcs)); + + hidden.hideColumns(4, 6); + tocs.setElementsFrom(fromcs, hidden); + + // expect cols 2 and 3 to be selected but not 5 + ColumnSelection expectcs = new ColumnSelection(); + expectcs.addElement(2); + expectcs.addElement(3); + assertTrue(tocs.equals(expectcs)); + } + /** * Test the remove method - in particular to verify that remove(int i) removes * the element whose value is i, _NOT_ the i'th element. @@ -88,264 +112,6 @@ public class ColumnSelectionTest } /** - * Test the method that finds the visible column position of an alignment - * column, allowing for hidden columns. - */ - @Test(groups = { "Functional" }) - public void testFindColumnPosition() - { - ColumnSelection cs = new ColumnSelection(); - assertEquals(5, cs.findColumnPosition(5)); - - // hiding column 6 makes no difference - cs.hideColumns(6, 6); - assertEquals(5, cs.findColumnPosition(5)); - - // hiding column 4 moves column 5 to column 4 - cs.hideColumns(4, 4); - assertEquals(4, cs.findColumnPosition(5)); - - // hiding column 4 moves column 4 to position 3 - assertEquals(3, cs.findColumnPosition(4)); - - // hiding columns 1 and 2 moves column 5 to column 2 - cs.hideColumns(1, 2); - assertEquals(2, cs.findColumnPosition(5)); - - // check with > 1 hidden column regions - // where some columns are in the hidden regions - ColumnSelection cs2 = new ColumnSelection(); - cs2.hideColumns(5, 10); - cs2.hideColumns(20, 27); - cs2.hideColumns(40, 44); - - // hiding columns 5-10 and 20-27 moves column 8 to column 4 - assertEquals(4, cs2.findColumnPosition(8)); - - // and moves column 24 to 13 - assertEquals(13, cs2.findColumnPosition(24)); - - // and moves column 28 to 14 - assertEquals(14, cs2.findColumnPosition(28)); - - // and moves column 40 to 25 - assertEquals(25, cs2.findColumnPosition(40)); - - // check when hidden columns start at 0 that the visible column - // is returned as 0 - ColumnSelection cs3 = new ColumnSelection(); - cs3.hideColumns(0, 4); - assertEquals(0, cs3.findColumnPosition(2)); - - } - - /** - * Test the method that finds the visible column position a given distance - * before another column - */ - @Test(groups = { "Functional" }) - public void testFindColumnNToLeft() - { - ColumnSelection cs = new ColumnSelection(); - - // test that without hidden columns, findColumnNToLeft returns - // position n to left of provided position - int pos = cs.subtractVisibleColumns(3, 10); - assertEquals(7, pos); - - // 0 returns same position - pos = cs.subtractVisibleColumns(0, 10); - assertEquals(10, pos); - - // overflow to left returns negative number - pos = cs.subtractVisibleColumns(3, 0); - assertEquals(-3, pos); - - // test that with hidden columns to left of result column - // behaviour is the same as above - cs.hideColumns(1, 3); - - // position n to left of provided position - pos = cs.subtractVisibleColumns(3, 10); - assertEquals(7, pos); - - // 0 returns same position - pos = cs.subtractVisibleColumns(0, 10); - assertEquals(10, pos); - - // test with one set of hidden columns between start and required position - cs.hideColumns(12, 15); - pos = cs.subtractVisibleColumns(8, 17); - assertEquals(5, pos); - - // test with two sets of hidden columns between start and required position - cs.hideColumns(20, 21); - pos = cs.subtractVisibleColumns(8, 23); - assertEquals(9, pos); - - // repeat last 2 tests with no hidden columns to left of required position - cs.revealAllHiddenColumns(); - - // test with one set of hidden columns between start and required position - cs.hideColumns(12, 15); - pos = cs.subtractVisibleColumns(8, 17); - assertEquals(5, pos); - - // test with two sets of hidden columns between start and required position - cs.hideColumns(20, 21); - pos = cs.subtractVisibleColumns(8, 23); - assertEquals(9, pos); - - } - - /** - * Test the code used to locate the reference sequence ruler origin - */ - @Test(groups = { "Functional" }) - public void testLocateVisibleBoundsofSequence() - { - ColumnSelection cs = new ColumnSelection(); - SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---"); - assertEquals(2, seq.findIndex(seq.getStart())); - - // no hidden columns - assertEquals( - Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1, - seq.findIndex(seq.getEnd()) - 1, seq.getStart(), - seq.getEnd(), seq.findIndex(seq.getStart()) - 1, - seq.findIndex(seq.getEnd()) - 1 }), - Arrays.toString(cs.locateVisibleBoundsOfSequence(seq))); - - // hidden column on gap after end of sequence - should not affect bounds - cs.hideColumns(13); - assertEquals( - Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1, - seq.findIndex(seq.getEnd()) - 1, seq.getStart(), - seq.getEnd(), seq.findIndex(seq.getStart()) - 1, - seq.findIndex(seq.getEnd()) - 1 }), - Arrays.toString(cs.locateVisibleBoundsOfSequence(seq))); - - cs.revealAllHiddenColumns(); - // hidden column on gap before beginning of sequence - should vis bounds by - // one - cs.hideColumns(0); - assertEquals( - Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 2, - seq.findIndex(seq.getEnd()) - 2, seq.getStart(), - seq.getEnd(), seq.findIndex(seq.getStart()) - 1, - seq.findIndex(seq.getEnd()) - 1 }), - Arrays.toString(cs.locateVisibleBoundsOfSequence(seq))); - - cs.revealAllHiddenColumns(); - // hide columns around most of sequence - leave one residue remaining - cs.hideColumns(1, 3); - cs.hideColumns(6, 11); - assertEquals("-D", - cs.getVisibleSequenceStrings(0, 5, new SequenceI[] { seq })[0]); - assertEquals( - Arrays.toString(new int[] { 1, 1, 3, 3, - seq.findIndex(seq.getStart()) - 1, - seq.findIndex(seq.getEnd()) - 1 }), - Arrays.toString(cs.locateVisibleBoundsOfSequence(seq))); - cs.revealAllHiddenColumns(); - - // hide whole sequence - should just get location of hidden region - // containing sequence - cs.hideColumns(1, 11); - assertEquals( - Arrays.toString(new int[] { 0, 1, 0, 0, - seq.findIndex(seq.getStart()) - 1, - seq.findIndex(seq.getEnd()) - 1 }), - Arrays.toString(cs.locateVisibleBoundsOfSequence(seq))); - - } - - @Test(groups = { "Functional" }) - public void testLocateVisibleBoundsPathologicals() - { - // test some pathological cases we missed - AlignmentI al = new Alignment(new SequenceI[] { new Sequence( - "refseqGaptest", "KTDVTI----------NFI-----G----L") }); - ColumnSelection cs = new ColumnSelection(); - cs.hideInsertionsFor(al.getSequenceAt(0)); - assertEquals( - "G", - "" - + al.getSequenceAt(0).getCharAt( - cs.adjustForHiddenColumns(9))); - - } - - @Test(groups = { "Functional" }) - public void testHideColumns() - { - ColumnSelection cs = new ColumnSelection(); - cs.hideColumns(5); - List hidden = cs.getHiddenColumns(); - assertEquals(1, hidden.size()); - assertEquals("[5, 5]", Arrays.toString(hidden.get(0))); - - cs.hideColumns(3); - assertEquals(2, hidden.size()); - // two hidden ranges, in order: - assertSame(hidden, cs.getHiddenColumns()); - assertEquals("[3, 3]", Arrays.toString(hidden.get(0))); - assertEquals("[5, 5]", Arrays.toString(hidden.get(1))); - - // hiding column 4 expands [3, 3] to [3, 4] - // and merges to [5, 5] to make [3, 5] - cs.hideColumns(4); - hidden = cs.getHiddenColumns(); - assertEquals(1, hidden.size()); - assertEquals("[3, 5]", Arrays.toString(hidden.get(0))); - - // clear hidden columns (note they are added to selected) - cs.revealAllHiddenColumns(); - // it is now actually null but getter returns an empty list - assertTrue(cs.getHiddenColumns().isEmpty()); - - cs.hideColumns(3, 6); - hidden = cs.getHiddenColumns(); - int[] firstHiddenRange = hidden.get(0); - assertEquals("[3, 6]", Arrays.toString(firstHiddenRange)); - - // adding a subrange of already hidden should do nothing - cs.hideColumns(4, 5); - assertEquals(1, hidden.size()); - assertSame(firstHiddenRange, cs.getHiddenColumns().get(0)); - cs.hideColumns(3, 5); - assertEquals(1, hidden.size()); - assertSame(firstHiddenRange, cs.getHiddenColumns().get(0)); - cs.hideColumns(4, 6); - assertEquals(1, hidden.size()); - assertSame(firstHiddenRange, cs.getHiddenColumns().get(0)); - cs.hideColumns(3, 6); - assertEquals(1, hidden.size()); - assertSame(firstHiddenRange, cs.getHiddenColumns().get(0)); - - cs.revealAllHiddenColumns(); - cs.hideColumns(2, 4); - hidden = cs.getHiddenColumns(); - assertEquals(1, hidden.size()); - assertEquals("[2, 4]", Arrays.toString(hidden.get(0))); - - // extend contiguous with 2 positions overlap - cs.hideColumns(3, 5); - assertEquals(1, hidden.size()); - assertEquals("[2, 5]", Arrays.toString(hidden.get(0))); - - // extend contiguous with 1 position overlap - cs.hideColumns(5, 6); - assertEquals(1, hidden.size()); - assertEquals("[2, 6]", Arrays.toString(hidden.get(0))); - - // extend contiguous with overlap both ends: - cs.hideColumns(1, 7); - assertEquals(1, hidden.size()); - assertEquals("[1, 7]", Arrays.toString(hidden.get(0))); - } - - /** * Test the method that hides a specified column including any adjacent * selected columns. This is a convenience method for the case where multiple * column regions are selected and then hidden using menu option View | Hide | @@ -354,48 +120,55 @@ public class ColumnSelectionTest @Test(groups = { "Functional" }) public void testHideColumns_withSelection() { + // create random alignment + AlignmentGenerator gen = new AlignmentGenerator(false); + AlignmentI al = gen.generate(50, 20, 123, 5, 5); + ColumnSelection cs = new ColumnSelection(); // select columns 4-6 cs.addElement(4); cs.addElement(5); cs.addElement(6); // hide column 5 (and adjacent): - cs.hideColumns(5); + cs.hideSelectedColumns(5, al.getHiddenColumns()); // 4,5,6 now hidden: - List hidden = cs.getHiddenColumns(); + List hidden = al.getHiddenColumns().getHiddenRegions(); assertEquals(1, hidden.size()); assertEquals("[4, 6]", Arrays.toString(hidden.get(0))); // none now selected: assertTrue(cs.getSelected().isEmpty()); // repeat, hiding column 4 (5 and 6) + al = gen.generate(50, 20, 123, 5, 5); cs = new ColumnSelection(); cs.addElement(4); cs.addElement(5); cs.addElement(6); - cs.hideColumns(4); - hidden = cs.getHiddenColumns(); + cs.hideSelectedColumns(4, al.getHiddenColumns()); + hidden = al.getHiddenColumns().getHiddenRegions(); assertEquals(1, hidden.size()); assertEquals("[4, 6]", Arrays.toString(hidden.get(0))); assertTrue(cs.getSelected().isEmpty()); // repeat, hiding column (4, 5 and) 6 + al = gen.generate(50, 20, 123, 5, 5); cs = new ColumnSelection(); cs.addElement(4); cs.addElement(5); cs.addElement(6); - cs.hideColumns(6); - hidden = cs.getHiddenColumns(); + cs.hideSelectedColumns(6, al.getHiddenColumns()); + hidden = al.getHiddenColumns().getHiddenRegions(); assertEquals(1, hidden.size()); assertEquals("[4, 6]", Arrays.toString(hidden.get(0))); assertTrue(cs.getSelected().isEmpty()); // repeat, with _only_ adjacent columns selected + al = gen.generate(50, 20, 123, 5, 5); cs = new ColumnSelection(); cs.addElement(4); cs.addElement(6); - cs.hideColumns(5); - hidden = cs.getHiddenColumns(); + cs.hideSelectedColumns(5, al.getHiddenColumns()); + hidden = al.getHiddenColumns().getHiddenRegions(); assertEquals(1, hidden.size()); assertEquals("[4, 6]", Arrays.toString(hidden.get(0))); assertTrue(cs.getSelected().isEmpty()); @@ -407,17 +180,23 @@ public class ColumnSelectionTest @Test(groups = { "Functional" }) public void testHideSelectedColumns() { + // create random alignment + AlignmentGenerator gen = new AlignmentGenerator(false); + AlignmentI al = gen.generate(50, 20, 123, 5, 5); + ColumnSelection cs = new ColumnSelection(); int[] sel = { 2, 3, 4, 7, 8, 9, 20, 21, 22 }; for (int col : sel) { cs.addElement(col); } - cs.hideColumns(15, 18); - cs.hideSelectedColumns(); + HiddenColumns cols = al.getHiddenColumns(); + cols.hideColumns(15, 18); + + cs.hideSelectedColumns(al); assertTrue(cs.getSelected().isEmpty()); - List hidden = cs.getHiddenColumns(); + List hidden = cols.getHiddenRegions(); assertEquals(4, hidden.size()); assertEquals("[2, 4]", Arrays.toString(hidden.get(0))); assertEquals("[7, 9]", Arrays.toString(hidden.get(1))); @@ -455,104 +234,27 @@ public class ColumnSelectionTest assertEquals("[0, 4]", Arrays.toString(range.get(0))); } - /** - * Test the method that reveals a range of hidden columns given the start - * column of the range - */ - @Test(groups = { "Functional" }) - public void testRevealHiddenColumns() - { - ColumnSelection cs = new ColumnSelection(); - cs.hideColumns(5, 8); - cs.addElement(10); - cs.revealHiddenColumns(5); - // hidden columns list now null but getter returns empty list: - assertTrue(cs.getHiddenColumns().isEmpty()); - // revealed columns are marked as selected (added to selection): - assertEquals("[10, 5, 6, 7, 8]", cs.getSelected().toString()); - - // calling with a column other than the range start does nothing: - cs = new ColumnSelection(); - cs.hideColumns(5, 8); - List hidden = cs.getHiddenColumns(); - cs.revealHiddenColumns(6); - assertSame(hidden, cs.getHiddenColumns()); - assertTrue(cs.getSelected().isEmpty()); - } - - @Test(groups = { "Functional" }) - public void testRevealAllHiddenColumns() - { - ColumnSelection cs = new ColumnSelection(); - cs.hideColumns(5, 8); - cs.hideColumns(2, 3); - cs.addElement(11); - cs.addElement(1); - cs.revealAllHiddenColumns(); - - /* - * revealing hidden columns adds them (in order) to the (unordered) - * selection list - */ - assertTrue(cs.getHiddenColumns().isEmpty()); - assertEquals("[11, 1, 2, 3, 5, 6, 7, 8]", cs.getSelected().toString()); - } - - @Test(groups = { "Functional" }) - public void testIsVisible() - { - ColumnSelection cs = new ColumnSelection(); - cs.hideColumns(2, 4); - cs.hideColumns(6, 7); - assertTrue(cs.isVisible(0)); - assertTrue(cs.isVisible(-99)); - assertTrue(cs.isVisible(1)); - assertFalse(cs.isVisible(2)); - assertFalse(cs.isVisible(3)); - assertFalse(cs.isVisible(4)); - assertTrue(cs.isVisible(5)); - assertFalse(cs.isVisible(6)); - assertFalse(cs.isVisible(7)); - } - - @Test(groups = { "Functional" }) - public void testGetVisibleContigs() - { - ColumnSelection cs = new ColumnSelection(); - cs.hideColumns(3, 6); - cs.hideColumns(8, 9); - cs.hideColumns(12, 12); - - // start position is inclusive, end position exclusive: - int[] visible = cs.getVisibleContigs(1, 13); - assertEquals("[1, 2, 7, 7, 10, 11]", Arrays.toString(visible)); - - visible = cs.getVisibleContigs(4, 14); - assertEquals("[7, 7, 10, 11, 13, 13]", Arrays.toString(visible)); - - visible = cs.getVisibleContigs(3, 10); - assertEquals("[7, 7]", Arrays.toString(visible)); - - visible = cs.getVisibleContigs(4, 6); - assertEquals("[]", Arrays.toString(visible)); - } - @Test(groups = { "Functional" }) public void testInvertColumnSelection() { + // create random alignment + AlignmentGenerator gen = new AlignmentGenerator(false); + AlignmentI al = gen.generate(50, 20, 123, 5, 5); + ColumnSelection cs = new ColumnSelection(); cs.addElement(4); cs.addElement(6); cs.addElement(8); - cs.hideColumns(3, 3); - cs.hideColumns(6, 6); + + HiddenColumns cols = al.getHiddenColumns(); + cols.hideColumns(3, 3); + cols.hideColumns(6, 6); // invert selection from start (inclusive) to end (exclusive) - // hidden columns are _not_ changed - cs.invertColumnSelection(2, 9); + cs.invertColumnSelection(2, 9, al); assertEquals("[2, 5, 7]", cs.getSelected().toString()); - cs.invertColumnSelection(1, 9); + cs.invertColumnSelection(1, 9, al); assertEquals("[1, 4, 8]", cs.getSelected().toString()); } @@ -595,9 +297,6 @@ public class ColumnSelectionTest cs.addElement(0); cs.addElement(513); cs.addElement(1); - cs.hideColumns(3); - cs.hideColumns(7); - cs.hideColumns(5, 9); // same selections added in a different order ColumnSelection cs2 = new ColumnSelection(); @@ -605,15 +304,6 @@ public class ColumnSelectionTest cs2.addElement(513); cs2.addElement(0); - // with no hidden columns - assertFalse(cs.equals(cs2)); - assertFalse(cs2.equals(cs)); - - // with hidden columns added in a different order - cs2.hideColumns(6, 9); - cs2.hideColumns(5, 8); - cs2.hideColumns(3); - assertTrue(cs.equals(cs2)); assertTrue(cs.equals(cs)); assertTrue(cs2.equals(cs)); @@ -625,18 +315,20 @@ public class ColumnSelectionTest cs2.removeElement(12); assertTrue(cs.equals(cs2)); - - cs2.hideColumns(88); - assertFalse(cs.equals(cs2)); - /* - * unhiding a column adds it to selection! - */ - cs2.revealHiddenColumns(88); - assertFalse(cs.equals(cs2)); - cs.addElement(88); - assertTrue(cs.equals(cs2)); } + /* + cs2.hideSelectedColumns(88); + assertFalse(cs.equals(cs2)); + /* + * unhiding a column adds it to selection! + */ + /* cs2.revealHiddenColumns(88); + assertFalse(cs.equals(cs2)); + cs.addElement(88); + assertTrue(cs.equals(cs2)); + */ + /** * Test the method that returns selected columns, in the order in which they * were added @@ -834,75 +526,14 @@ public class ColumnSelectionTest ColumnSelection cs = new ColumnSelection(); cs.addElement(3); cs.addElement(1); - cs.hideColumns(10, 11); - cs.hideColumns(5, 7); - assertEquals("[5, 7]", Arrays.toString(cs.getHiddenColumns().get(0))); ColumnSelection cs2 = new ColumnSelection(cs); assertTrue(cs2.hasSelectedColumns()); - assertTrue(cs2.hasHiddenColumns()); + // order of column selection is preserved assertEquals("[3, 1]", cs2.getSelected().toString()); - assertEquals(2, cs2.getHiddenColumns().size()); - // hidden columns are held in column order - assertEquals("[5, 7]", Arrays.toString(cs2.getHiddenColumns().get(0))); - assertEquals("[10, 11]", Arrays.toString(cs2.getHiddenColumns().get(1))); } - /** - * Test for the case when a hidden range encloses more one already hidden - * range - */ - @Test(groups = { "Functional" }) - public void testHideColumns_subsumingHidden() - { - /* - * JAL-2370 bug scenario: - * two hidden ranges subsumed by a third - */ - ColumnSelection cs = new ColumnSelection(); - cs.hideColumns(49, 59); - cs.hideColumns(69, 79); - List hidden = cs.getHiddenColumns(); - assertEquals(2, hidden.size()); - assertEquals("[49, 59]", Arrays.toString(hidden.get(0))); - assertEquals("[69, 79]", Arrays.toString(hidden.get(1))); - - cs.hideColumns(48, 80); - hidden = cs.getHiddenColumns(); - assertEquals(1, hidden.size()); - assertEquals("[48, 80]", Arrays.toString(hidden.get(0))); - - /* - * another...joining hidden ranges - */ - cs = new ColumnSelection(); - cs.hideColumns(10, 20); - cs.hideColumns(30, 40); - cs.hideColumns(50, 60); - // hiding 21-49 should merge to one range - cs.hideColumns(21, 49); - hidden = cs.getHiddenColumns(); - assertEquals(1, hidden.size()); - assertEquals("[10, 60]", Arrays.toString(hidden.get(0))); - - /* - * another...lef overlap, subsumption, right overlap, - * no overlap of existing hidden ranges - */ - cs = new ColumnSelection(); - cs.hideColumns(10, 20); - cs.hideColumns(10, 20); - cs.hideColumns(30, 35); - cs.hideColumns(40, 50); - cs.hideColumns(60, 70); - - cs.hideColumns(15, 45); - hidden = cs.getHiddenColumns(); - assertEquals(2, hidden.size()); - assertEquals("[10, 50]", Arrays.toString(hidden.get(0))); - assertEquals("[60, 70]", Arrays.toString(hidden.get(1))); - } @Test(groups = { "Functional" }) public void testStretchGroup_expand() diff --git a/test/jalview/datamodel/HiddenColumnsTest.java b/test/jalview/datamodel/HiddenColumnsTest.java new file mode 100644 index 0000000..b767cf7 --- /dev/null +++ b/test/jalview/datamodel/HiddenColumnsTest.java @@ -0,0 +1,520 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertSame; +import static org.testng.AssertJUnit.assertTrue; + +import jalview.analysis.AlignmentGenerator; +import jalview.gui.JvOptionPane; + +import java.util.Arrays; +import java.util.List; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class HiddenColumnsTest +{ + + @BeforeClass(alwaysRun = true) + public void setUpJvOptionPane() + { + JvOptionPane.setInteractiveMode(false); + JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION); + } + + /** + * Test the method which counts the number of hidden columns + */ + @Test(groups = { "Functional" }) + public void testGetSize() + { + HiddenColumns hidden = new HiddenColumns(); + assertEquals(0, hidden.getSize()); + + hidden.hideColumns(3, 5); + assertEquals(3, hidden.getSize()); + + hidden.hideColumns(8, 8); + assertEquals(4, hidden.getSize()); + + hidden.hideColumns(9, 14); + assertEquals(10, hidden.getSize()); + + ColumnSelection cs = new ColumnSelection(); + hidden.revealAllHiddenColumns(cs); + assertEquals(0, hidden.getSize()); + } + + /** + * Test the method that finds the visible column position of an alignment + * column, allowing for hidden columns. + */ + @Test(groups = { "Functional" }) + public void testFindColumnPosition() + { + HiddenColumns cs = new HiddenColumns(); + assertEquals(5, cs.findColumnPosition(5)); + + // hiding column 6 makes no difference + cs.hideColumns(6, 6); + assertEquals(5, cs.findColumnPosition(5)); + + // hiding column 4 moves column 5 to column 4 + cs.hideColumns(4, 4); + assertEquals(4, cs.findColumnPosition(5)); + + // hiding column 4 moves column 4 to position 3 + assertEquals(3, cs.findColumnPosition(4)); + + // hiding columns 1 and 2 moves column 5 to column 2 + cs.hideColumns(1, 2); + assertEquals(2, cs.findColumnPosition(5)); + + // check with > 1 hidden column regions + // where some columns are in the hidden regions + HiddenColumns cs2 = new HiddenColumns(); + cs2.hideColumns(5, 10); + cs2.hideColumns(20, 27); + cs2.hideColumns(40, 44); + + // hiding columns 5-10 and 20-27 moves column 8 to column 4 + assertEquals(4, cs2.findColumnPosition(8)); + + // and moves column 24 to 13 + assertEquals(13, cs2.findColumnPosition(24)); + + // and moves column 28 to 14 + assertEquals(14, cs2.findColumnPosition(28)); + + // and moves column 40 to 25 + assertEquals(25, cs2.findColumnPosition(40)); + + // check when hidden columns start at 0 that the visible column + // is returned as 0 + HiddenColumns cs3 = new HiddenColumns(); + cs3.hideColumns(0, 4); + assertEquals(0, cs3.findColumnPosition(2)); + + } + + /** + * Test the method that finds the visible column position a given distance + * before another column + */ + @Test(groups = { "Functional" }) + public void testFindColumnNToLeft() + { + HiddenColumns cs = new HiddenColumns(); + + // test that without hidden columns, findColumnNToLeft returns + // position n to left of provided position + int pos = cs.subtractVisibleColumns(3, 10); + assertEquals(7, pos); + + // 0 returns same position + pos = cs.subtractVisibleColumns(0, 10); + assertEquals(10, pos); + + // overflow to left returns negative number + pos = cs.subtractVisibleColumns(3, 0); + assertEquals(-3, pos); + + // test that with hidden columns to left of result column + // behaviour is the same as above + cs.hideColumns(1, 3); + + // position n to left of provided position + pos = cs.subtractVisibleColumns(3, 10); + assertEquals(7, pos); + + // 0 returns same position + pos = cs.subtractVisibleColumns(0, 10); + assertEquals(10, pos); + + // test with one set of hidden columns between start and required position + cs.hideColumns(12, 15); + pos = cs.subtractVisibleColumns(8, 17); + assertEquals(5, pos); + + // test with two sets of hidden columns between start and required position + cs.hideColumns(20, 21); + pos = cs.subtractVisibleColumns(8, 23); + assertEquals(9, pos); + + // repeat last 2 tests with no hidden columns to left of required position + ColumnSelection colsel = new ColumnSelection(); + cs.revealAllHiddenColumns(colsel); + + // test with one set of hidden columns between start and required position + cs.hideColumns(12, 15); + pos = cs.subtractVisibleColumns(8, 17); + assertEquals(5, pos); + + // test with two sets of hidden columns between start and required position + cs.hideColumns(20, 21); + pos = cs.subtractVisibleColumns(8, 23); + assertEquals(9, pos); + + } + + @Test(groups = { "Functional" }) + public void testGetVisibleContigs() + { + HiddenColumns cs = new HiddenColumns(); + cs.hideColumns(3, 6); + cs.hideColumns(8, 9); + cs.hideColumns(12, 12); + + // start position is inclusive, end position exclusive: + int[] visible = cs.getVisibleContigs(1, 13); + assertEquals("[1, 2, 7, 7, 10, 11]", Arrays.toString(visible)); + + visible = cs.getVisibleContigs(4, 14); + assertEquals("[7, 7, 10, 11, 13, 13]", Arrays.toString(visible)); + + visible = cs.getVisibleContigs(3, 10); + assertEquals("[7, 7]", Arrays.toString(visible)); + + visible = cs.getVisibleContigs(4, 6); + assertEquals("[]", Arrays.toString(visible)); + } + + @Test(groups = { "Functional" }) + public void testEquals() + { + HiddenColumns cs = new HiddenColumns(); + cs.hideColumns(5, 9); + + // a different set of hidden columns + HiddenColumns cs2 = new HiddenColumns(); + + // with no hidden columns + assertFalse(cs.equals(cs2)); + assertFalse(cs2.equals(cs)); + + // with hidden columns added in a different order + cs2.hideColumns(6, 9); + cs2.hideColumns(5, 8); + + assertTrue(cs.equals(cs2)); + assertTrue(cs.equals(cs)); + assertTrue(cs2.equals(cs)); + assertTrue(cs2.equals(cs2)); + } + + @Test(groups = "Functional") + public void testCopyConstructor() + { + HiddenColumns cs = new HiddenColumns(); + cs.hideColumns(10, 11); + cs.hideColumns(5, 7); + assertEquals("[5, 7]", Arrays.toString(cs.getHiddenRegions().get(0))); + + HiddenColumns cs2 = new HiddenColumns(cs); + assertTrue(cs2.hasHiddenColumns()); + assertEquals(2, cs2.getHiddenRegions().size()); + // hidden columns are held in column order + assertEquals("[5, 7]", Arrays.toString(cs2.getHiddenRegions().get(0))); + assertEquals("[10, 11]", Arrays.toString(cs2.getHiddenRegions().get(1))); + } + + /** + * Test the code used to locate the reference sequence ruler origin + */ + @Test(groups = { "Functional" }) + public void testLocateVisibleBoundsofSequence() + { + // create random alignment + AlignmentGenerator gen = new AlignmentGenerator(false); + AlignmentI al = gen.generate(50, 20, 123, 5, 5); + + HiddenColumns cs = al.getHiddenColumns(); + ColumnSelection colsel = new ColumnSelection(); + + SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---"); + assertEquals(2, seq.findIndex(seq.getStart())); + + // no hidden columns + assertEquals( + Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1, + seq.findIndex(seq.getEnd()) - 1, seq.getStart(), + seq.getEnd(), seq.findIndex(seq.getStart()) - 1, + seq.findIndex(seq.getEnd()) - 1 }), + Arrays.toString(cs.locateVisibleBoundsOfSequence(seq))); + + // hidden column on gap after end of sequence - should not affect bounds + colsel.hideSelectedColumns(13, al.getHiddenColumns()); + assertEquals( + Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1, + seq.findIndex(seq.getEnd()) - 1, seq.getStart(), + seq.getEnd(), seq.findIndex(seq.getStart()) - 1, + seq.findIndex(seq.getEnd()) - 1 }), + Arrays.toString(cs.locateVisibleBoundsOfSequence(seq))); + + cs.revealAllHiddenColumns(colsel); + // hidden column on gap before beginning of sequence - should vis bounds by + // one + colsel.hideSelectedColumns(0, al.getHiddenColumns()); + assertEquals( + Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 2, + seq.findIndex(seq.getEnd()) - 2, seq.getStart(), + seq.getEnd(), seq.findIndex(seq.getStart()) - 1, + seq.findIndex(seq.getEnd()) - 1 }), + Arrays.toString(cs.locateVisibleBoundsOfSequence(seq))); + + cs.revealAllHiddenColumns(colsel); + // hide columns around most of sequence - leave one residue remaining + cs.hideColumns(1, 3); + cs.hideColumns(6, 11); + assertEquals("-D", + cs.getVisibleSequenceStrings(0, 5, new SequenceI[] { seq })[0]); + assertEquals( + Arrays.toString(new int[] { 1, 1, 3, 3, + seq.findIndex(seq.getStart()) - 1, + seq.findIndex(seq.getEnd()) - 1 }), + Arrays.toString(cs.locateVisibleBoundsOfSequence(seq))); + cs.revealAllHiddenColumns(colsel); + + // hide whole sequence - should just get location of hidden region + // containing sequence + cs.hideColumns(1, 11); + assertEquals( + Arrays.toString(new int[] { 0, 1, 0, 0, + seq.findIndex(seq.getStart()) - 1, + seq.findIndex(seq.getEnd()) - 1 }), + Arrays.toString(cs.locateVisibleBoundsOfSequence(seq))); + + } + + @Test(groups = { "Functional" }) + public void testLocateVisibleBoundsPathologicals() + { + // test some pathological cases we missed + AlignmentI al = new Alignment(new SequenceI[] { new Sequence( + "refseqGaptest", "KTDVTI----------NFI-----G----L") }); + HiddenColumns cs = new HiddenColumns(); + cs.hideInsertionsFor(al.getSequenceAt(0)); + assertEquals( + "G", + "" + + al.getSequenceAt(0).getCharAt( + cs.adjustForHiddenColumns(9))); + + } + + @Test(groups = { "Functional" }) + public void testHideColumns() + { + // create random alignment + AlignmentGenerator gen = new AlignmentGenerator(false); + AlignmentI al = gen.generate(50, 20, 123, 5, 5); + + ColumnSelection colsel = new ColumnSelection(); + HiddenColumns cs = al.getHiddenColumns(); + colsel.hideSelectedColumns(5, al.getHiddenColumns()); + List hidden = cs.getHiddenRegions(); + assertEquals(1, hidden.size()); + assertEquals("[5, 5]", Arrays.toString(hidden.get(0))); + + colsel.hideSelectedColumns(3, al.getHiddenColumns()); + assertEquals(2, hidden.size()); + // two hidden ranges, in order: + assertSame(hidden, cs.getHiddenRegions()); + assertEquals("[3, 3]", Arrays.toString(hidden.get(0))); + assertEquals("[5, 5]", Arrays.toString(hidden.get(1))); + + // hiding column 4 expands [3, 3] to [3, 4] + // and merges to [5, 5] to make [3, 5] + colsel.hideSelectedColumns(4, al.getHiddenColumns()); + hidden = cs.getHiddenRegions(); + assertEquals(1, hidden.size()); + assertEquals("[3, 5]", Arrays.toString(hidden.get(0))); + + // clear hidden columns (note they are added to selected) + cs.revealAllHiddenColumns(colsel); + // it is now actually null but getter returns an empty list + assertTrue(cs.getHiddenRegions().isEmpty()); + + cs.hideColumns(3, 6); + hidden = cs.getHiddenRegions(); + int[] firstHiddenRange = hidden.get(0); + assertEquals("[3, 6]", Arrays.toString(firstHiddenRange)); + + // adding a subrange of already hidden should do nothing + cs.hideColumns(4, 5); + assertEquals(1, hidden.size()); + assertSame(firstHiddenRange, cs.getHiddenRegions().get(0)); + cs.hideColumns(3, 5); + assertEquals(1, hidden.size()); + assertSame(firstHiddenRange, cs.getHiddenRegions().get(0)); + cs.hideColumns(4, 6); + assertEquals(1, hidden.size()); + assertSame(firstHiddenRange, cs.getHiddenRegions().get(0)); + cs.hideColumns(3, 6); + assertEquals(1, hidden.size()); + assertSame(firstHiddenRange, cs.getHiddenRegions().get(0)); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(2, 4); + hidden = cs.getHiddenRegions(); + assertEquals(1, hidden.size()); + assertEquals("[2, 4]", Arrays.toString(hidden.get(0))); + + // extend contiguous with 2 positions overlap + cs.hideColumns(3, 5); + assertEquals(1, hidden.size()); + assertEquals("[2, 5]", Arrays.toString(hidden.get(0))); + + // extend contiguous with 1 position overlap + cs.hideColumns(5, 6); + assertEquals(1, hidden.size()); + assertEquals("[2, 6]", Arrays.toString(hidden.get(0))); + + // extend contiguous with overlap both ends: + cs.hideColumns(1, 7); + assertEquals(1, hidden.size()); + assertEquals("[1, 7]", Arrays.toString(hidden.get(0))); + } + + /** + * Test the method that reveals a range of hidden columns given the start + * column of the range + */ + @Test(groups = { "Functional" }) + public void testRevealHiddenColumns() + { + ColumnSelection colsel = new ColumnSelection(); + HiddenColumns cs = new HiddenColumns(); + cs.hideColumns(5, 8); + colsel.addElement(10); + cs.revealHiddenColumns(5, colsel); + // hidden columns list now null but getter returns empty list: + assertTrue(cs.getHiddenRegions().isEmpty()); + // revealed columns are marked as selected (added to selection): + assertEquals("[10, 5, 6, 7, 8]", colsel.getSelected().toString()); + + // calling with a column other than the range start does nothing: + colsel = new ColumnSelection(); + cs = new HiddenColumns(); + cs.hideColumns(5, 8); + List hidden = cs.getHiddenRegions(); + cs.revealHiddenColumns(6, colsel); + assertSame(hidden, cs.getHiddenRegions()); + assertTrue(colsel.getSelected().isEmpty()); + } + + @Test(groups = { "Functional" }) + public void testRevealAllHiddenColumns() + { + HiddenColumns cs = new HiddenColumns(); + ColumnSelection colsel = new ColumnSelection(); + cs.hideColumns(5, 8); + cs.hideColumns(2, 3); + colsel.addElement(11); + colsel.addElement(1); + cs.revealAllHiddenColumns(colsel); + + /* + * revealing hidden columns adds them (in order) to the (unordered) + * selection list + */ + assertTrue(cs.getHiddenRegions().isEmpty()); + assertEquals("[11, 1, 2, 3, 5, 6, 7, 8]", colsel.getSelected() + .toString()); + } + + @Test(groups = { "Functional" }) + public void testIsVisible() + { + HiddenColumns cs = new HiddenColumns(); + cs.hideColumns(2, 4); + cs.hideColumns(6, 7); + assertTrue(cs.isVisible(0)); + assertTrue(cs.isVisible(-99)); + assertTrue(cs.isVisible(1)); + assertFalse(cs.isVisible(2)); + assertFalse(cs.isVisible(3)); + assertFalse(cs.isVisible(4)); + assertTrue(cs.isVisible(5)); + assertFalse(cs.isVisible(6)); + assertFalse(cs.isVisible(7)); + } + + /** + * Test for the case when a hidden range encloses more one already hidden + * range + */ + @Test(groups = { "Functional" }) + public void testHideColumns_subsumingHidden() + { + /* + * JAL-2370 bug scenario: + * two hidden ranges subsumed by a third + */ + HiddenColumns cs = new HiddenColumns(); + cs.hideColumns(49, 59); + cs.hideColumns(69, 79); + List hidden = cs.getHiddenRegions(); + assertEquals(2, hidden.size()); + assertEquals("[49, 59]", Arrays.toString(hidden.get(0))); + assertEquals("[69, 79]", Arrays.toString(hidden.get(1))); + + cs.hideColumns(48, 80); + hidden = cs.getHiddenRegions(); + assertEquals(1, hidden.size()); + assertEquals("[48, 80]", Arrays.toString(hidden.get(0))); + + /* + * another...joining hidden ranges + */ + cs = new HiddenColumns(); + cs.hideColumns(10, 20); + cs.hideColumns(30, 40); + cs.hideColumns(50, 60); + // hiding 21-49 should merge to one range + cs.hideColumns(21, 49); + hidden = cs.getHiddenRegions(); + assertEquals(1, hidden.size()); + assertEquals("[10, 60]", Arrays.toString(hidden.get(0))); + + /* + * another...left overlap, subsumption, right overlap, + * no overlap of existing hidden ranges + */ + cs = new HiddenColumns(); + cs.hideColumns(10, 20); + cs.hideColumns(10, 20); + cs.hideColumns(30, 35); + cs.hideColumns(40, 50); + cs.hideColumns(60, 70); + + cs.hideColumns(15, 45); + hidden = cs.getHiddenRegions(); + assertEquals(2, hidden.size()); + assertEquals("[10, 50]", Arrays.toString(hidden.get(0))); + assertEquals("[60, 70]", Arrays.toString(hidden.get(1))); + } + +} diff --git a/test/jalview/datamodel/VisibleColsIteratorTest.java b/test/jalview/datamodel/VisibleColsIteratorTest.java new file mode 100644 index 0000000..b2d747b --- /dev/null +++ b/test/jalview/datamodel/VisibleColsIteratorTest.java @@ -0,0 +1,198 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import static org.testng.Assert.assertTrue; + +import java.util.NoSuchElementException; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class VisibleColsIteratorTest +{ + HiddenColumns hiddenCols; + + HiddenColumns hiddenColsAtStart; + + @BeforeClass(groups = { "Functional" }) + public void setup() + { + hiddenCols = new HiddenColumns(); + hiddenCols.hideColumns(2, 4); + + hiddenColsAtStart = new HiddenColumns(); + hiddenColsAtStart.hideColumns(0, 2); + } + + /* + * Test iterator iterates correctly through the columns + * when alignment has hidden cols + */ + @Test(groups = { "Functional" }) + public void testHasNextAndNextWithHidden() + { + VisibleColsIterator it = new VisibleColsIterator(0, 6, hiddenCols); + int count = 0; + while (it.hasNext()) + { + it.next(); + count++; + } + assertTrue(count == 4, "hasNext() is false after 4 iterations"); + } + + /* + * Test iterator iterates correctly through the columns + * when alignment has no hidden cols + */ + @Test(groups = { "Functional" }) + public void testHasNextAndNextNoHidden() + { + VisibleColsIterator it2 = new VisibleColsIterator(0, 3, + new HiddenColumns()); + int count = 0; + while (it2.hasNext()) + { + it2.next(); + count++; + } + assertTrue(count == 4, "hasNext() is false after 4 iterations"); + } + + /* + * Test iterator iterates correctly through the columns + * when alignment has hidden cols at start + */ + @Test(groups = { "Functional" }) + public void testHasNextAndNextStartHidden() + { + VisibleColsIterator it3 = new VisibleColsIterator(0, 6, + hiddenColsAtStart); + int count = 0; + while (it3.hasNext()) + { + it3.next(); + count++; + } + assertTrue(count == 4, "hasNext() is false after 4 iterations"); + } + + /* + * Test iterator iterates correctly through the columns + * when alignment has hidden cols at end + */ + @Test(groups = { "Functional" }) + public void testHasNextAndNextEndHidden() + { + VisibleColsIterator it4 = new VisibleColsIterator(0, 4, hiddenCols); + int count = 0; + while (it4.hasNext()) + { + it4.next(); + count++; + } + assertTrue(count == 2, "hasNext() is false after 2 iterations"); + + } + + /* + * Test iterator always throws NoSuchElementException at end of iteration + * when alignment has hidden cols + */ + @Test( + groups = { "Functional" }, + expectedExceptions = { NoSuchElementException.class }) + public void testLastNextWithHidden() throws NoSuchElementException + { + VisibleColsIterator it = new VisibleColsIterator(0, 3, hiddenCols); + while (it.hasNext()) + { + it.next(); + } + it.next(); + } + + /* + * Test iterator always throws NoSuchElementException at end of iteration + * when alignment has no hidden cols + */ + @Test( + groups = { "Functional" }, + expectedExceptions = { NoSuchElementException.class }) + public void testLastNextNoHidden() throws NoSuchElementException + { + VisibleColsIterator it2 = new VisibleColsIterator(0, 3, + new HiddenColumns()); + while (it2.hasNext()) + { + it2.next(); + } + it2.next(); + } + + /* + * Test iterator always throws NoSuchElementException at end of iteration + * when alignment has hidden cols at start + */ + @Test( + groups = { "Functional" }, + expectedExceptions = { NoSuchElementException.class }) + public void testLastNextStartHidden() throws NoSuchElementException + { + VisibleColsIterator it3 = new VisibleColsIterator(0, 6, + hiddenColsAtStart); + while (it3.hasNext()) + { + it3.next(); + } + it3.next(); + } + + /* + * Test iterator always throws NoSuchElementException at end of iteration + * when alignment has hidden cols at end + */ + @Test( + groups = { "Functional" }, + expectedExceptions = { NoSuchElementException.class }) + public void testLastNextEndHidden() throws NoSuchElementException + { + VisibleColsIterator it4 = new VisibleColsIterator(0, 4, hiddenCols); + while (it4.hasNext()) + { + it4.next(); + } + it4.next(); + } + + /* + * Test calls to remove throw UnsupportedOperationException + */ + @Test( + groups = { "Functional" }, + expectedExceptions = { UnsupportedOperationException.class }) + public void testRemove() throws UnsupportedOperationException + { + VisibleColsIterator it = new VisibleColsIterator(0, 3, hiddenCols); + it.remove(); + } +} diff --git a/test/jalview/datamodel/VisibleRowsIteratorTest.java b/test/jalview/datamodel/VisibleRowsIteratorTest.java new file mode 100644 index 0000000..4a021c5 --- /dev/null +++ b/test/jalview/datamodel/VisibleRowsIteratorTest.java @@ -0,0 +1,233 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import static org.testng.Assert.assertTrue; + +import jalview.analysis.AlignmentGenerator; + +import java.util.Hashtable; +import java.util.NoSuchElementException; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class VisibleRowsIteratorTest +{ + AlignmentI al; + + AlignmentI al2; + + AlignmentI al3; + + Hashtable hiddenRepSequences = new Hashtable(); + + Hashtable hiddenRepSequences2 = new Hashtable(); + + @BeforeClass(groups = { "Functional" }) + public void setup() + { + // create random alignment + AlignmentGenerator gen = new AlignmentGenerator(false); + al = gen.generate(20, 15, 123, 5, 5); + if (!hiddenRepSequences.isEmpty()) + { + al.getHiddenSequences().showAll(hiddenRepSequences); + } + hideSequences(al, hiddenRepSequences, 2, 4); + + al2 = gen.generate(20, 15, 123, 5, 5); + if (!hiddenRepSequences2.isEmpty()) + { + al2.getHiddenSequences().showAll(hiddenRepSequences2); + } + hideSequences(al2, hiddenRepSequences2, 0, 2); + + al3 = gen.generate(20, 15, 123, 5, 5); + } + + /* + * Test iterator iterates correctly through the rows + * when alignment has hidden rows + */ + @Test(groups = { "Functional" }) + public void testHasNextAndNextWithHidden() + { + VisibleRowsIterator it = new VisibleRowsIterator(0, 6, al); + int count = 0; + while (it.hasNext()) + { + it.next(); + count++; + } + assertTrue(count == 4, "hasNext() is false after 4 iterations"); + } + + /* + * Test iterator iterates correctly through the rows + * when alignment has no hidden rows + */ + @Test(groups = { "Functional" }) + public void testHasNextAndNextNoHidden() + { + VisibleRowsIterator it = new VisibleRowsIterator(0, 3, al3); + int count = 0; + while (it.hasNext()) + { + it.next(); + count++; + } + assertTrue(count == 4, "hasNext() is false after 4 iterations"); + } + + /* + * Test iterator iterates correctly through the rows + * when alignment has hidden rows at start + */ + @Test(groups = { "Functional" }) + public void testHasNextAndNextStartHidden() + { + VisibleRowsIterator it = new VisibleRowsIterator(0, 6, al2); + int count = 0; + while (it.hasNext()) + { + it.next(); + count++; + } + assertTrue(count == 4, "hasNext() is false after 4 iterations"); + } + + /* + * Test iterator iterates correctly through the rows + * when alignment has hidden rows at end + */ + @Test(groups = { "Functional" }) + public void testHasNextAndNextEndHidden() + { + VisibleRowsIterator it = new VisibleRowsIterator(0, 4, al); + int count = 0; + while (it.hasNext()) + { + it.next(); + count++; + } + assertTrue(count == 2, "hasNext() is false after 2 iterations"); + } + + /* + * Test iterator always throws NoSuchElementException at end of iteration + * when alignment has hidden rows + */ + @Test( + groups = { "Functional" }, + expectedExceptions = { NoSuchElementException.class }) + public void testLastNextWithHidden() throws NoSuchElementException + { + VisibleRowsIterator it = new VisibleRowsIterator(0, 3, al); + while (it.hasNext()) + { + it.next(); + } + it.next(); + } + + /* + * Test iterator always throws NoSuchElementException at end of iteration + * when alignment has no hidden rows + */ + @Test( + groups = { "Functional" }, + expectedExceptions = { NoSuchElementException.class }) + public void testLastNextNoHidden() throws NoSuchElementException + { + VisibleRowsIterator it = new VisibleRowsIterator(0, 3, al3); + while (it.hasNext()) + { + it.next(); + } + it.next(); + } + + /* + * Test iterator always throws NoSuchElementException at end of iteration + * when alignment has hidden rows at start + */ + @Test( + groups = { "Functional" }, + expectedExceptions = { NoSuchElementException.class }) + public void testLastNextStartHidden() throws NoSuchElementException + { + VisibleRowsIterator it = new VisibleRowsIterator(0, 3, al2); + while (it.hasNext()) + { + it.next(); + } + it.next(); + } + + /* + * Test iterator always throws NoSuchElementException at end of iteration + * when alignment has hidden rows at end + */ + @Test( + groups = { "Functional" }, + expectedExceptions = { NoSuchElementException.class }) + public void testLastNextEndHidden() throws NoSuchElementException + { + VisibleRowsIterator it = new VisibleRowsIterator(0, 4, al); + while (it.hasNext()) + { + it.next(); + } + it.next(); + } + + /* + * Test calls to remove throw UnsupportedOperationException + */ + @Test( + groups = { "Functional" }, + expectedExceptions = { UnsupportedOperationException.class }) + public void testRemove() throws UnsupportedOperationException + { + VisibleRowsIterator it = new VisibleRowsIterator(0, 3, al); + it.remove(); + } + + /* + * Hide sequences between start and end + */ + private void hideSequences(AlignmentI alignment, + Hashtable hiddenRepSequences, + int start, int end) + { + SequenceI[] allseqs = alignment.getSequencesArray(); + SequenceGroup theseSeqs = new SequenceGroup(); + + for (int i = start; i <= end; i++) + { + theseSeqs.addSequence(allseqs[i], false); + alignment.getHiddenSequences().hideSequence(allseqs[i]); + } + + hiddenRepSequences.put(allseqs[start], theseSeqs); + } +} diff --git a/test/jalview/gui/AlignFrameTest.java b/test/jalview/gui/AlignFrameTest.java index 2ea94a4..fed5992 100644 --- a/test/jalview/gui/AlignFrameTest.java +++ b/test/jalview/gui/AlignFrameTest.java @@ -85,11 +85,13 @@ public class AlignFrameTest */ assertFalse(alignFrame.hideFeatureColumns("exon", true)); assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty()); - assertTrue(alignFrame.getViewport().getColumnSelection().getHiddenColumns() + assertTrue(alignFrame.getViewport().getAlignment().getHiddenColumns() + .getHiddenRegions() .isEmpty()); assertFalse(alignFrame.hideFeatureColumns("exon", false)); assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty()); - assertTrue(alignFrame.getViewport().getColumnSelection().getHiddenColumns() + assertTrue(alignFrame.getViewport().getAlignment().getHiddenColumns() + .getHiddenRegions() .isEmpty()); /* @@ -97,8 +99,9 @@ public class AlignFrameTest */ assertFalse(alignFrame.hideFeatureColumns("Metal", true)); assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty()); - List hidden = alignFrame.getViewport().getColumnSelection() - .getHiddenColumns(); + List hidden = alignFrame.getViewport().getAlignment() + .getHiddenColumns() + .getHiddenRegions(); assertTrue(hidden.isEmpty()); /* @@ -107,7 +110,8 @@ public class AlignFrameTest * [1-3], [6-8] base zero */ assertTrue(alignFrame.hideFeatureColumns("Turn", true)); - hidden = alignFrame.getViewport().getColumnSelection().getHiddenColumns(); + hidden = alignFrame.getViewport().getAlignment().getHiddenColumns() + .getHiddenRegions(); assertEquals(hidden.size(), 2); assertEquals(hidden.get(0)[0], 1); assertEquals(hidden.get(0)[1], 3); diff --git a/test/jalview/io/AnnotationFileIOTest.java b/test/jalview/io/AnnotationFileIOTest.java index 62bd0b9..6a00cde 100644 --- a/test/jalview/io/AnnotationFileIOTest.java +++ b/test/jalview/io/AnnotationFileIOTest.java @@ -24,7 +24,7 @@ import static org.testng.AssertJUnit.assertNotNull; import static org.testng.AssertJUnit.assertTrue; import jalview.datamodel.AlignmentI; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.gui.JvOptionPane; import jalview.io.AnnotationFile.ViewDef; @@ -115,7 +115,7 @@ public class AnnotationFileIOTest try { AlignmentI al = readAlignmentFile(f); - ColumnSelection cs = new ColumnSelection(); + HiddenColumns cs = new HiddenColumns(); assertTrue( "Test " + testname diff --git a/test/jalview/io/JSONFileTest.java b/test/jalview/io/JSONFileTest.java index acde68d..2aff5cc 100644 --- a/test/jalview/io/JSONFileTest.java +++ b/test/jalview/io/JSONFileTest.java @@ -27,7 +27,7 @@ import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceGroup; @@ -79,7 +79,7 @@ public class JSONFileTest private HashMap expectedGrps = new HashMap(); - private ColumnSelection expectedColSel = new ColumnSelection(); + private HiddenColumns expectedColSel = new HiddenColumns(); private SequenceI[] expectedHiddenSeqs = new SequenceI[1]; @@ -195,7 +195,7 @@ public class JSONFileTest TEST_SEQ_HEIGHT = expectedSeqs.size(); TEST_GRP_HEIGHT = expectedGrps.size(); TEST_ANOT_HEIGHT = expectedAnnots.size(); - TEST_CS_HEIGHT = expectedColSel.getHiddenColumns().size(); + TEST_CS_HEIGHT = expectedColSel.getHiddenRegions().size(); exportSettings = new AlignExportSettingI() { @@ -244,7 +244,7 @@ public class JSONFileTest jf = (JSONFile) formatAdapter.getAlignFile(); AlignFrame af = new AlignFrame(alignment, jf.getHiddenSequences(), - jf.getColumnSelection(), AlignFrame.DEFAULT_WIDTH, + jf.getHiddenColumns(), AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); af.getViewport().setShowSequenceFeatures(jf.isShowSeqFeatures()); String colourSchemeName = jf.getGlobalColourScheme(); @@ -313,13 +313,13 @@ public class JSONFileTest @Test(groups = { "Functional" }) public void hiddenColsTest() { - ColumnSelection cs = testJsonFile.getColumnSelection(); + HiddenColumns cs = testJsonFile.getHiddenColumns(); Assert.assertNotNull(cs); - Assert.assertNotNull(cs.getHiddenColumns()); - List hiddenCols = cs.getHiddenColumns(); + Assert.assertNotNull(cs.getHiddenRegions()); + List hiddenCols = cs.getHiddenRegions(); Assert.assertEquals(hiddenCols.size(), TEST_CS_HEIGHT); Assert.assertEquals(hiddenCols.get(0), expectedColSel - .getHiddenColumns().get(0), + .getHiddenRegions().get(0), "Mismatched hidden columns!"); } @@ -359,7 +359,7 @@ public class JSONFileTest JSONFile bioJsonFile = (JSONFile) formatAdapter.getAlignFile(); AlignFrame alignFrame = new AlignFrame(_alignment, bioJsonFile.getHiddenSequences(), - bioJsonFile.getColumnSelection(), AlignFrame.DEFAULT_WIDTH, + bioJsonFile.getHiddenColumns(), AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); /* diff --git a/test/jalview/structures/models/AAStructureBindingModelTest.java b/test/jalview/structures/models/AAStructureBindingModelTest.java index 7ba22b4..a7e483e 100644 --- a/test/jalview/structures/models/AAStructureBindingModelTest.java +++ b/test/jalview/structures/models/AAStructureBindingModelTest.java @@ -29,7 +29,7 @@ import jalview.api.FeatureRenderer; import jalview.api.SequenceRenderer; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; import jalview.datamodel.PDBEntry.Type; import jalview.datamodel.Sequence; @@ -171,7 +171,7 @@ public class AAStructureBindingModelTest @Override public String superposeStructures(AlignmentI[] als, int[] alm, - ColumnSelection[] alc) + HiddenColumns[] alc) { return null; } diff --git a/test/jalview/util/MappingUtilsTest.java b/test/jalview/util/MappingUtilsTest.java index b84e770..19c8438 100644 --- a/test/jalview/util/MappingUtilsTest.java +++ b/test/jalview/util/MappingUtilsTest.java @@ -33,6 +33,7 @@ import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SearchResultMatchI; import jalview.datamodel.SearchResultsI; import jalview.datamodel.Sequence; @@ -300,49 +301,60 @@ public class MappingUtilsTest setupMappedAlignments(); ColumnSelection colsel = new ColumnSelection(); + HiddenColumns hidden = new HiddenColumns(); /* * Column 0 in protein picks up Seq2/L, Seq3/G which map to cols 0-4 and 0-3 * in dna respectively, overall 0-4 */ colsel.addElement(0); - ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, - proteinView, dnaView); + ColumnSelection cs = new ColumnSelection(); + HiddenColumns hs = new HiddenColumns(); + MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView, + cs, hs); assertEquals("[0, 1, 2, 3, 4]", cs.getSelected().toString()); /* * Column 1 in protein picks up Seq1/K which maps to cols 0-3 in dna */ + cs.clear(); colsel.clear(); colsel.addElement(1); - cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView); + MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView, + cs, hs); assertEquals("[0, 1, 2, 3]", cs.getSelected().toString()); /* * Column 2 in protein picks up gaps only - no mapping */ + cs.clear(); colsel.clear(); colsel.addElement(2); - cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView); + MappingUtils.mapColumnSelection(colsel, hidden, proteinView, + dnaView, cs, hs); assertEquals("[]", cs.getSelected().toString()); /* * Column 3 in protein picks up Seq1/P, Seq2/Q, Seq3/S which map to columns * 6-9, 6-10, 5-8 respectively, overall to 5-10 */ + cs.clear(); colsel.clear(); colsel.addElement(3); - cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView); + MappingUtils.mapColumnSelection(colsel, hidden, proteinView, + dnaView, cs, hs); assertEquals("[5, 6, 7, 8, 9, 10]", cs.getSelected().toString()); /* * Combine selection of columns 1 and 3 to get a discontiguous mapped * selection */ + cs.clear(); colsel.clear(); colsel.addElement(1); colsel.addElement(3); - cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView); + MappingUtils.mapColumnSelection(colsel, hidden, proteinView, + dnaView, cs, hs); assertEquals("[0, 1, 2, 3, 5, 6, 7, 8, 9, 10]", cs.getSelected() .toString()); } @@ -407,14 +419,17 @@ public class MappingUtilsTest setupMappedAlignments(); ColumnSelection colsel = new ColumnSelection(); + HiddenColumns hidden = new HiddenColumns(); /* * Column 0 in dna picks up first bases which map to residue 1, columns 0-1 * in protein. */ + ColumnSelection cs = new ColumnSelection(); + HiddenColumns hs = new HiddenColumns(); colsel.addElement(0); - ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, dnaView, - proteinView); + MappingUtils.mapColumnSelection(colsel, hidden, dnaView, proteinView, + cs, hs); assertEquals("[0, 1]", cs.getSelected().toString()); /* @@ -424,7 +439,9 @@ public class MappingUtilsTest colsel.addElement(3); colsel.addElement(4); colsel.addElement(5); - cs = MappingUtils.mapColumnSelection(colsel, dnaView, proteinView); + cs.clear(); + MappingUtils.mapColumnSelection(colsel, hidden, dnaView, proteinView, + cs, hs); assertEquals("[0, 1, 3]", cs.getSelected().toString()); } @@ -432,8 +449,10 @@ public class MappingUtilsTest public void testMapColumnSelection_null() throws IOException { setupMappedAlignments(); - ColumnSelection cs = MappingUtils.mapColumnSelection(null, dnaView, - proteinView); + ColumnSelection cs = new ColumnSelection(); + HiddenColumns hs = new HiddenColumns(); + MappingUtils.mapColumnSelection(null, null, dnaView, proteinView, cs, + hs); assertTrue("mapped selection not empty", cs.getSelected().isEmpty()); } @@ -882,69 +901,80 @@ public class MappingUtilsTest setupMappedAlignments(); ColumnSelection proteinSelection = new ColumnSelection(); + HiddenColumns hiddenCols = new HiddenColumns(); /* * Column 0 in protein picks up Seq2/L, Seq3/G which map to cols 0-4 and 0-3 * in dna respectively, overall 0-4 */ - proteinSelection.hideColumns(0); - ColumnSelection dnaSelection = MappingUtils.mapColumnSelection( - proteinSelection, proteinView, dnaView); + proteinSelection.hideSelectedColumns(0, hiddenCols); + ColumnSelection dnaSelection = new ColumnSelection(); + HiddenColumns dnaHidden = new HiddenColumns(); + MappingUtils.mapColumnSelection(proteinSelection, hiddenCols, + proteinView, dnaView, dnaSelection, dnaHidden); assertEquals("[]", dnaSelection.getSelected().toString()); - List hidden = dnaSelection.getHiddenColumns(); + List hidden = dnaHidden.getHiddenRegions(); assertEquals(1, hidden.size()); assertEquals("[0, 4]", Arrays.toString(hidden.get(0))); /* * Column 1 in protein picks up Seq1/K which maps to cols 0-3 in dna */ - proteinSelection.revealAllHiddenColumns(); + dnaSelection = new ColumnSelection(); + dnaHidden = new HiddenColumns(); + hiddenCols.revealAllHiddenColumns(proteinSelection); // the unhidden columns are now marked selected! assertEquals("[0]", proteinSelection.getSelected().toString()); // deselect these or hideColumns will be expanded to include 0 proteinSelection.clear(); - proteinSelection.hideColumns(1); - dnaSelection = MappingUtils.mapColumnSelection(proteinSelection, - proteinView, dnaView); - hidden = dnaSelection.getHiddenColumns(); + proteinSelection.hideSelectedColumns(1, hiddenCols); + MappingUtils.mapColumnSelection(proteinSelection, hiddenCols, + proteinView, dnaView, dnaSelection, dnaHidden); + hidden = dnaHidden.getHiddenRegions(); assertEquals(1, hidden.size()); assertEquals("[0, 3]", Arrays.toString(hidden.get(0))); /* * Column 2 in protein picks up gaps only - no mapping */ - proteinSelection.revealAllHiddenColumns(); + dnaSelection = new ColumnSelection(); + dnaHidden = new HiddenColumns(); + hiddenCols.revealAllHiddenColumns(proteinSelection); proteinSelection.clear(); - proteinSelection.hideColumns(2); - dnaSelection = MappingUtils.mapColumnSelection(proteinSelection, - proteinView, dnaView); - assertTrue(dnaSelection.getHiddenColumns().isEmpty()); + proteinSelection.hideSelectedColumns(2, hiddenCols); + MappingUtils.mapColumnSelection(proteinSelection, hiddenCols, + proteinView, dnaView, dnaSelection, dnaHidden); + assertTrue(dnaHidden.getHiddenRegions().isEmpty()); /* * Column 3 in protein picks up Seq1/P, Seq2/Q, Seq3/S which map to columns * 6-9, 6-10, 5-8 respectively, overall to 5-10 */ - proteinSelection.revealAllHiddenColumns(); + dnaSelection = new ColumnSelection(); + dnaHidden = new HiddenColumns(); + hiddenCols.revealAllHiddenColumns(proteinSelection); proteinSelection.clear(); - proteinSelection.hideColumns(3); // 5-10 hidden in dna + proteinSelection.hideSelectedColumns(3, hiddenCols); // 5-10 hidden in dna proteinSelection.addElement(1); // 0-3 selected in dna - dnaSelection = MappingUtils.mapColumnSelection(proteinSelection, - proteinView, dnaView); + MappingUtils.mapColumnSelection(proteinSelection, hiddenCols, + proteinView, dnaView, dnaSelection, dnaHidden); assertEquals("[0, 1, 2, 3]", dnaSelection.getSelected().toString()); - hidden = dnaSelection.getHiddenColumns(); + hidden = dnaHidden.getHiddenRegions(); assertEquals(1, hidden.size()); assertEquals("[5, 10]", Arrays.toString(hidden.get(0))); /* * Combine hiding columns 1 and 3 to get discontiguous hidden columns */ - proteinSelection.revealAllHiddenColumns(); + dnaSelection = new ColumnSelection(); + dnaHidden = new HiddenColumns(); + hiddenCols.revealAllHiddenColumns(proteinSelection); proteinSelection.clear(); - proteinSelection.hideColumns(1); - proteinSelection.hideColumns(3); - dnaSelection = MappingUtils.mapColumnSelection(proteinSelection, - proteinView, dnaView); - hidden = dnaSelection.getHiddenColumns(); + proteinSelection.hideSelectedColumns(1, hiddenCols); + proteinSelection.hideSelectedColumns(3, hiddenCols); + MappingUtils.mapColumnSelection(proteinSelection, hiddenCols, + proteinView, dnaView, dnaSelection, dnaHidden); + hidden = dnaHidden.getHiddenRegions(); assertEquals(2, hidden.size()); assertEquals("[0, 3]", Arrays.toString(hidden.get(0))); assertEquals("[5, 10]", Arrays.toString(hidden.get(1))); diff --git a/test/jalview/viewmodel/OverviewDimensionsHideHiddenTest.java b/test/jalview/viewmodel/OverviewDimensionsHideHiddenTest.java new file mode 100644 index 0000000..2bd9c47 --- /dev/null +++ b/test/jalview/viewmodel/OverviewDimensionsHideHiddenTest.java @@ -0,0 +1,989 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.viewmodel; + +import static org.testng.Assert.assertEquals; + +import jalview.analysis.AlignmentGenerator; +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceCollectionI; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; + +import java.util.Hashtable; + +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +@Test(singleThreaded = true) +public class OverviewDimensionsHideHiddenTest +{ + AlignmentI al; + + OverviewDimensionsHideHidden od; + + // cached widths and heights + int boxWidth; + int boxHeight; + int viewHeight; + int viewWidth; + int alheight; + int alwidth; + + ViewportRanges vpranges; + + Hashtable hiddenRepSequences = new Hashtable(); + + HiddenColumns hiddenCols = new HiddenColumns(); + + @BeforeClass(alwaysRun = true) + public void setUpAlignment() + { + // create random alignment + AlignmentGenerator gen = new AlignmentGenerator(false); + al = gen.generate(157, 525, 123, 5, 5); + } + + @BeforeMethod(alwaysRun = true) + public void setUp() + { + if (!hiddenRepSequences.isEmpty()) + { + al.getHiddenSequences().showAll(hiddenRepSequences); + } + ColumnSelection colsel = new ColumnSelection(); + hiddenCols.revealAllHiddenColumns(colsel); + + vpranges = new ViewportRanges(al); + vpranges.setStartRes(0); + vpranges.setEndRes(62); + vpranges.setStartSeq(0); + vpranges.setEndSeq(17); + + viewHeight = vpranges.getEndSeq() - vpranges.getStartSeq() + 1; + viewWidth = vpranges.getEndRes() - vpranges.getStartRes() + 1; + + HiddenColumns hiddenCols = new HiddenColumns(); + + od = new OverviewDimensionsHideHidden(vpranges, true); + // Initial box sizing - default path through code + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); + + mouseClick(od, 0, 0); + moveViewport(0, 0); + + // calculate with visible values + alheight = vpranges.getVisibleAlignmentHeight(); + alwidth = vpranges.getVisibleAlignmentWidth(); + + boxWidth = Math.round((float) (vpranges.getEndRes() + - vpranges.getStartRes() + 1) + * od.getWidth() / alwidth); + boxHeight = Math.round((float) (vpranges.getEndSeq() + - vpranges.getStartSeq() + 1) + * od.getSequencesHeight() / alheight); + } + + @AfterClass(alwaysRun = true) + public void cleanUp() + { + al = null; + } + + /** + * Test that the OverviewDimensions constructor sets width and height + * correctly + */ + @Test(groups = { "Functional" }) + public void testConstructor() + { + SequenceI seqa = new Sequence("Seq1", "ABC"); + SequenceI seqb = new Sequence("Seq2", "ABC"); + SequenceI seqc = new Sequence("Seq3", "ABC"); + SequenceI seqd = new Sequence("Seq4", "ABC"); + SequenceI seqe = new Sequence("Seq5", + "ABCABCABCABCABCABCABCABCBACBACBACBAC"); + + int defaultGraphHeight = 20; + int maxWidth = 400; + int minWidth = 120; + int maxSeqHeight = 300; + int minSeqHeight = 40; + + // test for alignment with width > height + SequenceI[] seqs1 = new SequenceI[] { seqa, seqb }; + Alignment al1 = new Alignment(seqs1); + ViewportRanges props = new ViewportRanges(al1); + + OverviewDimensions od = new OverviewDimensionsHideHidden(props, true); + int scaledHeight = 267; + assertEquals(od.getGraphHeight(), defaultGraphHeight); + assertEquals(od.getSequencesHeight(), scaledHeight); + assertEquals(od.getWidth(), maxWidth); + assertEquals(od.getHeight(), scaledHeight + defaultGraphHeight); + + // test for alignment with width < height + SequenceI[] seqs2 = new SequenceI[] { seqa, seqb, seqc, seqd }; + Alignment al2 = new Alignment(seqs2); + props = new ViewportRanges(al2); + + od = new OverviewDimensionsHideHidden(props, true); + int scaledWidth = 300; + assertEquals(od.getGraphHeight(), defaultGraphHeight); + assertEquals(od.getSequencesHeight(), maxSeqHeight); + assertEquals(od.getWidth(), scaledWidth); + assertEquals(od.getHeight(), scaledWidth + defaultGraphHeight); + + // test for alignment with width > height and sequence height scaled below + // min value + SequenceI[] seqs3 = new SequenceI[] { seqe }; + Alignment al3 = new Alignment(seqs3); + props = new ViewportRanges(al3); + + od = new OverviewDimensionsHideHidden(props, true); + assertEquals(od.getGraphHeight(), defaultGraphHeight); + assertEquals(od.getSequencesHeight(), minSeqHeight); + assertEquals(od.getWidth(), maxWidth); + assertEquals(od.getHeight(), minSeqHeight + defaultGraphHeight); + + // test for alignment with width < height and width scaled below min value + SequenceI[] seqs4 = new SequenceI[] { seqa, seqb, seqc, seqd, seqa, + seqb, seqc, seqd, seqa, seqb, seqc, seqd, seqa, seqb, seqc, seqd }; + Alignment al4 = new Alignment(seqs4); + props = new ViewportRanges(al4); + + od = new OverviewDimensionsHideHidden(props, true); + assertEquals(od.getGraphHeight(), defaultGraphHeight); + assertEquals(od.getSequencesHeight(), maxSeqHeight); + assertEquals(od.getWidth(), minWidth); + assertEquals(od.getHeight(), maxSeqHeight + defaultGraphHeight); + + Alignment al5 = new Alignment(seqs4); + props = new ViewportRanges(al5); + + od = new OverviewDimensionsHideHidden(props, false); + assertEquals(od.getGraphHeight(), 0); + assertEquals(od.getSequencesHeight(), maxSeqHeight); + assertEquals(od.getWidth(), minWidth); + assertEquals(od.getHeight(), maxSeqHeight); + } + + /** + * Test that validation after mouse adjustments to boxX and boxY sets box + * dimensions and scroll values correctly, when there are no hidden rows or + * columns. + */ + @Test(groups = { "Functional" }) + public void testSetBoxFromMouseClick() + { + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // negative boxX value reset to 0 + mouseClick(od, -5, 10); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollRow(), + Math.round((float) 10 * alheight / od.getSequencesHeight())); + assertEquals(od.getScrollCol(), 0); + + // negative boxY value reset to 0 + mouseClick(od, 6, -2); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) 6 * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), 0); + + // overly large boxX value reset to width-boxWidth + mouseClick(od, 100, 6); + assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth()); + assertEquals(od.getBoxY(), 6); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) od.getBoxX() * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), + Math.round((float) od.getBoxY() * alheight + / od.getSequencesHeight())); + + // overly large boxY value reset to sequenceHeight - boxHeight + mouseClick(od, 10, 520); + assertEquals(od.getBoxX(), 10); + assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight()); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) od.getBoxX() * alwidth / od.getWidth())); + + // here (float) od.getBoxY() * alheight / od.getSequencesHeight() = 507.5 + // and round rounds to 508; however we get 507 working with row values + // hence the subtraction of 1 + assertEquals(od.getScrollRow(), + Math.round((float) od.getBoxY() * alheight + / od.getSequencesHeight()) - 1); + + // click past end of alignment, as above + mouseClick(od, 3000, 5); + assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth()); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) od.getBoxX() * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), + Math.round((float) od.getBoxY() * alheight + / od.getSequencesHeight())); + + // move viewport so startRes non-zero and then mouseclick + moveViewportH(50); + + // click at viewport position + int oldboxx = od.getBoxX(); + int oldboxy = od.getBoxY(); + mouseClick(od, od.getBoxX() + 5, od.getBoxY() + 2); + assertEquals(od.getBoxX(), oldboxx + 5); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) od.getBoxX() * alwidth / od.getWidth())); + assertEquals(od.getBoxY(), oldboxy + 2); + assertEquals(od.getScrollRow(), + Math.round((float) od.getBoxY() * alheight + / od.getSequencesHeight())); + + // click at top corner + mouseClick(od, 0, 0); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getScrollRow(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + } + + /** + * Test setting of the box position, when there are hidden cols at the start + * of the alignment + */ + @Test(groups = { "Functional" }) + public void testFromMouseWithHiddenColsAtStart() + { + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // hide cols at start and check updated box position is correct + int lastHiddenCol = 30; + hiddenCols.hideColumns(0, lastHiddenCol); + + testBoxIsAtClickPoint(0, 0); + + // click to right of hidden columns, box moves to click point + testBoxIsAtClickPoint(40, 0); + assertEquals(od.getScrollRow(), 0); + assertEquals(od.getScrollCol(), + Math.round((float) 40 * alwidth / od.getWidth())); + + // click to right of hidden columns such that box runs over right hand side + // of alignment + // box position is adjusted away from the edge + // overly large boxX value reset to width-boxWidth + int xpos = 100; + mouseClick(od, xpos, 0); + assertEquals(od.getBoxX(), Math.round(od.getWidth()) - boxWidth); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) od.getBoxX() * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), 0); + } + + /** + * Test setting of the box position, when there are hidden cols in the middle + * of the alignment + */ + @Test(groups = { "Functional" }) + public void testFromMouseWithHiddenColsInMiddle() + { + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols); + testBoxIsAtClickPoint(0, 0); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // hide columns 63-73, no change to box position or dimensions + int firstHidden = 63; + int lastHidden = 73; + hiddenCols.hideColumns(firstHidden, lastHidden); + + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); + testBoxIsAtClickPoint(0, 0); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // move box so that it overlaps with hidden cols on one side + // box width, boxX and scrollCol as for unhidden case + int xpos = 55 - boxWidth; // 55 is position in overview approx halfway + // between cols 60 and 70 + mouseClick(od, xpos, 0); + testBoxIsAtClickPoint(xpos, 0); + assertEquals(od.getScrollCol(), + Math.round(xpos * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), 0); + + // move box so that it completely covers hidden cols + // box width, boxX and scrollCol as for unhidden case + xpos = 33; + mouseClick(od, xpos, 0); + testBoxIsAtClickPoint(xpos, 0); + assertEquals(od.getScrollCol(), + Math.round((float) xpos * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), 0); + + // move box so boxX is in hidden cols, box overhangs at right + // boxX and scrollCol at left of hidden area, box width unchanged + xpos = 50; + mouseClick(od, xpos, 0); + testBoxIsAtClickPoint(xpos, 0); + assertEquals(od.getScrollCol(), + Math.round((float) xpos * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), 0); + + // move box so boxX is to right of hidden cols, but does not go beyond full + // width of alignment + // box width, boxX and scrollCol all as for non-hidden case + xpos = 75; + testBoxIsAtClickPoint(xpos, 0); + assertEquals(od.getScrollRow(), 0); + assertEquals(od.getScrollCol(), + Math.round(xpos * alwidth / od.getWidth())); + + // move box so it goes beyond full width of alignment + // boxX, scrollCol adjusted back, box width normal + xpos = 3000; + mouseClick(od, xpos, 0); + assertEquals(od.getBoxX(), Math.round(od.getWidth()) - boxWidth); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) od.getBoxX() * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), 0); + + } + + /** + * Test setting of the box position, when there are hidden cols at the end of + * the alignment + */ + @Test(groups = { "Functional" }) + public void testFromMouseWithHiddenColsAtEnd() + { + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // hide columns 140-164, no change to box position or dimensions + int firstHidden = 140; + int lastHidden = 164; + hiddenCols.hideColumns(firstHidden, lastHidden); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // click to left of hidden cols, without overlapping + // boxX, scrollCol and width as normal + int xpos = 5; + testBoxIsAtClickPoint(xpos, 0); + assertEquals(od.getScrollRow(), 0); + assertEquals(od.getScrollCol(), + Math.round((float) xpos * alwidth / od.getWidth())); + + // click to left of hidden cols, with overlap + // boxX and scrollCol adjusted for hidden cols, width normal + xpos = Math.round((float) 145 * od.getWidth() / alwidth) - boxWidth; + mouseClick(od, xpos, 0); + testBoxIsAtClickPoint(xpos, 0); + assertEquals(od.getScrollCol(), + Math.round((float) xpos * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), 0); + + // click off end of alignment + // boxX and scrollCol adjusted backwards, width normal + xpos = 3000; + mouseClick(od, xpos, 0); + assertEquals(od.getBoxX(), Math.round(od.getWidth()) - boxWidth); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) od.getBoxX() * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), 0); + } + + /** + * Test that the box position is set correctly when set from the viewport, + * with no hidden rows or columns + */ + @Test(groups = { "Functional" }) + public void testSetBoxFromViewport() + { + // move viewport to start of alignment + moveViewport(0, 0); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to right + moveViewportH(70); + assertEquals(od.getBoxX(), + Math.round((float) 70 * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport down + moveViewportV(100); + assertEquals(od.getBoxX(), + Math.round((float) 70 * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), + Math.round(100 * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to bottom right + moveViewport(98, 508); + assertEquals(od.getBoxX(), + Math.round((float) 98 * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), + Math.round((float) 508 * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + } + + /** + * Test that the box position is set correctly when there are hidden columns + * at the start + */ + @Test(groups = { "Functional" }) + public void testSetBoxFromViewportHiddenColsAtStart() + { + int firstHidden = 0; + int lastHidden = 20; + hiddenCols.hideColumns(firstHidden, lastHidden); + + // move viewport to start of alignment + moveViewport(0, 0); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to end of alignment - need to make startRes by removing + // hidden cols because of how viewport/overview are implemented + moveViewport(98 - lastHidden - 1, 0); + assertEquals(od.getBoxX(), + Math.round((float) (98 - lastHidden - 1) * od.getWidth() + / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + } + + /** + * Test that the box position is set correctly when there are hidden columns + * in the middle + */ + @Test(groups = { "Functional" }) + public void testSetBoxFromViewportHiddenColsInMiddle() + { + int firstHidden = 68; + int lastHidden = 78; + hiddenCols.hideColumns(firstHidden, lastHidden); + + // move viewport before hidden columns + moveViewport(3, 0); + + assertEquals(od.getBoxX(), + Math.round((float) 3 * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to left of hidden columns with overlap + moveViewport(10, 0); + assertEquals(od.getBoxX(), + Math.round((float) 10 * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to straddle hidden columns + moveViewport(63, 0); + assertEquals(od.getBoxX(), + Math.round((float) 63 * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to right of hidden columns, no overlap + moveViewport(80 - (lastHidden - firstHidden + 1), 0); + assertEquals(od.getBoxX(), + Math.round((float) (80 - (lastHidden - firstHidden + 1)) + * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + } + + /** + * Test that the box position is set correctly when there are hidden columns + * at the end + */ + @Test(groups = { "Functional" }) + public void testSetBoxFromViewportHiddenColsAtEnd() + { + int firstHidden = 152; + int lastHidden = 164; + hiddenCols.hideColumns(firstHidden, lastHidden); + + // move viewport before hidden columns + moveViewport(3, 0); + assertEquals(od.getBoxX(), + Math.round((float) 3 * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to hidden columns + // viewport can't actually extend into hidden cols, + // so move to the far right edge of the viewport + moveViewport(firstHidden - viewWidth, 0); + assertEquals(od.getBoxX(), + Math.round((float) (firstHidden - viewWidth) + * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + } + + /** + * Test that the box position is set correctly when there are hidden rows at + * the start + */ + @Test(groups = { "Functional" }) + public void testSetBoxFromViewportHiddenRowsAtStart() + { + int firstHidden = 0; + int lastHidden = 20; + hideSequences(firstHidden, lastHidden); + + // calculate with visible values + alheight = vpranges.getVisibleAlignmentHeight(); + alwidth = vpranges.getVisibleAlignmentWidth(); + + boxWidth = Math.round((float) (vpranges.getEndRes() + - vpranges.getStartRes() + 1) + * od.getWidth() / alwidth); + boxHeight = Math.round((float) (vpranges.getEndSeq() + - vpranges.getStartSeq() + 1) + * od.getSequencesHeight() / alheight); + + // move viewport to start of alignment: + // box moves to below hidden rows, height remains same + moveViewport(0, 0); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to end of alignment + moveViewport(0, 525 - viewHeight - lastHidden - 1); + assertEquals(od.getBoxX(), 0); + assertEquals( + od.getBoxY(), + Math.round((float) (525 - viewHeight - lastHidden - 1) + * od.getSequencesHeight() + / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + } + + /** + * Test that the box position is set correctly when there are hidden rows in + * the middle + */ + @Test(groups = { "Functional" }) + public void testSetBoxFromViewportHiddenRowsInMiddle() + { + int firstHidden = 200; + int lastHidden = 210; + hideSequences(firstHidden, lastHidden); + + // calculate with visible values + alheight = vpranges.getVisibleAlignmentHeight(); + alwidth = vpranges.getVisibleAlignmentWidth(); + + boxWidth = Math.round((float) (vpranges.getEndRes() + - vpranges.getStartRes() + 1) + * od.getWidth() / alwidth); + boxHeight = Math.round((float) (vpranges.getEndSeq() + - vpranges.getStartSeq() + 1) + * od.getSequencesHeight() / alheight); + + // move viewport to start of alignment: + // box, height etc as in non-hidden case + moveViewport(0, 0); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to straddle hidden rows + moveViewport(0, 198); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), Math.round ((float)198 * od.getSequencesHeight() + / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + } + + /** + * Test that the box position is set correctly when there are hidden rows at + * the bottom + */ + @Test(groups = { "Functional" }) + public void testSetBoxFromViewportHiddenRowsAtEnd() + { + int firstHidden = 500; + int lastHidden = 524; + hideSequences(firstHidden, lastHidden); + + // calculate with visible values + alheight = vpranges.getVisibleAlignmentHeight(); + alwidth = vpranges.getVisibleAlignmentWidth(); + + boxWidth = Math.round((float) (vpranges.getEndRes() + - vpranges.getStartRes() + 1) + * od.getWidth() / alwidth); + boxHeight = Math.round((float) (vpranges.getEndSeq() + - vpranges.getStartSeq() + 1) + * od.getSequencesHeight() / alheight); + + // move viewport to start of alignment: + // box, height etc as in non-hidden case + moveViewport(0, 0); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to end of alignment + // viewport sits above hidden rows and does not include them + moveViewport(0, firstHidden - viewHeight - 1); + assertEquals(od.getBoxX(), 0); + assertEquals( + od.getBoxY(), + Math.round((float) (firstHidden - viewHeight - 1) + * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + } + + /** + * Test setting of the box position, when there are hidden rows at the start + * of the alignment + */ + @Test(groups = { "Functional" }) + public void testFromMouseWithHiddenRowsAtStart() + { + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // hide rows at start and check updated box position is correct + int lastHiddenRow = 30; + hideSequences(0, lastHiddenRow); + + // calculate with visible values + alheight = vpranges.getVisibleAlignmentHeight(); + alwidth = vpranges.getVisibleAlignmentWidth(); + + boxWidth = Math.round((float) (vpranges.getEndRes() + - vpranges.getStartRes() + 1) + * od.getWidth() / alwidth); + boxHeight = Math.round((float) (vpranges.getEndSeq() + - vpranges.getStartSeq() + 1) + * od.getSequencesHeight() / alheight); + + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // click below hidden rows + mouseClick(od, 0, 150); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 150); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + } + + /** + * Test setting of the box position, when there are hidden rows at the middle + * of the alignment + */ + @Test(groups = { "Functional" }) + public void testFromMouseWithHiddenRowsInMiddle() + { + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols); + + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // hide rows in middle and check updated box position is correct + // no changes + int firstHiddenRow = 50; + int lastHiddenRow = 54; + hideSequences(firstHiddenRow, lastHiddenRow); + + // calculate with visible values + alheight = vpranges.getVisibleAlignmentHeight(); + alwidth = vpranges.getVisibleAlignmentWidth(); + + boxWidth = Math.round((float) (vpranges.getEndRes() + - vpranges.getStartRes() + 1) + * od.getWidth() / alwidth); + boxHeight = Math.round((float) (vpranges.getEndSeq() + - vpranges.getStartSeq() + 1) + * od.getSequencesHeight() / alheight); + + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); + + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // click above hidden rows, so that box overlaps + int ypos = 35; // column value in residues + mouseClick(od, 0, + Math.round((float) ypos * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), + Math.round((float) ypos * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // click so that box straddles hidden rows + ypos = 44; // column value in residues + mouseClick(od, 0, + Math.round((float) ypos * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), + Math.round((float) ypos * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + } + + /** + * Test setting of the box position, when there are hidden rows at the end of + * the alignment + */ + @Test(groups = { "Functional" }) + public void testFromMouseWithHiddenRowsAtEnd() + { + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // hide rows at end and check updated box position is correct + // no changes + int firstHidden = 500; + int lastHidden = 524; + hideSequences(firstHidden, lastHidden); + + // calculate with visible values + alheight = vpranges.getVisibleAlignmentHeight(); + alwidth = vpranges.getVisibleAlignmentWidth(); + + boxWidth = Math.round((float) (vpranges.getEndRes() + - vpranges.getStartRes() + 1) + * od.getWidth() / alwidth); + boxHeight = Math.round((float) (vpranges.getEndSeq() + - vpranges.getStartSeq() + 1) + * od.getSequencesHeight() / alheight); + + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // click above hidden rows + int ypos = 40; // row 40 + mouseClick(od, 0, + Math.round((float) ypos * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), + Math.round((float) ypos * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // click above hidden rows so box overlaps + // boxY, boxHeight remains same + ypos = 497; // row 497 + mouseClick(od, 0, + Math.round((float) ypos * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxX(), 0); + assertEquals( + od.getBoxY(), + Math.round((float) firstHidden * od.getSequencesHeight() + / alheight) + - boxHeight); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + } + + /* + * Move viewport horizontally: startRes + previous width gives new horizontal extent. Vertical extent stays the same. + */ + private void moveViewportH(int startRes) + { + vpranges.setStartRes(startRes); + vpranges.setEndRes(startRes + viewWidth - 1); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); + } + + /* + * Move viewport vertically: startSeq and endSeq give new vertical extent. Horizontal extent stays the same. + */ + private void moveViewportV(int startSeq) + { + vpranges.setStartSeq(startSeq); + vpranges.setEndSeq(startSeq + viewHeight - 1); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); + } + + /* + * Move viewport horizontally and vertically. + */ + private void moveViewport(int startRes, int startSeq) + { + vpranges.setStartRes(startRes); + vpranges.setEndRes(startRes + viewWidth - 1); + vpranges.setStartSeq(startSeq); + vpranges.setEndSeq(startSeq + viewHeight - 1); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); + } + + /* + * Mouse click as position x,y in overview window + */ + private void mouseClick(OverviewDimensionsHideHidden od, int x, int y) + { + od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols); + + // updates require an OverviewPanel to exist which it doesn't here + // so call setBoxPosition() as it would be called by the AlignmentPanel + // normally + + vpranges.setStartRes(od.getScrollCol()); + vpranges.setEndRes(od.getScrollCol() + viewWidth - 1); + vpranges.setStartSeq(od.getScrollRow()); + vpranges.setEndSeq(od.getScrollRow() + viewHeight - 1); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); + } + + /* + * Test that the box is positioned with the top left corner at xpos, ypos + * and with the original width and height + */ + private void testBoxIsAtClickPoint(int xpos, int ypos) + { + mouseClick(od, xpos, ypos); + assertEquals(od.getBoxX(), xpos); + assertEquals(od.getBoxY(), ypos); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + } + + /* + * Hide sequences between start and end + */ + private void hideSequences(int start, int end) + { + SequenceI[] allseqs = al.getSequencesArray(); + SequenceGroup theseSeqs = new SequenceGroup(); + + for (int i = start; i <= end; i++) + { + theseSeqs.addSequence(allseqs[i], false); + al.getHiddenSequences().hideSequence(allseqs[i]); + } + + hiddenRepSequences.put(allseqs[start], theseSeqs); + } +} diff --git a/test/jalview/viewmodel/OverviewDimensionsTest.java b/test/jalview/viewmodel/OverviewDimensionsShowHiddenTest.java similarity index 95% rename from test/jalview/viewmodel/OverviewDimensionsTest.java rename to test/jalview/viewmodel/OverviewDimensionsShowHiddenTest.java index 398fec3..8297159 100644 --- a/test/jalview/viewmodel/OverviewDimensionsTest.java +++ b/test/jalview/viewmodel/OverviewDimensionsShowHiddenTest.java @@ -26,6 +26,7 @@ import jalview.analysis.AlignmentGenerator; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceCollectionI; import jalview.datamodel.SequenceGroup; @@ -39,10 +40,10 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @Test(singleThreaded = true) -public class OverviewDimensionsTest +public class OverviewDimensionsShowHiddenTest { AlignmentI al; - OverviewDimensions od; + OverviewDimensionsShowHidden od; // cached widths and heights int boxWidth; @@ -56,10 +57,10 @@ public class OverviewDimensionsTest Hashtable hiddenRepSequences = new Hashtable(); - ColumnSelection hiddenCols = new ColumnSelection(); + HiddenColumns hiddenCols = new HiddenColumns(); @BeforeClass(alwaysRun = true) - public void setUpJvOptionPane() + public void setUpAlignment() { // create random alignment AlignmentGenerator gen = new AlignmentGenerator(false); @@ -73,7 +74,8 @@ public class OverviewDimensionsTest { al.getHiddenSequences().showAll(hiddenRepSequences); } - hiddenCols.revealAllHiddenColumns(); + ColumnSelection colsel = new ColumnSelection(); + hiddenCols.revealAllHiddenColumns(colsel); vpranges = new ViewportRanges(al); vpranges.setStartRes(0); @@ -84,11 +86,11 @@ public class OverviewDimensionsTest viewHeight = vpranges.getEndSeq() - vpranges.getStartSeq() + 1; viewWidth = vpranges.getEndRes() - vpranges.getStartRes() + 1; - ColumnSelection hiddenCols = new ColumnSelection(); + HiddenColumns hiddenCols = new HiddenColumns(); - od = new OverviewDimensions(vpranges, true); + od = new OverviewDimensionsShowHidden(vpranges, true); // Initial box sizing - default path through code - od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); mouseClick(od, 0, 0); moveViewport(0, 0); @@ -136,7 +138,7 @@ public class OverviewDimensionsTest Alignment al1 = new Alignment(seqs1); ViewportRanges props = new ViewportRanges(al1); - OverviewDimensions od = new OverviewDimensions(props, true); + OverviewDimensions od = new OverviewDimensionsShowHidden(props, true); int scaledHeight = 267; assertEquals(od.getGraphHeight(), defaultGraphHeight); assertEquals(od.getSequencesHeight(), scaledHeight); @@ -148,7 +150,7 @@ public class OverviewDimensionsTest Alignment al2 = new Alignment(seqs2); props = new ViewportRanges(al2); - od = new OverviewDimensions(props, true); + od = new OverviewDimensionsShowHidden(props, true); int scaledWidth = 300; assertEquals(od.getGraphHeight(), defaultGraphHeight); assertEquals(od.getSequencesHeight(), maxSeqHeight); @@ -161,7 +163,7 @@ public class OverviewDimensionsTest Alignment al3 = new Alignment(seqs3); props = new ViewportRanges(al3); - od = new OverviewDimensions(props, true); + od = new OverviewDimensionsShowHidden(props, true); assertEquals(od.getGraphHeight(), defaultGraphHeight); assertEquals(od.getSequencesHeight(), minSeqHeight); assertEquals(od.getWidth(), maxWidth); @@ -173,7 +175,7 @@ public class OverviewDimensionsTest Alignment al4 = new Alignment(seqs4); props = new ViewportRanges(al4); - od = new OverviewDimensions(props, true); + od = new OverviewDimensionsShowHidden(props, true); assertEquals(od.getGraphHeight(), defaultGraphHeight); assertEquals(od.getSequencesHeight(), maxSeqHeight); assertEquals(od.getWidth(), minWidth); @@ -182,7 +184,7 @@ public class OverviewDimensionsTest Alignment al5 = new Alignment(seqs4); props = new ViewportRanges(al5); - od = new OverviewDimensions(props, false); + od = new OverviewDimensionsShowHidden(props, false); assertEquals(od.getGraphHeight(), 0); assertEquals(od.getSequencesHeight(), maxSeqHeight); assertEquals(od.getWidth(), minWidth); @@ -197,8 +199,7 @@ public class OverviewDimensionsTest @Test(groups = { "Functional" }) public void testSetBoxFromMouseClick() { - od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols, - vpranges); + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols); assertEquals(od.getBoxX(), 0); assertEquals(od.getBoxY(), 0); assertEquals(od.getBoxWidth(), boxWidth); @@ -296,8 +297,7 @@ public class OverviewDimensionsTest @Test(groups = { "Functional" }) public void testFromMouseWithHiddenColsAtStart() { - od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols, - vpranges); + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols); assertEquals(od.getBoxX(), 0); assertEquals(od.getBoxY(), 0); assertEquals(od.getBoxWidth(), boxWidth); @@ -309,7 +309,7 @@ public class OverviewDimensionsTest int lastHiddenCol = 30; hiddenCols.hideColumns(0, lastHiddenCol); - od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); assertEquals(od.getBoxX(), Math.round((float) (lastHiddenCol + 1) * od.getWidth() / alwidth)); @@ -361,8 +361,7 @@ public class OverviewDimensionsTest @Test(groups = { "Functional" }) public void testFromMouseWithHiddenColsInMiddle() { - od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols, - vpranges); + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols); assertEquals(od.getBoxX(), 0); assertEquals(od.getBoxY(), 0); assertEquals(od.getBoxWidth(), boxWidth); @@ -374,7 +373,7 @@ public class OverviewDimensionsTest int lastHidden = 73; hiddenCols.hideColumns(firstHidden, lastHidden); - od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); assertEquals(od.getBoxX(), 0); assertEquals(od.getBoxY(), 0); assertEquals(od.getBoxWidth(), boxWidth); @@ -463,8 +462,7 @@ public class OverviewDimensionsTest @Test(groups = { "Functional" }) public void testFromMouseWithHiddenColsAtEnd() { - od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols, - vpranges); + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols); assertEquals(od.getBoxX(), 0); assertEquals(od.getBoxY(), 0); assertEquals(od.getBoxWidth(), boxWidth); @@ -475,7 +473,7 @@ public class OverviewDimensionsTest int firstHidden = 140; int lastHidden = 164; hiddenCols.hideColumns(firstHidden, lastHidden); - od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); assertEquals(od.getBoxX(), 0); assertEquals(od.getBoxY(), 0); assertEquals(od.getBoxWidth(), boxWidth); @@ -618,9 +616,7 @@ public class OverviewDimensionsTest assertEquals(od.getBoxX(), Math.round((float) 3 * od.getWidth() / alwidth)); assertEquals(od.getBoxY(), 0); - System.out.println(od.getBoxWidth()); assertEquals(od.getBoxWidth(), boxWidth); - System.out.println(od.getBoxWidth()); assertEquals(od.getBoxHeight(), boxHeight); // move viewport to left of hidden columns with overlap @@ -790,8 +786,7 @@ public class OverviewDimensionsTest @Test(groups = { "Functional" }) public void testFromMouseWithHiddenRowsAtStart() { - od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols, - vpranges); + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols); assertEquals(od.getBoxX(), 0); assertEquals(od.getBoxY(), 0); assertEquals(od.getBoxHeight(), boxHeight); @@ -804,7 +799,7 @@ public class OverviewDimensionsTest int lastHiddenRow = 30; hideSequences(0, lastHiddenRow); - od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); assertEquals(od.getBoxX(), 0); assertEquals(od.getBoxY(), Math.round((float) (lastHiddenRow + 1) @@ -837,8 +832,7 @@ public class OverviewDimensionsTest @Test(groups = { "Functional" }) public void testFromMouseWithHiddenRowsInMiddle() { - od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols, - vpranges); + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols); assertEquals(od.getBoxX(), 0); assertEquals(od.getBoxY(), 0); @@ -853,7 +847,7 @@ public class OverviewDimensionsTest int lastHiddenRow = 54; hideSequences(firstHiddenRow, lastHiddenRow); - od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); assertEquals(od.getBoxX(), 0); assertEquals(od.getBoxY(), 0); @@ -896,8 +890,7 @@ public class OverviewDimensionsTest @Test(groups = { "Functional" }) public void testFromMouseWithHiddenRowsAtEnd() { - od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols, - vpranges); + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols); assertEquals(od.getBoxX(), 0); assertEquals(od.getBoxY(), 0); assertEquals(od.getBoxWidth(), boxWidth); @@ -911,7 +904,7 @@ public class OverviewDimensionsTest int lastHidden = 524; hideSequences(firstHidden, lastHidden); - od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); assertEquals(od.getBoxX(), 0); assertEquals(od.getBoxY(), 0); assertEquals(od.getBoxWidth(), boxWidth); @@ -960,7 +953,7 @@ public class OverviewDimensionsTest { vpranges.setStartRes(startRes); vpranges.setEndRes(startRes + viewWidth - 1); - od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); } /* @@ -970,7 +963,7 @@ public class OverviewDimensionsTest { vpranges.setStartSeq(startSeq); vpranges.setEndSeq(startSeq + viewHeight - 1); - od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); } /* @@ -982,16 +975,15 @@ public class OverviewDimensionsTest vpranges.setEndRes(startRes + viewWidth - 1); vpranges.setStartSeq(startSeq); vpranges.setEndSeq(startSeq + viewHeight - 1); - od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); } /* * Mouse click as position x,y in overview window */ - private void mouseClick(OverviewDimensions od, int x, int y) + private void mouseClick(OverviewDimensionsShowHidden od, int x, int y) { - od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols, - vpranges); + od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols); // updates require an OverviewPanel to exist which it doesn't here // so call setBoxPosition() as it would be called by the AlignmentPanel @@ -1001,7 +993,7 @@ public class OverviewDimensionsTest vpranges.setEndRes(od.getScrollCol() + viewWidth - 1); vpranges.setStartSeq(od.getScrollRow()); vpranges.setEndSeq(od.getScrollRow() + viewHeight - 1); - od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols); } /*