279 lines
No EOL
25 KiB
MQL5
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 |