Работает на УТ 10.3, УПП
Механизм добавления кнопок копирование/вставки табличных частей во все документы без тотального изменения конфигурации.
Рано или поздно возникает мысль, что неплохо бы иметь возможность копировать табличные части между разными документами.
Большинство подходов неудобны тем, что приходится вносить изменения в формы большого числа документов (в каждую форму вставлять кнопочки) либо пользоваться универсальными копировщиками, т.е. нужно указывать объект источник, объект приемник и т.д., что неудобно.
Предлагается механизм добавления кнопок копирования/вставки без тотального изменения конфигурации. Документы можно даже не снимать с поддержки. Кнопки добавляются к каждой табличной части документа (их может быть несколько, например, "товары" и "услуги").
Upd: Сокращен состав изменений в конфигурации. Добавлена возможность сохранения буфера обмена в файл/ восстановления из файла.
Задача: в командную панель табличной части добавить кнопки копирования и вставки табличной части. Кнопка «Копировать» доступна всегда. Кнопка «Вставить» доступна если есть значения для копирования и если документ доступен для редактирования.
Решение: кнопки добавляем программно, используя вызов общих процедур для каждого документа. Значение храним в существующем параметре сеанса "ОбщиеЗначения". Кнопкой "копировать" просто помещаем объект в параметр сеанса. Кнопкой "вставить" вызываем обработку вставки, чтобы видеть что мы вставляем, иметь возможность отказаться от вставки и настроить вставляемые данные.
Альтернативное решение: Можно вообще отказаться изменений конфигурации. Для пользователя выглядеть это будет не так изящно, зато для программиста меньше забот. В альтернативном решение использован только стандартный функционал по внешним обработчикам таб.частей. Приложены два файла-обработки для действия копирования и вставки. Чтобы обработки начали работать нужно зарегистировать их в справочнике "ВнешниеОбработки" и привязать к документам и таб.частям. Обработки умеют сами себя регистрировать во внешних обработках и привязывать к документам и таб. частям. Для этого нужно просто запустить обработку и нажать кнопку "зарегистрировать"
Upd: Изменены обработки альтернативного решения. Добавлена авторегистрация обработок в справочнике "Внешние обработки"
Изменения конфигурации:
- новая обработка «БуферОбменаТаблицаЗначений»
- изменения роли «Пользователь» для настройки доступа к обработке
- изменения в процедуре «МеханизмНумерацииОбъектов.УстановитьДоступностьПоляВводаНомера»
- изменения в процедуре «УниверсальныеМеханизмы.СформироватьПодменюЗаполненияТЧ»
- изменения в процедуре «УниверсальныеМеханизмы.ОбработатьНажатиеНаДополнительнуюКнопкуЗаполненияТЧ»
- Как видно из списка измененных объектов здесь отсутствуют изменения в документах, что и было главной целью
МеханизмНумерацииОбъектов.УстановитьДоступностьПоляВводаНомера();
Процедура УстановитьДоступностьПоляВводаНомера(МетаданныеОбъекта, ФормаОбъекта, ПодменюДействия, ПолеВводаНомера) Экспорт
Обр = Обработки.БуферОбменаТаблицаЗначений.Создать();
Обр.БуферОбмена_ДобавитьКнопкиВКомандныеПанелиФормы(МетаданныеОбъекта,ФормаОбъекта);
Если ФормаОбъекта.Автонумерация = АвтонумерацияВФорме.Авто Тогда
Возврат;
КонецЕсли;
СтратегияРедактирования = ПолучитьСтратегиюРедактированияНомераОбъекта(МетаданныеОбъекта);
Если СтратегияРедактирования = Перечисления.СтратегияРедактированияНомеровОбъектов.Доступно Тогда
Если ПодменюДействия.Кнопки.Найти("РедактироватьКодНомер") <> Неопределено Тогда
ПодменюДействия.Кнопки.Удалить(ПодменюДействия.Кнопки.РедактироватьКодНомер);
КонецЕсли;
ПолеВводаНомера.ТолькоПросмотр = Ложь;
КонецЕсли;
ПолеВводаНомера.ПропускатьПриВводе = ПолеВводаНомера.ТолькоПросмотр;
УстановитьПодсказкуПоляВводаКодаНомера(ПолеВводаНомера, ПодменюДействия, СтратегияРедактирования);
КонецПроцедуры // УстановитьДоступностьПоляВводаНомера()
- Кнопка копирования: «КопироватьТЧВБуферОбмена_"+ИмяТабличнойЧасти
- Кнопка вставки: «ВставитьТЧИзБуфераОбмена_"+ИмяТабличнойЧасти
// Параметры
//_Метаданные - метаданные объекта
//_Форма - форма объекта
//Процедура добавляет в командные панели формы кнопки работы с буфером обмена (копирования/вставки табличных частей)
Процедура БуферОбмена_ДобавитьКнопкиВКомандныеПанелиФормы(_Метаданные,_Форма) Экспорт
Если _Метаданные.ТабличныеЧасти.Количество() <> 0 Тогда
соотвТабЧасть_КоманднаяПанель = Новый Соответствие;
Для Каждого ЭФ Из _Форма.ЭлементыФормы Цикл
Если ТипЗнч(ЭФ) = Тип("КоманднаяПанель") Тогда
Если ТипЗнч(ЭФ.ИсточникДействий) = Тип("ТабличноеПоле") Тогда
ИмяТЧ = ЭФ.ИсточникДействий.Данные;
ТабЧасть = _Метаданные.ТабличныеЧасти.Найти(ИмяТЧ);
Если ТабЧасть = Неопределено Тогда
Продолжить;
КонецЕсли;
//Если одной табличной части соответствует несколько панелей, то добавляем кнопки в первую, а не в последнюю
Если соотвТабЧасть_КоманднаяПанель.Получить(ТабЧасть) = Неопределено Тогда
соотвТабЧасть_КоманднаяПанель.Вставить(ТабЧасть,ЭФ);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
ВставкаВозможна = Истина;
Если соотвТабЧасть_КоманднаяПанель.Количество() <> 0 Тогда
Попытка
ХЗ = ПараметрыСеанса.ОбщиеЗначения;
ЗначениеХЗ = ХЗ.Получить();
Если ТипЗнч(ЗначениеХЗ) <> Тип("Структура") Тогда
ВставкаВозможна = ЛОЖЬ;
Иначе
ОписаниеИсточника = ЗначениеХЗ.ОписаниеИсточника;
ЗначениеТЧ = ЗначениеХЗ.ТабличнаяЧасть;
Если ТипЗнч(ЗначениеТЧ) <> Тип("ТаблицаЗначений") Тогда
ставкаВозможна = ЛОЖЬ;
КонецЕсли;
КонецЕсли;
Исключение
ВставкаВозможна = ЛОЖЬ;
КонецПопытки;
Иначе
ВставкаВозможна = ЛОЖЬ;
КонецЕсли;
Для Каждого Элем Из соотвТабЧасть_КоманднаяПанель Цикл
КП = Элем.Значение;
ТабЧасть = Элем.Ключ;
КнопкаКопировать = КП.Кнопки.Добавить("КопироватьТЧВБуферОбмена_"
+ТабЧасть.Имя,ТипКнопкиКоманднойПанели.Действие,,Новый Действие("НажатиеНаДополнительнуюКнопкуЗаполненияТЧ"));
КнопкаКопировать.Картинка = ПолучитьКартинкуКопировать();
Если ВставкаВозможна Тогда
КнопкаВставить = КП.Кнопки.Добавить("ВставитьТЧИзБуфераОбмена_"
+ТабЧасть.Имя,ТипКнопкиКоманднойПанели.Действие,,Новый Действие("НажатиеНаДополнительнуюКнопкуЗаполненияТЧ"));
КнопкаВставить.Картинка = ПолучитьКартинкуВставитьАктивная();
Иначе
КнопкаВставить = КП.Кнопки.Добавить("ВставитьТЧИзБуфераОбмена_"
+ТабЧасть.Имя,ТипКнопкиКоманднойПанели.Действие,,Новый Действие("ПроизвольныйТекстЧтобыКнопкаБылаНедоступна"));
КнопкаВставить.Картинка = ПолучитьКартинкуВставитьПассивная();
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
УниверсальныеМеханизмы.СформироватьПодменюЗаполненияТЧ(мКнопкиЗаполненияТЧ,СоответствиеТЧ);
- мКнопкиЗаполненияТЧ – дерево кнопок «пользовательской» обработки табличных частей
- СоответствиеТЧ – соответствие табличной части и ее кнопки(подменю) заполнения
Процедура СформироватьПодменюЗаполненияТЧ(ДеревоКнопок,СоответствиеТЧ) Экспорт
Для Каждого КлючИЗначение Из СоответствиеТЧ Цикл
ИмяТабличнойЧасти = КлючИЗначение.Ключ.Данные;
СтрокаПодменю = ДеревоКнопок.Строки.Найти(ИмяТабличнойЧасти, "Имя");
Если СтрокаПодменю <> Неопределено Тогда
// Табличное поле
СтрокаПодменю.Расшифровка = КлючИЗначение.Ключ;
ПодменюИлиКоманднаяПанель = КлючИЗначение.Значение;
Если ТипЗНЧ(ПодменюИлиКоманднаяПанель) = Тип("КоманднаяПанель") Тогда
ПодменюИлиКоманднаяПанель = ПодменюИлиКоманднаяПанель.Кнопки.Добавить(,ТипКнопкиКоманднойПанели.Подменю,"Заполнить");
КонецЕсли;
СформироватьПодменю(СтрокаПодменю, ПодменюИлиКоманднаяПанель,Ложь,Истина);
КонецЕсли;
КонецЦикла;
Обр = Обработки.БуферОбменаТаблицаЗначений.Создать();
Обр.БуферОбмена_ДополнитьПодменюЗаполненияТЧ(ДеревоКнопок,СоответствиеТЧ);
КонецПроцедуры
//Добавляем в дерево кнопок информацию о «своих» кнопках. Это дерево используется для определения обработчика при нажатии кнопки в форме.
//Отличать кнопки и из назначение будем по значению колонки «расшифровка».
//В стандартном решении поле расшифровка имеет тип "ВнешняяОбработка", а у нас тип "строка"
Процедура БуферОбмена_ДополнитьПодменюЗаполненияТЧ(_ДеревоКнопок,_СоответствиеТЧ) Экспорт
Для Каждого Элем Из _СоответствиеТЧ Цикл
НовСтрока = _ДеревоКнопок.Строки.Добавить();
НовСтрока.Расшифровка = "Полимагнит.БуферОбмена.Копировать";
НовСтрока.Имя = "КопироватьТЧВБуферОбмена_"+Элем.Ключ.Имя;
НовСтрока = _ДеревоКнопок.Строки.Добавить();
НовСтрока.Расшифровка = "Полимагнит.БуферОбмена.Вставить";
НовСтрока.Имя = "ВставитьТЧИзБуфераОбмена_"+Элем.Ключ.Имя;
КонецЦикла;
КонецПроцедуры
УниверсальныеМеханизмы.ОбработатьНажатиеНаДополнительнуюКнопкуЗаполненияТЧ(…)
// Процедура - обработчик нажатия любой из дополнительных кнопок заполнения табличных частей
// Параметры:
// СтрокаКнопки : строка дерева значений, содержащая "инструкцию" к обработке кнопки
// ЭтотОбъект : контекст объекта документа
Процедура ОбработатьНажатиеНаДополнительнуюКнопкуЗаполненияТЧ(СтрокаКнопки,ЭтотОбъект) Экспорт
Расшифровка = СтрокаКнопки.Расшифровка;
Если ТипЗНЧ(Расшифровка) = Тип("СправочникСсылка.ВнешниеОбработки") Тогда
ИмяФайла = КаталогВременныхФайлов()+"PrnForm.tmp";
ОбъектВнешнейФормы = Расшифровка.ПолучитьОбъект();
Если ОбъектВнешнейФормы = Неопределено Тогда
Сообщить("Ошибка получения внешней обработки заполнения табличной части документа. Возможно обработка была удалена", СтатусСообщения.Важное);
Возврат;
КонецЕсли;
ДополнительныеПараметры = Неопределено;
МетаданныеОбъекта = ЭтотОбъект.Метаданные();
СсылкаОбъекта = Неопределено;
Если Метаданные.Документы.Содержит(МетаданныеОбъекта) Тогда
СсылкаОбъекта = Документы[МетаданныеОбъекта.Имя].ПустаяСсылка();
ИначеЕсли Метаданные.Справочники.Содержит(МетаданныеОбъекта) Тогда
СсылкаОбъекта = Справочники[МетаданныеОбъекта.Имя].ПустаяСсылка();
КонецЕсли;
Если СсылкаОбъекта <> Неопределено Тогда
Для Каждого Стр Из Расшифровка.Принадлежность Цикл
Если (Стр.СсылкаОбъекта = СсылкаОбъекта) И (СокрЛП(Стр.ТабличнаяЧастьИмя) = СтрокаКнопки.Родитель.Имя) Тогда
ДополнительныеПараметры = Стр.ДополнительныеПараметрыОбработки.Получить();
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
ДвоичныеДанные = ОбъектВнешнейФормы.ХранилищеВнешнейОбработки.Получить();
ДвоичныеДанные.Записать(ИмяФайла);
Попытка
Обработка = ВнешниеОбработки.Создать(ИмяФайла);
Исключение
Сообщить("Ошибка исполнения внешней обработки табличной части документа."+Символы.ПС+ОписаниеОшибки(), СтатусСообщения.Важное);
Возврат;
КонецПопытки;
// Передать внешней обработке дополнительные параметры
Если ДополнительныеПараметры <> Неопределено Тогда
// Если у внешней обработки есть реквизит для дополнительных параметров, присвоить ему значение
Если НЕ Обработка.Метаданные().Реквизиты.Найти("ДополнительныеПараметры") = Неопределено Тогда
Обработка.ДополнительныеПараметры = ДополнительныеПараметры;
КонецЕсли;
КонецЕсли;
Попытка
Обработка.Инициализировать(ЭтотОбъект, СтрокаКнопки.Родитель.Имя, СтрокаКнопки.Родитель.Расшифровка);
Исключение
ОбщегоНазначения.СообщитьОбОшибке(ОписаниеОшибки(),, "Заполнение ТЧ не произведено!");
КонецПопытки;
Иначе //доработки
Обр = Обработки.БуферОбменаТаблицаЗначений.Создать();
Обр.БуферОбмена_ОбработатьНажатиеНаКнопку(СтрокаКнопки,ЭтотОбъект);
КонецЕсли;
КонецПроцедуры
- Через значение расшифровки определяем какая кнопка нажата – копирования или вставки.
- Имя табличной части получаем через имя кнопки. Помним, что
- Кнопка копирования: «КопироватьТЧВБуферОбмена_"+ИмяТабличнойЧасти
- Кнопка вставки: «ВставитьТЧИзБуфераОбмена_"+ИмяТабличнойЧасти
- Отсекая известные символы получаем имя табличной части.
- Через контекст объекта и имя табличной части получаем значение табличной части.
// Процедура - обработчик нажатия кнопку работы с буфером обмена (копировать/вставить)
// Параметры:
// _СтрокаКнопки : строка дерева значений, содержащая "инструкцию" к обработке кнопки
// _ЭтотОбъект : контекст объекта документа
Процедура БуферОбмена_ОбработатьНажатиеНаКнопку(_СтрокаКнопки,_ЭтотОбъект) Экспорт
Расшифровка = _СтрокаКнопки.Расшифровка;
ИмяКнопки = _СтрокаКнопки.Имя;
Если Расшифровка = "Полимагнит.БуферОбмена.Копировать" Тогда
ИмяТЧ = СокрЛП(СтрЗаменить(ИмяКнопки,"КопироватьТЧВБуферОбмена_",""));
ТабЧасть = _ЭтотОбъект[ИмяТЧ];
ЗначениеТабличнойЧасти = ТабЧасть.Выгрузить();
//предварительно обработаем таблицу значениий. Есть значения, которые нельзя копировать
ОбработатьТЗПриПомещенииВБуферОбмена(ЗначениеТабличнойЧасти,_ЭтотОбъект,ИмяТЧ);
стХЗ = Новый Структура();
стХЗ.Вставить("ОписаниеИсточника",Строка(_ЭтотОбъект));
стХЗ.Вставить("ТабличнаяЧасть",ЗначениеТабличнойЧасти);
ХЗ = Новый ХранилищеЗначения(стХЗ);
ПараметрыСеанса.ОбщиеЗначения = ХЗ;
ИначеЕсли Расшифровка = "Полимагнит.БуферОбмена.Вставить" Тогда
ИмяТЧ = СокрЛП(СтрЗаменить(ИмяКнопки,"ВставитьТЧИзБуфераОбмена_",""));
Приемник = _ЭтотОбъект[ИмяТЧ];
Попытка
ХЗ = ПараметрыСеанса.ОбщиеЗначения;
ЗначениеХЗ = ХЗ.Получить();
Если ТипЗнч(ЗначениеХЗ) <> Тип("Структура") Тогда
Сообщить("Буфер обмена не содержит значений нужного типа!");
Возврат;
Иначе
ОписаниеИсточника = ЗначениеХЗ.ОписаниеИсточника;
ЗначениеТЧ = ЗначениеХЗ.ТабличнаяЧасть;
Если ТипЗнч(ЗначениеТЧ) <> Тип("ТаблицаЗначений") Тогда
Сообщить("Буфер обмена не содержит значений нужного типа!");
Возврат;
КонецЕсли;
КонецЕсли;
Исключение
Сообщить("Буфер обмена не содержит значений нужного типа!");
Возврат;
КонецПопытки;
ОбработатьТЗПриИзвлеченииИзБуфераОбмена(ЗначениеТЧ,_ЭтотОбъект);
Обр = ЭтотОбъект;
Обр.ОписаниеИсточника = ОписаниеИсточника;
ФормаТаб = Обр.ПолучитьФорму();
ФормаТаб.ТЧ = ЗначениеТЧ;
ОтветФормы = ФормаТаб.ОткрытьМодально();
Если ОтветФормы = Неопределено Тогда
//Это отмена
Иначе
Источник = ФормаТаб.ТЧ;
Если ОтветФормы = "ОчиститьВставить" Тогда
Приемник.Очистить();
КонецЕсли;
Для Каждого Стр Из Источник Цикл
НовСтр = Приемник.Добавить();
ЗаполнитьЗначенияСвойств(НовСтр,Стр);
ОбработатьИсключительныеСлучаиИзмененияСтроки(НовСтр,_ЭтотОбъект)
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Процедура ОбработатьТЗПриПомещенииВБуферОбмена(_ТЗ,_ЭтотОбъект,_ИмяТЧ)
//Если ТипЗнч(_ЭтотОбъект) = Тип("ДокументОбъект.Заявка") Тогда
// Если _ИмяТЧ <> "Товары" Тогда
// _ТЗ.Очистить();
// Иначе //Товары
// стКолонкиДляУдаления = Новый Структура("Идентификатор");
// Для Каждого Элем Из стКолонкиДляУдаления Цикл
// _ТЗ.Колонки.Удалить(Элем.Ключ);
// КонецЦикла;
// КонецЕсли;
//
// КолонкаНоменклатура = _ТЗ.Колонки.Найти("Наименование");
// Если КолонкаНоменклатура <> Неопределено Тогда
// КолонкаНоменклатура.Имя = "Номенклатура";
// КонецЕсли;
//КонецЕсли;
КонецПроцедуры
Процедура ОбработатьТЗПриИзвлеченииИзБуфераОбмена(_ТЗ,_ЭтотОбъект)
//Если ТипЗнч(_ЭтотОбъект) = Тип("ДокументОбъект.Заявка") Тогда
// КолонкаНоменклатура = _ТЗ.Колонки.Найти("Номенклатура");
// Если КолонкаНоменклатура <> Неопределено Тогда
// КолонкаНоменклатура.Имя = "Наименование";
// КонецЕсли;
//КонецЕсли;
КонецПроцедуры
Процедура ОбработатьИсключительныеСлучаиИзмененияСтроки(_Строка,_ЭтотОбъект)
//Если ТипЗнч(_ЭтотОбъект) = Тип("ДокументОбъект.Заявка") Тогда
// _Строка.Идентификатор = Новый УникальныйИдентификатор();
//КонецЕсли;
КонецПроцедуры
Доброго дня А как получить пароль на архив?
$100
Добрый день! Внутри архива отсутствует обработка "БуферОбменаТаблицаЗначений". Вместо нее в архиве под разными именами лежит обработка "VneshnijObrabotchikBuferaObmena_Kopirovat".
Можно получить именно БуферОбменаТаблицаЗначений? Спасибо!
! | Правила, пункт 13! |
Украинский 1С форум: всё про 1С 8.3, 1С 8.2, 1С 8.1, 1С 8.0, 1С 7.7
https://pro1c.org.ua