NCBI C++ ToolKit
obj_event.cpp
Go to the documentation of this file.
00001 /*  $Id: obj_event.cpp 20108 2009-09-15 19:27:21Z kuznets $
00002  * ===========================================================================
00003  *
00004  *                            PUBLIC DOMAIN NOTICE
00005  *               National Center for Biotechnology Information
00006  *
00007  *  This software/database is a "United States Government Work" under the
00008  *  terms of the United States Copyright Act.  It was written as part of
00009  *  the author's official duties as a United States Government employee and
00010  *  thus cannot be copyrighted.  This software/database is freely available
00011  *  to the public for use. The National Library of Medicine and the U.S.
00012  *  Government have not placed any restriction on its use or reproduction.
00013  *
00014  *  Although all reasonable efforts have been taken to ensure the accuracy
00015  *  and reliability of the software and data, the NLM and the U.S.
00016  *  Government do not and cannot warrant the performance or results that
00017  *  may be obtained by using this software or data. The NLM and the U.S.
00018  *  Government disclaim all warranties, express or implied, including
00019  *  warranties of performance, merchantability or fitness for any particular
00020  *  purpose.
00021  *
00022  *  Please cite the author in any work or product based on this material.
00023  *
00024  * ===========================================================================
00025  *
00026  * Authors:  Andrey Yazhuk
00027  *
00028  * File Description:
00029  *
00030  */
00031 
00032 #include <ncbi_pch.hpp>
00033 
00034 #include <gui/objutils/obj_event.hpp>
00035 
00036 #include <corelib/ncbitime.hpp>
00037 #include <serial/iterator.hpp>
00038 
00039 #include <objects/seq/seq_id_mapper.hpp>
00040 #include <objmgr/util/sequence.hpp>
00041 
00042 #include <gui/objutils/utils.hpp>
00043 
00044 
00045 BEGIN_NCBI_SCOPE
00046 USING_SCOPE(objects);
00047 
00048 
00049 CSelectionEvent::TRawNameToType    CSelectionEvent::sm_RawNameToType;
00050 
00051 CSelectionEvent::EObjMatchPolicy
00052     CSelectionEvent::sm_ObjMatchPolicy = CSelectionEvent::eAtLeastOne;
00053 CSelectionEvent::EIdMatchPolicy
00054     CSelectionEvent::sm_IdMatchPolicy = CSelectionEvent::eAccOnly;
00055 bool    CSelectionEvent::sm_MatchAlnLocs = true;
00056 bool    CSelectionEvent::sm_MatchByProduct = true;
00057 bool    CSelectionEvent::sm_AutoBroadcast = true;
00058 bool    CSelectionEvent::sm_InterDocBroadcast = true;
00059 
00060 
00061 CSelectionEvent::CSelectionEvent( objects::CScope& scope, CEventHandler* sender )
00062     : CViewEvent( eSelectionChanged )
00063     , m_Scope( &scope )
00064     , m_HasRangeSelection( false )
00065     , m_HasObjectSelection( false )
00066 {
00067     m_Sender = sender;
00068 
00069     x_Init();
00070 }
00071 
00072 CSelectionEvent::CSelectionEvent( CRef<objects::CScope> scope, CEventHandler* sender )
00073     : CViewEvent( eSelectionChanged )
00074     , m_Scope( scope )
00075     , m_HasRangeSelection( false )
00076     , m_HasObjectSelection( false )
00077 {
00078     m_Sender = sender;
00079 
00080     x_Init();
00081 }
00082 
00083 void CSelectionEvent::x_Init()
00084 {
00085     if( sm_RawNameToType.size() == 0 ){ // fill the map only once
00086         string  feat_key = typeid(CSeq_feat).name();
00087         string  align_key = typeid(CSeq_align).name();
00088         string  loc_key = typeid(CSeq_loc).name();
00089         string  id_key = typeid(CSeq_id).name();
00090 
00091         sm_RawNameToType[feat_key] = eSeq_feat;
00092         sm_RawNameToType[align_key] = eSeq_align;
00093         sm_RawNameToType[loc_key] = eSeq_loc;
00094         sm_RawNameToType[id_key] = eSeq_id;
00095     }
00096 }
00097 
00098 
00099 
00100 
00101 bool    CSelectionEvent::HasRangeSelection() const
00102 {
00103     return m_HasRangeSelection;
00104 }
00105 
00106 
00107 const CHandleRangeMap&  CSelectionEvent::GetRangeSelection() const
00108 {
00109     return m_RangeMap;
00110 }
00111 
00112 
00113 void CSelectionEvent::AddRangeSelection(const CSeq_id& id, const TRangeColl& segs)
00114 {
00115     m_HasRangeSelection = true;
00116 
00117     CSeq_id_Handle h_id = CSeq_id_Handle::GetHandle(id);
00118     if (segs.size()) {
00119         ITERATE(TRangeColl, it, segs)   {
00120             m_RangeMap.AddRange(h_id, *it, eNa_strand_both);
00121         }
00122     } else {
00123         CRef<CSeq_loc> loc(new CSeq_loc());
00124         loc->SetEmpty().Assign(id);
00125         AddRangeSelection(*loc);
00126     }
00127 }
00128 
00129 void CSelectionEvent::AddRangeSelection(const objects::CSeq_loc& loc)
00130 {
00131     m_HasRangeSelection = true;
00132 
00133     m_RangeMap.AddLocation(loc);
00134 }
00135 
00136 
00137 bool    CSelectionEvent::GetRangeSelection(const CSeq_id& id, CScope& scope,
00138                                            TRangeColl& segs)
00139 {
00140     bool ok = false;
00141     const CHandleRangeMap::TLocMap& loc_map = m_RangeMap.GetMap();
00142     ITERATE(CHandleRangeMap::TLocMap, it, loc_map)  { // for every CSeq_id
00143         CConstRef<CSeq_id> sel_id = it->first.GetSeqId();
00144 
00145         if(Match(*sel_id, *m_Scope, id, scope))   {
00146             bool res = CSeqUtils::GetRangeCollection(*sel_id, m_RangeMap, segs);
00147             ok |= res;
00148         }
00149     }
00150     return ok;
00151 }
00152 
00153 
00154 void CSelectionEvent::GetRangeSelectionAsLocs(TConstObjects& objs) const
00155 {
00156     const CHandleRangeMap::TLocMap& loc_map = m_RangeMap.GetMap();
00157     CSeq_loc::TRanges ranges;
00158 
00159     ITERATE(CHandleRangeMap::TLocMap, it, loc_map)  { // for every CSeq_id
00160         CRef<CSeq_id> sel_id(new CSeq_id());
00161         sel_id->Assign(*it->first.GetSeqId());
00162 
00163         const CHandleRange& h_range = it->second;
00164 
00165         // create a CSeq_loc
00166         ranges.clear();
00167         ITERATE(CHandleRange, it_r, h_range) {
00168             if (it_r->first.NotEmpty()) {
00169                 ranges.push_back(it_r->first);
00170             }
00171         }
00172         if(! ranges.empty())    {
00173             CSeq_loc* loc = new CSeq_loc(*sel_id, ranges);
00174             objs.push_back(CConstRef<CObject>(loc));
00175         }
00176     }
00177 }
00178 
00179 
00180 bool    CSelectionEvent::HasObjectSelection()
00181 {
00182     return m_HasObjectSelection;
00183 }
00184 
00185 
00186 bool CSelectionEvent::AddObjectSelection(const CObject& obj)
00187 {
00188     const type_info& info = typeid(obj);
00189     if(info == typeid(CSeq_feat))   {
00190         const CSeq_feat* feat = dynamic_cast<const CSeq_feat*>(&obj);
00191         AddObjectSelection(*feat);
00192         return true;
00193     } else if(info == typeid(CSeq_align)) {
00194         const CSeq_align* align = dynamic_cast<const CSeq_align*>(&obj);
00195         AddObjectSelection(*align);
00196         return true;
00197     } else if(info == typeid(CSeq_loc)) {
00198         const CSeq_loc* loc = dynamic_cast<const CSeq_loc*>(&obj);
00199         AddObjectSelection(*loc);
00200         return true;
00201     } else if(info == typeid(CSeq_id)) {
00202         const CSeq_id* id = dynamic_cast<const CSeq_id*>(&obj);
00203         AddObjectSelection(*id);
00204         return true;
00205     }
00206     return false;
00207 }
00208 
00209 
00210 void CSelectionEvent::AddObjectSelection(const TConstObjects& objs)
00211 {
00212     ITERATE(TConstObjects, it, objs)  {
00213         const CObject& obj = **it;
00214         const type_info& info = typeid(obj);
00215 
00216         if(info == typeid(CSeq_feat))   {
00217            const CSeq_feat* feat = dynamic_cast<const CSeq_feat*>(&obj);
00218            AddObjectSelection(*feat);
00219         } else if(info == typeid(CSeq_align)) {
00220             const CSeq_align* align = dynamic_cast<const CSeq_align*>(&obj);
00221             AddObjectSelection(*align);
00222         } else if(info == typeid(CSeq_loc)) {
00223             const CSeq_loc* loc = dynamic_cast<const CSeq_loc*>(&obj);
00224             AddObjectSelection(*loc);
00225         } else if(info == typeid(CSeq_id)) {
00226             const CSeq_id* id = dynamic_cast<const CSeq_id*>(&obj);
00227             AddObjectSelection(*id);
00228         }
00229     }
00230 }
00231 
00232 
00233 void CSelectionEvent::AddObjectSelection(const CSeq_id& id)
00234 {
00235     m_HasObjectSelection = true;
00236 
00237     m_Ids.push_back(CConstRef<CSeq_id>(&id));
00238 }
00239 
00240 
00241 void CSelectionEvent::AddObjectSelection(const CSeq_feat& feat)
00242 {
00243     m_HasObjectSelection = true;
00244 
00245     m_Feats.push_back(CConstRef<CSeq_feat>(&feat));
00246 
00247     if(sm_MatchByProduct  &&  feat.IsSetProduct())   {
00248         const CSeq_loc& prod_loc = feat.GetProduct();
00249         const CSeq_id* id = prod_loc.GetId();
00250         if(id) {
00251             m_Ids.push_back(CConstRef<CSeq_id>(id));
00252         }
00253     }
00254 }
00255 
00256 
00257 void CSelectionEvent::AddObjectSelection(const CSeq_align& align)
00258 {
00259     m_HasObjectSelection = true;
00260 
00261     m_Aligns.push_back(CConstRef<CSeq_align>(&align));
00262 }
00263 
00264 
00265 
00266 void CSelectionEvent::AddObjectSelection(const CSeq_loc& loc)
00267 {
00268     m_HasObjectSelection = true;
00269 
00270     m_SeqLocs.push_back(CConstRef<CSeq_loc>(&loc));
00271 }
00272 
00273 
00274 void CSelectionEvent::AddObjectSelection(const objects::CSeq_id& id, const CRange<TSeqPos>& range)
00275 {
00276     m_HasObjectSelection = true;
00277 
00278     CIdLoc* loc = new CIdLoc();
00279     loc->m_Id.Reset(&id);
00280     loc->m_Range = range;
00281     m_IdLocs.push_back(CConstRef<CIdLoc>(loc));
00282 }
00283 
00284 
00285 void CSelectionEvent::GetAllObjects(TConstObjects& objs) const
00286 {
00287     typedef CConstRef<CObject> TR;
00288 
00289     ITERATE(TFeats, it_feat, m_Feats)    {
00290         objs.push_back(TR(&**it_feat));
00291     }
00292     ITERATE(TAligns, it_align, m_Aligns)    {
00293         objs.push_back(TR(&**it_align));
00294     }
00295     ITERATE(TSeqLocs, it_loc, m_SeqLocs)    {
00296         objs.push_back(TR(&**it_loc));
00297     }
00298     ITERATE(TIds, it_id, m_Ids)    {
00299         objs.push_back(TR(&**it_id));
00300     }
00301     ITERATE(TIdLocs, it_loc, m_IdLocs)    {
00302         objs.push_back(TR(&**it_loc));
00303     }
00304 }
00305 
00306 
00307 bool CSelectionEvent::Match(const CObject& obj1, CScope& scope1,
00308                             const CObject& obj2, CScope& scope2)
00309 {
00310     if(&obj1 == &obj2)  { // trivial matching
00311         return true;
00312     }
00313 
00314     const CSeq_feat *feat1 = NULL, *feat2 = NULL;
00315     const CSeq_align *align1 = NULL, *align2 = NULL;
00316     const CSeq_loc *loc1 = NULL, *loc2 = NULL;
00317     const CSeq_id *id1 = NULL, *id2 = NULL;
00318 
00319     const type_info& info2 = typeid(obj2);
00320     string name2 = info2.name();
00321     TRawNameToType::const_iterator it = sm_RawNameToType.find(name2);
00322     if(it == sm_RawNameToType.end())    {
00323         return false; // unsupported type
00324     }
00325     EObjType type2 = it->second;
00326 
00327     switch(type2)   {
00328     case eSeq_feat: feat2 = dynamic_cast<const CSeq_feat*>(&obj2); break;
00329     case eSeq_align:    align2 = dynamic_cast<const CSeq_align*>(&obj2); break;
00330     case eSeq_loc:      loc2 = dynamic_cast<const CSeq_loc*>(&obj2); break;
00331     case eSeq_id:       id2 = dynamic_cast<const CSeq_id*>(&obj2); break;
00332     }
00333 
00334     const type_info& info1 = typeid(obj1);
00335     string name1 = info1.name();
00336     it = sm_RawNameToType.find(name1);
00337     if(it == sm_RawNameToType.end())    {
00338         return false; // unsupported type
00339     }
00340     EObjType type1 = it->second;
00341 
00342     switch(type1)   {
00343     case eSeq_feat:
00344         feat1 = dynamic_cast<const CSeq_feat*>(&obj1);
00345         switch(type2)   {
00346         case eSeq_feat: return MatchFeatWithFeat(*feat1, scope1, *feat2, scope2);
00347         case eSeq_align: return false;
00348         case eSeq_loc:  return MatchFeatWithLoc(*feat1, scope1, *loc2, scope2);
00349         case eSeq_id:   return MatchFeatWithId(*feat1, scope1, *id2, scope2);
00350         }
00351     case eSeq_align:
00352         align1 = dynamic_cast<const CSeq_align*>(&obj1);
00353         if(type2 == eSeq_align) {
00354             return MatchAlignWithAlign(*align1, scope1, *align2, scope2);
00355         } else {
00356             return false;
00357         }
00358     case eSeq_loc:
00359         loc1 = dynamic_cast<const CSeq_loc*>(&obj1);
00360         switch(type2)   {
00361         case eSeq_feat: return MatchFeatWithLoc(*feat2, scope1, *loc1, scope2);
00362         case eSeq_align: return false;
00363         case eSeq_loc:  return MatchLocWithLoc(*loc1, scope1, *loc2, scope2);
00364         case eSeq_id:   return MatchLocWithId(*loc1, scope1, *id2, scope2);
00365         }
00366     case eSeq_id:
00367         id1 = dynamic_cast<const CSeq_id*>(&obj1);
00368         switch(type2)   {
00369         case eSeq_feat: return MatchFeatWithId(*feat2, scope1, *id1, scope2);
00370         case eSeq_align: return false;
00371         case eSeq_loc:  return MatchLocWithId(*loc2, scope1, *id1, scope2);
00372         case eSeq_id:   return MatchIdWithId(*id1, scope1, *id2, scope2);
00373         }
00374     }
00375 
00376     _ASSERT(false); // must be unreachable
00377     return false;
00378 }
00379 
00380 
00381 bool CSelectionEvent::MatchFeatWithFeat(const CSeq_feat& feat1, CScope& scope1,
00382                                         const CSeq_feat& feat2, CScope& scope2)
00383 {
00384     // TO DO extend to support comparision by values (not by pointer)
00385     return &feat1 == &feat2  ||  feat1.Equals(feat2);
00386 }
00387 
00388 
00389 bool CSelectionEvent::MatchFeatWithLoc(const CSeq_feat& feat1, CScope& scope1,
00390                                        const CSeq_loc& loc2, CScope& scope2)
00391 {
00392     if(feat1.CanGetLocation())  {
00393         const CSeq_loc& feat_loc = feat1.GetLocation();
00394         if(MatchLocWithLoc(feat_loc, scope1, loc2, scope2)) {
00395             return true;
00396         }
00397     }
00398     if(sm_MatchByProduct  &&  feat1.CanGetProduct())   {
00399         const CSeq_loc& prod_loc = feat1.GetProduct();
00400         if(MatchLocWithLoc(prod_loc, scope1, loc2, scope2)) {
00401             return true;
00402         }
00403     }
00404     return false;
00405 }
00406 
00407 
00408 bool CSelectionEvent::MatchFeatWithId(const CSeq_feat& feat1, CScope& scope1,
00409                                       const CSeq_id& id2, CScope& scope2)
00410 {
00411     if(sm_MatchByProduct  &&  feat1.IsSetProduct())   {
00412         const CSeq_loc& prod_loc = feat1.GetProduct();
00413         if(MatchLocWithId(prod_loc, scope1, id2, scope2)) {
00414             return true;
00415         }
00416     }
00417     return false;
00418 }
00419 
00420 
00421 bool CSelectionEvent::MatchAlignWithAlign(const CSeq_align& align1, CScope& scope1,
00422                                           const CSeq_align& align2, CScope& scope2)
00423 {
00424     // TO DO extend to support comparision by values (not by pointer)
00425     return &align1 == &align2  ||  align1.Equals(align2);
00426 }
00427 
00428 
00429 bool CSelectionEvent::MatchLocWithLoc(const CSeq_loc& loc1, CScope& scope1,
00430                                       const CSeq_loc& loc2, CScope& scope2)
00431 {
00432     // TO DO extend to support flexiable ID matching
00433     return &loc1 == &loc2  ||  loc1.Equals(loc2);
00434 }
00435 
00436 
00437 bool CSelectionEvent::MatchLocWithId(const CSeq_loc& loc1, CScope& scope1,
00438                                      const CSeq_id& id2, CScope& scope2)
00439 {
00440     // iterate by all CSeq_id-s in the loc1 and try to match them with id2
00441     set<CSeq_id_Handle> id_set;
00442     CTypeConstIterator<CSeq_id> id_it(loc1);
00443     for ( ;  id_it;  ++id_it) {
00444         id_set.insert(CSeq_id_Handle::GetHandle(*id_it));
00445     }
00446 
00447     switch(sm_ObjMatchPolicy)    {
00448     case eAtLeastOne:
00449         {{
00450             CSeq_id_Handle id2h = CSeq_id_Handle::GetHandle(id2);
00451             if (id_set.find(id2h) != id_set.end()) {
00452                 return true;
00453             }
00454         }}
00455 
00456     default:
00457         ITERATE (set<CSeq_id_Handle>, iter, id_set) {
00458             if (MatchIdWithId(*iter->GetSeqId(), scope1, id2, scope2))   {
00459                 return true;
00460             }
00461         }
00462         break;
00463     }
00464 
00465     return false;
00466 }
00467 
00468 struct SW
00469 {
00470     CStopWatch  m_W;
00471     SW()    { m_W.Start();  }
00472     ~SW()   {   LOG_POST(Info << "Time " << m_W.Elapsed()); }
00473 };
00474 
00475 
00476 bool    CSelectionEvent::MatchIdWithId(const CSeq_id& sel_id, CScope& scope1,
00477                                        const CSeq_id& id, CScope& scope2)
00478 {
00479     //SW w;
00480 
00481     switch(sm_ObjMatchPolicy)    {
00482     case eAllIds:   {
00483         vector<CSeq_id_Handle> ids1 = scope1.GetIds(sel_id);
00484         vector<CSeq_id_Handle> ids2 = scope2.GetIds(id);
00485         if(ids1.size() == ids2.size())  {
00486             sort(ids1.begin(), ids1.end());
00487             sort(ids2.begin(), ids2.end());
00488             for( size_t i = 0; i < ids1.size(); i++ )   {
00489                 if(! x_SimpleMatch(ids1[i], ids2[i]))
00490                     return false;
00491             }
00492             return true;
00493         } else return false;
00494     }
00495     case eAtLeastOne: {
00496         vector<CSeq_id_Handle> ids1 = scope1.GetIds(sel_id);
00497         vector<CSeq_id_Handle> ids2 = scope2.GetIds(id);
00498         for( size_t i = 0; i < ids1.size(); i++ )   {
00499             for( size_t j = 0; j < ids2.size(); j++)    {
00500                 if(x_SimpleMatch(ids1[i], ids2[j]))
00501                     return true;
00502             }
00503         }
00504         return false;
00505     }
00506     }
00507     _ASSERT(false); // must be unreachable
00508     return false;
00509 }
00510 
00511 
00512 bool    CSelectionEvent::x_SimpleMatch(const objects::CSeq_id_Handle& h_sel_id,
00513                                      const objects::CSeq_id_Handle& h_id)
00514 {
00515     //cout << "\nx_SimpleMatch()  " << h_sel_id.AsString() << "  " << h_id.AsString();
00516     switch(sm_IdMatchPolicy) {
00517     case eAccOnly:
00518         return h_sel_id.MatchesTo(h_id) || h_id.MatchesTo(h_sel_id);
00519     case eExact:
00520         return h_sel_id == h_id;
00521     };
00522     _ASSERT(false); // must be unreachable
00523     return false;
00524 }
00525 
00526 
00527 END_NCBI_SCOPE
Modified on Wed May 23 13:29:13 2012 by modify_doxy.py rev. 337098