NCBI C++ ToolKit
phylo_tree_force.cpp
Go to the documentation of this file.
00001 /*  $Id: phylo_tree_force.cpp 25384 2012-03-06 19:27:20Z ucko $
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:  Vladimir Tereshkov
00027  *
00028  * File Description:
00029  *      Force tree layout
00030  */
00031 
00032 #include <ncbi_pch.hpp>
00033 #include <corelib/ncbitime.hpp>
00034 #include <corelib/ncbistl.hpp>
00035 
00036 #include <gui/widgets/phylo_tree/phylo_tree_force.hpp>
00037 #include <gui/widgets/phylo_tree/phylo_tree_pane.hpp>
00038 #include <gui/widgets/phylo_tree/phylo_tree_ds.hpp>
00039 #include <gui/widgets/phylo_tree/phylo_tree_ps.hpp>
00040 #include <gui/opengl/glhelpers.hpp>
00041 #include <gui/graph/igraph_utils.hpp>
00042 //#include <gui/widgets/phylo_tree/phylo_tree_render.hpp>
00043 
00044 #include <gui/widgets/gl/attrib_menu.hpp>
00045 
00046 #include <gui/utils/event_translator.hpp>
00047 #include <gui/framework/app_task_service.hpp>
00048 #include <gui/utils/app_job_impl.hpp>
00049 #include <gui/utils/view_event.hpp>
00050 
00051 
00052 #include <math.h>
00053 
00054 BEGIN_NCBI_SCOPE
00055 
00056 #define PHYLO_RENDER_TIMER_ID 63001
00057 
00058 BEGIN_EVENT_MAP(CPhyloForce, CEventHandler)
00059     ON_MESSAGE(CAppJobNotification, CAppJobNotification::eStateChanged,
00060                &CPhyloForce::OnAppJobNotification)
00061     ON_MESSAGE(CAppJobNotification, CAppJobNotification::eProgress,
00062                &CPhyloForce::OnAppJobProgress)
00063 END_EVENT_MAP()
00064 
00065 BEGIN_EVENT_TABLE(CPhyloForce, CPhyloRadial)
00066     EVT_TIMER(PHYLO_RENDER_TIMER_ID, CPhyloForce::OnTimer)
00067 END_EVENT_TABLE()
00068 
00069 
00070 CPhyloForce::CPhyloForce()
00071 : m_Timer(this, PHYLO_RENDER_TIMER_ID)
00072 , m_MainThreadPS(NULL)
00073 , m_UseMainThreadPhysics(true)
00074 {
00075     m_JobID                 = CAppJobDispatcher::eInvalidJobID;
00076 
00077     // If rendering within gbench, use thread for force calculations,
00078     // otherwise we are probably cgi and should use main thread.
00079     if (CGuiRegistry::GetInstance().HasField("GBENCH")) {
00080         m_UseMainThreadPhysics = false;
00081     }
00082 }
00083 
00084 CPhyloForce::CPhyloForce(double w, double h) 
00085 : CPhyloRadial(w, h)
00086 , m_Timer(this, PHYLO_RENDER_TIMER_ID)
00087 , m_MainThreadPS(NULL)
00088 , m_UseMainThreadPhysics(true)
00089 {
00090     m_JobID                 = CAppJobDispatcher::eInvalidJobID;
00091 
00092     // If rendering within gbench, use thread for force calculations,
00093     // otherwise we are probably cgi and should use main thread.
00094     if (CGuiRegistry::GetInstance().HasField("GBENCH")) {
00095         m_UseMainThreadPhysics = false;      
00096     }
00097 
00098 #ifdef ATTRIB_MENU_SUPPORT
00099    // CAttribMenu& m = CAttribMenuInstance::GetInstance();
00100 
00101    // CAttribMenu* sub_menu = m.AddSubMenuUnique("Force ext", this);
00102    
00103    // sub_menu->AddFloatReadOnly("Vis Left", &vis_left);
00104    // sub_menu->AddFloatReadOnly("Vis Right", &vis_right);
00105    // sub_menu->AddFloatReadOnly("Vis Bottom", &vis_bottom);
00106    // sub_menu->AddFloatReadOnly("Vis Top", &vis_top);
00107 
00108    // sub_menu->AddFloatReadOnly("Ext Left", &ext_left);
00109    // sub_menu->AddFloatReadOnly("Ext Right", &ext_right);
00110    // sub_menu->AddFloatReadOnly("Ext Bottom", &ext_bottom);
00111    // sub_menu->AddFloatReadOnly("Ext top", &ext_top);
00112 #endif  
00113    
00114 }
00115 
00116 
00117 CPhyloForce::~CPhyloForce()
00118 {   
00119     if (m_JobID != CAppJobDispatcher::eInvalidJobID) {
00120         CAppJobDispatcher& disp = CAppJobDispatcher::GetInstance();
00121         disp.DeleteJob(m_JobID);
00122     }
00123 
00124     m_Timer.Stop();
00125 }
00126 
00127 void  CPhyloForce::x_Layout(CPhyloTreeDataSource& ds)
00128 {
00129     m_pRoot = ds.GetTree();
00130 
00131     bool distMode = m_bDistMode;
00132     m_bDistMode = false;
00133 
00134     // It is more efficient not to re-run the radial layout each time
00135     // if, for example, the user simply collapsed some nodes.  Unfortuately
00136     // some user operations wind up setting all node position values to 0,
00137     // so be be sure we have to compute the radial tree first each time.
00138     //if (m_SwitchedLayout)
00139     CPhyloRadial::x_Layout(ds);   
00140     m_bDistMode = distMode;
00141 
00142     Int4 leafs = ds.GetSize();
00143     Int4 width = ds.GetWidth();
00144 
00145     m_xStep = m_DimX /  width;
00146     m_yStep = m_DimY / ((leafs>1)?(leafs-1):2);
00147 
00148     if (ds.GetNormDistance() > 0){      
00149          m_NormDistance = m_DimX / ds.GetNormDistance();
00150     }
00151 
00152     m_Timer.Stop();
00153 
00154     CPhyloTreePS::PhysicsParms p;
00155     bool retain_parms = false;
00156 
00157     // Set drawing options that are specific to the force layout
00158     CGlVboNode* edge_node = ds.GetModel().FindGeomNode("TreeEdges");
00159     CGlVboNode* narrow_edge_node = ds.GetModel().FindGeomNode("NarrowTreeEdges");
00160 
00161     if (edge_node != NULL && narrow_edge_node != NULL) {   
00162         edge_node->GetState().Enable(GL_LINE_SMOOTH);
00163         edge_node->GetState().Enable(GL_BLEND);
00164         edge_node->GetState().SetBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);        
00165 
00166         narrow_edge_node->GetState().Enable(GL_LINE_SMOOTH);
00167         narrow_edge_node->GetState().Enable(GL_BLEND);
00168         narrow_edge_node->GetState().SetBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00169         narrow_edge_node->GetState().SetColor(CRgbaColor(1.0f, 1.0f, 1.0f, 0.7f));
00170     }
00171 
00172     CGlVboNode* filler_points_node = m_DS->GetModel().FindGeomNode("FillerPoints");
00173     if (filler_points_node != NULL)
00174         filler_points_node->SetVisible(false);
00175 
00176     // Special case: no need for particle system if there is only
00177     // one node.
00178     if (m_pRoot->IsLeafEx()) {
00179         TModelRect newRect = ds.GetBoundRect();
00180 
00181         newRect.Inflate(1.0f, 1.0f);
00182         m_RasterRect = newRect;
00183 
00184         // This handles single node case too.
00185         ComputeViewingLimits(*m_pPane, false);
00186 
00187         return;
00188     }
00189 
00190     if (!m_UseMainThreadPhysics) {
00191 
00192         try {
00193             CForceJob* j = m_Job.GetPointerOrNull();
00194 
00195             // for debugging, copy the particle system parameters from the current 
00196             // system to the new one (parameters may be updated via attribute
00197             // menus).
00198             if (j != NULL) {
00199                 p = j->GetPS()->getPhysicParms();
00200                 retain_parms = true;
00201             }
00202 
00203             if (m_JobID != CAppJobDispatcher::eInvalidJobID) {
00204                 CAppJobDispatcher& disp = CAppJobDispatcher::GetInstance();
00205                 IAppJob::EJobState state = disp.GetJobState(m_JobID);
00206                 if (state == IAppJob::eRunning)
00207                     disp.CancelJob(m_JobID);
00208                 else
00209                     disp.DeleteJob(m_JobID);
00210 
00211                 m_Job.Reset();
00212             }
00213 
00214             j = m_Job.GetPointerOrNull();
00215 
00216             if (j == NULL) {
00217                 // This is for debugging - if you run the force update several times,
00218                 // you may change parameters each time and this retains those updates,
00219                 // which probably occured through attribute menus, between updates.
00220                 CForceJob *fj = new CForceJob(ds.GetTree(), ds);
00221 
00222                 if (retain_parms) {
00223                     fj->GetPS()->SetPhysicsParms(p);
00224 
00225 
00226 #ifdef ATTRIB_MENU_SUPPORT
00227                     CAttribMenuInstance::GetInstance().SynchToUserValue();
00228 #endif
00229 
00230                 }
00231 
00232                 m_Job.Reset(fj);        
00233                 m_JobID = CAppJobDispatcher::GetInstance().StartJob(*m_Job, "ThreadPool", *this, 1, true);
00234 
00235                 m_Timer.Start(100);
00236             }
00237         }
00238         // Unable to start a job - try to do physics in foreground
00239         catch (CAppJobException&) {
00240             m_UseMainThreadPhysics = true;
00241         }
00242     }
00243     else {
00244         if (!m_MainThreadPS) {
00245             m_MainThreadPS = new CPhyloTreePS(ds);
00246             // This makes the system end more quickly since the velocity threshold
00247             // below which we can stop is raised.
00248             m_MainThreadPS->SetVelocityThresholdK(0.2f);
00249         } else {
00250             m_MainThreadPS->Init(ds);
00251         }
00252 
00253         //m_Timer.Start(50); // no good for cgi...
00254         
00255         // This has to work for a batch, CGI version too - so there are
00256         // no progressive updates - we just want to iterate until it stabilizes
00257         // or we reach a maximum iteration count.
00258         for (int i=0; i<200 && !m_MainThreadPS->IsDone(); ++i)    
00259             x_SingleThreadPhysics();
00260 
00261         CBoundaryPoints boundary_pts;
00262         x_CalculateBoundary(m_pRoot, boundary_pts, false);
00263         ComputeViewingLimits(*m_pPane, false);
00264 
00265         // This is the rect for viewing limits used by cgi.
00266         m_RasterRect = m_pPane->GetModelLimitsRect();
00267 
00268         return;
00269     }
00270 }
00271 
00272 void CPhyloForce::RemoveCurrentDataSource()
00273 {
00274     IPhyloTreeRenderer::RemoveCurrentDataSource();
00275 
00276     try {       
00277         m_Timer.Stop();
00278 
00279         if (m_JobID != CAppJobDispatcher::eInvalidJobID) {
00280             CAppJobDispatcher& disp = CAppJobDispatcher::GetInstance();
00281             IAppJob::EJobState state = disp.GetJobState(m_JobID);
00282 
00283             if (state == IAppJob::eRunning) {
00284                 disp.CancelJob(m_JobID);
00285 
00286                 // Wait until job is really done (current iteration is finished)
00287                 // to move on:
00288                 int count = 0;
00289                 while (count++<20 && disp.GetJobState(m_JobID) == IAppJob::eRunning) {
00290                     wxMilliSleep(100);
00291                 }
00292             }
00293             else {
00294                 disp.DeleteJob(m_JobID);
00295             }
00296 
00297             m_JobID = CAppJobDispatcher::eInvalidJobID;
00298             m_Job.Reset();
00299         }
00300     }
00301     catch (CAppJobException&) {    
00302         _TRACE("Error deleting force layout job");
00303     }
00304 
00305     m_JobID = CAppJobDispatcher::eInvalidJobID;            
00306     m_Job.Reset();
00307 }
00308 
00309 bool CPhyloForce::Render(CGlPane& pane, CPhyloTreeDataSource& ds)
00310 {
00311     m_pPane     = &pane;
00312     m_DS        = &ds;
00313 
00314     // Is a job running? If so make sure we don't draw while the 
00315     // particle system is syncing with the graphics model.  Otherwise
00316     // just draw.
00317     if (m_JobID != CAppJobDispatcher::eInvalidJobID) {               
00318 
00319         CForceJob* j = m_Job.GetPointerOrNull();
00320         if (j != NULL ) {
00321 
00322             if (j->DataSynched() == CForceJob::eDataSynched) {
00323                 j->SetDataSynched(CForceJob::eRenderInProgress);
00324 
00325 #ifdef BUFFERED_RENDER
00326                 /// Need only to drop scale marker for force layout...
00327                 IPhyloTreeRenderer::Render(pane,ds);
00328 #else
00329                 x_Render(pane, ds);
00330 #endif
00331                 j->SetDataSynched(CForceJob::eDataSynched);
00332             }
00333             // Unable to render since force thread is busy synchrnizing 
00334             // the particle system data with the graphics data.
00335             else {
00336                 return false;
00337             }
00338         }
00339     }
00340     else {
00341 #ifdef BUFFERED_RENDER
00342         /// Need only to drop scale marker for force layout...
00343         IPhyloTreeRenderer::Render(pane,ds);
00344 #else
00345         x_Render(pane, ds);
00346 #endif
00347     }
00348 
00349     return true;
00350 }
00351 
00352 void  CPhyloForce::x_SingleThreadPhysics() 
00353 {
00354     if (!m_MainThreadPS)
00355         return;
00356 
00357     if (!m_MainThreadPS->IsDone()) {    
00358         for (int j=0; j<10; ++j) {        
00359             m_MainThreadPS->Update();      
00360         }
00361 
00362         m_MainThreadPS->UpdateAndSynch();     
00363     }
00364     else {
00365         m_Timer.Stop();
00366     }
00367 }
00368 
00369 void  CPhyloForce::x_Render(CGlPane& pane, CPhyloTreeDataSource& ds)
00370 {
00371     CRgbaColor bgColor(m_SL->SetColor(CPhyloTreeScheme::eTree,
00372                                     CPhyloTreeScheme::eBgColor));
00373 
00374     glClearColor(bgColor.GetRed(), bgColor.GetGreen(),
00375         bgColor.GetBlue(), bgColor.GetAlpha());
00376 
00377     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  
00378     
00379     pane.OpenOrtho();
00380 
00381     x_DrawBoundingAreas(ds.GetTree());
00382     x_DrawTree( ds.GetTree() );
00383     x_DrawNodes( ds.GetTree() );
00384 
00385     pane.Close();
00386 
00387     x_RenderSelection(pane);
00388 }
00389 
00390 void CPhyloForce::x_DrawTree(CPhyloTreeNode * node)
00391 {
00392     // drawing leaf node
00393     if (node->GetParent()){     
00394         x_RenderLine(node->GetParent()->GetValue().X(),
00395                      node->GetParent()->GetValue().Y(),
00396                      node->GetValue().X(), node->GetValue().Y(),
00397                      (**node).GetSelectedState(),
00398                      GetEdgeColor(node));
00399     }
00400     for(CPhyloTreeNode::TNodeList_I  it = node->SubNodeBeginEx();
00401         it != node->SubNodeEndEx(); it++ ){
00402             x_DrawTree(static_cast<CPhyloTreeNode*>(*it));
00403     }
00404 }
00405 
00406 
00407 void CPhyloForce::x_CalculateBoundary(CPhyloTreeNode * node, 
00408                                       CBoundaryPoints& parent_boundary_pts,
00409                                       bool compute_boundary)
00410 {
00411     if ((**node).GetBoundedDisplay() == IPhyGraphicsNode::eBounded)
00412         compute_boundary = true;
00413 
00414     CBoundaryPoints node_boundary_pts;
00415 
00416     if (!node->IsLeafEx()) {
00417         for(CPhyloTreeNode::TNodeList_I  it = node->SubNodeBeginEx();
00418             it != node->SubNodeEnd(); it++)  {
00419             CPhyloTreeNode* subnode = static_cast<CPhyloTreeNode*>(*it);
00420             x_CalculateBoundary(subnode, node_boundary_pts, compute_boundary);
00421         }
00422     }
00423 
00424     x_ComputeNodeBoundary(node, compute_boundary, node_boundary_pts, "ForceLayout");
00425 
00426     // Each node that computes a boundary has to add in the points (and text rectangles)
00427     // for all nodes below it in the tree
00428     if (compute_boundary) {
00429         parent_boundary_pts.AddBoundedPoints(node_boundary_pts);
00430     }
00431 }
00432 
00433 void CPhyloForce::StartRendering(bool b) 
00434 { 
00435     IPhyloTreeRenderer::StartRendering(b);
00436     
00437     if (!b) {
00438         CAppJobDispatcher& disp = CAppJobDispatcher::GetInstance();      
00439         disp.DeleteJob(m_JobID);
00440         m_Timer.Stop();
00441     }
00442 }
00443 
00444 
00445 /// handles "state changed" notification from CAppJobDispatcher
00446 void CPhyloForce::OnAppJobNotification(CEvent* evt)
00447 {
00448     CAppJobNotification* notn = dynamic_cast<CAppJobNotification*>(evt);
00449     _ASSERT(notn);
00450 
00451 
00452     IAppJob::EJobState state = IAppJob::eInvalid;
00453     int job_id = 0;
00454 
00455     if(notn) {
00456         job_id = notn->GetJobID();
00457         if(job_id) {
00458             state = notn->GetState();
00459         }
00460     }
00461    
00462     if (state != IAppJob::eRunning) {        
00463         // Only redraw if job completed normally - not if it was cancellled.
00464         if (state == IAppJob::eCompleted) {
00465             CBoundaryPoints boundary_pts;
00466             x_CalculateBoundary(m_pRoot, boundary_pts, false);
00467             ComputeViewingLimits(*m_pPane, false);
00468             if (m_pHost != NULL)
00469                 m_pHost->HMGH_UpdateLimits(true);
00470     
00471             x_Render(*m_pPane, *m_DS);
00472         }
00473 
00474         // Stop timer if job is not running.  Can't just use job status since
00475         // when layout it called it stops the current job but then immediately
00476         // starts a new one, so this can be called from the cancelled job
00477         // even though the timer is needed for the newly created job.
00478         if (job_id == m_JobID) {
00479             m_Timer.Stop();
00480             m_JobID = CAppJobDispatcher::eInvalidJobID;
00481             m_Job.Reset();
00482         }           
00483     }
00484 }
00485 
00486 void CPhyloForce::OnTimer(wxTimerEvent& /* evt */)
00487 {
00488     // If there is a valid (deform) job running and it has 
00489     // synchronized the visual data with the physics data
00490     // since the last time called, recompute the tree boundaries
00491     // and redraw.
00492     if (!m_UseMainThreadPhysics &&
00493         m_JobID != CAppJobDispatcher::eInvalidJobID) {
00494         
00495         CAppJobDispatcher& disp = CAppJobDispatcher::GetInstance();
00496         IAppJob::EJobState state = disp.GetJobState(m_JobID);
00497 
00498         CForceJob* j = m_Job.GetPointerOrNull();
00499         if (j != NULL ) {
00500             CMutexGuard guard(j->GetMutex());
00501             if (state == IAppJob::eRunning && 
00502                 j->DataSynched() == CForceJob::eDataRefreshed) {
00503                     j->SetDataSynched(CForceJob::eRenderInProgress);
00504                     CBoundaryPoints boundary_pts;
00505                     x_CalculateBoundary(m_pRoot, boundary_pts, false);
00506                     ComputeViewingLimits(*m_pPane, false);
00507                     m_pHost->HMGH_UpdateLimits(true);
00508                     j->SetDataSynched(CForceJob::eDataSynched);
00509             }
00510         }
00511         else if (m_UseMainThreadPhysics) {
00512             x_SingleThreadPhysics();
00513     
00514             CBoundaryPoints boundary_pts;
00515             x_CalculateBoundary(m_pRoot, boundary_pts, false);
00516             ComputeViewingLimits(*m_pPane, false);
00517             if (m_pHost != NULL)
00518                 m_pHost->HMGH_UpdateLimits(true);
00519         }
00520     }
00521 }
00522 
00523 
00524 ///////////////////////////////////////////////////////////////////////////////
00525 //
00526 // Background job for running force update on a separate thread
00527 //
00528 ///////////////////////////////////////////////////////////////////////////////
00529 CForceJob::CForceJob(CPhyloTreeNode * node, CPhyloTreeDataSource& ds)
00530 : m_Node(node)
00531 , m_PS(NULL)
00532 , m_DataSynched(eDataSynched)
00533 , m_UpdatesSincLastSync(0)
00534 {
00535     m_PS = new CPhyloTreePS(ds);
00536 }
00537 
00538 CForceJob::~CForceJob()
00539 {
00540     delete m_PS;
00541     m_PS =  NULL;
00542 }
00543 
00544 IAppJob::EJobState CForceJob::Run()
00545 {
00546     // Loop a large number of times.  Ideally, system will stop when
00547     // velocity drops (checked in x_Calculate)
00548     for (int i=0; i<20000 && !Cancelled(); i++) 
00549         x_Calculate();
00550 
00551     return eCompleted;    
00552 }
00553 
00554 void CForceJob::x_Calculate()
00555 {
00556     if (Cancelled()) {
00557         return;
00558     }
00559 
00560     // updates should be timer based, but make sure that
00561     // a minimum number happen (otherwise it will slow down
00562     // progress of the particle system)
00563     double i = 0.0f;
00564 
00565     CStopWatch sw;
00566     sw.Start();
00567 
00568     // Update the system a fixed number of times or until 0.5 seconds
00569     // has passed.  
00570     while (i * sw.Elapsed() < 1.0) {        
00571         m_PS->Update(); 
00572         i += 2.0;
00573         ++m_UpdatesSincLastSync;
00574     }
00575 
00576     // Do a special update that synchronizes the tree data with the particle
00577     // system.  To keep rendering (kind of ) smooth during updates of larger
00578     // trees, don't do this if there were less than a (low) number of iterations
00579     // since synch blocks rendering.
00580     if (!Cancelled() && 
00581         m_DataSynched != eRenderInProgress &&
00582         m_UpdatesSincLastSync > 5) {
00583             m_UpdatesSincLastSync = 0;
00584             CMutexGuard guard(m_Mutex);
00585             m_DataSynched = eDataNotSynched;
00586             m_PS->UpdateAndSynch();
00587             m_DataSynched = eDataRefreshed;
00588 
00589             /// If velocity has dropped low enough, stop system.
00590             if (m_PS->IsDone())
00591                 RequestCancel();
00592     }                  
00593 }
00594 
00595 void CForceJob::RequestCancel()
00596 {
00597     CMutexGuard guard(m_Mutex);
00598     m_StopRequested = true;
00599 }
00600 
00601 CForceJob::TDataSynchStatus CForceJob::DataSynched()
00602 {
00603     return m_DataSynched;
00604 }
00605 
00606 void CForceJob::SetDataSynched(TDataSynchStatus s)
00607 {
00608     CMutexGuard guard(m_Mutex);
00609     m_DataSynched = s;
00610 }
00611 
00612 CConstIRef<IAppJobProgress> CForceJob::GetProgress()
00613 {
00614     return CConstIRef<IAppJobProgress>(new CAppJobProgress(1.0, "Finished"));
00615 }
00616 
00617 CRef<CObject> CForceJob::GetResult()
00618 {
00619     CMutexGuard guard(m_Mutex);
00620     CRef<CObject> result(new CObject());
00621     return result;
00622 }
00623 
00624 CConstIRef<IAppJobError> CForceJob::GetError()
00625 {
00626     return CConstIRef<IAppJobError>(new CAppJobError("No errors"));
00627 }
00628 
00629 string CForceJob::GetDescr() const
00630 {
00631     return "Building Force Layout";
00632 }
00633 
00634 void CForceJob::x_CheckCancelled() const
00635 {
00636     CMutexGuard guard(m_Mutex);
00637     if (Cancelled())
00638         NCBI_THROW(CException, eUnknown, "Job Cancelled");
00639 }
00640 
00641 void CPhyloForce::OnAppJobProgress(CEvent* evt)
00642 {
00643     CAppJobNotification* notn =
00644         dynamic_cast<CAppJobNotification*>(evt);
00645     _ASSERT(notn);
00646 
00647     if(notn) {      
00648 
00649         // Could redraw on this with code below, but we use a separate timer
00650         // since this is called to infrequently to be helpful 
00651         // (only called around 1/sec)
00652         /*       
00653         CForceJob* j = m_Job.GetPointerOrNull();
00654         if (j != NULL) {
00655 
00656         CMutexGuard guard(j->GetMutex());
00657 
00658         CBoundaryPoints boundary_pts;
00659         x_CalculateBoundary(m_pRoot, boundary_pts, false);
00660         ComputeViewingLimits(*m_pPane, false);
00661         m_pHost->HMGH_UpdateLimits(true);
00662         //x_GetParent()->GetPort().SetModelLimitsRect(m_MatrixPane.GetModelLimitsRect());
00663         //x_GetParent()->GetPort().SetVisibleRect(m_MatrixPane.GetVisibleRect());
00664         m_pPane->OpenOrtho();
00665 
00666         x_DrawBoundingAreas(m_DS->GetTree());
00667         x_DrawTree( m_DS->GetTree() );
00668         x_DrawNodes( m_DS->GetTree() );
00669 
00670         m_pPane->Close();
00671         }
00672         */
00673     }
00674     
00675 }
00676 
00677 
00678 
00679 
00680 END_NCBI_SCOPE
Modified on Wed May 23 13:10:06 2012 by modify_doxy.py rev. 337098