///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2024, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ПрограммныйИнтерфейс

// Возвращает двоичные данные файла.
//
// Параметры:
//  ПрисоединенныйФайл - ОпределяемыйТип.ПрисоединенныйФайл - ссылка на элемент справочника с файлом.
//
//  ВызыватьИсключение - Булево - если указать Ложь, то функция будет возвращать Неопределено
//                     			  вместо вызова исключений, уровень записи журнала регистрации будет понижен до "Предупреждение".
//                                Значение по умолчанию - Истина.
//
// Возвращаемое значение:
//  ДвоичныеДанные, Неопределено - двоичные данные присоединенного файла. Если двоичные данные файла не найдены
//                               в информационной базе или в томах, вызывает исключение. Если двоичные данные не
//                               найдены и параметр ВызыватьИсключение принимает значение Ложь, тогда
//                               возвращаемое значение - Неопределено.
//
// Пример:
//  Сохранение данных файла на сервере:
//	ДанныеФайла = РаботаСФайлами.ДвоичныеДанныеФайла(Файл, Ложь);
//	Если ДанныеФайла <> Неопределено Тогда
//		ДанныеФайла.Записать(ПутьКФайлу);
//	КонецЕсли;
//
Функция ДвоичныеДанныеФайла(Знач ПрисоединенныйФайл, Знач ВызыватьИсключение = Истина) Экспорт
	
	ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("РаботаСФайлами.ДвоичныеДанныеФайла", "ПрисоединенныйФайл", 
		ПрисоединенныйФайл, Метаданные.ОпределяемыеТипы.ПрисоединенныйФайл.Тип);
	
	ФайлОбъект = РаботаСФайламиСлужебный.ФайлОбъект(ПрисоединенныйФайл);
	Если (ФайлОбъект = Неопределено Или ФайлОбъект.ЭтоГруппа) И Не ВызыватьИсключение Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ОбщегоНазначенияКлиентСервер.Проверить(ФайлОбъект <> Неопределено, 
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Недопустимое значение параметра %1'"), "ПрисоединенныйФайл"),
		"РаботаСФайлами.ДвоичныеДанныеФайла");
	ОбщегоНазначенияКлиентСервер.Проверить(Не ФайлОбъект.ЭтоГруппа, 
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Недопустимое значение параметра %1 (папка файлов ""%2"")'"),
			"ПрисоединенныйФайл", ОбщегоНазначения.ПредметСтрокой(ПрисоединенныйФайл)),
		"РаботаСФайлами.ДвоичныеДанныеФайла");
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
	
	Если ФайлОбъект.ПометкаУдаления Тогда
		РаботаСФайламиСлужебный.СообщитьОбОшибкеФайлНеНайден(ФайлОбъект, ВызыватьИсключение);
		Возврат Неопределено;
	КонецЕсли;
	
	Если ФайлОбъект.ТипХраненияФайла = Перечисления.ТипыХраненияФайлов.ВИнформационнойБазе Тогда
		
		Результат = ХранилищеФайлаИзИнформационнойБазы(ФайлОбъект.Ссылка);
		Если ТипЗнч(Результат) = Тип("ХранилищеЗначения") Тогда
			Результат = Результат.Получить();
			Если ТипЗнч(Результат) = Тип("ДвоичныеДанные") Тогда
				Возврат Результат;
			ИначеЕсли ТипЗнч(Результат) = Тип("Картинка") Тогда
				Возврат Результат.ПолучитьДвоичныеДанные();
			КонецЕсли;
		КонецЕсли;
		
		РаботаСФайламиСлужебный.СообщитьОбОшибкеФайлНеНайден(ФайлОбъект, ВызыватьИсключение);
		Возврат Неопределено;
			
	Иначе
		Возврат РаботаСФайламиВТомахСлужебный.ДанныеФайла(ПрисоединенныйФайл, ВызыватьИсключение);
	КонецЕсли;
	
КонецФункции

// Возвращает двоичные данные файла.
//
// Параметры:
//  ПрисоединенныеФайлы - Массив из ОпределяемыйТип.ПрисоединенныйФайл - массив элементов справочника с файлом, все
//                                                                       элементы должны быть одного типа.
//
//  ВызыватьИсключение - Булево - если указать Ложь, то функция будет возвращать Неопределено
//                     			  вместо вызова исключений, уровень записи журнала регистрации будет понижен до "Предупреждение".
//                                Значение по умолчанию - Истина.
//
// Возвращаемое значение:
//  Соответствие из КлючИЗначение:
//   * Ключ - ОпределяемыйТип.ПрисоединенныйФайл - файл из параметра ПрисоединенныеФайлы. 
//   * Значение - ДвоичныеДанные - двоичные данные присоединенного файла. Если двоичные данные файла не существуют
//                               в информационной базе или в томах, вызывает исключение. Если двоичные данные не
//                               существуют и параметр ВызыватьИсключение принимает значение Ложь, тогда
//                               запись для такого файла будет отсутствовать.
//
Функция ДвоичныеДанныеФайлов(Знач ПрисоединенныеФайлы, Знач ВызыватьИсключение = Истина) Экспорт
	
	Если ПрисоединенныеФайлы.Количество() = 0 Тогда
		Возврат Новый Соответствие;
	КонецЕсли;
	
	ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("РаботаСФайлами.ДвоичныеДанныеФайла", "ПрисоединенныйФайл", 
		ПрисоединенныеФайлы[0], Метаданные.ОпределяемыеТипы.ПрисоединенныйФайл.Тип);
		
	ТипФайла = ТипЗнч(ПрисоединенныеФайлы[0]);
	Для Индекс = 1 По ПрисоединенныеФайлы.Количество() - 1 Цикл
		Если ТипЗнч(ПрисоединенныеФайлы[Индекс]) <> ТипФайла Тогда
			ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Все присоединенные файлы в параметре %1 должны быть одного типа в %2.'"),
				"ПрисоединенныеФайлы", "РаботаСФайлами.ДвоичныеДанныеФайлов"),
				КатегорияОшибки.ОшибкаКонфигурации);
		КонецЕсли;
	КонецЦикла;
	
	РазрешенныеПрисоединенныеФайлы = Новый Массив;
	ЕстьПраваНаОбъекты = ОбщегоНазначения.ЗначенияРеквизитовОбъектов(ПрисоединенныеФайлы, "Ссылка", Истина);
	Для Каждого ЕстьПраваНаОбъект Из ЕстьПраваНаОбъекты Цикл
		РазрешенныеПрисоединенныеФайлы.Добавить(ЕстьПраваНаОбъект.Ключ); 
	КонецЦикла; 
	
	МетаданныеОбъектаФайла = Метаданные.НайтиПоТипу(ТипФайла);
	
	ЕстьРеквизитТекущаяВерсия = ОбщегоНазначения.ЕстьРеквизитОбъекта("ВладелецФайла", МетаданныеОбъектаФайла)
		И ОбщегоНазначения.ЕстьРеквизитОбъекта("ТекущаяВерсия", МетаданныеОбъектаФайла);
		
	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
		
	Если ЕстьРеквизитТекущаяВерсия Тогда
		Если РаботаСФайламиСлужебныйПовтИсп.ДедупликацияВыполнена() Тогда
			ТекстЗапроса =
			"ВЫБРАТЬ
			|	ПрисоединенныеФайлы.Ссылка КАК Ссылка,
			|	ПрисоединенныеФайлы.ТипХраненияФайла КАК ТипХраненияФайла,
			|	ПрисоединенныеФайлы.Том КАК Том,
			|	ПрисоединенныеФайлы.ПометкаУдаления КАК ПометкаУдаления,
			|	ХранилищеФайлов.ХранилищеДвоичныхДанных.ДвоичныеДанные КАК ХранилищеФайла
			|ИЗ
			|	&ТаблицаПрисоединенныеФайлы КАК ПрисоединенныеФайлы
			|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ХранилищеФайлов КАК ХранилищеФайлов
			|		ПО ПрисоединенныеФайлы.Ссылка = ХранилищеФайлов.Файл
			|ГДЕ
			|	ПрисоединенныеФайлы.Ссылка В (&ПрисоединенныеФайлы)
			|	И ПрисоединенныеФайлы.ТекущаяВерсия = ЗНАЧЕНИЕ(Справочник.ВерсииФайлов.ПустаяСсылка)
			|
			|ОБЪЕДИНИТЬ ВСЕ
			|
			|ВЫБРАТЬ
			|	ПрисоединенныеФайлы.Ссылка,
			|	ПрисоединенныеФайлы.ТипХраненияФайла,
			|	ПрисоединенныеФайлы.Том,
			|	ПрисоединенныеФайлы.ПометкаУдаления,
			|	ХранилищеФайлов.ХранилищеДвоичныхДанных.ДвоичныеДанные
			|ИЗ
			|	&ТаблицаПрисоединенныеФайлы КАК ПрисоединенныеФайлы
			|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ХранилищеФайлов КАК ХранилищеФайлов
			|		ПО ПрисоединенныеФайлы.ТекущаяВерсия = ХранилищеФайлов.Файл
			|ГДЕ
			|	ПрисоединенныеФайлы.Ссылка В (&ПрисоединенныеФайлы)
			|	И ПрисоединенныеФайлы.ТекущаяВерсия <> ЗНАЧЕНИЕ(Справочник.ВерсииФайлов.ПустаяСсылка)";
		Иначе
			ТекстЗапроса =
			"ВЫБРАТЬ
			|	ПрисоединенныеФайлы.Ссылка КАК Ссылка,
			|	ПрисоединенныеФайлы.ТипХраненияФайла КАК ТипХраненияФайла,
			|	ПрисоединенныеФайлы.Том КАК Том,
			|	ПрисоединенныеФайлы.ПометкаУдаления КАК ПометкаУдаления,
			|	ВЫБОР
			|		КОГДА ХранилищеФайлов.Файл ЕСТЬ NULL
			|			ТОГДА УдалитьДвоичныеДанныеФайлов.ДвоичныеДанныеФайла
			|		ИНАЧЕ ХранилищеФайлов.ХранилищеДвоичныхДанных.ДвоичныеДанные
			|	КОНЕЦ КАК ХранилищеФайла
			|ИЗ
			|	&ТаблицаПрисоединенныеФайлы КАК ПрисоединенныеФайлы
			|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ХранилищеФайлов КАК ХранилищеФайлов
			|		ПО ПрисоединенныеФайлы.Ссылка = ХранилищеФайлов.Файл
			|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.УдалитьДвоичныеДанныеФайлов КАК УдалитьДвоичныеДанныеФайлов
			|		ПО ПрисоединенныеФайлы.Ссылка = УдалитьДвоичныеДанныеФайлов.Файл
			|ГДЕ
			|	ПрисоединенныеФайлы.Ссылка В (&ПрисоединенныеФайлы)
			|	И ПрисоединенныеФайлы.ТекущаяВерсия = ЗНАЧЕНИЕ(Справочник.ВерсииФайлов.ПустаяСсылка)
			|
			|ОБЪЕДИНИТЬ ВСЕ
			|
			|ВЫБРАТЬ
			|	ПрисоединенныеФайлы.Ссылка,
			|	ПрисоединенныеФайлы.ТипХраненияФайла,
			|	ПрисоединенныеФайлы.Том,
			|	ПрисоединенныеФайлы.ПометкаУдаления,
			|	ВЫБОР
			|		КОГДА ХранилищеФайлов.Файл ЕСТЬ NULL
			|			ТОГДА УдалитьДвоичныеДанныеФайлов.ДвоичныеДанныеФайла
			|		ИНАЧЕ ХранилищеФайлов.ХранилищеДвоичныхДанных.ДвоичныеДанные
			|	КОНЕЦ
			|ИЗ
			|	&ТаблицаПрисоединенныеФайлы КАК ПрисоединенныеФайлы
			|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ХранилищеФайлов КАК ХранилищеФайлов
			|		ПО ПрисоединенныеФайлы.ТекущаяВерсия = ХранилищеФайлов.Файл
			|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.УдалитьДвоичныеДанныеФайлов КАК УдалитьДвоичныеДанныеФайлов
			|		ПО ПрисоединенныеФайлы.ТекущаяВерсия = УдалитьДвоичныеДанныеФайлов.Файл
			|ГДЕ
			|	ПрисоединенныеФайлы.Ссылка В (&ПрисоединенныеФайлы)
			|	И ПрисоединенныеФайлы.ТекущаяВерсия <> ЗНАЧЕНИЕ(Справочник.ВерсииФайлов.ПустаяСсылка)";
		КонецЕсли;
	Иначе
		Если РаботаСФайламиСлужебныйПовтИсп.ДедупликацияВыполнена() Тогда
			ТекстЗапроса =
			"ВЫБРАТЬ
			|	ПрисоединенныеФайлы.Ссылка КАК Ссылка,
			|	ПрисоединенныеФайлы.ТипХраненияФайла КАК ТипХраненияФайла,
			|	ПрисоединенныеФайлы.Том КАК Том,
			|	ПрисоединенныеФайлы.ПометкаУдаления КАК ПометкаУдаления,
			|	ХранилищеФайлов.ХранилищеДвоичныхДанных.ДвоичныеДанные КАК ХранилищеФайла
			|ИЗ
			|	&ТаблицаПрисоединенныеФайлы КАК ПрисоединенныеФайлы
			|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ХранилищеФайлов КАК ХранилищеФайлов
			|		ПО ПрисоединенныеФайлы.Ссылка = ХранилищеФайлов.Файл
			|ГДЕ
			|	ПрисоединенныеФайлы.Ссылка В (&ПрисоединенныеФайлы)";
		Иначе
			ТекстЗапроса =
			"ВЫБРАТЬ
			|	ПрисоединенныеФайлы.Ссылка КАК Ссылка,
			|	ПрисоединенныеФайлы.ТипХраненияФайла КАК ТипХраненияФайла,
			|	ПрисоединенныеФайлы.Том КАК Том,
			|	ПрисоединенныеФайлы.ПометкаУдаления КАК ПометкаУдаления,
			|	ВЫБОР
			|		КОГДА ХранилищеФайлов.Файл ЕСТЬ NULL
			|			ТОГДА УдалитьДвоичныеДанныеФайлов.ДвоичныеДанныеФайла
			|		ИНАЧЕ ХранилищеФайлов.ХранилищеДвоичныхДанных.ДвоичныеДанные
			|	КОНЕЦ КАК ХранилищеФайла
			|ИЗ
			|	&ТаблицаПрисоединенныеФайлы КАК ПрисоединенныеФайлы
			|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ХранилищеФайлов КАК ХранилищеФайлов
			|		ПО ПрисоединенныеФайлы.Ссылка = ХранилищеФайлов.Файл
			|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.УдалитьДвоичныеДанныеФайлов КАК УдалитьДвоичныеДанныеФайлов
			|		ПО ПрисоединенныеФайлы.Ссылка = УдалитьДвоичныеДанныеФайлов.Файл
			|ГДЕ
			|	ПрисоединенныеФайлы.Ссылка В (&ПрисоединенныеФайлы)";
		КонецЕсли;
	КонецЕсли;
	
	Запрос = Новый Запрос;
	Запрос.Текст = СтрЗаменить(ТекстЗапроса, "&ТаблицаПрисоединенныеФайлы", МетаданныеОбъектаФайла.ПолноеИмя());
	Запрос.УстановитьПараметр("ПрисоединенныеФайлы", РазрешенныеПрисоединенныеФайлы);
	Выборка = Запрос.Выполнить().Выбрать();
	
	ДвоичныеДанныеФайлов = Новый Соответствие;
	Пока Выборка.Следующий() Цикл
		Если Выборка.ТипХраненияФайла = Перечисления.ТипыХраненияФайлов.ВИнформационнойБазе Тогда
			ДвоичныеДанные = Неопределено;
			Если Выборка.ХранилищеФайла <> Null Тогда
				ДвоичныеДанные = Выборка.ХранилищеФайла.Получить();
			КонецЕсли;
			Если ДвоичныеДанные = Неопределено Тогда
				РаботаСФайламиСлужебный.СообщитьОбОшибкеФайлНеНайден(Выборка.Ссылка, ВызыватьИсключение);
			Иначе
				ДвоичныеДанныеФайлов.Вставить(Выборка.Ссылка, ДвоичныеДанные);
			КонецЕсли;
		Иначе
			ДвоичныеДанные = РаботаСФайламиВТомахСлужебный.ДанныеФайла(Выборка.Ссылка, ВызыватьИсключение);
			Если ДвоичныеДанные <> Неопределено Тогда
				ДвоичныеДанныеФайлов.Вставить(Выборка.Ссылка, ДвоичныеДанные);
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Возврат ДвоичныеДанныеФайлов;
	
