Pull to refresh

Информационные сообщения в 1С. Как это можно сделать

Reading time 32 min
Views 32K

Здравствуйте.
Сегодня речь пойдет о реализации подсистемы выдачи информационных сообщений пользователю. Стандартный способ проинформировать о чем-либо пользователя – это использование процедуры «Сообщить». Однако в некоторых случаях, хочется создать отдельный список, который не будет замусоривать своим выводом основной список сообщений платформы. Также желательно иметь возможность выделять цветом различные сообщения (в зависимости от их типа, например). В общем, расскажу, как это получилось сделать у меня. Приведенное в статье решение можно встроить в свою программу без какой-либо адаптации.

Предыстория.


В свое время, работая с системой контроля версий Perforce, а именно с ее графическими клиентами, я обратил внимание на удобный элемент интерфейса – многострочное поле вывода сообщений внизу главного окна программы. После того, как пользователь выполнял какие-то обращения к серверу системы, в это поле добавлялись текстовые сообщения, описывающие процесс взаимодействия клиента с сервером (какие конкретно действия выполнялись, и результат их выполнения). Не знаю, почему именно Perforce произвел на меня такое впечатление, хотя абсолютно ту же систему я наблюдал до и после в различных графических IDE (Delphi, C++ и т.д.) – окно вывода сообщений той консольной программы (компилятор или клиент системы контроля версий), в качестве оболочки которой выступает графическая программа. Но впрочем, статья вовсе не про Perforce, просто я считаю удобным способ многострочного вывода сообщений в процессе выполнения какой-то длительной работы. Получить большой список сообщений гораздо лучше (информативнее), чем одиночный MessageBox в самом конце этой работы. Подобный подход мы, кстати, видим и в антивирусных программах.

На создание собственной подсистемы сообщений меня натолкнула необходимость реализации программы, которая выполняет относительно длительный процесс обработки данных (т.е. пользователь нажал кнопку «Выполнить», а потом может, условно говоря, несколько минут ждать, пока процесс выполняется). Подобные программы (обработки) есть и в типовых конфигурациях 1С (в основном это различные выгрузки-загрузки). Стандартное окно сообщений платформы (то, куда выводится информация процедурой «Сообщить») меня не устраивало. Я хотел, чтобы сообщения, связанные с моей обработкой были сгруппированы, и не смешивались ни с какими другими сообщениями. Также я хотел, чтобы список сообщений можно было как-то сохранять на всякий случай (в текстовый файл, как это сделано в антивирусах). Ну и главное, я планировал сделать сообщения разного типа (информационные, предупреждения, сообщения об ошибках). Ну и соответственно раскрашивать их в различные цвета.

В рассматриваемом примере таблица вывода сообщения (элемент интерфейса ТабличноеПоле) выглядит примерно так:


Описание реализации.


В общем, опишу здесь то, что получилось. Для реализации буду опять использовать свою технологию «ООП в 1С» (метод подробно описан здесь). Соответственно будет создан «класс»: «СообщенияПрограммы».
В дальнейшем при объяснениях будем считать, что делаем внешнюю обработку.

Нам понадобятся иконки для отображения статусов сообщений. Загрузим из соответствующих BMP-файлов (прилагаются к данной статье) в ресурсы (макеты типа «Двоичные данные»)
Изображение Название исходного файла Название макета
statok.bmp КартинкаСообщениеСтатусОК
statwarning.bmp КартинкаСообщениеСтатусПредупреждение
staterror.bmp КартинкаСообщениеСтатусОшибка

Затем нужно будет как-то эти картинки загрузить для использования – превратим их в ресурсы.
Определим в главном модуле глобальную переменную «КоллекцияКартинок» в виде структуры из объектов стандартного класса «Картинка». Напишем подпрограмму «СформироватьКоллекциюКартинок», которая будет инициализировать коллецию. Будем вызывать эту подпрограмму в инициализирующей секции модуля.

Также наши сообщения будут иметь некоторые числовые типы – уровни. Номер уровня будет влиять на количество отступов из пробельных символов слева при выводе сообщения в интерфейс или файл (как бы наглядно показываем уровень вложенности сообщений друг в друга).
Название Описание Числовое значение
ТИПСООБЩ_НЕОПРЕД Неопределенное значение 0
ТИПСООБЩ_УРОВЕНЬ1 Уровень вложенности 1 1
ТИПСООБЩ_УРОВЕНЬ2 Уровень вложенности 2 2
ТИПСООБЩ_УРОВЕНЬ3 Уровень вложенности 3 3

У каждого сообщения есть определенный статус, показывающий, чем именно является сообщение.
Название Описание Числовое значение
СТАТСООБЩ_НЕОПРЕД Неопределенное значение 0
СТАТСООБЩ_ОК Уровень вложенности 1 1
СТАТСООБЩ_ПРЕДУПР Уровень вложенности 2 2
СТАТСООБЩ_ОШИБКА Уровень вложенности 3 3

