暫無描述

IvrFlow.cpp 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. #include "StdAfx.h"
  2. #include "IvrFlow.h"
  3. #include "CellBase.h"
  4. #include "FlowTemplate.h"
  5. #include "MsgCenter.h"
  6. #include "NetworkIvr.h"
  7. #include "CellTimer.h"
  8. IMPLEMENT_DYNAMIC(CIvrFlow, CWnd)
  9. CIvrFlow::CIvrFlow(int Id) : m_Id(Id), m_State(IVR_FLOW_STATE_FREE), m_IsHangUp(false), m_IsNetLinkUp(false), m_AssoCallId(0), m_pFlowTemplate(NULL), m_pCurrentCell(NULL)
  10. {
  11. CreateEx(0, AfxRegisterWndClass(CS_GLOBALCLASS), "", 0, 0, 0, 0, 0, 0, 0);
  12. }
  13. CIvrFlow::~CIvrFlow(void)
  14. {
  15. __release();
  16. DestroyWindow();
  17. }
  18. BEGIN_MESSAGE_MAP(CIvrFlow, CWnd)
  19. ON_WM_TIMER()
  20. END_MESSAGE_MAP()
  21. /*****************************************************************
  22. **【函数名称】 __release
  23. **【函数功能】 释放资源
  24. **【参数】
  25. **【返回值】
  26. ****************************************************************/
  27. void CIvrFlow::__release( void )
  28. {
  29. if(m_pCurrentCell != NULL)
  30. __deleteCurrentCell();
  31. m_VarTable.RemoveAll();
  32. }
  33. /*****************************************************************
  34. **【函数名称】 __clearFlow
  35. **【函数功能】 流程结束时对流程进行清理
  36. **【参数】
  37. **【返回值】
  38. ****************************************************************/
  39. void CIvrFlow::__clearFlow( void )
  40. {
  41. m_AssoCallId = 0;
  42. m_IsHangUp = false;
  43. m_State = IVR_FLOW_STATE_FREE;
  44. __release();
  45. CMsgCenter::GetInstance().pushMsg(IVR_MSG_FLOW_STATE_UPDAET, reinterpret_cast<const PARAM>(m_Id));
  46. CMsgCenter::GetInstance().pushMsg(IVR_MSG_FLOW_CELL_UPDATE, reinterpret_cast<const PARAM>(m_Id));
  47. if(m_IsNetLinkUp && m_pFlowTemplate != NULL && m_pFlowTemplate->type() == FLOW_AUTO)
  48. start();
  49. }
  50. /*****************************************************************
  51. **【函数名称】 __onTimerTimeOut
  52. **【函数功能】 流程节点最大执行时间超时处理函数
  53. **【参数】
  54. **【返回值】
  55. ****************************************************************/
  56. void CIvrFlow::__onTimerTimeOut( void )
  57. {
  58. ASSERT(m_pCurrentCell != NULL);
  59. ASSERT(m_pFlowTemplate != NULL);
  60. if(m_pFlowTemplate->type() != FLOW_SUB) // 执行子流程时不上报流程结束
  61. {
  62. CPduEntity cmdFlowEnd(PDU_CMD_IVR_END);
  63. cmdFlowEnd.SetDataInt(1, m_Id);
  64. CNetworkIvr::GetInstance().send(cmdFlowEnd);
  65. }
  66. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{FLow}: 节点[%s]超过最大执行时间, 流程[%d]将被释放"), m_pCurrentCell->name(), m_Id);
  67. // 2022-07-28 钉钉推送
  68. CWarningPush::getInstance()->pushWarningInfo("IVR-流程超时提醒.txt");
  69. __clearFlow();
  70. }
  71. /*****************************************************************
  72. **【函数名称】 __onNextCellNull
  73. **【函数功能】 当下个节点为空的处理
  74. **【参数】
  75. **【返回值】
  76. ****************************************************************/
  77. void CIvrFlow::__onNextCellNull( int NullCellPos )
  78. {
  79. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{FLow}: 查找节点[%d]失败, 流程[%d]将被释放"), NullCellPos, m_Id);
  80. CPduEntity CmdHangUp(PDU_CMD_IVR_HANGUP);
  81. CmdHangUp.SetDataInt(1, m_Id);
  82. CNetworkIvr::GetInstance().send(CmdHangUp);
  83. __clearFlow();
  84. }
  85. /*****************************************************************
  86. **【函数名称】 __deleteCurrentCell
  87. **【函数功能】 删除当前节点
  88. **【参数】
  89. **【返回值】
  90. ****************************************************************/
  91. void CIvrFlow::__deleteCurrentCell( void )
  92. {
  93. ASSERT(m_pCurrentCell != NULL);
  94. if(m_pCurrentCell->maxWaitingTime() > 0)
  95. KillTimer((long)m_pCurrentCell);
  96. delete m_pCurrentCell;
  97. m_pCurrentCell = NULL;
  98. }
  99. /*****************************************************************
  100. **【函数名称】 start
  101. **【函数功能】 开始执行流程
  102. **【参数】 pFlowTemp: 流程模板
  103. **【返回值】 下一个节点编号
  104. ****************************************************************/
  105. int CIvrFlow::start( CFlowTemplate* pFlowTemp /*= NULL*/, int StartPos/* = 1*/ )
  106. {
  107. if(pFlowTemp != NULL)
  108. m_pFlowTemplate = pFlowTemp;
  109. if(m_pFlowTemplate == NULL)
  110. {
  111. ASSERT(FALSE);
  112. return CELL_OP_ERROR;
  113. }
  114. CString CellName = "";
  115. switch(m_pFlowTemplate->type())
  116. {
  117. case FLOW_NORMAL:
  118. case FLOW_SUB:
  119. CellName = CELL_NAME_START;
  120. break;
  121. case FLOW_AUTO:
  122. CellName = CELL_NAME_TIMER;
  123. break;
  124. }
  125. int Pos = m_pFlowTemplate->getCellPos(CellName);
  126. if(Pos < 1)
  127. {
  128. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Flow}: 执行流程[%d]时未找到起始节点, Template = %s"), m_Id, m_pFlowTemplate->name());
  129. return CELL_OP_ERROR;
  130. }
  131. Pos = (StartPos == 1) ? Pos : StartPos;
  132. m_State = IVR_FLOW_STATE_RUN;
  133. CMsgCenter::GetInstance().pushMsg(IVR_MSG_FLOW_STATE_UPDAET, reinterpret_cast<const PARAM>(m_Id));
  134. // 如果是自动流程,但是还未连接至CTI则等待,直到连至CTI后执行
  135. if(m_pFlowTemplate->type() == FLOW_AUTO && !m_IsNetLinkUp)
  136. {
  137. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Flow}: 自动流程[%d]挂起, 等候与CTI连接, Template = %s"), m_Id, m_pFlowTemplate->name());
  138. return CELL_OP_WAIT_FOR;
  139. }
  140. return next(Pos);
  141. }
  142. /*****************************************************************
  143. **【函数名称】 next
  144. **【函数功能】 执行流程下一结点
  145. **【参数】 NextPos:下一结点编号
  146. **【返回值】 后一个节点编号
  147. ****************************************************************/
  148. int CIvrFlow::next( int NextPos )
  149. {
  150. ASSERT(m_pFlowTemplate != NULL);
  151. if(m_pFlowTemplate == NULL)
  152. {
  153. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Flow}: 执行流程[%d]后续节点时,流程模板为空"), m_Id);
  154. return CELL_OP_ERROR;
  155. }
  156. int NextCellPos = NextPos;
  157. m_pCurrentCell = m_pFlowTemplate->findCell(NextCellPos);
  158. if(m_pCurrentCell == NULL)
  159. {
  160. __onNextCellNull(NextCellPos);
  161. return NextCellPos;
  162. }
  163. while(m_pCurrentCell != NULL)
  164. {
  165. m_pCurrentCell->assoIvrFlow() = this;
  166. CMsgCenter::GetInstance().pushMsg(IVR_MSG_FLOW_CELL_UPDATE, reinterpret_cast<const PARAM>(m_Id));
  167. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Flow}: 流程[%d]开始执行节点[%s]"), m_Id, m_pCurrentCell->name());
  168. NextCellPos = m_pCurrentCell->operate();
  169. if(NextCellPos > 0)
  170. {
  171. __deleteCurrentCell();
  172. m_pCurrentCell = m_pFlowTemplate->findCell(NextCellPos);
  173. if(m_pCurrentCell == NULL)
  174. {
  175. __onNextCellNull(NextCellPos);
  176. break;
  177. }
  178. }
  179. else if(NextCellPos == CELL_OP_END)
  180. {
  181. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Flow}: 流程[%d]执行模板[%s]结束"), m_Id, m_pFlowTemplate->name());
  182. __clearFlow();
  183. break;
  184. }
  185. else if(NextCellPos == CELL_OP_WAIT_FOR)
  186. {
  187. if(m_pCurrentCell->maxWaitingTime() > 0)
  188. SetTimer(reinterpret_cast<long>(m_pCurrentCell), m_pCurrentCell->maxWaitingTime() * 1000, NULL);
  189. break;
  190. }
  191. else if(NextCellPos == CELL_OP_ERROR)
  192. {
  193. CPduEntity cmdIVREnd(PDU_CMD_IVR_END);
  194. cmdIVREnd.SetDataInt(1, m_Id);
  195. if(!CNetworkIvr::GetInstance().send(cmdIVREnd))
  196. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING, _T("{Flow}: 流程[%d]执行节点[%s]时发生异常, 且通知Cti失败, 流程将被释放"), m_Id, m_pCurrentCell->name());
  197. else
  198. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING, _T("{Flow}: 流程[%d]执行节点[%s]时发生异常, 已成功通知Cti, 流程将被释放"), m_Id, m_pCurrentCell->name());
  199. __clearFlow();
  200. break;
  201. }
  202. else if(NextCellPos == CELL_OP_SEND_ERROR)
  203. {
  204. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING, _T("{Flow}: 流程[%d]执行节点[%s]时, 向Cti传送数据失败, 流程将被释放"), m_Id, m_pCurrentCell->name());
  205. __clearFlow();
  206. break;
  207. }
  208. }
  209. return NextCellPos;
  210. }
  211. /*****************************************************************
  212. **【函数名称】 procPdu
  213. **【函数功能】 处理PDU消息
  214. **【参数】 pPduEntity:PDU消息
  215. **【返回值】 下一个节点编号
  216. ****************************************************************/
  217. int CIvrFlow::procPdu( CPduEntity* pPduEntity )
  218. {
  219. ASSERT(pPduEntity != NULL);
  220. bool HangupFlag = false;
  221. if(pPduEntity->GetCmdType() == PDU_CMD_CTI_IVR_HANGUP && !pPduEntity->GetIsExecReturn())
  222. HangupFlag = true;
  223. if(m_pCurrentCell != NULL)
  224. {
  225. int NextCellPos = m_pCurrentCell->onOpResultReturn(pPduEntity);
  226. if(HangupFlag)
  227. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Flow}: 流程[%d]收到挂机消息, 流程当前节点为[%s], Note = %s, 下一节点[%d]"),
  228. m_Id, m_pCurrentCell->name(), m_pCurrentCell->note(), NextCellPos);
  229. else
  230. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Flow}: 流程[%d]收到节点操作的返回结果, 流程当前节点为[%s], Note = %s, 下一节点[%d]"),
  231. m_Id, m_pCurrentCell->name(), m_pCurrentCell->note(), NextCellPos);
  232. if(NextCellPos > 0) // NextCellPos为可用的下一结点编号
  233. {
  234. __deleteCurrentCell();
  235. return next(NextCellPos);
  236. }
  237. else if(NextCellPos == CELL_OP_WAIT_FOR)
  238. {
  239. if(HangupFlag) m_IsHangUp = true;
  240. return CELL_OP_WAIT_FOR;
  241. }
  242. else if(NextCellPos == CELL_OP_END)
  243. {
  244. ASSERT(FALSE);
  245. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Flow}: 流程[%d]执行模板[%s]结束"), m_Id, m_pFlowTemplate->name());
  246. __clearFlow();
  247. return CELL_OP_END;
  248. }
  249. else // CELL_OP_ERROR或者CELL_OP_SEND_ERROR的情况
  250. {
  251. __clearFlow();
  252. return CELL_OP_ERROR;
  253. }
  254. }
  255. else
  256. {
  257. if(HangupFlag)
  258. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Flow}: 流程[%d]收到挂机消息, 但是当前执行节点为空, 流程将被释放"), m_Id);
  259. else
  260. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Flow}: 流程[%d]收到节点操作的返回结果, 但是执行节点却为空, 流程将被释放"), m_Id);
  261. __clearFlow();
  262. return CELL_OP_ERROR;
  263. }
  264. }
  265. /*****************************************************************
  266. **【函数名称】 onNetLinkUpdated
  267. **【函数功能】 响应网络链接成功或断开事件
  268. **【参数】 IsConnect:网络链接成功或断开
  269. **【返回值】
  270. ****************************************************************/
  271. void CIvrFlow::onNetLinkUpdated( bool IsConnect )
  272. {
  273. m_IsNetLinkUp = IsConnect;
  274. if(!IsConnect)
  275. {
  276. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING, _T("{Flow}: 网络中断流程[%d]将被释放"), m_Id);
  277. __clearFlow();
  278. }
  279. else
  280. {
  281. if(m_pFlowTemplate != NULL && m_pFlowTemplate->type() == FLOW_AUTO)
  282. {
  283. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING, _T("{Flow}: 网络连接成功自动流程[%d]将启动"), m_Id);
  284. start();
  285. }
  286. }
  287. }
  288. /*****************************************************************
  289. **【函数名称】 addVar
  290. **【函数功能】 添加系统变量
  291. **【参数】 VarName: 变量名称
  292. VarValue: 变量值
  293. **【返回值】
  294. ****************************************************************/
  295. void CIvrFlow::addVar( const CString& VarName, const CString& VarValue )
  296. {
  297. m_VarTable.SetAt(VarName, VarValue);
  298. }
  299. /*****************************************************************
  300. **【函数名称】 findVarValue
  301. **【函数功能】 查找系统变量
  302. **【参数】 VarName:变量名称
  303. VarValue:变量值
  304. **【返回值】 true:查找到,false:未查找到
  305. ****************************************************************/
  306. bool CIvrFlow::findVarValue( const CString& VarName, CString& VarValue )
  307. {
  308. if(m_VarTable.Lookup(VarName, VarValue))
  309. return true;
  310. else
  311. return false;
  312. }
  313. /*****************************************************************
  314. **【函数名称】 replaceVar
  315. **【函数功能】 根据流程中的变量对指定字符串进行替换
  316. **【参数】 Src: 要进行替换的字符串
  317. Dst: 替换完成的字符串
  318. **【返回值】 成功true,失败false
  319. ****************************************************************/
  320. bool CIvrFlow::replaceVar( const CString& Src, CString& Dst )
  321. {
  322. Dst = Src;
  323. int Begin = 0;
  324. while( (Begin = Dst.Find(VAR_REF_START_FLAG, Begin)) != -1)
  325. {
  326. int End = Dst.Find(VAR_REF_END_FLAG, Begin);
  327. if(End != -1 && (End - Begin) > 2) // 可以取其中的变量
  328. {
  329. CString ValName = Dst.Mid(Begin + 2, End - Begin - 2);
  330. CString ValValue = _T("");
  331. // 将变量替换为具体值
  332. if( findVarValue(ValName, ValValue))
  333. Dst.Replace((VAR_REF_START_FLAG + ValName + VAR_REF_END_FLAG), ValValue);
  334. else
  335. return false;
  336. } // end if
  337. else
  338. {
  339. return false;
  340. }
  341. } // end while
  342. return true;
  343. }
  344. /*****************************************************************
  345. **【函数名称】 copyVar
  346. **【函数功能】 复制目标流程的系统变量
  347. **【参数】 DestFlow:目标流程
  348. **【返回值】
  349. ****************************************************************/
  350. void CIvrFlow::copyVar( CIvrFlow& DestFlow )
  351. {
  352. const VarTable::CPair* pPair = DestFlow.m_VarTable.PGetFirstAssoc();
  353. while(pPair != NULL)
  354. {
  355. m_VarTable.SetAt(pPair->key, pPair->value);
  356. DestFlow.m_VarTable.PGetNextAssoc(pPair);
  357. }
  358. }
  359. /*****************************************************************
  360. **【函数名称】 setFlowInfo
  361. **【函数功能】 保存流程信息
  362. **【参数】 CallId: 呼叫标识
  363. TrunkId: 外线Id
  364. CallerNum:主叫号码
  365. CalleeNum: 被叫号码
  366. **【返回值】
  367. ****************************************************************/
  368. void CIvrFlow::setFlowInfo(ULONG CallId, UINT TrunkId, const CString & CallerNum, const CString & CalleeNum)
  369. {
  370. m_AssoCallId = CallId;
  371. // 给系统变量呼叫标识赋值
  372. CString Data = "";
  373. Data.Format(_T("%lu"), CallId);
  374. addVar(SYSTEM_VAR_CALLID, Data);
  375. // 给系统变量外线号赋值
  376. Data.Format(_T("%u"), TrunkId);
  377. addVar(SYSTEM_VAR_OUTLINEID, Data);
  378. // 给系统变量主叫号码赋值
  379. addVar(SYSTEM_VAR_CALLER, CallerNum);
  380. // 给系统变量被叫号码赋值
  381. addVar(SYSTEM_VAR_CALLEE, CalleeNum);
  382. }
  383. /*****************************************************************
  384. **【函数名称】 setFlowInfo
  385. **【函数功能】 保存流程信息
  386. **【参数】 CallId: 呼叫标识
  387. TrunkId: 外线Id
  388. CallerNum:主叫号码
  389. CalleeNum: 被叫号码
  390. **【返回值】
  391. ****************************************************************/
  392. void CIvrFlow::setFlowInfo( ULONG CallId, UINT TrunkId, const CString& CallerNum, const CString& CalleeNum, const CString& UUID)
  393. {
  394. m_AssoCallId = CallId;
  395. // 给系统变量呼叫标识赋值
  396. CString Data = "";
  397. Data.Format(_T("%lu"), CallId);
  398. addVar(SYSTEM_VAR_CALLID, Data);
  399. // 给系统变量外线号赋值
  400. Data.Format(_T("%u"), TrunkId);
  401. addVar(SYSTEM_VAR_OUTLINEID, Data);
  402. // 给系统变量主叫号码赋值
  403. addVar(SYSTEM_VAR_CALLER, CallerNum);
  404. // 给系统变量被叫号码赋值
  405. addVar(SYSTEM_VAR_CALLEE, CalleeNum);
  406. // 给系统变量 UUID赋值 2022-10-08
  407. addVar(SYSTEM_VAR_UUID, UUID);
  408. }
  409. /*****************************************************************
  410. **【函数名称】 setFlowInfo
  411. **【函数功能】 保存流程信息
  412. **【参数】 CallId: 呼叫标识
  413. TrunkId: 外线Id
  414. TaskId: 预测任务ID
  415. OpType: 操作类型
  416. CallerNum:主叫号码
  417. CalleeNum: 被叫号码
  418. **【返回值】
  419. ****************************************************************/
  420. void CIvrFlow::setFlowInfo( ULONG CallId, UINT TrunkId, int TaskId, UINT OpType, const CString& CallerNum, const CString& CalleeNum )
  421. {
  422. setFlowInfo(CallId, TrunkId, CallerNum, CalleeNum);
  423. CString Data;
  424. Data.Format(_T("%d"), TaskId);
  425. addVar(SYSTEM_VAR_PRE_CALL_ID, Data);
  426. Data.Format(_T("%u"), OpType);
  427. addVar(SYSTEM_VAR_PRE_CALL_TYPE, Data);
  428. }
  429. /*****************************************************************
  430. **【函数名称】 setFlowAssoData
  431. **【函数功能】 设置流程随路数据
  432. **【参数】 AssoData: 随路数据
  433. **【返回值】
  434. ****************************************************************/
  435. void CIvrFlow::setFlowAssoData( CString AssoData )
  436. {
  437. CString DataInfo = "";
  438. CString DataName = "";
  439. CString DataValue = "";
  440. while(!AssoData.IsEmpty())
  441. {
  442. int nIndex = AssoData.Find("|");
  443. if(nIndex == -1)
  444. {
  445. DataInfo = AssoData;
  446. AssoData.Empty();
  447. }
  448. else
  449. {
  450. DataInfo = AssoData.Left(nIndex);
  451. AssoData = AssoData.Right(AssoData.GetLength() - nIndex - 1);
  452. }
  453. // 解析单个随路数据
  454. int Falg = DataInfo.Find(":");
  455. if(Falg == -1)
  456. continue;
  457. // 获取变量名
  458. DataName = DataInfo.Left(Falg);
  459. if(DataName.IsEmpty())
  460. continue;
  461. // 获取变量值
  462. DataValue = DataInfo.Right(DataInfo.GetLength() - Falg - 1);
  463. // 添加进随路数据
  464. this->addVar(DataName, DataValue);
  465. }
  466. }
  467. /*****************************************************************
  468. **【函数名称】 OnTimer
  469. **【函数功能】 定时器响应函数
  470. **【参数】 nIDEvent: 定时器ID
  471. **【返回值】
  472. ****************************************************************/
  473. void CIvrFlow::OnTimer( UINT_PTR nIDEvent )
  474. {
  475. KillTimer(nIDEvent);
  476. if(m_pCurrentCell != NULL && nIDEvent == reinterpret_cast<long>(m_pCurrentCell))
  477. __onTimerTimeOut();
  478. CWnd::OnTimer(nIDEvent);
  479. }
  480. /*****************************************************************
  481. **【函数名称】 onTimeUp
  482. **【函数功能】 定时器节点时间到
  483. **【参数】
  484. **【返回值】
  485. ****************************************************************/
  486. void CIvrFlow::onTimerTimeUp( int NextPos )
  487. {
  488. if(m_pCurrentCell->name() == CELL_NAME_TIMER)
  489. {
  490. __deleteCurrentCell();
  491. next(NextPos);
  492. }
  493. }