КонецФункции

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

	Если Не ВызыватьИсключение Тогда
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда
			МодульУправлениеДоступом = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступом");
			ЧтениеРазрешено = МодульУправлениеДоступом.ЧтениеРазрешено(ПрисоединенныйФайл);
		Иначе
			ЧтениеРазрешено = ПравоДоступа("Чтение", ПрисоединенныйФайл.Метаданные());
		КонецЕсли;
		Если Не ЧтениеРазрешено Тогда
			Возврат Неопределено;	
		КонецЕсли;
	КонецЕсли;
	
	ФайлОбъект = ПрисоединенныйФайл.ПолучитьОбъект();
	Если ФайлОбъект = Неопределено Тогда
		Если ВызыватьИсключение Тогда 
			ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru='Файл не существует или недоступен ""%1"" (%2)'"),
				Строка(ПрисоединенныйФайл), ПрисоединенныйФайл.Метаданные().Представление());
			ВызватьИсключение(ТекстСообщения, КатегорияОшибки.НарушениеПравДоступа);
		Иначе
			Возврат Неопределено;
		КонецЕсли;
	КонецЕсли;
	
	Если ДляРедактирования И Не ЗначениеЗаполнено(ФайлОбъект.Редактирует) Тогда
		ФайлОбъект.Заблокировать();
		РаботаСФайламиСлужебный.ЗанятьФайлДляРедактированияСервер(ФайлОбъект);
	КонецЕсли;
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
	
	СсылкаНаДвоичныеДанныеФайла = Неопределено;
	
	ПоддерживаетсяХранениеВерсий = (ТипЗнч(ПрисоединенныйФайл) = Тип("СправочникСсылка.Файлы"));
	ИспользуетсяВерсионированиеФайлов = ПоддерживаетсяХранениеВерсий
		И ПрисоединенныйФайл.ХранитьВерсии И ЗначениеЗаполнено(ПрисоединенныйФайл.ТекущаяВерсия);
	
	Если ПолучатьСсылкуНаДвоичныеДанные Тогда
		Если ИспользуетсяВерсионированиеФайлов Тогда
			ДвоичныеДанные = ДвоичныеДанныеФайла(ПрисоединенныйФайл.ТекущаяВерсия, ВызыватьИсключение);
		Иначе
			ДвоичныеДанные = ДвоичныеДанныеФайла(ПрисоединенныйФайл, ВызыватьИсключение);
		КонецЕсли;
		Если ТипЗнч(ИдентификаторФормы) = Тип("УникальныйИдентификатор") Тогда
			СсылкаНаДвоичныеДанныеФайла = ПоместитьВоВременноеХранилище(ДвоичныеДанные, ИдентификаторФормы);
		Иначе
			СсылкаНаДвоичныеДанныеФайла = ПоместитьВоВременноеХранилище(ДвоичныеДанные);
		КонецЕсли;
		
	КонецЕсли;
	
	Результат = Новый Структура;
	Результат.Вставить("Ссылка",                       ПрисоединенныйФайл);
	Результат.Вставить("СсылкаНаДвоичныеДанныеФайла",  СсылкаНаДвоичныеДанныеФайла);
	Результат.Вставить("ОтносительныйПуть",            ПолучитьИдентификаторОбъекта(ФайлОбъект.ВладелецФайла) + "\");
	Результат.Вставить("ДатаМодификацииУниверсальная", ФайлОбъект.ДатаМодификацииУниверсальная);
	Результат.Вставить("ИмяФайла",                     ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(ФайлОбъект.Наименование, ФайлОбъект.Расширение));
	Результат.Вставить("Наименование",                 ФайлОбъект.Наименование);
	Результат.Вставить("Расширение",                   ФайлОбъект.Расширение);
	Результат.Вставить("Размер",                       ФайлОбъект.Размер);
	Результат.Вставить("Редактирует",                  ФайлОбъект.Редактирует);
	Результат.Вставить("ПодписанЭП",                   ФайлОбъект.ПодписанЭП);
	Результат.Вставить("Зашифрован",                   ФайлОбъект.Зашифрован);
	Результат.Вставить("ХранитьВерсии",                ФайлОбъект.ХранитьВерсии);
	Результат.Вставить("ПометкаУдаления",              ФайлОбъект.ПометкаУдаления);
	Результат.Вставить("ДатаЗаема",                    ФайлОбъект.ДатаЗаема);
	Результат.Вставить("Владелец",                     ФайлОбъект.ВладелецФайла);
	Результат.Вставить("АвторТекущейВерсии",           ФайлОбъект.Изменил);
	Результат.Вставить("НавигационнаяСсылка", ПолучитьНавигационнуюСсылку(ПрисоединенныйФайл));
	
	ОбщегоНазначения.СократитьИмяФайла(Результат.ИмяФайла);
	
	МетаданныеОбъектаФайла = Метаданные.НайтиПоТипу(ТипЗнч(ПрисоединенныйФайл));
	ЕстьВозможностьХранитьВерсии = ОбщегоНазначения.ЕстьРеквизитОбъекта("ТекущаяВерсия", МетаданныеОбъектаФайла);
	
	Если ЕстьВозможностьХранитьВерсии И ЗначениеЗаполнено(ПрисоединенныйФайл.ТекущаяВерсия) Тогда
		РаботаСФайламиСлужебный.ЗаполнитьДополнительныеДанныеФайла(Результат, ПрисоединенныйФайл, ПрисоединенныйФайл.ТекущаяВерсия);
	Иначе
		РаботаСФайламиСлужебный.ЗаполнитьДополнительныеДанныеФайла(Результат, ПрисоединенныйФайл, Неопределено);
	КонецЕсли;
	
	Результат.Вставить("ФайлРедактируется",            ЗначениеЗаполнено(ФайлОбъект.Редактирует));
	Результат.Вставить("ФайлРедактируетТекущийПользователь",
		?(Результат.ФайлРедактируется, ФайлОбъект.Редактирует = Пользователи.АвторизованныйПользователь(), Ложь) );
		
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		МодульЭлектроннаяПодпись = ОбщегоНазначения.ОбщийМодуль("ЭлектроннаяПодпись");
		Если ФайлОбъект.Зашифрован Тогда
			Результат.Вставить("МассивСертификатовШифрования", МодульЭлектроннаяПодпись.СертификатыШифрования(ПрисоединенныйФайл));
		КонецЕсли;
	КонецЕсли;
	
	Файл = ?(ИспользуетсяВерсионированиеФайлов, ПрисоединенныйФайл.ТекущаяВерсия, ПрисоединенныйФайл);
	Результат.Вставить("Кодировка", РегистрыСведений.КодировкиФайлов.ОпределитьКодировкуФайла(Файл, ФайлОбъект.Расширение));
	
	Результат.Вставить("Служебный", Ложь);
	Если ОбщегоНазначенияКлиентСервер.ЕстьРеквизитИлиСвойствоОбъекта(ФайлОбъект, "Служебный") Тогда
		Результат.Служебный = ФайлОбъект.Служебный;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

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

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

// Обновляет свойства файла без учета версий: двоичные данные, текст, дату изменения,
// а также другие необязательные свойства. Использовать только для файлов, которые не хранят версии.
//
// Параметры:
//  ПрисоединенныйФайл - ОпределяемыйТип.ПрисоединенныйФайл - ссылка на элемент справочника с файлом.
//  ИнформацияОФайле - Структура:
//     * АдресФайлаВоВременномХранилище - Строка - адрес новых двоичных данных файла.
//     * АдресВременногоХранилищаТекста - Строка - адрес новых двоичных данных текста,
//                                                 извлеченного из файла.
//     * ИмяБезРасширения               - Строка - необязательное, если свойство не указано или не заполнено,
//                                                 тогда не будет изменено.
//     * ДатаМодификацииУниверсальная   - Дата   - необязательное, дата последнего изменения файла, если
//                                                 свойство не указано или не заполнено, тогда будет
//                                                 установлена текущая дата сеанса.
//     * Расширение                     - Строка - необязательное, новое расширение файла.
//     * Редактирует                    - ЛюбаяСсылка - необязательное, новый пользователь, редактирующий файл.
//     * Кодировка                      - Строка - необязательное, кодировка, в которой сохранен файл.
//                                                 Список поддерживаемых кодировок см. в справке к методу
//                                                 глобального контекста "ПолучитьДвоичныеДанныеИзСтроки".
//
Процедура ОбновитьФайл(Знач ПрисоединенныйФайл, Знач ИнформацияОФайле) Экспорт
	
	ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("РаботаСФайлами.ОбновитьФайл", "ПрисоединенныйФайл", 
		ПрисоединенныйФайл, Метаданные.ОпределяемыеТипы.ПрисоединенныйФайл.Тип);

	НачатьТранзакцию();
	Попытка
		БлокировкаДанных = Новый БлокировкаДанных;
		ЭлементБлокировкиДанных = БлокировкаДанных.Добавить(Метаданные.НайтиПоТипу(ТипЗнч(ПрисоединенныйФайл)).ПолноеИмя());
		ЭлементБлокировкиДанных.УстановитьЗначение("Ссылка", ПрисоединенныйФайл);
		БлокировкаДанных.Заблокировать();
		
		ФайлОбъект = ПрисоединенныйФайл.ПолучитьОбъект();
		ЗаблокироватьДанныеДляРедактирования(ПрисоединенныйФайл);

		ИмяБезРасширения = "";
		Если ИнформацияОФайле.Свойство("ИмяБезРасширения", ИмяБезРасширения) 
			И ЗначениеЗаполнено(ИнформацияОФайле.ИмяБезРасширения) Тогда
			ИмяБезРасширения   = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(ИмяБезРасширения);
			ФайлОбъект.Наименование = ИмяБезРасширения;
		КонецЕсли;
	
		ФайлОбъект.ДатаМодификацииУниверсальная = ТекущаяУниверсальнаяДата();
		Если ИнформацияОФайле.Свойство("ДатаМодификацииУниверсальная")
			И ЗначениеЗаполнено(ИнформацияОФайле.ДатаМодификацииУниверсальная)
			И ИнформацияОФайле.ДатаМодификацииУниверсальная < ФайлОбъект.ДатаМодификацииУниверсальная Тогда
			ФайлОбъект.ДатаМодификацииУниверсальная = ИнформацияОФайле.ДатаМодификацииУниверсальная;
		КонецЕсли;
		
		Если ИнформацияОФайле.Свойство("Редактирует") Тогда
			ФайлОбъект.Редактирует = ИнформацияОФайле.Редактирует;
		КонецЕсли;
		
		РасширениеФайла = "";
		Если ИнформацияОФайле.Свойство("Расширение", РасширениеФайла) Тогда
			РасширениеФайла = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(РасширениеФайла);
			ФайлОбъект.Расширение = РасширениеФайла;
		КонецЕсли;
		
		Если ИнформацияОФайле.Свойство("Кодировка") И Не ПустаяСтрока(ИнформацияОФайле.Кодировка) Тогда
			РегистрыСведений.КодировкиФайлов.ЗаписатьКодировкуВерсииФайла(ПрисоединенныйФайл, ИнформацияОФайле.Кодировка);
		КонецЕсли;
		
		ДвоичныеДанные = ПолучитьИзВременногоХранилища(ИнформацияОФайле.АдресФайлаВоВременномХранилище);
		РаботаСФайламиСлужебный.ЗаполнитьИзвлеченныйТекст(ФайлОбъект, 
			ИнформацияОФайле.АдресВременногоХранилищаТекста, ДвоичныеДанные);
		РаботаСФайламиСлужебный.ОбновитьДвоичныеДанныеФайлаНаСервере(ФайлОбъект, ДвоичныеДанные);
		ЗафиксироватьТранзакцию();

	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

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

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

// Добавляет новый файл из файловой системы.
// Если справочник файлов поддерживает хранение версий, то будет создана первая версия файла.
// 
// Параметры:
//   ВладелецФайлов    - ОпределяемыйТип.ВладелецПрисоединенныхФайлов - объект, к которому
//                       требуется прикрепить добавляемый файл.
//   ПутьКФайлуНаДиске - Строка - полный путь к файлу, включающий имя и расширение файла.
//                       Файл должен находиться на сервере.
//
// Возвращаемое значение:
//  ОпределяемыйТип.ПрисоединенныйФайл - ссылка на элемент справочника с созданным файлом.
//
Функция ДобавитьФайлСДиска(ВладелецФайлов, ПутьКФайлуНаДиске) Экспорт
	
	Если Не ЗначениеЗаполнено(ВладелецФайлов) Тогда
		ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не задано значение параметра %1 в %2.'"), 
			"ВладелецФайлов","РаботаСФайлами.ДобавитьФайлСДиска"),
			КатегорияОшибки.ОшибкаКонфигурации);
	КонецЕсли;
	
	Файл = Новый Файл(ПутьКФайлуНаДиске);
	
	ДвоичныеДанные = Новый ДвоичныеДанные(ПутьКФайлуНаДиске);
	АдресВременногоХранилищаФайла = ПоместитьВоВременноеХранилище(ДвоичныеДанные);
	
	АдресВременногоХранилищаТекста = "";
	
	Если РаботаСФайламиСлужебный.ИзвлекатьТекстыФайловНаСервере() Тогда
		// Текст извлечет регламентное задание.
		АдресВременногоХранилищаТекста = ""; 
	Иначе
		// Попытка извлечения текста, если сервер под Windows.
		Если ОбщегоНазначения.ЭтоWindowsСервер() Тогда
			Текст = РаботаСФайламиСлужебный.ИзвлечьТекстИзФайлаНаДиске(ПутьКФайлуНаДиске);
			АдресВременногоХранилищаТекста = Новый ХранилищеЗначения(Текст, Новый СжатиеДанных(9));
		КонецЕсли;
	КонецЕсли;
	
	СведенияОФайле = РаботаСФайламиКлиентСервер.СведенияОФайле("ФайлСВерсией", Файл);
	СведенияОФайле.АдресВременногоХранилищаФайла = АдресВременногоХранилищаФайла;
	СведенияОФайле.АдресВременногоХранилищаТекста = АдресВременногоХранилищаТекста;
	Результат = РаботаСФайламиСлужебныйВызовСервера.СоздатьФайлСВерсией(ВладелецФайлов, СведенияОФайле);

	Если ЭтоАдресВременногоХранилища(АдресВременногоХранилищаТекста) Тогда
		УдалитьИзВременногоХранилища(АдресВременногоХранилищаТекста);
	КонецЕсли;
	Если ЭтоАдресВременногоХранилища(АдресВременногоХранилищаФайла) Тогда
		УдалитьИзВременногоХранилища(АдресВременногоХранилищаФайла);
	КонецЕсли;

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

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

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

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

