2026-03-27 00:05:24 +07:00
//+------------------------------------------------------------------+
2026-03-26 23:54:10 +07:00
//| Tables.mqh |
2026-03-29 12:59:40 +07:00
//| Copyright 2025, MetaQuotes Ltd. |
2026-03-26 23:54:10 +07:00
//| https://www.mql5.com |
//+------------------------------------------------------------------+
2026-03-29 01:37:34 +07:00
# property copyright " Copyright 2025, MetaQuotes Ltd. "
# property link " https://www.mql5.com "
2026-03-26 23:54:10 +07:00
//+------------------------------------------------------------------+
2026-03-27 00:05:24 +07:00
//| Включаемые библиотеки |
//+------------------------------------------------------------------+
# include <Arrays\List.mqh>
//--- Форвард-декларация классов
class CTableCell ; // Класс ячейки таблицы
class CTableRow ; // Класс строки таблицы
class CTableModel ; // Класс модели таблицы
2026-03-27 00:24:00 +07:00
class CColumnCaption ; // Класс заголовка столбца таблицы
class CTableHeader ; // Класс заголовка таблицы
class CTable ; // Класс таблицы
class CTableByParam ; // Класс таблицы на основе массива параметров
2026-03-27 00:05:24 +07:00
//+------------------------------------------------------------------+
//| Макросы |
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
# define __TABLES__ / / Идентификатор данного файла
2026-03-27 00:05:24 +07:00
# define MARKER_START_DATA -1 / / Маркер начала данных в файле
# define MAX_STRING_LENGTH 128 / / Максимальная длина строки в ячейке
2026-03-27 00:24:00 +07:00
# define CELL_WIDTH_IN_CHARS 19 / / Ширина ячейки таблицы в символах
2026-03-29 15:13:53 +07:00
# define ASC_IDX_CORRECTION 10000 / / Смещение индекса столбца для сортировки по возрастанию
# define DESC_IDX_CORRECTION 20000 / / Смещение индекса столбца для сортировки по убыванию
2026-03-27 00:05:24 +07:00
//+------------------------------------------------------------------+
//| Перечисления |
//+------------------------------------------------------------------+
enum ENUM_OBJECT_TYPE // Перечисление типов объектов
{
OBJECT_TYPE_TABLE_CELL = 10000 , // Ячейка таблицы
OBJECT_TYPE_TABLE_ROW , // Строка таблицы
OBJECT_TYPE_TABLE_MODEL , // Модель таблицы
2026-03-27 00:24:00 +07:00
OBJECT_TYPE_COLUMN_CAPTION , // Заголовок столбца таблицы
OBJECT_TYPE_TABLE_HEADER , // Заголовок таблицы
OBJECT_TYPE_TABLE , // Таблица
OBJECT_TYPE_TABLE_BY_PARAM , // Таблица на данных массива параметров
2026-03-27 00:05:24 +07:00
} ;
enum ENUM_CELL_COMPARE_MODE // Режимы сравнения ячеек таблицы
{
CELL_COMPARE_MODE_COL , // Сравнение по номеру колонки
CELL_COMPARE_MODE_ROW , // Сравнение по номеру строки
CELL_COMPARE_MODE_ROW_COL , // Сравнение по строке и колонке
} ;
2026-03-27 00:24:00 +07:00
//+------------------------------------------------------------------+
2026-03-27 00:05:24 +07:00
//| Функции |
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
//+------------------------------------------------------------------+
//| Возвращает тип объекта как строку |
//+------------------------------------------------------------------+
2026-03-27 00:05:24 +07:00
string TypeDescription ( const ENUM_OBJECT_TYPE type )
{
string array [ ] ;
int total = StringSplit ( EnumToString ( type ) , StringGetCharacter ( " _ " , 0 ) , array ) ;
string result = " " ;
for ( int i = 2 ; i < total ; i + + )
{
array [ i ] + = " " ;
array [ i ] .Lower ( ) ;
array [ i ] .SetChar ( 0 , ushort ( array [ i ] .GetChar ( 0 ) -0x20 ) ) ;
result + = array [ i ] ;
}
result .TrimLeft ( ) ;
result .TrimRight ( ) ;
return result ;
}
//+------------------------------------------------------------------+
//| Классы |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс связанного списка объектов |
//+------------------------------------------------------------------+
class CListObj : public CList
{
protected :
ENUM_OBJECT_TYPE m_element_type ; // Тип создаваемого объекта в CreateElement()
public :
2026-03-29 15:13:53 +07:00
//--- Виртуальный метод (1) загрузки списка из файла, (2) создания элемента списка, (3) сравнения
2026-03-27 00:05:24 +07:00
virtual bool Load ( const int file_handle ) ;
virtual CObject * CreateElement ( void ) ;
} ;
//+------------------------------------------------------------------+
//| Загрузка списка из файла |
//+------------------------------------------------------------------+
bool CListObj : : Load ( const int file_handle )
{
//--- Переменные
CObject * node ;
bool result = true ;
//--- Проверяем хэндл
if ( file_handle = = INVALID_HANDLE )
return ( false ) ;
//--- Загрузка и проверка маркера начала списка - 0xFFFFFFFFFFFFFFFF
if ( : : FileReadLong ( file_handle ) ! = MARKER_START_DATA )
return ( false ) ;
//--- Загрузка и проверка типа списка
2026-03-29 15:13:53 +07:00
if ( : : FileReadInteger ( file_handle , INT_VALUE ) ! = this . Type ( ) )
2026-03-27 00:05:24 +07:00
return ( false ) ;
//--- Чтение размера списка (количество объектов)
uint num = : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Последовательно заново создаём элементы списка с помощью вызова метода Load() объектов node
this . Clear ( ) ;
for ( uint i = 0 ; i < num ; i + + )
{
//--- Читаем и проверяем маркер начала данных объекта - 0xFFFFFFFFFFFFFFFF
if ( : : FileReadLong ( file_handle ) ! = MARKER_START_DATA )
return false ;
//--- Читаем тип объекта
this . m_element_type = ( ENUM_OBJECT_TYPE ) : : FileReadInteger ( file_handle , INT_VALUE ) ;
node = this . CreateElement ( ) ;
if ( node = = NULL )
return false ;
this . Add ( node ) ;
//--- Сейчас файловый указатель смещён относительно начала маркера объекта на 12 байт (8 - маркер, 4 - тип)
//--- Поставим указатель на начало данных объекта и загрузим свойства объекта из файла методом Load() элемента node.
if ( ! : : FileSeek ( file_handle , -12 , SEEK_CUR ) )
return false ;
result & = node . Load ( file_handle ) ;
}
//--- Результат
return result ;
}
//+------------------------------------------------------------------+
//| Метод создания элемента списка |
//+------------------------------------------------------------------+
CObject * CListObj : : CreateElement ( void )
{
//--- В зависимости от типа объекта в m_element_type, создаём новый объект
switch ( this . m_element_type )
{
2026-03-27 00:24:00 +07:00
case OBJECT_TYPE_TABLE_CELL : return new CTableCell ( ) ;
case OBJECT_TYPE_TABLE_ROW : return new CTableRow ( ) ;
case OBJECT_TYPE_TABLE_MODEL : return new CTableModel ( ) ;
case OBJECT_TYPE_COLUMN_CAPTION : return new CColumnCaption ( ) ;
case OBJECT_TYPE_TABLE_HEADER : return new CTableHeader ( ) ;
case OBJECT_TYPE_TABLE : return new CTable ( ) ;
case OBJECT_TYPE_TABLE_BY_PARAM : return new CTableByParam ( ) ;
default : return NULL ;
2026-03-27 00:05:24 +07:00
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс ячейки таблицы |
//+------------------------------------------------------------------+
class CTableCell : public CObject
{
protected :
//--- Объединение для хранения значений ячейки (double, long, string)
union DataType
{
protected :
double double_value ;
long long_value ;
ushort ushort_value [ MAX_STRING_LENGTH ] ;
public :
//--- Установка значений
void SetValueD ( const double value ) { this . double_value = value ; }
void SetValueL ( const long value ) { this . long_value = value ; }
void SetValueS ( const string value ) { : : StringToShortArray ( value , ushort_value ) ; }
//--- Возврат значений
double ValueD ( void ) const { return this . double_value ; }
long ValueL ( void ) const { return this . long_value ; }
string ValueS ( void ) const
{
string res = : : ShortArrayToString ( this . ushort_value ) ;
res .TrimLeft ( ) ;
res .TrimRight ( ) ;
return res ;
}
} ;
//--- Переменные
DataType m_datatype_value ; // Значение
ENUM_DATATYPE m_datatype ; // Тип данных
CObject * m_object ; // Объект в ячейке
ENUM_OBJECT_TYPE m_object_type ; // Тип объекта в ячейке
int m_row ; // Номер строки
int m_col ; // Номер столбца
int m_digits ; // Точность представления данных
uint m_time_flags ; // Флаги отображения даты/времени
bool m_color_flag ; // Флаг отображения наименования цвета
bool m_editable ; // Флаг редактируемой ячейки
2026-03-27 00:24:00 +07:00
//--- Устанавливает "пустое значение"
void SetEmptyValue ( void )
{
switch ( this . m_datatype )
{
case TYPE_LONG :
case TYPE_DATETIME :
case TYPE_COLOR : this . SetValue ( LONG_MAX ) ; break ;
case TYPE_DOUBLE : this . SetValue ( DBL_MAX ) ; break ;
default : this . SetValue ( " " ) ; break ;
}
}
2026-03-27 00:05:24 +07:00
public :
//--- Возврат координат и свойств ячейки
2026-03-27 00:24:00 +07:00
uint Row ( void ) const { return this . m_row ; }
uint Col ( void ) const { return this . m_col ; }
ENUM_DATATYPE Datatype ( void ) const { return this . m_datatype ; }
int Digits ( void ) const { return this . m_digits ; }
uint DatetimeFlags ( void ) const { return this . m_time_flags ; }
bool ColorNameFlag ( void ) const { return this . m_color_flag ; }
bool IsEditable ( void ) const { return this . m_editable ; }
2026-03-27 00:05:24 +07:00
//--- Возвращает (1) double, (2) long, (3) string значение
2026-03-27 00:24:00 +07:00
double ValueD ( void ) const { return this . m_datatype_value . ValueD ( ) ; }
long ValueL ( void ) const { return this . m_datatype_value . ValueL ( ) ; }
string ValueS ( void ) const { return this . m_datatype_value . ValueS ( ) ; }
2026-03-27 00:05:24 +07:00
//--- Возвращает значение в виде форматированной строки
string Value ( void ) const
{
switch ( this . m_datatype )
{
2026-03-27 00:24:00 +07:00
case TYPE_DOUBLE : return ( this . ValueD ( ) ! = DBL_MAX ? : : DoubleToString ( this . ValueD ( ) , this . Digits ( ) ) : " " ) ;
case TYPE_LONG : return ( this . ValueL ( ) ! = LONG_MAX ? : : IntegerToString ( this . ValueL ( ) ) : " " ) ;
case TYPE_DATETIME : return ( this . ValueL ( ) ! = LONG_MAX ? : : TimeToString ( this . ValueL ( ) , this . m_time_flags ) : " " ) ;
case TYPE_COLOR : return ( this . ValueL ( ) ! = LONG_MAX ? : : ColorToString ( ( color ) this . ValueL ( ) , this . m_color_flag ) : " " ) ;
2026-03-27 00:05:24 +07:00
default : return this . ValueS ( ) ;
}
}
2026-03-27 00:24:00 +07:00
//--- Возвращает описание типа хранимого значения
2026-03-27 00:05:24 +07:00
string DatatypeDescription ( void ) const
{
string type = : : StringSubstr ( : : EnumToString ( this . m_datatype ) , 5 ) ;
type .Lower ( ) ;
return type ;
}
2026-03-27 00:24:00 +07:00
//--- Очищает данные
void ClearData ( void ) { this . SetEmptyValue ( ) ; }
2026-03-27 00:05:24 +07:00
//--- Установка значений переменных
2026-03-27 00:24:00 +07:00
void SetRow ( const uint row ) { this . m_row = ( int ) row ; }
void SetCol ( const uint col ) { this . m_col = ( int ) col ; }
void SetDatatype ( const ENUM_DATATYPE datatype ) { this . m_datatype = datatype ; }
void SetDigits ( const int digits ) { this . m_digits = digits ; }
void SetDatetimeFlags ( const uint flags ) { this . m_time_flags = flags ; }
void SetColorNameFlag ( const bool flag ) { this . m_color_flag = flag ; }
void SetEditable ( const bool flag ) { this . m_editable = flag ; }
//--- Устанавливает строку и колонку
2026-03-27 00:05:24 +07:00
void SetPositionInTable ( const uint row , const uint col )
{
this . SetRow ( row ) ;
this . SetCol ( col ) ;
}
//--- Назначает объект в ячейку
void AssignObject ( CObject * object )
{
if ( object = = NULL )
{
: : PrintFormat ( " %s: Error. Empty object passed " , __FUNCTION__ ) ;
return ;
}
this . m_object = object ;
this . m_object_type = ( ENUM_OBJECT_TYPE ) object . Type ( ) ;
}
//--- Снимает назначение объекта
void UnassignObject ( void )
{
this . m_object = NULL ;
this . m_object_type = -1 ;
}
2026-03-27 00:24:00 +07:00
//--- Возвращает (1) назначенный в ячейку объект, (2) тип назначенного в ячейку объекта
CObject * AssignedObject ( void ) { return this . m_object ; }
ENUM_OBJECT_TYPE AssignedObjType ( void ) const { return this . m_object_type ; }
2026-03-27 00:05:24 +07:00
//--- Устанавливает double-значение
void SetValue ( const double value )
{
this . m_datatype = TYPE_DOUBLE ;
if ( this . m_editable )
this . m_datatype_value . SetValueD ( value ) ;
}
//--- Устанавливает long-значение
void SetValue ( const long value )
{
this . m_datatype = TYPE_LONG ;
if ( this . m_editable )
this . m_datatype_value . SetValueL ( value ) ;
}
//--- Устанавливает datetime-значение
void SetValue ( const datetime value )
{
this . m_datatype = TYPE_DATETIME ;
if ( this . m_editable )
this . m_datatype_value . SetValueL ( value ) ;
}
//--- Устанавливает color-значение
void SetValue ( const color value )
{
this . m_datatype = TYPE_COLOR ;
if ( this . m_editable )
this . m_datatype_value . SetValueL ( value ) ;
}
//--- Устанавливает string-значение
void SetValue ( const string value )
{
this . m_datatype = TYPE_STRING ;
if ( this . m_editable )
this . m_datatype_value . SetValueS ( value ) ;
}
2026-03-27 00:24:00 +07:00
2026-03-27 00:05:24 +07:00
//--- (1) Возвращает, (2) выводит в журнал описание объекта
2026-03-27 00:24:00 +07:00
virtual string Description ( void ) ;
2026-03-27 00:05:24 +07:00
void Print ( void ) ;
//--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта
virtual int Compare ( const CObject * node , const int mode = 0 ) const ;
virtual bool Save ( const int file_handle ) ;
virtual bool Load ( const int file_handle ) ;
virtual int Type ( void ) const { return ( OBJECT_TYPE_TABLE_CELL ) ; }
//--- Конструкторы/деструктор
CTableCell ( void ) : m_row ( 0 ) , m_col ( 0 ) , m_datatype ( -1 ) , m_digits ( 0 ) , m_time_flags ( 0 ) , m_color_flag ( false ) , m_editable ( true ) , m_object ( NULL ) , m_object_type ( -1 )
{
this . m_datatype_value . SetValueD ( 0 ) ;
}
//--- Принимает double-значение
CTableCell ( const uint row , const uint col , const double value , const int digits ) :
m_row ( ( int ) row ) , m_col ( ( int ) col ) , m_datatype ( TYPE_DOUBLE ) , m_digits ( digits ) , m_time_flags ( 0 ) , m_color_flag ( false ) , m_editable ( true ) , m_object ( NULL ) , m_object_type ( -1 )
{
this . m_datatype_value . SetValueD ( value ) ;
}
//--- Принимает long-значение
CTableCell ( const uint row , const uint col , const long value ) :
m_row ( ( int ) row ) , m_col ( ( int ) col ) , m_datatype ( TYPE_LONG ) , m_digits ( 0 ) , m_time_flags ( 0 ) , m_color_flag ( false ) , m_editable ( true ) , m_object ( NULL ) , m_object_type ( -1 )
{
this . m_datatype_value . SetValueL ( value ) ;
}
//--- Принимает datetime-значение
CTableCell ( const uint row , const uint col , const datetime value , const uint time_flags ) :
m_row ( ( int ) row ) , m_col ( ( int ) col ) , m_datatype ( TYPE_DATETIME ) , m_digits ( 0 ) , m_time_flags ( time_flags ) , m_color_flag ( false ) , m_editable ( true ) , m_object ( NULL ) , m_object_type ( -1 )
{
this . m_datatype_value . SetValueL ( value ) ;
}
//--- Принимает color-значение
CTableCell ( const uint row , const uint col , const color value , const bool color_names_flag ) :
m_row ( ( int ) row ) , m_col ( ( int ) col ) , m_datatype ( TYPE_COLOR ) , m_digits ( 0 ) , m_time_flags ( 0 ) , m_color_flag ( color_names_flag ) , m_editable ( true ) , m_object ( NULL ) , m_object_type ( -1 )
{
this . m_datatype_value . SetValueL ( value ) ;
}
//--- Принимает string-значение
CTableCell ( const uint row , const uint col , const string value ) :
m_row ( ( int ) row ) , m_col ( ( int ) col ) , m_datatype ( TYPE_STRING ) , m_digits ( 0 ) , m_time_flags ( 0 ) , m_color_flag ( false ) , m_editable ( true ) , m_object ( NULL ) , m_object_type ( -1 )
{
this . m_datatype_value . SetValueS ( value ) ;
}
~ CTableCell ( void ) { }
} ;
//+------------------------------------------------------------------+
//| Сравнение двух объектов |
//+------------------------------------------------------------------+
int CTableCell : : Compare ( const CObject * node , const int mode = 0 ) const
{
2026-03-29 13:06:34 +07:00
if ( node = = NULL )
return -1 ;
2026-03-27 00:05:24 +07:00
const CTableCell * obj = node ;
switch ( mode )
{
case CELL_COMPARE_MODE_COL : return ( this .Col ( ) > obj .Col ( ) ? 1 : this .Col ( ) < obj .Col ( ) ? -1 : 0 ) ;
case CELL_COMPARE_MODE_ROW : return ( this .Row ( ) > obj .Row ( ) ? 1 : this .Row ( ) < obj .Row ( ) ? -1 : 0 ) ;
//---CELL_COMPARE_MODE_ROW_COL
default : return
(
this .Row ( ) > obj .Row ( ) ? 1 : this .Row ( ) < obj .Row ( ) ? -1 :
this .Col ( ) > obj .Col ( ) ? 1 : this .Col ( ) < obj .Col ( ) ? -1 : 0
) ;
}
}
//+------------------------------------------------------------------+
//| Сохранение в файл |
//+------------------------------------------------------------------+
bool CTableCell : : Save ( const int file_handle )
{
//--- Проверяем хэндл
if ( file_handle = = INVALID_HANDLE )
return ( false ) ;
//--- Сохраняем маркер начала данных - 0xFFFFFFFFFFFFFFFF
if ( : : FileWriteLong ( file_handle , MARKER_START_DATA ) ! = sizeof ( long ) )
return ( false ) ;
//--- Сохраняем тип объекта
if ( : : FileWriteInteger ( file_handle , this . Type ( ) , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Сохраняем тип данных
if ( : : FileWriteInteger ( file_handle , this . m_datatype , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Сохраняем тип объекта в ячейке
if ( : : FileWriteInteger ( file_handle , this . m_object_type , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Сохраняем номер строки
if ( : : FileWriteInteger ( file_handle , this . m_row , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Сохраняем номер столбца
if ( : : FileWriteInteger ( file_handle , this . m_col , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Сохраняем точность представления данных
if ( : : FileWriteInteger ( file_handle , this . m_digits , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Сохраняем флаги отображения даты/времени
if ( : : FileWriteInteger ( file_handle , this . m_time_flags , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Сохраняем флаг отображения наименования цвета
if ( : : FileWriteInteger ( file_handle , this . m_color_flag , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Сохраняем флаг редактируемой ячейки
if ( : : FileWriteInteger ( file_handle , this . m_editable , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Сохраняем значение
if ( : : FileWriteStruct ( file_handle , this . m_datatype_value ) ! = sizeof ( this . m_datatype_value ) )
return ( false ) ;
//--- Всё успешно
return true ;
}
//+------------------------------------------------------------------+
//| Загрузка из файла |
//+------------------------------------------------------------------+
bool CTableCell : : Load ( const int file_handle )
{
//--- Проверяем хэндл
if ( file_handle = = INVALID_HANDLE )
return ( false ) ;
//--- Загружаем и проверяем маркер начала данных - 0xFFFFFFFFFFFFFFFF
if ( : : FileReadLong ( file_handle ) ! = MARKER_START_DATA )
return ( false ) ;
//--- Загружаем тип объекта
if ( : : FileReadInteger ( file_handle , INT_VALUE ) ! = this . Type ( ) )
return ( false ) ;
//--- Загружаем тип данных
this . m_datatype = ( ENUM_DATATYPE ) : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Загружаем тип объекта в ячейке
this . m_object_type = ( ENUM_OBJECT_TYPE ) : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Загружаем номер строки
this . m_row = : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Загружаем номер столбца
this . m_col = : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Загружаем точность представления данных
this . m_digits = : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Загружаем флаги отображения даты/времени
this . m_time_flags = : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Загружаем флаг отображения наименования цвета
this . m_color_flag = : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Загружаем флаг редактируемой ячейки
this . m_editable = : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Загружаем значение
if ( : : FileReadStruct ( file_handle , this . m_datatype_value ) ! = sizeof ( this . m_datatype_value ) )
return ( false ) ;
//--- Всё успешно
return true ;
}
//+------------------------------------------------------------------+
//| Возвращает описание объекта |
//+------------------------------------------------------------------+
string CTableCell : : Description ( void )
{
return ( : : StringFormat ( " %s: Row %u, Col %u, %s <%s>Value: %s " ,
TypeDescription ( ( ENUM_OBJECT_TYPE ) this . Type ( ) ) , this .Row ( ) , this .Col ( ) ,
( this . m_editable ? " Editable " : " Uneditable " ) , this . DatatypeDescription ( ) , this . Value ( ) ) ) ;
}
//+------------------------------------------------------------------+
//| Выводит в журнал описание объекта |
//+------------------------------------------------------------------+
void CTableCell : : Print ( void )
{
: : Print ( this . Description ( ) ) ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс строки таблицы |
//+------------------------------------------------------------------+
class CTableRow : public CObject
{
protected :
CTableCell m_cell_tmp ; // Объект ячейки для поиска в списке
CListObj m_list_cells ; // Список ячеек
uint m_index ; // Индекс строки
//--- Добавляет указанную ячейку в конец списка
bool AddNewCell ( CTableCell * cell ) ;
public :
//--- (1) Устанавливает, (2) возвращает индекс строки
void SetIndex ( const uint index ) { this . m_index = index ; }
uint Index ( void ) const { return this . m_index ; }
//--- Устанавливает позиции строки и колонки всем ячейкам
void CellsPositionUpdate ( void ) ;
//--- Создаёт новую ячейку и добавляет в конец списка
2026-03-27 00:24:00 +07:00
CTableCell * CellAddNew ( const double value ) ;
CTableCell * CellAddNew ( const long value ) ;
CTableCell * CellAddNew ( const datetime value ) ;
CTableCell * CellAddNew ( const color value ) ;
CTableCell * CellAddNew ( const string value ) ;
2026-03-27 00:05:24 +07:00
//--- Возвращает (1) ячейку по индексу, (2) количество ячеек
CTableCell * GetCell ( const uint index ) { return this . m_list_cells . GetNodeAtIndex ( index ) ; }
uint CellsTotal ( void ) const { return this . m_list_cells . Total ( ) ; }
//--- Устанавливает значение в указанную ячейку
void CellSetValue ( const uint index , const double value ) ;
void CellSetValue ( const uint index , const long value ) ;
void CellSetValue ( const uint index , const datetime value ) ;
void CellSetValue ( const uint index , const color value ) ;
void CellSetValue ( const uint index , const string value ) ;
//--- (1) назначает в ячейку, (2) снимает с ячейки назначенный объект
void CellAssignObject ( const uint index , CObject * object ) ;
void CellUnassignObject ( const uint index ) ;
2026-03-27 00:24:00 +07:00
//--- Возвращает (1) назначенный в ячейку объект, (2) тип назначенного в ячейку объекта
CObject * CellGetObject ( const uint index ) ;
ENUM_OBJECT_TYPE CellGetObjType ( const uint index ) ;
2026-03-27 00:05:24 +07:00
//--- (1) Удаляет (2) перемещает ячейку
bool CellDelete ( const uint index ) ;
bool CellMoveTo ( const uint cell_index , const uint index_to ) ;
//--- Обнуляет данные ячеек строки
void ClearData ( void ) ;
//--- (1) Возвращает, (2) выводит в журнал описание объекта
2026-03-27 00:24:00 +07:00
virtual string Description ( void ) ;
void Print ( const bool detail , const bool as_table = false , const int cell_width = CELL_WIDTH_IN_CHARS ) ;
2026-03-27 00:05:24 +07:00
//--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта
virtual int Compare ( const CObject * node , const int mode = 0 ) const ;
virtual bool Save ( const int file_handle ) ;
virtual bool Load ( const int file_handle ) ;
virtual int Type ( void ) const { return ( OBJECT_TYPE_TABLE_ROW ) ; }
//--- Конструкторы/деструктор
CTableRow ( void ) : m_index ( 0 ) { }
CTableRow ( const uint index ) : m_index ( index ) { }
~ CTableRow ( void ) { }
} ;
//+------------------------------------------------------------------+
//| Сравнение двух объектов |
//+------------------------------------------------------------------+
int CTableRow : : Compare ( const CObject * node , const int mode = 0 ) const
{
2026-03-29 15:13:53 +07:00
/*
Sort ( 0 ) - по индексу строки
Sort ( ASC_IDX_CORRECTION ) - по возрастанию по столбцу 0
Sort ( 1 + ASC_IDX_CORRECTION ) - по возрастанию по столбцу 1
Sort ( 2 + ASC_IDX_CORRECTION ) - по возрастанию по столбцу 2
и т . д .
Sort ( DESC_IDX_CORRECTION ) - по убыванию по столбцу 0
Sort ( 1 + DESC_IDX_CORRECTION ) - по убыванию по столбцу 1
Sort ( 2 + DESC_IDX_CORRECTION ) - по убыванию по столбцу 2
и т . д .
* /
2026-03-29 13:06:34 +07:00
if ( node = = NULL )
return -1 ;
2026-03-29 15:13:53 +07:00
if ( mode = = 0 )
{
const CTableRow * obj = node ;
return ( this . Index ( ) > obj . Index ( ) ? 1 : this . Index ( ) < obj . Index ( ) ? -1 : 0 ) ;
}
//---
bool asc = ( mode > = ASC_IDX_CORRECTION & & mode < DESC_IDX_CORRECTION ) ;
int col = mode % ( asc ? ASC_IDX_CORRECTION : DESC_IDX_CORRECTION ) ;
//--- Снимаем константность node
CTableRow * nonconst_this = ( CTableRow * ) & this ;
CTableRow * nonconst_node = ( CTableRow * ) node ;
//--- Получаем текущую и сравниваемую ячейки по индексу mode
CTableCell * cell_current = nonconst_this . GetCell ( col ) ;
CTableCell * cell_compared = nonconst_node . GetCell ( col ) ;
if ( cell_current = = NULL | | cell_compared = = NULL )
return -1 ;
//--- Сравниваем в зависимости от типа ячейки
int cmp = 0 ;
switch ( cell_current . Datatype ( ) )
{
case TYPE_DOUBLE : cmp = ( cell_current . ValueD ( ) > cell_compared . ValueD ( ) ? 1 : cell_current . ValueD ( ) < cell_compared . ValueD ( ) ? -1 : 0 ) ; break ;
case TYPE_LONG :
case TYPE_DATETIME :
case TYPE_COLOR : cmp = ( cell_current . ValueL ( ) > cell_compared . ValueL ( ) ? 1 : cell_current . ValueL ( ) < cell_compared . ValueL ( ) ? -1 : 0 ) ; break ;
case TYPE_STRING : cmp = : : StringCompare ( cell_current . ValueS ( ) , cell_compared . ValueS ( ) ) ; break ;
default : break ;
}
return ( asc ? cmp : - cmp ) ;
2026-03-27 00:05:24 +07:00
}
//+------------------------------------------------------------------+
//| Создаёт новую double-ячейку и добавляет в конец списка |
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
CTableCell * CTableRow : : CellAddNew ( const double value )
2026-03-27 00:05:24 +07:00
{
//--- Создаём новый объект ячейки, хранящей значение с типом double
CTableCell * cell = new CTableCell ( this . m_index , this . CellsTotal ( ) , value , 2 ) ;
if ( cell = = NULL )
{
: : PrintFormat ( " %s: Error. Failed to create new cell in row %u at position %u " , __FUNCTION__ , this . m_index , this . CellsTotal ( ) ) ;
return NULL ;
}
//--- Добавляем созданную ячейку в конец списка
if ( ! this . AddNewCell ( cell ) )
{
delete cell ;
return NULL ;
}
//--- Возвращаем указатель на объект
return cell ;
}
//+------------------------------------------------------------------+
//| Создаёт новую long-ячейку и добавляет в конец списка |
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
CTableCell * CTableRow : : CellAddNew ( const long value )
2026-03-27 00:05:24 +07:00
{
//--- Создаём новый объект ячейки, хранящей значение с типом long
CTableCell * cell = new CTableCell ( this . m_index , this . CellsTotal ( ) , value ) ;
if ( cell = = NULL )
{
: : PrintFormat ( " %s: Error. Failed to create new cell in row %u at position %u " , __FUNCTION__ , this . m_index , this . CellsTotal ( ) ) ;
return NULL ;
}
//--- Добавляем созданную ячейку в конец списка
if ( ! this . AddNewCell ( cell ) )
{
delete cell ;
return NULL ;
}
//--- Возвращаем указатель на объект
return cell ;
}
//+------------------------------------------------------------------+
//| Создаёт новую datetime-ячейку и добавляет в конец списка |
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
CTableCell * CTableRow : : CellAddNew ( const datetime value )
2026-03-27 00:05:24 +07:00
{
//--- Создаём новый объект ячейки, хранящей значение с типом datetime
CTableCell * cell = new CTableCell ( this . m_index , this . CellsTotal ( ) , value , TIME_DATE | TIME_MINUTES | TIME_SECONDS ) ;
if ( cell = = NULL )
{
: : PrintFormat ( " %s: Error. Failed to create new cell in row %u at position %u " , __FUNCTION__ , this . m_index , this . CellsTotal ( ) ) ;
return NULL ;
}
//--- Добавляем созданную ячейку в конец списка
if ( ! this . AddNewCell ( cell ) )
{
delete cell ;
return NULL ;
}
//--- Возвращаем указатель на объект
return cell ;
}
//+------------------------------------------------------------------+
//| Создаёт новую color-ячейку и добавляет в конец списка |
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
CTableCell * CTableRow : : CellAddNew ( const color value )
2026-03-27 00:05:24 +07:00
{
//--- Создаём новый объект ячейки, хранящей значение с типом color
CTableCell * cell = new CTableCell ( this . m_index , this . CellsTotal ( ) , value , true ) ;
if ( cell = = NULL )
{
: : PrintFormat ( " %s: Error. Failed to create new cell in row %u at position %u " , __FUNCTION__ , this . m_index , this . CellsTotal ( ) ) ;
return NULL ;
}
//--- Добавляем созданную ячейку в конец списка
if ( ! this . AddNewCell ( cell ) )
{
delete cell ;
return NULL ;
}
//--- Возвращаем указатель на объект
return cell ;
}
//+------------------------------------------------------------------+
//| Создаёт новую string-ячейку и добавляет в конец списка |
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
CTableCell * CTableRow : : CellAddNew ( const string value )
2026-03-27 00:05:24 +07:00
{
//--- Создаём новый объект ячейки, хранящей значение с типом string
CTableCell * cell = new CTableCell ( this . m_index , this . CellsTotal ( ) , value ) ;
if ( cell = = NULL )
{
: : PrintFormat ( " %s: Error. Failed to create new cell in row %u at position %u " , __FUNCTION__ , this . m_index , this . CellsTotal ( ) ) ;
return NULL ;
}
//--- Добавляем созданную ячейку в конец списка
if ( ! this . AddNewCell ( cell ) )
{
delete cell ;
return NULL ;
}
//--- Возвращаем указатель на объект
return cell ;
}
//+------------------------------------------------------------------+
//| Добавляет ячейку в конец списка |
//+------------------------------------------------------------------+
bool CTableRow : : AddNewCell ( CTableCell * cell )
{
//--- Если передан пустой объект - сообщаем и возвращаем false
if ( cell = = NULL )
{
: : PrintFormat ( " %s: Error. Empty CTableCell object passed " , __FUNCTION__ ) ;
return false ;
}
//--- Устанавливаем индекс ячейки в списке и добавляем созданную ячейку в конец списка
cell . SetPositionInTable ( this . m_index , this . CellsTotal ( ) ) ;
if ( this . m_list_cells . Add ( cell ) = = WRONG_VALUE )
{
: : PrintFormat ( " %s: Error. Failed to add cell (%u,%u) to list " , __FUNCTION__ , this . m_index , this . CellsTotal ( ) ) ;
return false ;
}
//--- Успешно
return true ;
}
//+------------------------------------------------------------------+
//| Устанавливает double-значение в указанную ячейку |
//+------------------------------------------------------------------+
void CTableRow : : CellSetValue ( const uint index , const double value )
{
//--- Получаем из списка нужную ячейку и записываем в неё новое значение
CTableCell * cell = this . GetCell ( index ) ;
if ( cell ! = NULL )
cell . SetValue ( value ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает long-значение в указанную ячейку |
//+------------------------------------------------------------------+
void CTableRow : : CellSetValue ( const uint index , const long value )
{
//--- Получаем из списка нужную ячейку и записываем в неё новое значение
CTableCell * cell = this . GetCell ( index ) ;
if ( cell ! = NULL )
cell . SetValue ( value ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает datetime-значение в указанную ячейку |
//+------------------------------------------------------------------+
void CTableRow : : CellSetValue ( const uint index , const datetime value )
{
//--- Получаем из списка нужную ячейку и записываем в неё новое значение
CTableCell * cell = this . GetCell ( index ) ;
if ( cell ! = NULL )
cell . SetValue ( value ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает color-значение в указанную ячейку |
//+------------------------------------------------------------------+
void CTableRow : : CellSetValue ( const uint index , const color value )
{
//--- Получаем из списка нужную ячейку и записываем в неё новое значение
CTableCell * cell = this . GetCell ( index ) ;
if ( cell ! = NULL )
cell . SetValue ( value ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает string-значение в указанную ячейку |
//+------------------------------------------------------------------+
void CTableRow : : CellSetValue ( const uint index , const string value )
{
//--- Получаем из списка нужную ячейку и записываем в неё новое значение
CTableCell * cell = this . GetCell ( index ) ;
if ( cell ! = NULL )
cell . SetValue ( value ) ;
}
//+------------------------------------------------------------------+
//| Назначает в ячейку объект |
//+------------------------------------------------------------------+
void CTableRow : : CellAssignObject ( const uint index , CObject * object )
{
//--- Получаем из списка нужную ячейку и записываем в неё указатель на объект
CTableCell * cell = this . GetCell ( index ) ;
if ( cell ! = NULL )
cell . AssignObject ( object ) ;
}
//+------------------------------------------------------------------+
//| Отменяет для ячейки назначенный объект |
//+------------------------------------------------------------------+
void CTableRow : : CellUnassignObject ( const uint index )
{
//--- Получаем из списка нужную ячейку и отменяем в ней указатель на объект и его тип
CTableCell * cell = this . GetCell ( index ) ;
if ( cell ! = NULL )
cell . UnassignObject ( ) ;
}
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
//| Возвращает назначенный в ячейку объект |
//+------------------------------------------------------------------+
CObject * CTableRow : : CellGetObject ( const uint index )
{
//--- Получаем из списка нужную ячейку и возвращаем указатель на назначенный объект
CTableCell * cell = this . GetCell ( index ) ;
return ( cell ! = NULL ? cell . AssignedObject ( ) : NULL ) ;
}
//+------------------------------------------------------------------+
//| Возвращает тип назначенного в ячейку объекта |
//+------------------------------------------------------------------+
ENUM_OBJECT_TYPE CTableRow : : CellGetObjType ( const uint index )
{
//--- Получаем из списка нужную ячейку и возвращаем тип назначенного объекта
CTableCell * cell = this . GetCell ( index ) ;
return ( cell ! = NULL ? cell . AssignedObjType ( ) : ( ENUM_OBJECT_TYPE ) WRONG_VALUE ) ;
}
//+------------------------------------------------------------------+
2026-03-27 00:05:24 +07:00
//| Удаляет ячейку |
//+------------------------------------------------------------------+
bool CTableRow : : CellDelete ( const uint index )
{
//--- Удаляем ячейку в списке по индексу
if ( ! this . m_list_cells . Delete ( index ) )
return false ;
//--- Обновляем индексы для оставшихся ячеек в списке
this . CellsPositionUpdate ( ) ;
return true ;
}
//+------------------------------------------------------------------+
//| Перемещает ячейку на указанную позицию |
//+------------------------------------------------------------------+
bool CTableRow : : CellMoveTo ( const uint cell_index , const uint index_to )
{
//--- Получаем нужную ячейку по индексу в списке, делая её текущей
CTableCell * cell = this . GetCell ( cell_index ) ;
//--- Перемещаем текущую ячейку на указанную позицию в списке
if ( cell = = NULL | | ! this . m_list_cells . MoveToIndex ( index_to ) )
return false ;
//--- Обновляем индексы всех ячеек в списке
this . CellsPositionUpdate ( ) ;
return true ;
}
//+------------------------------------------------------------------+
//| Устанавливает позиции строки и колонки всем ячейкам |
//+------------------------------------------------------------------+
void CTableRow : : CellsPositionUpdate ( void )
{
//--- В цикле по всем ячейкам в списке
for ( int i = 0 ; i < this . m_list_cells . Total ( ) ; i + + )
{
//--- получаем очередную ячейку и устанавливаем в неё индексы строки и столбца
CTableCell * cell = this . GetCell ( i ) ;
if ( cell ! = NULL )
cell . SetPositionInTable ( this . Index ( ) , this . m_list_cells . IndexOf ( cell ) ) ;
}
}
//+------------------------------------------------------------------+
//| Обнуляет данные ячеек строки |
//+------------------------------------------------------------------+
void CTableRow : : ClearData ( void )
{
//--- В цикле по всем ячейкам в списке
for ( uint i = 0 ; i < this . CellsTotal ( ) ; i + + )
{
//--- получаем очередную ячейку и устанавливаем в неё пустое значение
CTableCell * cell = this . GetCell ( i ) ;
if ( cell ! = NULL )
cell . ClearData ( ) ;
}
}
//+------------------------------------------------------------------+
//| Возвращает описание объекта |
//+------------------------------------------------------------------+
string CTableRow : : Description ( void )
{
return ( : : StringFormat ( " %s: Position %u, Cells total: %u " ,
TypeDescription ( ( ENUM_OBJECT_TYPE ) this . Type ( ) ) , this . Index ( ) , this . CellsTotal ( ) ) ) ;
}
//+------------------------------------------------------------------+
//| Выводит в журнал описание объекта |
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
void CTableRow : : Print ( const bool detail , const bool as_table = false , const int cell_width = CELL_WIDTH_IN_CHARS )
2026-03-27 00:05:24 +07:00
{
//--- Количество ячеек
int total = ( int ) this . CellsTotal ( ) ;
//--- Если вывод в табличном виде
string res = " " ;
if ( as_table )
{
//--- создаём строку таблицы из значений всех ячеек
string head = " Row " + ( string ) this . Index ( ) ;
string res = : : StringFormat ( " |%-*s | " , cell_width , head ) ;
for ( int i = 0 ; i < total ; i + + )
{
CTableCell * cell = this . GetCell ( i ) ;
if ( cell = = NULL )
continue ;
res + = : : StringFormat ( " %*s | " , cell_width , cell . Value ( ) ) ;
}
//--- Выводим строку в журнал
: : Print ( res ) ;
return ;
}
//--- Выводим заголовок в виде описания строки
: : Print ( this . Description ( ) + ( detail ? " : " : " " ) ) ;
//--- Если детализированное описание
if ( detail )
{
//--- Вывод не в табличном виде
//--- В цикле по спискук ячеек строки
for ( int i = 0 ; i < total ; i + + )
{
//--- получаем текущую ячейку и добавляем в итоговую строку её описание
CTableCell * cell = this . GetCell ( i ) ;
if ( cell ! = NULL )
res + = " " + cell . Description ( ) + ( i < total -1 ? " \n " : " " ) ;
}
//--- Выводим в журнал созданную в цикле строку
: : Print ( res ) ;
}
}
//+------------------------------------------------------------------+
//| Сохранение в файл |
//+------------------------------------------------------------------+
bool CTableRow : : Save ( const int file_handle )
{
//--- Проверяем хэндл
if ( file_handle = = INVALID_HANDLE )
return ( false ) ;
//--- Сохраняем маркер начала данных - 0xFFFFFFFFFFFFFFFF
if ( : : FileWriteLong ( file_handle , MARKER_START_DATA ) ! = sizeof ( long ) )
return ( false ) ;
//--- Сохраняем тип объекта
if ( : : FileWriteInteger ( file_handle , this . Type ( ) , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Сохраняем индекс
if ( : : FileWriteInteger ( file_handle , this . m_index , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Сохраняем список ячеек
if ( ! this . m_list_cells . Save ( file_handle ) )
return ( false ) ;
//--- Успешно
return true ;
}
//+------------------------------------------------------------------+
//| Загрузка из файла |
//+------------------------------------------------------------------+
bool CTableRow : : Load ( const int file_handle )
{
//--- Проверяем хэндл
if ( file_handle = = INVALID_HANDLE )
return ( false ) ;
//--- Загружаем и проверяем маркер начала данных - 0xFFFFFFFFFFFFFFFF
if ( : : FileReadLong ( file_handle ) ! = MARKER_START_DATA )
return ( false ) ;
//--- Загружаем тип объекта
if ( : : FileReadInteger ( file_handle , INT_VALUE ) ! = this . Type ( ) )
return ( false ) ;
//--- Загружаем индекс
this . m_index = : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Загружаем список ячеек
if ( ! this . m_list_cells . Load ( file_handle ) )
return ( false ) ;
//--- Успешно
return true ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
//| Класс объекта параметра структуры |
//+------------------------------------------------------------------+
class CMqlParamObj : public CObject
{
protected :
public :
MqlParam m_param ;
//--- Установка параметров
void Set ( const MqlParam & param )
{
this . m_param . type = param . type ;
this . m_param . double_value = param . double_value ;
this . m_param . integer_value = param . integer_value ;
this . m_param . string_value = param . string_value ;
}
//--- Возврат параметров
MqlParam Param ( void ) const { return this . m_param ; }
ENUM_DATATYPE Datatype ( void ) const { return this . m_param . type ; }
double ValueD ( void ) const { return this . m_param . double_value ; }
long ValueL ( void ) const { return this . m_param . integer_value ; }
string ValueS ( void ) const { return this . m_param . string_value ; }
//--- Описание объекта
virtual string Description ( void )
{
string t = : : StringSubstr ( : : EnumToString ( this . m_param . type ) , 5 ) ;
t .Lower ( ) ;
string v = " " ;
switch ( this . m_param . type )
{
2026-03-29 15:13:53 +07:00
case TYPE_STRING : v = this . ValueS ( ) ; break ;
case TYPE_FLOAT : case TYPE_DOUBLE : v = : : DoubleToString ( this . ValueD ( ) ) ; break ;
2026-03-27 00:24:00 +07:00
case TYPE_DATETIME : v = : : TimeToString ( this . ValueL ( ) , TIME_DATE | TIME_MINUTES | TIME_SECONDS ) ; break ;
2026-03-29 15:13:53 +07:00
default : v = ( string ) this . ValueL ( ) ; break ;
2026-03-27 00:24:00 +07:00
}
return ( : : StringFormat ( " <%s>%s " , t , v ) ) ;
}
//--- Конструкторы/деструктор
CMqlParamObj ( void ) { }
CMqlParamObj ( const MqlParam & param ) { this .Set ( param ) ; }
~ CMqlParamObj ( void ) { }
} ;
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс для создания списков данных |
//+------------------------------------------------------------------+
class DataListCreator
{
public :
//--- Добавляет новую строку к списку CList list_data
static CList * AddNewRowToDataList ( CList * list_data )
{
CList * row = new CList ;
if ( row = = NULL | | list_data . Add ( row ) < 0 )
return NULL ;
return row ;
}
//--- Создаёт новый объект параметров CMqlParamObj и добавляет его к списку CList
static bool AddNewCellParamToRow ( CList * row , MqlParam & param )
{
CMqlParamObj * cell = new CMqlParamObj ( param ) ;
if ( cell = = NULL )
return false ;
if ( row . Add ( cell ) < 0 )
{
delete cell ;
return false ;
}
return true ;
}
} ;
//+------------------------------------------------------------------+
2026-03-27 00:05:24 +07:00
//| Класс модели таблицы |
//+------------------------------------------------------------------+
class CTableModel : public CObject
{
protected :
CTableRow m_row_tmp ; // Объект строки для поиска в списке
CListObj m_list_rows ; // Список строк таблицы
//--- Создаёт модель таблицы из двумерного массива
template < typename T >
void CreateTableModel ( T & array [ ] [ ] ) ;
2026-03-27 00:24:00 +07:00
void CreateTableModel ( const uint num_rows , const uint num_columns ) ;
void CreateTableModel ( const matrix & row_data ) ;
void CreateTableModel ( CList & list_param ) ;
2026-03-27 00:05:24 +07:00
//--- Возвращает корректный тип данных
ENUM_DATATYPE GetCorrectDatatype ( string type_name )
{
return
(
//--- Целочисленное значение
type_name = = " bool " | | type_name = = " char " | | type_name = = " uchar " | |
type_name = = " short " | | type_name = = " ushort " | | type_name = = " int " | |
type_name = = " uint " | | type_name = = " long " | | type_name = = " ulong " ? TYPE_LONG :
//--- Вещественное значение
type_name = = " float " | | type_name = = " double " ? TYPE_DOUBLE :
//--- Значение даты/времени
type_name = = " datetime " ? TYPE_DATETIME :
//--- Значение цвета
type_name = = " color " ? TYPE_COLOR :
/*--- Строковое значение */ TYPE_STRING ) ;
}
//--- Создаёт и добавляет новую пустую строку в конец списка
CTableRow * CreateNewEmptyRow ( void ) ;
//--- Добавляет строку в конец списка
bool AddNewRow ( CTableRow * row ) ;
//--- Устанавливает позиции строки и колонки всем ячейкам таблицы
void CellsPositionUpdate ( void ) ;
public :
//--- Возвращает (1) ячейку, (2) строку по индексу, количество (3) строк, ячеек (4) в указанной строке, (5) в таблице
CTableCell * GetCell ( const uint row , const uint col ) ;
2026-03-29 13:06:34 +07:00
CTableRow * GetRow ( const uint index ) { return this . m_list_rows . GetNodeAtIndex ( index ) ; }
uint RowsTotal ( void ) const { return this . m_list_rows . Total ( ) ; }
2026-03-27 00:05:24 +07:00
uint CellsInRow ( const uint index ) ;
uint CellsTotal ( void ) ;
//--- Устанавливает (1) значение, (2) точность, (3) флаги отображения времени, (4) флаг отображения имён цветов в указанную ячейку
template < typename T >
void CellSetValue ( const uint row , const uint col , const T value ) ;
void CellSetDigits ( const uint row , const uint col , const int digits ) ;
void CellSetTimeFlags ( const uint row , const uint col , const uint flags ) ;
void CellSetColorNamesFlag ( const uint row , const uint col , const bool flag ) ;
//--- (1) Назначает, (2) отменяет объект в ячейке
void CellAssignObject ( const uint row , const uint col , CObject * object ) ;
void CellUnassignObject ( const uint row , const uint col ) ;
//--- (1) Удаляет (2) перемещает ячейку
bool CellDelete ( const uint row , const uint col ) ;
bool CellMoveTo ( const uint row , const uint cell_index , const uint index_to ) ;
2026-03-27 00:24:00 +07:00
//---Возвращает (1) назначенный в ячейку объект, (2) тип назначенного в ячейку объекта
CObject * CellGetObject ( const uint row , const uint col ) ;
ENUM_OBJECT_TYPE CellGetObjType ( const uint row , const uint col ) ;
2026-03-27 00:05:24 +07:00
//--- (1) Возвращает, (2) выводит в журнал описание ячейки, (3) назначенный в ячейку объект
string CellDescription ( const uint row , const uint col ) ;
void CellPrint ( const uint row , const uint col ) ;
2026-03-27 00:24:00 +07:00
2026-03-27 00:05:24 +07:00
public :
//--- Создаёт новую строку и (1) добавляет в конец списка, (2) вставляет в указанную позицию списка
CTableRow * RowAddNew ( void ) ;
CTableRow * RowInsertNewTo ( const uint index_to ) ;
//--- (1) Удаляет (2) перемещает строку, (3) очищает данные строки
bool RowDelete ( const uint index ) ;
bool RowMoveTo ( const uint row_index , const uint index_to ) ;
2026-03-27 00:24:00 +07:00
void RowClearData ( const uint index ) ;
2026-03-27 00:05:24 +07:00
//--- (1) Возвращает, (2) выводит в журнал описание строки
string RowDescription ( const uint index ) ;
void RowPrint ( const uint index , const bool detail ) ;
2026-03-29 15:13:53 +07:00
//--- (1) Добавляет, (2) удаляет (3) перемещает столбец, (4) очищает данные, устанавливает (5) тип,
//--- (6) точность данных, флаги отображения (7) времени, (8) имён цветов столбца
2026-03-27 00:24:00 +07:00
bool ColumnAddNew ( const int index = -1 ) ;
2026-03-27 00:05:24 +07:00
bool ColumnDelete ( const uint index ) ;
2026-03-27 00:24:00 +07:00
bool ColumnMoveTo ( const uint col_index , const uint index_to ) ;
void ColumnClearData ( const uint index ) ;
void ColumnSetDatatype ( const uint index , const ENUM_DATATYPE type ) ;
void ColumnSetDigits ( const uint index , const int digits ) ;
2026-03-27 00:05:24 +07:00
2026-03-29 15:13:53 +07:00
void ColumnSetTimeFlags ( const uint index , const uint flags ) ;
void ColumnSetColorNamesFlag ( const uint index , const bool flag ) ;
//--- Сортирует таблицу по указанному столбцу и направлению
void SortByColumn ( const uint column , const bool descending ) ;
2026-03-27 00:05:24 +07:00
//--- (1) Возвращает, (2) выводит в журнал описание таблицы
2026-03-27 00:24:00 +07:00
virtual string Description ( void ) ;
2026-03-27 00:05:24 +07:00
void Print ( const bool detail ) ;
2026-03-27 00:24:00 +07:00
void PrintTable ( const int cell_width = CELL_WIDTH_IN_CHARS ) ;
2026-03-27 00:05:24 +07:00
//--- (1) Очищает данные, (2) уничтожает модель
void ClearData ( void ) ;
void Destroy ( void ) ;
//--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта
2026-03-29 13:06:34 +07:00
virtual int Compare ( const CObject * node , const int mode = 0 ) const { return -1 ; }
2026-03-27 00:05:24 +07:00
virtual bool Save ( const int file_handle ) ;
virtual bool Load ( const int file_handle ) ;
virtual int Type ( void ) const { return ( OBJECT_TYPE_TABLE_MODEL ) ; }
//--- Конструкторы/деструктор
2026-03-27 00:24:00 +07:00
template < typename T > CTableModel ( T & array [ ] [ ] ) { this . CreateTableModel ( array ) ; }
CTableModel ( const uint num_rows , const uint num_columns ) { this . CreateTableModel ( num_rows , num_columns ) ; }
CTableModel ( const matrix & row_data ) { this . CreateTableModel ( row_data ) ; }
CTableModel ( CList & row_data ) { this . CreateTableModel ( row_data ) ; }
2026-03-27 00:05:24 +07:00
CTableModel ( void ) { }
~ CTableModel ( void ) { }
} ;
//+------------------------------------------------------------------+
//| Создаёт модель таблицы из двумерного массива |
//+------------------------------------------------------------------+
template < typename T >
void CTableModel : : CreateTableModel ( T & array [ ] [ ] )
{
//--- Получаем из свойств массива количество строк и столбцов таблицы
int rows_total = : : ArrayRange ( array , 0 ) ;
int cols_total = : : ArrayRange ( array , 1 ) ;
//--- В цикле по индексам строк
for ( int r = 0 ; r < rows_total ; r + + )
{
//--- создаём новую пустую строку и добавляем её в конец списка строк
CTableRow * row = this . CreateNewEmptyRow ( ) ;
//--- Если строка создана и добавлена в список,
if ( row ! = NULL )
{
//--- В цикле по количеству ячеек в строке
//--- создаём все ячейки, добавляя каждую новую в конец списка ячеек строки
for ( int c = 0 ; c < cols_total ; c + + )
2026-03-27 00:24:00 +07:00
row . CellAddNew ( array [ r ] [ c ] ) ;
}
}
}
//+------------------------------------------------------------------+
//| Создаёт модель таблицы из указанного количества строк и столбцов |
//+------------------------------------------------------------------+
void CTableModel : : CreateTableModel ( const uint num_rows , const uint num_columns )
{
//--- В цикле по количеству строк
for ( uint r = 0 ; r < num_rows ; r + + )
{
//--- создаём новую пустую строку и добавляем её в конец списка строк
CTableRow * row = this . CreateNewEmptyRow ( ) ;
//--- Если строка создана и добавлена в список,
if ( row ! = NULL )
{
//--- В цикле по количеству столбцов
//--- создаём все ячейки, добавляя каждую новую в конец списка ячеек строки
for ( uint c = 0 ; c < num_columns ; c + + )
{
CTableCell * cell = row . CellAddNew ( 0.0 ) ;
if ( cell ! = NULL )
cell . ClearData ( ) ;
}
}
}
}
//+------------------------------------------------------------------+
//| Создаёт модель таблицы из указанной матрицы |
//+------------------------------------------------------------------+
void CTableModel : : CreateTableModel ( const matrix & row_data )
{
//--- Количество строк и столбцов
ulong num_rows = row_data .Rows ( ) ;
ulong num_columns = row_data .Cols ( ) ;
//--- В цикле по количеству строк
for ( uint r = 0 ; r < num_rows ; r + + )
{
//--- создаём новую пустую строку и добавляем её в конец списка строк
CTableRow * row = this . CreateNewEmptyRow ( ) ;
//--- Если строка создана и добавлена в список,
if ( row ! = NULL )
{
//--- В цикле по количеству столбцов
//--- создаём все ячейки, добавляя каждую новую в конец списка ячеек строки
for ( uint c = 0 ; c < num_columns ; c + + )
row . CellAddNew ( row_data [ r ] [ c ] ) ;
}
}
}
//+------------------------------------------------------------------+
//| Создаёт модель таблицы из списка параметров |
//+------------------------------------------------------------------+
void CTableModel : : CreateTableModel ( CList & list_param )
{
//--- Если передан пустой список - сообщаем об этом и уходим
if ( list_param . Total ( ) = = 0 )
{
: : PrintFormat ( " %s: Error. Empty list passed " , __FUNCTION__ ) ;
return ;
}
//--- Получаем указатель на первую строку таблицы для определения количества столбцов
//--- Если первую строку получить не удалось, или в ней нет ячеек - сообщаем об этом и уходим
CList * first_row = list_param . GetFirstNode ( ) ;
if ( first_row = = NULL | | first_row . Total ( ) = = 0 )
{
if ( first_row = = NULL )
: : PrintFormat ( " %s: Error. Failed to get first row of list " , __FUNCTION__ ) ;
else
: : PrintFormat ( " %s: Error. First row does not contain data " , __FUNCTION__ ) ;
return ;
}
//--- Количество строк и столбцов
ulong num_rows = list_param . Total ( ) ;
ulong num_columns = first_row . Total ( ) ;
//--- В цикле по количеству строк
for ( uint r = 0 ; r < num_rows ; r + + )
{
//--- получаем очередную строку таблицы из списка list_param
CList * col_list = list_param . GetNodeAtIndex ( r ) ;
if ( col_list = = NULL )
continue ;
//--- создаём новую пустую строку и добавляем её в конец списка строк
CTableRow * row = this . CreateNewEmptyRow ( ) ;
//--- Если строка создана и добавлена в список,
if ( row ! = NULL )
{
//--- В цикле по количеству столбцов
//--- создаём все ячейки, добавляя каждую новую в конец списка ячеек строки
for ( uint c = 0 ; c < num_columns ; c + + )
{
CMqlParamObj * param = col_list . GetNodeAtIndex ( c ) ;
if ( param = = NULL )
continue ;
//--- Объявляем указатель на ячейку и тип данных, которые будут в ней содержаться
CTableCell * cell = NULL ;
ENUM_DATATYPE datatype = param . Datatype ( ) ;
//--- В зависимости от типа данных
switch ( datatype )
{
//--- вещественный тип данных
case TYPE_FLOAT :
case TYPE_DOUBLE : cell = row . CellAddNew ( ( double ) param . ValueD ( ) ) ; // Создаём новую ячейку с double-данными и
if ( cell ! = NULL )
cell . SetDigits ( ( int ) param . ValueL ( ) ) ; // записываем точность отображаемых данных
break ;
//--- тип данных datetime
case TYPE_DATETIME : cell = row . CellAddNew ( ( datetime ) param . ValueL ( ) ) ; // Создаём новую ячейку с datetime-данными и
if ( cell ! = NULL )
cell . SetDatetimeFlags ( ( int ) param . ValueD ( ) ) ; // записываем флаги отображения даты/времени
break ;
//--- тип данных color
case TYPE_COLOR : cell = row . CellAddNew ( ( color ) param . ValueL ( ) ) ; // Создаём новую ячейку с color-данными и
if ( cell ! = NULL )
cell . SetColorNameFlag ( ( bool ) param . ValueD ( ) ) ; // записваем флаг отображения наименования известных цветов
break ;
//--- строковый тип данных
case TYPE_STRING : cell = row . CellAddNew ( ( string ) param . ValueS ( ) ) ; // Создаём новую ячейку со string-данными
break ;
//--- целочисленный тип данных
default : cell = row . CellAddNew ( ( long ) param . ValueL ( ) ) ; // Создаём новую ячейку с long-данными
break ;
}
}
2026-03-27 00:05:24 +07:00
}
}
}
//+------------------------------------------------------------------+
//| Создаёт новую пустую строку и добавляет в конец списка |
//+------------------------------------------------------------------+
CTableRow * CTableModel : : CreateNewEmptyRow ( void )
{
//--- Создаём новый объект строки
CTableRow * row = new CTableRow ( this . m_list_rows . Total ( ) ) ;
if ( row = = NULL )
{
: : PrintFormat ( " %s: Error. Failed to create new row at position %u " , __FUNCTION__ , this . m_list_rows . Total ( ) ) ;
return NULL ;
}
//--- Если строку не удалось добавить в список - удаляем созданный новый объект и возвращаем NULL
if ( ! this . AddNewRow ( row ) )
{
delete row ;
return NULL ;
}
//--- Успешно - возвращаем указатель на созданный объект
return row ;
}
//+------------------------------------------------------------------+
//| Добавляет строку в конец списка |
//+------------------------------------------------------------------+
bool CTableModel : : AddNewRow ( CTableRow * row )
{
//--- Если передан пустой объект - сообщаем об этом и возвращаем false
if ( row = = NULL )
{
: : PrintFormat ( " %s: Error. Empty CTableRow object passed " , __FUNCTION__ ) ;
return false ;
}
//--- Устанавливаем строке её индекс в списке и добавляем её в конец списка
row . SetIndex ( this . RowsTotal ( ) ) ;
if ( this . m_list_rows . Add ( row ) = = WRONG_VALUE )
{
: : PrintFormat ( " %s: Error. Failed to add row (%u) to list " , __FUNCTION__ , row . Index ( ) ) ;
return false ;
}
//--- Успешно
return true ;
}
//+------------------------------------------------------------------+
//| Создаёт новую строку и добавляет в конец списка |
//+------------------------------------------------------------------+
CTableRow * CTableModel : : RowAddNew ( void )
{
//--- Создаём новую пустую строку и добавляем её в конец списка строк
CTableRow * row = this . CreateNewEmptyRow ( ) ;
if ( row = = NULL )
return NULL ;
//--- Создаём ячейки по количеству ячеек первой строки
for ( uint i = 0 ; i < this . CellsInRow ( 0 ) ; i + + )
2026-03-27 00:24:00 +07:00
row . CellAddNew ( 0.0 ) ;
2026-03-27 00:05:24 +07:00
row . ClearData ( ) ;
//--- Успешно - возвращаем указатель на созданный объект
return row ;
}
//+------------------------------------------------------------------+
//| Создаёт и добавляет новую строку в указанную позицию списка |
//+------------------------------------------------------------------+
CTableRow * CTableModel : : RowInsertNewTo ( const uint index_to )
{
//--- Создаём новую пустую строку и добавляем её в конец списка строк
CTableRow * row = this . CreateNewEmptyRow ( ) ;
if ( row = = NULL )
return NULL ;
//--- Создаём ячейки по количеству ячеек первой строки
for ( uint i = 0 ; i < this . CellsInRow ( 0 ) ; i + + )
2026-03-27 00:24:00 +07:00
row . CellAddNew ( 0.0 ) ;
2026-03-27 00:05:24 +07:00
row . ClearData ( ) ;
//--- Смещаем строку на позицию index_to
this . RowMoveTo ( this . m_list_rows . IndexOf ( row ) , index_to ) ;
//--- Успешно - возвращаем указатель на созданный объект
return row ;
}
//+------------------------------------------------------------------+
//| Устанавливает значение в указанную ячейку |
//+------------------------------------------------------------------+
template < typename T >
void CTableModel : : CellSetValue ( const uint row , const uint col , const T value )
{
//--- Получаем ячейку по индексам строки и столбца
CTableCell * cell = this . GetCell ( row , col ) ;
if ( cell = = NULL )
return ;
//--- Получаем корректный тип устанавливаемых данных (double, long, datetime, color, string)
ENUM_DATATYPE type = this . GetCorrectDatatype ( typename ( T ) ) ;
//--- В зависимости от типа данных вызываем соответствующий типу данных
//--- метод ячейки для установки значения, явно указывая требуемый тип
switch ( type )
{
case TYPE_DOUBLE : cell . SetValue ( ( double ) value ) ; break ;
case TYPE_LONG : cell . SetValue ( ( long ) value ) ; break ;
case TYPE_DATETIME : cell . SetValue ( ( datetime ) value ) ; break ;
case TYPE_COLOR : cell . SetValue ( ( color ) value ) ; break ;
case TYPE_STRING : cell . SetValue ( ( string ) value ) ; break ;
default : break ;
}
}
//+------------------------------------------------------------------+
//| Устанавливает точность отображения данных в указанную ячейку |
//+------------------------------------------------------------------+
void CTableModel : : CellSetDigits ( const uint row , const uint col , const int digits )
{
//--- Получаем ячейку по индексам строки и столбца и
//--- вызываем её соответствующий метод для установки значения
CTableCell * cell = this . GetCell ( row , col ) ;
if ( cell ! = NULL )
cell . SetDigits ( digits ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает флаги отображения времени в указанную ячейку |
//+------------------------------------------------------------------+
void CTableModel : : CellSetTimeFlags ( const uint row , const uint col , const uint flags )
{
//--- Получаем ячейку по индексам строки и столбца и
//--- вызываем её соответствующий метод для установки значения
CTableCell * cell = this . GetCell ( row , col ) ;
if ( cell ! = NULL )
cell . SetDatetimeFlags ( flags ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает флаг отображения имён цветов в указанную ячейку |
//+------------------------------------------------------------------+
void CTableModel : : CellSetColorNamesFlag ( const uint row , const uint col , const bool flag )
{
//--- Получаем ячейку по индексам строки и столбца и
//--- вызываем её соответствующий метод для установки значения
CTableCell * cell = this . GetCell ( row , col ) ;
if ( cell ! = NULL )
cell . SetColorNameFlag ( flag ) ;
}
//+------------------------------------------------------------------+
//| Назначает объект в ячейку |
//+------------------------------------------------------------------+
void CTableModel : : CellAssignObject ( const uint row , const uint col , CObject * object )
{
//--- Получаем ячейку по индексам строки и столбца и
//--- вызываем её соответствующий метод для установки значения
CTableCell * cell = this . GetCell ( row , col ) ;
if ( cell ! = NULL )
cell . AssignObject ( object ) ;
}
//+------------------------------------------------------------------+
//| Отменяет назначение объекта в ячейке |
//+------------------------------------------------------------------+
void CTableModel : : CellUnassignObject ( const uint row , const uint col )
{
//--- Получаем ячейку по индексам строки и столбца и
//--- вызываем её соответствующий метод для установки значения
CTableCell * cell = this . GetCell ( row , col ) ;
if ( cell ! = NULL )
cell . UnassignObject ( ) ;
}
//+------------------------------------------------------------------+
//| Удаляет ячейку |
//+------------------------------------------------------------------+
bool CTableModel : : CellDelete ( const uint row , const uint col )
{
//--- Получаем строку по индексу и возвращаем результат удаления ячейки из списка
CTableRow * row_obj = this . GetRow ( row ) ;
return ( row_obj ! = NULL ? row_obj . CellDelete ( col ) : false ) ;
}
//+------------------------------------------------------------------+
//| Перемещает ячейку |
//+------------------------------------------------------------------+
bool CTableModel : : CellMoveTo ( const uint row , const uint cell_index , const uint index_to )
{
//--- Получаем строку по индексу и возвращаем результат перемещения ячейки на новую позицию
CTableRow * row_obj = this . GetRow ( row ) ;
return ( row_obj ! = NULL ? row_obj . CellMoveTo ( cell_index , index_to ) : false ) ;
}
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
//| Возвращает назначенный в ячейку объект |
//+------------------------------------------------------------------+
CObject * CTableModel : : CellGetObject ( const uint row , const uint col )
{
//--- Получаем строку по индексу и возвращаем объект, назначенный на ячейку с индексом col
CTableRow * row_obj = this . GetRow ( row ) ;
return ( row_obj ! = NULL ? row_obj . CellGetObject ( col ) : NULL ) ;
}
//+------------------------------------------------------------------+
//| Возвращает тип назначенного в ячейку объекта |
//+------------------------------------------------------------------+
ENUM_OBJECT_TYPE CTableModel : : CellGetObjType ( const uint row , const uint col )
{
//--- Получаем строку по индексу и возвращаем тип объекта, назначенного на ячейку с индексом col
CTableRow * row_obj = this . GetRow ( row ) ;
return ( row_obj ! = NULL ? row_obj . CellGetObjType ( col ) : ( ENUM_OBJECT_TYPE ) WRONG_VALUE ) ;
}
//+------------------------------------------------------------------+
2026-03-27 00:05:24 +07:00
//| Возвращает количество ячеек в указанной строке |
//+------------------------------------------------------------------+
uint CTableModel : : CellsInRow ( const uint index )
{
CTableRow * row = this . GetRow ( index ) ;
return ( row ! = NULL ? row . CellsTotal ( ) : 0 ) ;
}
//+------------------------------------------------------------------+
//| Возвращает количество ячеек в таблице |
//+------------------------------------------------------------------+
uint CTableModel : : CellsTotal ( void )
{
//--- подсчёт ячеек в цикле по строкам (медленно при большом количестве строк)
uint res = 0 , total = this . RowsTotal ( ) ;
for ( int i = 0 ; i < ( int ) total ; i + + )
{
CTableRow * row = this . GetRow ( i ) ;
res + = ( row ! = NULL ? row . CellsTotal ( ) : 0 ) ;
}
return res ;
}
//+------------------------------------------------------------------+
//| Возвращает указанную ячейку таблицы |
//+------------------------------------------------------------------+
CTableCell * CTableModel : : GetCell ( const uint row , const uint col )
{
//--- Получаем строку по индексу row и возвращаем по индексу col ячейку строки
CTableRow * row_obj = this . GetRow ( row ) ;
return ( row_obj ! = NULL ? row_obj . GetCell ( col ) : NULL ) ;
}
//+------------------------------------------------------------------+
//| Возвращает описание ячейки |
//+------------------------------------------------------------------+
string CTableModel : : CellDescription ( const uint row , const uint col )
{
CTableCell * cell = this . GetCell ( row , col ) ;
return ( cell ! = NULL ? cell . Description ( ) : " " ) ;
}
//+------------------------------------------------------------------+
//| Выводит в журнал описание ячейки |
//+------------------------------------------------------------------+
void CTableModel : : CellPrint ( const uint row , const uint col )
{
//--- Получаем ячейку по индексу строки и колонки и возвращаем её описание
CTableCell * cell = this . GetCell ( row , col ) ;
if ( cell ! = NULL )
cell . Print ( ) ;
}
//+------------------------------------------------------------------+
//| Удаляет строку |
//+------------------------------------------------------------------+
bool CTableModel : : RowDelete ( const uint index )
{
//--- Удаляем строку из списка по индексу
if ( ! this . m_list_rows . Delete ( index ) )
return false ;
//--- После удаления строки необходимо обновить все индексы всех ячеек таблицы
this . CellsPositionUpdate ( ) ;
return true ;
}
//+------------------------------------------------------------------+
//| Перемещает строку на указанную позицию |
//+------------------------------------------------------------------+
bool CTableModel : : RowMoveTo ( const uint row_index , const uint index_to )
{
//--- Получаем строку по индексу, делая её текущей
CTableRow * row = this . GetRow ( row_index ) ;
//--- Перемещаем текущую строку на указанную позицию в списке
if ( row = = NULL | | ! this . m_list_rows . MoveToIndex ( index_to ) )
return false ;
//--- После перемещения строки необходимо обновить все индексы всех ячеек таблицы
this . CellsPositionUpdate ( ) ;
return true ;
}
//+------------------------------------------------------------------+
//| Устанавливает позиции строки и колонки всем ячейкам |
//+------------------------------------------------------------------+
void CTableModel : : CellsPositionUpdate ( void )
{
//--- В цикле по списку строк
for ( int i = 0 ; i < this . m_list_rows . Total ( ) ; i + + )
{
//--- получаем очередную строку
CTableRow * row = this . GetRow ( i ) ;
if ( row = = NULL )
continue ;
//--- устанавливаем строке индекс, найденный методом IndexOf() списка
row . SetIndex ( this . m_list_rows . IndexOf ( row ) ) ;
//--- Обновляем индексы позиций ячеек строки
row . CellsPositionUpdate ( ) ;
}
}
//+------------------------------------------------------------------+
//| Очищает строку (только данные в ячйках) |
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
void CTableModel : : RowClearData ( const uint index )
2026-03-27 00:05:24 +07:00
{
//--- Получаем строку из списка и очищаем данные ячеек строки методом ClearData()
CTableRow * row = this . GetRow ( index ) ;
if ( row ! = NULL )
row . ClearData ( ) ;
}
//+------------------------------------------------------------------+
//| Очищает таблицу (данные всех ячеек) |
//+------------------------------------------------------------------+
void CTableModel : : ClearData ( void )
{
//--- В цикле по всем строкам таблицы очищаем данные каждой строки
for ( uint i = 0 ; i < this . RowsTotal ( ) ; i + + )
2026-03-27 00:24:00 +07:00
this . RowClearData ( i ) ;
2026-03-27 00:05:24 +07:00
}
//+------------------------------------------------------------------+
//| Возвращает описание строки |
//+------------------------------------------------------------------+
string CTableModel : : RowDescription ( const uint index )
{
//--- Получаем строку по индексу и возвращаем её описание
CTableRow * row = this . GetRow ( index ) ;
return ( row ! = NULL ? row . Description ( ) : " " ) ;
}
//+------------------------------------------------------------------+
//| Выводит в журнал описание строки |
//+------------------------------------------------------------------+
void CTableModel : : RowPrint ( const uint index , const bool detail )
{
CTableRow * row = this . GetRow ( index ) ;
if ( row ! = NULL )
row . Print ( detail ) ;
}
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
//| Добавляет столбец |
//+------------------------------------------------------------------+
bool CTableModel : : ColumnAddNew ( const int index = -1 )
{
//--- Объявляем переменные
CTableCell * cell = NULL ;
bool res = true ;
//--- В цикле по количеству строк
for ( uint i = 0 ; i < this . RowsTotal ( ) ; i + + )
{
//--- получаем очередную строку
CTableRow * row = this . GetRow ( i ) ;
if ( row ! = NULL )
{
//--- добавляем в конец строки ячейку с типом double
cell = row . CellAddNew ( 0.0 ) ;
if ( cell = = NULL )
res & = false ;
//--- очищаем ячейку
else
cell . ClearData ( ) ;
}
}
//--- Если передан индекс колонки не отрицательный - сдвигаем колонку на указанную позицию
if ( res & & index > -1 )
res & = this . ColumnMoveTo ( this . CellsInRow ( 0 ) -1 , index ) ;
//--- Возвращаем результат
return res ;
}
//+------------------------------------------------------------------+
2026-03-27 00:05:24 +07:00
//| Удаляет столбец |
//+------------------------------------------------------------------+
bool CTableModel : : ColumnDelete ( const uint index )
{
bool res = true ;
for ( uint i = 0 ; i < this . RowsTotal ( ) ; i + + )
{
CTableRow * row = this . GetRow ( i ) ;
if ( row ! = NULL )
res & = row . CellDelete ( index ) ;
}
return res ;
}
//+------------------------------------------------------------------+
//| Перемещает столбец |
//+------------------------------------------------------------------+
bool CTableModel : : ColumnMoveTo ( const uint col_index , const uint index_to )
{
bool res = true ;
for ( uint i = 0 ; i < this . RowsTotal ( ) ; i + + )
{
CTableRow * row = this . GetRow ( i ) ;
if ( row ! = NULL )
res & = row . CellMoveTo ( col_index , index_to ) ;
}
return res ;
}
//+------------------------------------------------------------------+
//| Очищает данные столбца |
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
void CTableModel : : ColumnClearData ( const uint index )
2026-03-27 00:05:24 +07:00
{
//--- В цикле по всем строкам таблицы
for ( uint i = 0 ; i < this . RowsTotal ( ) ; i + + )
{
//--- получаем из каждой строки ячейку с индексом столбца и очищаем её
CTableCell * cell = this . GetCell ( i , index ) ;
if ( cell ! = NULL )
cell . ClearData ( ) ;
}
}
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
//| Устанавливает тип данных столбца |
//+------------------------------------------------------------------+
void CTableModel : : ColumnSetDatatype ( const uint index , const ENUM_DATATYPE type )
{
//--- В цикле по всем строкам таблицы
for ( uint i = 0 ; i < this . RowsTotal ( ) ; i + + )
{
//--- получаем из каждой строки ячейку с индексом столбца и устанавливаем тип данных
CTableCell * cell = this . GetCell ( i , index ) ;
if ( cell ! = NULL )
cell . SetDatatype ( type ) ;
}
}
//+------------------------------------------------------------------+
//| Устанавливает точность данных столбца |
//+------------------------------------------------------------------+
void CTableModel : : ColumnSetDigits ( const uint index , const int digits )
{
//--- В цикле по всем строкам таблицы
for ( uint i = 0 ; i < this . RowsTotal ( ) ; i + + )
{
//--- получаем из каждой строки ячейку с индексом столбца и устанавливаем точность данных
CTableCell * cell = this . GetCell ( i , index ) ;
if ( cell ! = NULL )
cell . SetDigits ( digits ) ;
}
}
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
//| Устанавливает флаги отображения времени столбца |
//+------------------------------------------------------------------+
void CTableModel : : ColumnSetTimeFlags ( const uint index , const uint flags )
{
//--- В цикле по всем строкам таблицы
for ( uint i = 0 ; i < this . RowsTotal ( ) ; i + + )
{
//--- получаем из каждой строки ячейку с индексом столбца и устанавливаем флаги отображения времени
CTableCell * cell = this . GetCell ( i , index ) ;
if ( cell ! = NULL )
cell . SetDatetimeFlags ( flags ) ;
}
}
//+------------------------------------------------------------------+
//| Устанавливает флагb отображения имён цветов столбца |
//+------------------------------------------------------------------+
void CTableModel : : ColumnSetColorNamesFlag ( const uint index , const bool flag )
{
//--- В цикле по всем строкам таблицы
for ( uint i = 0 ; i < this . RowsTotal ( ) ; i + + )
{
//--- получаем из каждой строки ячейку с индексом столбца и устанавливаем флаг отображения имён цветов
CTableCell * cell = this . GetCell ( i , index ) ;
if ( cell ! = NULL )
cell . SetColorNameFlag ( flag ) ;
}
}
//+------------------------------------------------------------------+
//| Сортирует таблицу по указанному столбцу и направлению |
//+------------------------------------------------------------------+
void CTableModel : : SortByColumn ( const uint column , const bool descending )
{
if ( this . m_list_rows . Total ( ) = = 0 )
return ;
int mode = ( int ) column + ( descending ? DESC_IDX_CORRECTION : ASC_IDX_CORRECTION ) ;
this . m_list_rows .Sort ( mode ) ;
this . CellsPositionUpdate ( ) ;
}
//+------------------------------------------------------------------+
2026-03-27 00:05:24 +07:00
//| Возвращает описание объекта |
//+------------------------------------------------------------------+
string CTableModel : : Description ( void )
{
return ( : : StringFormat ( " %s: Rows %u, Cells in row %u, Cells Total %u " ,
TypeDescription ( ( ENUM_OBJECT_TYPE ) this . Type ( ) ) , this . RowsTotal ( ) , this . CellsInRow ( 0 ) , this . CellsTotal ( ) ) ) ;
}
//+------------------------------------------------------------------+
//| Выводит в журнал описание объекта |
//+------------------------------------------------------------------+
void CTableModel : : Print ( const bool detail )
{
//--- Выводим в журнал заголовок
: : Print ( this . Description ( ) + ( detail ? " : " : " " ) ) ;
//--- Если детализированное описание,
if ( detail )
{
//--- В цикле по всем строкам таблицы
for ( uint i = 0 ; i < this . RowsTotal ( ) ; i + + )
{
//--- получаем очередную строку и выводим в журнал её детализированное описание
CTableRow * row = this . GetRow ( i ) ;
if ( row ! = NULL )
row . Print ( true , false ) ;
}
}
}
//+------------------------------------------------------------------+
//| Выводит в журнал описание объекта в табличном виде |
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
void CTableModel : : PrintTable ( const int cell_width = CELL_WIDTH_IN_CHARS )
2026-03-27 00:05:24 +07:00
{
//--- Получаем указатель на первую строку (индекс 0)
CTableRow * row = this . GetRow ( 0 ) ;
if ( row = = NULL )
return ;
//--- По количеству ячеек первой строки таблицы создаём строку заголовка таблицы
uint total = row . CellsTotal ( ) ;
string head = " n/n " ;
string res = : : StringFormat ( " |%*s | " , cell_width , head ) ;
for ( uint i = 0 ; i < total ; i + + )
{
if ( this . GetCell ( 0 , i ) = = NULL )
continue ;
string cell_idx = " Column " + ( string ) i ;
res + = : : StringFormat ( " %*s | " , cell_width , cell_idx ) ;
}
//--- Выводим строку заголовка в журнал
: : Print ( res ) ;
//--- Пройдём в цикле по всем строкам таблицы и распечатаем их в табличном виде
for ( uint i = 0 ; i < this . RowsTotal ( ) ; i + + )
{
CTableRow * row = this . GetRow ( i ) ;
if ( row ! = NULL )
row . Print ( true , true , cell_width ) ;
}
}
//+------------------------------------------------------------------+
//| Уничтожает модель |
2026-03-26 23:54:10 +07:00
//+------------------------------------------------------------------+
2026-03-27 00:05:24 +07:00
void CTableModel : : Destroy ( void )
{
//--- Очищаем список строк
2026-03-27 00:24:00 +07:00
this . m_list_rows . Clear ( ) ;
2026-03-27 00:05:24 +07:00
}
2026-03-26 23:54:10 +07:00
//+------------------------------------------------------------------+
2026-03-27 00:05:24 +07:00
//| Сохранение в файл |
2026-03-26 23:54:10 +07:00
//+------------------------------------------------------------------+
2026-03-27 00:05:24 +07:00
bool CTableModel : : Save ( const int file_handle )
{
//--- Проверяем хэндл
if ( file_handle = = INVALID_HANDLE )
return ( false ) ;
//--- Сохраняем маркер начала данных - 0xFFFFFFFFFFFFFFFF
if ( : : FileWriteLong ( file_handle , MARKER_START_DATA ) ! = sizeof ( long ) )
return ( false ) ;
//--- Сохраняем тип объекта
if ( : : FileWriteInteger ( file_handle , this . Type ( ) , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Сохраняем список строк
if ( ! this . m_list_rows . Save ( file_handle ) )
return ( false ) ;
//--- Успешно
return true ;
}
2026-03-26 23:54:10 +07:00
//+------------------------------------------------------------------+
2026-03-27 00:05:24 +07:00
//| Загрузка из файла |
2026-03-26 23:54:10 +07:00
//+------------------------------------------------------------------+
2026-03-27 00:05:24 +07:00
bool CTableModel : : Load ( const int file_handle )
{
//--- Проверяем хэндл
if ( file_handle = = INVALID_HANDLE )
return ( false ) ;
//--- Загружаем и проверяем маркер начала данных - 0xFFFFFFFFFFFFFFFF
if ( : : FileReadLong ( file_handle ) ! = MARKER_START_DATA )
return ( false ) ;
//--- Загружаем тип объекта
if ( : : FileReadInteger ( file_handle , INT_VALUE ) ! = this . Type ( ) )
return ( false ) ;
//--- Загружаем список строк
if ( ! this . m_list_rows . Load ( file_handle ) )
return ( false ) ;
//--- Успешно
return true ;
}
2026-03-26 23:54:10 +07:00
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
//+------------------------------------------------------------------+
//| Класс заголовка столбца таблицы |
//+------------------------------------------------------------------+
class CColumnCaption : public CObject
{
protected :
//--- Переменные
ushort m_ushort_array [ MAX_STRING_LENGTH ] ; // Массив символов заголовка
uint m_column ; // Номер столбца
ENUM_DATATYPE m_datatype ; // Тип данных
public :
//--- (1) Устанавливает, (2) возвращает номер столбца
void SetColumn ( const uint column ) { this . m_column = column ; }
uint Column ( void ) const { return this . m_column ; }
//--- (1) Устанавливает, (2) возвращает тип данных столбца
ENUM_DATATYPE Datatype ( void ) const { return this . m_datatype ; }
void SetDatatype ( const ENUM_DATATYPE datatype ) { this . m_datatype = datatype ; }
//--- Очищает данные
void ClearData ( void ) { this . SetValue ( " " ) ; }
//--- Устанавливает заголовок
void SetValue ( const string value )
{
: : StringToShortArray ( value , this . m_ushort_array ) ;
}
//--- Возвращает текст заголовка
string Value ( void ) const
{
string res = : : ShortArrayToString ( this . m_ushort_array ) ;
res .TrimLeft ( ) ;
res .TrimRight ( ) ;
return res ;
}
//--- (1) Возвращает, (2) выводит в журнал описание объекта
virtual string Description ( void ) ;
void Print ( void ) ;
//--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта
virtual int Compare ( const CObject * node , const int mode = 0 ) const ;
virtual bool Save ( const int file_handle ) ;
virtual bool Load ( const int file_handle ) ;
virtual int Type ( void ) const { return ( OBJECT_TYPE_COLUMN_CAPTION ) ; }
//--- Конструкторы/деструктор
CColumnCaption ( void ) : m_column ( 0 ) { this . SetValue ( " " ) ; }
CColumnCaption ( const uint column , const string value ) : m_column ( column ) { this . SetValue ( value ) ; }
~ CColumnCaption ( void ) { }
} ;
//+------------------------------------------------------------------+
//| Сравнение двух объектов |
//+------------------------------------------------------------------+
int CColumnCaption : : Compare ( const CObject * node , const int mode = 0 ) const
{
2026-03-29 13:06:34 +07:00
if ( node = = NULL )
return -1 ;
2026-03-27 00:24:00 +07:00
const CColumnCaption * obj = node ;
return ( this . Column ( ) > obj . Column ( ) ? 1 : this . Column ( ) < obj . Column ( ) ? -1 : 0 ) ;
}
//+------------------------------------------------------------------+
//| Сохранение в файл |
//+------------------------------------------------------------------+
bool CColumnCaption : : Save ( const int file_handle )
{
//--- Проверяем хэндл
if ( file_handle = = INVALID_HANDLE )
return ( false ) ;
//--- Сохраняем маркер начала данных - 0xFFFFFFFFFFFFFFFF
if ( : : FileWriteLong ( file_handle , MARKER_START_DATA ) ! = sizeof ( long ) )
return ( false ) ;
//--- Сохраняем тип объекта
if ( : : FileWriteInteger ( file_handle , this . Type ( ) , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Сохраняем номер столбца
if ( : : FileWriteInteger ( file_handle , this . m_column , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Сохраняем значение
if ( : : FileWriteArray ( file_handle , this . m_ushort_array ) ! = sizeof ( this . m_ushort_array ) )
return ( false ) ;
//--- Всё успешно
return true ;
}
//+------------------------------------------------------------------+
//| Загрузка из файла |
//+------------------------------------------------------------------+
bool CColumnCaption : : Load ( const int file_handle )
{
//--- Проверяем хэндл
if ( file_handle = = INVALID_HANDLE )
return ( false ) ;
//--- Загружаем и проверяем маркер начала данных - 0xFFFFFFFFFFFFFFFF
if ( : : FileReadLong ( file_handle ) ! = MARKER_START_DATA )
return ( false ) ;
//--- Загружаем тип объекта
if ( : : FileReadInteger ( file_handle , INT_VALUE ) ! = this . Type ( ) )
return ( false ) ;
//--- Загружаем номер столбца
this . m_column = : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Загружаем значение
if ( : : FileReadArray ( file_handle , this . m_ushort_array ) ! = sizeof ( this . m_ushort_array ) )
return ( false ) ;
//--- Всё успешно
return true ;
}
//+------------------------------------------------------------------+
//| Возвращает описание объекта |
//+------------------------------------------------------------------+
string CColumnCaption : : Description ( void )
{
return ( : : StringFormat ( " %s: Column %u, Value: \" %s \" " ,
TypeDescription ( ( ENUM_OBJECT_TYPE ) this . Type ( ) ) , this . Column ( ) , this . Value ( ) ) ) ;
}
//+------------------------------------------------------------------+
//| Выводит в журнал описание объекта |
//+------------------------------------------------------------------+
void CColumnCaption : : Print ( void )
{
: : Print ( this . Description ( ) ) ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс заголовка таблицы |
//+------------------------------------------------------------------+
class CTableHeader : public CObject
{
protected :
CColumnCaption m_caption_tmp ; // Объект заголовка столбца для поиска в списке
CListObj m_list_captions ; // Список заголовков столбцлв
//--- Добавляет указанный заголовок в конец списка
bool AddNewColumnCaption ( CColumnCaption * caption ) ;
//--- Создаёт заголовок таблицы из строкового массива
void CreateHeader ( string & array [ ] ) ;
//--- Устанавливает позицию столбца всем заголовкам столбцов
void ColumnPositionUpdate ( void ) ;
public :
//--- Создаёт новый заголовок и добавляет в конец списка
CColumnCaption * CreateNewColumnCaption ( const string caption ) ;
//--- Возвращает (1) заголовок по индексу, (2) количество заголовков столбцов
CColumnCaption * GetColumnCaption ( const uint index ) { return this . m_list_captions . GetNodeAtIndex ( index ) ; }
uint ColumnsTotal ( void ) const { return this . m_list_captions . Total ( ) ; }
//--- Устанавливает значение указанному заголовку столбца
void ColumnCaptionSetValue ( const uint index , const string value ) ;
//--- (1) Устанавливает, (2) возвращает тип данных для указанного заголовка столбца
void ColumnCaptionSetDatatype ( const uint index , const ENUM_DATATYPE type ) ;
ENUM_DATATYPE ColumnCaptionDatatype ( const uint index ) ;
//--- (1) Удаляет (2) перемещает заголовок столбца
bool ColumnCaptionDelete ( const uint index ) ;
bool ColumnCaptionMoveTo ( const uint caption_index , const uint index_to ) ;
//--- Очищает данные заголовков столбцов
void ClearData ( void ) ;
//--- Очищает список заголовков столбцов
void Destroy ( void ) { this . m_list_captions . Clear ( ) ; }
//--- (1) Возвращает, (2) выводит в журнал описание объекта
virtual string Description ( void ) ;
void Print ( const bool detail , const bool as_table = false , const int column_width = CELL_WIDTH_IN_CHARS ) ;
//--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта
2026-03-29 13:06:34 +07:00
virtual int Compare ( const CObject * node , const int mode = 0 ) const { return -1 ; }
2026-03-27 00:24:00 +07:00
virtual bool Save ( const int file_handle ) ;
virtual bool Load ( const int file_handle ) ;
virtual int Type ( void ) const { return ( OBJECT_TYPE_TABLE_HEADER ) ; }
//--- Конструкторы/деструктор
CTableHeader ( void ) { }
CTableHeader ( string & array [ ] ) { this . CreateHeader ( array ) ; }
~ CTableHeader ( void ) { }
} ;
//+------------------------------------------------------------------+
//| Создаёт новый заголовок и добавляет в конец списка |
//+------------------------------------------------------------------+
CColumnCaption * CTableHeader : : CreateNewColumnCaption ( const string caption )
{
//--- Создаём новый объект заголовка
CColumnCaption * caption_obj = new CColumnCaption ( this . ColumnsTotal ( ) , caption ) ;
if ( caption_obj = = NULL )
{
: : PrintFormat ( " %s: Error. Failed to create new column caption at position %u " , __FUNCTION__ , this . ColumnsTotal ( ) ) ;
return NULL ;
}
//--- Добавляем созданный заголовок в конец списка
if ( ! this . AddNewColumnCaption ( caption_obj ) )
{
delete caption_obj ;
return NULL ;
}
//--- Возвращаем указатель на объект
return caption_obj ;
}
//+------------------------------------------------------------------+
//| Добавляет заголовок в конец списка |
//+------------------------------------------------------------------+
bool CTableHeader : : AddNewColumnCaption ( CColumnCaption * caption )
{
//--- Если передан пустой объект - сообщаем и возвращаем false
if ( caption = = NULL )
{
: : PrintFormat ( " %s: Error. Empty CColumnCaption object passed " , __FUNCTION__ ) ;
return false ;
}
//--- Устанавливаем индекс заголовка в списке и добавляем созданный заголовок в конец списка
caption . SetColumn ( this . ColumnsTotal ( ) ) ;
if ( this . m_list_captions . Add ( caption ) = = WRONG_VALUE )
{
: : PrintFormat ( " %s: Error. Failed to add caption (%u) to list " , __FUNCTION__ , this . ColumnsTotal ( ) ) ;
return false ;
}
//--- Успешно
return true ;
}
//+------------------------------------------------------------------+
//| Создаёт заголовок таблицы из строкового массива |
//+------------------------------------------------------------------+
void CTableHeader : : CreateHeader ( string & array [ ] )
{
//--- Получаем из свойств массива количество столбцов таблицы
uint total = array .Size ( ) ;
//--- В цикле по размеру массива
//--- создаём все заголовки, добавляя каждый новый в конец списка
for ( uint i = 0 ; i < total ; i + + )
this . CreateNewColumnCaption ( array [ i ] ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает значение в указанный заголовок столбца |
//+------------------------------------------------------------------+
void CTableHeader : : ColumnCaptionSetValue ( const uint index , const string value )
{
//--- Получаем из списка нужный заголовок и записываем в него новое значение
CColumnCaption * caption = this . GetColumnCaption ( index ) ;
if ( caption ! = NULL )
caption . SetValue ( value ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает тип данных для указанного заголовка столбца |
//+------------------------------------------------------------------+
void CTableHeader : : ColumnCaptionSetDatatype ( const uint index , const ENUM_DATATYPE type )
{
//--- Получаем из списка нужный заголовок и записываем в него новое значение
CColumnCaption * caption = this . GetColumnCaption ( index ) ;
if ( caption ! = NULL )
caption . SetDatatype ( type ) ;
}
//+------------------------------------------------------------------+
//| Возвращает тип данных указанного заголовка столбца |
//+------------------------------------------------------------------+
ENUM_DATATYPE CTableHeader : : ColumnCaptionDatatype ( const uint index )
{
//--- Получаем из списка нужный заголовок и возвращаем из него тип данных столбца
CColumnCaption * caption = this . GetColumnCaption ( index ) ;
return ( caption ! = NULL ? caption . Datatype ( ) : ( ENUM_DATATYPE ) WRONG_VALUE ) ;
}
//+------------------------------------------------------------------+
//| Удаляет заголовок указанного столбца |
//+------------------------------------------------------------------+
bool CTableHeader : : ColumnCaptionDelete ( const uint index )
{
//--- Удаляем заголовок в списке по индексу
if ( ! this . m_list_captions . Delete ( index ) )
return false ;
//--- Обновляем индексы для оставшихся заголовков в списке
this . ColumnPositionUpdate ( ) ;
return true ;
}
//+------------------------------------------------------------------+
//| Перемещает заголовок столбца на указанную позицию |
//+------------------------------------------------------------------+
bool CTableHeader : : ColumnCaptionMoveTo ( const uint caption_index , const uint index_to )
{
//--- Получаем нужный заголовок по индексу в списке, делая его текущим
CColumnCaption * caption = this . GetColumnCaption ( caption_index ) ;
//--- Перемещаем текущий заголовок на указанную позицию в списке
if ( caption = = NULL | | ! this . m_list_captions . MoveToIndex ( index_to ) )
return false ;
//--- Обновляем индексы всех заголовков в списке
this . ColumnPositionUpdate ( ) ;
return true ;
}
//+------------------------------------------------------------------+
//| Устанавливает позиции столбца всем заголовкам |
//+------------------------------------------------------------------+
void CTableHeader : : ColumnPositionUpdate ( void )
{
//--- В цикле по всем заголовкам в списке
for ( int i = 0 ; i < this . m_list_captions . Total ( ) ; i + + )
{
//--- получаем очередной заголовок и устанавливаем в него индекс столбца
CColumnCaption * caption = this . GetColumnCaption ( i ) ;
if ( caption ! = NULL )
caption . SetColumn ( this . m_list_captions . IndexOf ( caption ) ) ;
}
}
//+------------------------------------------------------------------+
//| Очищает данные заголовков столбцов в списке |
//+------------------------------------------------------------------+
void CTableHeader : : ClearData ( void )
{
//--- В цикле по всем заголовкам в списке
for ( uint i = 0 ; i < this . ColumnsTotal ( ) ; i + + )
{
//--- получаем очередной заголовок и устанавливаем в него пустое значение
CColumnCaption * caption = this . GetColumnCaption ( i ) ;
if ( caption ! = NULL )
caption . ClearData ( ) ;
}
}
//+------------------------------------------------------------------+
//| Возвращает описание объекта |
//+------------------------------------------------------------------+
string CTableHeader : : Description ( void )
{
return ( : : StringFormat ( " %s: Captions total: %u " ,
TypeDescription ( ( ENUM_OBJECT_TYPE ) this . Type ( ) ) , this . ColumnsTotal ( ) ) ) ;
}
//+------------------------------------------------------------------+
//| Выводит в журнал описание объекта |
//+------------------------------------------------------------------+
void CTableHeader : : Print ( const bool detail , const bool as_table = false , const int column_width = CELL_WIDTH_IN_CHARS )
{
//--- Количество заголовков
int total = ( int ) this . ColumnsTotal ( ) ;
//--- Если вывод в табличном виде
string res = " " ;
if ( as_table )
{
//--- создаём строку таблицы из значений всех заголовков
res = " | " ;
for ( int i = 0 ; i < total ; i + + )
{
CColumnCaption * caption = this . GetColumnCaption ( i ) ;
if ( caption = = NULL )
continue ;
res + = : : StringFormat ( " %*s | " , column_width , caption . Value ( ) ) ;
}
//--- Выводим строку в журнал и уходим
: : Print ( res ) ;
return ;
}
//--- Выводим заголовок в виде описания строки
: : Print ( this . Description ( ) + ( detail ? " : " : " " ) ) ;
//--- Если детализированное описание
if ( detail )
{
//--- В цикле по списку заголовков строки
for ( int i = 0 ; i < total ; i + + )
{
//--- получаем текущий заголовок и добавляем в итоговую строку его описание
CColumnCaption * caption = this . GetColumnCaption ( i ) ;
if ( caption ! = NULL )
res + = " " + caption . Description ( ) + ( i < total -1 ? " \n " : " " ) ;
}
//--- Выводим в журнал созданную в цикле строку
: : Print ( res ) ;
}
}
//+------------------------------------------------------------------+
//| Сохранение в файл |
//+------------------------------------------------------------------+
bool CTableHeader : : Save ( const int file_handle )
{
//--- Проверяем хэндл
if ( file_handle = = INVALID_HANDLE )
return ( false ) ;
//--- Сохраняем маркер начала данных - 0xFFFFFFFFFFFFFFFF
if ( : : FileWriteLong ( file_handle , MARKER_START_DATA ) ! = sizeof ( long ) )
return ( false ) ;
//--- Сохраняем тип объекта
if ( : : FileWriteInteger ( file_handle , this . Type ( ) , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Сохраняем список заголовков
if ( ! this . m_list_captions . Save ( file_handle ) )
return ( false ) ;
//--- Успешно
return true ;
}
//+------------------------------------------------------------------+
//| Загрузка из файла |
//+------------------------------------------------------------------+
bool CTableHeader : : Load ( const int file_handle )
{
//--- Проверяем хэндл
if ( file_handle = = INVALID_HANDLE )
return ( false ) ;
//--- Загружаем и проверяем маркер начала данных - 0xFFFFFFFFFFFFFFFF
if ( : : FileReadLong ( file_handle ) ! = MARKER_START_DATA )
return ( false ) ;
//--- Загружаем тип объекта
if ( : : FileReadInteger ( file_handle , INT_VALUE ) ! = this . Type ( ) )
return ( false ) ;
//--- Загружаем список заголовков
if ( ! this . m_list_captions . Load ( file_handle ) )
return ( false ) ;
//--- Успешно
return true ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс таблицы |
//+------------------------------------------------------------------+
class CTable : public CObject
{
private :
//--- Заполняет массив заголовков столбцов в стиле Excel
bool FillArrayExcelNames ( const uint num_columns ) ;
//--- Возвращает наименование столбца как в Excel
string GetExcelColumnName ( uint column_number ) ;
//--- Возвращает доступность заголовка
bool HeaderCheck ( void ) const { return ( this . m_table_header ! = NULL & & this . m_table_header . ColumnsTotal ( ) > 0 ) ; }
protected :
CTableModel * m_table_model ; // Указатель на модель таблицы
CTableHeader * m_table_header ; // Указатель на заголовок таблицы
CList m_list_rows ; // Список массивов параметров из полей структуры
string m_array_names [ ] ; // Массив заголовков столбцов
int m_id ; // Идентификатор таблицы
//--- Копирует массив наименований заголовков
bool ArrayNamesCopy ( const string & column_names [ ] , const uint columns_total ) ;
public :
//--- (1) Устанавливает, (2) возвращает модель таблицы
void SetTableModel ( CTableModel * table_model ) { this . m_table_model = table_model ; }
CTableModel * GetTableModel ( void ) { return this . m_table_model ; }
//--- (1) Устанавливает, (2) возвращает заголовок
void SetTableHeader ( CTableHeader * table_header ) { this . m_table_header = m_table_header ; }
CTableHeader * GetTableHeader ( void ) { return this . m_table_header ; }
//--- (1) Устанавливает, (2) возвращает идентификатор таблицы
void SetID ( const int id ) { this . m_id = id ; }
int ID ( void ) const { return this . m_id ; }
//--- Очищает данные заголовков столбцов
void HeaderClearData ( void )
{
if ( this . m_table_header ! = NULL )
this . m_table_header . ClearData ( ) ;
}
//--- Удаляет заголовок таблицы
void HeaderDestroy ( void )
{
if ( this . m_table_header = = NULL )
return ;
this . m_table_header . Destroy ( ) ;
this . m_table_header = NULL ;
}
//--- (1) Очищает все данные, (2) уничтожает модель таблицы и заголовок
void ClearData ( void )
{
if ( this . m_table_model ! = NULL )
this . m_table_model . ClearData ( ) ;
}
void Destroy ( void )
{
if ( this . m_table_model = = NULL )
return ;
this . m_table_model . Destroy ( ) ;
this . m_table_model = NULL ;
}
//--- Возвращает (1) заголовок, (2) ячейку, (3) строку по индексу, количество (4) строк, (5) столбцов, ячеек (6) в указанной строке, (7) в таблице
CColumnCaption * GetColumnCaption ( const uint index ) { return ( this . m_table_header ! = NULL ? this . m_table_header . GetColumnCaption ( index ) : NULL ) ; }
CTableCell * GetCell ( const uint row , const uint col ) { return ( this . m_table_model ! = NULL ? this . m_table_model . GetCell ( row , col ) : NULL ) ; }
CTableRow * GetRow ( const uint index ) { return ( this . m_table_model ! = NULL ? this . m_table_model . GetRow ( index ) : NULL ) ; }
uint RowsTotal ( void ) const { return ( this . m_table_model ! = NULL ? this . m_table_model . RowsTotal ( ) : 0 ) ; }
uint ColumnsTotal ( void ) const { return ( this . m_table_model ! = NULL ? this . m_table_model . CellsInRow ( 0 ) : 0 ) ; }
uint CellsInRow ( const uint index ) { return ( this . m_table_model ! = NULL ? this . m_table_model . CellsInRow ( index ) : 0 ) ; }
uint CellsTotal ( void ) { return ( this . m_table_model ! = NULL ? this . m_table_model . CellsTotal ( ) : 0 ) ; }
//--- Устанавливает (1) значение, (2) точность, (3) флаги отображения времени, (4) флаг отображения имён цветов в указанную ячейку
template < typename T >
void CellSetValue ( const uint row , const uint col , const T value ) ;
void CellSetDigits ( const uint row , const uint col , const int digits ) ;
void CellSetTimeFlags ( const uint row , const uint col , const uint flags ) ;
void CellSetColorNamesFlag ( const uint row , const uint col , const bool flag ) ;
//--- (1) Назначает, (2) отменяет объект в ячейке
void CellAssignObject ( const uint row , const uint col , CObject * object ) ;
void CellUnassignObject ( const uint row , const uint col ) ;
//--- Возвращает строковое значение указанной ячейки
virtual string CellValueAt ( const uint row , const uint col ) ;
protected :
//--- (1) Удаляет (2) перемещает ячейку
bool CellDelete ( const uint row , const uint col ) ;
bool CellMoveTo ( const uint row , const uint cell_index , const uint index_to ) ;
public :
//--- (1) Возвращает, (2) выводит в журнал описание ячейки, (3) назначенный в ячейку объект
string CellDescription ( const uint row , const uint col ) ;
void CellPrint ( const uint row , const uint col ) ;
//---Возвращает (1) назначенный в ячейку объект, (2) тип назначенного в ячейку объекта
CObject * CellGetObject ( const uint row , const uint col ) ;
ENUM_OBJECT_TYPE CellGetObjType ( const uint row , const uint col ) ;
//--- Создаёт новую строку и (1) добавляет в конец списка, (2) вставляет в указанную позицию списка
CTableRow * RowAddNew ( void ) ;
CTableRow * RowInsertNewTo ( const uint index_to ) ;
//--- (1) Удаляет (2) перемещает строку, (3) очищает данные строки
bool RowDelete ( const uint index ) ;
bool RowMoveTo ( const uint row_index , const uint index_to ) ;
void RowClearData ( const uint index ) ;
//--- (1) Возвращает, (2) выводит в журнал описание строки
string RowDescription ( const uint index ) ;
void RowPrint ( const uint index , const bool detail ) ;
//--- (1) Добавляет новый, (2) удаляет, (3) перемещает столбец, (4) очищает данные столбца
bool ColumnAddNew ( const string caption , const int index = -1 ) ;
bool ColumnDelete ( const uint index ) ;
bool ColumnMoveTo ( const uint index , const uint index_to ) ;
void ColumnClearData ( const uint index ) ;
2026-03-29 15:13:53 +07:00
//--- Устанавливает (1) значение указанному заголовку, (2) точность данных,
//--- флаги отображения (3) времени, (4) имён цвета указанному столбцу
2026-03-27 00:24:00 +07:00
void ColumnCaptionSetValue ( const uint index , const string value ) ;
void ColumnSetDigits ( const uint index , const int digits ) ;
2026-03-29 15:13:53 +07:00
void ColumnSetTimeFlags ( const uint index , const uint flags ) ;
void ColumnSetColorNamesFlag ( const uint col , const bool flag ) ;
2026-03-27 00:24:00 +07:00
//--- (1) Устанавливает, (2) возвращает тип данных для указанного столбца
void ColumnSetDatatype ( const uint index , const ENUM_DATATYPE type ) ;
ENUM_DATATYPE ColumnDatatype ( const uint index ) ;
//--- (1) Возвращает, (2) выводит в журнал описание объекта
virtual string Description ( void ) ;
void Print ( const int column_width = CELL_WIDTH_IN_CHARS ) ;
2026-03-29 15:13:53 +07:00
//--- Сортирует таблицу по указанному столбцу и направлению
void SortByColumn ( const uint column , const bool descending )
{
if ( this . m_table_model ! = NULL )
this . m_table_model . SortByColumn ( column , descending ) ;
}
2026-03-27 00:24:00 +07:00
//--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта
virtual int Compare ( const CObject * node , const int mode = 0 ) const ;
virtual bool Save ( const int file_handle ) ;
virtual bool Load ( const int file_handle ) ;
virtual int Type ( void ) const { return ( OBJECT_TYPE_TABLE ) ; }
//--- Конструкторы/деструктор
CTable ( void ) : m_table_model ( NULL ) , m_table_header ( NULL ) { this . m_list_rows . Clear ( ) ; }
template < typename T > CTable ( T & row_data [ ] [ ] , const string & column_names [ ] ) ;
CTable ( const uint num_rows , const uint num_columns ) ;
CTable ( const matrix & row_data , const string & column_names [ ] ) ;
~ CTable ( void ) ;
} ;
//+-------------------------------------------------------------------+
//| Конструктор с указанием массива таблицы и массива заголовков. |
//| Определяет количество и наименования колонок согласно column_names|
//| Количество строк определены размером массива данных row_data, |
//| который используется и для заполнения таблицы |
//+-------------------------------------------------------------------+
template < typename T >
CTable : : CTable ( T & row_data [ ] [ ] , const string & column_names [ ] ) : m_id ( -1 )
{
this . m_table_model = new CTableModel ( row_data ) ;
if ( column_names .Size ( ) > 0 )
this . ArrayNamesCopy ( column_names , row_data .Range ( 1 ) ) ;
else
{
: : PrintFormat ( " %s: An empty array names was passed. The header array will be filled in Excel style (A, B, C) " , __FUNCTION__ ) ;
this . FillArrayExcelNames ( ( uint ) : : ArrayRange ( row_data , 1 ) ) ;
}
this . m_table_header = new CTableHeader ( this . m_array_names ) ;
}
//+------------------------------------------------------------------+
//| Конструктор таблицы с определением количества колонок и строк. |
//| Колонки будут иметь Excel-наименования "A", "B", "C" и т.д. |
//+------------------------------------------------------------------+
CTable : : CTable ( const uint num_rows , const uint num_columns ) : m_table_header ( NULL ) , m_id ( -1 )
{
this . m_table_model = new CTableModel ( num_rows , num_columns ) ;
if ( this . FillArrayExcelNames ( num_columns ) )
this . m_table_header = new CTableHeader ( this . m_array_names ) ;
}
//+-------------------------------------------------------------------+
//| Конструктор таблицы с инициализацией колонок согласно column_names|
//| Количество строк определены параметром row_data, с типом matrix |
//+-------------------------------------------------------------------+
CTable : : CTable ( const matrix & row_data , const string & column_names [ ] ) : m_id ( -1 )
{
this . m_table_model = new CTableModel ( row_data ) ;
if ( column_names .Size ( ) > 0 )
this . ArrayNamesCopy ( column_names , ( uint ) row_data .Cols ( ) ) ;
else
{
: : PrintFormat ( " %s: An empty array names was passed. The header array will be filled in Excel style (A, B, C) " , __FUNCTION__ ) ;
this . FillArrayExcelNames ( ( uint ) row_data .Cols ( ) ) ;
}
this . m_table_header = new CTableHeader ( this . m_array_names ) ;
}
//+------------------------------------------------------------------+
//| Деструктор |
//+------------------------------------------------------------------+
CTable : : ~ CTable ( void )
{
if ( this . m_table_model ! = NULL )
{
this . m_table_model . Destroy ( ) ;
delete this . m_table_model ;
}
if ( this . m_table_header ! = NULL )
{
this . m_table_header . Destroy ( ) ;
delete this . m_table_header ;
}
}
//+------------------------------------------------------------------+
//| Сравнение двух объектов |
//+------------------------------------------------------------------+
int CTable : : Compare ( const CObject * node , const int mode = 0 ) const
{
2026-03-29 13:06:34 +07:00
if ( node = = NULL )
return -1 ;
2026-03-27 00:24:00 +07:00
const CTable * obj = node ;
return ( this . ID ( ) > obj . ID ( ) ? 1 : this . ID ( ) < obj . ID ( ) ? -1 : 0 ) ;
}
//+------------------------------------------------------------------+
//| Возвращает наименование столбца как в Excel |
//+------------------------------------------------------------------+
string CTable : : GetExcelColumnName ( uint column_number )
{
string column_name = " " ;
uint index = column_number ;
//--- Проверяем, что номер столбца больше 0
if ( index = = 0 )
return ( __FUNCTION__ + " : Error. Invalid column number passed " ) ;
//--- Преобразование номера в название столбца
while ( ! : : IsStopped ( ) & & index > 0 )
{
index - - ; // Уменьшаем номер на 1, чтобы сделать его 0-индексным
uint remainder = index % 26 ; // Остаток от деления на 26
uchar char_code = ' A ' + ( uchar ) remainder ; // Рассчитываем код символа (буквы)
column_name = : : CharToString ( char_code ) + column_name ; // Добавляем букву в начало строки
index / = 26 ; // Переходим к следующему разряду
}
return column_name ;
}
//+------------------------------------------------------------------+
//| Заполняет массив заголовков столбцов в стиле Excel |
//+------------------------------------------------------------------+
bool CTable : : FillArrayExcelNames ( const uint num_columns )
{
: : ResetLastError ( ) ;
if ( : : ArrayResize ( this . m_array_names , num_columns , num_columns ) ! = num_columns )
{
: : PrintFormat ( " %s: ArrayResize() failed. Error %d " , __FUNCTION__ , : : GetLastError ( ) ) ;
return false ;
}
for ( int i = 0 ; i < ( int ) num_columns ; i + + )
this . m_array_names [ i ] = this . GetExcelColumnName ( i + 1 ) ;
return true ;
}
//+------------------------------------------------------------------+
//| Копирует массив наименований заголовков |
//+------------------------------------------------------------------+
bool CTable : : ArrayNamesCopy ( const string & column_names [ ] , const uint columns_total )
{
if ( columns_total = = 0 )
{
: : PrintFormat ( " %s: Error. The table has no columns " , __FUNCTION__ ) ;
return false ;
}
if ( columns_total > column_names .Size ( ) )
{
: : PrintFormat ( " %s: The number of header names is less than the number of columns. The header array will be filled in Excel style (A, B, C) " , __FUNCTION__ ) ;
return this . FillArrayExcelNames ( columns_total ) ;
}
uint total = : : fmin ( columns_total , column_names .Size ( ) ) ;
return ( : : ArrayCopy ( this . m_array_names , column_names , 0 , 0 , total ) = = total ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает значение в указанную ячейку |
//+------------------------------------------------------------------+
template < typename T >
void CTable : : CellSetValue ( const uint row , const uint col , const T value )
{
if ( this . m_table_model ! = NULL )
this . m_table_model . CellSetValue ( row , col , value ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает точность в указанную ячейку |
//+------------------------------------------------------------------+
void CTable : : CellSetDigits ( const uint row , const uint col , const int digits )
{
if ( this . m_table_model ! = NULL )
this . m_table_model . CellSetDigits ( row , col , digits ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает флаги отображения времени в указанную ячейку |
//+------------------------------------------------------------------+
void CTable : : CellSetTimeFlags ( const uint row , const uint col , const uint flags )
{
if ( this . m_table_model ! = NULL )
this . m_table_model . CellSetTimeFlags ( row , col , flags ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает флаг отображения имён цветов в указанную ячейку |
//+------------------------------------------------------------------+
void CTable : : CellSetColorNamesFlag ( const uint row , const uint col , const bool flag )
{
if ( this . m_table_model ! = NULL )
this . m_table_model . CellSetColorNamesFlag ( row , col , flag ) ;
}
//+------------------------------------------------------------------+
//| Назначает объект в ячейку |
//+------------------------------------------------------------------+
void CTable : : CellAssignObject ( const uint row , const uint col , CObject * object )
{
if ( this . m_table_model ! = NULL )
this . m_table_model . CellAssignObject ( row , col , object ) ;
}
//+------------------------------------------------------------------+
//| Отменяет объект в ячейке |
//+------------------------------------------------------------------+
void CTable : : CellUnassignObject ( const uint row , const uint col )
{
if ( this . m_table_model ! = NULL )
this . m_table_model . CellUnassignObject ( row , col ) ;
}
//+------------------------------------------------------------------+
//| Возвращает строковое значение указанной ячейки |
//+------------------------------------------------------------------+
string CTable : : CellValueAt ( const uint row , const uint col )
{
CTableCell * cell = this . GetCell ( row , col ) ;
return ( cell ! = NULL ? cell . Value ( ) : " " ) ;
}
//+------------------------------------------------------------------+
//| Удаляет ячейку |
//+------------------------------------------------------------------+
bool CTable : : CellDelete ( const uint row , const uint col )
{
return ( this . m_table_model ! = NULL ? this . m_table_model . CellDelete ( row , col ) : false ) ;
}
//+------------------------------------------------------------------+
//| Перемещает ячейку |
//+------------------------------------------------------------------+
bool CTable : : CellMoveTo ( const uint row , const uint cell_index , const uint index_to )
{
return ( this . m_table_model ! = NULL ? this . m_table_model . CellMoveTo ( row , cell_index , index_to ) : false ) ;
}
//+------------------------------------------------------------------+
//| Возвращает назначенный в ячейку объект |
//+------------------------------------------------------------------+
CObject * CTable : : CellGetObject ( const uint row , const uint col )
{
return ( this . m_table_model ! = NULL ? this . m_table_model . CellGetObject ( row , col ) : NULL ) ;
}
//+------------------------------------------------------------------+
//| Возвращает тип назначенного в ячейку объекта |
//+------------------------------------------------------------------+
ENUM_OBJECT_TYPE CTable : : CellGetObjType ( const uint row , const uint col )
{
return ( this . m_table_model ! = NULL ? this . m_table_model . CellGetObjType ( row , col ) : ( ENUM_OBJECT_TYPE ) WRONG_VALUE ) ;
}
//+------------------------------------------------------------------+
//| Возвращает описание ячейки |
//+------------------------------------------------------------------+
string CTable : : CellDescription ( const uint row , const uint col )
{
return ( this . m_table_model ! = NULL ? this . m_table_model . CellDescription ( row , col ) : " " ) ;
}
//+------------------------------------------------------------------+
//| Выводит в журнал описание ячейки |
//+------------------------------------------------------------------+
void CTable : : CellPrint ( const uint row , const uint col )
{
if ( this . m_table_model ! = NULL )
this . m_table_model . CellPrint ( row , col ) ;
}
//+------------------------------------------------------------------+
//| Создаёт новую строку и добавляет в конец списка |
//+------------------------------------------------------------------+
CTableRow * CTable : : RowAddNew ( void )
{
return ( this . m_table_model ! = NULL ? this . m_table_model . RowAddNew ( ) : NULL ) ;
}
//+------------------------------------------------------------------+
//| Создаёт новую строку и вставляет в указанную позицию списка |
//+------------------------------------------------------------------+
CTableRow * CTable : : RowInsertNewTo ( const uint index_to )
{
return ( this . m_table_model ! = NULL ? this . m_table_model . RowInsertNewTo ( index_to ) : NULL ) ;
}
//+------------------------------------------------------------------+
//| Удаляет строку |
//+------------------------------------------------------------------+
bool CTable : : RowDelete ( const uint index )
{
return ( this . m_table_model ! = NULL ? this . m_table_model . RowDelete ( index ) : false ) ;
}
//+------------------------------------------------------------------+
//| Перемещает строку |
//+------------------------------------------------------------------+
bool CTable : : RowMoveTo ( const uint row_index , const uint index_to )
{
return ( this . m_table_model ! = NULL ? this . m_table_model . RowMoveTo ( row_index , index_to ) : false ) ;
}
//+------------------------------------------------------------------+
//| Очищает данные строки |
//+------------------------------------------------------------------+
void CTable : : RowClearData ( const uint index )
{
if ( this . m_table_model ! = NULL )
this . m_table_model . RowClearData ( index ) ;
}
//+------------------------------------------------------------------+
//| Возвращает описание строки |
//+------------------------------------------------------------------+
string CTable : : RowDescription ( const uint index )
{
return ( this . m_table_model ! = NULL ? this . m_table_model . RowDescription ( index ) : " " ) ;
}
//+------------------------------------------------------------------+
//| Выводит в журнал описание строки |
//+------------------------------------------------------------------+
void CTable : : RowPrint ( const uint index , const bool detail )
{
if ( this . m_table_model ! = NULL )
this . m_table_model . RowPrint ( index , detail ) ;
}
//+------------------------------------------------------------------+
//| Создаёт новый столбец и добавляет его в указанную позицию таблицы|
//+------------------------------------------------------------------+
bool CTable : : ColumnAddNew ( const string caption , const int index = -1 )
{
//--- Если нет модели таблицы, либо ошибка добавления нового столбца к модели - возвращаем false
if ( this . m_table_model = = NULL | | ! this . m_table_model . ColumnAddNew ( index ) )
return false ;
//--- Если нет заголовка - возвращаем true (столбец добавлен без заголовка)
if ( this . m_table_header = = NULL )
return true ;
//--- Проверяем создание нового заголовка столбца и, если не создан - возвращаем false
CColumnCaption * caption_obj = this . m_table_header . CreateNewColumnCaption ( caption ) ;
if ( caption_obj = = NULL )
return false ;
//--- Если передан не отрицательный индекс - возвращаем результат перемещения заголовка на указанный индекс
//--- В ином случае уже всё готово - просто возвращаем true
return ( index > -1 ? this . m_table_header . ColumnCaptionMoveTo ( caption_obj . Column ( ) , index ) : true ) ;
}
//+------------------------------------------------------------------+
//| Удаляет столбец |
//+------------------------------------------------------------------+
bool CTable : : ColumnDelete ( const uint index )
{
if ( ! this . HeaderCheck ( ) | | ! this . m_table_header . ColumnCaptionDelete ( index ) )
return false ;
return this . m_table_model . ColumnDelete ( index ) ;
}
//+------------------------------------------------------------------+
//| Перемещает столбец |
//+------------------------------------------------------------------+
bool CTable : : ColumnMoveTo ( const uint index , const uint index_to )
{
if ( ! this . HeaderCheck ( ) | | ! this . m_table_header . ColumnCaptionMoveTo ( index , index_to ) )
return false ;
return this . m_table_model . ColumnMoveTo ( index , index_to ) ;
}
//+------------------------------------------------------------------+
//| Очищает данные столбца |
//+------------------------------------------------------------------+
void CTable : : ColumnClearData ( const uint index )
{
if ( this . m_table_model ! = NULL )
this . m_table_model . ColumnClearData ( index ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает значение указанному заголовку |
//+------------------------------------------------------------------+
void CTable : : ColumnCaptionSetValue ( const uint index , const string value )
{
CColumnCaption * caption = this . m_table_header . GetColumnCaption ( index ) ;
if ( caption ! = NULL )
caption . SetValue ( value ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает тип данных для указанного столбца |
//+------------------------------------------------------------------+
void CTable : : ColumnSetDatatype ( const uint index , const ENUM_DATATYPE type )
{
//--- Если модель таблицы есть - устанавливаем тип данных для столбца
if ( this . m_table_model ! = NULL )
this . m_table_model . ColumnSetDatatype ( index , type ) ;
//--- Если заголовок есть - устанавливаем тип данных для заголовка
if ( this . m_table_header ! = NULL )
this . m_table_header . ColumnCaptionSetDatatype ( index , type ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает точность данных указанному столбцу |
//+------------------------------------------------------------------+
void CTable : : ColumnSetDigits ( const uint index , const int digits )
{
if ( this . m_table_model ! = NULL )
this . m_table_model . ColumnSetDigits ( index , digits ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
//| Устанавливает флаги отображения времени указанному столбцу |
//+------------------------------------------------------------------+
void CTable : : ColumnSetTimeFlags ( const uint index , const uint flags )
{
if ( this . m_table_model ! = NULL )
this . m_table_model . ColumnSetTimeFlags ( index , flags ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает флаги отображения имён цвета указанному столбцу |
//+------------------------------------------------------------------+
void CTable : : ColumnSetColorNamesFlag ( const uint index , const bool flag )
{
if ( this . m_table_model ! = NULL )
this . m_table_model . ColumnSetColorNamesFlag ( index , flag ) ;
}
//+------------------------------------------------------------------+
2026-03-27 00:24:00 +07:00
//| Возвращает тип данных для указанного столбца |
//+------------------------------------------------------------------+
ENUM_DATATYPE CTable : : ColumnDatatype ( const uint index )
{
return ( this . m_table_header ! = NULL ? this . m_table_header . ColumnCaptionDatatype ( index ) : ( ENUM_DATATYPE ) WRONG_VALUE ) ;
}
//+------------------------------------------------------------------+
//| Возвращает описание объекта |
//+------------------------------------------------------------------+
string CTable : : Description ( void )
{
return ( : : StringFormat ( " %s: Rows total: %u, Columns total: %u " ,
TypeDescription ( ( ENUM_OBJECT_TYPE ) this . Type ( ) ) , this . RowsTotal ( ) , this . ColumnsTotal ( ) ) ) ;
}
//+------------------------------------------------------------------+
//| Выводит в журнал описание объекта |
//+------------------------------------------------------------------+
void CTable : : Print ( const int column_width = CELL_WIDTH_IN_CHARS )
{
if ( this . HeaderCheck ( ) )
{
//--- Выводим заголовок в виде описания строки
: : Print ( this . Description ( ) + " : " ) ;
//--- Количество заголовков
int total = ( int ) this . ColumnsTotal ( ) ;
string res = " " ;
//--- создаём строку из значений всех заголовков столбцов таблицы
res = " | " ;
for ( int i = 0 ; i < total ; i + + )
{
CColumnCaption * caption = this . GetColumnCaption ( i ) ;
if ( caption = = NULL )
continue ;
res + = : : StringFormat ( " %*s | " , column_width , caption . Value ( ) ) ;
}
//--- Дополняем строку слева заголовком
string hd = " | " ;
hd + = : : StringFormat ( " %*s " , column_width , " n/n " ) ;
res = hd + res ;
//--- Выводим строку заголовка в журнал
: : Print ( res ) ;
}
//--- Пройдём в цикле по всем строкам таблицы и распечатаем их в табличном виде
for ( uint i = 0 ; i < this . RowsTotal ( ) ; i + + )
{
CTableRow * row = this . GetRow ( i ) ;
if ( row ! = NULL )
{
//--- создаём строку таблицы из значений всех ячеек
string head = " " + ( string ) row . Index ( ) ;
string res = : : StringFormat ( " |%-*s | " , column_width , head ) ;
for ( int i = 0 ; i < ( int ) row . CellsTotal ( ) ; i + + )
{
CTableCell * cell = row . GetCell ( i ) ;
if ( cell = = NULL )
continue ;
res + = : : StringFormat ( " %*s | " , column_width , cell . Value ( ) ) ;
}
//--- Выводим строку в журнал
: : Print ( res ) ;
}
}
}
//+------------------------------------------------------------------+
//| Сохранение в файл |
//+------------------------------------------------------------------+
bool CTable : : Save ( const int file_handle )
{
//--- Проверяем хэндл
if ( file_handle = = INVALID_HANDLE )
return ( false ) ;
//--- Сохраняем маркер начала данных - 0xFFFFFFFFFFFFFFFF
if ( : : FileWriteLong ( file_handle , MARKER_START_DATA ) ! = sizeof ( long ) )
return ( false ) ;
//--- Сохраняем тип объекта
if ( : : FileWriteInteger ( file_handle , this . Type ( ) , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Сохраняем идентификатор
if ( : : FileWriteInteger ( file_handle , this . m_id , INT_VALUE ) ! = INT_VALUE )
return ( false ) ;
//--- Проверяем модель таблицы
if ( this . m_table_model = = NULL )
return false ;
//--- Сохраняем модель таблицы
if ( ! this . m_table_model . Save ( file_handle ) )
return ( false ) ;
//--- Проверяем заголовок таблицы
if ( this . m_table_header = = NULL )
return false ;
//--- Сохраняем заголовок таблицы
if ( ! this . m_table_header . Save ( file_handle ) )
return ( false ) ;
//--- Успешно
return true ;
}
//+------------------------------------------------------------------+
//| Загрузка из файла |
//+------------------------------------------------------------------+
bool CTable : : Load ( const int file_handle )
{
//--- Проверяем хэндл
if ( file_handle = = INVALID_HANDLE )
return ( false ) ;
//--- Загружаем и проверяем маркер начала данных - 0xFFFFFFFFFFFFFFFF
if ( : : FileReadLong ( file_handle ) ! = MARKER_START_DATA )
return ( false ) ;
//--- Загружаем тип объекта
if ( : : FileReadInteger ( file_handle , INT_VALUE ) ! = this . Type ( ) )
return ( false ) ;
//--- Загружаем идентификатор
this . m_id = : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Проверяем модель таблицы
if ( this . m_table_model = = NULL & & ( this . m_table_model = new CTableModel ( ) ) = = NULL )
return ( false ) ;
//--- Загружаем модель таблицы
if ( ! this . m_table_model . Load ( file_handle ) )
return ( false ) ;
//--- Проверяем заголовок таблицы
if ( this . m_table_header = = NULL & & ( this . m_table_header = new CTableHeader ( ) ) = = NULL )
return false ;
//--- Загружаем заголовок таблицы
if ( ! this . m_table_header . Load ( file_handle ) )
return ( false ) ;
//--- Успешно
return true ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс для создания таблиц на основе массива параметров |
//+------------------------------------------------------------------+
class CTableByParam : public CTable
{
public :
2026-03-29 15:13:53 +07:00
virtual int Type ( void ) const { return ( OBJECT_TYPE_TABLE_BY_PARAM ) ; }
2026-03-27 00:24:00 +07:00
//--- Конструктор/деструктор
2026-03-29 15:13:53 +07:00
CTableByParam ( void ) { this . m_list_rows . Clear ( ) ; }
2026-03-27 00:24:00 +07:00
CTableByParam ( CList & row_data , const string & column_names [ ] ) ;
~ CTableByParam ( void ) { }
} ;
//+------------------------------------------------------------------+
//| Конструктор с указанием массива таблицы на основе списка row_data|
//| содержащего объекты с данными полей структуры. |
//| Определяет количество и наименования колонок согласно количеству |
//| наименований столбцов в массиве column_names |
//+------------------------------------------------------------------+
CTableByParam : : CTableByParam ( CList & row_data , const string & column_names [ ] )
{
//--- Копируем переданный список данных в переменную и
//--- создаём на основе этого списка модель таблицы
this . m_list_rows = row_data ;
this . m_table_model = new CTableModel ( this . m_list_rows ) ;
//--- Копируем переданный список заголовков в m_array_names и
//--- создаём на основе этого списка заголовок таблицы
this . ArrayNamesCopy ( column_names , column_names .Size ( ) ) ;
this . m_table_header = new CTableHeader ( this . m_array_names ) ;
}
//+------------------------------------------------------------------+