}
return result;
}
+
+ /**
+ * Returns a map of lists of sequences in the alignment, keyed by sequence
+ * name. For use in mapping between different alignment views of the same
+ * sequences.
+ *
+ * @see jalview.datamodel.AlignmentI#getSequencesByName()
+ */
+ public static Map<String, List<SequenceI>> getSequencesByName(
+ AlignmentI al)
+ {
+ Map<String, List<SequenceI>> theMap = new LinkedHashMap<String, List<SequenceI>>();
+ for (SequenceI seq : al.getSequences())
+ {
+ String name = seq.getName();
+ if (name != null)
+ {
+ List<SequenceI> seqs = theMap.get(name);
+ if (seqs == null)
+ {
+ seqs = new ArrayList<SequenceI>();
+ theMap.put(name, seqs);
+ }
+ seqs.add(seq);
+ }
+ }
+ return theMap;
+ }
+
+ /**
+ * Build mapping of protein to cDNA alignment. Mappings are made between
+ * sequences where the cDNA translates to the protein sequence. Any new
+ * mappings are added to the protein alignment. Returns true if any mappings
+ * either already exist or were added, else false.
+ *
+ * @param proteinAlignment
+ * @param cdnaAlignment
+ * @return
+ */
+ public static boolean mapProteinToCdna(
+ final AlignmentI proteinAlignment,
+ final AlignmentI cdnaAlignment)
+ {
+ if (proteinAlignment == null || cdnaAlignment == null)
+ {
+ return false;
+ }
+
+ Set<SequenceI> mappedDna = new HashSet<SequenceI>();
+ Set<SequenceI> mappedProtein = new HashSet<SequenceI>();
+
+ /*
+ * First pass - map sequences where cross-references exist. This include
+ * 1-to-many mappings to support, for example, variant cDNA.
+ */
+ boolean mappingPerformed = mapProteinToCdna(proteinAlignment,
+ cdnaAlignment, mappedDna, mappedProtein, true);
+
+ /*
+ * Second pass - map sequences where no cross-references exist. This only
+ * does 1-to-1 mappings and assumes corresponding sequences are in the same
+ * order in the alignments.
+ */
+ mappingPerformed |= mapProteinToCdna(proteinAlignment, cdnaAlignment,
+ mappedDna, mappedProtein, false);
+ return mappingPerformed;
+ }
+
+ /**
+ * Make mappings between compatible sequences (where the cDNA translation
+ * matches the protein).
+ *
+ * @param proteinAlignment
+ * @param cdnaAlignment
+ * @param mappedDna
+ * a set of mapped DNA sequences (to add to)
+ * @param mappedProtein
+ * a set of mapped Protein sequences (to add to)
+ * @param xrefsOnly
+ * if true, only map sequences where xrefs exist
+ * @return
+ */
+ protected static boolean mapProteinToCdna(
+ final AlignmentI proteinAlignment,
+ final AlignmentI cdnaAlignment, Set<SequenceI> mappedDna,
+ Set<SequenceI> mappedProtein, boolean xrefsOnly)
+ {
+ boolean mappingPerformed = false;
+ List<SequenceI> thisSeqs = proteinAlignment.getSequences();
+ for (SequenceI aaSeq : thisSeqs)
+ {
+ boolean proteinMapped = false;
+ AlignedCodonFrame acf = new AlignedCodonFrame();
+
+ for (SequenceI cdnaSeq : cdnaAlignment.getSequences())
+ {
+ /*
+ * Always try to map if sequences have xref to each other; this supports
+ * variant cDNA or alternative splicing for a protein sequence.
+ *
+ * If no xrefs, try to map progressively, assuming that alignments have
+ * mappable sequences in corresponding order. These are not
+ * many-to-many, as that would risk mixing species with similar cDNA
+ * sequences.
+ */
+ if (xrefsOnly && !CrossRef.haveCrossRef(aaSeq, cdnaSeq))
+ {
+ continue;
+ }
+
+ /*
+ * Don't map non-xrefd sequences more than once each. This heuristic
+ * allows us to pair up similar sequences in ordered alignments.
+ */
+ if (!xrefsOnly
+ && (mappedProtein.contains(aaSeq) || mappedDna
+ .contains(cdnaSeq)))
+ {
+ continue;
+ }
+ if (!mappingExists(proteinAlignment.getCodonFrames(),
+ aaSeq.getDatasetSequence(), cdnaSeq.getDatasetSequence()))
+ {
+ MapList map = mapProteinToCdna(aaSeq, cdnaSeq);
+ if (map != null)
+ {
+ acf.addMap(cdnaSeq, aaSeq, map);
+ mappingPerformed = true;
+ proteinMapped = true;
+ mappedDna.add(cdnaSeq);
+ mappedProtein.add(aaSeq);
+ }
+ }
+ }
+ if (proteinMapped)
+ {
+ proteinAlignment.addCodonFrame(acf);
+ }
+ }
+ return mappingPerformed;
+ }
+
+ /**
+ * Answers true if the mappings include one between the given (dataset)
+ * sequences.
+ */
+ public static boolean mappingExists(Set<AlignedCodonFrame> set,
+ SequenceI aaSeq, SequenceI cdnaSeq)
+ {
+ if (set != null)
+ {
+ for (AlignedCodonFrame acf : set)
+ {
+ if (cdnaSeq == acf.getDnaForAaSeq(aaSeq))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Build a mapping (if possible) of a protein to a cDNA sequence. The cDNA
+ * must be three times the length of the protein, possibly after ignoring
+ * start and/or stop codons, and must translate to the protein. Returns null
+ * if no mapping is determined.
+ *
+ * @param proteinSeqs
+ * @param cdnaSeq
+ * @return
+ */
+ public static MapList mapProteinToCdna(SequenceI proteinSeq,
+ SequenceI cdnaSeq)
+ {
+ /*
+ * Here we handle either dataset sequence set (desktop) or absent (applet).
+ * Use only the char[] form of the sequence to avoid creating possibly large
+ * String objects.
+ */
+ final SequenceI proteinDataset = proteinSeq.getDatasetSequence();
+ char[] aaSeqChars = proteinDataset != null ? proteinDataset
+ .getSequence() : proteinSeq.getSequence();
+ final SequenceI cdnaDataset = cdnaSeq.getDatasetSequence();
+ char[] cdnaSeqChars = cdnaDataset != null ? cdnaDataset.getSequence()
+ : cdnaSeq.getSequence();
+ if (aaSeqChars == null || cdnaSeqChars == null)
+ {
+ return null;
+ }
+
+ /*
+ * cdnaStart/End, proteinStartEnd are base 1 (for dataset sequence mapping)
+ */
+ final int mappedLength = 3 * aaSeqChars.length;
+ int cdnaLength = cdnaSeqChars.length;
+ int cdnaStart = 1;
+ int cdnaEnd = cdnaLength;
+ final int proteinStart = 1;
+ final int proteinEnd = aaSeqChars.length;
+
+ /*
+ * If lengths don't match, try ignoring stop codon.
+ */
+ if (cdnaLength != mappedLength && cdnaLength > 2)
+ {
+ String lastCodon = String.valueOf(cdnaSeqChars, cdnaLength - 3, 3)
+ .toUpperCase();
+ for (String stop : ResidueProperties.STOP)
+ {
+ if (lastCodon.equals(stop))
+ {
+ cdnaEnd -= 3;
+ cdnaLength -= 3;
+ break;
+ }
+ }
+ }
+
+ /*
+ * If lengths still don't match, try ignoring start codon.
+ */
+ if (cdnaLength != mappedLength
+ && cdnaLength > 2
+ && String.valueOf(cdnaSeqChars, 0, 3).toUpperCase()
+ .equals(
+ ResidueProperties.START))
+ {
+ cdnaStart += 3;
+ cdnaLength -= 3;
+ }
+
+ if (cdnaLength != mappedLength)
+ {
+ return null;
+ }
+ if (!translatesAs(cdnaSeqChars, cdnaStart - 1, aaSeqChars))
+ {
+ return null;
+ }
+ MapList map = new MapList(new int[]
+ { cdnaStart, cdnaEnd }, new int[]
+ { proteinStart, proteinEnd }, 3, 1);
+ return map;
+ }
+
+ /**
+ * Test whether the given cdna sequence, starting at the given offset,
+ * translates to the given amino acid sequence, using the standard translation
+ * table. Designed to fail fast i.e. as soon as a mismatch position is found.
+ *
+ * @param cdnaSeqChars
+ * @param cdnaStart
+ * @param aaSeqChars
+ * @return
+ */
+ protected static boolean translatesAs(char[] cdnaSeqChars, int cdnaStart,
+ char[] aaSeqChars)
+ {
+ int aaResidue = 0;
+ for (int i = cdnaStart; i < cdnaSeqChars.length - 2
+ && aaResidue < aaSeqChars.length; i += 3, aaResidue++)
+ {
+ String codon = String.valueOf(cdnaSeqChars, i, 3);
+ final String translated = ResidueProperties.codonTranslate(
+ codon);
+ /*
+ * ? allow X in protein to match untranslatable in dna ?
+ */
+ final char aaRes = aaSeqChars[aaResidue];
+ if ((translated == null || "STOP".equals(translated)) && aaRes == 'X')
+ {
+ continue;
+ }
+ if (translated == null
+ || !(aaRes == translated.charAt(0)))
+ {
+ // debug
- System.out.println(("Mismatch at " + i + "/" + aaResidue + ": "
- + codon + "(" + translated + ") != " + aaRes));
++ // System.out.println(("Mismatch at " + i + "/" + aaResidue + ": "
++ // + codon + "(" + translated + ") != " + aaRes));
+ return false;
+ }
+ }
+ // fail if we didn't match all of the aa sequence
+ return (aaResidue == aaSeqChars.length);
+ }
+
+ /**
+ * Align sequence 'seq' to match the alignment of a mapped sequence. Note this
+ * currently assumes that we are aligning cDNA to match protein.
+ *
+ * @param seq
+ * the sequence to be realigned
+ * @param al
+ * the alignment whose sequence alignment is to be 'copied'
+ * @param gap
+ * character string represent a gap in the realigned sequence
+ * @param preserveUnmappedGaps
+ * @param preserveMappedGaps
+ * @return true if the sequence was realigned, false if it could not be
+ */
+ public static boolean alignSequenceAs(SequenceI seq, AlignmentI al,
+ String gap, boolean preserveMappedGaps,
+ boolean preserveUnmappedGaps)
+ {
+ /*
+ * Get any mappings from the source alignment to the target (dataset) sequence.
+ */
+ // TODO there may be one AlignedCodonFrame per dataset sequence, or one with
+ // all mappings. Would it help to constrain this?
+ List<AlignedCodonFrame> mappings = al.getCodonFrame(seq);
+ if (mappings == null || mappings.isEmpty())
+ {
+ return false;
+ }
+
+ /*
+ * Locate the aligned source sequence whose dataset sequence is mapped. We
+ * just take the first match here (as we can't align cDNA like more than one
+ * protein sequence).
+ */
+ SequenceI alignFrom = null;
+ AlignedCodonFrame mapping = null;
+ for (AlignedCodonFrame mp : mappings)
+ {
+ alignFrom = mp.findAlignedSequence(seq.getDatasetSequence(), al);
+ if (alignFrom != null)
+ {
+ mapping = mp;
+ break;
+ }
+ }
+
+ if (alignFrom == null)
+ {
+ return false;
+ }
+ alignSequenceAs(seq, alignFrom, mapping, gap, al.getGapCharacter(),
+ preserveMappedGaps, preserveUnmappedGaps);
+ return true;
+ }
+
+ /**
+ * Align sequence 'alignTo' the same way as 'alignFrom', using the mapping to
+ * match residues and codons. Flags control whether existing gaps in unmapped
+ * (intron) and mapped (exon) regions are preserved or not. Gaps linking intro
+ * and exon are only retained if both flags are set.
+ *
+ * @param alignTo
+ * @param alignFrom
+ * @param mapping
+ * @param myGap
+ * @param sourceGap
+ * @param preserveUnmappedGaps
+ * @param preserveMappedGaps
+ */
+ public static void alignSequenceAs(SequenceI alignTo,
+ SequenceI alignFrom,
+ AlignedCodonFrame mapping, String myGap, char sourceGap,
+ boolean preserveMappedGaps, boolean preserveUnmappedGaps)
+ {
+ // TODO generalise to work for Protein-Protein, dna-dna, dna-protein
+ final char[] thisSeq = alignTo.getSequence();
+ final char[] thatAligned = alignFrom.getSequence();
+ StringBuilder thisAligned = new StringBuilder(2 * thisSeq.length);
+
+ // aligned and dataset sequence positions, all base zero
+ int thisSeqPos = 0;
+ int sourceDsPos = 0;
+
+ int basesWritten = 0;
+ char myGapChar = myGap.charAt(0);
+ int ratio = myGap.length();
+
+ /*
+ * Traverse the aligned protein sequence.
+ */
+ int sourceGapMappedLength = 0;
+ boolean inExon = false;
+ for (char sourceChar : thatAligned)
+ {
+ if (sourceChar == sourceGap)
+ {
+ sourceGapMappedLength += ratio;
+ continue;
+ }
+
+ /*
+ * Found a residue. Locate its mapped codon (start) position.
+ */
+ sourceDsPos++;
+ // Note mapping positions are base 1, our sequence positions base 0
+ int[] mappedPos = mapping.getMappedRegion(alignTo, alignFrom,
+ sourceDsPos);
+ if (mappedPos == null)
+ {
+ /*
+ * Abort realignment if unmapped protein. Or could ignore it??
+ */
+ System.err.println("Can't align: no codon mapping to residue "
+ + sourceDsPos + "(" + sourceChar + ")");
+ return;
+ }
+
+ int mappedCodonStart = mappedPos[0]; // position (1...) of codon start
+ int mappedCodonEnd = mappedPos[mappedPos.length - 1]; // codon end pos
+ StringBuilder trailingCopiedGap = new StringBuilder();
+
+ /*
+ * Copy dna sequence up to and including this codon. Optionally, include
+ * gaps before the codon starts (in introns) and/or after the codon starts
+ * (in exons).
+ *
+ * Note this only works for 'linear' splicing, not reverse or interleaved.
+ * But then 'align dna as protein' doesn't make much sense otherwise.
+ */
+ int intronLength = 0;
+ while (basesWritten < mappedCodonEnd && thisSeqPos < thisSeq.length)
+ {
+ final char c = thisSeq[thisSeqPos++];
+ if (c != myGapChar)
+ {
+ basesWritten++;
+
+ if (basesWritten < mappedCodonStart)
+ {
+ /*
+ * Found an unmapped (intron) base. First add in any preceding gaps
+ * (if wanted).
+ */
+ if (preserveUnmappedGaps && trailingCopiedGap.length() > 0)
+ {
+ thisAligned.append(trailingCopiedGap.toString());
+ intronLength += trailingCopiedGap.length();
+ trailingCopiedGap = new StringBuilder();
+ }
+ intronLength++;
+ inExon = false;
+ }
+ else
+ {
+ final boolean startOfCodon = basesWritten == mappedCodonStart;
+ int gapsToAdd = calculateGapsToInsert(preserveMappedGaps,
+ preserveUnmappedGaps, sourceGapMappedLength, inExon,
+ trailingCopiedGap.length(), intronLength, startOfCodon);
+ for (int i = 0; i < gapsToAdd; i++)
+ {
+ thisAligned.append(myGapChar);
+ }
+ sourceGapMappedLength = 0;
+ inExon = true;
+ }
+ thisAligned.append(c);
+ trailingCopiedGap = new StringBuilder();
+ }
+ else
+ {
+ if (inExon && preserveMappedGaps)
+ {
+ trailingCopiedGap.append(myGapChar);
+ }
+ else if (!inExon && preserveUnmappedGaps)
+ {
+ trailingCopiedGap.append(myGapChar);
+ }
+ }
+ }
+ }
+
+ /*
+ * At end of protein sequence. Copy any remaining dna sequence, optionally
+ * including (intron) gaps. We do not copy trailing gaps in protein.
+ */
+ while (thisSeqPos < thisSeq.length)
+ {
+ final char c = thisSeq[thisSeqPos++];
+ if (c != myGapChar || preserveUnmappedGaps)
+ {
+ thisAligned.append(c);
+ }
+ }
+
+ /*
+ * All done aligning, set the aligned sequence.
+ */
+ alignTo.setSequence(new String(thisAligned));
+ }
+
+ /**
+ * Helper method to work out how many gaps to insert when realigning.
+ *
+ * @param preserveMappedGaps
+ * @param preserveUnmappedGaps
+ * @param sourceGapMappedLength
+ * @param inExon
+ * @param trailingCopiedGap
+ * @param intronLength
+ * @param startOfCodon
+ * @return
+ */
+ protected static int calculateGapsToInsert(boolean preserveMappedGaps,
+ boolean preserveUnmappedGaps, int sourceGapMappedLength,
+ boolean inExon, int trailingGapLength,
+ int intronLength, final boolean startOfCodon)
+ {
+ int gapsToAdd = 0;
+ if (startOfCodon)
+ {
+ /*
+ * Reached start of codon. Ignore trailing gaps in intron unless we are
+ * preserving gaps in both exon and intron. Ignore them anyway if the
+ * protein alignment introduces a gap at least as large as the intronic
+ * region.
+ */
+ if (inExon && !preserveMappedGaps)
+ {
+ trailingGapLength = 0;
+ }
+ if (!inExon && !(preserveMappedGaps && preserveUnmappedGaps))
+ {
+ trailingGapLength = 0;
+ }
+ if (inExon)
+ {
+ gapsToAdd = Math.max(sourceGapMappedLength, trailingGapLength);
+ }
+ else
+ {
+ if (intronLength + trailingGapLength <= sourceGapMappedLength)
+ {
+ gapsToAdd = sourceGapMappedLength - intronLength;
+ }
+ else
+ {
+ gapsToAdd = Math.min(intronLength + trailingGapLength
+ - sourceGapMappedLength, trailingGapLength);
+ }
+ }
+ }
+ else
+ {
+ /*
+ * second or third base of codon; check for any gaps in dna
+ */
+ if (!preserveMappedGaps)
+ {
+ trailingGapLength = 0;
+ }
+ gapsToAdd = Math.max(sourceGapMappedLength, trailingGapLength);
+ }
+ return gapsToAdd;
+ }
+
+ /**
+ * Returns a list of sequences mapped from the given sequences and aligned
+ * (gapped) in the same way. For example, the cDNA for aligned protein, where
+ * a single gap in protein generates three gaps in cDNA.
+ *
+ * @param sequences
+ * @param gapCharacter
+ * @param mappings
+ * @return
+ */
+ public static List<SequenceI> getAlignedTranslation(
+ List<SequenceI> sequences, char gapCharacter,
+ Set<AlignedCodonFrame> mappings)
+ {
+ List<SequenceI> alignedSeqs = new ArrayList<SequenceI>();
+
+ for (SequenceI seq : sequences)
+ {
+ List<SequenceI> mapped = getAlignedTranslation(seq, gapCharacter,
+ mappings);
+ alignedSeqs.addAll(mapped);
+ }
+ return alignedSeqs;
+ }
+
+ /**
+ * Returns sequences aligned 'like' the source sequence, as mapped by the
+ * given mappings. Normally we expect zero or one 'mapped' sequences, but this
+ * will support 1-to-many as well.
+ *
+ * @param seq
+ * @param gapCharacter
+ * @param mappings
+ * @return
+ */
+ protected static List<SequenceI> getAlignedTranslation(SequenceI seq,
+ char gapCharacter, Set<AlignedCodonFrame> mappings)
+ {
+ List<SequenceI> result = new ArrayList<SequenceI>();
+ for (AlignedCodonFrame mapping : mappings)
+ {
+ if (mapping.involvesSequence(seq))
+ {
+ SequenceI mapped = getAlignedTranslation(seq, gapCharacter, mapping);
+ if (mapped != null)
+ {
+ result.add(mapped);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the translation of 'seq' (as held in the mapping) with
+ * corresponding alignment (gaps).
+ *
+ * @param seq
+ * @param gapCharacter
+ * @param mapping
+ * @return
+ */
+ protected static SequenceI getAlignedTranslation(SequenceI seq,
+ char gapCharacter, AlignedCodonFrame mapping)
+ {
+ String gap = String.valueOf(gapCharacter);
+ boolean toDna = false;
+ int fromRatio = 1;
+ SequenceI mapTo = mapping.getDnaForAaSeq(seq);
+ if (mapTo != null)
+ {
+ // mapping is from protein to nucleotide
+ toDna = true;
+ // should ideally get gap count ratio from mapping
+ gap = String.valueOf(new char[]
+ { gapCharacter, gapCharacter, gapCharacter });
+ }
+ else
+ {
+ // mapping is from nucleotide to protein
+ mapTo = mapping.getAaForDnaSeq(seq);
+ fromRatio = 3;
+ }
+ StringBuilder newseq = new StringBuilder(seq.getLength()
+ * (toDna ? 3 : 1));
+
+ int residueNo = 0; // in seq, base 1
+ int[] phrase = new int[fromRatio];
+ int phraseOffset = 0;
+ int gapWidth = 0;
+ boolean first = true;
+ final Sequence alignedSeq = new Sequence("", "");
+
+ for (char c : seq.getSequence())
+ {
+ if (c == gapCharacter)
+ {
+ gapWidth++;
+ if (gapWidth >= fromRatio)
+ {
+ newseq.append(gap);
+ gapWidth = 0;
+ }
+ }
+ else
+ {
+ phrase[phraseOffset++] = residueNo + 1;
+ if (phraseOffset == fromRatio)
+ {
+ /*
+ * Have read a whole codon (or protein residue), now translate: map
+ * source phrase to positions in target sequence add characters at
+ * these positions to newseq Note mapping positions are base 1, our
+ * sequence positions base 0.
+ */
+ SearchResults sr = new SearchResults();
+ for (int pos : phrase)
+ {
+ mapping.markMappedRegion(seq, pos, sr);
+ }
+ newseq.append(sr.toString());
+ if (first)
+ {
+ first = false;
+ // Hack: Copy sequence dataset, name and description from
+ // SearchResults.match[0].sequence
+ // TODO? carry over sequence names from original 'complement'
+ // alignment
+ SequenceI mappedTo = sr.getResultSequence(0);
+ alignedSeq.setName(mappedTo.getName());
+ alignedSeq.setDescription(mappedTo.getDescription());
+ alignedSeq.setDatasetSequence(mappedTo);
+ }
+ phraseOffset = 0;
+ }
+ residueNo++;
+ }
+ }
+ alignedSeq.setSequence(newseq.toString());
+ return alignedSeq;
+ }
+
+ /**
+ * Realigns the given protein to match the alignment of the dna, using codon
+ * mappings to translate aligned codon positions to protein residues.
+ *
+ * @param protein
+ * the alignment whose sequences are realigned by this method
+ * @param dna
+ * the dna alignment whose alignment we are 'copying'
+ * @return the number of sequences that were realigned
+ */
+ public static int alignProteinAsDna(AlignmentI protein, AlignmentI dna)
+ {
+ Set<AlignedCodonFrame> mappings = protein.getCodonFrames();
+
+ /*
+ * Map will hold, for each aligned codon position e.g. [3, 5, 6], a map of
+ * {dnaSequence, {proteinSequence, codonProduct}} at that position. The
+ * comparator keeps the codon positions ordered.
+ */
+ Map<AlignedCodon, Map<SequenceI, String>> alignedCodons = new TreeMap<AlignedCodon, Map<SequenceI, String>>(
+ new CodonComparator());
+ for (SequenceI dnaSeq : dna.getSequences())
+ {
+ for (AlignedCodonFrame mapping : mappings)
+ {
+ Mapping seqMap = mapping.getMappingForSequence(dnaSeq);
+ SequenceI prot = mapping.findAlignedSequence(
+ dnaSeq.getDatasetSequence(), protein);
+ if (prot != null)
+ {
+ addCodonPositions(dnaSeq, prot, protein.getGapCharacter(),
+ seqMap, alignedCodons);
+ }
+ }
+ }
+ return alignProteinAs(protein, alignedCodons);
+ }
+
+ /**
+ * Update the aligned protein sequences to match the codon alignments given in
+ * the map.
+ *
+ * @param protein
+ * @param alignedCodons
+ * an ordered map of codon positions (columns), with sequence/peptide
+ * values present in each column
+ * @return
+ */
+ protected static int alignProteinAs(AlignmentI protein,
+ Map<AlignedCodon, Map<SequenceI, String>> alignedCodons)
+ {
+ /*
+ * Prefill aligned sequences with gaps before inserting aligned protein
+ * residues.
+ */
+ int alignedWidth = alignedCodons.size();
+ char[] gaps = new char[alignedWidth];
+ Arrays.fill(gaps, protein.getGapCharacter());
+ String allGaps = String.valueOf(gaps);
+ for (SequenceI seq : protein.getSequences())
+ {
+ seq.setSequence(allGaps);
+ }
+
+ int column = 0;
+ for (AlignedCodon codon : alignedCodons.keySet())
+ {
+ final Map<SequenceI, String> columnResidues = alignedCodons.get(codon);
+ for (Entry<SequenceI, String> entry : columnResidues
+ .entrySet())
+ {
+ // place translated codon at its column position in sequence
+ entry.getKey().getSequence()[column] = entry.getValue().charAt(0);
+ }
+ column++;
+ }
+ return 0;
+ }
+
+ /**
+ * Populate the map of aligned codons by traversing the given sequence
+ * mapping, locating the aligned positions of mapped codons, and adding those
+ * positions and their translation products to the map.
+ *
+ * @param dna
+ * the aligned sequence we are mapping from
+ * @param protein
+ * the sequence to be aligned to the codons
+ * @param gapChar
+ * the gap character in the dna sequence
+ * @param seqMap
+ * a mapping to a sequence translation
+ * @param alignedCodons
+ * the map we are building up
+ */
+ static void addCodonPositions(SequenceI dna, SequenceI protein,
+ char gapChar,
+ Mapping seqMap,
+ Map<AlignedCodon, Map<SequenceI, String>> alignedCodons)
+ {
+ Iterator<AlignedCodon> codons = seqMap.getCodonIterator(dna, gapChar);
+ while (codons.hasNext())
+ {
+ AlignedCodon codon = codons.next();
+ Map<SequenceI, String> seqProduct = alignedCodons.get(codon);
+ if (seqProduct == null)
+ {
+ seqProduct = new HashMap<SequenceI, String>();
+ alignedCodons.put(codon, seqProduct);
+ }
+ seqProduct.put(protein, codon.product);
+ }
+ }
+
+ /**
+ * Returns true if a cDNA/Protein mapping either exists, or could be made,
+ * between at least one pair of sequences in the two alignments. Currently,
+ * the logic is:
+ * <ul>
+ * <li>One alignment must be nucleotide, and the other protein</li>
+ * <li>At least one pair of sequences must be already mapped, or mappable</li>
+ * <li>Mappable means the nucleotide translation matches the protein sequence</li>
+ * <li>The translation may ignore start and stop codons if present in the
+ * nucleotide</li>
+ * </ul>
+ *
+ * @param al1
+ * @param al2
+ * @return
+ */
+ public static boolean isMappable(AlignmentI al1, AlignmentI al2)
+ {
+ /*
+ * Require one nucleotide and one protein
+ */
+ if (al1.isNucleotide() == al2.isNucleotide())
+ {
+ return false;
+ }
+ AlignmentI dna = al1.isNucleotide() ? al1 : al2;
+ AlignmentI protein = dna == al1 ? al2 : al1;
+ Set<AlignedCodonFrame> mappings = protein.getCodonFrames();
+ for (SequenceI dnaSeq : dna.getSequences())
+ {
+ for (SequenceI proteinSeq : protein.getSequences())
+ {
+ if (isMappable(dnaSeq, proteinSeq, mappings))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the dna sequence is mapped, or could be mapped, to the
+ * protein sequence.
+ *
+ * @param dnaSeq
+ * @param proteinSeq
+ * @param mappings
+ * @return
+ */
+ public static boolean isMappable(SequenceI dnaSeq, SequenceI proteinSeq,
+ Set<AlignedCodonFrame> mappings)
+ {
+ SequenceI dnaDs = dnaSeq.getDatasetSequence() == null ? dnaSeq : dnaSeq.getDatasetSequence();
+ SequenceI proteinDs = proteinSeq.getDatasetSequence() == null ? proteinSeq
+ : proteinSeq.getDatasetSequence();
+
+ /*
+ * Already mapped?
+ */
+ for (AlignedCodonFrame mapping : mappings) {
+ if ( proteinDs == mapping.getAaForDnaSeq(dnaDs)) {
+ return true;
+ }
+ }
+
+ /*
+ * Just try to make a mapping (it is not yet stored), test whether
+ * successful.
+ */
+ return mapProteinToCdna(proteinDs, dnaDs) != null;
+ }
}
* indicating if they are displayed.
*/
private static void transferCodedFeatures(SequenceI dna, SequenceI pep,
- MapList map, Hashtable featureTypes, Hashtable featureGroups)
+ MapList map, Map<String, Object> featureTypes,
+ Map<String, Boolean> featureGroups)
{
- SequenceFeature[] sfs = (dna.getDatasetSequence() != null ? dna
- .getDatasetSequence() : dna).getSequenceFeatures();
- SequenceFeature[] sf = dna.getSequenceFeatures();
++ SequenceFeature[] sfs = dna.getSequenceFeatures();
Boolean fgstate;
- jalview.datamodel.DBRefEntry[] dnarefs = jalview.util.DBRefUtils
- .selectRefs(dna.getDBRef(),
- jalview.datamodel.DBRefSource.DNACODINGDBS);
+ DBRefEntry[] dnarefs = DBRefUtils.selectRefs(dna.getDBRef(),
+ DBRefSource.DNACODINGDBS);
if (dnarefs != null)
{
// intersect with pep
return file;
}
- // public LoadingThread(String _file, JalviewLite _applet)
- // {
- // this._file = _file;
- // applet = _applet;
- // }
-
- public LoadingThread(String _file, JalviewLite _applet)
+ public LoadingThread(String file, String file2, JalviewLite _applet)
{
- this._file = _file;
+ this._file = file;
+ this._file2 = file2;
applet = _applet;
}
import jalview.util.MessageManager;
import jalview.ws.HttpClientUtils;
++import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
// return processJsonResponseFor(HttpClientUtils.doHttpUrlPost(twoDtoolsURL,
// vals));
ArrayList<Reader> readers = new ArrayList<Reader>();
- readers.add(HttpClientUtils.doHttpUrlPost(twoDtoolsURL, vals, 0, 0));
- readers.add(HttpClientUtils.doHttpUrlPost(twoDtoolsURL, vals));
++ final BufferedReader postResponse = HttpClientUtils.doHttpUrlPost(twoDtoolsURL, vals, 0, 0);
++ readers.add(postResponse);
return readers.iterator();
}
*/
package jalview.ext.rbvi.chimera;
++import java.awt.Color;
++import java.util.ArrayList;
++import java.util.LinkedHashMap;
++import java.util.List;
++import java.util.Map;
++import java.util.TreeMap;
++
import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.datamodel.AlignmentI;
import jalview.util.ColorUtils;
import jalview.util.Comparison;
--import java.awt.Color;
--import java.util.ArrayList;
--import java.util.LinkedHashMap;
--import java.util.List;
--import java.util.Map;
--import java.util.TreeMap;
--
/**
* Routines for generating Chimera commands for Jalview/Chimera binding
*
final Map<String, List<int[]>> modelData = colourData.get(model);
for (String chain : modelData.keySet())
{
++ boolean hasChain = !"".equals(chain.trim());
for (int[] range : modelData.get(chain))
{
if (!firstPositionForModel)
{
sb.append(range[0]).append("-").append(range[1]);
}
-- sb.append(".").append(chain);
++ if (hasChain)
++ {
++ sb.append(".").append(chain);
++ }
firstPositionForModel = false;
}
}
for (s = 0; s < sSize; s++)
{
- sy = s * av.charHeight + scaleHeight;
+ sy = s * av.getCharHeight() + scaleHeight;
SequenceI seq = av.getAlignment().getSequenceAt(s);
- SequenceFeature[] features = seq.getDatasetSequence()
- .getSequenceFeatures();
+ SequenceFeature[] features = seq.getSequenceFeatures();
SequenceGroup[] groups = av.getAlignment().findAllGroups(seq);
for (res = 0; res < alwidth; res++)
{
public class AnnotationLabels extends JPanel implements MouseListener,
MouseMotionListener, ActionListener
{
++ private static final Pattern LEFT_ANGLE_BRACKET_PATTERN = Pattern.compile("<");
++
String TOGGLE_LABELSCALE = MessageManager.getString("label.scale_label_to_column");
String ADDNEW = MessageManager.getString("label.add_new_row");
|| (desc.substring(0, 6).toLowerCase().indexOf("<html>") < 0))
{
// clean the description ready for embedding in html
-- desc = new StringBuffer(Pattern.compile("<").matcher(desc)
++ desc = new StringBuffer(LEFT_ANGLE_BRACKET_PATTERN.matcher(desc)
.replaceAll("<"));
desc.insert(0, "<html>");
}
*/
package jalview.gui;
++import java.awt.Color;
++import java.awt.event.ActionEvent;
++import java.awt.event.ActionListener;
++import java.util.ArrayList;
++import java.util.Arrays;
++import java.util.Collection;
++import java.util.Collections;
++import java.util.Hashtable;
++import java.util.LinkedHashMap;
++import java.util.List;
++import java.util.Map;
++import java.util.TreeMap;
++import java.util.Vector;
++
++import javax.swing.ButtonGroup;
++import javax.swing.JCheckBoxMenuItem;
++import javax.swing.JColorChooser;
++import javax.swing.JMenu;
++import javax.swing.JMenuItem;
++import javax.swing.JOptionPane;
++import javax.swing.JPopupMenu;
++import javax.swing.JRadioButtonMenuItem;
++
import jalview.analysis.AAFrequency;
import jalview.analysis.AlignmentAnnotationUtils;
import jalview.analysis.Conservation;
import jalview.util.MessageManager;
import jalview.util.UrlLink;
--import java.awt.Color;
--import java.awt.event.ActionEvent;
--import java.awt.event.ActionListener;
--import java.util.ArrayList;
--import java.util.Arrays;
--import java.util.Collection;
--import java.util.Collections;
--import java.util.Hashtable;
--import java.util.LinkedHashMap;
--import java.util.List;
--import java.util.Map;
--import java.util.TreeMap;
--import java.util.Vector;
--
--import javax.swing.ButtonGroup;
--import javax.swing.JCheckBoxMenuItem;
--import javax.swing.JColorChooser;
--import javax.swing.JMenu;
--import javax.swing.JMenuItem;
--import javax.swing.JOptionPane;
--import javax.swing.JPopupMenu;
--import javax.swing.JRadioButtonMenuItem;
--
/**
* DOCUMENT ME!
*
*/
package jalview.io;
-import jalview.datamodel.DBRefEntry;
-import jalview.datamodel.SequenceFeature;
-import jalview.datamodel.SequenceI;
-import jalview.util.UrlLink;
+
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
charOffset = (av_charWidth - fm.charWidth(s)) / 2;
g.drawString(String.valueOf(s), charOffset
+ (av_charWidth * (i - start)), pady);
--
}
}
}
charOffset = (av_charWidth - fm.charWidth(s)) / 2;
g.drawString(String.valueOf(s), charOffset
+ (av_charWidth * (i - start)), pady);
--
}
}
}
// current feature to render
for (sfindex = 0; sfindex < sfSize; sfindex++)
{
- if (!sequenceFeatures[sfindex].type.equals(type))
- if (!lastSequenceFeatures[sfindex].type.equals(type))
++ final SequenceFeature sequenceFeature = lastSequenceFeatures[sfindex];
++ if (!sequenceFeature.type.equals(type))
{
continue;
}
if (featureGroups != null
- && sequenceFeatures[sfindex].featureGroup != null
- && sequenceFeatures[sfindex].featureGroup.length() != 0
- && featureGroups
- .containsKey(sequenceFeatures[sfindex].featureGroup)
- && !featureGroups
- .get(sequenceFeatures[sfindex].featureGroup)
- && lastSequenceFeatures[sfindex].featureGroup != null
- && lastSequenceFeatures[sfindex].featureGroup.length() != 0
- && featureGroups
- .containsKey(lastSequenceFeatures[sfindex].featureGroup)
- && !featureGroups
-.get(
- lastSequenceFeatures[sfindex].featureGroup)
++ && sequenceFeature.featureGroup != null
++ && sequenceFeature.featureGroup.length() != 0
++ && featureGroups.containsKey(sequenceFeature.featureGroup)
++ && !featureGroups.get(sequenceFeature.featureGroup)
.booleanValue())
{
continue;
}
if (!offscreenRender
- && (sequenceFeatures[sfindex].getBegin() > epos || sequenceFeatures[sfindex]
- && (lastSequenceFeatures[sfindex].getBegin() > epos || lastSequenceFeatures[sfindex]
++ && (sequenceFeature.getBegin() > epos || sequenceFeature
.getEnd() < spos))
{
continue;
if (offscreenRender && offscreenImage == null)
{
- if (sequenceFeatures[sfindex].begin <= start
- && sequenceFeatures[sfindex].end >= start)
- if (lastSequenceFeatures[sfindex].begin <= start
- && lastSequenceFeatures[sfindex].end >= start)
++ if (sequenceFeature.begin <= start
++ && sequenceFeature.end >= start)
{
// this is passed out to the overview and other sequence renderers
// (e.g. molecule viewer) to get displayed colour for rendered
// sequence
-- currentColour = new Integer(
- getColour(sequenceFeatures[sfindex]).getRGB());
-getColour(
- lastSequenceFeatures[sfindex]).getRGB());
++ currentColour = new Integer(getColour(sequenceFeature).getRGB());
// used to be retreived from av.featuresDisplayed
// currentColour = av.featuresDisplayed
// .get(sequenceFeatures[sfindex].type);
}
}
- else if (sequenceFeatures[sfindex].type.equals("disulfide bond"))
- else if (lastSequenceFeatures[sfindex].type
- .equals("disulfide bond"))
++ else if (sequenceFeature.type.equals("disulfide bond"))
{
--
-- renderFeature(g, seq,
- seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
- seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
- getColour(sequenceFeatures[sfindex])
- seq.findIndex(lastSequenceFeatures[sfindex].begin) - 1,
- seq.findIndex(lastSequenceFeatures[sfindex].begin) - 1,
- getColour(lastSequenceFeatures[sfindex])
++ renderFeature(g, seq, seq.findIndex(sequenceFeature.begin) - 1,
++ seq.findIndex(sequenceFeature.begin) - 1,
++ getColour(sequenceFeature)
// new Color(((Integer) av.featuresDisplayed
// .get(sequenceFeatures[sfindex].type)).intValue())
, start, end, y1);
-- renderFeature(g, seq,
- seq.findIndex(sequenceFeatures[sfindex].end) - 1,
- seq.findIndex(sequenceFeatures[sfindex].end) - 1,
- getColour(sequenceFeatures[sfindex])
- seq.findIndex(lastSequenceFeatures[sfindex].end) - 1,
- seq.findIndex(lastSequenceFeatures[sfindex].end) - 1,
- getColour(lastSequenceFeatures[sfindex])
++ renderFeature(g, seq, seq.findIndex(sequenceFeature.end) - 1,
++ seq.findIndex(sequenceFeature.end) - 1,
++ getColour(sequenceFeature)
// new Color(((Integer) av.featuresDisplayed
// .get(sequenceFeatures[sfindex].type)).intValue())
, start, end, y1);
}
- else if (showFeature(sequenceFeatures[sfindex]))
- else if (showFeature(lastSequenceFeatures[sfindex]))
++ else if (showFeature(sequenceFeature))
{
if (av_isShowSeqFeatureHeight
- && sequenceFeatures[sfindex].score != Float.NaN)
- && lastSequenceFeatures[sfindex].score != Float.NaN)
++ && sequenceFeature.score != Float.NaN)
{
renderScoreFeature(g, seq,
- seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
- seq.findIndex(sequenceFeatures[sfindex].end) - 1,
- getColour(sequenceFeatures[sfindex]), start, end, y1,
- normaliseScore(sequenceFeatures[sfindex]));
- seq.findIndex(lastSequenceFeatures[sfindex].begin) - 1,
- seq.findIndex(lastSequenceFeatures[sfindex].end) - 1,
- getColour(lastSequenceFeatures[sfindex]), start, end,
- y1, normaliseScore(lastSequenceFeatures[sfindex]));
++ seq.findIndex(sequenceFeature.begin) - 1,
++ seq.findIndex(sequenceFeature.end) - 1,
++ getColour(sequenceFeature), start, end, y1,
++ normaliseScore(sequenceFeature));
}
else
{
-- renderFeature(g, seq,
- seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
- seq.findIndex(sequenceFeatures[sfindex].end) - 1,
- getColour(sequenceFeatures[sfindex]), start, end, y1);
- seq.findIndex(lastSequenceFeatures[sfindex].begin) - 1,
- seq.findIndex(lastSequenceFeatures[sfindex].end) - 1,
- getColour(lastSequenceFeatures[sfindex]), start, end,
- y1);
++ renderFeature(g, seq, seq.findIndex(sequenceFeature.begin) - 1,
++ seq.findIndex(sequenceFeature.end) - 1,
++ getColour(sequenceFeature), start, end, y1);
}
}
*/
public class ParseHtmlBodyAndLinks
{
++ private static final Pattern LEFT_ANGLE_BRACKET_PATTERN = Pattern.compile("<");
++
String orig = null;
public String getOrig()
{
// instead of parsing the html into plaintext
// clean the description ready for embedding in html
-- sb = new StringBuffer(Pattern.compile("<").matcher(description)
++ sb = new StringBuffer(LEFT_ANGLE_BRACKET_PATTERN.matcher(description)
.replaceAll("<"));
}
--- /dev/null
+package jalview.util;
+
++import java.util.ArrayList;
++import java.util.List;
++import java.util.regex.Pattern;
++
+
+public class StringUtils
+{
++ private static final Pattern DELIMITERS_PATTERN = Pattern.compile(".*='[^']*(?!')");
++
++ private static final boolean DEBUG = false;
+
+ /**
+ * Returns a new character array, after inserting characters into the given
+ * character array.
+ *
+ * @param in
+ * the character array to insert into
+ * @param position
+ * the 0-based position for insertion
+ * @param count
+ * the number of characters to insert
+ * @param ch
+ * the character to insert
+ */
+ public static final char[] insertCharAt(char[] in, int position,
+ int count,
+ char ch)
+ {
+ char[] tmp = new char[in.length + count];
+
+ if (position >= in.length)
+ {
+ System.arraycopy(in, 0, tmp, 0, in.length);
+ position = in.length;
+ }
+ else
+ {
+ System.arraycopy(in, 0, tmp, 0, position);
+ }
+
+ int index = position;
+ while (count > 0)
+ {
+ tmp[index++] = ch;
+ count--;
+ }
+
+ if (position < in.length)
+ {
+ System.arraycopy(in, position, tmp, index,
+ in.length - position);
+ }
+
+ return tmp;
+ }
+
+ /**
+ * Delete
+ *
+ * @param in
+ * @param from
+ * @param to
+ * @return
+ */
+ public static final char[] deleteChars(char[] in, int from, int to)
+ {
+ if (from >= in.length)
+ {
+ return in;
+ }
+
+ char[] tmp;
+
+ if (to >= in.length)
+ {
+ tmp = new char[from];
+ System.arraycopy(in, 0, tmp, 0, from);
+ to = in.length;
+ }
+ else
+ {
+ tmp = new char[in.length - to + from];
+ System.arraycopy(in, 0, tmp, 0, from);
+ System.arraycopy(in, to, tmp, from, in.length - to);
+ }
+ return tmp;
+ }
+
+ /**
+ * Returns the last part of 'input' after the last occurrence of 'token'. For
+ * example to extract only the filename from a full path or URL.
+ *
+ * @param input
+ * @param token
+ * a delimiter which must be in regular expression format
+ * @return
+ */
+ public static String getLastToken(String input, String token)
+ {
+ if (input == null)
+ {
+ return null;
+ }
+ if (token == null)
+ {
+ return input;
+ }
+ String[] st = input.split(token);
+ return st[st.length - 1];
+ }
++
++ /**
++ * Parses the input string into components separated by the delimiter. Unlike
++ * String.split(), this method will ignore occurrences of the delimiter which
++ * are nested within single quotes in name-value pair values, e.g. a='b,c'.
++ *
++ * @param input
++ * @param delimiter
++ * @return elements separated by separator
++ */
++ public static String[] separatorListToArray(String input, String delimiter)
++ {
++ int seplen = delimiter.length();
++ if (input == null || input.equals("") || input.equals(delimiter))
++ {
++ return null;
++ }
++ List<String> jv = new ArrayList<String>();
++ int cp = 0, pos, escape;
++ boolean wasescaped = false, wasquoted = false;
++ String lstitem = null;
++ while ((pos = input.indexOf(delimiter, cp)) >= cp)
++ {
++ escape = (pos > 0 && input.charAt(pos - 1) == '\\') ? -1 : 0;
++ if (wasescaped || wasquoted)
++ {
++ // append to previous pos
++ jv.set(jv.size() - 1,
++ lstitem = lstitem + delimiter
++ + input.substring(cp, pos + escape));
++ }
++ else
++ {
++ jv.add(lstitem = input.substring(cp, pos + escape));
++ }
++ cp = pos + seplen;
++ wasescaped = escape == -1;
++ // last separator may be in an unmatched quote
++ wasquoted = DELIMITERS_PATTERN.matcher(lstitem).matches();
++ }
++ if (cp < input.length())
++ {
++ String c = input.substring(cp);
++ if (wasescaped || wasquoted)
++ {
++ // append final separator
++ jv.set(jv.size() - 1, lstitem + delimiter + c);
++ }
++ else
++ {
++ if (!c.equals(delimiter))
++ {
++ jv.add(c);
++ }
++ }
++ }
++ if (jv.size() > 0)
++ {
++ String[] v = jv.toArray(new String[jv.size()]);
++ jv.clear();
++ if (DEBUG)
++ {
++ System.err.println("Array from '" + delimiter
++ + "' separated List:\n" + v.length);
++ for (int i = 0; i < v.length; i++)
++ {
++ System.err.println("item " + i + " '" + v[i] + "'");
++ }
++ }
++ return v;
++ }
++ if (DEBUG)
++ {
++ System.err.println("Empty Array from '" + delimiter
++ + "' separated List");
++ }
++ return null;
++ }
++
++ /**
++ * Returns a string which contains the list elements delimited by the
++ * separator. Null items are ignored. If the input is null or has length zero,
++ * a single delimiter is returned.
++ *
++ * @param list
++ * @param separator
++ * @return concatenated string
++ */
++ public static String arrayToSeparatorList(String[] list, String separator)
++ {
++ StringBuffer v = new StringBuffer();
++ if (list != null && list.length > 0)
++ {
++ for (int i = 0, iSize = list.length; i < iSize; i++)
++ {
++ if (list[i] != null)
++ {
++ if (v.length() > 0)
++ {
++ v.append(separator);
++ }
++ // TODO - escape any separator values in list[i]
++ v.append(list[i]);
++ }
++ }
++ if (DEBUG)
++ {
++ System.err.println("Returning '" + separator
++ + "' separated List:\n");
++ System.err.println(v);
++ }
++ return v.toString();
++ }
++ if (DEBUG)
++ {
++ System.err.println("Returning empty '" + separator
++ + "' separated List\n");
++ }
++ return "" + separator;
++ }
+}
*/
public abstract class InputType
{
++ private static final Pattern URL_PATTERN = Pattern.compile("^([^=]+)=?'?([^']*)?'?");
++
/**
* not used yet
*/
boolean valid = true;
for (String tok : tokenstring)
{
-- Matcher mtch = Pattern.compile("^([^=]+)=?'?([^']*)?'?").matcher(tok);
++ Matcher mtch = URL_PATTERN.matcher(tok);
if (mtch.find())
{
try
*/
package jalview.ws.rest;
--import jalview.datamodel.SequenceI;
--import jalview.io.packed.DataProvider.JvDataType;
--import jalview.ws.rest.params.Alignment;
--import jalview.ws.rest.params.AnnotationFile;
--import jalview.ws.rest.params.SeqGroupIndexVector;
--
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
++import jalview.datamodel.SequenceI;
++import jalview.io.packed.DataProvider.JvDataType;
++import jalview.util.StringUtils;
++import jalview.ws.rest.params.Alignment;
++import jalview.ws.rest.params.AnnotationFile;
++import jalview.ws.rest.params.SeqGroupIndexVector;
++
public class RestServiceDescription
{
++ private static final Pattern PARAM_ENCODED_URL_PATTERN = Pattern.compile("([?&])([A-Za-z0-9_]+)=\\$([^$]+)\\$");
++
/**
* create a new rest service description ready to be configured
*/
return invalidMessage == null;
}
-- private static boolean debug = false;
--
-- /**
-- * parse the string into a list
-- *
-- * @param list
-- * @param separator
-- * @return elements separated by separator
-- */
-- public static String[] separatorListToArray(String list, String separator)
-- {
-- int seplen = separator.length();
-- if (list == null || list.equals("") || list.equals(separator))
- {
-- return null;
- }
-- java.util.ArrayList<String> jv = new ArrayList<String>();
-- int cp = 0, pos, escape;
-- boolean wasescaped = false, wasquoted = false;
-- String lstitem = null;
-- while ((pos = list.indexOf(separator, cp)) >= cp)
-- {
--
-- escape = (pos > 0 && list.charAt(pos - 1) == '\\') ? -1 : 0;
-- if (wasescaped || wasquoted)
-- {
-- // append to previous pos
-- jv.set(jv.size() - 1,
-- lstitem = lstitem + separator
-- + list.substring(cp, pos + escape));
- }
- else
- {
- jv.add(lstitem = list.substring(cp, pos + escape));
- }
- cp = pos + seplen;
- wasescaped = escape == -1;
- // last separator may be in an unmatched quote
- wasquoted = (java.util.regex.Pattern.matches(".*='[^']*(?!')",
- lstitem));
- }
- if (cp < list.length())
- {
- String c = list.substring(cp);
- if (wasescaped || wasquoted)
- {
- // append final separator
- jv.set(jv.size() - 1, lstitem + separator + c);
- }
- else
- {
- if (!c.equals(separator))
- {
- jv.add(c);
- }
- }
- }
- if (jv.size() > 0)
- {
- String[] v = jv.toArray(new String[jv.size()]);
- jv.clear();
- if (debug)
- {
- System.err.println("Array from '" + separator
- + "' separated List:\n" + v.length);
- for (int i = 0; i < v.length; i++)
- {
- System.err.println("item " + i + " '" + v[i] + "'");
- }
- }
- return v;
- }
- if (debug)
- {
- System.err.println("Empty Array from '" + separator
- + "' separated List");
- }
- return null;
- }
--
- /**
- * concatenate the list with separator
- *
- * @param list
- * @param separator
- * @return concatenated string
- */
- public static String arrayToSeparatorList(String[] list, String separator)
- {
- StringBuffer v = new StringBuffer();
- if (list != null && list.length > 0)
- {
- for (int i = 0, iSize = list.length; i < iSize; i++)
- {
- if (list[i] != null)
- {
- if (v.length() > 0)
- {
- v.append(separator);
- }
- // TODO - escape any separator values in list[i]
- v.append(list[i]);
- }
-- }
- if (debug)
- {
- System.err.println("Returning '" + separator
- + "' separated List:\n");
- System.err.println(v);
- }
- return v.toString();
- }
- if (debug)
- {
- System.err.println("Returning empty '" + separator
- + "' separated List\n");
- }
- return "" + separator;
- }
-
- else
- {
- jv.add(lstitem = list.substring(cp, pos + escape));
- }
- cp = pos + seplen;
- wasescaped = escape == -1;
- if (!wasescaped)
- {
- // last separator may be in an unmatched quote
- if (java.util.regex.Pattern.matches("('[^']*')*[^']*'", lstitem))
- {
- wasquoted = true;
- }
- }
-
- }
- if (cp < list.length())
- {
- String c = list.substring(cp);
- if (wasescaped || wasquoted)
- {
- // append final separator
- jv.set(jv.size() - 1, lstitem + separator + c);
- }
- else
- {
- if (!c.equals(separator))
- {
- jv.add(c);
- }
- }
- }
- if (jv.size() > 0)
- {
- String[] v = jv.toArray(new String[jv.size()]);
- jv.clear();
- if (debug)
- {
- System.err.println("Array from '" + separator
- + "' separated List:\n" + v.length);
- for (int i = 0; i < v.length; i++)
- {
- System.err.println("item " + i + " '" + v[i] + "'");
- }
- }
- return v;
- }
- if (debug)
- {
- System.err.println("Empty Array from '" + separator
- + "' separated List");
- }
- return null;
- }
-
- /**
- * concatenate the list with separator
- *
- * @param list
- * @param separator
- * @return concatenated string
- */
- public static String arrayToSeparatorList(String[] list, String separator)
- {
- StringBuffer v = new StringBuffer();
- if (list != null && list.length > 0)
- {
- for (int i = 0, iSize = list.length; i < iSize; i++)
- {
- if (list[i] != null)
- {
- if (v.length() > 0)
- {
- v.append(separator);
- }
- // TODO - escape any separator values in list[i]
- v.append(list[i]);
- }
- }
- if (debug)
- {
- System.err.println("Returning '" + separator
- + "' separated List:\n");
- System.err.println(v);
- }
- return v.toString();
- }
- if (debug)
- {
- System.err.println("Returning empty '" + separator
- + "' separated List\n");
- }
- return "" + separator;
- }
-
/**
* parse a string containing a list of service properties and configure the
* service description
private boolean configureFromServiceInputProperties(String propList,
StringBuffer warnings)
{
-- String[] props = separatorListToArray(propList, ",");
++ String[] props = StringUtils.separatorListToArray(propList, ",");
if (props == null)
{
return true;
;
vls.add(new String("gapCharacter='" + gapCharacter + "'"));
vls.add(new String("returns='" + _genOutputFormatString() + "'"));
-- return arrayToSeparatorList(vls.toArray(new String[0]), ",");
++ return StringUtils.arrayToSeparatorList(vls.toArray(new String[0]), ",");
}
public String toString()
public boolean configureFromEncodedString(String encoding,
StringBuffer warnings)
{
-- String[] list = separatorListToArray(encoding, "|");
++ String[] list = StringUtils.separatorListToArray(encoding, "|");
int nextpos = parseServiceList(list, warnings, 0);
if (nextpos > 0)
url.append("$");
url.append(param.getValue().getURLtokenPrefix());
url.append(":");
-- url.append(arrayToSeparatorList(vals.toArray(new String[0]),
++ url.append(StringUtils.arrayToSeparatorList(vals.toArray(new String[0]),
","));
url.append("$");
}
boolean valid = true;
int lastp = 0;
String url = new String();
-- Matcher prms = Pattern.compile("([?&])([A-Za-z0-9_]+)=\\$([^$]+)\\$")
++ Matcher prms = PARAM_ENCODED_URL_PATTERN
.matcher(ipurl);
Map<String, InputType> iparams = new Hashtable<String, InputType>();
InputType jinput;
if (iprm.equalsIgnoreCase(jinput.getURLtokenPrefix()))
{
ArrayList<String> al = new ArrayList<String>();
-- for (String prprm : separatorListToArray(iprmparams, ","))
++ for (String prprm : StringUtils.separatorListToArray(iprmparams, ","))
{
// hack to ensure that strings like "sep=','" containing unescaped
// commas as values are concatenated
public static List<RestServiceDescription> parseDescriptions(
String services) throws Exception
{
-- String[] list = separatorListToArray(services, "|");
++ String[] list = StringUtils.separatorListToArray(services, "|");
List<RestServiceDescription> svcparsed = new ArrayList<RestServiceDescription>();
int p = 0, lastp = 0;
StringBuffer warnings = new StringBuffer();
assertEquals("zABCDEF", seq.getSequenceAsString());
seq.insertCharAt(2, 2, 'x');
assertEquals("zAxxBCDEF", seq.getSequenceAsString());
-
-
// for static method see StringUtilsTest
}
package jalview.ext.paradise;
import static org.junit.Assert.assertTrue;
--import jalview.datamodel.AlignmentI;
--import jalview.datamodel.SequenceI;
--import jalview.io.FastaFile;
--import jalview.io.FormatAdapter;
import java.io.BufferedReader;
import java.io.File;
import org.junit.Test;
import MCview.PDBfile;
--
import compbio.util.FileUtil;
++import jalview.datamodel.AlignmentI;
++import jalview.datamodel.SequenceI;
++import jalview.io.FastaFile;
++import jalview.io.FormatAdapter;
++
public class TestAnnotate3D
{
sb.append(line + "\n");
}
assertTrue("No data returned by Annotate3D", sb.length() > 0);
-- AlignmentI al = new FormatAdapter().readFile(sb.toString(),
++ final String lines = sb.toString();
++ AlignmentI al = new FormatAdapter().readFile(lines,
FormatAdapter.PASTE, "RNAML");
if (al == null || al.getHeight() == 0)
{
-- System.out.println(sb.toString());
++ System.out.println(lines);
}
assertTrue("No alignment returned.", al != null);
assertTrue("No sequences in returned alignment.", al.getHeight() > 0);
String sq_ = new String(sq.getSequence()).toLowerCase();
for (SequenceI _struseq : pdbf.getSeqsAsArray())
{
-- if (new String(_struseq.getSequence()).toLowerCase().equals(
++ final String lowerCase = new String(_struseq.getSequence()).toLowerCase();
++ if (lowerCase.equals(
sq_))
{
struseq = _struseq;
--- /dev/null
+package jalview.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import jalview.api.AlignViewportI;
+import jalview.datamodel.AlignedCodonFrame;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResults.Match;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceGroup;
+import jalview.gui.AlignViewport;
+import jalview.io.AppletFormatAdapter;
+import jalview.io.FormatAdapter;
+
+import java.awt.Color;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+
+import org.junit.Test;
+
+public class MappingUtilsTest
+{
+ private AlignViewportI dnaView;
+ private AlignViewportI proteinView;
+
+ /**
+ * Simple test of mapping with no intron involved.
+ */
+ @Test
+ public void testBuildSearchResults()
+ {
+ final Sequence seq1 = new Sequence("Seq1", "C-G-TA-GC");
+ seq1.createDatasetSequence();
+
+ final Sequence aseq1 = new Sequence("Seq1", "-P-R");
+ aseq1.createDatasetSequence();
+
+ /*
+ * Map dna bases 1-6 to protein residues 1-2
+ */
+ AlignedCodonFrame acf = new AlignedCodonFrame();
+ MapList map = new MapList(new int[]
+ { 1, 6 }, new int[]
+ { 1, 2 }, 3, 1);
+ acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
+ Set<AlignedCodonFrame> acfList = Collections.singleton(acf);
+
+ /*
+ * Check protein residue 1 maps to codon 1-3, 2 to codon 4-6
+ */
+ SearchResults sr = MappingUtils.buildSearchResults(aseq1, 1, acfList);
+ assertEquals(1, sr.getResults().size());
+ Match m = sr.getResults().get(0);
+ assertEquals(seq1.getDatasetSequence(), m.getSequence());
+ assertEquals(1, m.getStart());
+ assertEquals(3, m.getEnd());
+ sr = MappingUtils.buildSearchResults(aseq1, 2, acfList);
+ assertEquals(1, sr.getResults().size());
+ m = sr.getResults().get(0);
+ assertEquals(seq1.getDatasetSequence(), m.getSequence());
+ assertEquals(4, m.getStart());
+ assertEquals(6, m.getEnd());
+
+ /*
+ * Check inverse mappings, from codons 1-3, 4-6 to protein 1, 2
+ */
+ for (int i = 1; i < 7; i++)
+ {
+ sr = MappingUtils.buildSearchResults(seq1, i, acfList);
+ assertEquals(1, sr.getResults().size());
+ m = sr.getResults().get(0);
+ assertEquals(aseq1.getDatasetSequence(), m.getSequence());
+ int residue = i > 3 ? 2 : 1;
+ assertEquals(residue, m.getStart());
+ assertEquals(residue, m.getEnd());
+ }
+ }
+
+ /**
+ * Simple test of mapping with introns involved.
+ */
+ @Test
+ public void testBuildSearchResults_withIntro()
+ {
+ final Sequence seq1 = new Sequence("Seq1", "C-G-TAGA-GCAGCTT");
+ seq1.createDatasetSequence();
+
+ final Sequence aseq1 = new Sequence("Seq1", "-P-R");
+ aseq1.createDatasetSequence();
+
+ /*
+ * Map dna bases [2, 4, 5], [7, 9, 11] to protein residues 1 and 2
+ */
+ AlignedCodonFrame acf = new AlignedCodonFrame();
+ MapList map = new MapList(new int[]
+ { 2, 2, 4, 5, 7, 7, 9, 9, 11, 11 }, new int[]
+ { 1, 2 }, 3, 1);
+ acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
+ Set<AlignedCodonFrame> acfList = Collections.singleton(acf);
+
+ /*
+ * Check protein residue 1 maps to [2, 4, 5]
+ */
+ SearchResults sr = MappingUtils.buildSearchResults(aseq1, 1, acfList);
+ assertEquals(2, sr.getResults().size());
+ Match m = sr.getResults().get(0);
+ assertEquals(seq1.getDatasetSequence(), m.getSequence());
+ assertEquals(2, m.getStart());
+ assertEquals(2, m.getEnd());
+ m = sr.getResults().get(1);
+ assertEquals(seq1.getDatasetSequence(), m.getSequence());
+ assertEquals(4, m.getStart());
+ assertEquals(5, m.getEnd());
+
+ /*
+ * Check protein residue 2 maps to [7, 9, 11]
+ */
+ sr = MappingUtils.buildSearchResults(aseq1, 2, acfList);
+ assertEquals(3, sr.getResults().size());
+ m = sr.getResults().get(0);
+ assertEquals(seq1.getDatasetSequence(), m.getSequence());
+ assertEquals(7, m.getStart());
+ assertEquals(7, m.getEnd());
+ m = sr.getResults().get(1);
+ assertEquals(seq1.getDatasetSequence(), m.getSequence());
+ assertEquals(9, m.getStart());
+ assertEquals(9, m.getEnd());
+ m = sr.getResults().get(2);
+ assertEquals(seq1.getDatasetSequence(), m.getSequence());
+ assertEquals(11, m.getStart());
+ assertEquals(11, m.getEnd());
+
+ /*
+ * Check inverse mappings, from codons to protein
+ */
+ for (int i = 1; i < 14; i++)
+ {
+ sr = MappingUtils.buildSearchResults(seq1, i, acfList);
+ int residue = (i == 2 || i == 4 || i == 5) ? 1 : (i == 7 || i == 9
+ || i == 11 ? 2 : 0);
+ if (residue == 0)
+ {
+ assertEquals(0, sr.getResults().size());
+ continue;
+ }
+ assertEquals(1, sr.getResults().size());
+ m = sr.getResults().get(0);
+ assertEquals(aseq1.getDatasetSequence(), m.getSequence());
+ assertEquals(residue, m.getStart());
+ assertEquals(residue, m.getEnd());
+ }
+ }
+
+ /**
+ * Test mapping a sequence group.
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testMapSequenceGroup() throws IOException
+ {
+ /*
+ * Set up dna and protein Seq1/2/3 with mappings (held on the protein
+ * viewport).
+ */
+ AlignmentI cdna = loadAlignment(">Seq1\nACG\n>Seq2\nTGA\n>Seq3\nTAC\n",
+ "FASTA");
+ cdna.setDataset(null);
+ AlignmentI protein = loadAlignment(">Seq1\nK\n>Seq2\nL\n>Seq3\nQ\n",
+ "FASTA");
+ protein.setDataset(null);
+ AlignedCodonFrame acf = new AlignedCodonFrame();
+ MapList map = new MapList(new int[]
+ { 1, 3 }, new int[]
+ { 1, 1 }, 3, 1);
+ for (int seq = 0; seq < 3; seq++)
+ {
+ acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(), protein
+ .getSequenceAt(seq).getDatasetSequence(), map);
+ }
+ Set<AlignedCodonFrame> acfList = Collections.singleton(acf);
+
+ AlignViewportI dnaView = new AlignViewport(cdna);
+ AlignViewportI proteinView = new AlignViewport(protein);
+ protein.setCodonFrames(acfList);
+
+ /*
+ * Select Seq1 and Seq3 in the protein
+ */
+ SequenceGroup sg = new SequenceGroup();
+ sg.setColourText(true);
+ sg.setIdColour(Color.GREEN);
+ sg.setOutlineColour(Color.LIGHT_GRAY);
+ sg.addSequence(protein.getSequenceAt(0), false);
+ sg.addSequence(protein.getSequenceAt(2), false);
+
+ /*
+ * Verify the mapped sequence group in dna
+ */
+ SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg, proteinView, dnaView);
+ assertTrue(mappedGroup.getColourText());
+ assertSame(sg.getIdColour(), mappedGroup.getIdColour());
+ assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
+ assertEquals(2, mappedGroup.getSequences().size());
+ assertSame(cdna.getSequenceAt(0), mappedGroup.getSequences().get(0));
+ assertSame(cdna.getSequenceAt(2), mappedGroup.getSequences().get(1));
+
+ /*
+ * Verify mapping sequence group from dna to protein
+ */
+ sg.clear();
+ sg.addSequence(cdna.getSequenceAt(1), false);
+ sg.addSequence(cdna.getSequenceAt(0), false);
+ mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
+ assertTrue(mappedGroup.getColourText());
+ assertSame(sg.getIdColour(), mappedGroup.getIdColour());
+ assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
+ assertEquals(2, mappedGroup.getSequences().size());
+ assertSame(protein.getSequenceAt(1), mappedGroup.getSequences().get(0));
+ assertSame(protein.getSequenceAt(0), mappedGroup.getSequences().get(1));
+ }
+
+ /**
+ * Helper method to load an alignment and ensure dataset sequences are set up.
+ *
+ * @param data
+ * @param format
+ * TODO
+ * @return
+ * @throws IOException
+ */
+ protected AlignmentI loadAlignment(final String data, String format)
+ throws IOException
+ {
+ Alignment a = new FormatAdapter().readFile(data,
+ AppletFormatAdapter.PASTE, format);
+ a.setDataset(null);
+ return a;
+ }
+
+ /**
+ * Test mapping a column selection in protein to its dna equivalent
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testMapColumnSelection_proteinToDna() throws IOException
+ {
+ setupMappedAlignments();
+
+ ColumnSelection colsel = new ColumnSelection();
+
+ /*
+ * 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);
+ 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
+ */
+ colsel.clear();
+ colsel.addElement(1);
+ cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
+ assertEquals("[0, 1, 2, 3]", cs.getSelected().toString());
+
+ /*
+ * Column 2 in protein picks up gaps only - no mapping
+ */
+ colsel.clear();
+ colsel.addElement(2);
+ cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
+ 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
+ */
+ colsel.clear();
+ colsel.addElement(3);
+ cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
+ assertEquals("[5, 6, 7, 8, 9, 10]", cs.getSelected().toString());
+
+ /*
+ * Combine selection of columns 1 and 3 to get a discontiguous mapped
+ * selection
+ */
+ colsel.clear();
+ colsel.addElement(1);
+ colsel.addElement(3);
+ cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
+ assertEquals("[0, 1, 2, 3, 5, 6, 7, 8, 9, 10]", cs.getSelected()
+ .toString());
+ }
+
+ /**
+ * @throws IOException
+ */
+ protected void setupMappedAlignments() throws IOException
+ {
+ /*
+ * Set up dna and protein Seq1/2/3 with mappings (held on the protein
+ * viewport). Lower case for introns.
+ */
+ AlignmentI cdna = loadAlignment(">Seq1\nAC-GctGtC-T\n"
+ + ">Seq2\nTc-GA-G-T-Tc\n" + ">Seq3\nTtTT-AaCGg-\n",
+ "FASTA");
+ cdna.setDataset(null);
+ AlignmentI protein = loadAlignment(
+ ">Seq1\n-K-P\n>Seq2\nL--Q\n>Seq3\nG--S\n",
+ "FASTA");
+ protein.setDataset(null);
+ AlignedCodonFrame acf = new AlignedCodonFrame();
+ MapList map = new MapList(new int[]
+ { 1, 3, 6, 6, 8, 9 }, new int[]
+ { 1, 2 }, 3, 1);
+ acf.addMap(cdna.getSequenceAt(0).getDatasetSequence(), protein
+ .getSequenceAt(0).getDatasetSequence(), map);
+ map = new MapList(new int[]
+ { 1, 1, 3, 4, 5, 7 }, new int[]
+ { 1, 2 }, 3, 1);
+ acf.addMap(cdna.getSequenceAt(1).getDatasetSequence(), protein
+ .getSequenceAt(1).getDatasetSequence(), map);
+ map = new MapList(new int[]
+ { 1, 1, 3, 4, 5, 5, 7, 8 }, new int[]
+ { 1, 2 }, 3, 1);
+ acf.addMap(cdna.getSequenceAt(2).getDatasetSequence(), protein
+ .getSequenceAt(2).getDatasetSequence(), map);
+ Set<AlignedCodonFrame> acfList = Collections.singleton(acf);
+
+ dnaView = new AlignViewport(cdna);
+ proteinView = new AlignViewport(protein);
+ protein.setCodonFrames(acfList);
+ }
+
+ /**
- * Test mapping a column selection including hidden columns
- *
- * @throws IOException
- */
- @Test
- public void testMapColumnSelection_hiddenColumns() throws IOException
- {
- setupMappedAlignments();
-
- ColumnSelection colsel = new ColumnSelection();
-
- /*
- * 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);
- assertEquals("[0, 1, 2, 3, 4]", cs.getSelected().toString());
-
- fail("write me");
- }
-
- /**
+ * Test mapping a column selection in dna to its protein equivalent
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testMapColumnSelection_dnaToProtein() throws IOException
+ {
+ setupMappedAlignments();
+
+ ColumnSelection colsel = new ColumnSelection();
+
+ /*
+ * Column 0 in dna picks up first bases which map to residue 1, columns 0-1
+ * in protein.
+ */
+ colsel.addElement(0);
+ ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, dnaView,
+ proteinView);
+ assertEquals("[0, 1]", cs.getSelected().toString());
+
+ /*
+ * Columns 3-5 in dna map to the first residues in protein Seq1, Seq2, and
+ * the first two in Seq3. Overall to columns 0, 1, 3 (col2 is all gaps).
+ */
+ colsel.addElement(3);
+ colsel.addElement(4);
+ colsel.addElement(5);
+ cs = MappingUtils.mapColumnSelection(colsel, dnaView, proteinView);
+ assertEquals("[0, 1, 3]", cs.getSelected().toString());
+ }
+
+ /**
+ * Tests for the method that converts a series of [start, end] ranges to
+ * single positions
+ */
+ @Test
+ public void testFlattenRanges()
+ {
+ assertEquals("[1, 2, 3, 4]",
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 1, 4 })));
+ assertEquals("[1, 2, 3, 4]",
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 1, 2, 3, 4 })));
+ assertEquals("[1, 2, 3, 4]",
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 1, 1, 2, 2, 3, 3, 4, 4 })));
+ assertEquals("[1, 2, 3, 4, 7, 8, 9, 12]",
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 1, 4, 7, 9, 12, 12 })));
+ // unpaired start position is ignored:
+ assertEquals("[1, 2, 3, 4, 7, 8, 9, 12]",
+ Arrays.toString(MappingUtils.flattenRanges(new int[]
+ { 1, 4, 7, 9, 12, 12, 15 })));
+ }
+}
--- /dev/null
+package jalview.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+public class StringUtilsTest
+{
+
+ @Test
+ public void testInsertCharAt()
+ {
+ char[] c1 = "ABC".toCharArray();
+ char[] expected = new char[]
+ { 'A', 'B', 'C', 'w', 'w' };
+ assertTrue(Arrays.equals(expected,
+ StringUtils.insertCharAt(c1, 3, 2, 'w')));
+ expected = new char[]
+ { 'A', 'B', 'C', 'w', 'w' };
+ assertTrue(Arrays.equals(expected,
+ StringUtils.insertCharAt(c1, 4, 2, 'w')));
+ assertTrue(Arrays.equals(expected,
+ StringUtils.insertCharAt(c1, 5, 2, 'w')));
+ assertTrue(Arrays.equals(expected,
+ StringUtils.insertCharAt(c1, 6, 2, 'w')));
+ assertTrue(Arrays.equals(expected,
+ StringUtils.insertCharAt(c1, 7, 2, 'w')));
+ }
+
+ @Test
+ public void testDeleteChars()
+ {
+ char[] c1 = "ABC".toCharArray();
+
+ // delete second position
+ assertTrue(Arrays.equals(new char[]
+ { 'A', 'C' }, StringUtils.deleteChars(c1, 1, 2)));
+
+ // delete positions 1 and 2
+ assertTrue(Arrays.equals(new char[]
+ { 'C' }, StringUtils.deleteChars(c1, 0, 2)));
+
+ // delete positions 1-3
+ assertTrue(Arrays.equals(new char[]
+ {}, StringUtils.deleteChars(c1, 0, 3)));
+
+ // delete position 3
+ assertTrue(Arrays.equals(new char[]
+ { 'A', 'B' }, StringUtils.deleteChars(c1, 2, 3)));
+
+ // out of range deletion is ignore
+ assertTrue(Arrays.equals(c1, StringUtils.deleteChars(c1, 3, 4)));
+ }
+
+ @Test
+ public void testGetLastToken()
+ {
+ assertNull(StringUtils.getLastToken(null, null));
+ assertNull(StringUtils.getLastToken(null, "/"));
+ assertEquals("a", StringUtils.getLastToken("a", null));
+
+ assertEquals("abc", StringUtils.getLastToken("abc", "/"));
+ assertEquals("c", StringUtils.getLastToken("abc", "b"));
+ assertEquals("file1.dat", StringUtils.getLastToken(
+ "file://localhost:8080/data/examples/file1.dat", "/"));
+ }
++
++ @Test
++ public void testSeparatorListToArray()
++ {
++ String[] result = StringUtils.separatorListToArray(
++ "foo=',',min='foo',max='1,2,3',fa=','", ",");
++ assertEquals("[foo=',', min='foo', max='1,2,3', fa=',']",
++ Arrays.toString(result));
++ /*
++ * Comma nested in '' is not treated as delimiter; tokens are not trimmed
++ */
++ result = StringUtils.separatorListToArray("minsize='2', sep=','", ",");
++ assertEquals("[minsize='2', sep=',']", Arrays.toString(result));
++
++ /*
++ * String delimited by | containing a quoted | (should not be treated as
++ * delimiter)
++ */
++ assertEquals("[abc='|'d, ef, g]", Arrays.toString(StringUtils
++ .separatorListToArray("abc='|'d|ef|g", "|")));
++ }
++
++ @Test
++ public void testArrayToSeparatorList()
++ {
++ assertEquals("*", StringUtils.arrayToSeparatorList(null, "*"));
++ assertEquals("*", StringUtils.arrayToSeparatorList(new String[]
++ {}, "*"));
++ assertEquals("a*bc*cde", StringUtils.arrayToSeparatorList(new String[]
++ { "a", "bc", "cde" }, "*"));
++ assertEquals("a*cde", StringUtils.arrayToSeparatorList(new String[]
++ { "a", null, "cde" }, "*"));
++ assertEquals("a**cde", StringUtils.arrayToSeparatorList(new String[]
++ { "a", "", "cde" }, "*"));
++ // delimiter within token is not (yet) escaped
++ assertEquals("a*b*c*cde", StringUtils.arrayToSeparatorList(new String[]
++ { "a", "b*c", "cde" }, "*"));
++ }
+}
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
--import jalview.datamodel.AlignmentI;
--import jalview.gui.Jalview2XML;
--import jalview.io.AnnotationFile;
--import jalview.io.FormatAdapter;
--import jalview.io.StockholmFileTest;
--import jalview.ws.jws2.JPred301Client;
--import jalview.ws.jws2.JabaParamStore;
--import jalview.ws.jws2.Jws2Discoverer;
--import jalview.ws.jws2.SequenceAnnotationWSClient;
--import jalview.ws.jws2.jabaws2.Jws2Instance;
--import jalview.ws.params.AutoCalcSetting;
import java.awt.Component;
import java.util.ArrayList;
import compbio.metadata.Argument;
import compbio.metadata.WrongParameterException;
++import jalview.datamodel.AlignmentI;
++import jalview.gui.Jalview2XML;
++import jalview.io.AnnotationFile;
++import jalview.io.FormatAdapter;
++import jalview.io.StockholmFileTest;
++import jalview.ws.jws2.JPred301Client;
++import jalview.ws.jws2.JabaParamStore;
++import jalview.ws.jws2.Jws2Discoverer;
++import jalview.ws.jws2.SequenceAnnotationWSClient;
++import jalview.ws.jws2.jabaws2.Jws2Instance;
++import jalview.ws.params.AutoCalcSetting;
++
public class JpredJabaStructExportImport
{
public static String testseqs = "examples/uniref50.fa";
if (jpredws == null)
{
-- System.exit(0);
++ fail("jpredws is null");
}
jalview.io.FileLoader fl = new jalview.io.FileLoader(false);
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
--import jalview.datamodel.AlignmentI;
--import jalview.gui.Jalview2XML;
--import jalview.io.AnnotationFile;
--import jalview.io.FormatAdapter;
--import jalview.io.StockholmFileTest;
--import jalview.ws.jws2.Jws2Discoverer;
--import jalview.ws.jws2.RNAalifoldClient;
--import jalview.ws.jws2.SequenceAnnotationWSClient;
--import jalview.ws.jws2.jabaws2.Jws2Instance;
--import jalview.ws.params.AutoCalcSetting;
import java.awt.Component;
import java.util.ArrayList;
import compbio.metadata.WrongParameterException;
++import jalview.datamodel.AlignmentI;
++import jalview.gui.Jalview2XML;
++import jalview.io.AnnotationFile;
++import jalview.io.FormatAdapter;
++import jalview.io.StockholmFileTest;
++import jalview.ws.jws2.Jws2Discoverer;
++import jalview.ws.jws2.RNAalifoldClient;
++import jalview.ws.jws2.SequenceAnnotationWSClient;
++import jalview.ws.jws2.jabaws2.Jws2Instance;
++import jalview.ws.params.AutoCalcSetting;
++
public class RNAStructExportImport
{
public static String testseqs = "examples/unfolded_RF00031.aln";
if (rnaalifoldws == null)
{
-- System.exit(0);
++ fail("no web service");
}
jalview.io.FileLoader fl = new jalview.io.FileLoader(false);
*/
package jalview.ws.rest;
--import static org.junit.Assert.*;
++import static org.junit.Assert.assertNotNull;
++import static org.junit.Assert.assertTrue;
--import java.io.BufferedReader;
--import java.io.IOException;
--import java.util.ArrayList;
--import java.util.Hashtable;
--import java.util.List;
import java.util.Map;
--import jalview.datamodel.AlignmentI;
--import jalview.datamodel.AlignmentView;
--import jalview.gui.AlignFrame;
--import jalview.io.FileParse;
--import jalview.ws.rest.InputType;
--import jalview.ws.rest.params.SeqGroupIndexVector;
--
--import org.junit.AfterClass;
--import org.junit.BeforeClass;
import org.junit.Test;
++import jalview.gui.AlignFrame;
++import jalview.util.StringUtils;
++
/**
* @author jimp
*
{
@Test
-- public void testSeparatorListToArrayForRestServiceDescriptions()
-- {
-- assertTrue(
-- "separatorListToArray is faulty.",
-- RestServiceDescription.separatorListToArray(
-- "foo=',',min='foo',max='1,2,3',fa=','", ",").length == 4);
-- assertTrue("separatorListToArray is faulty.",
-- RestServiceDescription.separatorListToArray(
-- "minsize='2', sep=','", ",").length != 2); // probably
-- // should come as
-- // 2
-- }
--
-- @Test
public void testShmmrService()
{
*/
package jalview.ws.seqfetcher;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
- import jalview.analysis.CrossRef;
- import jalview.datamodel.AlignmentI;
- import jalview.datamodel.DBRefEntry;
- import jalview.datamodel.DBRefSource;
- import jalview.util.DBRefUtils;
- import jalview.ws.SequenceFetcher;
import java.util.ArrayList;
import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
++import jalview.analysis.CrossRef;
++import jalview.datamodel.AlignmentI;
++import jalview.datamodel.DBRefEntry;
++import jalview.datamodel.DBRefSource;
++import jalview.util.DBRefUtils;
++import jalview.ws.SequenceFetcher;
++
/**
* @author jimp
*