// Создает объект в справочнике для хранения файла и заполняет его реквизиты переданными свойствами.
//
// Параметры:
//   ПараметрыФайла                 - см. РаботаСФайлами.ПараметрыДобавленияФайла.
//   АдресФайлаВоВременномХранилище - Строка - адрес, указывающий на двоичные данные во временном хранилище.
//   АдресВременногоХранилищаТекста - Строка - адрес, указывающий на извлеченный текст из файла во временном хранилище.
//   Описание                       - Строка - текстовое описание файла.
//   НоваяСсылкаНаФайл              - Неопределено - если у владельца файла только один справочник хранения файлов.
//                                  - ОпределяемыйТип.ПрисоединенныйФайл - ссылка на элемент справочника хранения файлов,
//                                    которую следует использовать для добавляемого файла.
//                                    Должна соответствовать одному из типов справочников хранения файлов владельца
//                                    файлов. Ссылка может быть получена функцией НоваяСсылкаНаФайл.
// 
// Возвращаемое значение:
//   ОпределяемыйТип.ПрисоединенныйФайл - ссылка на созданный присоединенный файл.
//
Функция ДобавитьФайл(ПараметрыФайла, Знач АдресФайлаВоВременномХранилище, 
	Знач АдресВременногоХранилищаТекста = "", Знач Описание = "", Знач НоваяСсылкаНаФайл = Неопределено) Экспорт
	
	ВладелецФайлов     = ПараметрыФайла.ВладелецФайлов;
	
	Если Не ЗначениеЗаполнено(ВладелецФайлов) Тогда
		ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не задано значение параметра %1 в %2.'"), 
			"ПараметрыФайла.ВладелецФайлов", "РаботаСФайлами.ДобавитьФайл"),
			КатегорияОшибки.ОшибкаКонфигурации);
	КонецЕсли;
	
	ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресФайлаВоВременномХранилище); // ДвоичныеДанные
	ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("РаботаСФайлами.ДобавитьФайл",
		"АдресФайлаВоВременномХранилище", ДвоичныеДанные, Тип("ДвоичныеДанные"));
	
	ГруппаФайлов = Неопределено;
	Если ПараметрыФайла.Свойство("ГруппаФайлов")
		И ЗначениеЗаполнено(ПараметрыФайла.ГруппаФайлов)
		И Не РаботаСФайламиСлужебный.ЭтоПапкаФайлов(ВладелецФайлов) Тогда
		
		ГруппаФайлов = ПараметрыФайла.ГруппаФайлов;
	КонецЕсли;
	
	ИмяБезРасширения   = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(ПараметрыФайла.ИмяБезРасширения);
	РасширениеБезТочки = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(ПараметрыФайла.РасширениеБезТочки);
	Если Не ЗначениеЗаполнено(РасширениеБезТочки) Тогда
		ЧастиИмениФайла = СтрРазделить(ИмяБезРасширения, ".", Ложь);
		Если ЧастиИмениФайла.Количество() > 1 Тогда
			РасширениеБезТочки = ЧастиИмениФайла[ЧастиИмениФайла.Количество() - 1];
			ИмяБезРасширения = Лев(ИмяБезРасширения, СтрДлина(ИмяБезРасширения) - (СтрДлина(РасширениеБезТочки) + 1));
		КонецЕсли;
	КонецЕсли; 

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

// Возвращает персональные настройки работы с файлами.
//
// Возвращаемое значение:
//  Структура:
//    * ПоказыватьЗанятыеФайлыПриЗавершенииРаботы        - Булево - существует, только если внедрена подсистема Работа с
//                                                                  файлами.
//    * СпрашиватьРежимРедактированияПриОткрытииФайла    - Булево - существует, только если внедрена подсистема Работа с
//                                                                  файлами.
//    * ПоказыватьКолонкуРазмер                          - Булево - существует, только если внедрена подсистема Работа с
//                                                                  файлами.
//    * ДействиеПоДвойномуЩелчкуМыши                     - Строка - существует, только если внедрена подсистема Работа с
//                                                                  файлами.
//    * СпособСравненияВерсийФайлов                      - Строка - существует, только если внедрена подсистема Работа с
//                                                                  файлами.
//    * ГрафическиеСхемыРасширение                       - Строка - список расширений для графических схем.
//    * ГрафическиеСхемыСпособОткрытия                   - ПеречислениеСсылка.СпособыОткрытияФайлаНаПросмотр - способ
//                                                       открытия графических схем.
//    * ТекстовыеФайлыРасширение                         - Строка - расширения файлов открытого формата документов.
//    * ТекстовыеФайлыСпособОткрытия                     - ПеречислениеСсылка.СпособыОткрытияФайлаНаПросмотр - способ
//                                                       открытия текстовых файлов.
//    * МаксимальныйРазмерЛокальногоКэшаФайлов           - Число - определяет максимальный размер локального кэша файлов.
//    * ПоказыватьИнформациюЧтоФайлНеБылИзменен          - Булево - показывать файлы при завершении работы.
//    * ПоказыватьПодсказкиПриРедактированииФайлов       - Булево - а веб-клиенте показывать подсказки при
//                                                                  редактировании файлов.
//    * ПутьКЛокальномуКэшуФайлов                        - Строка - путь к локальному кэшу файлов.
//    * ЭтоПолноправныйПользователь                      - Булево - устарел, следует использовать
//                                                           ПользователиКлиент.ЭтоПолноправныйПользователь.
//    * УдалятьФайлИзЛокальногоКэшаФайловПриЗавершенииРедактирования - Булево - удаление файлов из локального кэша при
//                                                                              завершении редактирования.
//
Функция НастройкиРаботыСФайлами() Экспорт
	
	Возврат РаботаСФайламиСлужебныйПовтИсп.НастройкиРаботыСФайлами().ПерсональныеНастройки;
	
КонецФункции

// Возвращает максимальный размер файла.
//
// Возвращаемое значение:
//  Число - целое число байтов.
//
Функция МаксимальныйРазмерФайла() Экспорт
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
	
	РазделениеВключеноИДоступноИспользование = (ОбщегоНазначения.РазделениеВключено()
		И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных());
		
	ИмяКонстанты = ?(РазделениеВключеноИДоступноИспользование, "МаксимальныйРазмерФайлаОбластиДанных", "МаксимальныйРазмерФайла");
	
	МаксимальныйРазмерФайла = Константы[ИмяКонстанты].Получить();
	
	Если НЕ ЗначениеЗаполнено(МаксимальныйРазмерФайла) Тогда
		МаксимальныйРазмерФайла = 52428800; // 50*1024*1024 = 50 Мб
	КонецЕсли;
	
	Если РазделениеВключеноИДоступноИспользование Тогда
		ГлобальныйМаксимальныйРазмерФайла = Константы.МаксимальныйРазмерФайла.Получить();
		ГлобальныйМаксимальныйРазмерФайла = ?(ЗначениеЗаполнено(ГлобальныйМаксимальныйРазмерФайла),
			ГлобальныйМаксимальныйРазмерФайла, 52428800);
		МаксимальныйРазмерФайла           = Мин(МаксимальныйРазмерФайла, ГлобальныйМаксимальныйРазмерФайла);
	КонецЕсли;
	
	Возврат МаксимальныйРазмерФайла;
	
КонецФункции

// Возвращает максимальный размер файла провайдера.
//
// Возвращаемое значение:
//  Число - целое число байтов.
//
Функция МаксимальныйРазмерФайлаОбщий() Экспорт
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
	
	МаксимальныйРазмерФайла = Константы.МаксимальныйРазмерФайла.Получить();
	
	Если МаксимальныйРазмерФайла = Неопределено
	 ИЛИ МаксимальныйРазмерФайла = 0 Тогда
		
		МаксимальныйРазмерФайла = 50*1024*1024; // 50 мб
	КонецЕсли;
	
	Возврат МаксимальныйРазмерФайла;
	
КонецФункции

