00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <ncbi_pch.hpp>
00033 #include <corelib/ncbistd.hpp>
00034
00035 #include <gui/utils/event_handler.hpp>
00036
00037 #include <algorithm>
00038
00039
00040 BEGIN_NCBI_SCOPE
00041
00042
00043
00044
00045
00046 CEventHandler::CEventHandler()
00047 {
00048 }
00049
00050
00051 CEventHandler::~CEventHandler()
00052 {
00053 x_DeclareDead();
00054
00055 #ifdef _DEBUG
00056
00057
00058
00059 TPools::iterator iter = m_Pools.find(ePool_Default);
00060 if (iter != m_Pools.end()) {
00061 NON_CONST_ITERATE (TListeners, it, iter->second) {
00062 if (*it) {
00063 (*it)->RemoveListener(this);
00064 }
00065 }
00066 }
00067 m_Pools.clear();
00068 #endif
00069 }
00070
00071
00072 void CEventHandler::x_DeclareDead()
00073 {
00074
00075 if(m_Queue) {
00076 m_Queue->DeclareDead(this);
00077 }
00078 }
00079
00080
00081 SEvtMapEntry defaultUpdateEntry = {CEvent::eEvent_CommandUpdate, "", 0, 0, NULL};
00082
00083
00084
00085 const SEvtMapEntry* FindEventMapEntry(const SEvtMap* pMap,
00086 CEvent::TEventClass cls,
00087 CEvent::TEventTypeInfo tif,
00088 CEvent::TEventID CmdID)
00089 {
00090 const SEvtMapEntry* pEntry = 0;
00091 const SEvtMapEntry* pUpdateEntry = 0;
00092
00093 while(pMap) {
00094 for (pEntry = pMap->entries; pEntry->id != CEvent::eEvent_InvalidID; ++pEntry) {
00095
00096 bool cmd_between = (CmdID >= pEntry->id && CmdID <= pEntry->last_id);
00097 bool typeinfo_safe = (strcmp(tif, pEntry->type_info) == 0);
00098 bool class_safe = (cls == pEntry->evt_class);
00099 bool is_cmd = (cls == CEvent::eEvent_Command) ||
00100 (cls == CEvent::eEvent_CommandUpdate);
00101
00102 if (cmd_between && (typeinfo_safe || is_cmd) && class_safe) {
00103 return pEntry;
00104 }
00105
00106
00107
00108 if (cmd_between && typeinfo_safe &&
00109 (cls == CEvent::eEvent_CommandUpdate) && (pEntry->evt_class == CEvent::eEvent_Command)) {
00110 pUpdateEntry = &defaultUpdateEntry;
00111 }
00112 }
00113 pMap = pMap->base_map;
00114 }
00115 return pUpdateEntry;
00116 }
00117
00118
00119
00120
00121 const SEvtMap CEventHandler::sm_EvtMap =
00122 {
00123 NULL,
00124 &CEventHandler::sm_EvtMapEntries[0]
00125 };
00126
00127
00128 const SEvtMap* CEventHandler::GetEventMap() const
00129 {
00130 return &CEventHandler::sm_EvtMap;
00131 }
00132
00133 const SEvtMapEntry CEventHandler::sm_EvtMapEntries[] =
00134 {
00135 { CEvent::eEvent_Message, typeid(void).name(),
00136 CEvent::eEvent_InvalidID, CEvent::eEvent_InvalidID, 0 }
00137 };
00138
00139
00140 void CEventHandler::AddListener(CEventHandler* listener, int pool)
00141 {
00142 if(listener) {
00143 if(pool != ePool_Default) {
00144 x_AddListenerToPool(listener, ePool_Default);
00145 }
00146 x_AddListenerToPool(listener, pool);
00147 } else {
00148 _TRACE("CEventHandler::AddListener(): NULL listener");
00149 return;
00150 }
00151 }
00152
00153
00154 void CEventHandler::x_AddListenerToPool(CEventHandler* listener, int pool_name)
00155 {
00156 _ASSERT(listener);
00157
00158 TListeners& pool = m_Pools[pool_name];
00159 TListeners::iterator it = std::find(pool.begin(), pool.end(), listener);
00160 if(it == pool.end()) {
00161 pool.push_back(listener);
00162 }
00163 }
00164
00165
00166 void CEventHandler::RemoveListener(CEventHandler* listener)
00167 {
00168 if(listener) {
00169 for(TPools::iterator it = m_Pools.begin(); it != m_Pools.end(); ) {
00170 TListeners& pool = it->second;
00171 TListeners::iterator it_lst = std::find(pool.begin(), pool.end(), listener);
00172 if(it_lst != pool.end()) {
00173 pool.erase(it_lst);
00174 }
00175 if(pool.empty()) {
00176 TPools::iterator it_del = it;
00177 ++it;
00178 m_Pools.erase(it_del);
00179 } else {
00180 ++it;
00181 }
00182 }
00183 } else {
00184 _TRACE("CEventHandler::RemoveListener(): NULL listener");
00185 return;
00186 }
00187 }
00188
00189
00190 void CEventHandler::RemoveAllListeners(void)
00191 {
00192 m_Pools.clear();
00193 }
00194
00195
00196 bool CEventHandler::HasListener(CEventHandler* listener, int pool_name) const
00197 {
00198 if(listener != NULL) {
00199 TPools::const_iterator it_pool = m_Pools.find(pool_name);
00200 if(it_pool != m_Pools.end()) {
00201 const TListeners& pool = it_pool->second;
00202 TListeners::const_iterator it = std::find(pool.begin(), pool.end(), listener);
00203 return (it != pool.end());
00204 }
00205 }
00206 return false;
00207 }
00208
00209
00210 const CEventHandler::TListeners* CEventHandler::GetListeners(int pool_name) const
00211 {
00212 TPools::const_iterator it_pool = m_Pools.find(pool_name);
00213 return (it_pool != m_Pools.end()) ? &it_pool->second : NULL;
00214 }
00215
00216
00217 static const char* kOnEventException = "CEventHandler::OnEvent() ";
00218 static const char* kDispatchException = "CEventHandler::Dispatch() ";
00219
00220 bool CEventHandler::OnEvent(CEvent * evt)
00221 {
00222 _ASSERT(evt);
00223 evt->Visit(this);
00224
00225 try {
00226 const CEvent::TEventClass cls = evt->GetEventClass();
00227 CEvent::TEventTypeInfo info = evt->GetTypeInfo();
00228 CEvent::TEventID id = evt->GetID();
00229
00230 const SEvtMapEntry* pEntry =
00231 FindEventMapEntry(GetEventMap(), cls, info, id);
00232
00233 if (pEntry) {
00234 switch (pEntry->evt_class) {
00235 case CEvent::eEvent_Command:
00236 if (pEntry->handler){
00237 if (pEntry->last_id != pEntry->id) {
00238 FCommandRangeHandler handler =
00239 (FCommandRangeHandler) pEntry->handler;
00240 (this->*handler)(evt->GetID());
00241 } else {
00242 FCommandHandler handler =
00243 (FCommandHandler) pEntry->handler;
00244 (this->*handler)();
00245 }
00246 return true;
00247 }
00248 break;
00249
00250 case CEvent::eEvent_CommandUpdate:
00251
00252 if (pEntry->handler) {
00253
00254 FCommandUpdateHandler handler =
00255 (FCommandUpdateHandler) pEntry->handler;
00256 (this->*handler)(evt->GetAttachment());
00257 }
00258 return true;
00259
00260 default:
00261 if (pEntry->handler) {
00262 FEventHandler handler = pEntry->handler;
00263 (this->*handler)(evt);
00264 return true;
00265 }
00266 break;
00267 }
00268 }
00269 }
00270 catch(CException& e) {
00271 ERR_POST(kOnEventException << e.GetMsg());
00272 }
00273 catch(std::exception& e) {
00274 ERR_POST(kOnEventException << e.what());
00275 }
00276 #ifndef _DEBUG
00277 catch(...) {
00278 ERR_POST(kOnEventException << " unknown exception");
00279 }
00280 #endif
00281 return false;
00282 }
00283
00284
00285 bool CEventHandler::Dispatch(CEvent* evt, EDispatch disp_how, int pool)
00286 {
00287 _ASSERT(evt);
00288 bool handled = false;
00289
00290 try {
00291 TPools::iterator iter = m_Pools.find(pool);
00292 if(iter == m_Pools.end()) {
00293 return false;
00294 }
00295
00296 switch (disp_how) {
00297 case eDispatch_SelfOnly:
00298 break;
00299
00300 case eDispatch_AllHandlers:
00301 ITERATE(TListeners, listener, iter->second) {
00302 CEventHandler* handler = *listener;
00303 if(evt->Visit(handler)) {
00304 handled |= handler->Send(evt, disp_how, pool);
00305 }
00306 }
00307 break;
00308
00309 case eDispatch_FirstHandler:
00310 ITERATE(TListeners, listener, iter->second){
00311 CEventHandler* handler = *listener;
00312 if(evt->Visit(handler)) {
00313 handled = handler->Send(evt, disp_how, pool);
00314 if(handled) {
00315 return true;
00316 }
00317 }
00318 }
00319 break;
00320 }
00321 }
00322 catch(CException& e) {
00323 ERR_POST(kDispatchException << e.GetMsg());
00324 }
00325 catch(std::exception& e) {
00326 ERR_POST(kDispatchException << e.what());
00327 }
00328 #ifndef _DEBUG
00329 catch(...) {
00330 ERR_POST(kDispatchException << " unknown exception");
00331 }
00332 #endif
00333 return handled;
00334 }
00335
00336
00337 bool CEventHandler::Send(CEvent* evt, EDispatch disp_how, int pool_name)
00338 {
00339 _ASSERT(evt);
00340
00341 bool handled = OnEvent(evt);
00342
00343 switch (disp_how) {
00344 case eDispatch_SelfOnly:
00345 break;
00346
00347 case eDispatch_AllHandlers:
00348 handled |= Dispatch(evt, disp_how, pool_name);
00349 break;
00350
00351 case eDispatch_FirstHandler:
00352 if( ! handled) {
00353 handled = Dispatch(evt, disp_how, pool_name);
00354 }
00355 break;
00356 }
00357 return handled;
00358 }
00359
00360
00361 bool CEventHandler::Send(CEvent* evt, int pool_name)
00362 {
00363 return Send(evt, eDispatch_Default, pool_name);
00364 }
00365
00366
00367 void CEventHandler::Post(CRef<CEvent> evt, EDispatch disp_how, int pool_name)
00368 {
00369 _ASSERT(evt);
00370 if( ! m_Queue) {
00371 m_Queue = CPostQueue::GetInstance();
00372 }
00373
00374 SPostRequest* req = new SPostRequest();
00375 req->m_Target = this;
00376 req->m_Event = evt;
00377 req->m_DispHow = disp_how;
00378 req->m_PoolName = pool_name;
00379
00380 m_Queue->Post(req);
00381 }
00382
00383
00384 void CEventHandler::FireEvent(CEvent* evt, EDispatch disp_how, int pool_name)
00385 {
00386 LOG_POST(Warning << "CEventHandler::FireEvent() - is deprecated,"
00387 << "use Send(), Dispatch() or Post() instead");
00388 Send(evt, disp_how, pool_name);
00389 }
00390
00391
00392 bool CEventHandler::OnCommand(const TCmdID CmdID)
00393 {
00394 CEvent evt(CEvent::eEvent_Command, CmdID);
00395 return Send(&evt, eDispatch_FirstHandler);
00396 }
00397
00398
00399 bool CEventHandler::HandlePostRequest()
00400 {
00401 CRef<CPostQueue> queue = CPostQueue::GetInstance();
00402 return queue->ExecuteFirstRequest();
00403 }
00404
00405
00406
00407 void CEventHandler::ClearPostQueue()
00408 {
00409 CRef<CPostQueue> queue = CPostQueue::GetInstance();
00410 queue->Clear();
00411 }
00412
00413
00414 void CEventHandler::DestroyPostQueue()
00415 {
00416 CPostQueue::DestroyInstance();
00417 }
00418
00419
00420 CEventHandler::FOnPostCallback CEventHandler::sm_PostCallback = NULL;
00421
00422
00423 void CEventHandler::SetPostCallback(FOnPostCallback callback)
00424 {
00425 sm_PostCallback = callback;
00426 }
00427
00428
00429
00430
00431 CRef<CEventHandler::CPostQueue> CEventHandler::CPostQueue::sm_PostQueue;
00432
00433 CRef<CEventHandler::CPostQueue> CEventHandler::CPostQueue::GetInstance()
00434 {
00435 if( ! sm_PostQueue) {
00436 static CMutex s_CreateQueueMutex;
00437 TMutexGuard lock(s_CreateQueueMutex);
00438
00439
00440 if( ! sm_PostQueue) {
00441 sm_PostQueue.Reset(new CPostQueue());
00442 }
00443 }
00444 return sm_PostQueue;
00445 }
00446
00447
00448 void CEventHandler::CPostQueue::DestroyInstance()
00449 {
00450 sm_PostQueue.Reset();
00451 }
00452
00453
00454 CEventHandler::CPostQueue::~CPostQueue()
00455 {
00456 CMutexGuard guard(m_Mutex);
00457
00458 NON_CONST_ITERATE(THandlerToCount, it, m_AliveTargets) {
00459 it->first->m_Queue.Reset();
00460 }
00461
00462 m_AliveTargets.clear();
00463 m_Queue.clear();
00464 }
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476 void CEventHandler::CPostQueue::Post(SPostRequest* req)
00477 {
00478 if(req) {
00479
00480
00481
00482
00483
00484
00485
00486 {
00487 CMutexGuard guard(m_Mutex);
00488
00489 CEventHandler* target = req->m_Target;
00490 THandlerToCount::iterator it = m_AliveTargets.find(target);
00491 if(it == m_AliveTargets.end()) {
00492 m_AliveTargets[target] = 1;
00493 } else {
00494 it->second++;
00495 }
00496
00497 m_Queue.push_back(req);
00498
00499 }
00500 if(sm_PostCallback) {
00501 (*sm_PostCallback)();
00502 }
00503
00504
00505
00506 #ifdef _DEBUG
00507 size_t size = m_Queue.size();
00508 if(size > 1000 && (size % 100) == 0) {
00509 LOG_POST(Error << "CEventHandler::CPostQueue::Post() - "
00510 "queue is too long, size = " << size);
00511 }
00512 #endif
00513 }
00514 }
00515
00516
00517
00518 bool CEventHandler::CPostQueue::ExecuteFirstRequest()
00519 {
00520 CRef<CObject> target_guard;
00521
00522
00523 AutoPtr<SPostRequest> request;
00524
00525 {{
00526 #if 0
00527 m_ExecCounter++;
00528 if(m_ExecCounter % kSampling == 0) {
00529 double t = m_ExecTimer.Elapsed();
00530 LOG_POST("CPostQueue::ExecuteFirstRequest() - " << m_ExecCounter << " calls, "
00531 << (kSampling / t) << " calls per second, "
00532 << (m_ExecEventCounter / t) << " events executed per second");
00533
00534 m_ExecTimer.Restart();
00535 m_ExecEventCounter = 0;
00536 }
00537 #endif
00538
00539
00540 TMutexGuard guard(m_Mutex);
00541
00542 if (!m_Queue.empty() ) {
00543
00544 request = m_Queue.front();
00545 m_Queue.pop_front();
00546
00547 THandlerToCount::iterator it = m_AliveTargets.find(request->m_Target);
00548 if(it != m_AliveTargets.end()) {
00549
00550 target_guard.Reset(dynamic_cast<CObject*>(request->m_Target));
00551
00552 if(it->second == 1) {
00553
00554 m_AliveTargets.erase(it);
00555 } else {
00556 it->second--;
00557 }
00558 } else {
00559 request.reset(NULL);
00560 }
00561 }
00562
00563
00564
00565 }}
00566
00567 if(request.get()) {
00568
00569
00570
00571
00572
00573
00574 CEventHandler* target = request->m_Target;
00575 CEvent* evt = request->m_Event.GetPointer();
00576
00577 _ASSERT(target && evt);
00578
00579
00580 target->Send(evt, request->m_DispHow, request->m_PoolName);
00581 return true;
00582 }
00583 return false;
00584 }
00585
00586
00587 void CEventHandler::CPostQueue::DeclareDead(CEventHandler* handler)
00588 {
00589 if(handler) {
00590 CMutexGuard guard(m_Mutex);
00591 m_AliveTargets.erase(handler);
00592 }
00593 }
00594
00595
00596 void CEventHandler::CPostQueue::Clear()
00597 {
00598 CMutexGuard guard(m_Mutex);
00599 m_Queue.clear();
00600 m_AliveTargets.clear();
00601 }
00602
00603
00604 END_NCBI_SCOPE
00605
00606