Возникла у меня необходимость в существующем отчете на СКД, имеющем набор данных - запрос, изменить тип набора данных с запроса на объект - таблицу значений. Но при смене типа набора данных слетели все поля, роли, ресурсы, оформление – в общем, все слетело.
Нашел способ - //infostart.ru/public/285576/ (хочу выразить свое уважение 1cKiller Alexey - респект) - редактирование xml- файла схемы компоновки данных в текстовом редакторе. А почему бы не написать обработку для 1С, которая все сделает сама?
Предлагаю вместе создать такую обработку.
Итак, у нас xml – файл СКД, в котором присутствует набор данных – запрос (учтем, что в данном файле наборы данных могут быть не только на основании запросов, но и объектов, а также объединения). Файл получен, нажатием в конфигураторе кнопки «Сохранить схему в файл»:
Предлагаю на форме разместить два поля: первое для отображения наборов данных (тип ДеревоЗначений, т.к. объединение тоже может содержать различные наборы данных, то использование таблицы значений нам не подойдет), второе для отображения текста запроса набора данных-запрос(строка неограниченной длины, на форме многострочная):
Теперь организуем выбор и обработку файла исходной схемы компоновки данных. Для этого создадим кнопку «Заполнить из файла», назначим ей событие при нажатии:
Процедура КоманднаяПанель1ЗаполнитьИзФайла(Кнопка)
//Открытие диалога выбора файла
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.ПолноеИмяФайла = "";
Диалог.Фильтр = "файлы СКД *.xml|*.xml";
Диалог.МножественныйВыбор = Ложь;
Диалог.Заголовок = "Выберите файл СКД - ресурс";
Если Диалог.Выбрать() Тогда
МассивФайлов = Диалог.ВыбранныеФайлы;
Для Каждого ИмяФайла Из МассивФайлов Цикл
ИсходныйФайл = ИмяФайла;
КонецЦикла;
Файл = Новый Файл(ИсходныйФайл);
Если Файл.Существует() Тогда
ЗаполнитьТЧ(ИсходныйФайл); //Чтение XML-файла и заполнение дерева наборов
Иначе
Сообщить("Не найден файл " + ИсходныйФайл);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Процедура ЗаполнитьТЧ() рекурсивно формирует дерево наборов данных и создает колонки соответствующего элемента формы:
Процедура ЗаполнитьДерево(Позиция, НаборыДанных)
Сч = 0;
Для Каждого НаборДанных Из НаборыДанных Цикл
Сч = Сч + 1;
НовСтр = Позиция.Строки.Добавить();
ЗаполнитьЗначенияСвойств(НовСтр, НаборДанных);
НовСтр.Номер = Сч;
Если ЗначениеЗаполнено(НовСтр.Запрос) Тогда
НовСтр.ТипНабора = "Запрос";
ИначеЕсли ЗначениеЗаполнено(НовСтр.ИсточникДанных) Тогда
НовСтр.ТипНабора = "Объект";
Иначе
НовСтр.ТипНабора = "Объединение";
//Т.к. объединение может содержать различные наборы,
//то разберем набор-объединение по наборам данных
ЗаполнитьДерево(НовСтр, НаборДанных.Элементы);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Для того, чтобы в нижней части обработки в поле РасшифровкаСтроки отображался текст запроса текущего набора данных (если, конечно, этот набор даных-запрос) используем событие ПриАктивацииСтроки нашего дерева:
Процедура ДеревоНаборовПриАктивизацииСтроки(Элемент)
ТекДанные = Элемент.ТекущиеДанные;
Если ТекДанные.ТипНабора = "Запрос" Тогда
РасшифровкаСтроки = ТекДанные.Запрос;
ИначеЕсли ТекДанные.ТипНабора = "Объект" Тогда
РасшифровкаСтроки = ТекДанные.ИмяОбъекта;
Иначе
РасшифровкаСтроки = "";
КонецЕсли;
КонецПроцедуры
Теперь можно в дереве указать, какие наборы заменять (установка флажка в колонке «Пометка» и имя объекта, содержащего данные в колонке «Имя объекта»), например, так:
Создадим кнопку «Сохранить СКД в файл как…», процедура, вызываемая по нажатию этой кнопки:
Процедура КоманднаяПанель1СохранитьВФайл(Кнопка)
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
Диалог.ПолноеИмяФайла = "";
Диалог.Фильтр = "файлы СКД *.xml|*.xml";
Диалог.МножественныйВыбор = Ложь;
Диалог.Заголовок = "Файл СКД исправленный";
Если Диалог.Выбрать() Тогда
МассивФайлов = Диалог.ВыбранныеФайлы;
Для Каждого ИмяФайла Из МассивФайлов Цикл
КоррФайл = ИмяФайла;
КонецЦикла;
НовСКД = Новый СхемаКомпоновкиДанных;
НовСКД = СКД;
ВыполнитьЗамену(ДеревоНаборов.Строки, НовСКД.НаборыДанных);
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(КоррФайл);
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, НовСКД);
КонецЕсли;
КонецПроцедуры
А вот и сама, так сказать, процедура-гвоздь программы ВыполнитьЗамену(), рекурсивно:
Процедура ВыполнитьЗамену(ДеревоНаборовСтроки, НовСКДНаборыДанных)
Для Каждого Стр Из ДеревоНаборовСтроки Цикл
Если Стр.Отметка Тогда
НовыйНабор = НовСКДНаборыДанных.Вставить(Стр.Номер - 1, Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));
СтарыйНабор = НовСКДНаборыДанных[Стр.Номер];
ЗаполнитьЗначенияСвойств(НовыйНабор, СтарыйНабор);
НовыйНабор.ИмяОбъекта = Стр.ИмяОбъекта;
Для Каждого СтарыйНаборПоле ИЗ СтарыйНабор.Поля Цикл
НовПоле = НовыйНабор.Поля.Добавить(ТипЗнч(СтарыйНаборПоле));
ЗаполнитьЗначенияСвойств(НовПоле, СтарыйНаборПоле);
КонецЦикла;
НовСКДНаборыДанных.Удалить(СтарыйНабор);
Иначе
Если Стр.ТипНабора = "Объединение" Тогда
ВыполнитьЗамену(Стр.Строки, НовСКДНаборыДанных[Стр.Номер - 1].Элементы);
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Все очень просто, обработка (неуправляемые формы) прилагается – используйте.
При необходимости, не против добавить и на управляемых формах. Удачи…