// Сохраняет настройки работы с файлами.
//
// Параметры:
//  НастройкиРаботыСФайлами - Структура - настройки работы с файлами с их значениями:
//     * ПоказыватьИнформациюЧтоФайлНеБылИзменен        - Булево - необязательный. Показывать сообщение, если файл не
//                                                      был изменен.
//     * ПоказыватьЗанятыеФайлыПриЗавершенииРаботы      - Булево - необязательный. Показывать файлы при завершении работы.
//     * ПоказыватьКолонкуРазмер                        - Булево - необязательный. Если принимает значение Истина, на формах
//                                                      списках файлов будет отображаться колонка Размер.
//     * ТекстовыеФайлыРасширение                       - Строка - расширения файлов открытого формата документов.
//     * ТекстовыеФайлыСпособОткрытия                   - ПеречислениеСсылка.СпособыОткрытияФайлаНаПросмотр - способ
//                                                      открытия текстовых файлов.
//     * ГрафическиеСхемыРасширение                     - Строка - список расширений графических файлов.
//     * ПоказыватьПодсказкиПриРедактированииФайлов     - Булево - необязательный. В веб-клиенте показывать подсказки
//                                                      при редактировании файлов.
//     * СпрашиватьРежимРедактированияПриОткрытииФайла  - Булево - необязательный. Выбирать режим редактирования при
//                                                      открытии файла.
//     * СпособСравненияВерсийФайлов                    - ПеречислениеСсылка.СпособыСравненияВерсийФайлов -
//                                                        необязательный. Способ сравнения версий и файлов.
//     * ДействиеПоДвойномуЩелчкуМыши                   - ПеречислениеСсылка.ДействияСФайламиПоДвойномуЩелчку - необязательный.
//     * ГрафическиеСхемыСпособОткрытия                 - ПеречислениеСсылка.СпособыОткрытияФайлаНаПросмотр -
//                                                        необязательный. Способ открытия файла на просмотр.
//
Процедура СохранитьНастройкиРаботыСФайлами(НастройкиРаботыСФайлами) Экспорт
	
	КлючиОбъектовНастроекРаботыСФайлами = КлючиОбъектовНастроекРаботыСФайлами();
	
	Для Каждого Настройка Из НастройкиРаботыСФайлами Цикл
		
		КлючОбъектаНастройки = КлючиОбъектовНастроекРаботыСФайлами[Настройка.Ключ];
		Если КлючОбъектаНастройки <> Неопределено Тогда
			Если СтрНачинаетсяС(КлючОбъектаНастройки, "НастройкиОткрытияФайлов\") Тогда
				ТипФайловНастройки = СтрЗаменить(КлючОбъектаНастройки, "НастройкиОткрытияФайлов\", "");
				ОбщегоНазначения.ХранилищеОбщихНастроекСохранить(КлючОбъектаНастройки,
					СтрЗаменить(Настройка.Ключ, ТипФайловНастройки, ""), Настройка.Значение);
			Иначе
				ОбщегоНазначения.ХранилищеОбщихНастроекСохранить(КлючОбъектаНастройки, Настройка.Ключ, Настройка.Значение);
			КонецЕсли;
			
		КонецЕсли;
	
	КонецЦикла;
	
КонецПроцедуры

// Возвращает реквизиты объекта, которые разрешается редактировать
// с помощью обработки группового изменения реквизитов.
//
// Возвращаемое значение:
//  Массив из Строка
//
Функция РеквизитыРедактируемыеВГрупповойОбработке() Экспорт
	
	РедактируемыеРеквизиты = Новый Массив;
	РедактируемыеРеквизиты.Добавить("Описание");
	РедактируемыеРеквизиты.Добавить("Редактирует");
	
	Возврат РедактируемыеРеквизиты;
	
КонецФункции

// Переносит файлы между справочниками хранения при объекте-владельце файлов и помечает 
// перенесенные файлы к удалению.
//
// Для использования в процедурах обновления ИБ, когда выполняется перенос присоединенных файлов 
// объекта-владельца между таблиц хранения файлов. Например, для справочника владельца присоединенных 
// можно осуществить перенос файлов из справочника 
// Справочник.<Имя справочника владельца>ПрисоединенныеФайлы в справочник Справочник.Файлы 
// или в обратную сторону. 
// Выполняется последовательно для каждого элемента объекта-владельца файлов
// (элемента справочника, ПВХ, документа и т.п.).
//
// Параметры:
//   ВладелецФайлов - ОпределяемыйТип.ВладелецПрисоединенныхФайлов - объект-владелец - приемник файлов.
//   Источник - Строка - если требуется конвертация из указанного хранилища.
//                       Если не заполнен, то используется первый неосновной справочник хранения.
//   Приемник - Строка - если требуется конвертация в указанное хранилище.
//                       Если не заполнен, то используется основной справочник хранения файлов.
//
// Возвращаемое значение:
//  Соответствие из КлючИЗначение:
//   * Ключ     - ОпределяемыйТип.ПрисоединенныйФайл - перенесенный файл, который помечен на удаление
//                                                     после переноса.
//   * Значение - ОпределяемыйТип.ПрисоединенныйФайл - созданный файл.
//
Функция ПеренестиФайлыМеждуСправочникамиХранения(Знач ВладелецФайлов, Знач Источник = Неопределено,
	Знач Приемник = Неопределено) Экспорт
	
	Если Не ЗначениеЗаполнено(ВладелецФайлов) Тогда
		ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не задано значение параметра %1 в %2.'"), 
				"ВладелецФайлов","РаботаСФайлами.СконвертироватьФайлыВПрисоединенные"), 
			КатегорияОшибки.ОшибкаКонфигурации);
	КонецЕсли;
	
	Если Источник = Неопределено Или Приемник = Неопределено Тогда
		ИменаСправочников = РаботаСФайламиСлужебный.ИменаСправочниковХраненияФайлов(ВладелецФайлов, Истина);
		Для каждого ИмяСправочника Из ИменаСправочников Цикл
			Если Источник = Неопределено И Не ИмяСправочника.Значение Тогда
				Источник = Метаданные.Справочники[ИмяСправочника.Ключ].ПолноеИмя();
			КонецЕсли;
			
			Если Приемник = Неопределено И ИмяСправочника.Значение Тогда
				Приемник = Метаданные.Справочники[ИмяСправочника.Ключ].ПолноеИмя();
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;

	ЗаголовокОшибки = НСтр("ru = 'Ошибка при конвертации присоединенных файлов.'");
	
	Если Источник = Приемник Тогда
		ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			ЗаголовокОшибки + Символы.ПС
				+ НСтр("ru = 'Справочник-источник присоединенных файлов ""%1"" совпадает 
			             |со справочником-приемником в %2.'"),
				Источник, "РаботаСФайлами.ПеренестиФайлыМеждуСправочникамиХранения"),
			КатегорияОшибки.ОшибкаКонфигурации);
	КонецЕсли;
	
	ИмяПриемника = Метаданные.НайтиПоПолномуИмени(Приемник).Имя;
	
	Результат = Новый Соответствие;
	ИмяСправочника = РаботаСФайламиСлужебный.ИмяСправочникаХраненияФайлов(
	ВладелецФайлов, ИмяПриемника, ЗаголовокОшибки);
	
	ФайлыИсточник = РаботаСФайламиСлужебный.ПолучитьВсеПодчиненныеФайлы(ВладелецФайлов, Источник);
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
	МенеджерПрисоединенныхФайлов = Справочники[ИмяСправочника];
	
	ДоступноВерсионирование = Метаданные.Справочники.Файлы.ПолноеИмя() = Источник;
	
	Для Каждого ФайлИсточник Из ФайлыИсточник Цикл
		НачатьТранзакцию();
		Попытка
			
			БлокировкаДанных = Новый БлокировкаДанных;
			ЭлементБлокировкиДанных = БлокировкаДанных.Добавить(Источник);
			ЭлементБлокировкиДанных.УстановитьЗначение("Ссылка", ФайлИсточник);
			БлокировкаДанных.Заблокировать();
			
			ФайлИсточникОбъект = ФайлИсточник.ПолучитьОбъект();
			Если ФайлИсточникОбъект <> Неопределено И Не ФайлИсточникОбъект.ПометкаУдаления Тогда
				
				Если ДоступноВерсионирование Тогда
					СсылкаКорректная = Истина;
					Если ЗначениеЗаполнено(ФайлИсточникОбъект.ТекущаяВерсия) Тогда
						ТекущаяВерсияОбъект = ФайлИсточникОбъект.ТекущаяВерсия.ПолучитьОбъект();
						Если ТекущаяВерсияОбъект <> Неопределено Тогда
							БлокировкаДанных = Новый БлокировкаДанных;
							ЭлементБлокировкиДанных = БлокировкаДанных.Добавить(Метаданные.Справочники.ВерсииФайлов.ПолноеИмя());
							ЭлементБлокировкиДанных.УстановитьЗначение("Ссылка", ФайлИсточникОбъект.ТекущаяВерсия);
							БлокировкаДанных.Заблокировать();
						Иначе
							СсылкаКорректная = Ложь;
						КонецЕсли;
						
					Иначе
						ТекущаяВерсияОбъект = ФайлИсточникОбъект;
					КонецЕсли;
					
					Если СсылкаКорректная Тогда
						// @skip-check query-in-loop - по-объектная запись файлов в транзакции
						СсылкаНаПрисоединенныйФайл = СоздатьПрисоединенныйФайлНаОснованииФайла(ВладелецФайлов, 
							МенеджерПрисоединенныхФайлов, ФайлИсточникОбъект, ТекущаяВерсияОбъект);
						
						Если ЗначениеЗаполнено(ФайлИсточникОбъект.ТекущаяВерсия) Тогда
							ТекущаяВерсияОбъект.ДополнительныеСвойства.Вставить("КонвертацияФайлов", Истина);
							ТекущаяВерсияОбъект.Записать();
						КонецЕсли;
						
						ФайлИсточникОбъект.ДополнительныеСвойства.Вставить("КонвертацияФайлов", Истина);
						ФайлИсточникОбъект.Записать();
						Результат.Вставить(ФайлИсточникОбъект.Ссылка, СсылкаНаПрисоединенныйФайл);
					КонецЕсли;
				Иначе
					// @skip-check query-in-loop - по-объектная запись файлов в транзакции
					СсылкаНаПрисоединенныйФайл = СоздатьПрисоединенныйФайлНаОснованииФайла(ВладелецФайлов, 
						МенеджерПрисоединенныхФайлов, ФайлИсточникОбъект);
					
					ФайлИсточникОбъект.ДополнительныеСвойства.Вставить("КонвертацияФайлов", Истина);
					ФайлИсточникОбъект.Записать();
					Результат.Вставить(ФайлИсточникОбъект.Ссылка, СсылкаНаПрисоединенныйФайл);
				КонецЕсли;
			КонецЕсли;
			
			ЗафиксироватьТранзакцию();
			
		Исключение
			ОтменитьТранзакцию();
			ВызватьИсключение;
		КонецПопытки;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

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

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

// Инициализирует структуру параметров для размещения гиперссылки присоединенных файлов на форме.
//
// Возвращаемое значение:
//  Структура - параметры размещения гиперссылки. Свойства:
//    * Владелец                   - Строка - имя реквизита, содержащего ссылку на владельца присоединенных файлов.
//                                 Значение по умолчанию - "Объект.Ссылка".
//    * Размещение                 - Строка
//                                 - Неопределено - если указано имя группы формы или командная панель,
//                                 гиперссылка будет помещена в указанную группу или панель. Если указано имя элемента
//                                 формы, гиперссылка будет вставлена перед указанным элементом. Если значение
//                                 параметра - Неопределено или элемент не найден, гиперссылка будет добавлена на форму
//                                 после всех существующих элементов.
//                                 Значение по умолчанию - "УправлениеПрисоединеннымиФайлами".
//    * Заголовок                  - Строка - заголовок гиперссылки. Значение по умолчанию - "Файлы".
//    * ОтображатьЗаголовокСправа  - Булево - если параметр принимает значение Истина, заголовок
//                                 будет отображаться после команд добавления, иначе - перед командами добавления.
//                                 Значение по умолчанию - Истина;
//    * ОтображатьКоличество       - Булево - если параметр принимает значение Истина, отображает
//                                 количество присоединенных файлов в заголовке. Значение по умолчанию - Истина.
//    * ДобавлятьФайлы             - Булево - если указать Ложь, команды добавления файлов будут отсутствовать.
//                                 Значение по умолчанию - Истина.
//    * ОтображениеФигуры          - Строка - строковое представление свойства "ОтображениеФигуры" для
//                                 команд добавления присоединенных файлов. Значение по умолчанию - "Авто".
//    * Видимость                  - Булево - если параметр принимает значение Ложь, гиперссылка на форме размещаться
//                                 не будет. Параметр имеет смысл только для глобального отключения видимости
//                                 в процедуре РаботаСФайламиПереопределяемый.ПриОпределенииГиперссылкиФайлов.
//
Функция ГиперссылкаФайлов() Экспорт
	
	ПараметрыГиперссылки = Новый Структура;
	ПараметрыГиперссылки.Вставить("Владелец",                  "Объект.Ссылка");
	ПараметрыГиперссылки.Вставить("Размещение",                "УправлениеПрисоединеннымиФайлами");
	ПараметрыГиперссылки.Вставить("Заголовок",                 НСтр("ru = 'Файлы'"));
	ПараметрыГиперссылки.Вставить("ОтображатьЗаголовокСправа", Истина);
	ПараметрыГиперссылки.Вставить("ОтображатьКоличество",      Истина);
	ПараметрыГиперссылки.Вставить("ДобавлятьФайлы",            Истина);
	ПараметрыГиперссылки.Вставить("ОтображениеФигуры",         "Авто");
	ПараметрыГиперссылки.Вставить("Видимость",                 Истина);
	
	РаботаСФайламиПереопределяемый.ПриОпределенииГиперссылкиФайлов(ПараметрыГиперссылки);
	
	Возврат ПараметрыГиперссылки;
	
КонецФункции

