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

505 lines
23 KiB
MQL5

//+------------------------------------------------------------------+
//| Tree |
//| 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 "Node.mqh"
//------------------------------------------------------------------ class CTreeBase
class CTreeBase
{
public:
CNode *m_root; // первый узел дерева
int m_maxid; // счетчик ID
//--- базовые функции
public:
CTreeBase(); // конструктор
~CTreeBase(); // деструктор
void Clear(CNode *root=NULL); // удаления всех узлов после указанного
CNode* FindNode(int id, CNode *root=NULL); // поиск узла по ID, начиная с заданного узла
CNode* FindNode(string txt, CNode *root=NULL); // поиск узла по txt, начиная с заданного узла
int GetID(string txt, CNode *root=NULL); // получение ID для указанного Text, поиск с заданного узла
int GetMaxID(CNode *root=NULL); // получение максимального ID в дереве
int AddNode(int id, string text, CNode *root=NULL); // добавление в список с поиском по ID узла, начиная с заданного узла
int AddNode(string txt, string text, CNode *root=NULL); // добавление в список с поиском по тексту узла, начиная с заданного узла
int AddNode(CNode *root, string text); // добавление под root
};
//------------------------------------------------------------------ CTreeBase
void CTreeBase::CTreeBase()
{
m_maxid=0; m_root=new CNode;
m_root.m_id=m_maxid; m_root.m_text="__base__";
}
//------------------------------------------------------------------ ~CTreeBase
void CTreeBase::~CTreeBase()
{
delete m_root; m_maxid=0; // сбросили счетчик
}
//------------------------------------------------------------------ Reset
void CTreeBase::Clear(CNode *root=NULL)
{
if (root==NULL) root=m_root; // если только начали, то задаем первый
if (NIL(root)) return; // правильность указателя
root.m_uses=0; root.m_tick=0; // обнулили в текущем узле
int n=ArraySize(root.m_next);
for (int i=0; i<n; i++) // обнуляем всю ветку
if (!NIL(root.m_next[i])) // правильность указателя
delete root.m_next[i];
ArrayResize(root.m_next, 0);
m_maxid=GetMaxID(); // сбросили счетчик
}
//------------------------------------------------------------------ FindNode
CNode* CTreeBase::FindNode(int id, CNode *root=NULL)
{
if (root==NULL) root=m_root; // если только начали, то задаем первый
if (NIL(root)) return(NULL); // правильность указателя
if (root.m_id==id) return(root); // если нашли, то присваиваем и выходим
CNode *node; int n=ArraySize(root.m_next);
for (int i=0; i<n; i++) // иначе проверяем массив
{
if (NIL(root.m_next[i])) continue; // правильность указателя
node=FindNode(id, root.m_next[i]); if (!NIL(node)) return(node); // проверили на узле
}
return(NULL);
}
//------------------------------------------------------------------ FindNode
CNode* CTreeBase::FindNode(string txt, CNode *root=NULL)
{
if (root==NULL) root=m_root; // если только начали, то задаем первый
if (NIL(root)) return(NULL); // правильность указателя
if (root.m_text==txt) return(root); // если нашли, то присваиваем и выходим
CNode *node; int n;
n=ArraySize(root.m_next);
for (int i=0; i<n; i++) // иначе проверяем массив
{
if (NIL(root.m_next[i])) continue; // правильность указателя
node=FindNode(txt, root.m_next[i]); if (!NIL(node)) return(node); // проверили на узле
}
return(NULL);
}
//------------------------------------------------------------------ GetID
int CTreeBase::GetID(string txt, CNode *root=NULL)
{
CNode *node=FindNode(txt, root); if (NIL(node)) return(-1);
return(node.m_id);
}
//------------------------------------------------------------------ GetMaxID
int CTreeBase::GetMaxID(CNode *root=NULL) // получение максимального ID
{
if (root==NULL) root=m_root; // если только начали, то задаем первый
if (NIL(root)) return(-1); // правильность указателя
int max=root.m_id;
int n=ArraySize(root.m_next);
for (int i=0; i<n; i++) // иначе проверяем массив
{
if (NIL(root.m_next[i])) continue; // правильность указателя
max=MathMax(max, GetMaxID(root.m_next[i]));
}
return(max);
}
//------------------------------------------------------------------ AddNode
int CTreeBase::AddNode(int id, string text, CNode *root=NULL)
{
CNode *node=FindNode(id, root); if (NIL(node)) return(-1);
int size=ArraySize(node.m_next); bool b=false; int i;
for (i=0; i<size; i++) // ищем узел с таким же текстом
{
if (NIL(node.m_next[i])) continue; // правильность указателя
if (node.m_next[i].m_text==text) { b=true; break; }
}
if (b) return(node.m_next[i].m_id); // если узел найден
// иначе добавляем
ArrayResize(node.m_next, size+1); node.m_next[size]=new CNode; m_maxid++;
node.m_next[size].m_id=m_maxid; node.m_next[size].m_text=text; node.m_next[size].m_prev=node;
return(node.m_next[size].m_id);
}
//------------------------------------------------------------------ AddNode
int CTreeBase::AddNode(string txt, string text, CNode *root=NULL)
{
CNode *node=FindNode(txt, root); if (NIL(node)) return(-1);
int size=ArraySize(node.m_next); bool b=false; int i;
for (i=0; i<size; i++) // ищем узел с таким же текстом
{
if (NIL(node.m_next[i])) continue; // правильность указателя
if (node.m_next[i].m_text==text) { b=true; break; }
}
if (b) return(node.m_next[i].m_id); // если узел найден
// иначе добавляем
ArrayResize(node.m_next, size+1); node.m_next[size]=new CNode; m_maxid++;
node.m_next[size].m_id=m_maxid; node.m_next[size].m_text=text; node.m_next[size].m_prev=node;
return(node.m_next[size].m_id);
}
//------------------------------------------------------------------ AddNode
int CTreeBase::AddNode(CNode *node, string text)
{
if (node==NULL) node=m_root; if (NIL(node)) return(-1);
int size=ArraySize(node.m_next); bool b=false; int i;
for (i=0; i<size; i++) // ищем узел с таким же текстом
{
if (NIL(node.m_next[i])) continue; // правильность указателя
if (node.m_next[i].m_text==text) { b=true; break; }
}
if (b) return(node.m_next[i].m_id); // если узел найден
// иначе добавляем
ArrayResize(node.m_next, size+1);
node.m_next[size]=new CNode; m_maxid++;
node.m_next[size].m_id=m_maxid; node.m_next[size].m_prev=node;
node.m_next[size].m_text=text;
return(node.m_next[size].m_id);
}
#define TG_ALL 0x00000001
#define TG_ID 0x00000002
#define TG_TEXT 0x00000004
#define TG_PATH 0x00000008
#define TG_FILE 0x00000010
#define TG_CLASS 0x00000020
#define TG_FUNC 0x00000040
#define TG_DESC 0x00000080
#define TG_EDIT 0x00000100
#define TG_BRKUSE 0x00000200
#define TG_UP 0x00000400
//------------------------------------------------------------------ class CTreeCtrl
class CTreeCtrl : public CTreeBase
{
public:
int m_mode; // тип дерева (для вида отображения TraceView)
//--- базовые функции
public:
CTreeCtrl() { m_bBreak=true; m_mode=0; m_root.m_path=""; m_root.m_file="__base__"; m_root.m_line=0; m_root.m_func="__base__"; m_root.m_class="__base__"; } // конструктор
~CTreeCtrl() { delete m_root; m_maxid=0; } // деструктор
void Reset(CNode *root=NULL); // сброс состояния всех узлов
void SetDataBy(int mode, int id, string text, CNode *root=NULL); // изменение свойства для указанного ID, поиск с заданного узла
void SetDataBy(int mode, int id, int data, CNode *root=NULL); // изменение свойства для указанного ID, поиск с заданного узла
string GetDataBy(int mode, int id, CNode *root=NULL); // получение свойства для указанного ID, поиск с заданного узла
//--- обработка состояния
public:
bool IsExpand(int id, CNode *root=NULL); // получение свойства m_expand для указанного ID, поиск с заданного узла
bool ExpandIt(int id, bool state, CNode *root=NULL); // меняем состояние m_expand, поиск с заданного узла
void ExpandBy(int mode, CNode *node, bool state, CNode *root=NULL); // раксрываем узлы только указанного
bool IsCheck(int id, CNode *root=NULL); // получение свойства m_check для указанного ID, поиск с заданного узла
bool CheckIt(int id, bool state, CNode *root=NULL); // меняем состояние m_check на требуемую, начиная с заданного узла
void CheckBy(int mode, CNode *node, bool state, CNode *root=NULL); // отмечаем все дерево
bool IsSelect(int id, CNode *root=NULL); // получение свойства m_select для указанного ID, поиск с заданного узла
bool SelectIt(int id, bool state, CNode *root=NULL); // меняем состояние m_select на требуемую, начиная с заданного узла
void SelectBy(int mode, CNode *node, bool state, CNode *root=NULL); // подсвечиваем все дерево
bool IsBreak(int id, CNode *root=NULL); // получение свойства m_break для указанного ID, поиск с заданного узла
bool BreakIt(int id, bool state, CNode *root=NULL); // меняем состояние m_break, поиск с заданного узла
void BreakBy(int mode, CNode *node, bool state, CNode *root=NULL); // задаем только для указанного
bool m_bBreak; // флаг разрешения режима дебага
//--- операции с нодами
public:
void SortBy(int mode, bool ascend, CNode *root=NULL); // сортировка по свойству
void GroupBy(int mode, CTreeCtrl* atree, CNode* node=NULL); // группировка по свойству
};
//------------------------------------------------------------------ Reset
void CTreeCtrl::Reset(CNode *root=NULL)
{
if (root==NULL) root=m_root; // если только начали, то задаем первый
if (NIL(root)) return; // правильность указателя
root.m_uses=0; root.m_tick=0; // обнулили в текущем узле
int n=ArraySize(root.m_next);
for (int i=0; i<n; i++) // обнуляем всю ветку
if (!NIL(root.m_next[i])) // правильность указателя
Reset(root.m_next[i]);
}
//------------------------------------------------------------------ SetDataBy
void CTreeCtrl::SetDataBy(int mode, int id, string text, CNode *root=NULL)
{
CNode *node=FindNode(id, root); if (NIL(node)) return;
if (bool(mode&TG_TEXT)) node.m_text=text;
if (bool(mode&TG_PATH)) node.m_path=text;
if (bool(mode&TG_FILE)) node.m_file=text;
if (bool(mode&TG_CLASS)) node.m_class=text;
if (bool(mode&TG_FUNC)) node.m_func=text;
if (bool(mode&TG_DESC)) node.m_desc=text;
}
//------------------------------------------------------------------ SetDataBy
void CTreeCtrl::SetDataBy(int mode, int id, int data, CNode *root=NULL)
{
CNode *node=FindNode(id, root); if (NIL(node)) return;
if (bool(mode&TG_ID)) node.m_id=data;
if (bool(mode&TG_EDIT)) node.m_edit=bool(data);
if (bool(mode&TG_BRKUSE)) node.m_brkuse=data;
}
//------------------------------------------------------------------ GetDataBy
string CTreeCtrl::GetDataBy(int mode, int id, CNode *root=NULL) // получение текста для указанного ID, поиск с заданного узла
{
CNode *node=FindNode(id, root); if (NIL(node)) return("");
switch(mode)
{
case TG_ID: return(string(node.m_id));
case TG_TEXT: return(node.m_text);
case TG_PATH: return(node.m_path);
case TG_FILE: return(node.m_file);
case TG_CLASS: return(node.m_class);
case TG_FUNC: return(node.m_func);
case TG_DESC: return(node.m_desc);
case TG_EDIT: return(string(node.m_edit));
case TG_BRKUSE: return(string(node.m_brkuse));
}
return("");
}
//------------------------------------------------------------------ IsExpand
bool CTreeCtrl::IsExpand(int id, CNode *root=NULL) // получение свойства m_expand для указанного ID, поиск с заданного узла
{
CNode *node=FindNode(id, root); if (NIL(node)) return(false);
return(node.m_expand);
}
//------------------------------------------------------------------ ExpandIt
bool CTreeCtrl::ExpandIt(int id, bool state, CNode *root=NULL) // меняем состояние m_expand, поиск с заданного узла
{
CNode *node=FindNode(id, root); if (NIL(node)) return(false);
node.m_expand=state; return(true); // если нашли, то меняем и выходим
}
//------------------------------------------------------------------ ExpandBy
void CTreeCtrl::ExpandBy(int mode, CNode *node, bool state, CNode *root=NULL) // раскрываем все дерево
{
if (mode!=TG_ALL && mode!=TG_UP && mode!=(TG_ALL|TG_UP))
if (NIL(node)) { Print(__FUNCTION__+" node==0"); return; } // правильность указателя
if (root==NULL) root=m_root; // если только начали, то задаем первый
if (NIL(root)) return; // правильность указателя
bool b=true;
if (bool(mode&TG_ID)) b=b&&(root.m_id==node.m_id);
if (bool(mode&TG_TEXT)) b=b&&(root.m_text==node.m_text);
if (bool(mode&TG_PATH)) b=b&&(root.m_path==node.m_path);
if (bool(mode&TG_FILE)) b=b&&(root.m_file==node.m_file);
if (bool(mode&TG_CLASS)) b=b&&(root.m_class==node.m_class);
if (bool(mode&TG_FUNC)) b=b&&(root.m_func==node.m_func);
if (bool(mode&TG_DESC)) b=b&&(root.m_desc==node.m_desc);
if (bool(mode&TG_EDIT)) b=b&&(root.m_edit==node.m_edit);
if (bool(mode&TG_BRKUSE)) b=b&&(root.m_brkuse==node.m_brkuse);
if (b) root.m_expand=state; // раскрываем
if (!bool(mode&TG_UP))
{
int n=ArraySize(root.m_next);
for (int i=0; i<n; i++) // иначе проверяем массив
{
if (NIL(root.m_next[i])) continue; // правильность указателя
ExpandBy(mode, node, state, root.m_next[i]); // проверили на узле
}
}
else if (!NIL(root.m_prev)) // правильность указателя
ExpandBy(TG_UP, node, state, root.m_prev); // проверили на узле
}
//------------------------------------------------------------------ IsCheck
bool CTreeCtrl::IsCheck(int id, CNode *root=NULL) // получение свойства m_check для указанного ID, поиск с заданного узла
{
CNode *node=FindNode(id, root); if (NIL(node)) return(false);
return(node.m_check);
}
//------------------------------------------------------------------ CheckIt
bool CTreeCtrl::CheckIt(int id, bool state, CNode *root=NULL) // меняем состояние m_check на требуемую, начиная с заданного узла
{
CNode *node=FindNode(id, root); if (NIL(node)) return(false);
node.m_check=state; return(true); // если нашли, то меняем и выходим
}
//------------------------------------------------------------------ CheckBy
void CTreeCtrl::CheckBy(int mode, CNode *node, bool state, CNode *root=NULL) // отмечаем все дерево
{
if (mode!=TG_ALL) if (NIL(node)) { Print(__FUNCTION__+" node==0"); return; } // правильность указателя
if (root==NULL) root=m_root; // если только начали, то задаем первый
if (NIL(root)) return; // правильность указателя
bool b=true;
if (bool(mode&TG_ID)) b=b&&(root.m_id==node.m_id);
if (bool(mode&TG_TEXT)) b=b&&(root.m_text==node.m_text);
if (bool(mode&TG_PATH)) b=b&&(root.m_path==node.m_path);
if (bool(mode&TG_FILE)) b=b&&(root.m_file==node.m_file);
if (bool(mode&TG_CLASS)) b=b&&(root.m_class==node.m_class);
if (bool(mode&TG_FUNC)) b=b&&(root.m_func==node.m_func || node.m_func=="");
if (bool(mode&TG_DESC)) b=b&&(root.m_desc==node.m_desc);
if (bool(mode&TG_EDIT)) b=b&&(root.m_edit==node.m_edit);
if (bool(mode&TG_BRKUSE)) b=b&&(root.m_brkuse==node.m_brkuse);
if (b) root.m_check=state; // отмечаем
if (!bool(mode&TG_UP))
{
int n=ArraySize(root.m_next);
for (int i=0; i<n; i++) // иначе проверяем массив
{
if (NIL(root.m_next[i])) continue; // правильность указателя
CheckBy(mode, node, state, root.m_next[i]); // проверили на узле
}
}
else if (!NIL(root.m_prev)) // правильность указателя
CheckBy(TG_UP, node, state, root.m_prev); // проверили на узле
}
//------------------------------------------------------------------ IsSelect
bool CTreeCtrl::IsSelect(int id, CNode *root=NULL) // получение свойства m_select для указанного ID, поиск с заданного узла
{
CNode *node=FindNode(id, root); if (NIL(node)) return(false);
return(node.m_select);
}
//------------------------------------------------------------------ SelectIt
bool CTreeCtrl::SelectIt(int id, bool state, CNode *root=NULL) // меняем состояние m_select на требуемую, начиная с заданного узла
{
CNode *node=FindNode(id, root); if (NIL(node)) return(false);
node.m_select=state; return(true); // если нашли, то меняем и выходим
}
//------------------------------------------------------------------ SelectBy
void CTreeCtrl::SelectBy(int mode, CNode *node, bool state, CNode *root=NULL) // подсвечиваем все дерево
{
if (mode!=TG_ALL) if (NIL(node)) { Print(__FUNCTION__+" node==0"); return; } // правильность указателя
if (root==NULL) root=m_root; // если только начали, то задаем первый
if (NIL(root)) { Print(__FUNCTION__+" root==0"); return; } // правильность указателя
bool b=true;
if (bool(mode&TG_ID)) b=b&&(root.m_id==node.m_id);
if (bool(mode&TG_TEXT)) b=b&&(root.m_text==node.m_text);
if (bool(mode&TG_PATH)) b=b&&(root.m_path==node.m_path);
if (bool(mode&TG_FILE)) b=b&&(root.m_file==node.m_file);
if (bool(mode&TG_CLASS)) b=b&&(root.m_class==node.m_class);
if (bool(mode&TG_FUNC)) b=b&&(root.m_func==node.m_func || node.m_func=="");
if (bool(mode&TG_DESC)) b=b&&(root.m_desc==node.m_desc);
if (bool(mode&TG_EDIT)) b=b&&(root.m_edit==node.m_edit);
if (bool(mode&TG_BRKUSE)) b=b&&(root.m_brkuse==node.m_brkuse);
if (b) root.m_select=state; // подсвечиваем
if (!bool(mode&TG_UP))
{
int n=ArraySize(root.m_next);
for (int i=0; i<n; i++) // иначе проверяем массив
{
if (NIL(root.m_next[i])) continue; // правильность указателя
SelectBy(mode, node, state, root.m_next[i]); // проверили на узле
}
}
else if (!NIL(root.m_prev)) // правильность указателя
SelectBy(TG_UP, node, state, root.m_prev); // проверили на узле
}
//------------------------------------------------------------------ IsBreak
bool CTreeCtrl::IsBreak(int id, CNode *root=NULL) // получение свойства m_break для указанного ID, поиск с заданного узла
{
CNode *node=FindNode(id, root); if (NIL(node)) return(false);
return(node.m_break);
}
//------------------------------------------------------------------ BreakIt
bool CTreeCtrl::BreakIt(int id, bool state, CNode *root=NULL) // меняем состояние m_break, поиск с заданного узла
{
CNode *node=FindNode(id, root); if (NIL(node)) return(false);
node.m_break=state; return(true); // если нашли, то меняем и выходим
}
//------------------------------------------------------------------ BreakBy
void CTreeCtrl::BreakBy(int mode, CNode *node, bool state, CNode *root=NULL) // задаем только для указанного
{
if (mode!=TG_ALL) if (NIL(node)) { Print(__FUNCTION__+" node==0"); return; } // правильность указателя
if (root==NULL) root=m_root; // если только начали, то задаем первый
if (NIL(root)) { Print(__FUNCTION__+" root==0"); return; } // правильность указателя
bool b=true;
if (bool(mode&TG_ID)) b=b&&(root.m_id==node.m_id);
if (bool(mode&TG_TEXT)) b=b&&(root.m_text==node.m_text);
if (bool(mode&TG_PATH)) b=b&&(root.m_path==node.m_path);
if (bool(mode&TG_FILE)) b=b&&(root.m_file==node.m_file);
if (bool(mode&TG_CLASS)) b=b&&(root.m_class==node.m_class);
if (bool(mode&TG_FUNC)) b=b&&(root.m_func==node.m_func || node.m_func=="");
if (bool(mode&TG_DESC)) b=b&&(root.m_desc==node.m_desc);
if (bool(mode&TG_EDIT)) b=b&&(root.m_edit==node.m_edit);
if (bool(mode&TG_BRKUSE)) b=b&&(root.m_brkuse==node.m_brkuse);
if (b) root.m_break=state; // подсвечиваем
if (!bool(mode&TG_UP))
{
int n=ArraySize(root.m_next);
for (int i=0; i<n; i++) // иначе проверяем массив
{
if (NIL(root.m_next[i])) continue; // правильность указателя
BreakBy(mode, node, state, root.m_next[i]); // проверили на узле
}
}
else if (!NIL(root.m_prev)) // правильность указателя
BreakBy(TG_UP, node, state, root.m_prev); // проверили на узле
}
//------------------------------------------------------------------ SortBy
void CTreeCtrl::SortBy(int mode, bool ascend, CNode *root=NULL) // сортировка по свойству
{
if (root==NULL) root=m_root; // если только начали, то задаем первый
if (NIL(root)) return; // правильность указателя
int n=ArraySize(root.m_next);
bool b=true; CNode *node;
while (b && n>1)
{
b=false;string st1="", st2="";
for (int i=1; i<n; i++) // сравниваем и упорядочиваем
{
// требуемая группа сортировки
st1=root.m_next[i-1].m_text; st2=root.m_next[i].m_text;
if (mode==TG_ID) { st1=string(root.m_next[i-1].m_id); st2=string(root.m_next[i].m_id); }
if (mode==TG_PATH) { st1=root.m_next[i-1].m_path; st2=root.m_next[i].m_path; }
if (mode==TG_FILE) { st1=root.m_next[i-1].m_file; st2=root.m_next[i].m_file; }
if (mode==TG_CLASS) { st1=root.m_next[i-1].m_class; st2=root.m_next[i].m_class; }
if (mode==TG_FUNC) { st1=root.m_next[i-1].m_func; st2=root.m_next[i].m_func; }
if (mode==TG_DESC) { st1=root.m_next[i-1].m_desc; st2=root.m_next[i].m_desc; }
if (mode==TG_EDIT) { st1=string(root.m_next[i-1].m_edit); st2=string(root.m_next[i].m_edit); }
if (mode==TG_BRKUSE) { st1=string(root.m_next[i-1].m_brkuse); st2=string(root.m_next[i].m_brkuse); }
StringToLower(st1); StringToLower(st2);
if ((ascend && st1>=st2) || (!ascend && st1<st2))
{ b=true; node=root.m_next[i-1]; root.m_next[i-1]=root.m_next[i]; root.m_next[i]=node; }
}
}
for (int i=0; i<n; i++) // проверяем массив глубже
{
if (NIL(root.m_next[i])) continue; // правильность указателя
SortBy(mode, ascend, root.m_next[i]); // проверили на узле
}
}
//------------------------------------------------------------------ GroupBy
void CTreeCtrl::GroupBy(int mode, CTreeCtrl* atree, CNode* root=NULL)
{
if (NIL(atree) || atree==NULL) return; // правильность указателя
if (root==NULL) root=m_root; // если только начали, то задаем первый
if (NIL(root)) return; // правильность указателя
if (root!=m_root)
{
int id; string st=" ";
if (mode==TG_PATH) st=root.m_path; // группируем по пути файла
if (mode==TG_FILE) st=root.m_file; // группируем по имени файла
if (mode==TG_CLASS) st=root.m_class; // группируем по имени класса
id=atree.AddNode(0, st);
atree.SetDataBy(TG_PATH, id, root.m_path);
atree.SetDataBy(TG_FILE, id, root.m_file);
atree.SetDataBy(TG_CLASS, id, root.m_class);
id=atree.AddNode(st, root.m_func);
CNode *node=atree.FindNode(id);
node.m_uses=root.m_uses; // число обращений к узлу
node.m_tick=root.m_tick; // время проведенное в узле
node.m_tick0=root.m_tick0; // время входа в узел
node.m_last=root.m_last; // время входа в узел
node.m_path=root.m_path; // путь файла
node.m_file=root.m_file; // имя файла
node.m_line=root.m_line; // номер линии в файле
node.m_class=root.m_class; // имя класса
node.m_func=root.m_func; // имя функции
node.m_desc=root.m_desc; // доп.инфо
node.m_edit=root.m_edit; // редактируемое поле
node.m_brkuse=root.m_brkuse; // редактируемое поле
}
int n=ArraySize(root.m_next);
for (int i=0; i<n; i++) // иначе проверяем массив
{
if (NIL(root.m_next[i])) continue; // правильность указателя
GroupBy(mode, atree, root.m_next[i]); // проверили на узле
}
}