Представим типы и статусы в виде числовых констант, как это делается в С/С++ (#define) или Pascal (const). В 1С будем имитировать константы вставкой их в глобальную переменную-структуру (ключ элемента структуры – это символьное имя константы, а значение элемента структуры – это численное значение константы).
Функция ИнициализацияПрочихКонстант()
	
	Проч = Новый Структура;
	
	// Типы сообщений
	Проч.Вставить("ТИПСООБЩ_НЕОПРЕД", 0);   // Тип неопределен
	Проч.Вставить("ТИПСООБЩ_УРОВЕНЬ1", 1);  // Сообщение уровня 1
	Проч.Вставить("ТИПСООБЩ_УРОВЕНЬ2", 2);  // Сообщение уровня 2
	Проч.Вставить("ТИПСООБЩ_УРОВЕНЬ3", 3);  // Сообщение уровня 3

	// Статусы сообщений
	Проч.Вставить("СТАТСООБЩ_НЕОПРЕД", 0);  // Статус неопределен
	Проч.Вставить("СТАТСООБЩ_ОК", 1);       // Статус "ОК"
	Проч.Вставить("СТАТСООБЩ_ПРЕДУПР", 2);  // Статус "Предупреждение"
	Проч.Вставить("СТАТСООБЩ_ОШИБКА", 3);   // Статус "Ошибка"
	
	Возврат Проч
	
КонецФункции

Еще нам нужно будет получать текущее значение времени в миллисекундах. Используем для этого машину JavaScript в виде глобальной переменной COM-объекта.

Вот что получилось в главном модуле:
Исходный текст
////////////////////////////////////////////////////////////////////////////////
// ПРОЧИЕ КОНСТАНТЫ

Перем Проч Экспорт;                       // Структура с константами

Перем КоллекцияКартинок Экспорт;          // Набор иконок интерфейса


////////////////////////////////////////////////////////////////////////////////
// ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ

Перем JavaScript;                         // Машина для работы с JavaScript


///////////////////////////////////////////////////////////////////////////////////////////////////
//
// П О Д П Р О Г Р А М М Ы    И Н И Ц И А Л И З А Ц И И    К О Н С Т А Н Т
//
///////////////////////////////////////////////////////////////////////////////////////////////////

// Инициализирует набор констант общего назначения
//
// Параметры:
//  НЕТ.
//
// Возврат:
//  Структура с полями - константами общего назначения
//
Функция ИнициализацияПрочихКонстант()
	
	Проч = Новый Структура;
	
	// Типы сообщений
	Проч.Вставить("ТИПСООБЩ_НЕОПРЕД", 0);   // Тип неопределен
	Проч.Вставить("ТИПСООБЩ_УРОВЕНЬ1", 1);  // Сообщение уровня 1
	Проч.Вставить("ТИПСООБЩ_УРОВЕНЬ2", 2);  // Сообщение уровня 2
	Проч.Вставить("ТИПСООБЩ_УРОВЕНЬ3", 3);  // Сообщение уровня 3

	// Статусы сообщений
	Проч.Вставить("СТАТСООБЩ_НЕОПРЕД", 0);  // Статус неопределен
	Проч.Вставить("СТАТСООБЩ_ОК", 1);       // Статус "ОК"
	Проч.Вставить("СТАТСООБЩ_ПРЕДУПР", 2);  // Статус "Предупреждение"
	Проч.Вставить("СТАТСООБЩ_ОШИБКА", 3);   // Статус "Ошибка"
	
	Возврат Проч
	
КонецФункции


// Формирует набор картинок, на основании изображений, сохраненных в двоичных
// макетах обработки.
//
// Параметры:
//  НЕТ.
//
// Возврат:
//  Структура с полями - объектами типа Картинка с загруженными картинками
//
Функция СформироватьКоллекциюКартинок()
	
	КоллекцияКартинок = Новый Структура;
	
	КоллекцияКартинок.Вставить("СообщениеСтатусОК", Новый Картинка(ПолучитьМакет("КартинкаСообщениеСтатусОК")));
	КоллекцияКартинок.Вставить("СообщениеСтатусПредупреждение", Новый Картинка(ПолучитьМакет("КартинкаСообщениеСтатусПредупреждение")));
	КоллекцияКартинок.Вставить("СообщениеСтатусОшибка", Новый Картинка(ПолучитьМакет("КартинкаСообщениеСтатусОшибка")));
	
	Возврат КоллекцияКартинок
	
КонецФункции


///////////////////////////////////////////////////////////////////////////////////////////////////
//
// П О Д П Р О Г Р А М М Ы    И Н И Ц И А Л И З А Ц И И    Г Л О Б А Л Ь Н Ы Х    П Е Р Е М Е Н Н Ы Х
//
///////////////////////////////////////////////////////////////////////////////////////////////////

// Создает объект JavaScript и возвращает его в качестве значения
// Формирует набор картинок, на основании изображений, сохраненных в двоичных
// макетах обработки.
//
// Параметры:
//  НЕТ.
//
// Возврат:
//  Ссылка на машину JavaScript или Неопределено, если машина не создана
//
Функция СоздатьОбъектJavaScript()
	
	Рез = Неопределено;
	Попытка
		Рез = Новый COMОбъект("MSScriptControl.ScriptControl");
	    Рез.Language = "javascript";	
	Исключение
	КонецПопытки;

    Возврат Рез

КонецФункции


///////////////////////////////////////////////////////////////////////////////////////////////////
//
// П О Д П Р О Г Р А М М Ы    О Б Щ Е Г О    Н А З Н А Ч Е Н И Я
//
///////////////////////////////////////////////////////////////////////////////////////////////////

// Расширяет строку до заданной ширины пробелами, добавляя их слева
//
// Параметры:
//  Стр - исходная строка
//  Ширина - кол-во символов до которого нужно расширить строку
// Возврат:
//  Полученная строка
//
Функция РасширСтрЛев(Стр, Ширина)
	
	Рез = Стр;
	Инд = Ширина - СтрДлина(Рез);
	Пока Инд > 0 Цикл
		Рез = " " + Рез;
		Инд = Инд - 1
	КонецЦикла;
	
	Возврат Рез
	
КонецФункции

// Расширяет строку до заданной ширины пробелами, добавляя их справа
//
// Параметры:
//  Стр - исходная строка
//  Ширина - кол-во символов до которого нужно расширить строку
// Возврат:
//  Полученная строка
//
Функция РасширСтрПрав(Стр, Ширина)
	
	Рез = Стр;
	Инд = Ширина - СтрДлина(Рез);
	Пока Инд > 0 Цикл
		Рез = Рез + " ";
		Инд = Инд - 1
	КонецЦикла;
	
	Возврат Рез
	
КонецФункции


// Возвращает текущую дату и время в миллисекундах
//
// Параметры:
//  НЕТ
// Возврат:
//  Числовое значение или 0, если значение определить не удалось
//
Функция ПолучитьТекущееВремяВМиллисекундах() Экспорт
	
	Время = 0;
	Если JavaScript <> Неопределено Тогда
		Время = JavaScript.Eval("new Date().getTime()");
	КонецЕсли;
	
	Возврат Время;
	
КонецФункции




////////////////////////////////////////////////////////////////////////////////
// ОПЕРАТОРЫ ОСНОВНОЙ ПРОГРАММЫ - НАЧАЛЬНАЯ ИНИЦИАЛИЗАЦИЯ



// ИНИЦИАЛИЗАЦИЯ КОНСТАНТ

// Константы общего назначения
Проч = ИнициализацияПрочихКонстант();

// Коллекция картинок
КоллекцияКартинок = СформироватьКоллекциюКартинок();



// ИНИЦИАЛИЗАЦИЯ ГЛОБАЛЬНЫХ ПЕРЕМЕННЫХ

// Создать машину JavaScript
JavaScript = СоздатьОбъектJavaScript();


Набор сообщений существует в виде таблицы значений (стандартный класс ТаблицаЗначений) со следующими колонками:
Название колонки Тип данных Назначение
ТипСообщ Число Тип сообщения (уровень) – одна из констант ТИПСООБЩ_
СтатусСообщ Число Статус сообщения – одна из констант СТАТСООБЩ_
ТекстСообщ Строка Основной текст сообщения. Здесь обычно указываем, какое действие выполняется длительным процессом в данный момент.
КомментарийСообщ Строка Дополнительный текст сообщения. Здесь обычно указываем результат выполнения действия, описанного в колонке ТекстСообщ. Если действие завершилось ошибкой, то сообщение об ошибке приводим в этой же колонке

Эта таблица значений уже может отображаться в каких-то элементах интерфейса пользователя (например в объекте класса TaбличноеПоле).

Набор сообщений будет реализован в виде класса, имеющего следующие методы:
Заголовок метода Описание
Функция Сообщения_Конструктор() Начальное создание объекта. Возвращает объект класса «Сообщения».
Процедура Сообщения_УстАтриб(Сообщ, Форма, ТабПоле, ТабЗнач) Установка атрибутов объекта. Нужно передать:
— ссылку на форму (Форма), на которой будет отображаться список сообщений;
— элемент формы типа ТабличноеПоле (ТабПоле), в который будут выводится сообщения;
— ТаблицаЗначений (ТабЗнач), в которой будет храниться собственно список сообщений.
Процедура Сообщения_Инициализация(Сообщ) Будет проинициализирована ТаблицаЗначений (ранее установленная процедурой Сообщения_УстАтриб)
Процедура Сообщения_Обновить(Сообщ) Выполняет принудительную отрисовку списка сообщений на форме (ранее установленная процедурой Сообщения_УстАтриб)
Функция Сообщения_Добавить(Сообщ, ТипСообщ, ТекстСообщ, СтатусСообщ=Неопределено, КомментСообщ=Неопределено) Добавляет в набор новое сообщение с соответствующими атрибутами. Возвращает идентификатор сообщения с помощью которого, к данному сообщению можно будет обращаться в дальнейшем.
Процедура Сообщения_Изменить(Сообщ, ИдСообщ, ТипСообщ=Неопределено, ТекстСообщ=Неопределено, СтатусСообщ=Неопределено, КомментСообщ=Неопределено) Изменяет атрибуты уже существующего сообщения с указанным идентификатором.
Процедура Сообщения_Удалить(Сообщ, ИдСообщ) Удалить ранее добавленное сообщение с соответствующим идентификатором.
Процедура Сообщения_Очистить(Сообщ) Удалить все сообщения набора.
Функция Сообщения_ПолучитьТип(Сообщ, ИдСообщ) Получить атрибут «Тип» для существующего сообщения с указанным идентификатором.
Процедура Сообщения_УстановитьТип(Сообщ, ИдСообщ, ТипСообщ) Установить атрибут «Тип» для существующего сообщения с указанным идентификатором.
Функция Сообщения_ПолучитьСтатус(Сообщ, ИдСообщ) Получить атрибут «Статус» для существующего сообщения с указанным идентификатором.
Процедура Сообщения_УстановитьСтатус(Сообщ, ИдСообщ, СтатусСообщ) Установить атрибут «Статус» для существующего сообщения с указанным идентификатором.
Функция Сообщения_ПолучитьТекст(Сообщ, ИдСообщ) Получить атрибут «Текст сообщения» для существующего сообщения с указанным идентификатором.
Процедура Сообщения_УстановитьТекст(Сообщ, ИдСообщ, ТекстСообщ) Установить атрибут «Текст сообщения» для существующего сообщения с указанным идентификатором.
Функция Сообщения_ПолучитьКоммент(Сообщ, ИдСообщ) Получить атрибут «Комментарий» для существующего сообщения с указанным идентификатором.
Процедура Сообщения_УстановитьКоммент(Сообщ, ИдСообщ, КомментСообщ) Установить атрибут «Комментарий» для существующего сообщения с указанным идентификатором.
Функция Сообщения_ЦветТекста(ТипСообщ, СтатусСообщ) Определить цвет текста сообщения для указанного статуса. Используется при раскраске сообщений в интерфейсе.
Функция Сообщения_ЦветКомментария(ТипСообщ, СтатусСообщ) Определить цвет дополнительного текста (комментария) сообщения для указанного статуса. Используется при раскраске сообщений в интерфейсе.
Функция Сообщения_Картинка(ТипСообщ, СтатусСообщ) Определить иконку для сообщения с указанным статусом. Используется при выводе сообщений в интерфейсе.
Функция Сообщения_СохранитьВФайл(Сообщ) Сохранить набор сообщений в текстовый файл (имя файла запрашивает у пользователя).

Итак, полный текст главного модуля обработки:
Текст модуля
////////////////////////////////////////////////////////////////////////////////
// ПРОЧИЕ КОНСТАНТЫ

Перем Проч Экспорт;                       // Структура с константами

Перем КоллекцияКартинок Экспорт;          // Набор иконок интерфейса


////////////////////////////////////////////////////////////////////////////////
// ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ

Перем JavaScript;                         // Машина для работы с JavaScript


///////////////////////////////////////////////////////////////////////////////////////////////////
//
// П О Д П Р О Г Р А М М Ы    И Н И Ц И А Л И З А Ц И И    К О Н С Т А Н Т
//
///////////////////////////////////////////////////////////////////////////////////////////////////

// Инициализирует набор констант общего назначения
//
// Параметры:
//  НЕТ.
//
// Возврат:
//  Структура с полями - константами общего назначения
//
Функция ИнициализацияПрочихКонстант()
	
	Проч = Новый Структура;
	
	// Типы сообщений
	Проч.Вставить("ТИПСООБЩ_НЕОПРЕД", 0);   // Тип неопределен
	Проч.Вставить("ТИПСООБЩ_УРОВЕНЬ1", 1);  // Сообщение уровня 1
	Проч.Вставить("ТИПСООБЩ_УРОВЕНЬ2", 2);  // Сообщение уровня 2
	Проч.Вставить("ТИПСООБЩ_УРОВЕНЬ3", 3);  // Сообщение уровня 3

	// Статусы сообщений
	Проч.Вставить("СТАТСООБЩ_НЕОПРЕД", 0);  // Статус неопределен
	Проч.Вставить("СТАТСООБЩ_ОК", 1);       // Статус "ОК"
	Проч.Вставить("СТАТСООБЩ_ПРЕДУПР", 2);  // Статус "Предупреждение"
	Проч.Вставить("СТАТСООБЩ_ОШИБКА", 3);   // Статус "Ошибка"
	
	Возврат Проч
	
КонецФункции


// Формирует набор картинок, на основании изображений, сохраненных в двоичных
// макетах обработки.
//
// Параметры:
//  НЕТ.
//
// Возврат:
//  Структура с полями - объектами типа Картинка с загруженными картинками
//
Функция СформироватьКоллекциюКартинок()
	
	КоллекцияКартинок = Новый Структура;
	
	КоллекцияКартинок.Вставить("СообщениеСтатусОК", Новый Картинка(ПолучитьМакет("КартинкаСообщениеСтатусОК")));
	КоллекцияКартинок.Вставить("СообщениеСтатусПредупреждение", Новый Картинка(ПолучитьМакет("КартинкаСообщениеСтатусПредупреждение")));
	КоллекцияКартинок.Вставить("СообщениеСтатусОшибка", Новый Картинка(ПолучитьМакет("КартинкаСообщениеСтатусОшибка")));
	
	Возврат КоллекцияКартинок
	
КонецФункции


///////////////////////////////////////////////////////////////////////////////////////////////////
//
// П О Д П Р О Г Р А М М Ы    И Н И Ц И А Л И З А Ц И И    Г Л О Б А Л Ь Н Ы Х    П Е Р Е М Е Н Н Ы Х
//
///////////////////////////////////////////////////////////////////////////////////////////////////

// Создает объект JavaScript и возвращает его в качестве значения
// Формирует набор картинок, на основании изображений, сохраненных в двоичных
// макетах обработки.
//
// Параметры:
//  НЕТ.
//
// Возврат:
//  Ссылка на машину JavaScript или Неопределено, если машина не создана
//
Функция СоздатьОбъектJavaScript()
	
	Рез = Неопределено;
	Попытка
		Рез = Новый COMОбъект("MSScriptControl.ScriptControl");
	    Рез.Language = "javascript";	
	Исключение
	КонецПопытки;

    Возврат Рез

КонецФункции


///////////////////////////////////////////////////////////////////////////////////////////////////
//
// П О Д П Р О Г Р А М М Ы    О Б Щ Е Г О    Н А З Н А Ч Е Н И Я
//
///////////////////////////////////////////////////////////////////////////////////////////////////

// Расширяет строку до заданной ширины пробелами, добавляя их слева
//
// Параметры:
//  Стр - исходная строка
//  Ширина - кол-во символов до которого нужно расширить строку
// Возврат:
//  Полученная строка
//
Функция РасширСтрЛев(Стр, Ширина)
	
	Рез = Стр;
	Инд = Ширина - СтрДлина(Рез);
	Пока Инд > 0 Цикл
		Рез = " " + Рез;
		Инд = Инд - 1
	КонецЦикла;
	
	Возврат Рез
	
КонецФункции

// Расширяет строку до заданной ширины пробелами, добавляя их справа
//
// Параметры:
//  Стр - исходная строка
//  Ширина - кол-во символов до которого нужно расширить строку
// Возврат:
//  Полученная строка
//
Функция РасширСтрПрав(Стр, Ширина)
	
	Рез = Стр;
	Инд = Ширина - СтрДлина(Рез);
	Пока Инд > 0 Цикл
		Рез = Рез + " ";
		Инд = Инд - 1
	КонецЦикла;
	
	Возврат Рез
	
КонецФункции


// Возвращает текущую дату и время в миллисекундах
//
// Параметры:
//  НЕТ
// Возврат:
//  Числовое значение или 0, если значение определить не удалось
//
Функция ПолучитьТекущееВремяВМиллисекундах() Экспорт
	
	Время = 0;
	Если JavaScript <> Неопределено Тогда
		Время = JavaScript.Eval("new Date().getTime()");
	КонецЕсли;
	
	Возврат Время;
	
КонецФункции


// Преобразует массив чисел из объекта COMSafeArray в строку символов
//
// Параметры:
//  ОбъектCOMSafeArray - ссылка на массив чисел типа COMSafeArray
//                       (размерность массива должна быть 1)
// Возврат:
//  Полученная строка или "", если операцию выполнить не удалось
//
Функция COMSafeArrayВСтроку(ОбъектCOMSafeArray) Экспорт
	
	Рез = "";
	
	Если ТипЗнч(ОбъектCOMSafeArray) = Тип("COMSafeArray") И
		 (ОбъектCOMSafeArray.GetDimensions() = 1) И
		 (ОбъектCOMSafeArray.GetLength(0) > 0) Тогда
		Массив = ОбъектCOMSafeArray.Выгрузить();
		Для Каждого КодСимв Из Массив Цикл
			Если ТипЗнч(КодСимв) = Тип("Число") Тогда
				// Перекодировка символа из Windows-1251 в UTF-8
				Если (КодСимв >= 192) И (КодСимв <= 223) Тогда
					// А - Я
					КодСимв = КодСимв + 848
				ИначеЕсли (КодСимв >= 224) И (КодСимв <= 239) Тогда
					// а - п
					КодСимв = КодСимв + 848
				ИначеЕсли (КодСимв >= 240) И (КодСимв <= 255) Тогда
					// р - я
					КодСимв = КодСимв + 848
				ИначеЕсли (КодСимв = 184) Тогда
					// ё
					КодСимв = 1105
				ИначеЕсли (КодСимв = 168) Тогда
					// Ё
					КодСимв = 1025
				ИначеЕсли (КодСимв = 185) Тогда
					// №
					КодСимв = 8470
				КонецЕсли;
				// Добавить символ к строке
				Рез = Рез + Символ(КодСимв)
			КонецЕсли
		КонецЦикла
	КонецЕсли;
	
	Возврат Рез
	
КонецФункции



///////////////////////////////////////////////////////////////////////////////////////////////////
//
// К Л А С С Ы    О Б Щ Е Г О    Н А З Н А Ч Е Н И Я
//
///////////////////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Реализация класса СообщенияПрограммы (Сообщения)

// Создание полей объекта в виде структуры.
//
// Параметры:
//  Нет.
// Возврат:
//  Возвращает созданную структуру
//
Функция Сообщения_СоздатьОбъект() Экспорт
	
	Сообщ = Новый Структура;
	// Общие параметры сущности
	Сообщ.Вставить("Форма", Неопределено);      // Форма с табличным полем
	Сообщ.Вставить("ТабПоле", Неопределено);    // Табличное поле на форме
	Сообщ.Вставить("ТабЗнач", Неопределено);    // Таблица значений с сообщениями
	Сообщ.Вставить("ВремяПредОбновл", Неопределено); // Время последн. обновл. формы, мс (INT)
	
	Возврат Сообщ;
	
КонецФункции

// Имитирует конструктор объекта.
//
// Параметры:
//  НЕТ
// Возврат:
//  (Структура) - Структура с полями объекта
//
Функция Сообщения_Конструктор() Экспорт
	
	Сообщ = Сообщения_СоздатьОбъект();
	
	Возврат Сообщ;
	
КонецФункции

// Имитирует деструктор объекта - освобождает память.
//
// Параметры:
//  Сообщ - ссылка на объект
//
Процедура Сообщения_Деструктор(Сообщ) Экспорт
	
КонецПроцедуры

// Устанавливает основные атрибуты для вывода сообщений.
//
// Параметры:
//  Сообщ - ссылка на объект
//  Форма - ссылка на форму, на которой расположено табличное поле списка
//  ТабПоле - ссылка табличное поле списка для вывода сообщений
//  ТабЗнач - таблица значений с сообщениями
//
Процедура Сообщения_УстАтриб(Сообщ, Форма, ТабПоле, ТабЗнач) Экспорт
	
	Сообщ.Форма = Форма;
	Сообщ.ТабПоле = ТабПоле;
	Сообщ.ТабЗнач = ТабЗнач
	
КонецПроцедуры

// Инициализирует таблицу сообщений. Добавляет недостающие колонки
//
// Параметры:
//  Сообщ - ссылка на объект
//
Процедура Сообщения_Инициализация(Сообщ) Экспорт
	
	Если Сообщ.ТабЗнач <> Неопределено Тогда
		КЧ = Новый КвалификаторыЧисла(10, 0);
		КС = Новый КвалификаторыСтроки();
		МассивТипов = Новый Массив;
		МассивТипов.Добавить(Тип("Число"));
		ОписаниеТиповЧисла = Новый ОписаниеТипов(МассивТипов, , ,КЧ);
		МассивТипов.Очистить();
		МассивТипов.Добавить(Тип("Строка"));
		ОписаниеТиповСтроки = Новый ОписаниеТипов(МассивТипов, , КС);
		
		// Колонка "ТипСообщ"
		Если Сообщ.ТабЗнач.Колонки.Найти("ТипСообщ") = Неопределено Тогда
			Сообщ.ТабЗнач.Колонки.Добавить("ТипСообщ", ОписаниеТиповЧисла, "Тип", 30)
		КонецЕсли;
		// Колонка "СтатусСообщ"
		Если Сообщ.ТабЗнач.Колонки.Найти("СтатусСообщ") = Неопределено Тогда
			Сообщ.ТабЗнач.Колонки.Добавить("СтатусСообщ", ОписаниеТиповЧисла, "Статус", 30)
		КонецЕсли;
		// Колонка "ТекстСообщ"
		Если Сообщ.ТабЗнач.Колонки.Найти("ТекстСообщ") = Неопределено Тогда
			Сообщ.ТабЗнач.Колонки.Добавить("ТекстСообщ", ОписаниеТиповСтроки, "Текст", 200)
		КонецЕсли;
		// Колонка "КомментарийСообщ"
		Если Сообщ.ТабЗнач.Колонки.Найти("КомментарийСообщ") = Неопределено Тогда
			Сообщ.ТабЗнач.Колонки.Добавить("КомментарийСообщ", ОписаниеТиповСтроки, "Комментарий", 200)
		КонецЕсли
	КонецЕсли

КонецПроцедуры

// Выполняет овновление формы, на которой размещено табличное поле
// Тем самым вызывает прорисовку сообщений.
// Выполняет это не чаще заданного интервала, мс
//
// Параметры:
//  Сообщ - ссылка на объект
//
Процедура Сообщения_Обновить(Сообщ) Экспорт
	
	Если Сообщ.Форма <> Неопределено Тогда
		Интервал = 500;  // Интервал обновлений (не чаще), мс
		ВремяТекущОбновл = ПолучитьТекущееВремяВМиллисекундах();
		Если (Сообщ.ВремяПредОбновл = Неопределено) ИЛИ
			 (Сообщ.ВремяПредОбновл = 0) ИЛИ
			 (ВремяТекущОбновл - Сообщ.ВремяПредОбновл >= Интервал) Тогда
			// Выполняем обновление
			Сообщ.ВремяПредОбновл = ВремяТекущОбновл;
			Сообщ.Форма.Обновить()
		КонецЕсли
	КонецЕсли
	
КонецПроцедуры

// Добавляет новое сообщение в таблицу значений
//
// Параметры:
//  Сообщ - ссылка на объект;
//  ТипСообщ - тип добавляемого сообщения;
//  ТекстСообщ - текст добавляемого сообщения;
//  СтатусСообщ - статус добавляемого сообщения;
//  КомментСообщ - комментарий к добавляемому сообщению
// Возврат:
//  Уникальный идентификатор добавленного сообщения. Используется для дальнейшего обращения к сообщению с целью
//  его редактирования. По сути представляет собой порядковый номер строки в таблице Сообщ.ТабЗнач
//
Функция Сообщения_Добавить(Сообщ, ТипСообщ, ТекстСообщ, СтатусСообщ=Неопределено, КомментСообщ=Неопределено) Экспорт
	
	ИдСообщ = Неопределено;
	Если (Сообщ.ТабЗнач <> Неопределено) И
		 (ТипСообщ <> Неопределено) И
		 (ТипСообщ >= Проч.ТИПСООБЩ_УРОВЕНЬ1) И (ТипСообщ <= Проч.ТИПСООБЩ_УРОВЕНЬ3) И
 		 (ТекстСообщ <> Неопределено) Тогда
		НоваяСтрока = Сообщ.ТабЗнач.Добавить();
		НоваяСтрока.ТипСообщ = ТипСообщ;
		// Преобразовать текст
		Если ТипСообщ = Проч.ТИПСООБЩ_УРОВЕНЬ1 Тогда
			
		ИначеЕсли ТипСообщ = Проч.ТИПСООБЩ_УРОВЕНЬ2 Тогда
			ТекстСообщ = "  " + ТекстСообщ
		ИначеЕсли ТипСообщ = Проч.ТИПСООБЩ_УРОВЕНЬ3 Тогда
			ТекстСообщ = "    " + ТекстСообщ
		КонецЕсли;
		// Установить текст
		НоваяСтрока.ТекстСообщ = ТекстСообщ;
		Если (СтатусСообщ <> Неопределено) И
			 (СтатусСообщ >= Проч.СТАТСООБЩ_ОК) И (СтатусСообщ <= Проч.СТАТСООБЩ_ОШИБКА) Тогда
			НоваяСтрока.СтатусСообщ = СтатусСообщ;
		Иначе
			НоваяСтрока.СтатусСообщ = Проч.СТАТСООБЩ_НЕОПРЕД;
		КонецЕсли;
		НоваяСтрока.КомментарийСообщ = КомментСообщ;
		Если Сообщ.ТабПоле <> Неопределено Тогда
			// Изменение текущей строки табличного поля на добавляемую,
			// чтобы пользователь видел, что добавляется в список в данный момент
			Сообщ.ТабПоле.ТекущаяСтрока = НоваяСтрока;
		КонецЕсли;
		Сообщения_Обновить(Сообщ);
		 
		ИдСообщ = Сообщ.ТабЗнач.Индекс(НоваяСтрока);
	КонецЕсли;
	 
	Возврат ИдСообщ

КонецФункции

// Изменяет атрибуты сообщения с идентификатором ИдСообщ. Те, значение которых не "Неопределено"
//
// Параметры:
//  Сообщ - ссылка на объект;
//  ИдСообщ - идентификатор сообщения (порядковый номер строки);
//  ТипСообщ - тип добавляемого сообщения;
//  ТекстСообщ - текст добавляемого сообщения;
//  СтатусСообщ - статус добавляемого сообщения;
//  КомментСообщ - комментарий к добавляемому сообщению
//
Процедура Сообщения_Изменить(Сообщ, ИдСообщ, ТипСообщ=Неопределено, ТекстСообщ=Неопределено, 
							 СтатусСообщ=Неопределено, КомментСообщ=Неопределено) Экспорт
	
	Если (Сообщ.ТабЗнач <> Неопределено) И
		 (ИдСообщ <> Неопределено) И
		 (ИдСообщ >= 0) И (ИдСообщ < Сообщ.ТабЗнач.Количество()) Тогда
		ФлагИзменения = Ложь; // Признак того, что что-то изменили (хоть один атрибут)
		Если ТипСообщ <> Неопределено Тогда
			Если (ТипСообщ <> Сообщ.ТабЗнач[ИдСообщ].ТипСообщ) И
				  (ТипСообщ >= Проч.ТИПСООБЩ_УРОВЕНЬ1) И (ТипСообщ <= Проч.ТИПСООБЩ_УРОВЕНЬ3) Тогда
				Сообщ.ТабЗнач[ИдСообщ].ТипСообщ = ТипСообщ;
				ФлагИзменения = Истина
			КонецЕсли
		КонецЕсли;
		Если ТекстСообщ <> Неопределено Тогда
			Если ТекстСообщ <> Сообщ.ТабЗнач[ИдСообщ].ТекстСообщ Тогда
				// Преобразовать текст
				Если Сообщ.ТабЗнач[ИдСообщ].ТипСообщ = Проч.ТИПСООБЩ_УРОВЕНЬ1 Тогда
			
				ИначеЕсли Сообщ.ТабЗнач[ИдСообщ].ТипСообщ = Проч.ТИПСООБЩ_УРОВЕНЬ2 Тогда
					ТекстСообщ = "  " + ТекстСообщ
				ИначеЕсли Сообщ.ТабЗнач[ИдСообщ].ТипСообщ = Проч.ТИПСООБЩ_УРОВЕНЬ3 Тогда
					ТекстСообщ = "    " + ТекстСообщ
				КонецЕсли;
				// Установить текст
				Сообщ.ТабЗнач[ИдСообщ].ТекстСообщ = ТекстСообщ;
				ФлагИзменения = Истина
			КонецЕсли
		КонецЕсли;
		Если СтатусСообщ <> Неопределено Тогда
			Если СтатусСообщ <> Сообщ.ТабЗнач[ИдСообщ].СтатусСообщ Тогда
				Если (СтатусСообщ <> Неопределено) И
					 (СтатусСообщ >= Проч.СТАТСООБЩ_ОК) И (СтатусСообщ <= Проч.СТАТСООБЩ_ОШИБКА) Тогда
					Сообщ.ТабЗнач[ИдСообщ].СтатусСообщ = СтатусСообщ;
				Иначе
					Сообщ.ТабЗнач[ИдСообщ].СтатусСообщ = Проч.СТАТСООБЩ_НЕОПРЕД;
				КонецЕсли;
				ФлагИзменения = Истина
			КонецЕсли
		КонецЕсли;
		Если КомментСообщ <> Неопределено Тогда
			Если КомментСообщ <> Сообщ.ТабЗнач[ИдСообщ].КомментарийСообщ Тогда
				Сообщ.ТабЗнач[ИдСообщ].КомментарийСообщ = КомментСообщ;
				ФлагИзменения = Истина
			КонецЕсли
		КонецЕсли;
		Если ФлагИзменения = Истина Тогда
			// Прорисовка, если реально було обновление
			Сообщения_Обновить(Сообщ)
		КонецЕсли
	КонецЕсли

КонецПроцедуры

// Удаляет сообщение с идентификатором ИдСообщ
//
// Параметры:
//  Сообщ - ссылка на объект
//  ИдСообщ - идентификатор сообщения (порядковый номер строки)
//
Процедура Сообщения_Удалить(Сообщ, ИдСообщ) Экспорт
	
	Если (Сообщ.ТабЗнач <> Неопределено) И
		 (ИдСообщ <> Неопределено) И
		 (ИдСообщ >= 0) И (ИдСообщ < Сообщ.ТабЗнач.Количество()) Тогда
		Сообщ.ТабЗнач.Удалить(ИдСообщ);
		Сообщения_Обновить(Сообщ)
	КонецЕсли
	
КонецПроцедуры

// Удаляет все сообщения из таблицы
//
// Параметры:
//  Сообщ - ссылка на объект
//
Процедура Сообщения_Очистить(Сообщ) Экспорт
	
	Если (Сообщ.ТабЗнач <> Неопределено) И
		 (Сообщ.ТабЗнач.Количество() > 0) Тогда
		Сообщ.ТабЗнач.Очистить();
		Сообщения_Обновить(Сообщ)
	КонецЕсли
	
КонецПроцедуры

// Возвращает тип сообщения с идентификатором ИдСообщ
//
// Параметры:
//  Сообщ - ссылка на объект
//  ИдСообщ - идентификатор сообщения (порядковый номер строки)
// Возврат:
//  Тип сообщения или Неопределено, если сообщение не найдено
//
Функция Сообщения_ПолучитьТип(Сообщ, ИдСообщ) Экспорт
	
	Рез = Неопределено;
	Если (Сообщ.ТабЗнач <> Неопределено) И
		 (ИдСообщ <> Неопределено) И
		 (ИдСообщ >= 0) И (ИдСообщ < Сообщ.ТабЗнач.Количество()) Тогда
		Рез = Сообщ.ТабЗнач[ИдСообщ].ТипСообщ
	КонецЕсли;
	 
	Возврат Рез
	
КонецФункции

// Устанавливает тип сообщения с идентификатором ИдСообщ
//
// Параметры:
//  Сообщ - ссылка на объект
//  ИдСообщ - идентификатор сообщения (порядковый номер строки)
//  ТипСообщ - тип сообщения
//
Процедура Сообщения_УстановитьТип(Сообщ, ИдСообщ, ТипСообщ) Экспорт

	Если (Сообщ.ТабЗнач <> Неопределено) И
		 (ИдСообщ <> Неопределено) И
		 (ИдСообщ >= 0) И (ИдСообщ < Сообщ.ТабЗнач.Количество()) И
		 (ТипСообщ <> Сообщ.ТабЗнач[ИдСообщ].ТекстСообщ) И
		 (ТипСообщ >= Проч.ТИПСООБЩ_УРОВЕНЬ1) И (ТипСообщ <= Проч.ТИПСООБЩ_УРОВЕНЬ3) Тогда
		Сообщ.ТабЗнач[ИдСообщ].ТипСообщ = ТипСообщ;
		Сообщения_Обновить(Сообщ)
	КонецЕсли;
	 
КонецПроцедуры

// Возвращает статус сообщения с идентификатором ИдСообщ
//
// Параметры:
//  Сообщ - ссылка на объект
//  ИдСообщ - идентификатор сообщения (порядковый номер строки)
// Возврат:
//  Статус сообщения или Неопределено, если сообщение не найдено
//
Функция Сообщения_ПолучитьСтатус(Сообщ, ИдСообщ) Экспорт
	
	Рез = Неопределено;
	Если (Сообщ.ТабЗнач <> Неопределено) И
		 (ИдСообщ <> Неопределено) И
		 (ИдСообщ >= 0) И (ИдСообщ < Сообщ.ТабЗнач.Количество()) Тогда
		 Рез = Сообщ.ТабЗнач[ИдСообщ].СтатусСообщ
	КонецЕсли;
	 
	Возврат Рез
	
КонецФункции

// Устанавливает статус сообщения с идентификатором ИдСообщ
//
// Параметры:
//  Сообщ - ссылка на объект
//  ИдСообщ - идентификатор сообщения (порядковый номер строки)
//  СтатусСообщ - статус сообщения
//
Процедура Сообщения_УстановитьСтатус(Сообщ, ИдСообщ, СтатусСообщ) Экспорт
	
	Если (Сообщ.ТабЗнач <> Неопределено) И
		 (ИдСообщ <> Неопределено) И
		 (ИдСообщ >= 0) И (ИдСообщ < Сообщ.ТабЗнач.Количество()) И
		 (СтатусСообщ <> Сообщ.ТабЗнач[ИдСообщ].СтатусСообщ) Тогда
		Если (СтатусСообщ <> Неопределено) И
			 (СтатусСообщ >= Проч.СТАТСООБЩ_ОК) И (СтатусСообщ <= Проч.СТАТСООБЩ_ОШИБКА) Тогда
			Сообщ.ТабЗнач[ИдСообщ].СтатусСообщ = СтатусСообщ;
		Иначе
			Сообщ.ТабЗнач[ИдСообщ].СтатусСообщ = Проч.СТАТСООБЩ_НЕОПРЕД;
		КонецЕсли;
		Сообщения_Обновить(Сообщ)
	КонецЕсли
	
КонецПроцедуры

// Возвращает текст сообщения с идентификатором ИдСообщ
//
// Параметры:
//  Сообщ - ссылка на объект
//  ИдСообщ - идентификатор сообщения (порядковый номер строки)
// Возврат:
//  Текст сообщения или Неопределено, если сообщение не найдено
//
Функция Сообщения_ПолучитьТекст(Сообщ, ИдСообщ) Экспорт
	
	Рез = Неопределено;
	Если (Сообщ.ТабЗнач <> Неопределено) И
		 (ИдСообщ <> Неопределено) И
		 (ИдСообщ >= 0) И (ИдСообщ < Сообщ.ТабЗнач.Количество()) Тогда
		Рез = Сообщ.ТабЗнач[ИдСообщ].ТекстСообщ
	КонецЕсли;
	 
	Возврат Рез
	
КонецФункции

// Устанавливает текст сообщения с идентификатором ИдСообщ
//
// Параметры:
//  Сообщ - ссылка на объект
//  ИдСообщ - идентификатор сообщения (порядковый номер строки)
//  ТекстСообщ - текст добавляемого сообщения;
//
Процедура Сообщения_УстановитьТекст(Сообщ, ИдСообщ, ТекстСообщ) Экспорт
	
	Если (Сообщ.ТабЗнач <> Неопределено) И
		 (ИдСообщ <> Неопределено) И
		 (ИдСообщ >= 0) И (ИдСообщ < Сообщ.ТабЗнач.Количество()) И
		 (ТекстСообщ <> Неопределено) И
		 (ТекстСообщ <> Сообщ.ТабЗнач[ИдСообщ].ТипСообщ) Тогда
		// Преобразовать текст
		Если Сообщ.ТабЗнач[ИдСообщ].ТипСообщ = Проч.ТИПСООБЩ_УРОВЕНЬ1 Тогда
			
		ИначеЕсли Сообщ.ТабЗнач[ИдСообщ].ТипСообщ = Проч.ТИПСООБЩ_УРОВЕНЬ2 Тогда
			ТекстСообщ = "  " + ТекстСообщ
		ИначеЕсли Сообщ.ТабЗнач[ИдСообщ].ТипСообщ = Проч.ТИПСООБЩ_УРОВЕНЬ3 Тогда
			ТекстСообщ = "    " + ТекстСообщ
		КонецЕсли;
		// Установить текст
		Сообщ.ТабЗнач[ИдСообщ].ТекстСообщ = ТекстСообщ;
		Сообщения_Обновить(Сообщ)
	КонецЕсли
	
КонецПроцедуры

// Возвращает комментарий к сообщению с идентификатором ИдСообщ
//
// Параметры:
//  Сообщ - ссылка на объект
//  ИдСообщ - идентификатор сообщения (порядковый номер строки)
// Возврат:
//  Комментарий сообщения или Неопределено, если сообщение не найдено
//
Функция Сообщения_ПолучитьКоммент(Сообщ, ИдСообщ) Экспорт
	
	Рез = Неопределено;
	Если (Сообщ.ТабЗнач <> Неопределено) И
		 (ИдСообщ <> Неопределено) И
		 (ИдСообщ >= 0) И (ИдСообщ < Сообщ.ТабЗнач.Количество()) Тогда
		Рез = Сообщ.ТабЗнач[ИдСообщ].КомментарийСообщ
	КонецЕсли;
	 
	Возврат Рез
	
КонецФункции

// Устанавливает комментарий к сообщению с идентификатором ИдСообщ
//
// Параметры:
//  Сообщ - ссылка на объект
//  ИдСообщ - идентификатор сообщения (порядковый номер строки)
//  КомментСообщ - комментарий к сообщению
//
Процедура Сообщения_УстановитьКоммент(Сообщ, ИдСообщ, КомментСообщ) Экспорт
	
	Если (Сообщ.ТабЗнач <> Неопределено) И
		 (ИдСообщ <> Неопределено) И
		 (ИдСообщ >= 0) И (ИдСообщ < Сообщ.ТабЗнач.Количество()) И
		 (КомментСообщ <> Сообщ.ТабЗнач[ИдСообщ].КомментарийСообщ) Тогда
		Сообщ.ТабЗнач[ИдСообщ].КомментарийСообщ = КомментСообщ;
		Сообщения_Обновить(Сообщ)
	КонецЕсли
	
КонецПроцедуры

// В зависимости от типа сообщения и статуса определяет цвет текста сообщения
//
// Параметры:
//  ТипСообщ - тип сообщения
//  СтатусСообщ - статус сообщения
// Возврат:
//  Цвет текста сообщения
//
Функция Сообщения_ЦветТекста(ТипСообщ, СтатусСообщ) Экспорт
	
	Рез = Неопределено;
	Если ТипСообщ = Проч.ТИПСООБЩ_УРОВЕНЬ1 Тогда
		Рез = WebЦвета.Черный
	ИначеЕсли ТипСообщ = Проч.ТИПСООБЩ_УРОВЕНЬ2 Тогда
		Рез = WebЦвета.Черный
	ИначеЕсли ТипСообщ = Проч.ТИПСООБЩ_УРОВЕНЬ3 Тогда
		Рез = WebЦвета.Черный
	КонецЕсли;
	
	Возврат Рез
	
КонецФункции

// В зависимости от типа сообщения и статуса определяет цвет текста комментария
//
// Параметры:
//  ТипСообщ - тип сообщения
//  СтатусСообщ - статус сообщения
// Возврат:
//  Цвет текста комментария
//
Функция Сообщения_ЦветКомментария(ТипСообщ, СтатусСообщ) Экспорт
	
	Рез = Неопределено;
	Если СтатусСообщ = Проч.СТАТСООБЩ_ОК Тогда
		Рез = WebЦвета.Зеленый
	ИначеЕсли СтатусСообщ = Проч.СТАТСООБЩ_ПРЕДУПР Тогда
		Рез = WebЦвета.Оранжевый
	ИначеЕсли СтатусСообщ = Проч.СТАТСООБЩ_ОШИБКА Тогда
		Рез = WebЦвета.Красный
	КонецЕсли;
	
	Возврат Рез
	
КонецФункции

// В зависимости от типа сообщения и статуса определяет картинку статуса сообщения
//
// Параметры:
//  ТипСообщ - тип сообщения
//  СтатусСообщ - статус сообщения
// Возврат:
//  Картинка статуса сообщения
//
Функция Сообщения_Картинка(ТипСообщ, СтатусСообщ) Экспорт
	
	Рез = Неопределено;
	Если СтатусСообщ = Проч.СТАТСООБЩ_ОК Тогда
		Рез = КоллекцияКартинок.СообщениеСтатусОК
	ИначеЕсли СтатусСообщ = Проч.СТАТСООБЩ_ПРЕДУПР Тогда
		Рез = КоллекцияКартинок.СообщениеСтатусПредупреждение
	ИначеЕсли СтатусСообщ = Проч.СТАТСООБЩ_ОШИБКА Тогда
		Рез = КоллекцияКартинок.СообщениеСтатусОшибка
	КонецЕсли;
	
	Возврат Рез

КонецФункции

// Запрашивает имя файла и сохраняет набор сообщений в текстовый файл
//
// Параметры:
//  Сообщ - ссылка на объект
// Возврат:
//  Истина, если сохранение выполнено и Ложь - в противном случае
//
Функция Сообщения_СохранитьВФайл(Сообщ) Экспорт
	
	Рез = Ложь;	// Еще ничего не сохранили
	
	Если Сообщ.ТабЗнач = Неопределено  Тогда
		// Неверные параметры
		Возврат Рез
	КонецЕсли;
	
	// Создать диалог и выбрать файл для сохранения
	ДиалогВыбораФайла								=	Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
	
	ДиалогВыбораФайла.Фильтр						=	"Текстовые файлы (*.txt)|*.txt" +
														"|Все файлы (*.*)|*.*";
	ДиалогВыбораФайла.Заголовок						=	"Сохранение сообщений";
	ДиалогВыбораФайла.МножественныйВыбор            =   Ложь;
	ДиалогВыбораФайла.ПредварительныйПросмотр		=	Ложь;
	ДиалогВыбораФайла.Расширение					=	"txt";
	ДиалогВыбораФайла.ИндексФильтра					=	0;
	ДиалогВыбораФайла.ПроверятьСуществованиеФайла	=	Истина;
	
	Если ДиалогВыбораФайла.Выбрать() Тогда
		// Выполнить сохранение
		Попытка
			// Открыть файл
			ЗаписьТекста = Новый ЗаписьТекста(ДиалогВыбораФайла.ПолноеИмяФайла, КодировкаТекста.ANSI);
			
			// Сформировать и записать в файл строки сообщений 
			// Выяснить максимальные длины строк в сообщениях
			ДлинаТекстаМакс = 0;
			ДлинаКомментМакс = 0;
			Для Каждого СтрокаТЗ Из Сообщ.ТабЗнач Цикл
				ДлинаТекстаТек = СтрДлина(СтрокаТЗ.ТекстСообщ);
				Если ДлинаТекстаТек > ДлинаТекстаМакс Тогда
					ДлинаТекстаМакс = ДлинаТекстаТек;
				КонецЕсли;
				ДлинаКомментТек = СтрДлина(СтрокаТЗ.КомментарийСообщ);
				Если ДлинаКомментТек > ДлинаКомментМакс Тогда
					ДлинаКомментМакс = ДлинаКомментТек;
				КонецЕсли;
			КонецЦикла;
			// Выполнить запись строк
			Для Каждого СтрокаТЗ Из Сообщ.ТабЗнач Цикл
				Дист = "  ";  // Разделитель элементов строки
				Стр = "";
				
				// Записать в строку статус сообщения
				Если (СтрокаТЗ.СтатусСообщ <> Неопределено) И
					 (СтрокаТЗ.СтатусСообщ <> Проч.СТАТСООБЩ_НЕОПРЕД) Тогда
					СтатусСтр = "";
					Если СтрокаТЗ.СтатусСообщ = Проч.СТАТСООБЩ_ОК Тогда
						СтатусСтр = "ОК";
					ИначеЕсли СтрокаТЗ.СтатусСообщ = Проч.СТАТСООБЩ_ПРЕДУПР Тогда
						СтатусСтр = "ПРЕДУПРЕЖДЕНИЕ";
					ИначеЕсли СтрокаТЗ.СтатусСообщ = Проч.СТАТСООБЩ_ОШИБКА Тогда
						СтатусСтр = "ОШИБКА";
					КонецЕсли;
					Если Стр <> "" Тогда
						Стр = Стр + Дист
					КонецЕсли;
					Стр = Стр + РасширСтрПрав(СтатусСтр, 14);
				КонецЕсли;
				// Записать в строку текст сообщения
				Если (СтрокаТЗ.ТекстСообщ <> Неопределено) И
					 (СтрокаТЗ.ТекстСообщ <> "") Тогда
					Если Стр <> "" Тогда
						Стр = Стр + Дист
					КонецЕсли;
					Стр = Стр + РасширСтрПрав(СтрокаТЗ.ТекстСообщ, ДлинаТекстаМакс);
				КонецЕсли;
				// Записать в строку текст комментария
				Если (СтрокаТЗ.КомментарийСообщ <> Неопределено) И
					 (СтрокаТЗ.КомментарийСообщ <> "") Тогда
					Если Стр <> "" Тогда
						Стр = Стр + Дист
					КонецЕсли;
					Стр = Стр + РасширСтрПрав(СтрокаТЗ.КомментарийСообщ, ДлинаКомментМакс);
				КонецЕсли;
				// Записать строку в файл
				Если Стр <> "" Тогда
					ЗаписьТекста.ЗаписатьСтроку(Стр)
				КонецЕсли
			КонецЦикла;
			
			// Закрыть файл
			ЗаписьТекста.Закрыть();
			
			Рез = Истина	// Операция выполнена успешно
		Исключение
			// Сообщение об ошибке
			Предупреждение("Ошибка сохранения сообщений:" + Символы.ПС +
							ИнформацияОбОшибке().Описание);
		КонецПопытки
	КонецЕсли;

	Возврат Рез
	
КонецФункции




////////////////////////////////////////////////////////////////////////////////
// ОПЕРАТОРЫ ОСНОВНОЙ ПРОГРАММЫ - НАЧАЛЬНАЯ ИНИЦИАЛИЗАЦИЯ



// ИНИЦИАЛИЗАЦИЯ КОНСТАНТ

// Константы общего назначения
Проч = ИнициализацияПрочихКонстант();

// Коллекция картинок
КоллекцияКартинок = СформироватьКоллекциюКартинок();



// ИНИЦИАЛИЗАЦИЯ ГЛОБАЛЬНЫХ ПЕРЕМЕННЫХ

// Создать машину JavaScript
JavaScript = СоздатьОбъектJavaScript();


Обратите внимание на то, что при выполнении длительного процесса в цикле, интерфейс пользователя блокируется, и поэтому факт добавления или изменения сообщений не будет виден пользователю – прорисовки не будет. Для принудительного выполнения прорисовки, нужно вызвать метод Обновить() формы, отображающей сообщения. Но частый вызов этого метода затормозит работу, поэтому вызывать его нужно лишь иногда (хоть и с небольшим интервалом, чтобы пользователь не заметил лагов – в данной реализации интервал обновления не чаще чем 1 раз в 0,5сек). Для реализации обновления служит метод класса Сообщения_Обновить.

Пример использования.


В данном примере форма, отображающая набор сообщений выглядит вот так:


Вместо кнопки «Запустить процесс», в реальности должно быть что-то более полезное – какой-то пользовательский интерфейс. Кнопка «Запустить процесс» имитирует заполнение списка сообщений, демонстрируя то, как могли бы выводиться сообщения в процессе реального выполнения какого-либо длительного действия.
В качестве реквизитов формы создана ТаблицаЗначений — «Сообщения». Мы ее никак не инициализируем, а просто передаем в качестве параметров соответствующим методам класса «Сообщения_», а они уже создают нужные колонки:
ОбъектСообщ = Сообщения_Конструктор();
Сообщения_УстАтриб(ОбъектСообщ, ЭтаФорма, ЭлементыФормы.ТабличноеПолеСообщения, Сообщения);
Сообщения_Инициализация(ОбъектСообщ);


Для отображения ТаблицыЗначений «Сообщения», на форме размещен визуальный компонент типа «ТабличноеПоле» — «ТабличноеПолеСообщения». При создании колонок в ТабличномПоле, учитываем следующие колонки ТаблицыЗначений (описывались ранее):
ТипСообщ;
СтатусСообщ;
ТекстСообщ;
КомментарийСообщ.

Текст модуля главной формы обработки (отображающей сообщения):
Текст модуля формы
////////////////////////////////////////////////////////////////////////////////
// ОСНОВНОЕ ОКНО ПРОГРАММЫ

Перем ОбъектСообщ;          // Объект для вывода сообщений в таблицу знач. и отобр. в табл. поле


////////////////////////////////////////////////////////////////////////////////
// ОБРАБОТЧИКИ СОБЫТИЙ ФОРМЫ

// Процедура - обработчик события "При открытии" формы. Данное событие
// возникает при открытии формы, до показа окна пользователю.
//
// Параметры:
//  Нет.
//
Процедура ПриОткрытии()
	
	// Создание объекта сообщений и инициализация таблицы сообщений
	ОбъектСообщ = Сообщения_Конструктор();
	Сообщения_УстАтриб(ОбъектСообщ, ЭтаФорма, ЭлементыФормы.ТабличноеПолеСообщения, Сообщения);
	Сообщения_Инициализация(ОбъектСообщ);
	
КонецПроцедуры

// Процедура - обработчик события "При закрытии" формы. Данное событие
// возникает после закрытия формы.
// Освобождение занятых ресурсов.
//
// Параметры:
//  Нет.
//
Процедура ПриЗакрытии()
	
	// Завершить работу с объектом вывода сообщений
	Сообщения_Деструктор(ОбъектСообщ)
	
КонецПроцедуры


// Процедура - обработчик события "Нажатие" кнопки КнопкаЗапуститьПроцесс.
// Имитирует операцию, в процессе выполнения которой выводятся сообщения.
//
// Параметры:
//  Элемент - кнопка.
//
Процедура КнопкаЗапуститьПроцессНажатие(Элемент)
	
	// Подготовка данных к началу операции
	ГСЧ = Новый ГенераторСлучайныхЧисел();
    ВсегоОбъектов = ГСЧ.СлучайноеЧисло(1, 100);
	// Запросить согласие пользователя на выполнение операции
	РезВопр = Вопрос("Выполнить обработку данных?",
			 		 РежимДиалогаВопрос.ДаНет,
				 	 ,
					 ,
				 	 "Обработка данных");
	Если РезВопр = КодВозвратаДиалога.Да Тогда
		// Подготовка интерфейса к запуску процесса
		ErrMsg = "";
		Сообщения_Очистить(ОбъектСообщ);
		// Сообщение о начале операции
		Сообщения_Добавить(ОбъектСообщ, Проч.ТИПСООБЩ_УРОВЕНЬ1, "*** НАЧАЛО ОБРАБОТКИ ДАННЫХ ***");
		Рез = Ложь;
		КолОбрОб = 0;
		Попытка
			// Выполнять обработку объектов
			Для Инд=1 По ВсегоОбъектов Цикл
				// Вывести сообщение о том, что началась обработка очередного объекта
				ИдСообщУр2 = Сообщения_Добавить(ОбъектСообщ, Проч.ТИПСООБЩ_УРОВЕНЬ2, "Обработка объекта " + Формат(Инд, "ЧГ=0; ЧН=''"));
				
				// ******************************
				// Здесь собственно выполняется сама операция над текущим объектом
				Если ГСЧ.СлучайноеЧисло(0, ВсегоОбъектов) > 0 Тогда
					// Считаем, что операция над текущим объектом выполнена успешно
					Рез = Истина
				Иначе
					// Считаем, что операция над текущим объектом выполнена с ошибкой
					Рез = Ложь
				КонецЕсли;
				// ******************************
				
				// Установить результат операции над текущим объектом в окне сообщений
				СтатСообщ = Проч.СТАТСООБЩ_НЕОПРЕД;
				КоммСообщ = "";
				Если Рез Тогда
					// Операция завершена удачно
					СтатСообщ = Проч.СТАТСООБЩ_ОК;
					КоммСообщ = "ОК"
				Иначе
					// Ошибки при выполнении операции
					СтатСообщ = Проч.СТАТСООБЩ_ОШИБКА;
					КоммСообщ = "ОШИБКА"
				КонецЕсли;
				Сообщения_Изменить(ОбъектСообщ, ИдСообщУр2, , , СтатСообщ, КоммСообщ);
								   
				// Анализируем результат текущей итерации														  
				Если НЕ Рез Тогда
					// Ошибка - прервать работу
					Прервать
				КонецЕсли;
				КолОбрОб = КолОбрОб + 1
			КонецЦикла
		Исключение
			// Возникло исключение - ошибка
			ErrMsg = ИнформацияОбОшибке().Описание;
			Рез = Ложь
		КонецПопытки;
		// Сообщение об окончании операции
		Если Рез Тогда
			// Операция завершена успешно
			Сообщения_Добавить(ОбъектСообщ, Проч.ТИПСООБЩ_УРОВЕНЬ1, "*** ОБРАБОТКА ДАННЫХ ЗАВЕРШЕНА ***");
		Иначе
			// Операция прервана
			Сообщения_Добавить(ОбъектСообщ, Проч.ТИПСООБЩ_УРОВЕНЬ1, "*** ОБРАБОТКА ДАННЫХ ПРЕРВАНА ***", Проч.СТАТСООБЩ_ОШИБКА, ErrMsg)
		КонецЕсли;
    	// Установка интерфейса по окончанию загрузки
		ТекстСообщ = "";
		Если Рез Тогда
			ТекстСообщ = "Обработка выполнена успешно"
		Иначе
			ТекстСообщ = "Обработка выполнена с ошибками"
		КонецЕсли;
		ТекстСообщ = ТекстСообщ + Символы.ПС;
		ТекстСообщ = ТекстСообщ + "Обработано " + Формат(КолОбрОб, "ЧГ=0; ЧН=''") + " объектов.";
		Предупреждение(ТекстСообщ, , "Обработка данных")
	КонецЕсли
КонецПроцедуры

// Процедура - обработчик события "ПриВыводеСтроки" табличного поля
// ТабличноеПолеСообщения. Данное событие происходит при выводе каждой строки.
//
// Параметры:
//  Элемент - табличное поле;
//  ОформлениеСтроки - объект настройки визуального оформления строки
//  ДанныеСтроки - набор данных строки табличного поля.
//
Процедура ТабличноеПолеСообщенияПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
	
	// Оформление ячейки "Статус"
	ОформлениеСтроки.Ячейки.КолонкаСтатусСообщения.ОтображатьТекст = Ложь;
	КартинкаСтатуса = Сообщения_Картинка(ДанныеСтроки.ТипСообщ, ДанныеСтроки.СтатусСообщ);
	Если КартинкаСтатуса <> Неопределено Тогда
		ОформлениеСтроки.Ячейки.КолонкаСтатусСообщения.ОтображатьКартинку = Истина;
		ОформлениеСтроки.Ячейки.КолонкаСтатусСообщения.Картинка = КартинкаСтатуса;
	КонецЕсли;
	// Оформление ячейки "Текст"
	Если (ДанныеСтроки.ТекстСообщ <> Неопределено) И
		 (ДанныеСтроки.ТекстСообщ <> "") Тогда
		ЦветТекста = Сообщения_ЦветТекста(ДанныеСтроки.ТипСообщ, ДанныеСтроки.СтатусСообщ);
		Если ЦветТекста <> Неопределено Тогда
			ОформлениеСтроки.Ячейки.КолонкаТекстСообщения.ЦветТекста = ЦветТекста
		КонецЕсли
	КонецЕсли;
	// Оформление ячейки "Комментарий"
	Если (ДанныеСтроки.КомментарийСообщ <> Неопределено) И
		 (ДанныеСтроки.КомментарийСообщ <> "") Тогда
		ЦветКомментария = Сообщения_ЦветКомментария(ДанныеСтроки.ТипСообщ, ДанныеСтроки.СтатусСообщ);
		Если ЦветКомментария <> Неопределено Тогда
			ОформлениеСтроки.Ячейки.КолонкаКомментарийСообщения.ЦветТекста = ЦветКомментария
		КонецЕсли
	КонецЕсли
	
КонецПроцедуры

// Процедура - обработчик события "Нажатие" кнопки КнопкаСообщенияОткрытьВНовомОкне.
// Открывает текущий список сообщений в новом окне.
//
// Параметры:
//  Элемент - кнопка.
//
Процедура КнопкаСообщенияОткрытьВНовомОкнеНажатие(Элемент)

	ФормаПросмотраСообщений = ЭтотОбъект.ПолучитьФорму("ФормаПросмотраСообщений", ЭтаФорма);
	ФормаПросмотраСообщений.ShowMessagesDlg(ОбъектСообщ)
	
КонецПроцедуры

// Процедура - обработчик события "Нажатие" кнопки КнопкаСообщенияСохранить.
// Сохранить текущий набор сообщений в файл.
//
// Параметры:
//  Элемент - кнопка.
//
Процедура КнопкаСообщенияСохранитьНажатие(Элемент)

	Сообщения_СохранитьВФайл(ОбъектСообщ);
	
КонецПроцедуры


Форма просмотра сообщений.


Также имеется отдельное окно просмотра списка сообщений (соответствующей ТаблицыЗначений). Оно предназначено для того, чтобы можно было более удобно проанализировать большой список (так как в основном диалоговом окне ТабличноеПоле сообщений сильно растянуть по высоте не удастся – будет мешать другие элементы интерфейса).

Выглядит форма примерно следующим образом:


Код модуля формы совсем несложный. Вот такой:
Текст модуля формы
////////////////////////////////////////////////////////////////////////////////
// ДИАЛОГ ДЛЯ ОТОБРАЖЕНИЯ СПИСКА СООБЩЕНИЙ В ОТДЕЛЬНОМ ОКНЕ

Перем ОбъектСообщ;      // Объект для работы с сообщениями



////////////////////////////////////////////////////////////////////////////////
// ОБРАБОТЧИКИ СОБЫТИЙ ФОРМЫ

// Процедура - обработчик события "Действие" элемента меню КоманднаяПанельМенюСохранитьВФайл.
// Сохранить текущий набор сообщений в файл.
//
// Параметры:
//  Кнопка - элемент меню.
//
Процедура КоманднаяПанельМенюСохранитьВФайл(Кнопка)
	
	Сообщения_СохранитьВФайл(ОбъектСообщ);

КонецПроцедуры

// Процедура - обработчик события "ПриВыводеСтроки" табличного поля
// ТабличноеПолеСообщения. Данное событие происходит при выводе каждой строки.
//
// Параметры:
//  Элемент - табличное поле;
//  ОформлениеСтроки - объект настройки визуального оформления строки
//  ДанныеСтроки - набор данных строки табличного поля.
//
Процедура ТабличноеПолеСообщенияПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
	
	// Оформление ячейки "Статус"
	ОформлениеСтроки.Ячейки.КолонкаСтатусСообщения.ОтображатьТекст = Ложь;
	КартинкаСтатуса = Сообщения_Картинка(ДанныеСтроки.ТипСообщ, ДанныеСтроки.СтатусСообщ);
	Если КартинкаСтатуса <> Неопределено Тогда
		ОформлениеСтроки.Ячейки.КолонкаСтатусСообщения.ОтображатьКартинку = Истина;
		ОформлениеСтроки.Ячейки.КолонкаСтатусСообщения.Картинка = КартинкаСтатуса;
	КонецЕсли;
	// Оформление ячейки "Текст"
	Если (ДанныеСтроки.ТекстСообщ <> Неопределено) И
		 (ДанныеСтроки.ТекстСообщ <> "") Тогда
		ЦветТекста = Сообщения_ЦветТекста(ДанныеСтроки.ТипСообщ, ДанныеСтроки.СтатусСообщ);
		Если ЦветТекста <> Неопределено Тогда
			ОформлениеСтроки.Ячейки.КолонкаТекстСообщения.ЦветТекста = ЦветТекста
		КонецЕсли
	КонецЕсли;
	// Оформление ячейки "Комментарий"
	Если (ДанныеСтроки.КомментарийСообщ <> Неопределено) И
		 (ДанныеСтроки.КомментарийСообщ <> "") Тогда
		ЦветКомментария = Сообщения_ЦветКомментария(ДанныеСтроки.ТипСообщ, ДанныеСтроки.СтатусСообщ);
		Если ЦветКомментария <> Неопределено Тогда
			ОформлениеСтроки.Ячейки.КолонкаКомментарийСообщения.ЦветТекста = ЦветКомментария
		КонецЕсли
	КонецЕсли
	
КонецПроцедуры


////////////////////////////////////////////////////////////////////////////////
// ПОДПРОГРАММЫ ВНЕШНЕГО ИНТЕРФЕЙСА


// Вызов диалога просмотра списка сообщений
//
// Параметры:
//  ОбъектСообщения - объект для работы с сообщениями.
//
Процедура ShowMessagesDlg(ОбъектСообщений) Экспорт;

	Если ОбъектСообщений <> Неопределено Тогда
		// Выполнить начальную установку параметров
		ОбъектСообщ = ОбъектСообщений;
		ЭлементыФормы.ТабличноеПолеСообщения.Значение = ОбъектСообщ.ТабЗнач;
		// Вызвать диалог
		ЭтаФорма.ОткрытьМодально()
	КонецЕсли
	
КонецПроцедуры


Скачать исходные тексты подсистемы сообщений и рассмотренный пример (обработка для 1С 8.2) можно здесь.

На этом все. Всем удачи. До встречи.

P.S.

В следующей статье я планирую рассказать о работе с сервером (базами) FireBird из 1С.
Мы выясним:
— как корректно подключаться к серверу (базе) и отключаться;
— как выполнять запросы: передавать и получать данные;
— как работать с бинарными полями и строками в различной кодировке;
— как вызывать хранимые процедуры и получать результаты их работы;
— как обойти такую неприятность, как автоматический разрыв клиентского соединения со стороны сервера FireBird (простой и понятный способ, который почему-то нигде не описан в Интернете).

Мы создадим обособленные и переносимые наборы подпрограмм («классов»):
— для подключения к базе (сможем подключаться к серверу, базе и выполнять запросы);
— для работы с параметрами запроса (можно будет задавать и устанавливать параметры почти как в Delphi);
А также:
— для работы с множествами целых чисел и строк (удобно задавать множественные параметры для запросов);
— удобное хранилище профилей подключений к различным базам FireBird, а также интерфейс пользователя (форма для редактирования набора профилей подключений)

В общем, думаю, что будет интересно. Еще раз, удачи…
Tags:
Hubs:
+5
Comments 3
Comments Comments 3

Articles