// Инициализирует структуру параметров для размещения поля присоединенного файла на форме.
//
// Возвращаемое значение:
//  Структура - параметры размещения гиперссылки. Свойства:
//    * Владелец                  - Строка - имя реквизита, содержащего ссылку на владельца присоединенных файлов.
//                                Значение по умолчанию - "Объект.Ссылка".
//    * Размещение                - Строка
//                                - Неопределено - если указано имя группы формы, поле будет
//                                размещено в указанной группе. Если указано имя элемента формы, поле будет
//                                вставлено перед указанным элементом. Если значение параметра - Неопределено
//                                или элемент не найден, поле будет добавлено на форму после всех существующих
//                                элементов. Значение по умолчанию - "УправлениеПрисоединеннымиФайлами".
//    * ПутьКДанным               - Строка
//                                - Неопределено - имя реквизита формы, содержащего ссылку на файл для
//                                отображения. Если параметр принимает значение Неопределено или реквизит не найден,
//                                добавляет реквизит формы с именем "ПолеПрисоединенногоФайла" и типом
//                                "ОпределяемыйТип.ПрисоединенныйФайл". Значение по умолчанию - "ПолеПрисоединенногоФайла".
//    * ПутьКДаннымИзображения    - Строка
//                                - Неопределено - имя реквизита формы, содержащего изображение, которое будет
//                                выведено в поле предпросмотра. Если параметр принимает значение Неопределено или реквизит
//                                не найден, добавляет реквизит формы с именем "ПолеКартинкиПрисоединенногоФайла" и типом
//                                "Строка". Значение по умолчанию - Неопределено.
//    * ТолькоОдинФайл            - Булево - если указать Истина, с помощью команд добавления можно будет
//                                присоединить только один файл. После добавления первого файла, команда "Добавить"
//                                будет заменять существующий файл на файл, выбранный пользователем, а нажатие на 
//                                заголовок приведет к открытию файла для просмотра. Значение по умолчанию - Ложь.
//    * ПоказыватьПредпросмотр    - Булево - если параметр принимает значение Истина, добавляет на форму
//                                область предпросмотра присоединенного файла. Значение по умолчанию - Истина.
//    * ТекстНевыбраннойКартинки  - Строка - выводится в поле предпросмотра изображения, если 
//                                изображение отсутствует. Значение по умолчанию - "Добавить изображение".
//    * Заголовок                 - Строка - если заголовок отличается от пустой строки, добавляет на форму заголовок
//                                поля присоединенного файла. Значение по умолчанию - "".
//    * ВыводитьЗаголовокФайла    - Булево - если параметр принимает значение Истина, добавляет гиперссылку
//                                заголовок которой соответствует краткому имени файла. Если значение параметра
//                                "Заголовок" отличается от "", заголовок файла будет добавлен после общего заголовка
//                                элемента управления. Значение по умолчанию - Ложь.
//    * ПоказыватьКоманднуюПанель - Булево - если параметр принимает значение Истина, команды будут размещены в 
//                                командной панели на форме и в контекстном меню элемента предпросмотра, иначе -
//                                только в контекстном меню элемента предпросмотра. Значение по умолчанию - Истина.
//    * ДобавлятьФайлы            - Булево - если указать Ложь, команды добавления файлов будут отсутствовать.
//                                Значение по умолчанию - Истина.
//    * ВыбиратьФайл              - Булево - если параметр принимает значение Истина, добавляет команду выбора файла
//                                из присоединенных. Значение по умолчанию - Истина.
//    * ПросматриватьФайл         - Булево - если параметр принимает значение Истина, добавляет команду открытия
//                                файла для просмотра. Значение по умолчанию - Истина.
//    * РедактироватьФайл         - Строка - если параметр принимает значение "ВФорме", добавляет команду
//                                открытия формы присоединенного файла. Если параметр принимает значение
//                                "Непосредственно", добавляет команды редактирования файла, сохранения и отмены
//                                изменений. Если принимает значение "НеРедактировать", команды редактирования добавлены
//                                не будут. Значение по умолчанию - "ВФорме".
//    * ОчищатьФайл               - Булево - если параметр принимает значение Истина, добавляет команду очистки 
//                                реквизита-владельца. Значение по умолчанию - Истина.
//    * МаксимальныйРазмер        - Число - ограничение на размер файла (в мегабайтах), загружаемого из файловой системы.
//                                Если принимает значение 0, проверка размера не проводится. Свойство игнорируется,
//                                если принимает значение больше, чем указано в константе МаксимальныйРазмерФайла.
//                                Значение по умолчанию - 0.
//    * ФильтрДиалогаВыбора       - Строка - фильтр, устанавливаемый в диалог выбора при добавлении файла.
//                                Формат см. в свойстве Фильтр объекта ДиалогВыбораФайла в синтакс-помощнике.
//                                Значение по умолчанию - "Все файлы (*.*)|*.*"
//
Функция ПолеФайла() Экспорт
	
	ПараметрыПоля = Новый Структура;
	ПараметрыПоля.Вставить("Владелец",                  "Объект.Ссылка");
	ПараметрыПоля.Вставить("Размещение",                "УправлениеПрисоединеннымиФайлами");
	ПараметрыПоля.Вставить("ПутьКДанным",               "ПолеПрисоединенногоФайла");
	ПараметрыПоля.Вставить("ПутьКДаннымИзображения",    Неопределено);
	ПараметрыПоля.Вставить("ТолькоОдинФайл",            Ложь);
	ПараметрыПоля.Вставить("ПоказыватьПредпросмотр",    Истина);
	ПараметрыПоля.Вставить("ТекстНевыбраннойКартинки",  НСтр("ru = 'Добавить изображение'"));
	ПараметрыПоля.Вставить("Заголовок",                 "");
	ПараметрыПоля.Вставить("ВыводитьЗаголовокФайла",    Ложь);
	ПараметрыПоля.Вставить("ПоказыватьКоманднуюПанель", Истина);
	ПараметрыПоля.Вставить("ДобавлятьФайлы",            Истина);
	ПараметрыПоля.Вставить("ВыбиратьФайл",              Истина);
	ПараметрыПоля.Вставить("ПросматриватьФайл",         Истина);
	ПараметрыПоля.Вставить("РедактироватьФайл",         "ВФорме");
	ПараметрыПоля.Вставить("ОчищатьФайл",               Истина);
	ПараметрыПоля.Вставить("МаксимальныйРазмер",        0);
	ПараметрыПоля.Вставить("ФильтрДиалогаВыбора", 
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Все файлы (%1)|%1'"), ПолучитьМаскуВсеФайлы()));
	
	Возврат ПараметрыПоля;
	
КонецФункции

// Определяет наличие активных томов хранения файлов.
// Если есть хоть один том хранения файлов, то будет возвращена Истина.
//
// Возвращаемое значение:
//  Булево - если Истина, тогда существует хотя бы один работающий том.
//
Функция ЕстьТомаХраненияФайлов() Экспорт
	
	Возврат РаботаСФайламиВТомахСлужебный.ЕстьТомаХраненияФайлов();
	
КонецФункции

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

// При программном копировании Источника создает у Получателя копии всех
// присоединенных файлов. Для интерактивного копирования необходимо использовать
// процедуру РаботаСФайлами.ПриЗаписиНаСервере.
// Источник и Получатель должны быть объектами одного типа.
//
// Параметры:
//  Источник   - ЛюбаяСсылка - объект, имеющий присоединенные файлы для копирования.
//  Получатель - ЛюбаяСсылка - объект, к которому копируются присоединенные файлы.
//
Процедура СкопироватьПрисоединенныеФайлы(Знач Источник, Знач Получатель) Экспорт
	
	РаботаСФайламиСлужебный.СкопироватьПрисоединенныеФайлы(Источник, Получатель);
	
КонецПроцедуры

// Инициализирует структуру параметров для настройки работы с файлами в форме.
//
// Возвращаемое значение:
//  Структура - параметры копирования файлов. Свойства:
//    * КопироватьПрисоединенныеФайлы - Булево - признак копирования присоединенных файлов при копировании объекта-владельца
//                                   Значение по умолчанию - Ложь.
//
Функция НастройкиРаботыСФайламиВФорме() Экспорт
	
	НастройкиРаботыСФайламиВФорме = Новый Структура;
	НастройкиРаботыСФайламиВФорме.Вставить("КопироватьПрисоединенныеФайлы", Ложь);
	
	Возврат НастройкиРаботыСФайламиВФорме;
	
КонецФункции

// Получает настройки сканирования пользователя.
// 
// Параметры:
//  ИдентификаторКлиента - УникальныйИдентификатор - идентификатор клиента
// 
// Возвращаемое значение:
//   см. РаботаСФайламиКлиентСервер.НастройкиСканированияПользователя
//
Функция ПолучитьНастройкиСканированияПользователя(ИдентификаторКлиента) Экспорт
	
	Результат = РаботаСФайламиКлиентСервер.НастройкиСканированияПользователя();
	
	Результат.ПоказыватьДиалогСканера = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/ПоказыватьДиалогСканера", 
		ИдентификаторКлиента, Истина);
	
	Результат.ИмяУстройства = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/ИмяУстройства", 
		ИдентификаторКлиента, "");
	
	Результат.ФорматСканированногоИзображения = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/ФорматСканированногоИзображения", 
		ИдентификаторКлиента, Перечисления.ФорматыСканированногоИзображения.PNG);
	Если Результат.ФорматСканированногоИзображения = Перечисления.ФорматыСканированногоИзображения.ПустаяСсылка() Тогда
		Результат.ФорматСканированногоИзображения = Перечисления.ФорматыСканированногоИзображения.PNG;	
	КонецЕсли;
	
	Результат.СохранятьВPDF = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/СохранятьВPDF", 
		ИдентификаторКлиента, Ложь);
	
	Результат.ФорматХраненияМногостраничный = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/ФорматХраненияМногостраничный", 
		ИдентификаторКлиента, Перечисления.ФорматыХраненияМногостраничныхФайлов.TIF);
	
	Результат.Разрешение = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/Разрешение", 
		ИдентификаторКлиента);
	
	Результат.Цветность = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/Цветность", 
		ИдентификаторКлиента);
	
	Результат.Поворот = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/Поворот", 
		ИдентификаторКлиента);
	
	Результат.РазмерБумаги = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/РазмерБумаги", 
		ИдентификаторКлиента);
	
	Результат.ДвустороннееСканирование = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/ДвустороннееСканирование", 
		ИдентификаторКлиента, Ложь);
	
	Результат.АвтоматическаяПодачаДокументов = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/АвтоматическаяПодачаДокументов", 
		ИдентификаторКлиента, Ложь);

	Результат.ИспользоватьImageMagickДляПреобразованияВPDF =  ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/ИспользоватьImageMagickДляПреобразованияВPDF", 
		ИдентификаторКлиента, Ложь);
		
	Результат.КачествоJPG = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/КачествоJPG", 
		ИдентификаторКлиента, 100);
	
	Результат.СжатиеTIFF = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/СжатиеTIFF", 
		ИдентификаторКлиента, Перечисления.ВариантыСжатияTIFF.БезСжатия);
	
	Результат.ПутьКПрограммеКонвертации = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/ПутьКПрограммеКонвертации", 
		ИдентификаторКлиента, ""); // ImageMagick
		
	Результат.КаталогЖурналаСканирования = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/КаталогЖурналаСканирования", 
		ИдентификаторКлиента, ""); 
		
	Результат.ИспользоватьКаталогЖурналаСканирования = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"НастройкиСканирования/ИспользоватьКаталогЖурналаСканирования", 
		ИдентификаторКлиента, Ложь);
		
	Возврат Результат;
КонецФункции

// Сохраняет настройки сканирования пользователя.
//
// Параметры:
//  НастройкиСканированияПользователя - см. РаботаСФайламиКлиентСервер.НастройкиСканированияПользователя
//  ИдентификаторКлиента - УникальныйИдентификатор
//
Процедура СохранитьНастройкиСканированияПользователя(НастройкиСканированияПользователя, ИдентификаторКлиента) Экспорт

	Результат = Новый Массив;
	
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("ПоказыватьДиалогСканера",
		НастройкиСканированияПользователя.ПоказыватьДиалогСканера, ИдентификаторКлиента));
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("ИмяУстройства",
		НастройкиСканированияПользователя.ИмяУстройства, ИдентификаторКлиента));
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("ФорматСканированногоИзображения",
		НастройкиСканированияПользователя.ФорматСканированногоИзображения, ИдентификаторКлиента));
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("СохранятьВPDF",
		НастройкиСканированияПользователя.СохранятьВPDF, ИдентификаторКлиента));
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("ФорматХраненияМногостраничный",
		НастройкиСканированияПользователя.ФорматХраненияМногостраничный, ИдентификаторКлиента));
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("Разрешение",
		НастройкиСканированияПользователя.Разрешение, ИдентификаторКлиента));
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("Цветность",
		НастройкиСканированияПользователя.Цветность, ИдентификаторКлиента));
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("Поворот",
		НастройкиСканированияПользователя.Поворот, ИдентификаторКлиента));
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("РазмерБумаги",
		НастройкиСканированияПользователя.РазмерБумаги, ИдентификаторКлиента));
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("ДвустороннееСканирование",
		НастройкиСканированияПользователя.ДвустороннееСканирование, ИдентификаторКлиента));
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("АвтоматическаяПодачаДокументов",
		НастройкиСканированияПользователя.АвтоматическаяПодачаДокументов, ИдентификаторКлиента));
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("ИспользоватьImageMagickДляПреобразованияВPDF",
		НастройкиСканированияПользователя.ИспользоватьImageMagickДляПреобразованияВPDF, ИдентификаторКлиента));
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("КачествоJPG",
		НастройкиСканированияПользователя.КачествоJPG, ИдентификаторКлиента));
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("СжатиеTIFF",
		НастройкиСканированияПользователя.СжатиеTIFF, ИдентификаторКлиента));
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("ПутьКПрограммеКонвертации",
		НастройкиСканированияПользователя.ПутьКПрограммеКонвертации, ИдентификаторКлиента));
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("КаталогЖурналаСканирования",
		НастройкиСканированияПользователя.КаталогЖурналаСканирования, ИдентификаторКлиента));
	Результат.Добавить(РаботаСФайламиСлужебный.НастройкаСканирования("ИспользоватьКаталогЖурналаСканирования",
		НастройкиСканированияПользователя.ИспользоватьКаталогЖурналаСканирования, ИдентификаторКлиента));
	
	ОбщегоНазначения.ХранилищеОбщихНастроекСохранитьМассив(Результат, Истина);
КонецПроцедуры

#Область ДляВызоваИзДругихПодсистем

// ЭлектронноеВзаимодействие

// Следующие процедуры и функции предназначены для интеграции с 1С:Библиотека электронных документов.

// Переносит сведения об электронных подписях файла из табличной части файла в регистр сведений.
//
// Параметры:
//   Параметры - Структура - параметры выполнения отложенного обработчика обновления.
//
Процедура ПеренестиЭлектронныеПодписиИСертификатыШифрованияВРегистрыСведений(Параметры) Экспорт  // АПК:530 Обрабатывает таблицы присоединенных файлов, а не данные других подсистем.
	// Для обратной совместимости
КонецПроцедуры

// Конец ЭлектронноеВзаимодействие

#КонецОбласти

