update_viewer.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:53k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: update_viewer.cpp,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/01 18:29:49  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.73
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: update_viewer.cpp,v 1000.3 2004/06/01 18:29:49 gouriano Exp $
  10. * ===========================================================================
  11. *
  12. *                            PUBLIC DOMAIN NOTICE
  13. *               National Center for Biotechnology Information
  14. *
  15. *  This software/database is a "United States Government Work" under the
  16. *  terms of the United States Copyright Act.  It was written as part of
  17. *  the author's official duties as a United States Government employee and
  18. *  thus cannot be copyrighted.  This software/database is freely available
  19. *  to the public for use. The National Library of Medicine and the U.S.
  20. *  Government have not placed any restriction on its use or reproduction.
  21. *
  22. *  Although all reasonable efforts have been taken to ensure the accuracy
  23. *  and reliability of the software and data, the NLM and the U.S.
  24. *  Government do not and cannot warrant the performance or results that
  25. *  may be obtained by using this software or data. The NLM and the U.S.
  26. *  Government disclaim all warranties, express or implied, including
  27. *  warranties of performance, merchantability or fitness for any particular
  28. *  purpose.
  29. *
  30. *  Please cite the author in any work or product based on this material.
  31. *
  32. * ===========================================================================
  33. *
  34. * Authors:  Paul Thiessen
  35. *
  36. * File Description:
  37. *      implementation of non-GUI part of update viewer
  38. *
  39. * ===========================================================================
  40. */
  41. #ifdef _MSC_VER
  42. #pragma warning(disable:4018)   // disable signed/unsigned mismatch warning in MSVC
  43. #endif
  44. #include <ncbi_pch.hpp>
  45. #include <corelib/ncbistd.hpp>
  46. #include <corelib/ncbistl.hpp>
  47. #include <objects/cdd/Cdd.hpp>
  48. #include <objects/cdd/Update_align.hpp>
  49. #include <objects/cdd/Update_comment.hpp>
  50. #include <objects/seq/Seq_annot.hpp>
  51. #include <objects/seq/Bioseq.hpp>
  52. #include <objects/seqset/Seq_entry.hpp>
  53. #include <objects/seqset/Bioseq_set.hpp>
  54. #include <objects/ncbimime/Ncbi_mime_asn1.hpp>
  55. #include <objects/ncbimime/Biostruc_seq.hpp>
  56. #include <objects/mmdb2/Model_type.hpp>
  57. #include <objects/mmdb2/Biostruc_model.hpp>
  58. #include <objects/mmdb1/Biostruc_graph.hpp>
  59. #include <objects/mmdb1/Biostruc_descr.hpp>
  60. #include <objects/general/Dbtag.hpp>
  61. #include <objects/general/Object_id.hpp>
  62. #include <objects/mmdb1/Biostruc_id.hpp>
  63. #include <objects/mmdb1/Mmdb_id.hpp>
  64. #include <objects/mmdb1/Biostruc_annot_set.hpp>
  65. #include <objects/mmdb3/Biostruc_feature_set.hpp>
  66. #include <objects/mmdb3/Chem_graph_alignment.hpp>
  67. #include <objects/mmdb3/Chem_graph_pntrs.hpp>
  68. #include <objects/mmdb3/Residue_pntrs.hpp>
  69. #include <objects/mmdb3/Residue_interval_pntr.hpp>
  70. #include <objects/mmdb1/Molecule_id.hpp>
  71. #include <objects/mmdb1/Residue_id.hpp>
  72. #include <objects/mmdb3/Biostruc_feature_set_id.hpp>
  73. #include <objects/mmdb3/Biostruc_feature_id.hpp>
  74. #include <memory>
  75. #include <algorithm>
  76. #include "update_viewer.hpp"
  77. #include "asn_reader.hpp"
  78. #include "update_viewer_window.hpp"
  79. #include "messenger.hpp"
  80. #include "sequence_display.hpp"
  81. #include "cn3d_colors.hpp"
  82. #include "alignment_manager.hpp"
  83. #include "cn3d_threader.hpp"
  84. #include "structure_set.hpp"
  85. #include "molecule.hpp"
  86. #include "cn3d_tools.hpp"
  87. #include "asn_converter.hpp"
  88. #include "cn3d_blast.hpp"
  89. #include "molecule_identifier.hpp"
  90. #include "cn3d_cache.hpp"
  91. #include "cn3d_ba_interface.hpp"
  92. #include <wx/tokenzr.h>
  93. // C stuff
  94. #include <stdio.h>
  95. #include <tofasta.h>
  96. #include <objseq.h>
  97. #include <objsset.h>
  98. USING_NCBI_SCOPE;
  99. USING_SCOPE(objects);
  100. BEGIN_SCOPE(Cn3D)
  101. UpdateViewer::UpdateViewer(AlignmentManager *alnMgr) :
  102.     // not sure why this cast is necessary, but MSVC requires it...
  103.     ViewerBase(reinterpret_cast<ViewerWindowBase**>(&updateWindow), alnMgr),
  104.     updateWindow(NULL)
  105. {
  106.     // when first created, start with blank display
  107.     AlignmentList emptyAlignmentList;
  108.     SequenceDisplay *blankDisplay = new SequenceDisplay(true, viewerWindow);
  109.     InitData(&emptyAlignmentList, blankDisplay);
  110.     EnableStacks();
  111. }
  112. UpdateViewer::~UpdateViewer(void)
  113. {
  114. }
  115. void UpdateViewer::SetInitialState(void)
  116. {
  117.     KeepCurrent();
  118.     EnableStacks();
  119. }
  120. void UpdateViewer::SaveDialog(bool prompt)
  121. {
  122.     if (updateWindow) updateWindow->SaveDialog(prompt, false);
  123. }
  124. void UpdateViewer::CreateUpdateWindow(void)
  125. {
  126.     if (updateWindow) {
  127.         updateWindow->Show(true);
  128.         GlobalMessenger()->PostRedrawSequenceViewer(this);
  129.     } else {
  130.         SequenceDisplay *display = GetCurrentDisplay();
  131.         if (display) {
  132.             updateWindow = new UpdateViewerWindow(this);
  133.             updateWindow->NewDisplay(display, false);
  134.             updateWindow->ScrollToColumn(display->GetStartingColumn());
  135.             updateWindow->Show(true);
  136.             // ScrollTo causes immediate redraw, so don't need a second one
  137.             GlobalMessenger()->UnPostRedrawSequenceViewer(this);
  138.         }
  139.     }
  140. }
  141. void UpdateViewer::AddAlignments(const AlignmentList& newAlignments)
  142. {
  143.     AlignmentList& alignments = GetCurrentAlignments();
  144.     SequenceDisplay *display = GetCurrentDisplay();
  145.     // populate successive lines of the display with each alignment, with blank lines inbetween
  146.     AlignmentList::const_iterator a, ae = newAlignments.end();
  147.     int nViolations = 0;
  148.     for (a=newAlignments.begin(); a!=ae; ++a) {
  149.         if ((*a)->NRows() != 2) {
  150.             ERRORMSG("UpdateViewer::AddAlignments() - got alignment with "
  151.                 << (*a)->NRows() << " rows");
  152.             continue;
  153.         }
  154.         // add alignment to stack list
  155.         alignments.push_back(*a);
  156.         // add alignment to the display, including block row since editor is always on
  157.         if (display->NRows() != 0) display->AddRowFromString("");
  158.         display->AddBlockBoundaryRow(*a);
  159.         for (int row=0; row<2; ++row)
  160.             display->AddRowFromAlignment(row, *a);
  161.     }
  162.     if (alignments.size() > 0)
  163.         display->SetStartingColumn(alignments.front()->GetFirstAlignedBlockPosition() - 5);
  164.     Save();    // make this an undoable operation
  165. if (updateWindow) updateWindow->UpdateDisplay(display);
  166. }
  167. void UpdateViewer::ReplaceAlignments(const AlignmentList& alignmentList)
  168. {
  169.     // empty out the current alignment list and display (but not the undo stacks!)
  170.     DELETE_ALL_AND_CLEAR(GetCurrentAlignments(), AlignmentList);
  171.     GetCurrentDisplay()->Empty();
  172.     AddAlignments(alignmentList);
  173. }
  174. void UpdateViewer::DeleteAlignment(BlockMultipleAlignment *toDelete)
  175. {
  176.     AlignmentList keepAlignments;
  177.     AlignmentList::const_iterator a, ae = GetCurrentAlignments().end();
  178.     for (a=GetCurrentAlignments().begin(); a!=ae; ++a)
  179.         if (*a != toDelete)
  180.             keepAlignments.push_back((*a)->Clone());
  181.     ReplaceAlignments(keepAlignments);
  182. }
  183. void UpdateViewer::SaveAlignments(void)
  184. {
  185.     SetInitialState();
  186.     // construct a new list of ASN Update-aligns
  187.     CCdd::TPending updates;
  188.     map < CUpdate_align * , bool > usedUpdateAligns;
  189.     AlignmentList::const_iterator a, ae = GetCurrentAlignments().end();
  190.     for (a=GetCurrentAlignments().begin(); a!=ae; ++a) {
  191.         // create a Seq-align (with Dense-diags) out of this update
  192.         if ((*a)->NRows() != 2) {
  193.             ERRORMSG("CreateSeqAlignFromUpdate() - can only save pairwise updates");
  194.             continue;
  195.         }
  196.         BlockMultipleAlignment::UngappedAlignedBlockList blocks;
  197.         (*a)->GetUngappedAlignedBlocks(&blocks);
  198.         CSeq_align *newSeqAlign = CreatePairwiseSeqAlignFromMultipleRow(*a, blocks, 1);
  199.         if (!newSeqAlign) continue;
  200.         // the Update-align and Seq-annot's list of Seq-aligns where this new Seq-align will go
  201.         CUpdate_align *updateAlign = (*a)->updateOrigin.GetPointer();
  202.         CSeq_annot::C_Data::TAlign *seqAlignList = NULL;
  203.         // if this alignment came from an existing Update-align, then replace just the Seq-align
  204.         // so that the rest of the Update-align's comments/annotations are preserved
  205.         if (updateAlign) {
  206.             if (!updateAlign->IsSetSeqannot() || !updateAlign->GetSeqannot().GetData().IsAlign()) {
  207.                 ERRORMSG("UpdateViewer::SaveAlignments() - confused by Update-align format");
  208.                 continue;
  209.             }
  210.         }
  211.         // if this is a new update, create a new Update-align and tag it
  212.         else {
  213.             updateAlign = new CUpdate_align();
  214.             // set type field depending on whether demoted sequence has structure
  215.             updateAlign->SetType((*a)->GetSequenceOfRow(1)->molecule ?
  216.                 CUpdate_align::eType_demoted_3d : CUpdate_align::eType_demoted);
  217.             // add a text comment
  218.             CUpdate_comment *comment = new CUpdate_comment();
  219.             comment->SetComment("Created by demotion or import in Cn3D 4.0");
  220.             updateAlign->SetDescription().resize(updateAlign->GetDescription().size() + 1);
  221.             updateAlign->SetDescription().back().Reset(comment);
  222.             // create a new Seq-annot
  223.             CRef < CSeq_annot > seqAnnotRef(new CSeq_annot());
  224.             seqAnnotRef->SetData().SetAlign();
  225.             updateAlign->SetSeqannot(*seqAnnotRef);
  226.         }
  227.         // get Seq-align list
  228.         if (!updateAlign || !(seqAlignList = &(updateAlign->SetSeqannot().SetData().SetAlign()))) {
  229.             ERRORMSG("UpdateViewer::SaveAlignments() - can't find Update-align and/or Seq-align list");
  230.             continue;
  231.         }
  232.         // if this is the first re-use of this Update-align, then empty out all existing
  233.         // Seq-aligns and push it onto the new update list
  234.         if (usedUpdateAligns.find(updateAlign) == usedUpdateAligns.end()) {
  235.             seqAlignList->clear();
  236.             updates.resize(updates.size() + 1);
  237.             updates.back().Reset(updateAlign);
  238.             usedUpdateAligns[updateAlign] = true;
  239.         }
  240.         // finally, add the new Seq-align to the list
  241.         seqAlignList->resize(seqAlignList->size() + 1);
  242.         seqAlignList->back().Reset(newSeqAlign);
  243.     }
  244.     // save these changes to the ASN data
  245.     alignmentManager->ReplaceUpdatesInASN(updates);
  246. }
  247. const Sequence * UpdateViewer::GetMasterSequence(void) const
  248. {
  249.     const Sequence *master = NULL;
  250.     // if there's a multiple alignment in the sequence viewer, use same master as that
  251.     if (alignmentManager->GetCurrentMultipleAlignment()) {
  252.         master = alignmentManager->GetCurrentMultipleAlignment()->GetMaster();
  253.     }
  254.     // if there's already an update present, use same master as that
  255.     else if (GetCurrentAlignments().size() > 0) {
  256.         master = GetCurrentAlignments().front()->GetMaster();
  257.     }
  258.     // otherwise, this must be a single structure with no updates, so we need to pick one of its
  259.     // chains as the new master
  260.     else {
  261.         vector < const Sequence * > chains;
  262.         if (alignmentManager->GetStructureProteins(&chains)) {
  263.             if (chains.size() == 1) {
  264.                 master = chains[0];
  265.             } else {
  266.                 wxString *titles = new wxString[chains.size()];
  267.                 int choice;
  268.                 for (choice=0; choice<chains.size(); ++choice)
  269.                     titles[choice] = chains[choice]->identifier->ToString().c_str();
  270.                 choice = wxGetSingleChoiceIndex("Align to which protein chain?",
  271.                     "Select Chain", chains.size(), titles);
  272.                 if (choice >= 0)
  273.                     master = chains[choice];
  274.                 else    // cancelled
  275.                     return NULL;
  276.             }
  277.         }
  278.     }
  279.     if (!master)
  280.         ERRORMSG("UpdateViewer::GetMasterSequence() - no master sequence defined");
  281.     return master;
  282. }
  283. void UpdateViewer::FetchSequencesViaHTTP(SequenceList *newSequences, StructureSet *sSet) const
  284. {
  285.     wxString ids =
  286.         wxGetTextFromUser("Enter a list of protein GIs or Accessions:",
  287.             "Input Identifier", "", *viewerWindow);
  288.     if (ids.size() == 0) return;
  289.     wxStringTokenizer tkz(ids, " ,;trn", wxTOKEN_STRTOK);
  290.     while (tkz.HasMoreTokens()) {
  291.         wxString id = tkz.GetNextToken();
  292.         CRef < CBioseq > bioseq = FetchSequenceViaHTTP(id.c_str());
  293.         const Sequence *sequence = sSet->CreateNewSequence(*bioseq);
  294.         if (sequence) {
  295.             if (sequence->isProtein)
  296.                 newSequences->push_back(sequence);
  297.             else
  298.                 ERRORMSG("The sequence must be a protein");
  299.         }
  300.     }
  301. }
  302. void UpdateViewer::ReadSequencesFromFile(SequenceList *newSequences, StructureSet *sSet) const
  303. {
  304.     newSequences->clear();
  305.     wxString fastaFile = wxFileSelector("Choose a FASTA file from which to import",
  306.         "", "", "", "*.*", wxOPEN | wxFILE_MUST_EXIST, *viewerWindow);
  307.     if (fastaFile.size() > 0) {
  308.         FILE *fp = FileOpen(fastaFile.c_str(), "r");
  309.         if (fp) {
  310.             SeqEntry *sep = NULL;
  311.             string err;
  312.             while ((sep=FastaToSeqEntry(fp, FALSE)) != NULL) {
  313.                 // convert C to C++ SeqEntry
  314.                 CSeq_entry se;
  315.                 if (!ConvertAsnFromCToCPP(sep, (AsnWriteFunc) SeqEntryAsnWrite, &se, &err)) {
  316.                     ERRORMSG("UpdateViewer::ImportSequence() - error converting to C++ object: "
  317.                         << err);
  318.                 } else {
  319.                     // create Sequence - just one from each Seq-entry for now
  320.                     if (se.IsSeq()) {
  321.                         const Sequence *sequence = sSet->CreateNewSequence(se.SetSeq());
  322.                         if (sequence)
  323.                             newSequences->push_back(sequence);
  324.                     } else {
  325.                         ERRORMSG("FastaToSeqEntry() returned Bioseq-set in Seq-entry");
  326.                     }
  327.                 }
  328.                 SeqEntryFree(sep);
  329.             }
  330.             FileClose(fp);
  331.         } else
  332.             ERRORMSG("Unable to open " << fastaFile.c_str());
  333.     }
  334. }
  335. static BlockMultipleAlignment * MakeEmptyAlignment(const Sequence *master, const Sequence *slave)
  336. {
  337.     BlockMultipleAlignment::SequenceList *seqs = new BlockMultipleAlignment::SequenceList(2);
  338.     (*seqs)[0] = master;
  339.     (*seqs)[1] = slave;
  340.     BlockMultipleAlignment *newAlignment =
  341.         new BlockMultipleAlignment(seqs, master->parentSet->alignmentManager);
  342.     if (!newAlignment->AddUnalignedBlocks() || !newAlignment->UpdateBlockMapAndColors(false)) {
  343.         ERRORMSG("MakeEmptyAlignment() - error finalizing alignment");
  344.         delete newAlignment;
  345.         return NULL;
  346.     }
  347.     return newAlignment;
  348. }
  349. void UpdateViewer::MakeEmptyAlignments(const SequenceList& newSequences,
  350.     const Sequence *master, AlignmentList *newAlignments) const
  351. {
  352.     newAlignments->clear();
  353.     SequenceList::const_iterator s, se = newSequences.end();
  354.     for (s=newSequences.begin(); s!=se; ++s) {
  355.         BlockMultipleAlignment *newAlignment = MakeEmptyAlignment(master, *s);
  356.         if (newAlignment) newAlignments->push_back(newAlignment);
  357.     }
  358. }
  359. void UpdateViewer::FetchSequences(StructureSet *sSet, SequenceList *newSequences) const
  360. {
  361.     // choose import type
  362.     static const wxString choiceStrings[] = { "Network via GI/Accession", "From a FASTA File" };
  363.     enum choiceValues { FROM_GI=0, FROM_FASTA, N_CHOICES };
  364.     int importFrom = wxGetSingleChoiceIndex("From what source would you like to import sequences?",
  365.         "Select Import Source", N_CHOICES, choiceStrings, *viewerWindow);
  366.     if (importFrom < 0) return;     // cancelled
  367.     // network import
  368.     if (importFrom == FROM_GI)
  369.         FetchSequencesViaHTTP(newSequences, sSet);
  370.     // FASTA import
  371.     else if (importFrom == FROM_FASTA)
  372.         ReadSequencesFromFile(newSequences, sSet);
  373. }
  374. void UpdateViewer::ImportSequences(void)
  375. {
  376.     // determine the master sequence for new alignments
  377.     const Sequence *master = GetMasterSequence();
  378.     if (!master) return;
  379.     // import the new sequence(s)
  380.     SequenceList newSequences;
  381.     FetchSequences(master->parentSet, &newSequences);
  382.     if (newSequences.size() == 0) {
  383.         WARNINGMSG("UpdateViewer::ImportSequence() - no sequences were imported");
  384.         return;
  385.     }
  386.     // create null-alignments for each sequence
  387.     AlignmentList newAlignments;
  388.     MakeEmptyAlignments(newSequences, master, &newAlignments);
  389.     // add new alignments to update list
  390.     if (newAlignments.size() > 0)
  391.         AddAlignments(newAlignments);
  392.     else
  393.         ERRORMSG("UpdateViewer::ImportSequence() - no new alignments were created");
  394. }
  395. void UpdateViewer::GetVASTAlignments(const SequenceList& newSequences,
  396.     const Sequence *master, AlignmentList *newAlignments,
  397.     PendingStructureAlignments *structureAlignments,
  398.     int masterFrom, int masterTo) const
  399. {
  400.     if (master->identifier->pdbID.size() == 0) {
  401.         WARNINGMSG("UpdateViewer::GetVASTAlignments() - "
  402.             "can't be called with non-MMDB master " << master->identifier->ToString());
  403.         return;
  404.     }
  405.     SequenceList::const_iterator s, se = newSequences.end();
  406.     for (s=newSequences.begin(); s!=se; ++s) {
  407.         if ((*s)->identifier->pdbID.size() == 0) {
  408.             WARNINGMSG("UpdateViewer::GetVASTAlignments() - "
  409.                 "can't be called with non-MMDB slave " << (*s)->identifier->ToString());
  410.             BlockMultipleAlignment *newAlignment = MakeEmptyAlignment(master, *s);
  411.             if (newAlignment) newAlignments->push_back(newAlignment);
  412.             continue;
  413.         }
  414.         // set up URL
  415.         string
  416.             host = "www.ncbi.nlm.nih.gov",
  417.             path = "/Structure/VA/vastalign.cgi", err;
  418.         CNcbiOstrstream argstr;
  419.         argstr << "master=" << master->identifier->ToString()
  420.             << "&slave=" << (*s)->identifier->ToString();
  421.         if (masterFrom >= 0 && masterTo >= 0 && masterFrom <= masterTo &&
  422.             masterFrom < master->Length() && masterTo < master->Length())
  423.             argstr << "&from=" << (masterFrom+1) << "&to=" << (masterTo+1); // URL #'s are 1-based
  424.         argstr << '';
  425.         auto_ptr<char> args(argstr.str());
  426.         // connect to vastalign.cgi
  427.         CBiostruc_annot_set structureAlignment;
  428.         INFOMSG("trying to load VAST alignment data from " << host << path << '?' << args.get());
  429.         if (!GetAsnDataViaHTTP(host, path, args.get(), &structureAlignment, &err)) {
  430.             ERRORMSG("Error calling vastalign.cgi: " << err);
  431.             BlockMultipleAlignment *newAlignment = MakeEmptyAlignment(master, *s);
  432.             if (newAlignment) newAlignments->push_back(newAlignment);
  433.             continue;
  434.         }
  435.         INFOMSG("successfully loaded data from vastalign.cgi");
  436. #ifdef _DEBUG
  437.         WriteASNToFile("vastalign.dat.txt", structureAlignment, false, &err);
  438. #endif
  439.         // create initially empty alignment
  440.         BlockMultipleAlignment::SequenceList *seqs = new BlockMultipleAlignment::SequenceList(2);
  441.         (*seqs)[0] = master;
  442.         (*seqs)[1] = *s;
  443.         BlockMultipleAlignment *newAlignment =
  444.             new BlockMultipleAlignment(seqs, master->parentSet->alignmentManager);
  445.         // skip if no VAST alignment found
  446.         if (structureAlignment.IsSetId() && structureAlignment.GetId().front()->IsMmdb_id() &&
  447.             structureAlignment.GetId().front()->GetMmdb_id().Get() == 0)
  448.         {
  449.             WARNINGMSG("VAST found no alignment for these chains");
  450.         }
  451.         else try {
  452.             if (!structureAlignment.IsSetId() || !structureAlignment.GetId().front()->IsMmdb_id() ||
  453.                 structureAlignment.GetFeatures().size() != 1 ||
  454.                 structureAlignment.GetFeatures().front()->GetFeatures().size() != 1 ||
  455.                 !structureAlignment.GetFeatures().front()->GetFeatures().front()->IsSetLocation() ||
  456.                 !structureAlignment.GetFeatures().front()->GetFeatures().front()->GetLocation().IsAlignment())
  457.             {
  458.                 throw "VAST data does not contain exactly one alignment of recognized format - "
  459.                     "possibly a problem with vastalign.cgi";
  460.             }
  461.             if (structureAlignment.GetId().front()->GetMmdb_id().Get() != master->identifier->mmdbID)
  462.                 throw "Master structure MMDB ID mismatch - check to see if this structure been updated";
  463.             // load in alignment, check format
  464.             const CChem_graph_alignment& alignment =
  465.                 structureAlignment.GetFeatures().front()->GetFeatures().front()->GetLocation().GetAlignment();
  466.             if (alignment.GetDimension() != 2 || alignment.GetAlignment().size() != 2 ||
  467.                 alignment.GetBiostruc_ids().size() != 2 ||
  468.                 !alignment.GetBiostruc_ids().front()->IsMmdb_id() ||
  469.                 alignment.GetBiostruc_ids().front()->GetMmdb_id().Get() != master->identifier->mmdbID ||
  470.                 !alignment.GetBiostruc_ids().back()->IsMmdb_id() ||
  471.                 alignment.GetBiostruc_ids().back()->GetMmdb_id().Get() != (*s)->identifier->mmdbID ||
  472.                 !alignment.GetAlignment().front()->IsResidues() ||
  473.                 !alignment.GetAlignment().front()->GetResidues().IsInterval() ||
  474.                 !alignment.GetAlignment().back()->IsResidues() ||
  475.                 !alignment.GetAlignment().back()->GetResidues().IsInterval() ||
  476.                 alignment.GetAlignment().front()->GetResidues().GetInterval().size() !=
  477.                     alignment.GetAlignment().back()->GetResidues().GetInterval().size())
  478.             {
  479.                 throw "Unrecognized VAST data format";
  480.             }
  481.             // construct alignment from residue intervals
  482.             CResidue_pntrs::TInterval::const_iterator i, j,
  483.                 ie = alignment.GetAlignment().front()->GetResidues().GetInterval().end();
  484.             for (i=alignment.GetAlignment().front()->GetResidues().GetInterval().begin(),
  485.                  j=alignment.GetAlignment().back()->GetResidues().GetInterval().begin(); i!=ie; ++i, ++j)
  486.             {
  487.                 if ((*i)->GetMolecule_id().Get() != master->identifier->moleculeID ||
  488.                     (*j)->GetMolecule_id().Get() != (*s)->identifier->moleculeID)
  489.                 {
  490.                     throw "Mismatch in molecule ids in alignment interval block";
  491.                 }
  492.                 UngappedAlignedBlock *newBlock = new UngappedAlignedBlock(newAlignment);
  493.                 newBlock->SetRangeOfRow(0, (*i)->GetFrom().Get() - 1, (*i)->GetTo().Get() - 1);
  494.                 newBlock->SetRangeOfRow(1, (*j)->GetFrom().Get() - 1, (*j)->GetTo().Get() - 1);
  495.                 newBlock->width = (*i)->GetTo().Get() - (*i)->GetFrom().Get() + 1;
  496.                 newAlignment->AddAlignedBlockAtEnd(newBlock);
  497.             }
  498.             // add structure alignment to list
  499.             if (alignment.GetTransform().size() == 1)
  500.             {
  501.                 structureAlignments->resize(structureAlignments->size() + 1);
  502.                 structureAlignments->back().structureAlignment =
  503.                     structureAlignment.SetFeatures().front()->SetFeatures().front();
  504.                 structureAlignments->back().masterDomainID =
  505.                     structureAlignment.GetFeatures().front()->GetId().Get();
  506.                 structureAlignments->back().slaveDomainID =
  507.                     structureAlignment.GetFeatures().front()->GetFeatures().front()->GetId().Get();
  508.             } else
  509.                 throw "No structure alignment in VAST data blob";
  510.         } catch (const char *err) {
  511.             ERRORMSG("Failed to import VAST alignment: " << err);
  512.         }
  513.         // finalize alignment
  514.         if (!newAlignment->AddUnalignedBlocks() || !newAlignment->UpdateBlockMapAndColors(false)) {
  515.             ERRORMSG("MakeEmptyAlignment() - error finalizing alignment");
  516.             delete newAlignment;
  517.             continue;
  518.         }
  519.         newAlignments->push_back(newAlignment);
  520.     }
  521. }
  522. void UpdateViewer::ImportStructure(void)
  523. {
  524.     // determine the master sequence for new alignments
  525.     const Sequence *master = GetMasterSequence();
  526.     if (!master) return;
  527.     if (!master->molecule) {
  528.         ERRORMSG("Can't import another structure unless master sequence has structure");
  529.         return;
  530.     }
  531.     if (master->parentSet->objects.size() == 1 && master->parentSet->frameMap.size() != 1) {
  532.         ERRORMSG("Can't import another structure when current structure has multiple models");
  533.         return;
  534.     }
  535.     // choose import type for structure
  536.     static const wxString choiceStrings[] = { "Via Network", "From a File" };
  537.     enum choiceValues { FROM_NETWORK=0, FROM_FILE, N_CHOICES };
  538.     int importFrom = wxGetSingleChoiceIndex(
  539.         "From what source would you like to import the structure?", "Select Import Source",
  540.         N_CHOICES, choiceStrings, *viewerWindow);
  541.     if (importFrom < 0) return;     // cancelled
  542.     CRef < CBiostruc > biostruc;
  543.     BioseqRefList bioseqs;
  544.     if (importFrom == FROM_NETWORK) {
  545.         wxString id = wxGetTextFromUser("Enter a PDB or MMDB ID:", "Input Identifier", "", *viewerWindow);
  546.         biostruc.Reset(new CBiostruc());
  547.         if (!LoadStructureViaCache(id.c_str(),
  548.                 (master->parentSet->isAlphaOnly ? eModel_type_ncbi_backbone : eModel_type_ncbi_all_atom),
  549.                 biostruc, &bioseqs)) {
  550.             ERRORMSG("Failed to load structure " << id.c_str());
  551.             return;
  552.         }
  553.     }
  554.     else if (importFrom == FROM_FILE) {
  555.         string filename = wxFileSelector("Choose a single-structure file:",
  556.             GetUserDir().c_str(), "", "", "*.*", wxOPEN | wxFILE_MUST_EXIST, *viewerWindow).c_str();
  557.         if (filename.size() == 0) return;
  558.         bool readOK = false;
  559.         string err;
  560.         TRACEMSG("trying to read file '" << filename << "' as binary mime");
  561.         CRef < CNcbi_mime_asn1 > mime(new CNcbi_mime_asn1());
  562.         SetDiagPostLevel(eDiag_Fatal); // ignore all but Fatal errors while reading data
  563.         readOK = ReadASNFromFile(filename.c_str(), mime.GetPointer(), true, &err);
  564.         SetDiagPostLevel(eDiag_Info);
  565.         if (!readOK) {
  566.             TRACEMSG("error: " << err);
  567.             TRACEMSG("trying to read file '" << filename << "' as ascii mime");
  568.             mime.Reset(new CNcbi_mime_asn1());
  569.             SetDiagPostLevel(eDiag_Fatal); // ignore all but Fatal errors while reading data
  570.             readOK = ReadASNFromFile(filename.c_str(), mime.GetPointer(), false, &err);
  571.             SetDiagPostLevel(eDiag_Info);
  572.         }
  573.         if (!readOK) {
  574.             TRACEMSG("error: " << err);
  575.             ERRORMSG("Couldn't read structure from " << filename);
  576.             return;
  577.         }
  578.         ExtractBiostrucAndBioseqs(*mime, biostruc, &bioseqs);
  579.     }
  580.     int mmdbID;
  581.     if (biostruc->GetId().size() == 0 || !biostruc->GetId().front()->IsMmdb_id()) {
  582.         ERRORMSG("Can't get MMDB ID from loaded structure");
  583.         return;
  584.     }
  585.     mmdbID = biostruc->GetId().front()->GetMmdb_id().Get();
  586.     // make sure Biostruc is of correct type
  587.     if (biostruc->GetModel().size() != 1 ||
  588.         (master->parentSet->isAlphaOnly &&
  589.             biostruc->GetModel().front()->GetType() != eModel_type_ncbi_backbone) ||
  590.         (!master->parentSet->isAlphaOnly &&
  591.             biostruc->GetModel().front()->GetType() != eModel_type_ncbi_all_atom)) {
  592.         ERRORMSG("Biostruc does not match current data - should be "
  593.             << (master->parentSet->isAlphaOnly ? "alpha-only" : "one-coordinate-per-atom") << " model");
  594.         return;
  595.     }
  596.     // make list of protein chains in this structure
  597.     vector < pair < const CSeq_id * , char > > chains;  // holds Seq-id and chain name
  598.     map < const CSeq_id * , int > moleculeIDs;          // maps Seq-id -> molecule ID within MMDB object
  599.     CBiostruc_graph::TDescr::const_iterator d, de;
  600.     CBiostruc_graph::TMolecule_graphs::const_iterator
  601.         m, me = biostruc->GetChemical_graph().GetMolecule_graphs().end();
  602.     for (m=biostruc->GetChemical_graph().GetMolecule_graphs().begin(); m!=me; ++m) {
  603.         bool isProtein = false;
  604.         const CSeq_id *sid = NULL;
  605.         char name = 0;
  606.         // check descr for chain name/type
  607.         de = (*m)->GetDescr().end();
  608.         for (d=(*m)->GetDescr().begin(); d!=de; ++d) {
  609.             if ((*d)->IsName())
  610.                 name = (*d)->GetName()[0];
  611.             else if ((*d)->IsMolecule_type() &&
  612.                      (*d)->GetMolecule_type() == CBiomol_descr::eMolecule_type_protein)
  613.                 isProtein = true;
  614.             if (isProtein && name) break;
  615.         }
  616.         // get gi
  617.         if ((*m)->IsSetSeq_id())
  618.             sid = &((*m)->GetSeq_id());
  619.         // add protein to list
  620.         if (isProtein && name && sid != NULL) {
  621.             moleculeIDs[sid] = (*m)->GetId().Get();
  622.             chains.push_back(make_pair(sid, name));
  623.         }
  624.     }
  625.     if (chains.size() == 0) {
  626.         ERRORMSG("No protein chains found in this structure!");
  627.         return;
  628.     }
  629.     // get protein name (PDB identifier)
  630.     string pdbID;
  631.     CBiostruc::TDescr::const_iterator n, ne = biostruc->GetDescr().end();
  632.     for (n=biostruc->GetDescr().begin(); n!=ne; ++n) {
  633.         if ((*n)->IsName()) {
  634.             pdbID = (*n)->GetName();    // assume first 'name' is pdb id
  635.             break;
  636.         }
  637.     }
  638.     // which chains to align?
  639.     vector < const CSeq_id * > sids;
  640.     if (chains.size() == 1) {
  641.         sids.push_back(chains[0].first);
  642.     } else {
  643.         wxString *choices = new wxString[chains.size()];
  644.         int choice;
  645.         for (choice=0; choice<chains.size(); ++choice)
  646.             choices[choice].Printf("%s_%c %s",
  647.                 pdbID.c_str(), chains[choice].second, chains[choice].first->GetSeqIdString().c_str());
  648.         wxArrayInt selections;
  649.         int nsel = wxGetMultipleChoices(selections, "Which chain do you want to align?",
  650.             "Select Chain", chains.size(), choices, *viewerWindow);
  651.         if (nsel == 0) return;
  652.         for (choice=0; choice<nsel; ++choice)
  653.             sids.push_back(chains[selections[choice]].first);
  654.     }
  655.     SequenceList newSequences;
  656.     SequenceSet::SequenceList::const_iterator s, se = master->parentSet->sequenceSet->sequences.end();
  657.     map < const Sequence * , const CSeq_id * > seq2id;
  658.     for (int j=0; j<sids.size(); ++j) {
  659.         // first check to see if this sequence is already present
  660.         for (s=master->parentSet->sequenceSet->sequences.begin(); s!=se; ++s) {
  661.             if ((*s)->identifier->MatchesSeqId(*(sids[j]))) {
  662.                 TRACEMSG("using existing sequence for " << sids[j]->GetSeqIdString());
  663.                 newSequences.push_back(*s);
  664.                 seq2id[*s] = sids[j];
  665.                 break;
  666.             }
  667.         }
  668.         if (s == se) {
  669.             // if not, find the sequence in the list from the structure file
  670.             BioseqRefList::iterator b, be = bioseqs.end();
  671.             for (b=bioseqs.begin(); b!=be; ++b) {
  672.                 CBioseq::TId::const_iterator i, ie = (*b)->GetId().end();
  673.                 for (i=(*b)->GetId().begin(); i!=ie; ++i) {
  674.                     if ((*i)->Match(*(sids[j])))
  675.                         break;
  676.                 }
  677.                 if (i != ie) {
  678.                     const Sequence *sequence = master->parentSet->CreateNewSequence(**b);
  679.                     if (sequence) {
  680.                         TRACEMSG("found Bioseq for " << sids[j]->GetSeqIdString());
  681.                         newSequences.push_back(sequence);
  682.                         seq2id[sequence] = sids[j];
  683.                         break;
  684.                     }
  685.                 }
  686.             }
  687.             if (b == be) {
  688.                 ERRORMSG("ImportStructure() - can't find " << sids[j]->GetSeqIdString() << " in bioseq list!");
  689. //                return;
  690.             }
  691.         }
  692.     }
  693.     SequenceList::const_iterator w, we = newSequences.end();
  694.     for (w=newSequences.begin(); w!=we; ++w) {
  695.         // add MMDB id tag to Bioseq if not present already
  696.         (*w)->AddMMDBAnnotTag(mmdbID);
  697.         // add MMDB and molecule id to identifier if not already set
  698.         if ((*w)->identifier->mmdbID == MoleculeIdentifier::VALUE_NOT_SET) {
  699.             (const_cast<MoleculeIdentifier*>((*w)->identifier))->mmdbID = mmdbID;
  700.         } else {
  701.             if ((*w)->identifier->mmdbID != mmdbID)
  702.                 ERRORMSG("MMDB ID mismatch in sequence " << (*w)->identifier->ToString()
  703.                     << "; " << (*w)->identifier->mmdbID << " vs " << mmdbID);
  704.         }
  705.         if (moleculeIDs.find(seq2id[*w]) != moleculeIDs.end()) {
  706.             if ((*w)->identifier->moleculeID == MoleculeIdentifier::VALUE_NOT_SET) {
  707.                 (const_cast<MoleculeIdentifier*>((*w)->identifier))->moleculeID =
  708.                     moleculeIDs[seq2id[*w]];
  709.             } else {
  710.                 if ((*w)->identifier->moleculeID != moleculeIDs[seq2id[*w]])
  711.                     ERRORMSG("Molecule ID mismatch in sequence " << (*w)->identifier->ToString());
  712.             }
  713.         } else
  714.             ERRORMSG("No matching id for MMDB sequence " << (*w)->identifier->ToString());
  715.     }
  716.     // create null-alignment
  717.     AlignmentList newAlignments;
  718.     int masterFrom = -1, masterTo = -1;
  719.     const BlockMultipleAlignment *multiple = alignmentManager->GetCurrentMultipleAlignment();
  720.     if (multiple) {
  721.         BlockMultipleAlignment::UngappedAlignedBlockList aBlocks;
  722.         multiple->GetUngappedAlignedBlocks(&aBlocks);
  723.         if (aBlocks.size() > 0) {
  724.             masterFrom = aBlocks.front()->GetRangeOfRow(0)->from;
  725.             masterTo = aBlocks.back()->GetRangeOfRow(0)->to;
  726.         }
  727.     }
  728.     GetVASTAlignments(newSequences, master, &newAlignments,
  729.         &pendingStructureAlignments, masterFrom, masterTo);
  730.     // add new alignment to update list
  731.     if (newAlignments.size() == newSequences.size())
  732.         AddAlignments(newAlignments);
  733.     else {
  734.         ERRORMSG("UpdateViewer::ImportStructure() - no new alignments were created");
  735.         DELETE_ALL_AND_CLEAR(newAlignments, AlignmentList);
  736.         return;
  737.     }
  738.     // will add Biostruc and structure alignments to ASN data later on, after merge
  739.     pendingStructures.push_back(biostruc);
  740.     // inform user of success
  741.     wxMessageBox("The structure has been successfully imported! However, it will not appear until youn"
  742.         "save this data to a file and then re-load it in a new session. And depending on the typen"
  743.         "of data, it still might not appear unless the corresponding new pairwise alignment hasn"
  744.         "been merged into the multiple alignment.",
  745.         "Structure Added", wxOK | wxICON_INFORMATION, *viewerWindow);
  746. }
  747. void UpdateViewer::SavePendingStructures(void)
  748. {
  749.     TRACEMSG("saving pending imported structures and structure alignments");
  750.     StructureSet *sSet =
  751.         (alignmentManager->GetCurrentMultipleAlignment() &&
  752.          alignmentManager->GetCurrentMultipleAlignment()->GetMaster()) ?
  753.          alignmentManager->GetCurrentMultipleAlignment()->GetMaster()->parentSet : NULL;
  754.     if (!sSet) return;
  755.     while (pendingStructures.size() > 0) {
  756.         if (!sSet->AddBiostrucToASN(pendingStructures.front().GetPointer())) {
  757.             ERRORMSG("UpdateViewer::SavePendingStructures() - error saving Biostruc");
  758.             return;
  759.         }
  760.         pendingStructures.pop_front();
  761.     }
  762.     while (pendingStructureAlignments.size() > 0) {
  763.         sSet->AddStructureAlignment(pendingStructureAlignments.front().structureAlignment.GetPointer(),
  764.             pendingStructureAlignments.front().masterDomainID,
  765.             pendingStructureAlignments.front().slaveDomainID);
  766.         pendingStructureAlignments.pop_front();
  767.     }
  768. }
  769. void UpdateViewer::BlastUpdate(BlockMultipleAlignment *alignment, bool usePSSMFromMultiple)
  770. {
  771.     const BlockMultipleAlignment *multipleForPSSM = alignmentManager->GetCurrentMultipleAlignment();
  772.     if (usePSSMFromMultiple && !multipleForPSSM) {
  773.         ERRORMSG("Can't do BLAST/PSSM when no multiple alignment is present");
  774.         return;
  775.     }
  776.     // find alignment, and replace it with BLAST result
  777.     AlignmentList::iterator a, ae = GetCurrentAlignments().end();
  778.     for (a=GetCurrentAlignments().begin(); a!=ae; ++a) {
  779.         if (*a != alignment) continue;
  780.         // run BLAST between master and first slave (should be only one slave...)
  781.         BLASTer::AlignmentList toRealign;
  782.         toRealign.push_back(alignment);
  783.         BLASTer::AlignmentList newAlignments;
  784.         alignmentManager->blaster->CreateNewPairwiseAlignmentsByBlast(
  785.             multipleForPSSM, toRealign, &newAlignments, usePSSMFromMultiple);
  786.         if (newAlignments.size() != 1) {
  787.             ERRORMSG("UpdateViewer::BlastUpdate() - CreateNewPairwiseAlignmentsByBlast() failed");
  788.             return;
  789.         }
  790.         if (newAlignments.front()->NAlignedBlocks() == 0) {
  791.             WARNINGMSG("alignment unchanged");
  792.             delete newAlignments.front();
  793.             return;
  794.         }
  795.         // replace alignment with BLAST result
  796.         TRACEMSG("BLAST succeeded - replacing alignment");
  797.         delete alignment;
  798.         *a = newAlignments.front();
  799.         break;
  800.     }
  801.     // recreate alignment display with new alignment
  802.     AlignmentList copy = GetCurrentAlignments();
  803.     GetCurrentAlignments().clear();
  804.     GetCurrentDisplay()->Empty();
  805.     AddAlignments(copy);
  806. //    (*viewerWindow)->ScrollToColumn(GetCurrentDisplay()->GetStartingColumn());
  807. }
  808. static void MapSlaveToMaster(const BlockMultipleAlignment *alignment,
  809.     int slaveRow, vector < int > *slave2master)
  810. {
  811.     slave2master->clear();
  812.     slave2master->resize(alignment->GetSequenceOfRow(slaveRow)->Length(), -1);
  813.     BlockMultipleAlignment::UngappedAlignedBlockList uaBlocks;
  814.     alignment->GetUngappedAlignedBlocks(&uaBlocks);
  815.     BlockMultipleAlignment::UngappedAlignedBlockList::const_iterator b, be = uaBlocks.end();
  816.     for (b=uaBlocks.begin(); b!=be; ++b) {
  817.         const Block::Range
  818.             *masterRange = (*b)->GetRangeOfRow(0),
  819.             *slaveRange = (*b)->GetRangeOfRow(slaveRow);
  820.         for (int i=0; i<(*b)->width; ++i)
  821.             (*slave2master)[slaveRange->from + i] = masterRange->from + i;
  822.     }
  823. }
  824. static BlockMultipleAlignment * GetAlignmentByBestNeighbor(
  825.     const BlockMultipleAlignment *multiple,
  826.     const BLASTer::AlignmentList rowAlignments)
  827. {
  828.     if (rowAlignments.size() != multiple->NRows()) {
  829.         ERRORMSG("GetAlignmentByBestNeighbor: wrong # alignments");
  830.         return NULL;
  831.     }
  832.     // find best-scoring aligment above some threshold
  833.     const BlockMultipleAlignment *bestMatchFromMultiple = NULL;
  834.     int b, bestRow = -1;
  835.     BLASTer::AlignmentList::const_iterator p, pe = rowAlignments.end();
  836.     for (b=0, p=rowAlignments.begin(); p!=pe; ++b, ++p) {
  837.         if (!bestMatchFromMultiple || (*p)->GetRowDouble(0) < bestMatchFromMultiple->GetRowDouble(0)) {
  838.             bestMatchFromMultiple = *p;
  839.             bestRow = b;
  840.         }
  841.     }
  842.     if (!bestMatchFromMultiple || bestMatchFromMultiple->GetRowDouble(0) > 0.000001) {
  843.         WARNINGMSG("GetAlignmentByBestNeighbor: no significant hit found");
  844.         return NULL;
  845.     }
  846.     INFOMSG("Closest neighbor from multiple: sequence "
  847.         << bestMatchFromMultiple->GetMaster()->identifier->ToString()
  848.         << ", E-value: " << bestMatchFromMultiple->GetRowDouble(0));
  849.     GlobalMessenger()->RemoveAllHighlights(true);
  850.     GlobalMessenger()->AddHighlights(
  851.         bestMatchFromMultiple->GetMaster(), 0, bestMatchFromMultiple->GetMaster()->Length()-1);
  852.     // if the best match is the multiple's master, then just use that alignment
  853.     if (bestRow == 0) return bestMatchFromMultiple->Clone();
  854.     // otherwise, use best match as a guide alignment to align the slave with the multiple's master
  855.     vector < int > import2slave, slave2master;
  856.     MapSlaveToMaster(bestMatchFromMultiple, 1, &import2slave);
  857.     MapSlaveToMaster(multiple, bestRow, &slave2master);
  858.     const Sequence *importSeq = bestMatchFromMultiple->GetSequenceOfRow(1);
  859.     BlockMultipleAlignment::SequenceList *seqs = new BlockMultipleAlignment::SequenceList(2);
  860.     (*seqs)[0] = multiple->GetSequenceOfRow(0);
  861.     (*seqs)[1] = importSeq;
  862.     BlockMultipleAlignment *newAlignment =
  863.         new BlockMultipleAlignment(seqs, importSeq->parentSet->alignmentManager);
  864.     // create maximally sized blocks
  865.     int masterStart, importStart, importLoc, slaveLoc, masterLoc, len;
  866.     for (importStart=-1, importLoc=0; importLoc<=importSeq->Length(); ++importLoc) {
  867.         // map import -> slave -> master
  868.         slaveLoc = (importLoc<importSeq->Length()) ? import2slave[importLoc] : -1;
  869.         masterLoc = (slaveLoc >= 0) ? slave2master[slaveLoc] : -1;
  870.         // if we're currently inside a block..
  871.         if (importStart >= 0) {
  872.             // add another residue to a continuously aligned block
  873.             if (masterLoc >= 0 && masterLoc-masterStart == importLoc-importStart) {
  874.                 ++len;
  875.             }
  876.             // terminate block
  877.             else {
  878.                 UngappedAlignedBlock *newBlock = new UngappedAlignedBlock(newAlignment);
  879.                 newBlock->SetRangeOfRow(0, masterStart, masterStart + len - 1);
  880.                 newBlock->SetRangeOfRow(1, importStart, importStart + len - 1);
  881.                 newBlock->width = len;
  882.                 newAlignment->AddAlignedBlockAtEnd(newBlock);
  883.                 importStart = -1;
  884.             }
  885.         }
  886.         // search for start of block
  887.         if (importStart < 0) {
  888.             if (masterLoc >= 0) {
  889.                 masterStart = masterLoc;
  890.                 importStart = importLoc;
  891.                 len = 1;
  892.             }
  893.         }
  894.     }
  895.     // finalize and and add new alignment to list
  896.     if (!newAlignment->AddUnalignedBlocks() || !newAlignment->UpdateBlockMapAndColors(false)) {
  897.         ERRORMSG("error finalizing alignment");
  898.         delete newAlignment;
  899.         return NULL;
  900.     }
  901.     return newAlignment;
  902. }
  903. void UpdateViewer::BlastNeighbor(BlockMultipleAlignment *update)
  904. {
  905.     const BlockMultipleAlignment *multiple = alignmentManager->GetCurrentMultipleAlignment();
  906.     if (!multiple) {
  907.         ERRORMSG("Can't do BLAST Neighbor when no multiple alignment is present");
  908.         return;
  909.     }
  910.     BlockMultipleAlignment::UngappedAlignedBlockList uaBlocks;
  911.     multiple->GetUngappedAlignedBlocks(&uaBlocks);
  912.     if (uaBlocks.size() == 0) {
  913.         ERRORMSG("Can't do BLAST Neighbor with null multiple alignment");
  914.         return;
  915.     }
  916.     const Sequence *updateSeq = update->GetSequenceOfRow(1);
  917.     // find alignment, to replace it with BLAST result
  918.     AlignmentList::iterator a, ae = GetCurrentAlignments().end();
  919.     for (a=GetCurrentAlignments().begin(); a!=ae; ++a)
  920.         if (*a == update) break;
  921.     if (a == GetCurrentAlignments().end()) return;
  922.     // set up BLAST-2-sequences between update slave and each sequence from the multiple
  923.     BLASTer::AlignmentList toRealign;
  924.     for (int row=0; row<multiple->NRows(); ++row) {
  925.         BlockMultipleAlignment::SequenceList *seqs = new BlockMultipleAlignment::SequenceList(2);
  926.         (*seqs)[0] = multiple->GetSequenceOfRow(row);
  927.         (*seqs)[1] = updateSeq;
  928.         BlockMultipleAlignment *newAlignment =
  929.             new BlockMultipleAlignment(seqs, updateSeq->parentSet->alignmentManager);
  930.         if (newAlignment->AddUnalignedBlocks() && newAlignment->UpdateBlockMapAndColors(false))
  931.         {
  932.             int excess = 0;
  933.             if (!RegistryGetInteger(REG_ADVANCED_SECTION, REG_FOOTPRINT_RES, &excess))
  934.                 WARNINGMSG("Can't get footprint excess residues from registry");
  935.             newAlignment->alignMasterFrom = uaBlocks.front()->GetRangeOfRow(row)->from - excess;
  936.             if (newAlignment->alignMasterFrom < 0)
  937.                 newAlignment->alignMasterFrom = 0;
  938.             newAlignment->alignMasterTo = uaBlocks.back()->GetRangeOfRow(row)->to + excess;
  939.             if (newAlignment->alignMasterTo >= (*seqs)[0]->Length())
  940.                 newAlignment->alignMasterTo = (*seqs)[0]->Length() - 1;
  941.             newAlignment->alignSlaveFrom = update->alignSlaveFrom;
  942.             newAlignment->alignSlaveTo = update->alignSlaveTo;
  943.             toRealign.push_back(newAlignment);
  944.         } else {
  945.             ERRORMSG("error finalizing alignment");
  946.             delete newAlignment;
  947.         }
  948.     }
  949.     // actually do BLAST alignments
  950.     BLASTer::AlignmentList newAlignments;
  951.     SetDiagPostLevel(eDiag_Error); // ignore all but Errors while reading data
  952.     alignmentManager->blaster->
  953.         CreateNewPairwiseAlignmentsByBlast(NULL, toRealign, &newAlignments, false);
  954.     SetDiagPostLevel(eDiag_Info);
  955.     DELETE_ALL_AND_CLEAR(toRealign, BLASTer::AlignmentList);
  956.     if (newAlignments.size() != multiple->NRows()) {
  957.         ERRORMSG("UpdateViewer::BlastUpdate() - CreateNewPairwiseAlignmentsByBlast() failed");
  958.         return;
  959.     }
  960.     // replace alignment with result
  961.     BlockMultipleAlignment *alignmentByNeighbor = GetAlignmentByBestNeighbor(multiple, newAlignments);
  962.     DELETE_ALL_AND_CLEAR(newAlignments, BLASTer::AlignmentList);
  963.     if (!alignmentByNeighbor) {
  964.         WARNINGMSG("alignment unchanged");
  965.         return;
  966.     }
  967.     TRACEMSG("BLAST Neighbor succeeded - replacing alignment");
  968.     delete update;
  969.     *a = alignmentByNeighbor;
  970.     // recreate alignment display with new alignment
  971.     AlignmentList copy = GetCurrentAlignments();
  972.     GetCurrentAlignments().clear();
  973.     GetCurrentDisplay()->Empty();
  974.     AddAlignments(copy);
  975. //    (*viewerWindow)->ScrollToColumn(GetCurrentDisplay()->GetStartingColumn());
  976. }
  977. // comparison function: if CompareRows(a, b) == true, then row a moves up
  978. typedef bool (*CompareUpdates)(BlockMultipleAlignment *a, BlockMultipleAlignment *b);
  979. static bool CompareUpdatesByIdentifier(BlockMultipleAlignment *a, BlockMultipleAlignment *b)
  980. {
  981.     return MoleculeIdentifier::CompareIdentifiers(
  982.         a->GetSequenceOfRow(1)->identifier, // sort by first slave row
  983.         b->GetSequenceOfRow(1)->identifier);
  984. }
  985. static CompareUpdates updateComparisonFunction = NULL;
  986. void UpdateViewer::SortByIdentifier(void)
  987. {
  988.     TRACEMSG("sorting updates by identifier");
  989.     updateComparisonFunction = CompareUpdatesByIdentifier;
  990.     SortUpdates();
  991. }
  992. void UpdateViewer::SortUpdates(void)
  993. {
  994.     if (!updateComparisonFunction) {
  995.         ERRORMSG("UpdateViewer::SortUpdates() - must first set comparison function");
  996.         return;
  997.     }
  998.     // make vector of alignments
  999.     AlignmentList& currentAlignments = GetCurrentAlignments();
  1000.     if (currentAlignments.size() < 2) return;
  1001.     vector < BlockMultipleAlignment * > sortedVector(currentAlignments.size());
  1002.     AlignmentList::const_iterator a, ae = currentAlignments.end();
  1003.     int i = 0;
  1004.     for (a=currentAlignments.begin(); a!=ae; ++a) sortedVector[i++] = *a;
  1005.     // sort them
  1006.     stable_sort(sortedVector.begin(), sortedVector.end(), updateComparisonFunction);
  1007.     updateComparisonFunction = NULL;
  1008.     // replace window contents with sorted list
  1009.     currentAlignments.clear();
  1010.     GetCurrentDisplay()->Empty();
  1011.     AlignmentList sortedList;
  1012.     for (i=0; i<sortedVector.size(); ++i) sortedList.push_back(sortedVector[i]);
  1013.     AddAlignments(sortedList);
  1014. }
  1015. END_SCOPE(Cn3D)
  1016. /*
  1017. * ---------------------------------------------------------------------------
  1018. * $Log: update_viewer.cpp,v $
  1019. * Revision 1000.3  2004/06/01 18:29:49  gouriano
  1020. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.73
  1021. *
  1022. * Revision 1.73  2004/05/21 21:41:40  gorelenk
  1023. * Added PCH ncbi_pch.hpp
  1024. *
  1025. * Revision 1.72  2004/05/21 17:29:51  thiessen
  1026. * allow conversion of mime to cdd data
  1027. *
  1028. * Revision 1.71  2004/03/15 18:38:52  thiessen
  1029. * prefer prefix vs. postfix ++/-- operators
  1030. *
  1031. * Revision 1.70  2004/02/19 17:05:20  thiessen
  1032. * remove cn3d/ from include paths; add pragma to disable annoying msvc warning
  1033. *
  1034. * Revision 1.69  2004/01/17 00:17:32  thiessen
  1035. * add Biostruc and network structure load
  1036. *
  1037. * Revision 1.68  2004/01/05 17:09:16  thiessen
  1038. * abort import and warn if same accession different gi
  1039. *
  1040. * Revision 1.67  2003/11/06 18:52:32  thiessen
  1041. * make geometry violations shown on/off; allow multiple pmid entry in ref dialog
  1042. *
  1043. * Revision 1.66  2003/09/25 14:11:43  thiessen
  1044. * don't assume gi Seq-id's for imported structure's sequences
  1045. *
  1046. * Revision 1.65  2003/08/21 18:27:40  thiessen
  1047. * change header order for Mac compilation
  1048. *
  1049. * Revision 1.64  2003/07/14 18:37:08  thiessen
  1050. * change GetUngappedAlignedBlocks() param types; other syntax changes
  1051. *
  1052. * Revision 1.63  2003/04/04 14:02:22  thiessen
  1053. * more informative error messages on structure import
  1054. *
  1055. * Revision 1.62  2003/04/02 18:03:16  thiessen
  1056. * fix wxString/string confusion
  1057. *
  1058. * Revision 1.61  2003/04/02 17:49:18  thiessen
  1059. * allow pdb id's in structure import dialog
  1060. *
  1061. * Revision 1.60  2003/03/14 19:57:07  thiessen
  1062. * adjust wxStringTokenizer mode
  1063. *
  1064. * Revision 1.59  2003/03/14 19:48:51  thiessen
  1065. * allow multiple gi's in network sequence import dialog
  1066. *
  1067. * Revision 1.58  2003/03/13 18:55:17  thiessen
  1068. * tweak file load error reporting
  1069. *
  1070. * Revision 1.57  2003/02/03 19:20:08  thiessen
  1071. * format changes: move CVS Log to bottom of file, remove std:: from .cpp files, and use new diagnostic macros
  1072. *
  1073. * Revision 1.56  2003/01/31 17:18:58  thiessen
  1074. * many small additions and changes...
  1075. *
  1076. * Revision 1.55  2003/01/23 20:03:05  thiessen
  1077. * add BLAST Neighbor algorithm
  1078. *
  1079. * Revision 1.54  2002/11/19 21:19:44  thiessen
  1080. * more const changes for objects; fix user vs default style bug
  1081. *
  1082. * Revision 1.53  2002/11/06 00:18:10  thiessen
  1083. * fixes for new CRef/const rules in objects
  1084. *
  1085. * Revision 1.52  2002/10/27 22:23:51  thiessen
  1086. * save structure alignments from vastalign.cgi imports
  1087. *
  1088. * Revision 1.51  2002/10/25 19:00:02  thiessen
  1089. * retrieve VAST alignment from vastalign.cgi on structure import
  1090. *
  1091. * Revision 1.50  2002/10/15 22:04:09  thiessen
  1092. * fix geom vltns bug
  1093. *
  1094. * Revision 1.49  2002/10/13 22:58:08  thiessen
  1095. * add redo ability to editor
  1096. *
  1097. * Revision 1.48  2002/09/30 17:13:02  thiessen
  1098. * change structure import to do sequences as well; change cache to hold mimes; change block aligner vocabulary; fix block aligner dialog bugs
  1099. *
  1100. * Revision 1.47  2002/09/26 18:31:24  thiessen
  1101. * allow simultaneous import of multiple chains from single PDB
  1102. *
  1103. * Revision 1.46  2002/09/16 21:24:58  thiessen
  1104. * add block freezing to block aligner
  1105. *
  1106. * Revision 1.45  2002/09/09 13:38:23  thiessen
  1107. * separate save and save-as
  1108. *
  1109. * Revision 1.44  2002/08/15 22:13:18  thiessen
  1110. * update for wx2.3.2+ only; add structure pick dialog; fix MultitextDialog bug
  1111. *
  1112. * Revision 1.43  2002/08/13 20:46:37  thiessen
  1113. * add global block aligner
  1114. *
  1115. * Revision 1.42  2002/07/27 12:29:52  thiessen
  1116. * fix block aligner crash
  1117. *
  1118. * Revision 1.41  2002/07/26 15:28:48  thiessen
  1119. * add Alejandro's block alignment algorithm
  1120. *
  1121. * Revision 1.40  2002/07/26 13:07:01  thiessen
  1122. * fix const object problem
  1123. *
  1124. * Revision 1.39  2002/07/01 23:17:04  thiessen
  1125. * skip warning if master choice canceled
  1126. *
  1127. * Revision 1.38  2002/06/06 01:30:02  thiessen
  1128. * fixes for linux/gcc
  1129. *
  1130. * Revision 1.37  2002/06/05 14:28:41  thiessen
  1131. * reorganize handling of window titles
  1132. *
  1133. * Revision 1.36  2002/06/04 12:48:56  thiessen
  1134. * tweaks for release ; fill out help menu
  1135. *
  1136. * Revision 1.35  2002/05/22 17:17:09  thiessen
  1137. * progress on BLAST interface ; change custom spin ctrl implementation
  1138. *
  1139. * Revision 1.34  2002/05/17 19:10:27  thiessen
  1140. * preliminary range restriction for BLAST/PSSM
  1141. *
  1142. * Revision 1.33  2002/04/26 19:01:00  thiessen
  1143. * fix display delete bug
  1144. *
  1145. * Revision 1.32  2002/03/28 14:06:02  thiessen
  1146. * preliminary BLAST/PSSM ; new CD startup style
  1147. *
  1148. * Revision 1.31  2002/03/07 19:16:04  thiessen
  1149. * don't auto-show sequence windows
  1150. *
  1151. * Revision 1.30  2002/03/04 15:52:15  thiessen
  1152. * hide sequence windows instead of destroying ; add perspective/orthographic projection choice
  1153. *
  1154. * Revision 1.29  2002/02/27 16:29:42  thiessen
  1155. * add model type flag to general mime type
  1156. *
  1157. * Revision 1.28  2002/02/22 14:24:01  thiessen
  1158. * sort sequences in reject dialog ; general identifier comparison
  1159. *
  1160. * Revision 1.27  2002/02/13 14:53:30  thiessen
  1161. * add update sort
  1162. *
  1163. * Revision 1.26  2002/02/12 17:19:22  thiessen
  1164. * first working structure import
  1165. *
  1166. * Revision 1.25  2002/02/01 00:41:21  thiessen
  1167. * tweaks
  1168. *
  1169. * Revision 1.24  2002/01/24 20:07:57  thiessen
  1170. * read multiple FAST sequences
  1171. *
  1172. * Revision 1.23  2002/01/02 02:08:29  thiessen
  1173. * go back to viewer.cgi to test http/301 forwarding
  1174. *
  1175. * Revision 1.22  2001/12/15 03:15:59  thiessen
  1176. * adjustments for slightly changed object loader Set...() API
  1177. *
  1178. * Revision 1.21  2001/12/12 14:58:10  thiessen
  1179. * change URL to viewer.fcgi
  1180. *
  1181. * Revision 1.20  2001/12/06 23:13:47  thiessen
  1182. * finish import/align new sequences into single-structure data; many small tweaks
  1183. *
  1184. * Revision 1.19  2001/11/30 14:02:05  thiessen
  1185. * progress on sequence imports to single structures
  1186. *
  1187. * Revision 1.18  2001/11/27 16:26:10  thiessen
  1188. * major update to data management system
  1189. *
  1190. * Revision 1.17  2001/10/01 16:04:25  thiessen
  1191. * make CDD annotation window non-modal; add SetWindowTitle to viewers
  1192. *
  1193. * Revision 1.16  2001/09/27 15:38:00  thiessen
  1194. * decouple sequence import and BLAST
  1195. *
  1196. * Revision 1.15  2001/09/20 19:31:30  thiessen
  1197. * fixes for SGI and wxWin 2.3.2
  1198. *
  1199. * Revision 1.14  2001/09/19 22:55:39  thiessen
  1200. * add preliminary net import and BLAST
  1201. *
  1202. * Revision 1.13  2001/09/18 03:10:46  thiessen
  1203. * add preliminary sequence import pipeline
  1204. *
  1205. * Revision 1.12  2001/06/02 17:22:46  thiessen
  1206. * fixes for GCC
  1207. *
  1208. * Revision 1.11  2001/05/17 18:34:26  thiessen
  1209. * spelling fixes; change dialogs to inherit from wxDialog
  1210. *
  1211. * Revision 1.10  2001/05/02 13:46:28  thiessen
  1212. * major revision of stuff relating to saving of updates; allow stored null-alignments
  1213. *
  1214. * Revision 1.9  2001/04/20 18:02:41  thiessen
  1215. * don't open update viewer right away
  1216. *
  1217. * Revision 1.8  2001/04/19 12:58:32  thiessen
  1218. * allow merge and delete of individual updates
  1219. *
  1220. * Revision 1.7  2001/04/05 22:55:36  thiessen
  1221. * change bg color handling ; show geometry violations
  1222. *
  1223. * Revision 1.6  2001/04/04 00:27:15  thiessen
  1224. * major update - add merging, threader GUI controls
  1225. *
  1226. * Revision 1.5  2001/03/30 03:07:34  thiessen
  1227. * add threader score calculation & sorting
  1228. *
  1229. * Revision 1.4  2001/03/22 00:33:17  thiessen
  1230. * initial threading working (PSSM only); free color storage in undo stack
  1231. *
  1232. * Revision 1.3  2001/03/17 14:06:49  thiessen
  1233. * more workarounds for namespace/#define conflicts
  1234. *
  1235. * Revision 1.2  2001/03/13 01:25:06  thiessen
  1236. * working undo system for >1 alignment (e.g., update window)
  1237. *
  1238. * Revision 1.1  2001/03/09 15:49:06  thiessen
  1239. * major changes to add initial update viewer
  1240. *
  1241. */