2879 lines
149 KiB
MQL5
2879 lines
149 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Tables.mqh |
|
||
|
|
//| Copyright 2025, MetaQuotes Ltd. |
|
||
|
|
//| https://www.mql5.com |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#property copyright "Copyright 2025, MetaQuotes Ltd."
|
||
|
|
#property link "https://www.mql5.com"
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Включаемые библиотеки |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#include <Arrays\List.mqh>
|
||
|
|
|
||
|
|
//--- Форвард-декларация классов
|
||
|
|
class CTableCell; // Класс ячейки таблицы
|
||
|
|
class CTableRow; // Класс строки таблицы
|
||
|
|
class CTableModel; // Класс модели таблицы
|
||
|
|
class CColumnCaption; // Класс заголовка столбца таблицы
|
||
|
|
class CTableHeader; // Класс заголовка таблицы
|
||
|
|
class CTable; // Класс таблицы
|
||
|
|
class CTableByParam; // Класс таблицы на основе массива параметров
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Макросы |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#define __TABLES__ // Идентификатор данного файла
|
||
|
|
#define MARKER_START_DATA -1 // Маркер начала данных в файле
|
||
|
|
#define MAX_STRING_LENGTH 128 // Максимальная длина строки в ячейке
|
||
|
|
#define CELL_WIDTH_IN_CHARS 19 // Ширина ячейки таблицы в символах
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Перечисления |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
enum ENUM_OBJECT_TYPE // Перечисление типов объектов
|
||
|
|
{
|
||
|
|
OBJECT_TYPE_TABLE_CELL=10000, // Ячейка таблицы
|
||
|
|
OBJECT_TYPE_TABLE_ROW, // Строка таблицы
|
||
|
|
OBJECT_TYPE_TABLE_MODEL, // Модель таблицы
|
||
|
|
OBJECT_TYPE_COLUMN_CAPTION, // Заголовок столбца таблицы
|
||
|
|
OBJECT_TYPE_TABLE_HEADER, // Заголовок таблицы
|
||
|
|
OBJECT_TYPE_TABLE, // Таблица
|
||
|
|
OBJECT_TYPE_TABLE_BY_PARAM, // Таблица на данных массива параметров
|
||
|
|
};
|
||
|
|
|
||
|
|
enum ENUM_CELL_COMPARE_MODE // Режимы сравнения ячеек таблицы
|
||
|
|
{
|
||
|
|
CELL_COMPARE_MODE_COL, // Сравнение по номеру колонки
|
||
|
|
CELL_COMPARE_MODE_ROW, // Сравнение по номеру строки
|
||
|
|
CELL_COMPARE_MODE_ROW_COL, // Сравнение по строке и колонке
|
||
|
|
};
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Функции |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Возвращает тип объекта как строку |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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:
|
||
|
|
//--- Виртуальный метод (1) загрузки списка из файла, (2) создания элемента списка
|
||
|
|
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);
|
||
|
|
//--- Загрузка и проверка типа списка
|
||
|
|
if(::FileReadInteger(file_handle,INT_VALUE)!=Type())
|
||
|
|
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)
|
||
|
|
{
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Класс ячейки таблицы |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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; // Флаг редактируемой ячейки
|
||
|
|
|
||
|
|
//--- Устанавливает "пустое значение"
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
public:
|
||
|
|
//--- Возврат координат и свойств ячейки
|
||
|
|
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; }
|
||
|
|
//--- Возвращает (1) double, (2) long, (3) string значение
|
||
|
|
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(); }
|
||
|
|
//--- Возвращает значение в виде форматированной строки
|
||
|
|
string Value(void) const
|
||
|
|
{
|
||
|
|
switch(this.m_datatype)
|
||
|
|
{
|
||
|
|
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) : "");
|
||
|
|
default : return this.ValueS();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//--- Возвращает описание типа хранимого значения
|
||
|
|
string DatatypeDescription(void) const
|
||
|
|
{
|
||
|
|
string type=::StringSubstr(::EnumToString(this.m_datatype),5);
|
||
|
|
type.Lower();
|
||
|
|
return type;
|
||
|
|
}
|
||
|
|
//--- Очищает данные
|
||
|
|
void ClearData(void) { this.SetEmptyValue(); }
|
||
|
|
//--- Установка значений переменных
|
||
|
|
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; }
|
||
|
|
//--- Устанавливает строку и колонку
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Возвращает (1) назначенный в ячейку объект, (2) тип назначенного в ячейку объекта
|
||
|
|
CObject *AssignedObject(void) { return this.m_object; }
|
||
|
|
ENUM_OBJECT_TYPE AssignedObjType(void) const { return this.m_object_type; }
|
||
|
|
|
||
|
|
//--- Устанавливает 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);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- (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_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
|
||
|
|
{
|
||
|
|
if(node==NULL)
|
||
|
|
return -1;
|
||
|
|
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);
|
||
|
|
|
||
|
|
//--- Создаёт новую ячейку и добавляет в конец списка
|
||
|
|
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);
|
||
|
|
|
||
|
|
//--- Возвращает (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);
|
||
|
|
|
||
|
|
//--- Возвращает (1) назначенный в ячейку объект, (2) тип назначенного в ячейку объекта
|
||
|
|
CObject *CellGetObject(const uint index);
|
||
|
|
ENUM_OBJECT_TYPE CellGetObjType(const uint index);
|
||
|
|
|
||
|
|
//--- (1) Удаляет (2) перемещает ячейку
|
||
|
|
bool CellDelete(const uint index);
|
||
|
|
bool CellMoveTo(const uint cell_index, const uint index_to);
|
||
|
|
|
||
|
|
//--- Обнуляет данные ячеек строки
|
||
|
|
void ClearData(void);
|
||
|
|
|
||
|
|
//--- (1) Возвращает, (2) выводит в журнал описание объекта
|
||
|
|
virtual string Description(void);
|
||
|
|
void Print(const bool detail, const bool as_table=false, const int cell_width=CELL_WIDTH_IN_CHARS);
|
||
|
|
|
||
|
|
//--- Виртуальные методы (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
|
||
|
|
{
|
||
|
|
if(node==NULL)
|
||
|
|
return -1;
|
||
|
|
const CTableRow *obj=node;
|
||
|
|
return(this.Index()>obj.Index() ? 1 : this.Index()<obj.Index() ? -1 : 0);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Создаёт новую double-ячейку и добавляет в конец списка |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CTableCell *CTableRow::CellAddNew(const double value)
|
||
|
|
{
|
||
|
|
//--- Создаём новый объект ячейки, хранящей значение с типом 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-ячейку и добавляет в конец списка |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CTableCell *CTableRow::CellAddNew(const long value)
|
||
|
|
{
|
||
|
|
//--- Создаём новый объект ячейки, хранящей значение с типом 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-ячейку и добавляет в конец списка |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CTableCell *CTableRow::CellAddNew(const datetime value)
|
||
|
|
{
|
||
|
|
//--- Создаём новый объект ячейки, хранящей значение с типом 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-ячейку и добавляет в конец списка |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CTableCell *CTableRow::CellAddNew(const color value)
|
||
|
|
{
|
||
|
|
//--- Создаём новый объект ячейки, хранящей значение с типом 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-ячейку и добавляет в конец списка |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CTableCell *CTableRow::CellAddNew(const string value)
|
||
|
|
{
|
||
|
|
//--- Создаём новый объект ячейки, хранящей значение с типом 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();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Возвращает назначенный в ячейку объект |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Удаляет ячейку |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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()));
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Выводит в журнал описание объекта |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableRow::Print(const bool detail, const bool as_table=false, const int cell_width=CELL_WIDTH_IN_CHARS)
|
||
|
|
{
|
||
|
|
|
||
|
|
//--- Количество ячеек
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Класс объекта параметра структуры |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
class CMqlParamObj : public CObject
|
||
|
|
{
|
||
|
|
protected:
|
||
|
|
public:
|
||
|
|
MqlParam m_param;
|
||
|
|
//--- Установка параметров
|
||
|
|
void Set(const MqlParam ¶m)
|
||
|
|
{
|
||
|
|
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)
|
||
|
|
{
|
||
|
|
case TYPE_STRING : v=this.ValueS(); break;
|
||
|
|
case TYPE_FLOAT : case TYPE_DOUBLE : v=::DoubleToString(this.ValueD()); break;
|
||
|
|
case TYPE_DATETIME: v=::TimeToString(this.ValueL(),TIME_DATE|TIME_MINUTES|TIME_SECONDS); break;
|
||
|
|
default : v=(string)this.ValueL(); break;
|
||
|
|
}
|
||
|
|
return(::StringFormat("<%s>%s",t,v));
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Конструкторы/деструктор
|
||
|
|
CMqlParamObj(void){}
|
||
|
|
CMqlParamObj(const MqlParam ¶m) { 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 ¶m)
|
||
|
|
{
|
||
|
|
CMqlParamObj *cell=new CMqlParamObj(param);
|
||
|
|
if(cell==NULL)
|
||
|
|
return false;
|
||
|
|
if(row.Add(cell)<0)
|
||
|
|
{
|
||
|
|
delete cell;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Класс модели таблицы |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
class CTableModel : public CObject
|
||
|
|
{
|
||
|
|
protected:
|
||
|
|
CTableRow m_row_tmp; // Объект строки для поиска в списке
|
||
|
|
CListObj m_list_rows; // Список строк таблицы
|
||
|
|
//--- Создаёт модель таблицы из двумерного массива
|
||
|
|
template<typename T>
|
||
|
|
void CreateTableModel(T &array[][]);
|
||
|
|
void CreateTableModel(const uint num_rows,const uint num_columns);
|
||
|
|
void CreateTableModel(const matrix &row_data);
|
||
|
|
void CreateTableModel(CList &list_param);
|
||
|
|
//--- Возвращает корректный тип данных
|
||
|
|
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);
|
||
|
|
CTableRow *GetRow(const uint index) { return this.m_list_rows.GetNodeAtIndex(index);}
|
||
|
|
uint RowsTotal(void) const { return this.m_list_rows.Total(); }
|
||
|
|
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);
|
||
|
|
//---Возвращает (1) назначенный в ячейку объект, (2) тип назначенного в ячейку объекта
|
||
|
|
CObject *CellGetObject(const uint row, const uint col);
|
||
|
|
ENUM_OBJECT_TYPE CellGetObjType(const uint row, const uint col);
|
||
|
|
//--- (1) Возвращает, (2) выводит в журнал описание ячейки, (3) назначенный в ячейку объект
|
||
|
|
string CellDescription(const uint row, const uint col);
|
||
|
|
void CellPrint(const uint row, const uint col);
|
||
|
|
|
||
|
|
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);
|
||
|
|
void RowClearData(const uint index);
|
||
|
|
//--- (1) Возвращает, (2) выводит в журнал описание строки
|
||
|
|
string RowDescription(const uint index);
|
||
|
|
void RowPrint(const uint index,const bool detail);
|
||
|
|
|
||
|
|
//--- (1) Добавляет, (2) удаляет (3) перемещает столбец, (4) очищает данные, устанавливает (5) тип, (6) точность данных столбца
|
||
|
|
bool ColumnAddNew(const int index=-1);
|
||
|
|
bool ColumnDelete(const uint index);
|
||
|
|
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);
|
||
|
|
|
||
|
|
//--- (1) Возвращает, (2) выводит в журнал описание таблицы
|
||
|
|
virtual string Description(void);
|
||
|
|
void Print(const bool detail);
|
||
|
|
void PrintTable(const int cell_width=CELL_WIDTH_IN_CHARS);
|
||
|
|
|
||
|
|
//--- (1) Очищает данные, (2) уничтожает модель
|
||
|
|
void ClearData(void);
|
||
|
|
void Destroy(void);
|
||
|
|
|
||
|
|
//--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта
|
||
|
|
virtual int Compare(const CObject *node,const int mode=0) const { return -1; }
|
||
|
|
virtual bool Save(const int file_handle);
|
||
|
|
virtual bool Load(const int file_handle);
|
||
|
|
virtual int Type(void) const { return(OBJECT_TYPE_TABLE_MODEL); }
|
||
|
|
|
||
|
|
//--- Конструкторы/деструктор
|
||
|
|
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); }
|
||
|
|
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++)
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Создаёт новую пустую строку и добавляет в конец списка |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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++)
|
||
|
|
row.CellAddNew(0.0);
|
||
|
|
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++)
|
||
|
|
row.CellAddNew(0.0);
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Возвращает назначенный в ячейку объект |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Возвращает количество ячеек в указанной строке |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Очищает строку (только данные в ячйках) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableModel::RowClearData(const uint index)
|
||
|
|
{
|
||
|
|
//--- Получаем строку из списка и очищаем данные ячеек строки методом ClearData()
|
||
|
|
CTableRow *row=this.GetRow(index);
|
||
|
|
if(row!=NULL)
|
||
|
|
row.ClearData();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Очищает таблицу (данные всех ячеек) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableModel::ClearData(void)
|
||
|
|
{
|
||
|
|
//--- В цикле по всем строкам таблицы очищаем данные каждой строки
|
||
|
|
for(uint i=0;i<this.RowsTotal();i++)
|
||
|
|
this.RowClearData(i);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Возвращает описание строки |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Добавляет столбец |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Удаляет столбец |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Очищает данные столбца |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableModel::ColumnClearData(const uint index)
|
||
|
|
{
|
||
|
|
//--- В цикле по всем строкам таблицы
|
||
|
|
for(uint i=0;i<this.RowsTotal();i++)
|
||
|
|
{
|
||
|
|
//--- получаем из каждой строки ячейку с индексом столбца и очищаем её
|
||
|
|
CTableCell *cell=this.GetCell(i, index);
|
||
|
|
if(cell!=NULL)
|
||
|
|
cell.ClearData();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Устанавливает тип данных столбца |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Возвращает описание объекта |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Выводит в журнал описание объекта в табличном виде |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableModel::PrintTable(const int cell_width=CELL_WIDTH_IN_CHARS)
|
||
|
|
{
|
||
|
|
//--- Получаем указатель на первую строку (индекс 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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Уничтожает модель |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableModel::Destroy(void)
|
||
|
|
{
|
||
|
|
//--- Очищаем список строк
|
||
|
|
this.m_list_rows.Clear();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Сохранение в файл |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Загрузка из файла |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Класс заголовка столбца таблицы |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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
|
||
|
|
{
|
||
|
|
if(node==NULL)
|
||
|
|
return -1;
|
||
|
|
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) тип объекта
|
||
|
|
virtual int Compare(const CObject *node,const int mode=0) const { return -1; }
|
||
|
|
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);
|
||
|
|
|
||
|
|
//--- Устанавливает (1) значение указанному заголовку, (2) точность данных указанному столбцу
|
||
|
|
void ColumnCaptionSetValue(const uint index,const string value);
|
||
|
|
void ColumnSetDigits(const uint index,const int digits);
|
||
|
|
|
||
|
|
//--- (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);
|
||
|
|
|
||
|
|
//--- Виртуальные методы (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
|
||
|
|
{
|
||
|
|
if(node==NULL)
|
||
|
|
return -1;
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Возвращает тип данных для указанного столбца |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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:
|
||
|
|
virtual int Type(void) const { return(OBJECT_TYPE_TABLE_BY_PARAM); }
|
||
|
|
//--- Конструктор/деструктор
|
||
|
|
CTableByParam(void) { this.m_list_rows.Clear(); }
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|