#Область УстаревшиеПроцедурыИФункции

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

// Устарела. Следует использовать РаботаСФайламиКлиентСервер.ОпределитьФормуПрисоединенногоФайла.
// Обработчик подписки на событие ОбработкаПолученияФормы для переопределения формы файла.
//
// Параметры:
//  Источник                 - СправочникМенеджер - менеджер справочника с именем "*ПрисоединенныеФайлы".
//  ВидФормы                 - Строка - имя стандартной формы.
//  Параметры                - Структура - параметры формы.
//  ВыбраннаяФорма           - Строка - имя или объект метаданных открываемой формы.
//  ДополнительнаяИнформация - Структура - дополнительная информация открытия формы.
//  СтандартнаяОбработка     - Булево - признак выполнения стандартной (системной) обработки события.
//
Процедура ОпределитьФормуПрисоединенногоФайла(Источник, ВидФормы, Параметры,
	ВыбраннаяФорма, ДополнительнаяИнформация, СтандартнаяОбработка) Экспорт
	
	РаботаСФайламиКлиентСервер.ОпределитьФормуПрисоединенногоФайла(
		Источник, ВидФормы, Параметры, ВыбраннаяФорма, ДополнительнаяИнформация, СтандартнаяОбработка);
	
КонецПроцедуры

// Устарела. Следует использовать СконвертироватьФайлыВПрисоединенные.
//
// Переносит файлы из справочника Файлы в присоединенные файлы при объекте-владельце файлов и помечает 
// перенесенные файлы к удалению.
//
// Для использования в процедурах обновления ИБ.
// Выполняется последовательно для каждого элемента объекта-владельца файлов
// (элемента справочника, ПВХ, документа и т.п.).
//
// Параметры:
//   ВладелецФайлов - ЛюбаяСсылка - ссылка на объект, для которого выполняется конвертация.
//   ИмяСправочника - Строка - если требуется конвертация в указанное хранилище.
//
Процедура ИзменитьСправочникХраненияФайлов(Знач ВладелецФайлов, ИмяСправочника = Неопределено) Экспорт
	
	Если Не ЗначениеЗаполнено(ВладелецФайлов) Тогда
		ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не задано значение параметра %1 в %2.'"), 
				"ВладелецФайлов","РаботаСФайлами.ИзменитьСправочникХраненияФайлов"),
			КатегорияОшибки.ОшибкаКонфигурации);
	КонецЕсли;
	
	ЗаголовокОшибки = НСтр("ru = 'Ошибка при конвертации присоединенных файлов.'");
	ИмяСправочника = РаботаСФайламиСлужебный.ИмяСправочникаХраненияФайлов(
		ВладелецФайлов, ИмяСправочника, ЗаголовокОшибки);
	
	УстановитьОтключениеБезопасногоРежима(Истина);	
	УстановитьПривилегированныйРежим(Истина);
	
	ФайлыИсточник = РаботаСФайламиСлужебный.ПолучитьВсеПодчиненныеФайлы(ВладелецФайлов);
	МенеджерПрисоединенныхФайлов = Справочники[ИмяСправочника];
	
	Для Каждого ФайлИсточник Из ФайлыИсточник Цикл
		НачатьТранзакцию();
		Попытка
		
			БлокировкаДанных = Новый БлокировкаДанных;
			ЭлементБлокировкиДанных = БлокировкаДанных.Добавить(Метаданные.Справочники.Файлы.ПолноеИмя());
			ЭлементБлокировкиДанных.УстановитьЗначение("Ссылка", ФайлИсточник);
			БлокировкаДанных.Заблокировать();

			ФайлИсточникОбъект = ФайлИсточник.ПолучитьОбъект();
			Если ФайлИсточникОбъект = Неопределено Или ФайлИсточникОбъект.ПометкаУдаления Тогда
				ЗафиксироватьТранзакцию();
				Продолжить;
			КонецЕсли;
			
			Если ЗначениеЗаполнено(ФайлИсточникОбъект.ТекущаяВерсия) Тогда
				БлокировкаДанных = Новый БлокировкаДанных;
				ЭлементБлокировкиДанных = БлокировкаДанных.Добавить(Метаданные.Справочники.ВерсииФайлов.ПолноеИмя());
				ЭлементБлокировкиДанных.УстановитьЗначение("Ссылка", ФайлИсточникОбъект.ТекущаяВерсия);
				БлокировкаДанных.Заблокировать();
				
				ТекущаяВерсияОбъект = ФайлИсточникОбъект.ТекущаяВерсия.ПолучитьОбъект();
			Иначе
				ТекущаяВерсияОбъект = ФайлИсточникОбъект;
			КонецЕсли;
			
			СсылкаНового = МенеджерПрисоединенныхФайлов.ПолучитьСсылку();
			ПрисоединенныйФайл = МенеджерПрисоединенныхФайлов.СоздатьЭлемент(); // ОпределяемыйТип.ПрисоединенныйФайлОбъект
			ПрисоединенныйФайл.УстановитьСсылкуНового(СсылкаНового);
			
			ПрисоединенныйФайл.ВладелецФайла                = ВладелецФайлов;
			ПрисоединенныйФайл.Наименование                 = ФайлИсточникОбъект.Наименование;
			ПрисоединенныйФайл.Автор                        = ФайлИсточникОбъект.Автор;
			ПрисоединенныйФайл.ДатаМодификацииУниверсальная = ТекущаяВерсияОбъект.ДатаМодификацииУниверсальная;
			ПрисоединенныйФайл.ДатаСоздания                 = ФайлИсточникОбъект.ДатаСоздания;
			
			ПрисоединенныйФайл.Зашифрован                   = ФайлИсточникОбъект.Зашифрован;
			ПрисоединенныйФайл.Изменил                      = ТекущаяВерсияОбъект.Автор;
			ПрисоединенныйФайл.Описание                     = ФайлИсточникОбъект.Описание;
			ПрисоединенныйФайл.ПодписанЭП                   = ФайлИсточникОбъект.ПодписанЭП;
			ПрисоединенныйФайл.Размер                       = ТекущаяВерсияОбъект.Размер;
			
			ПрисоединенныйФайл.Расширение                   = ТекущаяВерсияОбъект.Расширение;
			ПрисоединенныйФайл.Редактирует                  = ФайлИсточникОбъект.Редактирует;
			ПрисоединенныйФайл.ТекстХранилище               = ФайлИсточникОбъект.ТекстХранилище;
			ПрисоединенныйФайл.ТипХраненияФайла             = ТекущаяВерсияОбъект.ТипХраненияФайла;
			ПрисоединенныйФайл.ПометкаУдаления              = ФайлИсточникОбъект.ПометкаУдаления;
			
			// Если файл хранится на томе - делается ссылка на существующий файл.
			ПрисоединенныйФайл.Том                          = ТекущаяВерсияОбъект.Том;
			ПрисоединенныйФайл.ПутьКФайлу                   = ТекущаяВерсияОбъект.ПутьКФайлу;
			
			Для Каждого СертификатШифрованияСтрока Из ФайлИсточникОбъект.УдалитьСертификатыШифрования Цикл
				НоваяСтрока = ПрисоединенныйФайл.УдалитьСертификатыШифрования.Добавить();
				ЗаполнитьЗначенияСвойств(НоваяСтрока, СертификатШифрованияСтрока);
			КонецЦикла;
			
			Если ЗначениеЗаполнено(ФайлИсточникОбъект.ТекущаяВерсия) Тогда
				Для Каждого ЭПСтрока Из ТекущаяВерсияОбъект.УдалитьЭлектронныеПодписи Цикл
					НоваяСтрока = ПрисоединенныйФайл.УдалитьЭлектронныеПодписи.Добавить();
					ЗаполнитьЗначенияСвойств(НоваяСтрока, ЭПСтрока);
				КонецЦикла;
			КонецЕсли;
			ПрисоединенныйФайл.Заполнить(Неопределено);
			
			ПрисоединенныйФайл.Записать();
			
			Если ПрисоединенныйФайл.ТипХраненияФайла = Перечисления.ТипыХраненияФайлов.ВИнформационнойБазе Тогда
				// @skip-check query-in-loop - по-объектная запись данных 
				ХранилищеФайла = ХранилищеФайлаИзИнформационнойБазы(ТекущаяВерсияОбъект.Ссылка);
				
				РегистрыСведений.ХранилищеФайлов.ЗаписатьДвоичныеДанные(СсылкаНового, ХранилищеФайла.Получить());
			КонецЕсли;
			
			ТекущаяВерсияОбъект.ПометкаУдаления = Истина;
			ФайлИсточникОбъект.ПометкаУдаления = Истина;
			
			// Удаление ссылок на том в старом файле, что бы при удалении, файлы остались на месте.
			Если ТекущаяВерсияОбъект.ТипХраненияФайла = Перечисления.ТипыХраненияФайлов.ВТомахНаДиске Тогда
				ТекущаяВерсияОбъект.ПутьКФайлу = "";
				ТекущаяВерсияОбъект.Том = Справочники.ТомаХраненияФайлов.ПустаяСсылка();
				ФайлИсточникОбъект.ПутьКФайлу = "";
				ФайлИсточникОбъект.Том = "";
				Если ЗначениеЗаполнено(ФайлИсточникОбъект.ТекущаяВерсия) Тогда
					РаботаСФайламиСлужебный.ПометитьНаУдалениеВерсииФайла(ФайлИсточникОбъект.Ссылка, ТекущаяВерсияОбъект.Ссылка);
				КонецЕсли;
			КонецЕсли;
			
			Если ЗначениеЗаполнено(ФайлИсточникОбъект.ТекущаяВерсия) Тогда
				ТекущаяВерсияОбъект.ДополнительныеСвойства.Вставить("КонвертацияФайлов", Истина);
				ТекущаяВерсияОбъект.Записать();
			КонецЕсли;
			
			ФайлИсточникОбъект.ДополнительныеСвойства.Вставить("КонвертацияФайлов", Истина);
			ФайлИсточникОбъект.Записать();
			
			ЗафиксироватьТранзакцию();
		
		Исключение
			ОтменитьТранзакцию();
			ВызватьИсключение;
		КонецПопытки;
	КонецЦикла;
	
КонецПроцедуры

// Устарела. Следует использовать РаботаСФайлами.ПеренестиФайлыМеждуСправочникамиХранения. 
// Переносит файлы из справочника Файлы в присоединенные файлы при объекте-владельце файлов и помечает 
// перенесенные файлы к удалению.
//
// Для использования в процедурах обновления ИБ, если выполняется переход от использования
// хранения файлов в справочнике Файлы на хранение файлов как присоединенных при объекте-владельце файлов.
// Выполняется последовательно для каждого элемента объекта-владельца файлов
// (элемента справочника, ПВХ, документа и т.п.).
//
// Параметры:
//   ВладелецФайлов - ОпределяемыйТип.ВладелецПрисоединенныхФайлов - объект-владелец - приемник файлов.
//   ИмяСправочника - Строка - если требуется конвертация в указанное хранилище.
//
// Возвращаемое значение:
//  Соответствие из КлючИЗначение:
//   * Ключ     - СправочникСсылка.Файлы - перенесенный файл, который помечен на удаление после переноса.
//   * Значение - ОпределяемыйТип.ПрисоединенныйФайл - созданный файл.
//
Функция СконвертироватьФайлыВПрисоединенные(Знач ВладелецФайлов, ИмяСправочника = Неопределено) Экспорт
	
	Возврат ПеренестиФайлыМеждуСправочникамиХранения(ВладелецФайлов, Метаданные.Справочники.Файлы.ПолноеИмя(), ИмяСправочника);
	
КонецФункции

#КонецОбласти

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Функция РасширениеДляЗашифрованныхФайлов() Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		МодульЭлектроннаяПодпись = ОбщегоНазначения.ОбщийМодуль("ЭлектроннаяПодпись");
		Возврат МодульЭлектроннаяПодпись.ПерсональныеНастройки().РасширениеДляЗашифрованныхФайлов;
	Иначе
		Возврат "p7m";
	КонецЕсли;
	
КонецФункции

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

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

#Область ВспомогательныеПроцедурыИФункции

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

// Помечает/снимает пометку удаления у приложенных файлов.
Процедура ПометитьНаУдалениеПрисоединенныеФайлы(Знач Источник, ИмяСправочника = Неопределено)
	
	Если Источник.ЭтоНовый() Тогда
		Возврат;
	КонецЕсли;
	
	ИсточникСсылкаПометкаУдаления = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Источник.Ссылка, "ПометкаУдаления");	
	Если Источник.ПометкаУдаления = ИсточникСсылкаПометкаУдаления Тогда
		Возврат;
	КонецЕсли;
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
	
	ИменаСправочников = РаботаСФайламиСлужебный.ИменаСправочниковХраненияФайлов(ТипЗнч(Источник.Ссылка));
	
	ТекстыЗапроса = Новый Массив;
	ШаблонЗапроса =
		"ВЫБРАТЬ РАЗРЕШЕННЫЕ
		|	Файлы.Ссылка КАК Ссылка,
		|	Файлы.Редактирует КАК Редактирует
		|ИЗ
		|	&ИмяСправочника КАК Файлы
		|ГДЕ
		|	Файлы.ВладелецФайла = &ВладелецФайла";
	
	Для каждого ОписаниеИмениСправочника Из ИменаСправочников Цикл
		
		ПолноеИмяСправочника = "Справочник." + ОписаниеИмениСправочника.Ключ;
		ТекстЗапроса = СтрЗаменить(ШаблонЗапроса, "&ИмяСправочника", ПолноеИмяСправочника);
		Если ТекстыЗапроса.Количество() > 0 Тогда
			ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ВЫБРАТЬ РАЗРЕШЕННЫЕ", "ВЫБРАТЬ"); // @query-part-1, @query-part-2
		КонецЕсли;
		ТекстыЗапроса.Добавить(ТекстЗапроса);
		
	КонецЦикла;
	
	Запрос = Новый Запрос(СтрСоединить(ТекстыЗапроса, Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС + Символы.ПС)); // @query-part
	Запрос.УстановитьПараметр("ВладелецФайла", Источник.Ссылка);
	
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Если Источник.ПометкаУдаления И ЗначениеЗаполнено(Выборка.Редактирует) Тогда
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = '""%1"" не может быть удален,
				           |т.к. содержит занятый для редактирования присоединенный файл ""%2"".'"),
				ОбщегоНазначения.ПредметСтрокой(Источник.Ссылка),
				Строка(Выборка.Ссылка));
		КонецЕсли;
		
		НачатьТранзакцию();
		Попытка
			Блокировка = Новый БлокировкаДанных();
			ЭлементБлокировки = Блокировка.Добавить(Выборка.Ссылка.Метаданные().ПолноеИмя());
			ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Ссылка);
			Блокировка.Заблокировать();
			
			ФайлОбъект = Выборка.Ссылка.ПолучитьОбъект();
			ФайлОбъект.Заблокировать();
			ФайлОбъект.УстановитьПометкуУдаления(Источник.ПометкаУдаления);
			
			ЗафиксироватьТранзакцию();
		Исключение
			ОтменитьТранзакцию();
			ВызватьИсключение; 
		КонецПопытки
		
	КонецЦикла;
	
