EA-Setka-2/Libs/MQL5Trace/Trace.mqh
super.admin a4b861dd93 convert
2025-05-30 14:50:44 +02:00

193 lines
No EOL
19 KiB
MQL5

//+------------------------------------------------------------------+
//| 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; i<size; i++) // ищем в ветках текущего нода требуемое имя
{
if (NIL(m_cur.m_next[i])) continue; // правильность указателя
if (m_cur.m_next[i].m_text==atext) { b=true; break; } // если нашли, то поиск останавливаем
}
ident=(m_cur.m_file==afile && m_cur.m_line==aline && m_cur.m_path==apath);
if (b)
{
m_cur=m_cur.m_next[i]; // передвинулись к следующему узлу
m_cur.m_desc=adesc; // задали атрибут
}
else if (!ident)// если узел не найден и это не текущий, то создаем новый узел
{
ArrayResize(m_cur.m_next, size+1); // расширили массив
m_cur.m_next[size]=new CNode; // создали узел
if (NIL(m_cur.m_next[size])) return; // проверили
m_stack.m_maxid++; // увеличили глобальный счетчик
m_cur.m_next[size].m_prev=m_cur; // поставили указатель на родителя
m_cur=m_cur.m_next[size]; // переместили текущий указатель на новый узел
m_cur.m_id=m_stack.m_maxid; m_cur.m_text=atext;
// задали атрибуты
string afunc=atext, aclass="__base__"; int k=StringFind(atext, "::");
if (k>0) { 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