//+------------------------------------------------------------------+ //| 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=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; i0) 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