//////////////////////////////////////////////////////////////////////////////////
//
// Модуль Динамического Формирования Информера
// Начало разработки 01.08.2022 года
//
// Автор и разработчик: Котов Дмитрий Вадимович
// GIT: https://github.com/KotovDima1C
// Инфостарт: //infostart.ru/profile/564942/
// telegram: @KotovDima
//
// Алгоритм формирования информера:
// 1. Элемент формы оборачивается в Обычную группу, с горизонтальной группировкой
// 2. Добавляется всплывающая группа
// 3. В всплывающую группу добавляются необходимые элементы формы для создания псевдо подсказки
// при желание можно добавить хоть поле HTML
//
// !!!Требования для работы наличия Библиотеки ДФИ, скачать можно здесь: https://github.com/KotovDima1C/DFI
//
//////////////////////////////////////////////////////////////////////////////////
#Область ФормированиеИнформера
// Параметры:
// Форма - ФормаКлиентскогоПриложения - Форма на которой создаются элементы
// Элемент - Строка - достаточно указать название элемента формы
// - Элементы - но иожно передать элемент формы
// СвойстваИнформера - Структура - Перечень требуемых настроек информера:
//
//
Процедура СформироватьИнформер(Форма, Элемент, СвойстваИнформера) Экспорт
ПроверитьСвойстваИнформера(СвойстваИнформера);
ОпределитьЗначенияПоУмолчанию(СвойстваИнформера);
ОпределитьРеквизитСозданныхЭлементов(Форма);
ОпределитьЭлементФормы(Форма, Элемент);
ШифрИмениЭлементов = ПолучитьШифрИмениЭлементов(Элемент);
ДобавитьШифрИмениЭлементовВСписок(Форма, ШифрИмениЭлементов);
ИнформерНайден = ПроверитьНаличиеИнформера(Форма, ШифрИмениЭлементов);
// Если ранее уже создали группу элементов, то следует её сделать видимой
Если ИнформерНайден <> Неопределено Тогда
УстановитьЦветАкцента(Элемент,СвойстваИнформера.ЦветАкцента);
УправлениеВидимостьюИнформера(Форма, ШифрИмениЭлементов, ИСТИНА);
// Если нету группы, создаем новые элементы
Иначе
СформироватьЭлементы(Форма, Элемент, ШифрИмениЭлементов, СвойстваИнформера);
КонецЕсли;
УстановитьЗаголовокИнформера(Форма, ШифрИмениЭлементов, СвойстваИнформера.ЗаголовокИнформера);
УстановитьТекстИнформера(Форма, ШифрИмениЭлементов,СвойстваИнформера.ТекстИнформера);
ЭлементИнформера = ПолучитьИмяГруппыИнформера(ШифрИмениЭлементов);
ОпределитьЭлементФормы(Форма, ЭлементИнформера);
ЭлементИнформера.Показать();
КонецПроцедуры
Процедура ПроверитьНеобходимостьСкрытьИнформеры(Форма) Экспорт
ИмяРеквизита = ПолучитьИмяРеквизитаСозданныхИнформеров();
Для Каждого текЭлемент Из Форма[ИмяРеквизита] Цикл
СкрытьИнформер(Форма,,текЭлемент.Значение);
КонецЦикла;
КонецПроцедуры
Процедура СкрытьИнформер(Форма, Элемент = Неопределено, ШифрИмениЭлементов = "") Экспорт
Если ШифрИмениЭлементов = "" И Элемент <> Неопределено Тогда
Возврат;
ИначеЕсли ШифрИмениЭлементов = "" Тогда
ШифрИмениЭлементов = ПолучитьШифрИмениЭлементов(Элемент);
КонецЕсли;
УправлениеВидимостьюИнформера(Форма, ШифрИмениЭлементов, ЛОЖЬ);
ВосстановитьЦветАкцента(Форма, ШифрИмениЭлементов);
КонецПроцедуры
#Область ВспомогательныеФункции
Процедура СформироватьЭлементы(Форма, Элемент, ШифрИмениЭлементов, СвойстваИнформера)
УстановитьЦветАкцента(Элемент, СвойстваИнформера.ЦветАкцента);
ЭлементПеред = ОпределитьЭлементПеред(Форма, Элемент);
ЭлементРодитель = ПолучитьИмяРодителяЭлемента(Элемент);
ИмяГруппыОбертка = ПолучитьИмяГруппыОбертки(ШифрИмениЭлементов);
ГруппаОбертка = кот_ДФИ.СздГруппаОбычнаяБезОтображения(Форма,ИмяГруппыОбертка,ЭлементРодитель,3,,,,ЭлементПеред);
Форма.Элементы.Переместить(Элемент,ГруппаОбертка);
// Способ отображения информера
ЭлементПеред = Неопределено;
ЗаголовокИнформера = "i";
ОпределитьСпособОтображения(Форма,СвойстваИнформера.СпособОтображения,Элемент,ЭлементПеред,ЗаголовокИнформера);
СвойстваГруппыИнформеры = Новый Структура;
СвойстваГруппыИнформеры.Вставить("Поведение", ПоведениеОбычнойГруппы.Всплывающая);
СвойстваГруппыИнформеры.Вставить("ЦветФона", СвойстваИнформера.ЦветФона);
Если НЕ (СвойстваИнформера.ЦветАкцента = "" ИЛИ СвойстваИнформера.ЦветАкцента = Неопределено) Тогда
СвойстваГруппыИнформеры.Вставить("ЦветТекстаЗаголовка", СвойстваИнформера.ЦветАкцента);
КонецЕсли;
ИмяГруппыИнформера = ПолучитьИмяГруппыИнформера(ШифрИмениЭлементов);
ГруппаИнформер = кот_ДФИ.СздГруппаОбычная(Форма,ИмяГруппыИнформера,ГруппаОбертка,ЗаголовокИнформера,1,2,2,СвойстваГруппыИнформеры,ЭлементПеред);
ИмяГруппыШапки = ИмяГруппыИнформера + "Шапка";
ГруппаШапка = кот_ДФИ.СздГруппаОбычнаяБезОтображения(Форма,ИмяГруппыШапки,ГруппаИнформер,3,2,2);
ИмяДекорации = ИмяГруппыИнформера + "Картинка";
кот_ДФИ.СздДекорацияКартинка(Форма,ИмяДекорации,ГруппаШапка,"Информация");
ИмяЗаголовок = ПолучитьИмяНадписиЗаголовка(ШифрИмениЭлементов);
кот_ДФИ.СздДекорацияНадпись(Форма,ИмяЗаголовок,ГруппаШапка,"Информация",ЛОЖЬ);
ИмяТекст = ПолучитьИмяНадписиТекст(ШифрИмениЭлементов);
кот_ДФИ.СздДекорацияНадпись(Форма,ИмяТекст,ГруппаИнформер,"Текст информации",ЛОЖЬ);
КонецПроцедуры
Функция СформироватьЦветСтиля(ЦветRGB)
ЦветRGB = СтрЗаменить(ЦветRGB," ","");
Разделитель1 = Найти(ЦветRGB, ",");
R = Лев(ЦветRGB, Разделитель1-1);
GB = Прав(ЦветRGB, СтрДлина(ЦветRGB)-Разделитель1);
Разделитель2 = Найти(GB, ",");
G = Лев(GB, Разделитель2-1);
B = Прав(GB, СтрДлина(GB) - Разделитель2);
СтильЦвет = Новый Цвет(R,G,B);
Возврат СтильЦвет;
КонецФункции
// Функция возвращает элемент перед которым находится искомый элемент, добавлю позже её в библиотеку ДФИ
Функция ОпределитьЭлементПеред(Форма, Элемент)
ЭлементРодитель = ПолучитьИмяРодителяЭлемента(Элемент);
ОпределитьЭлементФормы(Форма, ЭлементРодитель);
ЭлементПослеНайден = ЛОЖЬ;
ЭлементПосле = Неопределено;
Для Каждого текЭлемент Из ЭлементРодитель.ПодчиненныеЭлементы Цикл
Если ЭлементПослеНайден = ИСТИНА Тогда
ЭлементПосле = текЭлемент;
Прервать;
КонецЕсли;
Если Элемент = текЭлемент Тогда
ЭлементПослеНайден = ИСТИНА;
КонецЕсли;
КонецЦикла;
Возврат ЭлементПосле;
КонецФункции
Процедура ОпределитьЭлементФормы(Форма, Элемент)
Если ТипЗнч(Элемент) = Тип("Строка") Тогда
Элемент = Форма.Элементы[Элемент];
КонецЕсли;
КонецПроцедуры
Процедура ОпределитьЦветФонаПоУмолчанию(ЦветФона)
Если ЦветФона = Неопределено ИЛИ ЦветФона = "" Тогда
ЦветФона = ЦветаСтиля.ЦветФонаПодсказки;
ИначеЕсли ТипЗнч(ЦветФона) = Тип("Строка") Тогда
ЦветФона = ОпределитьЦвет(ЦветФона);
КонецЕсли;
КонецПроцедуры
Процедура ОпределитьЦветАкцентаПоУмолчанию(ЦветРамки)
Если ЦветРамки = Неопределено ИЛИ ЦветРамки = "" Тогда
ЦветРамки = ЦветаСтиля.ЦветАкцента;
ИначеЕсли ТипЗнч(ЦветРамки) = Тип("Строка") Тогда
ЦветРамки = ОпределитьЦвет(ЦветРамки);
КонецЕсли;
КонецПроцедуры
Процедура ОпределитьРеквизитСозданныхЭлементов(Форма)
ИмяРеквизита = ПолучитьИмяРеквизитаСозданныхИнформеров();
РеквизитСоздан = ЕстьРеквизитИлиСвойствоОбъекта(Форма,ИмяРеквизита);
Если РеквизитСоздан = ЛОЖЬ Тогда
кот_ДФИ.СоздатьРеквизит(Форма,ИмяРеквизита,Новый ОписаниеТипов("СписокЗначений"));
КонецЕсли;
КонецПроцедуры
Процедура ОпределитьЗначенияПоУмолчанию(СвойстваИнформера)
ОпределитьЗаголовокПоУмолчанию(СвойстваИнформера.ЗаголовокИнформера);
ОпределитьТекстПоУмолчанию(СвойстваИнформера.ТекстИнформера);
ОпределитьЦветФонаПоУмолчанию(СвойстваИнформера.ЦветФона);
ОпределитьЦветАкцентаПоУмолчанию(СвойстваИнформера.ЦветАкцента);
ОпределитьСпособОтображенияПоУмолчанию(СвойстваИнформера.СпособОтображения);
КонецПроцедуры
Процедура ОпределитьСпособОтображенияПоУмолчанию(СпособОтображения)
Если СпособОтображения = 0 или СпособОтображения = Неопределено Тогда
СпособОтображения = 1;
КонецЕсли;
КонецПроцедуры
Процедура ОпределитьЗаголовокПоУмолчанию(ЗаголовокИнформера)
Если ЗаголовокИнформера = "" ИЛИ ЗаголовокИнформера = Неопределено Тогда
ЗаголовокИнформера = "Информация";
КонецЕсли;
КонецПроцедуры
Процедура ОпределитьТекстПоУмолчанию(ТекстИнформера)
Если ТекстИнформера = "" ИЛИ ТекстИнформера = Неопределено Тогда
ТекстИнформера = "Обратите внимание на данный реквизит";
КонецЕсли;
КонецПроцедуры
Процедура ОпределитьСпособОтображения(Форма,СпособОтображения,Элемент,ЭлементПеред,ЗаголовокИнформера)
// Способ отображения 1 - Выводить после реквизита Информер с заголовком "i"
// Способ отображения 2 - Выводить перед реквизитом, вместо заголовка слева
Если СпособОтображения = 2 И (Элемент.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Лево ИЛИ Элемент.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Авто) Тогда
ЗаголовокИнформера = ПолучитьЗаголовокЭлементаФормы(Форма,Элемент);
Элемент.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Нет;
Элемент.Заголовок = ПолучитьШифрИмениЭлементов(Элемент);
ЭлементПеред = Элемент;
КонецЕсли;
КонецПроцедуры
Функция ОпределитьЦвет(тЦвет)
Если ТипЗнч(тЦвет) = Тип("Строка") Тогда
тЦвет = СформироватьЦветСтиля(тЦвет)
Иначе
тЦвет = Неопределено;
КонецЕсли;
Возврат тЦвет;
КонецФункции
Процедура ДобавитьШифрИмениЭлементовВСписок(Форма, ШифрИмениЭлементов)
ИмяРеквизита = ПолучитьИмяРеквизитаСозданныхИнформеров();
Форма[ИмяРеквизита].Добавить(ШифрИмениЭлементов);
КонецПроцедуры
Процедура ВосстановитьЦветАкцента(Форма, ШифрИмениЭлементов)
Элемент = ПолучитьИмяЭлемента(ШифрИмениЭлементов);
ОпределитьЭлементФормы(Форма, Элемент);
Элемент.ЦветРамки = Новый Цвет();
КонецПроцедуры
// Подробнее о функции и назначение написанно в моей статье - //infostart.ru/1c/articles/1112550/
Функция ПолучитьЦветПоЦветуСтиля(ЦветСтиля) Экспорт
ТекстХТМЛДокумента = "";
ФорматированныйДокумент = Новый ФорматированныйДокумент;
ФорматированныйДокумент.Добавить("ОпределениеЦвета", Тип("ТекстФорматированногоДокумента"));
ФорматированныйДокумент.Элементы[0].Элементы[0].ЦветФона = ЦветСтиля; //Не устанавливается хз почему, но если убрать, то и в ЦветТекста не встанет
ФорматированныйДокумент.Элементы[0].Элементы[0].ЦветТекста = ЦветСтиля; //Устанавливается :)
ФорматированныйДокумент.ПолучитьHTML(ТекстХТМЛДокумента, Новый Структура);
ФорматированныйДокумент.УстановитьHTML(ТекстХТМЛДокумента, Новый Структура);
Возврат ФорматированныйДокумент.Элементы[0].Элементы[0].ЦветТекста;
КонецФункции
// TODO Надо поправить получение заголовка если это будет Объект или путь через точку
Функция ПолучитьЗаголовокЭлементаФормы(Объект,Элемент)
ЗаголовокЭлемента = Элемент.Заголовок;
ПутьКДаннымЭлемента = Элемент.ПутьКДанным; // todo
Если ЗаголовокЭлемента = "" Тогда
//ЗаголовокЭлемента = Форма[Элемент.ПутьКДанным].Заголовок;
МассивРеквизитов = Объект.ПолучитьРеквизиты();
Для Каждого текЭлемент Из МассивРеквизитов Цикл
Если текЭлемент.Имя = ПутьКДаннымЭлемента Тогда
ЗаголовокЭлемента = текЭлемент.Заголовок;
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если ЗаголовокЭлемента = "" Тогда
ЗаголовокЭлемента = ПутьКДаннымЭлемента;
КонецЕсли;
Возврат ЗаголовокЭлемента + ":";
КонецФункции
Функция ПолучитьИмяРодителяЭлемента(Элемент)
Возврат Элемент.Родитель.Имя;
КонецФункции
Функция ПолучитьИмяГруппыИнформера(ШифрИмениЭлементов)
Возврат ШифрИмениЭлементов + "Группа";
КонецФункции
Функция ПолучитьИмяГруппыОбертки(ШифрИмениЭлементов)
Возврат ШифрИмениЭлементов + "Обертка";
КонецФункции
Функция ПолучитьИмяНадписиЗаголовка(ШифрИмениЭлементов)
Возврат ШифрИмениЭлементов + "Заголовок";
КонецФункции
Функция ПолучитьИмяНадписиТекст(ШифрИмениЭлементов)
Возврат ШифрИмениЭлементов + "Текст";
КонецФункции
Функция ПолучитьИмяРеквизитаСозданныхИнформеров()
Возврат ПолучитьПрефиксШифра() + "СоданныеРеквизиты";
КонецФункции
Функция ПолучитьПрефиксШифра()
Возврат "ФормированиеИнформера";
КонецФункции
Функция ПолучитьИмяЭлемента(ШифрИмениЭлементов)
ИмяПрефикса = ПолучитьПрефиксШифра();
ИмяЭлемента = СтрЗаменить(ШифрИмениЭлементов,ИмяПрефикса,"");
Возврат ИмяЭлемента;
КонецФункции
Функция ПолучитьШифрИмениЭлементов(Элемент)
Возврат ПолучитьПрефиксШифра() + Элемент.Имя;
КонецФункции
Функция ПолучитьПараметрыСвойствИнформера() Экспорт
НаборПараметров = "ЗаголовокИнформера, ТекстИнформера, ЦветФона, ЦветАкцента, СпособОтображения";
МассивПараметров = СтрРазделить(НаборПараметров,",",ЛОЖЬ);
Возврат МассивПараметров;
КонецФункции
Функция ПолучитьПараметрыСвойствИнформераНеобязательные()
НаборПараметров = "ЗаголовокИнформера, ТекстИнформера, ЦветФона, ЦветАкцента, СпособОтображения";
МассивПараметров = СтрРазделить(НаборПараметров,",",ЛОЖЬ);
Возврат МассивПараметров;
КонецФункции
Процедура УстановитьЦветАкцента(Элемент, ЦветАкцента)
Элемент.ЦветРамки = ЦветАкцента;
КонецПроцедуры
Процедура УстановитьЗаголовокИнформера(Форма, ШифрИмениЭлементов, ЗаголовокИнформера)
ЭлементЗаголовка = ПолучитьИмяНадписиЗаголовка(ШифрИмениЭлементов);
ОпределитьЭлементФормы(Форма, ЭлементЗаголовка);
ЭлементЗаголовка.Заголовок = ЗаголовокИнформера;
КонецПроцедуры
Процедура УстановитьТекстИнформера(Форма, ШифрИмениЭлементов, ТекстИнформера)
ЭлементТекста = ПолучитьИмяНадписиТекст(ШифрИмениЭлементов);
ОпределитьЭлементФормы(Форма, ЭлементТекста);
ЭлементТекста.Заголовок = ТекстИнформера;
КонецПроцедуры
Процедура УправлениеВидимостьюИнформера(Форма, ШифрИмениЭлементов,СостояниеВидимости)
Перем Заголовок;
// Отображенние информера
ЭлементИнформера = ПолучитьИмяГруппыИнформера(ШифрИмениЭлементов);
ОпределитьЭлементФормы(Форма, ЭлементИнформера);
ЭлементИнформера.Видимость = СостояниеВидимости;
// Обработка Способа отображения = 2, возращаем заголовок
Элемент = СтрЗаменить(ШифрИмениЭлементов,ПолучитьПрефиксШифра(),"");
ОпределитьЭлементФормы(Форма,Элемент);
Если СостояниеВидимости = ЛОЖЬ И Элемент.Заголовок = ШифрИмениЭлементов Тогда
Заголовок = ЭлементИнформера.Заголовок;
ЭлементИнформера.Заголовок = ШифрИмениЭлементов;
Элемент.Заголовок = Заголовок;
Элемент.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Нет;
ИначеЕсли СостояниеВидимости = ИСТИНА И ЭлементИнформера.Заголовок = ШифрИмениЭлементов Тогда
Заголовок = Элемент.Заголовок;
Элемент.Заголовок = ШифрИмениЭлементов;
ЭлементИнформера.Заголовок = Заголовок;
Элемент.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Лево;
КонецЕсли;
КонецПроцедуры
Функция ПроверитьНаличиеИнформера(Форма, ШифрИмениЭлементов)
Возврат Форма.Элементы.Найти(ПолучитьИмяГруппыОбертки(ШифрИмениЭлементов));
КонецФункции
Процедура ПроверитьСвойстваИнформера(СвойстваИнформера)
// Добавляем все необязательные к заполнению свойства, если они не были указаны
НеобязательныеПараметры = ПолучитьПараметрыСвойствИнформераНеобязательные();
Для Каждого текЭлемент Из НеобязательныеПараметры Цикл
Если СвойстваИнформера.Свойство(текЭлемент) = ЛОЖЬ Тогда
СвойстваИнформера.Вставить(текЭлемент,Неопределено);
КонецЕсли;
КонецЦикла;
// Проверяем обязательные свойства
ВсеПараметры = ПолучитьПараметрыСвойствИнформера();
ОтсутствующиеПараметры = "";
Для Каждого текЭлемент Из ВсеПараметры Цикл
Если СвойстваИнформера.Свойство(текЭлемент) = ЛОЖЬ Тогда
ОтсутствующиеПараметры = ОтсутствующиеПараметры + ?(ОтсутствующиеПараметры = "","",", ") + текЭлемент;
КонецЕсли;
КонецЦикла;
Если ОтсутствующиеПараметры <> "" Тогда
ТекстОшибки = "Отсутствуют параметры в структуре свойств Информера:" + Символы.ПС + ОтсутствующиеПараметры;
Попытка
ВызватьИсключение ТекстОшибки;
Исключение
ЗаписьЖурналаРегистрации("Динамическое формирование Информера",УровеньЖурналаРегистрации.Ошибка,,,ТекстОшибки);
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Функция ЕстьРеквизитИлиСвойствоОбъекта(Объект, ИмяРеквизита) Экспорт
Попытка
Проверка = Объект[ИмяРеквизита];
ЕстьРеквизит = Истина;
Исключение
ЕстьРеквизит = Ложь;
КонецПопытки;
Возврат ЕстьРеквизит;
КонецФункции
#КонецОбласти
#КонецОбласти