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

279 lines
No EOL
25 KiB
MQL5

//+------------------------------------------------------------------+
//| TraceView |
//| Copyright 2006-2011, www.FXmaster.de |
//| www.FXmaster.de |
//+------------------------------------------------------------------+
#property copyright "Copyright 2006-2011, www.FXmaster.de"
#property link "www.FXmaster.de"
#property version "1.00"
#include "..\Trace.mqh"
#include "PropertyView.mqh"
//------------------------------------------------------------------ class CTreeView
class CTraceView: public CView
{
//--- базовые функции
public:
CTraceView() { }; // конструктор
~CTraceView() { Deinit(); } // деструтор
void Deinit(); // полная деинициализация представления
virtual void Create(long chart); // создаем и активируем представление
//--- функции обработки состояния
public:
int m_hagent; // хендлер индикатора-агента для отправки сообщений
CTraceCtrl* m_trace; // указатель на созданные трейсер
CTreeView* m_viewstack; // дерево для отображения стека
CPropertyView* m_viewprop; // дерево для отображения свойств узла
CTreeView* m_viewfile; // дерево для отображения стека с группировкой по файлам
CTreeView* m_viewclass; // дерево для отображения стека с группировкой по классам
void OnTimer(); // обработчик таймера
void OnChartEvent(const int , const long& , const double& , const string& ); // обработчик события
//--- функции отображения
public:
virtual void Draw(); // обновили объекты
virtual void DeleteView(); // удалили отображение
void UpdateInfo(CNode *node, bool bclear); // вывод окна подробной информации узла
string TimeSeparate(long time); // спецфункция для преобразования времени в строку
};
//------------------------------------------------------------------ ~CTraceView
void CTraceView::Deinit()
{ _IN("");
EventKillTimer();
delete m_viewclass;
delete m_viewfile;
delete m_viewprop;
delete m_viewstack;
ChartIndicatorDelete(m_chart, 0, "!TraceAgent");
m_hagent=INVALID_HANDLE;
ChartClose(m_chart);
}
//------------------------------------------------------------------ Create
void CTraceView::Create(long chart)
{ _IN("");
m_chart=ChartOpen(Symbol(), Period()); // открыли окно чарта для работы
// прикрепили к нему агента для отправки сообщений текущему окну
#ifndef __MQL4__
m_hagent=iCustom(Symbol(), Period(), "!TraceAgent", chart);
if (m_hagent==INVALID_HANDLE) return;
ChartIndicatorAdd(m_chart, 0, m_hagent);
#endif
HideChart(m_chart, LightSteelBlue); // скрыли отображение графика и элементов
int heigh=(int)ChartGetInteger(m_chart, CHART_HEIGHT_IN_PIXELS)-m_dy-5; // взяли параметры чарта
int width=(int)ChartGetInteger(m_chart, CHART_WIDTH_IN_PIXELS)-10; // взяли параметры чарта
// создаем четыре дерева для отбражения трассировки и её группировок
double k=1.7, kx=width/(k+2);
int dh=int(heigh/2.5);
int x=5, y=m_dy+5, dx=int(k*kx);
// главный стек
m_viewstack=new CTreeView; m_viewstack.m_tree=m_trace.m_stack; // присоединили граф к отображению
m_viewstack.Create(m_chart, "viewstack", 0, Black, White, DarkBlue, x, y, dx, heigh-dh-3, 0, 8, "Tahoma"); // создали область
m_viewstack.m_tree.SortBy(TG_TEXT, true);
m_viewstack.Draw();
// информация узла
m_viewprop=new CPropertyView; m_viewprop.m_tree=m_trace.m_prop; // присоединили граф к отображению
m_viewprop.Create(m_chart, "viewprop", 0, Black, White, DarkBlue, x, y+heigh-dh, dx, dh, 0, 8, "Tahoma"); // создали область
m_viewprop.Draw();
// группировка по классам
x+=dx+3; dx=(int)kx;
m_viewclass=new CTreeView; m_viewclass.m_tree=m_trace.m_class; // присоединили граф к отображению
m_viewclass.Create(m_chart, "viewclass", 0, Black, White, DarkBlue, x, y, dx, heigh, 0, 8, "Tahoma"); // создали область
m_viewclass.m_tree.SortBy(TG_TEXT, true);
m_viewclass.Draw();
// группировка по файлам
x+=dx+3; dx=(int)kx;
m_viewfile=new CTreeView; m_viewfile.m_tree=m_trace.m_file; // присоединили граф к отображению
m_viewfile.Create(m_chart, "viewfile", 0, Black, White, DarkBlue, x, y, dx, heigh, 0, 8, "Tahoma"); // создали область
m_viewfile.m_tree.SortBy(TG_TEXT, true);
m_viewfile.Draw();
EventSetTimer(2);
ChartRedraw(m_chart);
}
//------------------------------------------------------------------ OnTimer
void CTraceView::OnTimer()
{ _IN("");
_WATCH("time", TTS(TimeLocal()));
Draw(); // перерисовали деревья
}
//------------------------------------------------------------------ OnChartEvent
void CTraceView::OnChartEvent(const int aid, const long& lparam, const double& dparam, const string& sparam)
{ _IN("");
if (aid<CHARTEVENT_CUSTOM) return; // работаем только с пользовательскими событиями
int id=aid-CHARTEVENT_CUSTOM;
_WATCH("Event", EnumToString(ENUM_CHART_EVENT(id)));
// анализируем клик на объекте
if (id==CHARTEVENT_OBJECT_CLICK)
{ _IN2("");
if (StringFind(sparam, "viewstack")>=0) // на главном стеке
{
int btn=m_viewstack.OnClick(sparam);
if (btn==BTN_CLEAR)
{
m_viewclass.DeleteView(); m_viewclass.m_tree.Clear(); m_viewclass.Draw();
m_viewfile.DeleteView(); m_viewfile.m_tree.Clear(); m_viewfile.Draw();
m_viewprop.DeleteView();
}
if (m_viewstack.m_sid<=0) return;
CNode *node=m_viewstack.m_tree.FindNode(m_viewstack.m_sid); if (NIL(node)) return;
UpdateInfo(node, true);
m_viewclass.m_tree.SelectBy(TG_ALL, NULL, false); m_viewclass.m_tree.CheckBy(TG_ALL, NULL, false);
m_viewclass.m_tree.SelectBy(TG_CLASS|TG_FUNC, node, true); m_viewclass.m_tree.CheckBy(TG_CLASS|TG_FUNC, node, true);
m_viewclass.m_sid=-1; m_viewclass.Draw();
m_viewfile.m_tree.SelectBy(TG_ALL, NULL, false); m_viewfile.m_tree.CheckBy(TG_ALL, NULL, false);
m_viewfile.m_tree.SelectBy(TG_FILE|TG_FUNC, node, true); m_viewfile.m_tree.CheckBy(TG_FILE|TG_FUNC, node, true);
m_viewfile.m_sid=-1; m_viewfile.Draw();
ChartRedraw(m_chart);
}
if (StringFind(sparam, "viewclass")>=0) // на дереве классов
{
int btn=m_viewclass.OnClick(sparam);
if (btn==BTN_CLEAR)
{
m_viewstack.m_tree.GroupBy(TG_CLASS, m_viewclass.m_tree); m_viewclass.m_tree.SortBy(TG_TEXT, true);
m_viewclass.Draw();
}
m_viewprop.DeleteView();
if (m_viewclass.m_sid<=0) return;
CNode *node=m_viewclass.m_tree.FindNode(m_viewclass.m_sid); if (NIL(node)) return;
m_viewstack.m_tree.SelectBy(TG_ALL, NULL, false); m_viewstack.m_tree.CheckBy(TG_ALL, NULL, false);
m_viewstack.m_tree.SelectBy(TG_CLASS|TG_FUNC, node, true); m_viewstack.m_tree.CheckBy(TG_CLASS|TG_FUNC, node, true);
m_viewstack.m_sid=-1; m_viewstack.Draw();
m_viewfile.m_tree.SelectBy(TG_ALL, NULL, false); m_viewfile.m_tree.CheckBy(TG_ALL, NULL, false);
m_viewfile.m_tree.SelectBy(TG_FILE|TG_FUNC, node, true); m_viewfile.m_tree.CheckBy(TG_FILE|TG_FUNC, node, true);
m_viewfile.m_sid=-1; m_viewfile.Draw();
ChartRedraw(m_chart);
}
if (StringFind(sparam, "viewfile")>=0) // на дереве файлов
{
int btn=m_viewfile.OnClick(sparam);
if (btn==BTN_CLEAR)
{
m_viewstack.m_tree.GroupBy(TG_FILE, m_viewfile.m_tree); m_viewfile.m_tree.SortBy(TG_TEXT, true);
m_viewfile.Draw();
}
m_viewprop.DeleteView();
if (m_viewfile.m_sid<=0) return;
CNode *node=m_viewfile.m_tree.FindNode(m_viewfile.m_sid); if (NIL(node)) return;
m_viewstack.m_tree.SelectBy(TG_ALL, NULL, false); m_viewstack.m_tree.CheckBy(TG_ALL, NULL, false);
m_viewstack.m_tree.SelectBy(TG_FILE|TG_FUNC, node, true); m_viewstack.m_tree.CheckBy(TG_FILE|TG_FUNC, node, true);
m_viewstack.m_sid=-1; m_viewstack.Draw();
m_viewclass.m_tree.SelectBy(TG_ALL, NULL, false); m_viewclass.m_tree.CheckBy(TG_ALL, NULL, false);
m_viewclass.m_tree.SelectBy(TG_FILE|TG_FUNC, node, true); m_viewclass.m_tree.CheckBy(TG_FILE|TG_FUNC, node, true);
m_viewclass.m_sid=-1; m_viewclass.Draw();
ChartRedraw(m_chart);
}
if (StringFind(sparam, "viewprop")>=0) // на дереве свойств узла
{
m_viewprop.OnClick(sparam); ChartRedraw(m_chart);
}
}
if (id==CHARTEVENT_OBJECT_ENDEDIT)
{
if (StringFind(sparam, "viewprop")>=0) // на дереве свойств узла
{
if (StringFind(sparam, ".prop")>=0)
{
int n=(int)StringToInteger(ObjectGetString(m_chart, sparam, OBJPROP_TEXT)); // взяли
m_viewstack.m_tree.SetDataBy(TG_BRKUSE, m_viewstack.m_sid, n); // установили
}
}
}
if (id==CHARTEVENT_CHART_CHANGE)
{
Draw(); // изменился размер окна чарта
}
}
//------------------------------------------------------------------ Draw
void CTraceView::Draw()
{ _IN("");
int heigh=(int)ChartGetInteger(m_chart, CHART_HEIGHT_IN_PIXELS)-m_dy-5; // взяли параметры
int dh=int(heigh/2.5);
m_viewstack.m_dy=heigh-dh-3; m_viewprop.m_dy=dh; m_viewprop.m_y=m_viewstack.m_y+heigh-dh;
m_viewclass.m_dy=heigh; m_viewfile.m_dy=heigh;
int width=(int)ChartGetInteger(m_chart, CHART_WIDTH_IN_PIXELS)-10; // взяли параметры чарта
double k=1.7, kx=width/(k+2);
int x=5, dx=int(k*kx); m_viewstack.m_dx=dx; m_viewprop.m_dx=dx;
x+=dx+3; dx=int(kx); m_viewclass.m_x=x; m_viewclass.m_dx=dx;
x+=dx+3; dx=int(kx); m_viewfile.m_x=x; m_viewfile.m_dx=dx;
m_viewstack.Draw(); m_viewclass.Draw(); m_viewfile.Draw(); // перерисовали деревья
CNode *node=m_viewstack.m_tree.FindNode(m_viewstack.m_sid); // отображаем инфо по узлу
UpdateInfo(node, false);
ChartRedraw(m_chart);
}
//------------------------------------------------------------------ Draw
void CTraceView::DeleteView()
{ _IN("");
m_viewstack.DeleteView(); m_viewprop.DeleteView();
m_viewclass.DeleteView(); m_viewfile.DeleteView(); // удалили отображение
}
//------------------------------------------------------------------ UpdateInfo
void CTraceView::UpdateInfo(CNode *node, bool bclear)
{
if (NIL(node)) return;
if (NIL(m_viewprop.m_tree.m_root)) return;
//1. Копируем некторые данные узла в корневой узел дерева, для упрощения обработки кнопок
CNode *root=m_viewprop.m_tree.m_root;
root.m_text=node.m_text; // название узла
root.m_path=node.m_path; // имя файла
root.m_line=node.m_line; // номер линии в файле
int id, id2;
//2. Создаем дерево по узлу
id=m_viewprop.m_tree.AddNode(0, "Run-time инфо");
id2=m_viewprop.m_tree.AddNode(id, "Число вызовов"); m_viewprop.m_tree.SetDataBy(TG_DESC, id2, string(node.m_uses));
id2=m_viewprop.m_tree.AddNode(id, "DebugBreak после"); m_viewprop.m_tree.SetDataBy(TG_DESC, id2, node.m_brkuse<=0 ? "<откл>":string(node.m_brkuse));
m_viewprop.m_tree.SetDataBy(TG_EDIT, id2, true);
id2=m_viewprop.m_tree.AddNode(id, "Суммарное время"); m_viewprop.m_tree.SetDataBy(TG_DESC, id2, TimeSeparate(node.m_tick));
id2=m_viewprop.m_tree.AddNode(id, "Последний вход"); m_viewprop.m_tree.SetDataBy(TG_DESC, id2, TTS(node.m_last));
id2=m_viewprop.m_tree.AddNode(id, "Дополнительно"); m_viewprop.m_tree.SetDataBy(TG_DESC, id2, node.m_desc);
id=m_viewprop.m_tree.AddNode(0, "Расположение");
id2=m_viewprop.m_tree.AddNode(id, "Файл"); m_viewprop.m_tree.SetDataBy(TG_DESC, id2, node.m_file);
id2=m_viewprop.m_tree.AddNode(id, "Номер строки"); m_viewprop.m_tree.SetDataBy(TG_DESC, id2, string(node.m_line));
id2=m_viewprop.m_tree.AddNode(id, "Класс"); m_viewprop.m_tree.SetDataBy(TG_DESC, id2, node.m_class);
id2=m_viewprop.m_tree.AddNode(id, "Функция"); m_viewprop.m_tree.SetDataBy(TG_DESC, id2, node.m_func);
id=m_viewprop.m_tree.AddNode(0, "Watch-параметры");
if (bclear)
{
CNode *w=m_viewprop.m_tree.FindNode(id); // взяли узел watch
m_viewprop.DeleteView(w, false); // удалили его отображение
m_viewprop.m_tree.Clear(w); // удалили массив субузлов
}
// отрисовали watch
int n=ArraySize(node.m_watch);
for (int i=0; i<n; i++)
{
id2=m_viewprop.m_tree.AddNode(id, node.m_watch[i].m_name); m_viewprop.m_tree.SetDataBy(TG_DESC, id2, node.m_watch[i].m_val);
}
m_viewprop.Draw();
}
//------------------------------------------------------------------ TimeSeparate
string CTraceView::TimeSeparate(long time)
{
long sec=1000; long min=sec*60; long hour=min*60; long day=hour*24;
string txt="";
long d=long(time/day); if (d>0) txt+=string(d)+" дней ";
long h=long(time/hour)-d*day; if (h>9) txt+=string(h)+":"; else txt+="0"+string(h)+":";
long m=long(time/min)-(h*hour+d*day); if (m>9) txt+=string(m)+":"; else txt+="0"+string(m)+":";
long s=long(time/sec)-(m*min+h*hour+d*day); if (s>9) txt+=string(s)+"."; else txt+="0"+string(s)+".";
long ms=time-(s*sec+m*min+h*hour+d*day); txt+=string(ms);
return(txt);
}
#ifndef __MQL4__
extern CTraceView* m_traceview; // единственный экземпляр для отображения
#else
CTraceView* m_traceview; // единственный экземпляр для отображения
#endif