КонецПроцедуры

// Возвращает идентификатор владельца присоединенного файла.
Функция ПолучитьИдентификаторОбъекта(Знач ВладелецФайлов)
	
	ТекстЗапроса =
		"ВЫБРАТЬ
		|	НаличиеФайлов.ИдентификаторОбъекта
		|ИЗ
		|	РегистрСведений.НаличиеФайлов КАК НаличиеФайлов
		|ГДЕ
		|	НаличиеФайлов.ОбъектСФайлами = &ОбъектСФайлами";
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	Запрос.УстановитьПараметр("ОбъектСФайлами", ВладелецФайлов);
	РезультатВыполнения = Запрос.Выполнить();
	
	Если РезультатВыполнения.Пустой() Тогда
		Возврат "";
	КонецЕсли;
	
	Выборка = РезультатВыполнения.Выбрать();
	Выборка.Следующий();
	
	Возврат Выборка.ИдентификаторОбъекта;
	
КонецФункции

// Возвращает двоичные данные файла из информационной базы.
//
// Параметры:
//   ФайлСсылка - ссылка на файл или его версию.
//
// Возвращаемое значение:
//   ХранилищеЗначения - двоичные данные файла.
//
Функция ХранилищеФайлаИзИнформационнойБазы(ФайлСсылка) Экспорт
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	ХранилищеФайлов.ХранилищеДвоичныхДанных.ДвоичныеДанные КАК ДвоичныеДанныеФайла
	|ИЗ
	|	РегистрСведений.ХранилищеФайлов КАК ХранилищеФайлов
	|ГДЕ
	|	ХранилищеФайлов.Файл = &ФайлСсылка";
	
	Запрос.УстановитьПараметр("ФайлСсылка", ФайлСсылка);
	Выборка = Запрос.Выполнить().Выбрать();
	
	Если Выборка.Следующий() Тогда
		Возврат Выборка.ДвоичныеДанныеФайла;
	КонецЕсли;
	
	Если РаботаСФайламиСлужебныйПовтИсп.ДедупликацияВыполнена() Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	УдалитьДвоичныеДанныеФайлов.ДвоичныеДанныеФайла КАК ДвоичныеДанныеФайла
	|ИЗ
	|	РегистрСведений.УдалитьДвоичныеДанныеФайлов КАК УдалитьДвоичныеДанныеФайлов
	|ГДЕ
	|	УдалитьДвоичныеДанныеФайлов.Файл = &ФайлСсылка";
	Выборка = Запрос.Выполнить().Выбрать();
	
	Возврат ?(Выборка.Следующий(), Выборка.ДвоичныеДанныеФайла, Неопределено);
	
КонецФункции

#КонецОбласти

#Область ОбработчикиПодписокНаСобытия

// Обработчик подписки на событие ПередЗаписью для заполнения авто реквизитов присоединенного файла.
//
// Параметры:
//  Источник   - СправочникОбъект - объект справочника с именем "*ПрисоединенныеФайлы".
//  Отказ      - Булево - параметр, передаваемый в подписку на событие ПередЗаписью.
//
Процедура ВыполнитьДействияПередЗаписьюПрисоединенногоФайла(Источник, Отказ) Экспорт
	
	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;
	
	Если Источник.ДополнительныеСвойства.Свойство("КонвертацияФайлов") Тогда
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(Источник) = Тип("СправочникОбъект.ВерсииФайлов") Тогда
		Если Не Источник.ЭтоНовый() И Не Пользователи.ЭтоПолноправныйПользователь() Тогда
			ПрежниеЗначения = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Источник.Ссылка, "Автор");
			ПроверитьИзменениеАвтораФайла(ПрежниеЗначения, Источник);
		КонецЕсли;
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.ИнформационнаяБазаФайловая()
	   И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда
		МодульУправлениеДоступомСлужебный = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступомСлужебный");
		МодульУправлениеДоступомСлужебный.ЗаблокироватьРегистрыПередЗаписьюОбъектаНастройкиДоступаВФайловойИБ();
	КонецЕсли;
	
	Если Источник.ЭтоНовый() Тогда
		// Проверка права "Добавление".
		Если НЕ РаботаСФайламиСлужебный.ЕстьПраво("ДобавлениеФайлов", Источник.ВладелецФайла) Тогда
			ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Недостаточно прав для добавления файлов в папку ""%1"".'"),
				Строка(Источник.ВладелецФайла));
			ВызватьИсключение(ТекстСообщения, КатегорияОшибки.НарушениеПравДоступа);
		КонецЕсли;
	Иначе
		
		Если Пользователи.ЭтоПолноправныйПользователь() Тогда
			ПрежниеЗначения = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Источник.Ссылка, "ПометкаУдаления");
		Иначе	
			ПрежниеЗначения = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Источник.Ссылка, 
				"ПометкаУдаления, Автор, Редактирует, Изменил");
			ПроверитьИзменениеАвтораФайла(ПрежниеЗначения, Источник);
		КонецЕсли;
		
		ИзмененаПометкаУдаления = Источник.ПометкаУдаления <> ПрежниеЗначения.ПометкаУдаления;
		Если ИзмененаПометкаУдаления Тогда
			Если НЕ РаботаСФайламиСлужебный.ЕстьПраво("ПометкаУдаленияФайлов", Источник.ВладелецФайла) Тогда
				ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Недостаточно прав для пометки файлов на удаление в папке ""%1"".'"),
					Строка(Источник.ВладелецФайла));
				ВызватьИсключение(ТекстСообщения, КатегорияОшибки.НарушениеПравДоступа);
			КонецЕсли;
		КонецЕсли;
		
		Если ИзмененаПометкаУдаления И ЗначениеЗаполнено(Источник.Редактирует) Тогда
				
			Если Источник.Редактирует = Пользователи.АвторизованныйПользователь() Тогда
				ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Действие недоступно, так как файл ""%1"" занят для редактирования.'"),
					Источник.Наименование);
			Иначе
				ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Действие недоступно, так как файл ""%1"" занят для редактирования
						|пользователем %2.'"),
					Источник.Наименование, Строка(Источник.Редактирует));
			КонецЕсли;
			ВызватьИсключение ТекстСообщения;
			
		КонецЕсли;
		
		ЗаписьПодписанногоОбъекта = Ложь;
		Если Источник.ДополнительныеСвойства.Свойство("ЗаписьПодписанногоОбъекта") Тогда
			ЗаписьПодписанногоОбъекта = Источник.ДополнительныеСвойства.ЗаписьПодписанногоОбъекта;
		КонецЕсли;
		
		Если ЗаписьПодписанногоОбъекта <> Истина Тогда
			
			СтруктураРеквизитов = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Источник.Ссылка,
				"ПодписанЭП, Зашифрован, Редактирует");
			
			СсылкаПодписан    = СтруктураРеквизитов.ПодписанЭП;
			СсылкаЗашифрован  = СтруктураРеквизитов.Зашифрован;
			СсылкаЗанят       = ЗначениеЗаполнено(СтруктураРеквизитов.Редактирует);
			Занят = ЗначениеЗаполнено(Источник.Редактирует);
			
			Если Не Источник.ЭтоГруппа И Источник.ПодписанЭП И СсылкаПодписан И Занят И Не СсылкаЗанят Тогда
				ВызватьИсключение НСтр("ru = 'Подписанный файл нельзя редактировать.'");
			КонецЕсли;
			
			Если Не Источник.ЭтоГруппа И Источник.Зашифрован И СсылкаЗашифрован И Источник.ПодписанЭП И НЕ СсылкаПодписан Тогда
				ВызватьИсключение НСтр("ru = 'Зашифрованный файл нельзя подписывать.'");
			КонецЕсли;
			
		КонецЕсли;
		
		СправочникПоддерживаетВозможностьХранитьВерсии = ОбщегоНазначения.ЕстьРеквизитОбъекта("ТекущаяВерсия", 
			Метаданные.НайтиПоТипу(ТипЗнч(Источник)));
		
		Если Не Источник.ЭтоГруппа И СправочникПоддерживаетВозможностьХранитьВерсии 
			И ЗначениеЗаполнено(Источник.ТекущаяВерсия) Тогда
			
			РеквизитыТекущейВерсии = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Источник.ТекущаяВерсия, "Наименование");
			
			// Проверим равенство имени файла и его текущей версии.
			// Если имена отличаются - имя у версии должно стать как у карточки с файлом.
			Если РеквизитыТекущейВерсии.Наименование <> Источник.Наименование
			   И ЗначениеЗаполнено(Источник.ТекущаяВерсия) Тогда
				
				БлокировкаДанных = Новый БлокировкаДанных;
				ЭлементБлокировкиДанных = БлокировкаДанных.Добавить(
					Метаданные.НайтиПоТипу(ТипЗнч(Источник.ТекущаяВерсия)).ПолноеИмя());
				
				ЭлементБлокировкиДанных.УстановитьЗначение("Ссылка", Источник.ТекущаяВерсия);
				БлокировкаДанных.Заблокировать();
				
				Объект = Источник.ТекущаяВерсия.ПолучитьОбъект();
				
				Если Объект <> Неопределено Тогда
					УстановитьОтключениеБезопасногоРежима(Истина);
					УстановитьПривилегированныйРежим(Истина);
					Объект.Наименование = Источник.Наименование;
					// Чтобы не сработала подписка СкопироватьРеквизитыВерсииФайловВФайл.
					Объект.ДополнительныеСвойства.Вставить("ПереименованиеФайла", Истина);
					Объект.Записать();
					УстановитьПривилегированныйРежим(Ложь);
					УстановитьОтключениеБезопасногоРежима(Ложь);
				КонецЕсли;
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(Источник.ВладелецФайла) Тогда
		
		ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не заполнен владелец в файле
			|""%1"".'"), Источник.Наименование);
		
		Если ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы() Тогда
			ЗаписьЖурналаРегистрации(НСтр("ru = 'Файлы.Ошибка записи файла при обновлении ИБ'", ОбщегоНазначения.КодОсновногоЯзыка()),
				УровеньЖурналаРегистрации.Ошибка,, Источник.Ссылка, ОписаниеОшибки);
		Иначе
			ВызватьИсключение ОписаниеОшибки;
		КонецЕсли;
		
	КонецЕсли;
	
	Если Источник.ЭтоГруппа Тогда
		Источник.ИндексКартинки = 2;
	Иначе
		Источник.ИндексКартинки = РаботаСФайламиСлужебныйКлиентСервер.ИндексПиктограммыФайла(Источник.Расширение);
	КонецЕсли;
	
	Если Источник.ЭтоНовый() И Не ЗначениеЗаполнено(Источник.Автор) Тогда
		Источник.Автор = Пользователи.АвторизованныйПользователь();
	КонецЕсли;
	
КонецПроцедуры

// Обработчик подписки на событие ПередУдалением для удаления данных, связанных с присоединенным файлом.
//
// Параметры:
//  Источник   - СправочникОбъект - объект справочника с именем "*ПрисоединенныеФайлы".
//  Отказ      - Булево - параметр, передаваемый в подписку на событие ПередЗаписью.
//
Процедура ВыполнитьДействияПередУдалениемПрисоединенногоФайла(Источник, Отказ) Экспорт
	
	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(Источник) = Тип("СправочникОбъект.ВерсииФайлов") Тогда
		Возврат;
	КонецЕсли;
	
	РаботаСФайламиСлужебный.ПередУдалениемПрисоединенногоФайлаСервер(
		Источник.Ссылка,
		Источник.ВладелецФайла,
		Источник.Том,
		Источник.ТипХраненияФайла,
		Источник.ПутьКФайлу);
	
КонецПроцедуры

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

Процедура ЗаписатьДанныеФайлаВРегистрПриОбмене(Знач Источник)
	
	Перем ДвоичныеДанныеФайла;
	
	Если Источник.ДополнительныеСвойства.Свойство("ДвоичныеДанныеФайла", ДвоичныеДанныеФайла) Тогда
		УстановитьПривилегированныйРежим(Истина);
		РегистрыСведений.ХранилищеФайлов.ЗаписатьДвоичныеДанные(Источник.Ссылка, ДвоичныеДанныеФайла);
		УстановитьПривилегированныйРежим(Ложь);
		
		Источник.ДополнительныеСвойства.Удалить("ДвоичныеДанныеФайла");
	КонецЕсли;
	
