//+------------------------------------------------------------------+ //| Trace | //| Copyright 2006-2011, www.FXmaster.de | //| www.FXmaster.de | //+------------------------------------------------------------------+ #property copyright "Copyright 2006-2011, www.FXmaster.de" #property link "www.FXmaster.de" #include "Tree.mqh" class CTraceView; // предварительное объявление //------------------------------------------------------------------ class CTraceCtrl class CTraceCtrl { public: CTreeCtrl *m_stack; // объект графа CTreeCtrl *m_prop; // объект списка свойств CTreeCtrl *m_file; // группировка по файлам CTreeCtrl *m_class; // группировка по классам CTraceView* m_traceview; // указатель на отображение класса CNode* m_cur; // указатель на текущий узел public: CTraceCtrl() { Create(); Reset(); } // создали трейсер ~CTraceCtrl() { delete m_stack; delete m_prop; delete m_file; delete m_class; } // удалили трейсер void Create(); // создали трейсер void In(string apath, string afile, int aline, string atext, string adesc, int aid); // вход в указанный узел void Out(int aid); // выход до указанного узла bool StepBack(); // выход из узла на один шаг вверх (переход на родителя) void Reset() { m_cur=m_stack.m_root; m_stack.Reset(); m_file.Reset(); m_class.Reset(); } // сброс всех узлов void Clear() { m_cur=m_stack.m_root; m_stack.Clear(); m_file.Clear(); m_class.Clear(); } // сброс всех узлов public: void AddWatch(string name, string val); // проверка дебаг режима для узла void Break(); // пауза для узла }; //------------------------------------------------------------------ CTraceCtrl void CTraceCtrl::Create() { m_stack=new CTreeCtrl; m_stack.m_root.m_text="TRACE"; m_stack.m_mode=1; // создали объект графа m_prop=new CTreeCtrl; m_prop.m_root.m_text="INFO"; // создали объект графа m_file=new CTreeCtrl; m_file.m_root.m_text="FILE"; // создали объект графа m_class=new CTreeCtrl; m_class.m_root.m_text="CLASS"; // создали объект графа m_cur=m_stack.m_root; // установили указатель на корень m_stack.m_bBreak=true; } //------------------------------------------------------------------ In void CTraceCtrl::In(string apath, string afile, int aline, string atext, string adesc, int aid) { if (NIL(m_stack) || NIL(m_cur)) return; // правильность указателя if (aid>=0) Out(aid); // если задан требуемый узел, то переходим на него // проверяем имена уже имеющихся узлов int i, size=ArraySize(m_cur.m_next); // взяли список веток нода bool b=false, ident; for (i=0; i0) { aclass=StringSubstr(atext, 0, k); afunc=StringSubstr(atext, k+2); } m_cur.m_path=apath; m_cur.m_file=afile; m_cur.m_line=aline; m_cur.m_func=afunc; m_cur.m_class=aclass; m_cur.m_desc=adesc; // группируем в деревья m_stack.SortBy(TG_TEXT, true); m_file.Clear(); m_stack.GroupBy(TG_FILE, m_file); m_file.SortBy(TG_TEXT, true); m_class.Clear(); m_stack.GroupBy(TG_CLASS, m_class); m_class.SortBy(TG_TEXT, true); } m_cur.m_uses++; m_cur.m_tick0=GetTickCount(); m_cur.m_last=TimeLocal(); // задали число обращений и время входа } //------------------------------------------------------------------ Out void CTraceCtrl::Out(int aid) { if (aid<0) { StepBack(); return; } CNode *node=m_stack.FindNode(aid); if (NIL(node)) return; // нашли узел требуемого id while (m_cur!=node) if (!StepBack()) break; // выходим из узлов, пока не достигнем требуемого if (m_cur!=node) m_cur=node; // если в соседней ветке, то перепрыгиваем if (NIL(m_cur)) m_cur=node; // если текущий не указан, то задаем } //------------------------------------------------------------------ StepBack bool CTraceCtrl::StepBack() { if (NIL(m_stack.m_root)) { Print("-err Out root"); return(false); } // правильность указателя if (NIL(m_cur)) { m_cur=m_stack.m_root; return(false); } // правильность указателя if (m_cur.m_tick0>0) m_cur.m_tick+=GetTickCount()-m_cur.m_tick0; m_cur.m_tick0=0; // подсчитали время if (m_cur==m_stack.m_root) return(false); // если уже на верхушке if (NIL(m_cur.m_prev)) { Print("-err Out "+m_cur.m_text+"("+(string)m_cur.m_id+")"); return(false); } // правильность указателя m_cur=m_cur.m_prev; // перешли к родительскому узлу return(true); } //------------------------------------------------------------------ AddWatch void CTraceCtrl::AddWatch(string name, string val) // добавиление Watch-переменной в текущий узел { if (!NIL(m_trace) && !NIL(m_trace.m_cur)) m_trace.m_cur.AddWatch(name, val); } //------------------------------------------------------------------ Break void CTraceCtrl::Break() // проверка дебаг режима для узла { if (NIL(m_traceview) || NIL(m_stack)) return; // проверка валидности if (!m_stack.m_bBreak) return; // проверка разрешенности дебага m_stack.BreakBy(TG_ALL, NULL, false); // убрали флаги m_break со всех ущлов m_cur.m_break=true; // активировали только на текущем m_traceview.m_viewstack.m_sid=m_cur.m_id; // перенесли выделение на него m_stack.ExpandBy(TG_UP, m_cur, true, m_cur); // раскрыли родительские узлы, если закрыты m_traceview.Draw(); // отрисовали все string namedbg=m_traceview.m_viewstack.m_name+string(m_cur.m_id)+".dbg"; // получили имя кнопки BREAK string name=m_traceview.m_viewstack.m_name+".break"; // получили имя кнопки BREAK bool state=ObjectGetInteger(m_traceview.m_chart, namedbg, OBJPROP_STATE); while(!state) // пока кнопка не нажата, выполняем цикл { Sleep(500); // сделали паузу state=ObjectGetInteger(m_traceview.m_chart, namedbg, OBJPROP_STATE); // проверяем её состояние if (!m_traceview.IsOpenView()) break; // если окно закрыто, то выходим m_stack.m_bBreak=ObjectGetInteger(m_traceview.m_chart, name, OBJPROP_STATE); // проверяем её состояние state=state || !m_stack.m_bBreak; // учитываем состояние кнопки активности дебага системы m_traceview.Draw(); // отрисовали возможные изменения } m_cur.m_break=false; // убрали флаг m_traceview.Draw(); // отрисовали обновление } //------------------------------------------------------------------ CIn class CIn { public: void In(string apath, string afile, int aline, string afunc, string adesc) { if (NIL(m_trace)) return; // если нет графа, то выходим if (NIL(m_trace.m_stack)) return; if (NIL(m_trace.m_stack.m_root)) return; if (NIL(m_trace.m_cur)) m_trace.m_cur=m_trace.m_stack.m_root; m_trace.In(apath, afile, aline, afunc, adesc, -1); // вошли в следующий if (m_trace.m_cur.m_brkuse>0 && m_trace.m_cur.m_uses>=m_trace.m_cur.m_brkuse) // если достигли числа вызовов m_trace.Break(); //то входим в дебаг } void ~CIn() { if (!NIL(m_trace)) m_trace.Out(-1); } // вышли выше }; // определение макросов #ifdef TRACE #define _IN(desc) CIn _in; _in.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc)) #define _IN1(desc) CIn _in1; _in1.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc)) #define _IN2(desc) CIn _in2; _in2.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc)) #define _IN3(desc) CIn _in3; _in3.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc)) #define _IN4(desc) CIn _in4; _in4.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc)) #define _IN5(desc) CIn _in5; _in5.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc)) #define _WATCH(w, v) if (!NIL(m_trace)) if (!NIL(m_trace.m_cur)) m_trace.m_cur.AddWatch(w, string(v)); #define _BRKUSES(u) if (!NIL(m_trace)) if (!NIL(m_trace.m_cur)) if (m_trace.m_cur.m_brkuse==-2) m_trace.m_cur.m_brkuse=long(u); #include "View\TraceView.mqh" // подключаем описание класса #ifndef __MQL4__ extern CTraceCtrl* m_trace; // единственный экземпляр трассировщика #else CTraceCtrl* m_trace; // единственный экземпляр трассировщика #endif #else //TRACE #define _IN(desc) ;// CIn _in; _in.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc)) #define _IN1(desc) ;// CIn _in1; _in1.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc)) #define _IN2(desc) ;// CIn _in2; _in2.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc)) #define _IN3(desc) ;// CIn _in3; _in3.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc)) #define _IN4(desc) ;// CIn _in4; _in4.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc)) #define _IN5(desc) ;// CIn _in5; _in5.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc)) #define _WATCH(w, v) ;// if (!NIL(m_trace)) if (!NIL(m_trace.m_cur)) m_trace.m_cur.AddWatch(w, string(v)); #define _BRKUSES(u) ;//if (!NIL(m_trace)) if (!NIL(m_trace.m_cur)) if (m_trace.m_cur.m_brkuse==-2) m_trace.m_cur.m_brkuse=long(u); #endif //TRACE