v8: Полный парсинг для глобальной обработки событий (ГОС)
Статья описывает метод, который позволит перехватывать все события объектов и форм - глобально. | Автор статьи: Гений 1С | Редакторы: TormozIT Последняя редакция №14 от 11.09.06 |
Ключевые слова: парсинг,события,обработчики,глобальный,триггер,модуль,форма
Полный парсинг 80.
Пока в ближайших планах 1С похоже нет намерений дать программистам возможности использовать глобальные триггеры, вызываемые при открытии любой формы, документа, справочника и т.п.
А ведь иногда для контроля прав доступа, протоколирования, добавления общих элементов управления на формы и т.п. нужно использовать свои глобальные обработчики событий.
Чтобы не давить тараканов по одному, я решил использовать дуст и вытравить их всех сразу. Суть идеи – выгружаем все модули прикладных объектов и их форм, а также модули отчетов. Потом обрабатываем их (парсим). После этого загружаем модули обратно. Процедуру можно повторять многократно, например, при обновлении версии библиотеки обработки глобальных событий.
Какие бонусы мы получим:
• Для объектов – для всех событий объектов будут вызываться события до стандартной реакции, после стандартной реакции и можно будет отменить стандартную реакцию.
• Для форм - для всех событий формы будут вызываться события до стандартной реакции, после стандартной реакции и можно будет отменить стандартную реакцию.
• Для форм можно будет добавлять любые элементы управления, реакцию на которые описывать в общем модуле, т.к. все события всех возможных типов элементов управления будут прописаны в форме.
• У форм и объектов будет добавлена одна переменная типа структура, где можно будет хранить свои вспомогательные переменные, чтобы не добавлять их в объявление переменных каждой формы/объекта.
• У форм и объектов будут доступны некоторые недостающие методы, которые будут описывать форму/объект. Например, для формы это будет функция, которая возвращает имя формы.
• Обработчики событий элементов управления формы можно будет программно вызывать, т.е. например программно кликать на кнопках, вводить текст в поле ввода аналогично тому, как это делает пользователь и т.п.
Возможные применения:
• Вмешательства в типовые конфигурации. После обновления можно просто прогнать парсинг и получить нужный функционал быстрее, чем если вставлять заплатки непосредственно в модули объектов.
• Контроль прав доступа. Парсинг события ПередЗаписью объектов позволяет организовать альтернативный контроль прав доступа.
• Приемы программирования. Иногда требуется отлавливать событие у всех объектов – например назначения обработчика оповещения для всех открытых форм, чтобы получать список открытых форм или отлавливать запись объектов, чтобы вести протокол.
В целях ускорения разработки я выношу ее на коллективную правку/работу. На исключительные авторские права не претендую.
Общие принципы
Каждая строка помечается комментарием-маркером в конце строки «//Глобальная Обработка Событий fixin», после которой идет текущая дата и время внесения правки и дополнительные сведения (если программист задал их перед парсингом). В форме обработки будет возможность изменять этот комментарий, если стандартный не подходит.
Переда началом парсинга модуля из него удаляются все строки, помеченные таким маркером. Поэтому не стоит добавлять свой код в эти строки.
Также не следует добавлять код в процедуры, добавленные при парсинге. Код следует добавлять в процедуры, которые вызываются из этих процедур.
Все процедуры и функции будут начинаться с префикса «ГОС_» для избежания конфликтов по имени.
В комплект поставки будет также входить текст общего модуля «ГОС». В этом модуле будут содержаться заготовки под всевозможные обработчики событий объектов и форм.
Будут разработаны возможности контроля для того, чтобы отключать ту или иную составляющую парсинга для некоторых объектов.
Добавленные в модули переменные-свойства для увеличения быстродействия не инициализируются, но предполагается, что они должны иметь тип «Структура». В модуле «ГОС» будут функции для установки/чтения параметров таких возможно неинициализированных структур. Они будут инициализированы при первом обращении на чтение/запись.
В настоящее время рассматривается обработка только справочников/документов. В последующем возможно расширение до бизнес-процессов, задач, счетов, модулей записей регистров и т.п.
Парсинг модуля объекта
Добавление переменных
В начало каждого модуля добавляется переменная:
Перем ГОС_Параметры Экспорт;
Парсинг обработчиков событий
Для модулей объектов характерно, что события объектов идентифицируются строго по имени процедур.
Для справочника определены следующие события:
• ОбработкаЗаполнения(<Основание>)
• ПередЗаписью(<Отказ>)
• ПередУдалением(<Отказ>)
• ПриЗаписи(<Отказ>)
• ПриКопировании(<Объект копирования>)
• ПриУстановкеНовогоКода(<Стандартная обработка>, <Префикс>)
Для документа определены следующие события:
• ОбработкаЗаполнения(<Основание>)
• ОбработкаПроведения(<Отказ>, <Режим проведения>)
• ОбработкаУдаленияПроведения(<Отказ>)
• ПередЗаписью(<Отказ>, <Режим записи>, <Режим проведения>)
• ПередУдалением(<Отказ>)
• ПриЗаписи(<Отказ>)
• ПриКопировании(<Объект копирования>)
• ПриУстановкеНовогоНомера(<Стандартная обработка>, <Префикс>)
Парсер проверяет, есть ли обработкичи этих событий в модуле объекта.
Если событий нет, он их добавляет со всеми переменных.
Если события есть, но не хватает всех переменных, парсер добавляет необходимые переменные.
Названия переменных-параметров в существующих обработчиках могут отличаться от принятых по умолчанию, поэтому для каждого обработчика парсер запоминает названия всех переменных-параметров.
Далее парсинг идет для всех обработчиков по одинаковой схеме, приведенной в примере:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения) Если ГОС_Объект_Перед_ПередЗаписью(ЭтотОбъект, Отказ, РежимЗаписи, РежимПроведения)=ложь Тогда Возврат; КонецЕсли; //Здесь размещается старый код процедуры ГОС_Объект_После_ПередЗаписью(ЭтотОбъект, Отказ, РежимЗаписи, РежимПроведения) КонецПроцедуры
Т.е. если функция-обработчик начала события вернет ложь, стандартная обработка события вызываться не будет.
Парсинг форм
Парсинг идет одинаково для всех определенных в конфигурации форм прикладного объекта.
Добавление переменных
В начало каждого модуля добавляется переменная:
Перем ГОС_Параметры Экспорт;
Добавление методов
Добавляются следующие функции-методы:
• ВидФормы() – возвращает один из видов формы: ФормаСписка, ФормаЭлемента, ФормаВыбора, ФормаВыбораГруппы, ФормаГруппы, Форма.
• ИмяФормы() – возвращает имя формы, как оно задано в конфигураторе.
Эти параметры определяются из названия модуля во время парсинга.
Парсинг обработчиков событий
Для формы характерно отсутствие явного соответствия между событием и именем процедуры, кроме того обработчики событий могут назначаться динамически.
Поэтому и перехват событий для формы возможен только динамически.
Список событий всех форм:
• ВнешнееСобытие(<Источник>, <Событие>, <Данные>)
• ОбновлениеОтображения()
• ОбработкаАктивизацииОбъекта(<Активный объект>, <Источник>)
• ОбработкаВыбора(<Результат выбора>, <Источник выбора>)
• ОбработкаЗаписиНовогоОбъекта(<Объект>, <Источник>)
• ОбработкаОповещения(<Имя события>, <Параметр>, <Источник>)
• ПередЗакрытием(<Отказ>, <Стандартная обработка>)
• ПередОткрытием(<Отказ>, <Стандартная обработка>)
• ПриЗакрытии()
• ПриОткрытии()
• ПриПовторномОткрытии(<Стандартная обработка>)
Список дополнительных событий форм элементов справочников:
• ПередЗаписью(<Отказ>)
• ПослеЗаписи()
• ПриЗаписи(<Отказ>)
• ПриИзмененииДанных()
Список дополнительных событий форм документов:
• ПередЗаписью(<Отказ>, <Режим записи>, <Режим проведения>)
• ПослеЗаписи()
• ПриЗаписи(<Отказ>)
• ПриИзмененииДанных()
У форм списков справочников и документов дополнительных событий нет.
Рассмотрим переназначение событий на двух примерах:
1. В форме есть обработчик ПередОткрытием(Отк) - т.е. указаны не все названия параметров и первый параметр называется нестандартно, т.е. Отк, а не Отказ.
2. В форме нет обработчика ОбработкаВыбора.
Шаг 1.В конце модуля формы прописывается код, который проверяет наличие у формы обработчиков событий, в случае их наличия определяет количество параметров у обработчиков событий.
Для определения количества параметров компилируется условный вызов функции.
Пример 1:
ИмяСобытия= Строка(ПолучитьДействие(«ПередОткрытием»)); ГОС_Параметры.Вставить(«СтарыйОбработчик_ПередОткрытием», Неопределено); Попытка Код=«Перейти ~ГОС_Метка; »+ИмяСобытия+ «()»+ «~ГОС_Метка:»; Выполнить Код; ГОС_Параметры.Вставить(«СтарыйОбработчик_ПередОткрытием», Код); Исключение КонецПопытки; Попытка Код=«Перейти ~ГОС_Метка; »+ИмяСобытия+ «(Отказ)»+ «~ГОС_Метка:»; Выполнить Код; ГОС_Параметры.Вставить(«СтарыйОбработчик_ПередОткрытием», Код); Исключение КонецПопытки; Попытка Код=«Перейти ~ГОС_Метка; »+ИмяСобытия+ «(Отказ, СтандартнаяОбработка)»+ «~ГОС_Метка:»; Выполнить Код; ГОС_Параметры.Вставить(«СтарыйОбработчик_ПередОткрытием», Код); Исключение КонецПопытки;
Шаг 2.Вся полученная информация заносится в структуру ГОС_Параметры.
Пример 1:
В структуру по ключу «СтарыйОбработчик_ПередОткрытием» будет добавлена строка «ПередОткрытием(Отказ)».
Пример 2:
В структуру по ключу «СтарыйОбработчик_ОбработкаВыбора» будет добавлено значение Неопределено.
Шаг 3.Добавляем в модуль формы процедуры:
Пример 1:
Процедура ГОС_Форма_ПередОткрытием(Отказ, СтандартнаяОбработка) Если ГОС_Форма_Перед_ПередОткрытием (ЭтаФорма, Отказ, СтандартнаяОбработка)=ложь Тогда Возврат; КонецЕсли; Выполнить(ГОС_Параметры.СтарыйОбработчик_ПередОткрытием); ГОС_Форма_После_ПередОткрытием (ЭтаФорма, Отказ, СтандартнаяОбработка) ; КонецПроцедуры
Пример 2:
Процедура ГОС_Форма_ОбработкаВыбора(РезультатВыбора, ИсточникВыбора) Если ГОС_Форма_Перед_ ОбработкаВыбора (ЭтаФорма, РезультатВыбора, ИсточникВыбора)=ложь Тогда Возврат; КонецЕсли; Выполнить(ГОС_Параметры.СтарыйОбработчик_ОбработкаВыбора); ГОС_Форма_После_ ОбработкаВыбора (ЭтаФорма, РезультатВыбора, ИсточникВыбора) ; КонецПроцедуры
Шаг 4.Далее все события формы переназначаются на новые процедуры.
Пример 1:
ЭтаФорма.УстановитьДействие(«ПередОткрытием», Новый Действие(«ГОС_Форма_ПередОткрытием»));
Пример 2:
ЭтаФорма.УстановитьДействие(«ОбработкаВыбора», Новый Действие(«ГОС_Форма_ ОбработкаВыбора»));
Алгоритм парсинга
Используется неидеальная, но простая и эффективная схема парсинга, построенная на ряде допущений. Тем не менее схема должна отрабатывать 100% случаев на типовых конфигурациях и 99.99% случаев на нетиповых.
Преполагается что строка с объявлением процедуры(функции) начинается с ключевого слова «Процедура»(«Функция») написанного в любом регистре, которому могут предшествовать пустые знаки (пробелы или табуляция).
Наличие этого ключевого слова маркирует начало объявления процедуры(функции). Объявление может располагаться на нескольких строчках.
Концом процедуры(функции) считается наличие слова «КонецПроцедуры» («КонецФункции»).
Модули, где не наблюдается парности начала/конца объявления функций не обрабатываются, а выдается сообщение об ошибке.
Процедура/функция разбирается в структуру вида:
• ВидПроцедуры: «Процедура» или «Функция»
• Переменные – таблица значений
• Имя – имя переменной
• Экспорт – булево, да, если экспортируемая, нет, если не экспортируемая.
Парсинг для элементов управления.
Для того, чтобы у форм можно будет добавлять новые элементы управления, нужно, чтобы в форме существовали процедуры-обработчики событий этих элементов. К сожалению в 1С 8.0 нельзя назначить элементу управления процедуру-обработчик, находящуюся в общем модуле.
Однако с помощью парсинга в модуль каждой формы можно внедрить по одной процедуре на каждый вид события каждого элемента формы, которую можно назначать как процедуру-обработчик для новых элементов.
Список процедур-обработчиков – для всех форм одинаков.
• ГОС_Элемент_Лок_АвтоПодборТекста(Элемент, Текст, ТекстАвтоПодбора, СтандартнаяОбработка)
• ГОС_Элемент_Лок_Выбор(Элемент, Область, СтандартнаяОбработка)
• ГОС_Элемент_Лок_ДокументСформирован(Элемент)
• ГОС_Элемент_Лок_Нажатие(Элемент)
• ГОС_Элемент_Лок_НачалоВыбора(Элемент, СтандартнаяОбработка)
• ГОС_Элемент_Лок_НачалоПеретаскивания(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка)
• ГОС_Элемент_Лок_ОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
• ГОС_Элемент_Лок_ОбработкаЗаписиНовогоОбъекта(Элемент, Объект, СтандартнаяОбработка)
• ГОС_Элемент_Лок_ОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка)
• ГОС_Элемент_Лок_ОкончаниеВводаТекста(Элемент, Текст, Значение, СтандартнаяОбработка)
• ГОС_Элемент_Лок_ОкончаниеПеретаскивания(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка)
• ГОС_Элемент_Лок_Открытие(Элемент, СтандартнаяОбработка)
• ГОС_Элемент_Лок_Очистка(Элемент, СтандартнаяОбработка)
• ГОС_Элемент_Лок_ПередНачаломДобавления(Элемент, Отказ, Копирование)
• ГОС_Элемент_Лок_ПередНачаломИзменения(Элемент, Отказ)
• ГОС_Элемент_Лок_ПередОкончаниемРедактирования(Элемент, НоваяСтрока, ОтменаРедактирования, Отказ)
• ГОС_Элемент_Лок_ПередУдалением(Элемент, Отказ)
• ГОС_Элемент_Лок_Перетаскивание(Элемент, Параметры перетаскивания, СтандартнаяОбработка, Область)
• ГОС_Элемент_Лок_ПослеУдаления(Элемент)
• ГОС_Элемент_Лок_ПриАктивизацииКолонки(Элемент)
• ГОС_Элемент_Лок_ПриАктивизацииОбласти(Элемент)
• ГОС_Элемент_Лок_ПриАктивизацииСтроки(Элемент)
• ГОС_Элемент_Лок_ПриАктивизацииЯчейки(Элемент)
• ГОС_Элемент_Лок_ПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
• ГОС_Элемент_Лок_ПриИзменении(Элемент)
• ГОС_Элемент_Лок_ПриИзмененииСодержимогоОбласти(Элемент, Область)
• ГОС_Элемент_Лок_ПриИзмененииФлажка(Элемент)
• ГОС_Элемент_Лок_ПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
• ГОС_Элемент_Лок_ПриОкончанииРедактирования(Элемент, НоваяСтрока, Отмена редактирования)
• ГОС_Элемент_Лок_ПриОкончанииРедактированияИнтервала(Элемент, Интервал, Отмена)
• ГОС_Элемент_Лок_ПриПолученииДанных(Элемент, ОформленияСтрок)
• ГОС_Элемент_Лок_ПриСменеСтраницы(Элемент, ТекущаяСтраница) – при смене страницы панели
• ГОС_Элемент_Лок_ПриСменеТекущегоРодителя(Элемент)
• ГОС_Элемент_Лок_ПроверкаПеретаскивания(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Область)
• ГОС_Элемент_Лок_Регулирование(Элемент, Направление, СтандартнаяОбработка)
• схемы, Серия)
При установке обработчика события на одну из этих процедур вызывается аналогичная процедура модуля ГОС, например при срабатывании ГОС_Элемент_Лок_Нажатие(Элемент) вызывается функция ГОС_Элемент_Нажатие(Элемент).
Таким образом если мы программно добавили кнопку «КнопкаВыполнить», то в дальнейшем ей можно назначить процедуру-обработчик нажатия на кнопку так:
ЭлементыФормы.КнопкаВыполнить.УстановитьДействие(Новый Действие(«Нажатие»));
Парсинг для программного вызова событий.
В каждую форму добавляется экспортируемая функция
Функция ГОС_ВызовСобытия(Элемент, ИмяСобытия, П1=Неопределенно, П2=Неопределенно, П3=Неопределено) Экспорт Попытка ИмяФункции=Строка(Элемент.ПолучитьДействие(ИмяСобытия)); Исключение Возврат ложь; КонецПопытки; Попытка Выполнить («»+ИмяФункции+«(П1,П2,П3)»); Исключение Возврат ложь; КонецПопытки; Попытка Выполнить («»+ИмяФункции+«(П1,П2)»); Исключение Возврат ложь; КонецПопытки; Попытка Выполнить («»+ИмяФункции+«(П1)»); Исключение Возврат ложь; КонецПопытки; Попытка Выполнить («»+ИмяФункции+«()»); Исключение Возврат ложь; КонецПопытки; Возврат Истина; КонецФункции
С ее помощью можно программно вызывать события у любого элемента управления на форме. Например, программный клик на кнопке:
Форма.ГОС_ВызовСобытия(ЭлементыФормы.КнопкаВыполнить, «Нажатие»);
Состояние дел
На текущий момент имеется полная теоретическая база (данная статья) для приступления к кодированию парсинга.
Слабо проработаны алгоритмы синтаксического разбора модулей.
Есть также код, который перебирает все выгруженные модули конфигурации, определяет по имени файла, что это за модуль – документа или справочника, это форма или модуль объекта, а также вид формы.
Остается только закодировать.
Кстати, небольшое финансовое вливание в размере 1000$ может ускорить релиз этой обработки. :)
TormozIT:
Еще очень важный момент. После написания этого парсера нужно написать еще и роллбэк-парсер, который все внесенные первым парсером изменения устранит. Это нужно для значительного облегчения обновления конфигурации, после которого снова нужно запустить первый парсер.