КонецПроцедуры

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

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

// Обработчик подписки на событие ПередЗаписью владельца присоединенного файла.
// Помечает на удаление связанные файлы.
//
// Параметры:
//  Источник        - ДокументОбъект - владелец присоединенного файла.
//  Отказ           - Булево - параметр, передаваемый в подписку на событие ПередЗаписью.
//  РежимЗаписи     - Булево - параметр, передаваемый в подписку на событие ПередЗаписью.
//  РежимПроведения - Булево - параметр, передаваемый в подписку на событие ПередЗаписью.
// 
Процедура УстановитьПометкуУдаленияПрисоединенныхФайловДокументов(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
	
	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;
	
	ПометитьНаУдалениеПрисоединенныеФайлы(Источник);
	
КонецПроцедуры

Процедура ПроверитьИзменениеАвтораФайла(Знач ПрежниеЗначения, Знач Источник)
	
	ИзмененАвтор = Источник.Автор <> ПрежниеЗначения.Автор;
	Если ИзмененАвтор Тогда
		ВызватьИсключение(НСтр("ru = 'Недостаточно прав для изменения автора файла.'"), КатегорияОшибки.НарушениеПравДоступа);
	КонецЕсли;
	
	Если ТипЗнч(Источник) = Тип("СправочникОбъект.ВерсииФайлов") Тогда
		Возврат;
	КонецЕсли;
		
	ТекущийПользователь = Пользователи.АвторизованныйПользователь();
	Если Источник.Редактирует <> ПрежниеЗначения.Редактирует
		И (НедопустимыйАвтор(Источник.Редактирует, ТекущийПользователь) 
			Или НедопустимыйАвтор(ПрежниеЗначения.Редактирует, ТекущийПользователь)) Тогда
		ВызватьИсключение(НСтр("ru = 'Недостаточно прав для редактирования файла.'"), КатегорияОшибки.НарушениеПравДоступа);
	КонецЕсли;
	
	Если Источник.Изменил <> ПрежниеЗначения.Изменил
		И (НедопустимыйАвтор(Источник.Изменил, ТекущийПользователь) 
			Или НедопустимыйАвтор(ПрежниеЗначения.Изменил, ТекущийПользователь)) Тогда
		ВызватьИсключение(НСтр("ru = 'Недостаточно прав для редактирования файла.'"), КатегорияОшибки.НарушениеПравДоступа);
	КонецЕсли;

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

Функция НедопустимыйАвтор(АвторСсылка, ТекущийПользователь)
	
	// Можно изменять только с пустого значения на себя и наоборот.
	Возврат АвторСсылка <> Неопределено И Не АвторСсылка.Пустая() 
		И ТипЗнч(АвторСсылка) <> Тип("СправочникСсылка.УчетныеЗаписиСинхронизацииФайлов")
		И АвторСсылка <> ТекущийПользователь; 
	
КонецФункции	

#КонецОбласти

#Область УправлениеПрисоединеннымиФайлами

Процедура СоздатьГиперссылкуФайлов(Форма, ДобавляемыйЭлемент, ВладелецПрисоединенныхФайлов, ПараметрыГиперссылки)
	
	ИмяГруппы          = ПараметрыГиперссылки.ИмяГруппы;
	НомерЭлемента      = ПараметрыГиперссылки.НомерЭлемента;
	ДоступноДобавление = ПараметрыГиперссылки.ДоступноДобавление;

	ПрефиксКоманды             = РаботаСФайламиКлиентСервер.ПрефиксКоманд();
	ИмяКомандыЗагрузитьФайл    = РаботаСФайламиКлиентСервер.ИмяКомандыЗагрузитьФайл();
	ИмяКомандыСоздатьПоШаблону = РаботаСФайламиКлиентСервер.ИмяКомандыСоздатьПоШаблону();
	ИмяКомандыСканировать      = РаботаСФайламиКлиентСервер.ИмяКомандыСканировать();
	ИмяКомандыОткрытьСписок    = РаботаСФайламиКлиентСервер.ИмяКомандыОткрытьСписок();
	
	СвойстваКомандыФормы = Новый Структура;
	СвойстваКомандыФормы.Вставить("Отображение", ОтображениеКнопки.Текст);
	СвойстваКомандыФормы.Вставить("Действие", "Подключаемый_КомандаПанелиПрисоединенныхФайлов");
	
	Если ДобавляемыйЭлемент.Размещение = "КоманднаяПанель" Тогда
		ЭлементРазмещения = Форма.КоманднаяПанель;
	Иначе
		ЭлементРазмещения = Форма.Элементы.Найти(ДобавляемыйЭлемент.Размещение);
	КонецЕсли;
	
	ВидГруппы = ВидГруппыФормы.КоманднаяПанель;
	ЭтоГруппаКнопок = Ложь;
	Если ЭлементРазмещения <> Неопределено
		И ТипЗнч(ЭлементРазмещения) = Тип("ГруппаФормы") Тогда
		
		ЭтоГруппаКнопок = ЭлементРазмещения.Вид = ВидГруппыФормы.ГруппаКнопок
			ИЛИ ЭлементРазмещения.Вид = ВидГруппыФормы.КоманднаяПанель;
		ВидГруппы = ?(ЭтоГруппаКнопок, ВидГруппыФормы.ГруппаКнопок, ВидГруппы);
		Если ЭлементРазмещения.Вид = ВидГруппыФормы.ОбычнаяГруппа
			ИЛИ ЭлементРазмещения.Вид = ВидГруппыФормы.Страница
			ИЛИ ЭтоГруппаКнопок Тогда
			
			ЭлементРодитель   = ЭлементРазмещения;
			ЭлементРазмещения = Неопределено;
		КонецЕсли;
		
	КонецЕсли;
	
	ГруппаРазмещенияНаФорме = Форма.Элементы.Вставить(ИмяГруппы, Тип("ГруппаФормы"), 
		ЭлементРодитель, ЭлементРазмещения); // ГруппаФормы
	ГруппаРазмещенияНаФорме.Заголовок = ПараметрыГиперссылки.ЗаголовокГруппы;
	ГруппаРазмещенияНаФорме.Вид = ВидГруппы;
	
	ПодменюДобавления = Неопределено;
	Если ДобавляемыйЭлемент.ДобавлятьФайлы
		И ДоступноДобавление Тогда
		
		ПодменюДобавления = Форма.Элементы.Добавить("ПодменюДобавленияФайла" + НомерЭлемента, Тип("ГруппаФормы"),
			ГруппаРазмещенияНаФорме); // ГруппаФормы
		
		ПодменюДобавления.Вид         = ВидГруппыФормы.Подменю;
		ПодменюДобавления.Картинка    = БиблиотекаКартинок.Скрепка;
		ПодменюДобавления.Заголовок   = НСтр("ru = 'Присоединить файлы'");
		ПодменюДобавления.Подсказка   = НСтр("ru = 'Присоединить файлы'");
		ПодменюДобавления.Отображение = ОтображениеКнопки.Картинка;
		
		ЗагрузитьФайл           = Форма.Команды.Добавить(ПрефиксКоманды + ИмяКомандыЗагрузитьФайл + "_" + НомерЭлемента);
		ЗагрузитьФайл.Действие  = "Подключаемый_КомандаПанелиПрисоединенныхФайлов";
		ЗаголовокКоманды = НСтр("ru = 'Загрузить файл с компьютера'");
		ЗагрузитьФайл.Подсказка = ЗаголовокКоманды;
		ЗагрузитьФайл.Заголовок = ЗаголовокКоманды + "...";
		
		КнопкаЗагрузки = ДобавитьКнопкуНаФорму(Форма, ПрефиксКоманды + ИмяКомандыЗагрузитьФайл + НомерЭлемента, ГруппаРазмещенияНаФорме, ЗагрузитьФайл.Имя);
		КнопкаЗагрузки.Картинка    = БиблиотекаКартинок.Скрепка;
		КнопкаЗагрузки.Видимость   = Ложь;
		КнопкаЗагрузки.Отображение = ОтображениеКнопки.Картинка;
		
		Если ЗначениеЗаполнено(ДобавляемыйЭлемент.ОтображениеФигуры) Тогда
			КнопкаЗагрузки.ОтображениеФигуры = ОтображениеФигурыКнопки[ДобавляемыйЭлемент.ОтображениеФигуры];
			ПодменюДобавления.ОтображениеФигуры = ОтображениеФигурыКнопки[ДобавляемыйЭлемент.ОтображениеФигуры];
		КонецЕсли;
		
		КнопкаЗагрузкиИзПодменю = ДобавитьКнопкуНаФорму(Форма, 
			ИмяКомандыЗагрузитьФайл + ИмяДополнительнойКомандыИзПодменю() + НомерЭлемента, ПодменюДобавления, ЗагрузитьФайл.Имя);
		КнопкаЗагрузкиИзПодменю.Отображение = ОтображениеКнопки.Текст;
		
		СоздатьПоШаблону = Форма.Команды.Добавить(ПрефиксКоманды + ИмяКомандыСоздатьПоШаблону + "_" + НомерЭлемента);
		СоздатьПоШаблону.Заголовок = НСтр("ru = 'Создать по шаблону...'");
		ЗаполнитьЗначенияСвойств(СоздатьПоШаблону, СвойстваКомандыФормы);
		
		ДобавитьКнопкуНаФорму(Форма, ИмяКомандыСоздатьПоШаблону + НомерЭлемента, ПодменюДобавления, СоздатьПоШаблону.Имя);
		
		Сканировать = Форма.Команды.Добавить(ПрефиксКоманды + ИмяКомандыСканировать + "_" + НомерЭлемента);
		Сканировать.Заголовок = НСтр("ru = 'Сканировать...'");
		ЗаполнитьЗначенияСвойств(Сканировать, СвойстваКомандыФормы);
		
		ДобавитьКнопкуНаФорму(Форма, ИмяКомандыСканировать + НомерЭлемента, ПодменюДобавления, Сканировать.Имя);
		
	КонецЕсли;
	
	КомандаОткрытияСписка = Форма.Команды.Добавить(ПрефиксКоманды + ИмяКомандыОткрытьСписок + "_" + НомерЭлемента);
	ЗаполнитьЗначенияСвойств(КомандаОткрытияСписка, СвойстваКомандыФормы);
	
	Если ДобавляемыйЭлемент.ОтображатьЗаголовокСправа
		ИЛИ Не ДобавляемыйЭлемент.ДобавлятьФайлы Тогда
		ГиперссылкаПерехода = ДобавитьКнопкуНаФорму(Форма, ПрефиксКоманды + ИмяКомандыОткрытьСписок + НомерЭлемента,
			ГруппаРазмещенияНаФорме, КомандаОткрытияСписка.Имя);
	Иначе
		ГиперссылкаПерехода = Форма.Элементы.Вставить(ПрефиксКоманды + ИмяКомандыОткрытьСписок + НомерЭлемента,
			Тип("КнопкаФормы"), ГруппаРазмещенияНаФорме, ПодменюДобавления);
			
		ГиперссылкаПерехода.ИмяКоманды = КомандаОткрытияСписка.Имя;
	КонецЕсли;
	
	ГиперссылкаПерехода.Вид = ?(ЭтоГруппаКнопок, ВидКнопкиФормы.ГиперссылкаКоманднойПанели, ВидКнопкиФормы.Гиперссылка);
	ГиперссылкаПерехода.Заголовок = ДобавляемыйЭлемент.Заголовок;
	Если ДобавляемыйЭлемент.ОтображатьКоличество Тогда
		
		КоличествоПрисоединенныхФайлов = РаботаСФайламиСлужебныйВызовСервера.КоличествоПрисоединенныхФайлов(ВладелецПрисоединенныхФайлов);
		Если КоличествоПрисоединенныхФайлов > 0 Тогда
			ГиперссылкаПерехода.Заголовок = ГиперссылкаПерехода.Заголовок + " ("
				+ Формат(КоличествоПрисоединенныхФайлов, "ЧГ=") + ")";
		КонецЕсли;
		
	КонецЕсли;
			
КонецПроцедуры

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

Процедура УстановитьДоступностьРедактирования(ДанныеФайла, КнопкаРедактирования, КнопкаОтмены, КнопкаПомещения)
	
	Если ДанныеФайла <> Неопределено Тогда
		КнопкаРедактирования.Доступность = Не ДанныеФайла.ФайлРедактируется;
		КнопкаОтмены.Доступность = ДанныеФайла.ФайлРедактируется И ДанныеФайла.ФайлРедактируетТекущийПользователь;
		КнопкаПомещения.Доступность = ДанныеФайла.ФайлРедактируется И ДанныеФайла.ФайлРедактируетТекущийПользователь;
	Иначе
		КнопкаОтмены.Доступность = Ложь;
		КнопкаПомещения.Доступность = Ложь;
		КнопкаРедактирования.Доступность = Ложь;
	КонецЕсли;

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

Функция ДобавитьКнопкуНаФорму(Форма, ИмяКнопки, Родитель, ИмяКоманды)
	
	КнопкаФормы = Форма.Элементы.Добавить(ИмяКнопки, Тип("КнопкаФормы"), Родитель);
	КнопкаФормы.ИмяКоманды = ИмяКоманды;
	Возврат КнопкаФормы;
	
КонецФункции

Функция РеквизитФормыПоИмени(РеквизитыФормы, ИмяРеквизита)
	
	Для Каждого Реквизит Из РеквизитыФормы Цикл
		Если Реквизит.Имя = ИмяРеквизита Тогда
			Возврат Реквизит;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Неопределено;
	
КонецФункции

Функция ИмяДополнительнойКомандыИзПодменю()
	Возврат "ИзПодменю";
КонецФункции

#КонецОбласти

#КонецОбласти