Процедура СообщитьПользователю(
	Знач ТекстСообщенияПользователю,
	Знач КлючДанных = Неопределено,
	Знач Поле = "",
	Знач ПутьКДанным = "",
	Отказ = Ложь) Экспорт

	ЭтоОбъект = Ложь;

	Если КлючДанных <> Неопределено
		И XMLТипЗнч(КлючДанных) <> Неопределено Тогда

		ТипЗначенияСтрокой = XMLТипЗнч(КлючДанных).ИмяТипа;
		ЭтоОбъект = СтрНайти(ТипЗначенияСтрокой, "Object.") > 0;
	КонецЕсли;

	Сообщение = Новый СообщениеПользователю;
	Сообщение.Текст = ТекстСообщенияПользователю;
	Сообщение.Поле = Поле;

	Если ЭтоОбъект Тогда
		Сообщение.УстановитьДанные(КлючДанных);
	Иначе
		Сообщение.КлючДанных = КлючДанных;
	КонецЕсли;

	Если НЕ ПустаяСтрока(ПутьКДанным) Тогда
		Сообщение.ПутьКДанным = ПутьКДанным;
	КонецЕсли;

	Сообщение.Сообщить();

	Отказ = Истина;

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

// Возвращает ссылку на общий модуль по имени.
//
// Параметры:
//  Имя          - Строка - имя общего модуля, например:
//                 "ОбщегоНазначения",
//                 "ОбщегоНазначенияКлиент".
//
// Возвращаемое значение:
//  ОбщийМодуль
//

Функция ОбщийМодуль(Имя) Экспорт

	Если ЕстьБазоваяФункциональность() Тогда
		МодульОбщегоНазначения = ВычислитьВБезопасномРежиме("ОбщегоНазначения");
		Модуль = МодульОбщегоНазначения.ОбщийМодуль(Имя);
	Иначе
		Если Метаданные.ОбщиеМодули.Найти(Имя) <> Неопределено Тогда
			Модуль = ВычислитьВБезопасномРежиме(Имя);
		ИначеЕсли СтрЧислоВхождений(Имя, ".") = 1 Тогда
			Возврат СерверныйМодульМенеджера(Имя);
		Иначе
			Модуль = Неопределено;
		КонецЕсли;

		Если ТипЗнч(Модуль) <> Тип("ОбщийМодуль") Тогда
			СообщениеИсключения = НСтр("ru = 'Общий модуль ""%1"" не найден.'");
			ВызватьИсключение СтрЗаменить(СообщениеИсключения, "%1", Имя);
		КонецЕсли;
	КонецЕсли;

	Возврат Модуль;

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

// Возвращает серверный модуль менеджера по имени объекта.

Функция СерверныйМодульМенеджера(Имя)
	ОбъектНайден = Ложь;

	ЧастиИмени = СтрРазделить(Имя, ".");
	Если ЧастиИмени.Количество() = 2 Тогда

		ИмяВида = ВРег(ЧастиИмени[0]);
		ИмяОбъекта = ЧастиИмени[1];

		Если ИмяВида = ВРег(ИмяТипаКонстанты()) Тогда
			Если Метаданные.Константы.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектНайден = Истина;
			КонецЕсли;
		ИначеЕсли ИмяВида = ВРег(ИмяТипаРегистрыСведений()) Тогда
			Если Метаданные.РегистрыСведений.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектНайден = Истина;
			КонецЕсли;
		ИначеЕсли ИмяВида = ВРег(ИмяТипаРегистрыНакопления()) Тогда
			Если Метаданные.РегистрыНакопления.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектНайден = Истина;
			КонецЕсли;
		ИначеЕсли ИмяВида = ВРег(ИмяТипаРегистрыБухгалтерии()) Тогда
			Если Метаданные.РегистрыБухгалтерии.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектНайден = Истина;
			КонецЕсли;
		ИначеЕсли ИмяВида = ВРег(ИмяТипаРегистрыРасчета()) Тогда
			Если Метаданные.РегистрыРасчета.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектНайден = Истина;
			КонецЕсли;
		ИначеЕсли ИмяВида = ВРег(ИмяТипаСправочники()) Тогда
			Если Метаданные.Справочники.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектНайден = Истина;
			КонецЕсли;
		ИначеЕсли ИмяВида = ВРег(ИмяТипаДокументы()) Тогда
			Если Метаданные.Документы.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектНайден = Истина;
			КонецЕсли;
		ИначеЕсли ИмяВида = ВРег(ИмяТипаОтчеты()) Тогда
			Если Метаданные.Отчеты.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектНайден = Истина;
			КонецЕсли;
		ИначеЕсли ИмяВида = ВРег(ИмяТипаОбработки()) Тогда
			Если Метаданные.Обработки.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектНайден = Истина;
			КонецЕсли;
		ИначеЕсли ИмяВида = ВРег(ИмяТипаБизнесПроцессы()) Тогда
			Если Метаданные.БизнесПроцессы.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектНайден = Истина;
			КонецЕсли;
		ИначеЕсли ИмяВида = ВРег(ИмяТипаЖурналыДокументов()) Тогда
			Если Метаданные.ЖурналыДокументов.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектНайден = Истина;
			КонецЕсли;
		ИначеЕсли ИмяВида = ВРег(ИмяТипаЗадачи()) Тогда
			Если Метаданные.Задачи.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектНайден = Истина;
			КонецЕсли;
		ИначеЕсли ИмяВида = ВРег(ИмяТипаПланыСчетов()) Тогда
			Если Метаданные.ПланыСчетов.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектНайден = Истина;
			КонецЕсли;
		ИначеЕсли ИмяВида = ВРег(ИмяТипаПланыОбмена()) Тогда
			Если Метаданные.ПланыОбмена.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектНайден = Истина;
			КонецЕсли;
		ИначеЕсли ИмяВида = ВРег(ИмяТипаПланыВидовХарактеристик()) Тогда
			Если Метаданные.ПланыВидовХарактеристик.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектНайден = Истина;
			КонецЕсли;
		ИначеЕсли ИмяВида = ВРег(ИмяТипаПланыВидовРасчета()) Тогда
			Если Метаданные.ПланыВидовРасчета.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектНайден = Истина;
			КонецЕсли;
		КонецЕсли;

	КонецЕсли;

	Если Не ОбъектНайден Тогда
		СообщениеИсключения = НСтр("ru = 'Объект метаданных ""%1"" не найден,
			|либо для него не поддерживается получение модуля менеджера.'");
		ВызватьИсключение СтрЗаменить(СообщениеИсключения, "%1", Имя);
	КонецЕсли;

	Модуль = ВычислитьВБезопасномРежиме(Имя);

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

// Возвращает значение для идентификации общего типа "Регистры сведений".
//
// Возвращаемое значение:
//  Строка
//

Функция ИмяТипаРегистрыСведений()

	Возврат "РегистрыСведений";

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

// Возвращает значение для идентификации общего типа "Регистры накопления".
//
// Возвращаемое значение:
//  Строка
//

Функция ИмяТипаРегистрыНакопления()

	Возврат "РегистрыНакопления";

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

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

Функция ИмяТипаРегистрыБухгалтерии()

	Возврат "РегистрыБухгалтерии";

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

// Возвращает значение для идентификации общего типа "Регистры расчета".
//
// Возвращаемое значение:
//  Строка
//

Функция ИмяТипаРегистрыРасчета()

	Возврат "РегистрыРасчета";

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

// Возвращает значение для идентификации общего типа "Документы".
//
// Возвращаемое значение:
//  Строка
//

Функция ИмяТипаДокументы()

	Возврат "Документы";

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

// Возвращает значение для идентификации общего типа "Справочники".
//
// Возвращаемое значение:
//  Строка
//

Функция ИмяТипаСправочники()

	Возврат "Справочники";

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

// Возвращает значение для идентификации общего типа "Отчеты".
//
// Возвращаемое значение:
//  Строка
//

Функция ИмяТипаОтчеты()

	Возврат "Отчеты";

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

// Возвращает значение для идентификации общего типа "Обработки".
//
// Возвращаемое значение:
//  Строка
//

Функция ИмяТипаОбработки()

	Возврат "Обработки";

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

// Возвращает значение для идентификации общего типа "ПланыОбмена".
//
// Возвращаемое значение:
//  Строка
//

Функция ИмяТипаПланыОбмена()

	Возврат "ПланыОбмена";

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

// Возвращает значение для идентификации общего типа "Планы видов характеристик".
//
// Возвращаемое значение:
//  Строка
//

Функция ИмяТипаПланыВидовХарактеристик()

	Возврат "ПланыВидовХарактеристик";

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

// Возвращает значение для идентификации общего типа "Бизнес-процессы".
//
// Возвращаемое значение:
//  Строка
//

Функция ИмяТипаБизнесПроцессы()

	Возврат "БизнесПроцессы";

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

// Возвращает значение для идентификации общего типа "Задачи".
//
// Возвращаемое значение:
//  Строка
//

Функция ИмяТипаЗадачи()

	Возврат "Задачи";

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

// Возвращает значение для идентификации общего типа "Планы счетов".
//
// Возвращаемое значение:
//  Строка
//

Функция ИмяТипаПланыСчетов()

	Возврат "ПланыСчетов";

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

// Возвращает значение для идентификации общего типа "Планы видов расчета".
//
// Возвращаемое значение:
//  Строка
//

Функция ИмяТипаПланыВидовРасчета()

	Возврат "ПланыВидовРасчета";

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

// Возвращает значение для идентификации общего типа "Константы".
//
// Возвращаемое значение:
//  Строка
//

Функция ИмяТипаКонстанты()

	Возврат "Константы";

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

// Возвращает значение для идентификации общего типа "Журналы документов".
//
// Возвращаемое значение:
//  Строка
//


Функция КэшФормы(ИмяФормы, ИсточникиЧерезЗапятую, ЭтоФормаОбъекта) Экспорт
	Команды = ТаблицаКоманд();
	Источники = ДеревоИсточниковКоманд();
	НастройкиПрограммногоИнтерфейса = НастройкиПрограммногоИнтерфейсаПодключаемыхОбъектов();
	ПодключенныеОбъекты = ТаблицаПодключаемыхОбъектов(НастройкиПрограммногоИнтерфейса);

	КэшФормы = Новый Структура;
	КэшФормы.Вставить("Команды", Команды);
	КэшФормы.Вставить("ЕстьУсловияВидимости", Ложь);
	КэшФормы.Вставить("ФункциональныеОпции", Новый Структура);

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

	Если ЭтоФормаОбъекта = Истина И ТипыИсточников.Количество() = 1 И МетаданныеРодителя <> Метаданные.НайтиПоТипу(ТипыИсточников[0]) Тогда
		ЭтоФормаОбъекта = Ложь; // В форме объекта размещен список от другого типа объекта.
	КонецЕсли;

	Если ЭтоФормаОбъекта = Неопределено Тогда
		Если ТипыИсточников.Количество() > 1 Тогда
			ЭтоФормаОбъекта = Ложь;
		ИначеЕсли МетаданныеРодителя <> Неопределено Тогда
			Коллекция = Новый Структура("ОсновнаяФормаСписка, ОсновнаяФормаОбъекта");
			ЗаполнитьЗначенияСвойств(Коллекция, МетаданныеРодителя);
			Если МетаданныеФормы = Коллекция.ОсновнаяФормаСписка Тогда
				ЭтоФормаОбъекта = Ложь;
			ИначеЕсли МетаданныеФормы = Коллекция.ОсновнаяФормаОбъекта И МетаданныеРодителя <> Метаданные.НайтиПоТипу(ТипыИсточников[0]) Тогда
				ЭтоФормаОбъекта = Истина;
			Иначе
				Если ВидВРег = ВРег("ЖурналДокументов") Тогда
					ЭтоФормаОбъекта = Ложь;
				ИначеЕсли ВидВРег = ВРег("Обработка") Тогда
					ЭтоФормаОбъекта = Ложь;
				Иначе
					ЭтоФормаОбъекта = Истина;
				КонецЕсли;
			КонецЕсли;
		Иначе
			ЭтоФормаОбъекта = Ложь;
		КонецЕсли;
	КонецЕсли;
	КэшФормы.Вставить("ЭтоФормаОбъекта", ЭтоФормаОбъекта);

	Контекст = Новый Структура;
	Контекст.Вставить("ВидВРег", ВидВРег);
	Контекст.Вставить("ИмяФормы", ИмяФормы);
	Контекст.Вставить("МетаданныеФормы", МетаданныеФормы);
	Контекст.Вставить("ТипыИсточников", ТипыИсточников);
	Контекст.Вставить("ЭтоФормаОбъекта", ЭтоФормаОбъекта);
	Контекст.Вставить("ФункциональныеОпции", КэшФормы.ФункциональныеОпции);

	КэшФормы.Вставить("ВводНаОснованииЧерезПодключаемыеКоманды", СозданиеНаОсновании.ОбъектыПодключеныКПодсистеме(ТипыИсточников));
	Если КэшФормы.ВводНаОснованииЧерезПодключаемыеКоманды Тогда
		СозданиеНаОсновании.ПриОпределенииКомандПодключенныхКОбъекту(Контекст, Источники, ПодключенныеОбъекты, Команды);
	КонецЕсли;

	ЗаполнениеОбъектов.ПриОпределенииКомандПодключенныхКОбъекту(Контекст, Источники, ПодключенныеОбъекты, Команды);
	ИнтеграцияПодсистемБСП.ПриОпределенииКомандПодключенныхКОбъекту(Контекст, Источники, ПодключенныеОбъекты, Команды);
	ПодключаемыеКомандыПереопределяемый.ПриОпределенииКомандПодключенныхКОбъекту(Контекст, Источники, ПодключенныеОбъекты, Команды);

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

		// Фильтр по назначению.
		Если Команда.Назначение = "ДляСписка" И Контекст.ЭтоФормаОбъекта Или Команда.Назначение = "ДляОбъекта" И Не Контекст.ЭтоФормаОбъекта Тогда
			Команды.Удалить(Команда);
			Продолжить;
		КонецЕсли;

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

		Если ПустаяСтрока(Команда.Идентификатор) Тогда
			Команда.Идентификатор = "Авто_" + ОбщегоНазначения.КонтрольнаяСуммаСтрокой(Команда.Менеджер + "/" + Команда.ИмяФормы + "/" + Команда.Обработчик);
		КонецЕсли;
	КонецЦикла;

	Возврат КэшФормы;
КонецФункции

Процедура ПроверитьИмяВидаКоманд(ИмяВида) Экспорт

	Если Не ОбщегоНазначенияКлиентСервер.ИмяСоответствуетТребованиямИменованияСвойств(ИмяВида) Тогда
		ТекстОшибки = НСтр("ru = 'Имя вида команд ""%1"" не удовлетворяет требованиям именования переменных.'");
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, ИмяВида);
	КонецЕсли;

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

////////////////////////////////////////////////////////////////////////////////
// Вывод.

// Размещает подключенные команды в форме.
//
// Параметры:
//   Форма - ФормаКлиентскогоПриложения - форма, в которой необходимо разместить команды.
//   Команды - см. ТаблицаКоманд
//   ПараметрыРазмещения - см. ПараметрыРазмещения
//


Функция СведенияОВсехПодменю()

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

	Возврат СведенияОВсехПодменю;

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

// Возвращаемое значение:
//  Структура:
//   * Имя - Строка
//   * КомандыСУсловиямиВидимости - Массив
//   * ЕстьКомандыБезУсловийВидимости - Булево
//

Функция КраткиеСведенияОПодменю(СведенияОПодменю)
	КраткиеСведенияОПодменю = Новый Структура("Имя, КомандыСУсловиямиВидимости, ЕстьКомандыБезУсловийВидимости");
	ЗаполнитьЗначенияСвойств(КраткиеСведенияОПодменю, СведенияОПодменю);
	Возврат КраткиеСведенияОПодменю;
КонецФункции

Функция КлючПараметровРазмещения(Знач ПараметрыРазмещения)

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

	Возврат ОбщегоНазначения.КонтрольнаяСуммаСтрокой(ОбщегоНазначения.ЗначениеВСтрокуXML(ПараметрыРазмещения));

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

Процедура УдалитьКоманды(Форма, УдаляемыеКоманды)

	Для Каждого ОписаниеКоманды Из УдаляемыеКоманды Цикл
		Команда = Форма.Команды[ОписаниеКоманды.ИмяВФорме];
		Форма.Команды.Удалить(Команда);
		Форма.Элементы.Удалить(Форма.Элементы[ОписаниеКоманды.ИмяВФорме]);
	КонецЦикла;

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

Функция КоманднаяПанельФормы(Форма, ПрефиксГрупп, ЭтоФормаОбъекта)

	Элементы = Форма.Элементы;

	Результат = Элементы.Найти(ПрефиксГрупп + "ПодключаемыеКоманды");
	Если Результат = Неопределено Тогда
		Результат = Элементы.Найти(ПрефиксГрупп + "КоманднаяПанель");

		Если Результат = Неопределено Тогда
			Результат = Элементы.Найти(ПрефиксГрупп + "ОсновнаяКоманднаяПанель");

			Если Результат = Неопределено И ЗначениеЗаполнено(ПрефиксГрупп) Тогда
				ТаблицаФормы = Элементы.Найти(ПрефиксГрупп);
				Если ТипЗнч(ТаблицаФормы) = Тип("ТаблицаФормы") Тогда
					Результат = ТаблицаФормы.КоманднаяПанель;
				КонецЕсли;
			КонецЕсли;

			Если Не ЭтоФормаОбъекта
				И Результат = Неопределено
				И Не ЗначениеЗаполнено(ПрефиксГрупп) Тогда
				ТаблицаФормы = Элементы.Найти("Список");
				Если ТипЗнч(ТаблицаФормы) = Тип("ТаблицаФормы")
					И ТаблицаФормы.ПоложениеКоманднойПанели <> ПоложениеКоманднойПанелиЭлементаФормы.Нет Тогда
					Результат = ТаблицаФормы.КоманднаяПанель;
				КонецЕсли;
			КонецЕсли;

			Если Результат = Неопределено Тогда
				Результат = Форма.КоманднаяПанель;
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;

	Возврат Результат;

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

Функция ПодключенныеКоманды(Форма)

	ЗначенияСвойств = Новый Структура("ПараметрыПодключаемыхКоманд", Null);
	ЗаполнитьЗначенияСвойств(ЗначенияСвойств, Форма);

	Результат = ЗначенияСвойств.ПараметрыПодключаемыхКоманд;

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

		Результат = Новый Структура;
		Результат.Вставить("ЕстьУсловияВидимости", Ложь);
		Результат.Вставить("ПодменюСУсловиямиВидимости", Новый Массив);
		Результат.Вставить("КомандыСПометкой", Новый Массив);
		Результат.Вставить("КорневыеПодменюИКоманды", Новый Соответствие);
		Результат.Вставить("ДоступностьКоманд", Истина);
		Результат.Вставить("АдресТаблицыКоманд", Неопределено);
		Результат.Вставить("ВводНаОснованииЧерезПодключаемыеКоманды");
		Результат.Вставить("ВладельцыКоманд", Новый Массив);

		Форма.ПараметрыПодключаемыхКоманд = Результат;
	КонецЕсли;

	Возврат Результат;

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

Функция СвойстваКорневогоПодменюКоманды()

	Результат = Новый Структура;
	Результат.Вставить("ЕстьВКоманднойПанели", Ложь);
	Результат.Вставить("ПрефиксКоманд", "");
	Результат.Вставить("ДоступностьКоманд", Истина);

	Возврат Результат;

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

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

	Возврат Истина;
КонецФункции

Функция ОписаниеКомандыНаКлиенте(Команда, КнопкаФормы, ПрефиксКоманд)
	ОписаниеКоманды = Новый Структура;
	ОписаниеКоманды.Вставить("ИмяВФорме", КнопкаФормы.Имя);
	ОписаниеКоманды.Вставить("Вид", Команда.Вид);
	ОписаниеКоманды.Вставить("Идентификатор", Команда.Идентификатор);
	ОписаниеКоманды.Вставить("ЗначениеПометки", Команда.ЗначениеПометки);
	ОписаниеКоманды.Вставить("ПрефиксКоманд", ПрефиксКоманд);
	Возврат ОписаниеКоманды;
КонецФункции


Процедура ДобавитьАдминистраторамПравоОткрытияВнешнихОтчетовИОбработок() Экспорт

	ДобавляемаяРоль = Метаданные.Роли.ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок;
	РольАдминистратора = Метаданные.Роли.АдминистраторСистемы;
	ПользователиИБ = ПользователиИнформационнойБазы.ПолучитьПользователей();

	Для Каждого ПользовательИБ Из ПользователиИБ Цикл

		Если ПользовательИБ.Роли.Содержит(РольАдминистратора)
		   И Не ПользовательИБ.Роли.Содержит(ДобавляемаяРоль) Тогда

			ПользовательИБ.Роли.Добавить(ДобавляемаяРоль);
			ПользовательИБ.Записать();
		КонецЕсли;

	КонецЦикла;

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

// Вызывается при переходе на новую версию конфигурации 2.4.1.1.

Процедура ПереименоватьКлючХраненияРешенияПоОткрытиюВнешнихОтчетовИОбработок() Экспорт

	Блокировка = Новый БлокировкаДанных;
	Блокировка.Добавить("Константа.ПараметрыАдминистрированияИБ");

	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();

		ПараметрыАдминистрированияИБ = Константы.ПараметрыАдминистрированияИБ.Получить().Получить();

		Если ТипЗнч(ПараметрыАдминистрированияИБ) = Тип("Структура")
		   И ПараметрыАдминистрированияИБ.Свойство("РазрешеноОткрытиеВнешнихОтчетовИОбработок") Тогда

			Если Не ПараметрыАдминистрированияИБ.Свойство("ПринятоРешениеПоОткрытиюВнешнихОтчетовИОбработок")
			   И ТипЗнч(ПараметрыАдминистрированияИБ.РазрешеноОткрытиеВнешнихОтчетовИОбработок) = Тип("Булево")
			   И ПараметрыАдминистрированияИБ.РазрешеноОткрытиеВнешнихОтчетовИОбработок Тогда

				ПараметрыАдминистрированияИБ.Вставить("ПринятоРешениеПоОткрытиюВнешнихОтчетовИОбработок", Истина);
			КонецЕсли;
			ПараметрыАдминистрированияИБ.Удалить("РазрешеноОткрытиеВнешнихОтчетовИОбработок");
			Константы.ПараметрыАдминистрированияИБ.Установить(Новый ХранилищеЗначения(ПараметрыАдминистрированияИБ));
		КонецЕсли;

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

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

// Вызывается при переходе на версию конфигурации 3.0.2.124 и при начальном заполнении.

Процедура ЗаполнитьНаименованиеПредопределенныхГруппПользователей() Экспорт

	УстановитьНаименование(Справочники.ГруппыПользователей.ВсеПользователи,
		НСтр("ru = 'Все пользователи'"));

	УстановитьНаименование(Справочники.ГруппыВнешнихПользователей.ВсеВнешниеПользователи,
		НСтр("ru = 'Все внешние пользователи'"));

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

// Для процедуры ЗаполнитьНаименованиеПредопределенныхГруппПользователей.

Процедура УстановитьНаименование(Ссылка, Наименование)

	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить(Ссылка.Метаданные().ПолноеИмя());
	ЭлементБлокировки.УстановитьЗначение("Ссылка", Ссылка);

	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		Объект = Ссылка.ПолучитьОбъект();
		Объект.Наименование = НСтр("ru = 'Все пользователи'");
		ОбновлениеИнформационнойБазы.ЗаписатьОбъект(Объект);
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;

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

////////////////////////////////////////////////////////////////////////////////
// Работа с настройками пользователей.

// Вызывается из обработки НастройкиПользователей и формирует
// список настроек пользователей.
//

Процедура ЗаполнитьСпискиНастроек(Параметры, АдресХранилища) Экспорт

	Если Параметры.ПользовательИнформационнойБазы <> ИмяПользователя()
	   И Не ПравоДоступа("АдминистрированиеДанных", Метаданные) Тогда

		ТекстОшибки = НСтр("ru = 'Недостаточно прав для получения настроек пользователя.'");
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;

	Обработки.НастройкиПользователей.ЗаполнитьСпискиНастроек(Параметры);

	Результат = Новый Структура;
	Результат.Вставить("НастройкиВнешнегоВида");
	Результат.Вставить("НастройкиОтчетовДерево");
	Результат.Вставить("ПрочиеНастройкиДерево");
	Результат.Вставить("ПользовательскиеВариантыОтчетов");

	ЗаполнитьЗначенияСвойств(Результат, Параметры);
	ПоместитьВоВременноеХранилище(Результат, АдресХранилища);

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

////////////////////////////////////////////////////////////////////////////////
// Прочие пользовательские настройки.

// См. ПользователиПереопределяемый.ПриПолученииПрочихНастроек

Процедура ПриПолученииПрочихНастроекПользователя(СведенияОПользователе, Настройки) Экспорт

	ИнтеграцияПодсистемБСП.ПриПолученииПрочихНастроек(СведенияОПользователе, Настройки);
	ПользователиПереопределяемый.ПриПолученииПрочихНастроек(СведенияОПользователе, Настройки);

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

Процедура ПриСохраненииПрочихНастроекПользователя(СведенияОПользователе, Настройки) Экспорт

	ИнтеграцияПодсистемБСП.ПриСохраненииПрочихНастроек(СведенияОПользователе, Настройки);
	ПользователиПереопределяемый.ПриСохраненииПрочихНастроек(СведенияОПользователе, Настройки);

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

Процедура ПриУдаленииПрочихНастроекПользователя(СведенияОПользователе, Настройки) Экспорт

	ИнтеграцияПодсистемБСП.ПриУдаленииПрочихНастроек(СведенияОПользователе, Настройки);
	ПользователиПереопределяемый.ПриУдаленииПрочихНастроек(СведенияОПользователе, Настройки);

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

// Возвращаемое значение:
//  ТаблицаЗначений:
//   * Объект - Строка
//   * Идентификатор - Строка
//

Функция НовоеОписаниеНастройки() Экспорт

	Возврат Новый Структура;

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

////////////////////////////////////////////////////////////////////////////////
// ВСПОМОГАТЕЛЬНЫЕ ПРОЦЕДУРЫ И ФУНКЦИИ

// При первом запуске подчиненного узла очищает идентификаторы
// пользователей ИБ, скопированные при создании начального образа.
//

Процедура ОчиститьИдентификаторыНесуществующихПользователейИБ()

	Если ОбщегоНазначения.РазделениеВключено() Тогда
		Возврат;
	КонецЕсли;

	ПустойУникальныйИдентификатор = ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор();

	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", ПустойУникальныйИдентификатор);

	Запрос.Текст =
	"ВЫБРАТЬ
	|	Пользователи.Ссылка КАК Ссылка,
	|	Пользователи.ИдентификаторПользователяИБ
	|ИЗ
	|	Справочник.Пользователи КАК Пользователи
	|ГДЕ
	|	Пользователи.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	ВнешниеПользователи.Ссылка,
	|	ВнешниеПользователи.ИдентификаторПользователяИБ
	|ИЗ
	|	Справочник.Пользователи КАК ВнешниеПользователи
	|ГДЕ
	|	ВнешниеПользователи.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор";

	Выборка = Запрос.Выполнить().Выбрать();

	Пока Выборка.Следующий() Цикл

		ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(
			Выборка.ИдентификаторПользователяИБ);

		Если ПользовательИБ <> Неопределено Тогда
			Продолжить;
		КонецЕсли;

		Блокировка = Новый БлокировкаДанных;
		ЭлементБлокировки = Блокировка.Добавить(Выборка.Ссылка.Метаданные().ПолноеИмя());
		ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Ссылка);

		НачатьТранзакцию();
		Попытка
			Блокировка.Заблокировать();
			ТекущийОбъект = Выборка.Ссылка.ПолучитьОбъект();
			ТекущийОбъект.ИдентификаторПользователяИБ = ПустойУникальныйИдентификатор;
			ОбновлениеИнформационнойБазы.ЗаписатьДанные(ТекущийОбъект);
			ЗафиксироватьТранзакцию();
		Исключение
			ОтменитьТранзакцию();
			ВызватьИсключение;
		КонецПопытки;
	КонецЦикла;

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

// Обновляет представление внешнего пользователя при изменении представления его объекта авторизации,
// а также помечает, как недействительного, если объект авторизации помечен на удаление.
//


Процедура ОбновитьДеревоРолей(Параметры)

	Форма           = Параметры.Форма;
	Элементы        = Форма.Элементы;
	Роли            = Форма.Роли;
	НазначениеРолей = Параметры.НазначениеРолей;

	СкрытьРольПолныеПрава = Параметры.Свойство("СкрытьРольПолныеПрава")
	                      И Параметры.СкрытьРольПолныеПрава = Истина;

	Если Элементы.Найти("РолиПоказатьТолькоВыбранныеРоли") <> Неопределено Тогда
		Если НЕ Элементы.РолиПоказатьТолькоВыбранныеРоли.Доступность Тогда
			Элементы.РолиПоказатьТолькоВыбранныеРоли.Пометка = Истина;
		КонецЕсли;
		ПоказатьТолькоВыбранныеРоли = Элементы.РолиПоказатьТолькоВыбранныеРоли.Пометка;
	Иначе
		ПоказатьТолькоВыбранныеРоли = Истина;
	КонецЕсли;

	ПоказатьПодсистемыРолей = Параметры.Форма.ПоказатьПодсистемыРолей;

	// Запоминание текущей строки.
	ТекущаяПодсистема = "";
	ТекущаяРоль       = "";

	Если Элементы.Роли.ТекущаяСтрока <> Неопределено Тогда
		ТекущиеДанные = Роли.НайтиПоИдентификатору(Элементы.Роли.ТекущаяСтрока);

		Если ТекущиеДанные = Неопределено Тогда
			Элементы.Роли.ТекущаяСтрока = Неопределено;

		ИначеЕсли ТекущиеДанные.ЭтоРоль Тогда
			ТекущаяРоль       = ТекущиеДанные.Имя;
			ТекущаяПодсистема = ?(ТекущиеДанные.ПолучитьРодителя() = Неопределено, "",
				ТекущиеДанные.ПолучитьРодителя().Имя);
		Иначе
			ТекущаяРоль       = "";
			ТекущаяПодсистема = ТекущиеДанные.Имя;
		КонецЕсли;
	КонецЕсли;

	ХранилищеДереваРолей = ПользователиСлужебныйПовтИсп.ДеревоРолей(ПоказатьПодсистемыРолей, НазначениеРолей);
	ДеревоРолей = ХранилищеДереваРолей.Получить(); // см. ПользователиСлужебныйПовтИсп.ДеревоРолей

	ДеревоРолей.Колонки.Добавить("ЭтоНедоступнаяРоль",    Новый ОписаниеТипов("Булево"));
	ДеревоРолей.Колонки.Добавить("ЭтоНесуществующаяРоль", Новый ОписаниеТипов("Булево"));
	ДобавитьИменаНесуществующихИНедоступныхРолей(Параметры, ДеревоРолей);

	ДеревоРолей.Колонки.Добавить("Пометка",       Новый ОписаниеТипов("Булево"));
	ДеревоРолей.Колонки.Добавить("НомерКартинки", Новый ОписаниеТипов("Число"));
	ПодготовитьДеревоРолей(ДеревоРолей.Строки, СкрытьРольПолныеПрава, ПоказатьТолькоВыбранныеРоли,
		Параметры.КоллекцияРолей, ?(Параметры.Свойство("СтандартныеРолиРасширений"),
			Параметры.СтандартныеРолиРасширений, Неопределено));

	Параметры.Форма.ЗначениеВРеквизитФормы(ДеревоРолей, "Роли");

	Элементы.Роли.Отображение = ?(ДеревоРолей.Строки.Найти(Ложь, "ЭтоРоль") = Неопределено,
		ОтображениеТаблицы.Список, ОтображениеТаблицы.Дерево);

	// Восстановление текущей строки.
	Отбор = Новый Структура("ЭтоРоль, Имя", Ложь, ТекущаяПодсистема);
	НайденныеСтроки = ДеревоРолей.Строки.НайтиСтроки(Отбор, Истина);
	Если НайденныеСтроки.Количество() <> 0 Тогда
		ОписаниеПодсистемы = НайденныеСтроки[0];

		ИндексПодсистемы = ?(ОписаниеПодсистемы.Родитель = Неопределено,
			ДеревоРолей.Строки, ОписаниеПодсистемы.Родитель.Строки).Индекс(ОписаниеПодсистемы);

		СтрокаПодсистемы = ДанныеФормыКоллекцияЭлементовДерева(Роли,
			ОписаниеПодсистемы).Получить(ИндексПодсистемы);

		Если ЗначениеЗаполнено(ТекущаяРоль) Тогда
			Отбор = Новый Структура("ЭтоРоль, Имя", Истина, ТекущаяРоль);
			НайденныеСтроки = ОписаниеПодсистемы.Строки.НайтиСтроки(Отбор);
			Если НайденныеСтроки.Количество() <> 0 Тогда
				ОписаниеРоли = НайденныеСтроки[0];
				Элементы.Роли.ТекущаяСтрока = СтрокаПодсистемы.ПолучитьЭлементы().Получить(
					ОписаниеПодсистемы.Строки.Индекс(ОписаниеРоли)).ПолучитьИдентификатор();
			Иначе
				Элементы.Роли.ТекущаяСтрока = СтрокаПодсистемы.ПолучитьИдентификатор();
			КонецЕсли;
		Иначе
			Элементы.Роли.ТекущаяСтрока = СтрокаПодсистемы.ПолучитьИдентификатор();
		КонецЕсли;
	Иначе
		Отбор = Новый Структура("ЭтоРоль, Имя", Истина, ТекущаяРоль);
		НайденныеСтроки = ДеревоРолей.Строки.НайтиСтроки(Отбор, Истина);
		Если НайденныеСтроки.Количество() <> 0 Тогда
			ОписаниеРоли = НайденныеСтроки[0];

			ИндексРоли = ?(ОписаниеРоли.Родитель = Неопределено,
				ДеревоРолей.Строки, ОписаниеРоли.Родитель.Строки).Индекс(ОписаниеРоли);

			СтрокаРоли = ДанныеФормыКоллекцияЭлементовДерева(Роли, ОписаниеРоли).Получить(ИндексРоли);
			Элементы.Роли.ТекущаяСтрока = СтрокаРоли.ПолучитьИдентификатор();
		КонецЕсли;
	КонецЕсли;

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

// Параметры:
//  Параметры - см. ОбработатьИнтерфейсРолей.Параметры
//  ДеревоРолей - ДеревоЗначений:
//    * ЭтоРоль - Булево
//    * Имя     - Строка - имя роли или подсистемы.
//    * Синоним - Строка - синоним роли или подсистемы.
//    * ЭтоНедоступнаяРоль    - Булево
//    * ЭтоНесуществующаяРоль - Булево
//    * Пометка               - Булево
//    * НомерКартинки         - Число
//

Процедура ДобавитьИменаНесуществующихИНедоступныхРолей(Параметры, ДеревоРолей)

	КоллекцияРолей  = Параметры.КоллекцияРолей;
	ВсеРоли = ВсеРоли().Соответствие;

	НедоступныеРоли    = Новый СписокЗначений;
	НесуществующиеРоли = Новый СписокЗначений;

	// Добавление несуществующих ролей.
	Для каждого Строка Из КоллекцияРолей Цикл
		Отбор = Новый Структура("ЭтоРоль, Имя", Истина, Строка.Роль);
		Если ДеревоРолей.Строки.НайтиСтроки(Отбор, Истина).Количество() > 0 Тогда
			Продолжить;
		КонецЕсли;
		Синоним = ВсеРоли.Получить(Строка.Роль);
		Если Синоним = Неопределено Тогда
			НесуществующиеРоли.Добавить(Строка.Роль,
				?(Лев(Строка.Роль, 1) = "?", Строка.Роль, "? " + Строка.Роль));
		Иначе
			НедоступныеРоли.Добавить(Строка.Роль, Синоним);
		КонецЕсли;
	КонецЦикла;

	НедоступныеРоли.СортироватьПоПредставлению();
	Для Каждого ОписаниеРоли Из НедоступныеРоли Цикл
		Индекс = НедоступныеРоли.Индекс(ОписаниеРоли);
		СтрокаДерева = ДеревоРолей.Строки.Вставить(Индекс);
		СтрокаДерева.Имя     = ОписаниеРоли.Значение;
		СтрокаДерева.Синоним = ОписаниеРоли.Представление;
		СтрокаДерева.ЭтоРоль = Истина;
		СтрокаДерева.ЭтоНедоступнаяРоль = Истина;
	КонецЦикла;

	НесуществующиеРоли.СортироватьПоПредставлению();
	Для Каждого ОписаниеРоли Из НесуществующиеРоли Цикл
		Индекс = НесуществующиеРоли.Индекс(ОписаниеРоли);
		СтрокаДерева = ДеревоРолей.Строки.Вставить(Индекс);
		СтрокаДерева.Имя     = ОписаниеРоли.Значение;
		СтрокаДерева.Синоним = ОписаниеРоли.Представление;
		СтрокаДерева.ЭтоРоль = Истина;
		СтрокаДерева.ЭтоНесуществующаяРоль = Истина;
	КонецЦикла;

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

Процедура ПодготовитьДеревоРолей(Знач Коллекция, Знач СкрытьРольПолныеПрава, Знач ПоказатьТолькоВыбранныеРоли,
			КоллекцияРолей, СтандартныеРолиРасширений)

	Индекс = Коллекция.Количество()-1;

	Пока Индекс >= 0 Цикл
		Строка = Коллекция[Индекс];

		ПодготовитьДеревоРолей(Строка.Строки, СкрытьРольПолныеПрава, ПоказатьТолькоВыбранныеРоли,
			КоллекцияРолей, СтандартныеРолиРасширений);

		Если Строка.ЭтоРоль Тогда
			Если СкрытьРольПолныеПрава
			   И (    ВРег(Строка.Имя) = ВРег("ПолныеПрава")
			      ИЛИ ВРег(Строка.Имя) = ВРег("АдминистраторСистемы")
			      ИЛИ СтандартныеРолиРасширений <> Неопределено
			        И (    СтандартныеРолиРасширений.ПолныеПрава.Найти(Строка.Имя) <> Неопределено
			           Или СтандартныеРолиРасширений.АдминистраторСистемы.Найти(Строка.Имя) <> Неопределено)) Тогда
				Коллекция.Удалить(Индекс);
			Иначе
				Строка.НомерКартинки = 7;
				Строка.Пометка = КоллекцияРолей.НайтиСтроки(
					Новый Структура("Роль", Строка.Имя)).Количество() > 0;

				Если ПоказатьТолькоВыбранныеРоли И НЕ Строка.Пометка Тогда
					Коллекция.Удалить(Индекс);
				КонецЕсли;
			КонецЕсли;
		Иначе
			Если Строка.Строки.Количество() = 0 Тогда
				Коллекция.Удалить(Индекс);
			Иначе
				Строка.НомерКартинки = 6;
				Строка.Пометка = Строка.Строки.НайтиСтроки(
					Новый Структура("Пометка", Ложь)).Количество() = 0;
			КонецЕсли;
		КонецЕсли;

		Индекс = Индекс-1;
	КонецЦикла;

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

// Возвращает иерархическую коллекцию.
//
// Параметры:
//  ДанныеФормыДерево - ДанныеФормыДерево
//  СтрокаДереваЗначений - СтрокаДереваЗначений
//
// Возвращаемое значение:
//  ДанныеФормыКоллекцияЭлементовДерева
//


Функция ДанныеФормыКоллекцияЭлементовДерева(Знач ДанныеФормыДерево, Знач СтрокаДереваЗначений)

	Если СтрокаДереваЗначений.Родитель = Неопределено Тогда
		ДанныеФормыКоллекцияЭлементовДерева = ДанныеФормыДерево.ПолучитьЭлементы();
	Иначе
		ИндексРодителя = ?(СтрокаДереваЗначений.Родитель.Родитель = Неопределено,
			СтрокаДереваЗначений.Владелец().Строки, СтрокаДереваЗначений.Родитель.Родитель.Строки).Индекс(
				СтрокаДереваЗначений.Родитель);

		ДанныеФормыКоллекцияЭлементовДерева = ДанныеФормыКоллекцияЭлементовДерева(ДанныеФормыДерево,
			СтрокаДереваЗначений.Родитель).Получить(ИндексРодителя).ПолучитьЭлементы();
	КонецЕсли;

	Возврат ДанныеФормыКоллекцияЭлементовДерева;

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

// Параметры:
//  Параметры - см. ОбработатьИнтерфейсРолей.Параметры
//

Процедура ОбновитьСоставРолей(Параметры)

	Форма = Параметры.Форма;

	Роли                        = Форма.Роли;
	ПоказатьТолькоВыбранныеРоли = Форма.Элементы.РолиПоказатьТолькоВыбранныеРоли.Пометка;
	НазначениеРолей             = Параметры.НазначениеРолей;

	ВсеРоли         = ВсеРоли().Массив;
	НедоступныеРоли = ПользователиСлужебныйПовтИсп.НедоступныеРоли(НазначениеРолей);

	Если Параметры.ОсновнойПараметр = "ВключитьВсе" Тогда
		ИдентификаторСтроки = Неопределено;
		Добавить            = Истина;

	ИначеЕсли Параметры.ОсновнойПараметр = "ИсключитьВсе" Тогда
		ИдентификаторСтроки = Неопределено;
		Добавить            = Ложь;
	Иначе
		ИдентификаторСтроки = Форма.Элементы.Роли.ТекущаяСтрока;
	КонецЕсли;

	Если ИдентификаторСтроки = Неопределено Тогда

		БылУстановленАдминистративныйДоступ = Параметры.КоллекцияРолей.НайтиСтроки(
			Новый Структура("Роль", "ПолныеПрава")).Количество() > 0;

		// Обработка всех.
		КоллекцияРолей = Параметры.КоллекцияРолей;
		КоллекцияРолей.Очистить();
		Если Добавить Тогда
			Для Каждого ИмяРоли Из ВсеРоли Цикл

				Если ИмяРоли = "ПолныеПрава"
				 Или ИмяРоли = "АдминистраторСистемы"
				 Или НедоступныеРоли.Получить(ИмяРоли) <> Неопределено
				 Или ВРег(Лев(ИмяРоли, СтрДлина("Удалить"))) = ВРег("Удалить") Тогда

					Продолжить;
				КонецЕсли;
				КоллекцияРолей.Добавить().Роль = ИмяРоли;
			КонецЦикла;
		КонецЕсли;

		Если Параметры.Свойство("ЗапретИзмененияАдминистративногоДоступа")
			И Параметры.ЗапретИзмененияАдминистративногоДоступа Тогда

			УстановленАдминистративныйДоступ = Параметры.КоллекцияРолей.НайтиСтроки(
				Новый Структура("Роль", "ПолныеПрава")).Количество() > 0;

			Если УстановленАдминистративныйДоступ И НЕ БылУстановленАдминистративныйДоступ Тогда
				Отбор = Новый Структура("Роль", "ПолныеПрава");
				Параметры.КоллекцияРолей.НайтиСтроки(Отбор).Удалить(0);

			ИначеЕсли БылУстановленАдминистративныйДоступ И НЕ УстановленАдминистративныйДоступ Тогда
				КоллекцияРолей.Добавить().Роль = "ПолныеПрава";
			КонецЕсли;
		КонецЕсли;
		ЗаполнитьСтандартныеРолиРасширений(Параметры);

		Если ПоказатьТолькоВыбранныеРоли Тогда
			Если КоллекцияРолей.Количество() > 0 Тогда
				ОбновитьДеревоРолей(Параметры);
			Иначе
				Роли.ПолучитьЭлементы().Очистить();
			КонецЕсли;

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

	ОбновитьПометкуВыбранныхРолей(Параметры, Роли.ПолучитьЭлементы());

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

Процедура ЗаполнитьСтандартныеРолиРасширений(Параметры)

	Если Не Параметры.Свойство("СтандартныеРолиРасширений") Тогда
		Возврат;
	КонецЕсли;

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

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

// Параметры:
//  Параметры - см. ОбработатьИнтерфейсРолей.Параметры
//  Роль      - Строка
//  Добавить  - Булево
//

Процедура ДобавитьУдалитьРоль(Параметры, Знач Роль, Знач Добавить)

	НайденныеРоли = Параметры.КоллекцияРолей.НайтиСтроки(Новый Структура("Роль", Роль));

	Если Добавить Тогда
		Если НайденныеРоли.Количество() = 0 Тогда
			Параметры.КоллекцияРолей.Добавить().Роль = Роль;
		КонецЕсли;
	Иначе
		Если НайденныеРоли.Количество() > 0 Тогда
			Параметры.КоллекцияРолей.Удалить(НайденныеРоли[0]);
		КонецЕсли;
	КонецЕсли;

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

// Изменяет состав ролей.
//
// Параметры:
//  Параметры - см. ОбработатьИнтерфейсРолей.Параметры
//  Коллекция - см. ОбработатьИнтерфейсРолей.Параметры.Форма.Элементы.Роли
//  Добавить  - Булево
//

Процедура ДобавитьУдалитьРолиПодсистемы(Параметры, Знач Коллекция, Знач Добавить)

	Для каждого Строка Из Коллекция Цикл
		Если Строка.ЭтоРоль Тогда
			ДобавитьУдалитьРоль(Параметры, Строка.Имя, Добавить);
		Иначе
			ДобавитьУдалитьРолиПодсистемы(Параметры, Строка.ПолучитьЭлементы(), Добавить);
		КонецЕсли;
	КонецЦикла;

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

// Параметры:
//  Параметры - см. ОбработатьИнтерфейсРолей.Параметры
//  Коллекция - см. ОбработатьИнтерфейсРолей.Параметры.Форма.Элементы.Роли
//

Процедура ОбновитьПометкуВыбранныхРолей(Параметры, Знач Коллекция)

	Форма = Параметры.Форма;

	ПоказатьТолькоВыбранныеРоли = Форма.Элементы.РолиПоказатьТолькоВыбранныеРоли.Пометка;

	Индекс = Коллекция.Количество()-1;

	Пока Индекс >= 0 Цикл
		Строка = Коллекция[Индекс];

		Если Строка.ЭтоРоль Тогда
			Отбор = Новый Структура("Роль", Строка.Имя);
			Строка.Пометка = Параметры.КоллекцияРолей.НайтиСтроки(Отбор).Количество() > 0;
			Если ПоказатьТолькоВыбранныеРоли И НЕ Строка.Пометка Тогда
				Коллекция.Удалить(Индекс);
			КонецЕсли;
		Иначе
			ОбновитьПометкуВыбранныхРолей(Параметры, Строка.ПолучитьЭлементы());
			Если Строка.ПолучитьЭлементы().Количество() = 0 Тогда
				Коллекция.Удалить(Индекс);
			Иначе
				Строка.Пометка = Истина;
				Для каждого Элемент Из Строка.ПолучитьЭлементы() Цикл
					Если НЕ Элемент.Пометка Тогда
						Строка.Пометка = Ложь;
						Прервать;
					КонецЕсли;
				КонецЦикла;
			КонецЕсли;
		КонецЕсли;

		Индекс = Индекс-1;
	КонецЦикла;

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

Функция ПользователиДобавленныеСПомощьюКонфигуратора()

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	Пользователи.Ссылка КАК Ссылка,
	|	Пользователи.Наименование КАК ПолноеИмя,
	|	Пользователи.ИдентификаторПользователяИБ,
	|	ЛОЖЬ КАК ЭтоВнешнийПользователь
	|ИЗ
	|	Справочник.Пользователи КАК Пользователи
	|ГДЕ
	|	Пользователи.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	ВнешниеПользователи.Ссылка,
	|	ВнешниеПользователи.Наименование,
	|	ВнешниеПользователи.ИдентификаторПользователяИБ,
	|	ИСТИНА
	|ИЗ
	|	Справочник.ВнешниеПользователи КАК ВнешниеПользователи
	|ГДЕ
	|	ВнешниеПользователи.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор";

	Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор",
		ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор());

	Выгрузка = Запрос.Выполнить().Выгрузить();
	Выгрузка.Индексы.Добавить("ИдентификаторПользователяИБ");

	ПользователиИБ = ПользователиИнформационнойБазы.ПолучитьПользователей();
	ПользователейДобавленоВКонфигураторе = 0;

	Для Каждого ПользовательИБ Из ПользователиИБ Цикл

		Строка = Выгрузка.Найти(ПользовательИБ.УникальныйИдентификатор, "ИдентификаторПользователяИБ");
		Если Строка = Неопределено Тогда
			ПользователейДобавленоВКонфигураторе = ПользователейДобавленоВКонфигураторе + 1;
		КонецЕсли;

	КонецЦикла;

	Возврат ПользователейДобавленоВКонфигураторе;

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

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


Функция РазрешениеНаИспользованиеКаталогаФайловойСистемы(Знач Адрес, Знач ЧтениеДанных = Ложь, Знач ЗаписьДанных = Ложь, Знач Описание = "") Экспорт

	Пакет = РаботаВБезопасномРежимеСлужебный.Пакет();
	Результат = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(Пакет, "FileSystemAccess"));
	Результат.Description = Описание;

	Если СтрЗаканчиваетсяНа(Адрес, "\") Или СтрЗаканчиваетсяНа(Адрес, "/") Тогда
		Адрес = Лев(Адрес, СтрДлина(Адрес) - 1);
	КонецЕсли;

	Результат.Path = Адрес;
	Результат.AllowedRead = ЧтениеДанных;
	Результат.AllowedWrite = ЗаписьДанных;

	Возврат Результат;

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

// Возвращает внутреннее описание разрешения на использование каталога временных файлов.
// Для передачи в качестве параметра в функции:
// РаботаВБезопасномРежиме.ЗапросНаИспользованиеВнешнихРесурсов и
// РаботаВБезопасномРежиме.ЗапросНаОтменуРазрешенийИспользованияВнешнихРесурсов.
//
// Параметры:
//  ЧтениеДанных - Булево - указывает необходимость предоставления разрешения
//                          на чтение данных из каталога временных файлов.
//  ЗаписьДанных - Булево - указывает необходимость предоставления разрешения
//                          на запись данных в каталог временных файлов.
//  Описание - Строка - описание причины, по которой требуется предоставление разрешения.
//
// Возвращаемое значение:
//  ОбъектXDTO
//

Функция РазрешениеНаИспользованиеКаталогаВременныхФайлов(Знач ЧтениеДанных = Ложь, Знач ЗаписьДанных = Ложь, Знач Описание = "") Экспорт

	Возврат РазрешениеНаИспользованиеКаталогаФайловойСистемы(ПсевдонимКаталогаВременныхФайлов(), ЧтениеДанных, ЗаписьДанных);

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

// Возвращает внутреннее описание разрешения на использование каталога программы.
// Для передачи в качестве параметра в функции:
// РаботаВБезопасномРежиме.ЗапросНаИспользованиеВнешнихРесурсов и
// РаботаВБезопасномРежиме.ЗапросНаОтменуРазрешенийИспользованияВнешнихРесурсов.
//
// Параметры:
//  ЧтениеДанных - Булево - указывает необходимость предоставления разрешения
//                          на чтение данных из каталога программы.
//  ЗаписьДанных - Булево - указывает необходимость предоставления разрешения
//                          на запись данных в каталог программы.
//  Описание - Строка - описание причины, по которой требуется предоставление разрешения.
//
// Возвращаемое значение:
//  ОбъектXDTO
//

Функция РазрешениеНаИспользованиеКаталогаПрограммы(Знач ЧтениеДанных = Ложь, Знач ЗаписьДанных = Ложь, Знач Описание = "") Экспорт

	Возврат РазрешениеНаИспользованиеКаталогаФайловойСистемы(ПсевдонимКаталогаПрограммы(), ЧтениеДанных, ЗаписьДанных);

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

// Возвращает внутреннее описание разрешения на использование COM-класса.
// Для передачи в качестве параметра в функции:
// РаботаВБезопасномРежиме.ЗапросНаИспользованиеВнешнихРесурсов и
// РаботаВБезопасномРежиме.ЗапросНаОтменуРазрешенийИспользованияВнешнихРесурсов.
//
// Параметры:
//  ProgID - Строка - ProgID класса COM, с которым он зарегистрирован в системе.
//                    Например, "Excel.Application".
//  CLSID - Строка - CLSID класса COM, с которым он зарегистрирован в системе.
//  ИмяКомпьютера - Строка - имя компьютера, на котором надо создать указанный объект.
//                           Если не указано, то объект будет создан на компьютере, на котором выполняется
//                           текущий рабочий процесс.
//  Описание - Строка - описание причины, по которой требуется предоставление разрешения.
//
// Возвращаемое значение:
//  ОбъектXDTO
//

Функция РазрешениеНаСозданиеCOMКласса(Знач ProgID, Знач CLSID, Знач ИмяКомпьютера = "", Знач Описание = "") Экспорт

	Пакет = РаботаВБезопасномРежимеСлужебный.Пакет();
	Результат = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(Пакет, "CreateComObject"));
	Результат.Description = Описание;

	Результат.ProgId = ProgID;
	Результат.CLSID = Строка(CLSID);
	Результат.ComputerName = ИмяКомпьютера;

	Возврат Результат;

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

// Возвращает внутреннее описание разрешения на использование внешней компоненты, поставляемой
// в общем макете конфигурации.
// Для передачи в качестве параметра в функции:
// РаботаВБезопасномРежиме.ЗапросНаИспользованиеВнешнихРесурсов и
// РаботаВБезопасномРежиме.ЗапросНаОтменуРазрешенийИспользованияВнешнихРесурсов.
//
// Параметры:
//  ИмяМакета - Строка - имя общего макета в конфигурации, в котором поставляется внешняя компонента.
//  Описание - Строка - описание причины, по которой требуется предоставление разрешения.
//
// Возвращаемое значение:
//  ОбъектXDTO
//

Функция РазрешениеНаИспользованиеВнешнейКомпоненты(Знач ИмяМакета, Знач Описание = "") Экспорт

	Пакет = РаботаВБезопасномРежимеСлужебный.Пакет();
	Результат = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(Пакет, "AttachAddin"));
	Результат.Description = Описание;

	Результат.TemplateName = ИмяМакета;

	Возврат Результат;

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

// Возвращает внутреннее описание разрешения на использование расширения конфигурации.
// Для передачи в качестве параметра в функции:
// РаботаВБезопасномРежиме.ЗапросНаИспользованиеВнешнихРесурсов и
// РаботаВБезопасномРежиме.ЗапросНаОтменуРазрешенийИспользованияВнешнихРесурсов.
//
// Параметры:
//  Имя - Строка - имя расширения конфигурации.
//  КонтрольнаяСумма - Строка - контрольная сумма расширения конфигурации.
//  Описание - Строка - описание причины, по которой требуется предоставление разрешения.
//
// Возвращаемое значение:
//  ОбъектXDTO
//

Функция РазрешениеНаИспользованиеВнешнегоМодуля(Знач Имя, Знач КонтрольнаяСумма, Знач Описание = "") Экспорт

	Пакет = РаботаВБезопасномРежимеСлужебный.Пакет();
	Результат = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(Пакет, "ExternalModule"));
	Результат.Description = Описание;

	Результат.Name = Имя;
	Результат.Hash = КонтрольнаяСумма;

	Возврат Результат;

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

// Возвращает внутреннее описание разрешения на использование приложения операционной системы.
// Для передачи в качестве параметра в функции:
// РаботаВБезопасномРежиме.ЗапросНаИспользованиеВнешнихРесурсов и
// РаботаВБезопасномРежиме.ЗапросНаОтменуРазрешенийИспользованияВнешнихРесурсов.
//
// Параметры:
//  ШаблонСтрокиЗапуска - Строка - шаблон строки запуска приложения.
//                                 Подробнее см. документацию к платформе.
//  Описание - Строка - описание причины, по которой требуется предоставление разрешения.
//
// Возвращаемое значение:
//  ОбъектXDTO
//

Функция РазрешениеНаИспользованиеПриложенияОперационнойСистемы(Знач ШаблонСтрокиЗапуска, Знач Описание = "") Экспорт

	Пакет = РаботаВБезопасномРежимеСлужебный.Пакет();
	Результат = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(Пакет, "RunApplication"));
	Результат.Description = Описание;

	Результат.CommandMask = ШаблонСтрокиЗапуска;

	Возврат Результат;

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

// Возвращает внутреннее описание разрешения на использование интернет-ресурса.
// Для передачи в качестве параметра в функции:
// РаботаВБезопасномРежиме.ЗапросНаИспользованиеВнешнихРесурсов и
// РаботаВБезопасномРежиме.ЗапросНаОтменуРазрешенийИспользованияВнешнихРесурсов.
//
// Параметры:
//  Протокол - Строка - протокол, по которому выполняется взаимодействие с ресурсом. Допустимые значения:
//                      IMAP, POP3, SMTP, HTTP, HTTPS, FTP, FTPS, WS, WSS.
//  Адрес - Строка - адрес ресурса без указания протокола.
//  Порт - Число - номер порта через который выполняется взаимодействие с ресурсом.
//  Описание - Строка - описание причины, по которой требуется предоставление разрешения.
//
// Возвращаемое значение:
//  ОбъектXDTO
//


Процедура СоздатьНовоеПисьмо(ПараметрыОтправкиПисьма = Неопределено, ОповещениеОЗакрытииФормы = Неопределено) Экспорт

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

	СведенияДляОтправки = РаботаСПочтовымиСообщениямиВызовСервера.СведенияДляОтправки(ПараметрыОтправки);
	ПараметрыОтправки.Вставить("ПоказыватьДиалогВыбораФорматаСохраненияВложений", СведенияДляОтправки.ПоказыватьДиалогВыбораФорматаСохраненияВложений);
	ПараметрыОтправки.Вставить("ОповещениеОЗакрытииФормы", ОповещениеОЗакрытииФормы);

	Если ТипЗнч(ПараметрыОтправки.Получатель) = Тип("Строка") Тогда
		ПараметрыОтправки.Получатель = СписокПолучателейИзСтроки(ПараметрыОтправки.Получатель);
	КонецЕсли;

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

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

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

Функция ПараметрыОтправкиПисьма() Экспорт
	ПараметрыПисьма = Новый Структура;

	ПараметрыПисьма.Вставить("Отправитель", Неопределено);
	ПараметрыПисьма.Вставить("Получатель", Неопределено);
	ПараметрыПисьма.Вставить("Копии", Неопределено);
	ПараметрыПисьма.Вставить("СкрытыеКопии", Неопределено);
	ПараметрыПисьма.Вставить("Тема", Неопределено);
	ПараметрыПисьма.Вставить("Текст", Неопределено);
	ПараметрыПисьма.Вставить("Вложения", Неопределено);
	ПараметрыПисьма.Вставить("УдалятьФайлыПослеОтправки", Неопределено);
	ПараметрыПисьма.Вставить("Предмет", Неопределено);

	Возврат ПараметрыПисьма;
КонецФункции

// Если у пользователя нет настроенной почты для отправки писем, то в зависимости от прав либо показывает
// помощник настройки новой почты, либо выводит сообщение о невозможности отправки.
// Предназначена для сценариев, в которых требуется выполнить настройку почты перед запросом дополнительных
// параметров отправки.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения - процедура, в которую необходимо передать выполнение кода после проверки.
//                                              В качестве результата возвращается Истина, если есть доступная учетная
//                                              запись для отправки почты. Иначе возвращается Ложь.
//

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

// Открывает форму сообщения об ошибке, в которой помимо текста ошибки сообщаются возможные причины
// и способы устранения.
//
// Параметры:
//  УчетнаяЗапись - СправочникСсылка.УчетныеЗаписиЭлектроннойПочты
//  Заголовок - Строка - текст заголовка в открываемой форме.
//  ТекстОшибки - Строка - исходный текст исключения, рекомендуется передавать КраткоеПредставлениеОшибки.
//

Процедура СообщитьОбОшибкеПодключения(УчетнаяЗапись, Заголовок, ТекстОшибки) Экспорт

	ОткрытьФорму("Справочник.УчетныеЗаписиЭлектроннойПочты.Форма.ПроверкаНастроекУчетнойЗаписи",
		Новый Структура("УчетнаяЗапись, Заголовок, ТекстОшибки", УчетнаяЗапись, Заголовок, ТекстОшибки));

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

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

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

Процедура ПерейтиКДокументацииПоВводуУчетнойЗаписиЭлектроннойПочты() Экспорт

	ФайловаяСистемаКлиент.ОткрытьНавигационнуюСсылку("https://its.1c.eu/bmk/bsp_email_account");

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

Процедура ПолеПароляНачалоВыбора(Элемент, Реквизит, СтандартнаяОбработка) Экспорт

	СтандартнаяОбработка = Ложь;
	Реквизит = Элемент.ТекстРедактирования;
	Элемент.РежимПароля = Не Элемент.РежимПароля;
	Если Элемент.РежимПароля Тогда
		Элемент.КартинкаКнопкиВыбора = БиблиотекаКартинок.ВводимыеСимволыВидны;
	Иначе
		Элемент.КартинкаКнопкиВыбора = БиблиотекаКартинок.ВводимыеСимволыСкрыты;
	КонецЕсли;

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

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

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

// Продолжение процедуры СоздатьНовоеПисьмо.


Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт

	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.1.3.40";
	Обработчик.Процедура = "Справочники.УчетныеЗаписиЭлектроннойПочты.ОбработатьДанныеДляПереходаНаНовуюВерсию";
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.Идентификатор = Новый УникальныйИдентификатор("d57f7a36-46ca-4a52-baab-db960e3d376d");
	Обработчик.Комментарий = НСтр("ru = 'Обновляет сведения об учетных записях электронной почты.
		|До завершения обработки список учетных записей электронной почты может быть неполным.'");
	Обработчик.ПроцедураЗаполненияДанныхОбновления = "Справочники.УчетныеЗаписиЭлектроннойПочты.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию";

	ЧитаемыеОбъекты = Новый Массив;
	ЧитаемыеОбъекты.Добавить("Справочник.УчетныеЗаписиЭлектроннойПочты");

	ИзменяемыеОбъекты = Новый Массив;
	ИзменяемыеОбъекты.Добавить("Справочник.УчетныеЗаписиЭлектроннойПочты");

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

	Обработчик.ЧитаемыеОбъекты = СтрСоединить(ЧитаемыеОбъекты, ",");
	Обработчик.ИзменяемыеОбъекты = СтрСоединить(ИзменяемыеОбъекты, ",");

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

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

// См. УправлениеДоступомПереопределяемый.ПриЗаполненииВидовДоступа.

Процедура ПриЗаполненииВидовДоступа(ВидыДоступа) Экспорт

	ВидДоступа = ВидыДоступа.Добавить();
	ВидДоступа.Имя = "УчетныеЗаписиЭлектроннойПочты";
	ВидДоступа.Представление = НСтр("ru = 'Учетные записи электронной почты'");
	ВидДоступа.ТипЗначений   = Тип("СправочникСсылка.УчетныеЗаписиЭлектроннойПочты");

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

// См. УправлениеДоступомПереопределяемый.ПриЗаполненииСписковСОграничениемДоступа.

Процедура ПриЗаполненииСписковСОграничениемДоступа(Списки) Экспорт

	Списки.Вставить(Метаданные.Справочники.УчетныеЗаписиЭлектроннойПочты, Истина);

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

// См. УправлениеДоступомПереопределяемый.ПриЗаполненииВидовОграниченийПравОбъектовМетаданных.

Процедура ПриЗаполненииВидовОграниченийПравОбъектовМетаданных(Описание) Экспорт

	Если НЕ ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда
		Возврат;
	КонецЕсли;

	МодульУправлениеДоступомСлужебный = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступомСлужебный");

	Если МодульУправлениеДоступомСлужебный.ВидДоступаСуществует("УчетныеЗаписиЭлектроннойПочты") Тогда

		Описание = Описание + "
		|Справочник.УчетныеЗаписиЭлектроннойПочты.Чтение.УчетныеЗаписиЭлектроннойПочты
		|Справочник.УчетныеЗаписиЭлектроннойПочты.Чтение.Пользователи
		|Справочник.УчетныеЗаписиЭлектроннойПочты.Изменение.Пользователи
		|";

	КонецЕсли;

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

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных.

Процедура ПриДобавленииПереименованийОбъектовМетаданных(Итог) Экспорт

	Библиотека = "СтандартныеПодсистемы";

	СтароеИмя = "Роль.ИспользованиеУчетныхЗаписейЭлектроннойПочты";
	НовоеИмя  = "Роль.ЧтениеУчетныхЗаписейЭлектроннойПочты";
	ОбщегоНазначения.ДобавитьПереименование(Итог, "2.3.3.11", СтароеИмя, НовоеИмя, Библиотека);

	СтароеИмя = "Роль.ЧтениеУчетныхЗаписейЭлектроннойПочты";
	НовоеИмя  = "Роль.ДобавлениеИзменениеУчетныхЗаписейЭлектроннойПочты";
	ОбщегоНазначения.ДобавитьПереименование(Итог, "2.4.1.1", СтароеИмя, НовоеИмя, Библиотека);

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

// Смотри также ОбновлениеИнформационнойБазыПереопределяемый.ПриОпределенииНастроек
//
// Параметры:
//  Объекты - Массив из ОбъектМетаданных
//

Процедура ПриОпределенииОбъектовСНачальнымЗаполнением(Объекты) Экспорт

	Объекты.Добавить(Метаданные.Справочники.УчетныеЗаписиЭлектроннойПочты);

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

// См. ОчередьЗаданийПереопределяемый.ПриОпределенииПсевдонимовОбработчиков.

Процедура ПриОпределенииПсевдонимовОбработчиков(СоответствиеИменПсевдонимам) Экспорт

	СоответствиеИменПсевдонимам.Вставить(Метаданные.РегламентныеЗадания.ПолучениеСтатусовЭлектронныхПисем.ИмяМетода);

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

// Кодирует строку по алгоритму Punycode
//
// Параметры:
//  Строка - Строка - исходная строка
//
// Возвращаемое значение:
//  Строка - кодированная строка
//

Функция СтрокаВPunycode(Знач Строка) Экспорт

	СтруктураURI = ОбщегоНазначенияКлиентСервер.СтруктураURI(Строка);
	АдресХоста = СтруктураURI.Хост;
	КодированныйАдресХоста = КодироватьСтрокуСРазделителем(АдресХоста);
	Результат = СтрЗаменить(Строка, АдресХоста, КодированныйАдресХоста);

	Логин = СтруктураURI.Логин;
	КодированныйЛогин = КодироватьСтрокуСРазделителем(Логин);
	Результат = СтрЗаменить(Результат, Логин, КодированныйЛогин);

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

// Декодирует адреса электронной почты по алгоритму Punycode
//
// Параметры:
//  Письмо - ИнтернетПочтовоеСообщение - обрабатываемое письмо
//

Процедура ДекодироватьАдресаВПисьме(Письмо) Экспорт
	ДекодироватьКоллекциюАдресов(Письмо.АдресаУведомленияОПрочтении);
	ДекодироватьКоллекциюАдресов(Письмо.ОбратныйАдрес);
	ДекодироватьКоллекциюАдресов(Письмо.Получатели);
	ДекодироватьКоллекциюАдресов(Письмо.СлепыеКопии);
	Письмо.Отправитель.Адрес = PunycodeВСтроку(Письмо.Отправитель.Адрес);
КонецПроцедуры

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

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

// Проверяет, что предопределенная системная учетная запись электронной почты
// доступна для использования.
//

Функция ПроверитьСистемнаяУчетнаяЗаписьДоступна() Экспорт

	Если НЕ ПравоДоступа("Чтение", Метаданные.Справочники.УчетныеЗаписиЭлектроннойПочты) Тогда
		Возврат Ложь;
	КонецЕсли;

	ТекстЗапроса =
		"ВЫБРАТЬ РАЗРЕШЕННЫЕ
		|	УчетныеЗаписиЭлектроннойПочты.Ссылка КАК Ссылка
		|ИЗ
		|	Справочник.УчетныеЗаписиЭлектроннойПочты КАК УчетныеЗаписиЭлектроннойПочты
		|ГДЕ
		|	УчетныеЗаписиЭлектроннойПочты.Ссылка = &Ссылка";

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

	Возврат Истина;

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


Функция ДобавитьФайл(ПараметрыФайла,
                     Знач АдресФайлаВоВременномХранилище,
                     Знач АдресВременногоХранилищаТекста = "",
                     Знач Описание = "",
                     Знач НоваяСсылкаНаФайл = Неопределено) Экспорт

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

	Если Не ЗначениеЗаполнено(ВладелецФайлов) Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не задано значение параметра %1 в %2.'"), "ПараметрыФайла.ВладелецФайлов", "РаботаСФайлами.ДобавитьФайл");
	КонецЕсли;

	ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресФайлаВоВременномХранилище); // ДвоичныеДанные
	ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("РаботаСФайлами.ДобавитьФайл",
		"АдресФайлаВоВременномХранилище", ДвоичныеДанные, Тип("ДвоичныеДанные"));

	ГруппаФайлов = Неопределено;
	Если ПараметрыФайла.Свойство("ГруппаФайлов")
		И ЗначениеЗаполнено(ПараметрыФайла.ГруппаФайлов)
		И Не РаботаСФайламиСлужебный.ЭтоПапкаФайлов(ВладелецФайлов) Тогда

		ГруппаФайлов = ПараметрыФайла.ГруппаФайлов;
	КонецЕсли;

	Если Не ЗначениеЗаполнено(РасширениеБезТочки) Тогда
		ЧастиИмениФайла = СтрРазделить(ИмяБезРасширения, ".", Ложь);
		Если ЧастиИмениФайла.Количество() > 1 Тогда
			РасширениеБезТочки = ЧастиИмениФайла[ЧастиИмениФайла.Количество() - 1];
			ИмяБезРасширения = Лев(ИмяБезРасширения, СтрДлина(ИмяБезРасширения) - (СтрДлина(РасширениеБезТочки) + 1));
		КонецЕсли;
	КонецЕсли;

	ИмяБезРасширения = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(ИмяБезРасширения);
	РасширениеБезТочки = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(РасширениеБезТочки);

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

	ЗаголовокОшибки = НСтр("ru = 'Ошибка при добавлении присоединенного файла.'");

	Если НоваяСсылкаНаФайл = Неопределено Тогда
		ИмяСправочника = РаботаСФайламиСлужебный.ИмяСправочникаХраненияФайлов(ВладелецФайлов, "", ЗаголовокОшибки,
			СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'В этом случае параметр ""%1"" должен быть указан.'"), "НоваяСсылкаНаФайл"));

		НоваяСсылкаНаФайл = Справочники[ИмяСправочника].ПолучитьСсылку();
	Иначе

		Если Не Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(НоваяСсылкаНаФайл))
			Или Не ЗначениеЗаполнено(НоваяСсылкаНаФайл) Тогда

			ВызватьИсключение НСтр("ru = 'Ошибка при добавлении присоединенного файла.
				|Ссылка на новый файл не заполнена.'");
		КонецЕсли;

		ИмяСправочника = РаботаСФайламиСлужебный.ИмяСправочникаХраненияФайлов(
			ВладелецФайлов, НоваяСсылкаНаФайл.Метаданные().Имя, ЗаголовокОшибки);

	КонецЕсли;

	ХранитьВерсии = СтрСравнить(ИмяСправочника, Метаданные.Справочники.Файлы.Имя) = 0;

	ПрисоединенныйФайл = Справочники[ИмяСправочника].СоздатьЭлемент(); // ОпределяемыйТип.ПрисоединенныйФайлОбъект
	ПрисоединенныйФайл.УстановитьСсылкуНового(НоваяСсылкаНаФайл);

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

	Если ГруппаФайлов <> Неопределено Тогда
		ПрисоединенныйФайл.Родитель = ГруппаФайлов;
	КонецЕсли;

	ЗаполнитьЗначенияСвойств(ПрисоединенныйФайл, ПараметрыФайла);

	ПрисоединенныйФайл.Том        = Справочники.ТомаХраненияФайлов.ПустаяСсылка();
	ПрисоединенныйФайл.ПутьКФайлу = "";
	ПрисоединенныйФайл.Заполнить(Неопределено);

	ИспользованиеПолнотекстовогоПоиска = Метаданные.СвойстваОбъектов.ИспользованиеПолнотекстовогоПоиска.Использовать;
	ИзвлекатьТекст = Метаданные.Справочники[ИмяСправочника].ПолнотекстовыйПоиск = ИспользованиеПолнотекстовогоПоиска;

	Если ИзвлекатьТекст И ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыФайла, "Зашифрован", Ложь) <> Истина Тогда

		РезультатИзвлеченияТекста = РаботаСФайламиСлужебный.ИзвлечьТекст(АдресВременногоХранилищаТекста,
			ДвоичныеДанные, ПрисоединенныйФайл.Расширение);

		ПрисоединенныйФайл.ТекстХранилище = РезультатИзвлеченияТекста.ТекстХранилище;
		ПрисоединенныйФайл.СтатусИзвлеченияТекста = РезультатИзвлеченияТекста.СтатусИзвлеченияТекста;

	Иначе
		ПрисоединенныйФайл.ТекстХранилище = Новый ХранилищеЗначения("");
		ПрисоединенныйФайл.СтатусИзвлеченияТекста = Перечисления.СтатусыИзвлеченияТекстаФайлов.НеИзвлечен;
	КонецЕсли;

	Если Не ЗначениеЗаполнено(ПрисоединенныйФайл.Изменил) Тогда
		ПрисоединенныйФайл.Изменил = Пользователи.АвторизованныйПользователь();
	КонецЕсли;

	Контекст = РаботаСФайламиСлужебный.КонтекстОбновленияФайла(ПрисоединенныйФайл, АдресФайлаВоВременномХранилище, НоваяСсылкаНаФайл);
	МенеджерФайла = РаботаСФайламиСлужебный.МенеджерФайлов(ПрисоединенныйФайл);
	МенеджерФайла.ПередОбновлениемДанныхФайла(Контекст);

	НачатьТранзакцию();
	Попытка

		МенеджерФайла.ПередЗаписьюДанныхФайла(Контекст, ПрисоединенныйФайл);
		ПрисоединенныйФайл.Записать();

		Если ХранитьВерсии Тогда

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

			СведенияОФайле.АдресВременногоХранилищаФайла   = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(
																Контекст,
																"ПутьКФайлу",
																АдресФайлаВоВременномХранилище);
			СведенияОФайле.АдресВременногоХранилищаТекста  = АдресВременногоХранилищаТекста;
			СведенияОФайле.ЗаписатьВИсторию                = Истина;

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

		ЗафиксироватьТранзакцию();

	Исключение

		ОтменитьТранзакцию();

		ИнформацияОбОшибке = ИнформацияОбОшибке();

		ШаблонСообщения = НСтр("ru = 'Ошибка при добавлении присоединенного файла ""%1"":
			|%2'");
		КомментарийЖурналаРегистрации = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			ШаблонСообщения,
			ИмяБезРасширения + "." + РасширениеБезТочки,
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке));

		ЗаписьЖурналаРегистрации(
			НСтр("ru = 'Файлы.Добавление присоединенного файла'",
			ОбщегоНазначения.КодОсновногоЯзыка()),
			УровеньЖурналаРегистрации.Ошибка,
			,
			,
			КомментарийЖурналаРегистрации);

		МенеджерФайла.ПослеОбновленияДанныхФайла(Контекст, Ложь);

		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			ШаблонСообщения,
			ИмяБезРасширения + "." + РасширениеБезТочки,
			ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));

	КонецПопытки;

	МенеджерФайла.ПослеОбновленияДанныхФайла(Контекст, Истина);

	РаботаСФайламиПереопределяемый.ПриСозданииФайла(ПрисоединенныйФайл.Ссылка);
	Возврат ПрисоединенныйФайл.Ссылка;

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

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


Функция ЕстьТомаХраненияФайлов() Экспорт

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	ИСТИНА КАК ЗначениеИстина
	|ИЗ
	|	Справочник.ТомаХраненияФайлов КАК ТомаХраненияФайлов
	|ГДЕ
	|	ТомаХраненияФайлов.ПометкаУдаления = ЛОЖЬ";

	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
	Возврат НЕ Запрос.Выполнить().Пустой();

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

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

Функция ДанныеФайла(ПрисоединенныйФайл, Знач ВызыватьИсключение = Истина) Экспорт

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

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

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

Функция ПараметрыДобавленияФайла() Экспорт

	ПараметрыФайла = Новый Структура;
	ПараметрыФайла.Вставить("Ссылка", Неопределено);
	ПараметрыФайла.Вставить("Том", Справочники.ТомаХраненияФайлов.ПустаяСсылка());
	ПараметрыФайла.Вставить("ПутьКФайлу", "");
	ПараметрыФайла.Вставить("Расширение", Неопределено);
	ПараметрыФайла.Вставить("Размер", 0);
	ПараметрыФайла.Вставить("Наименование", "");
	ПараметрыФайла.Вставить("ХранимыйФайл", Неопределено);
	ПараметрыФайла.Вставить("ВладелецФайла", Неопределено);
	ПараметрыФайла.Вставить("ТипХраненияФайла", Неопределено);
	ПараметрыФайла.Вставить("ДатаМодификацииУниверсальная", Неопределено);
	ПараметрыФайла.Вставить("ДополнительныеСвойства", Новый Структура);

	Возврат ПараметрыФайла;

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

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

Процедура ДобавитьФайл(ПрисоединенныйФайл, ДвоичныеДанныеИлиПуть,
	ДатаДляРазмещенияВТоме = Неопределено, ЗаполнятьСлужебныйРеквизитХранилище = Ложь, ТомДляРазмещения = Неопределено) Экспорт

	ЗаполнитьСведенияОФайле(ПрисоединенныйФайл, ДвоичныеДанныеИлиПуть, ДатаДляРазмещенияВТоме, ЗаполнятьСлужебныйРеквизитХранилище);

	Если НЕ ПрисоединенныйФайл.ТипХраненияФайла = Перечисления.ТипыХраненияФайлов.ВИнформационнойБазе Тогда
		ЗаписатьДанныеФайлаВТом(ПрисоединенныйФайл, ДвоичныеДанныеИлиПуть);
	КонецЕсли;

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

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


Процедура ПереименоватьФайл(ПрисоединенныйФайл,Знач НовоеИмя,
	Знач СтароеИмя = "", УникальныйИдентификатор = Неопределено) Экспорт

	НачатьТранзакцию();
	Попытка

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

		ПрисоединенныйФайлОбъект = ПрисоединенныйФайл.ПолучитьОбъект();
		ЗаблокироватьДанныеДляРедактирования(ПрисоединенныйФайл, , УникальныйИдентификатор);

		СвойстваФайла = СвойстваФайлаВТоме();
		ЗаполнитьЗначенияСвойств(СвойстваФайла, ПрисоединенныйФайлОбъект);

		ПутьКТому = ПолныйПутьТома(ПрисоединенныйФайлОбъект.Том);
		ТекущийПутьКФайлу = ПолноеИмяФайлаВТоме(СвойстваФайла);

		ФайлНаДиске = Новый Файл(ТекущийПутьКФайлу);
		ИмяДляЗамены = ?(ПустаяСтрока(СтароеИмя), ПрисоединенныйФайлОбъект.Наименование, СтароеИмя);
		НовоеИмяФайла = СтрЗаменить(ФайлНаДиске.ИмяБезРасширения, ИмяДляЗамены, НовоеИмя) + ФайлНаДиске.Расширение;

		НовыйПутьКФайлу = ФайлНаДиске.Путь
			+ РаботаСФайламиСлужебныйКлиентСервер.УникальноеИмяСПутем(ФайлНаДиске.Путь, НовоеИмяФайла);

		ПереместитьФайл(ТекущийПутьКФайлу, НовыйПутьКФайлу);

		ПрисоединенныйФайлОбъект.ПутьКФайлу = СтрЗаменить(НовыйПутьКФайлу, ПутьКТому, "");
		ПрисоединенныйФайлОбъект.Записать();

		РазблокироватьДанныеДляРедактирования(ПрисоединенныйФайл, УникальныйИдентификатор);
		ЗафиксироватьТранзакцию();

	Исключение
		ОтменитьТранзакцию();
		РазблокироватьДанныеДляРедактирования(ПрисоединенныйФайл, УникальныйИдентификатор);
		ВызватьИсключение;
	КонецПопытки;

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

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

Функция СвойстваФайлаВТоме(Файл = Неопределено) Экспорт

	СвойстваФайла = Новый Структура;
	СвойстваФайла.Вставить("Наименование", "");
	СвойстваФайла.Вставить("Расширение", "");
	СвойстваФайла.Вставить("Том", Справочники.ТомаХраненияФайлов.ПустаяСсылка());
	СвойстваФайла.Вставить("ПутьКФайлу", "");
	СвойстваФайла.Вставить("ВладелецФайла", Неопределено);
	СвойстваФайла.Вставить("НомерВерсии", "");

	Если ЗначениеЗаполнено(Файл) Тогда

		Если ТипЗнч(Файл) = Тип("СправочникСсылка.Файлы") Тогда
			СсылкаНаВерсию = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Файл, "ТекущаяВерсия");
		Иначе
			СсылкаНаВерсию = Файл;
		КонецЕсли;

		// Во время удаления файла версии могут не существовать.
		ПроверяемоеСвойство = Новый Структура("ВерсияДанных");
		ЗаполнитьЗначенияСвойств(ПроверяемоеСвойство, СсылкаНаВерсию);
		Если НЕ ЗначениеЗаполнено(ПроверяемоеСвойство.ВерсияДанных) Тогда
			СсылкаНаВерсию = Файл;
		КонецЕсли;

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

		ИменаРеквизитов = СтрСоединить(РеквизитыФайла, ",");
		РеквизитыФайла = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(СсылкаНаВерсию, ИменаРеквизитов);
		ЗаполнитьЗначенияСвойств(СвойстваФайла, РеквизитыФайла);

		Если РеквизитыФайла.Свойство("Владелец") И ЗначениеЗаполнено(РеквизитыФайла.Владелец) Тогда
			СвойстваФайла.ВладелецФайла = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(РеквизитыФайла.Владелец, "ВладелецФайла");
		КонецЕсли;

	КонецЕсли;

	Если ТипЗнч(СвойстваФайла.НомерВерсии) <> Тип("Строка") Тогда
		СвойстваФайла.НомерВерсии = Строка(СвойстваФайла.НомерВерсии);
	КонецЕсли;

	Возврат СвойстваФайла;

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

// Возвращает полное имя для файла в томе с учетом настроек
// хранения файлов в томах и значений разделителя.
//
// Параметры:
//   СвойстваФайла - см. СвойстваФайлаВТоме.
//   ДатаДляРазмещенияВТоме - Дата
//
// Возвращаемое значение:
//   Строка
//

Функция ПолноеИмяФайлаВТоме(СвойстваФайла, ДатаДляРазмещенияВТоме = Неопределено) Экспорт

	Разделитель = ПолучитьРазделительПути();

	Если НЕ ЗначениеЗаполнено(СвойстваФайла.Том) Тогда
		Возврат "";
	КонецЕсли;

	ПолныйПутьТома = ПолныйПутьТома(СвойстваФайла.Том);
	Если Не ПустаяСтрока(СвойстваФайла.ПутьКФайлу) Тогда
		Возврат ПолныйПутьТома + СвойстваФайла.ПутьКФайлу;
	КонецЕсли;

	КорневойКаталог = ПолныйПутьТома + ?(Прав(ПолныйПутьТома, 1) = Разделитель, "", Разделитель);
	Если СоздаватьПодкаталогиСИменамиВладельцев() Тогда
		ИмяКаталогаВладельцаФайла = ИмяКаталогаВладельцаФайла(СвойстваФайла.ВладелецФайла);
		КорневойКаталог = КорневойКаталог + ИмяКаталогаВладельцаФайла + ?(ИмяКаталогаВладельцаФайла = "", "", Разделитель);
	КонецЕсли;

	ДатаРазмещения = ?(ЗначениеЗаполнено(ДатаДляРазмещенияВТоме), ДатаДляРазмещенияВТоме, ТекущаяДатаСеанса());
	КорневойКаталог = КорневойКаталог + Формат(ДатаРазмещения, "ДФ=ггггММдд") + Разделитель;

	ИмяФайла = СвойстваФайла.Наименование
		+ ?(ЗначениеЗаполнено(СвойстваФайла.НомерВерсии), "." + СвойстваФайла.НомерВерсии, "")
		+ ?(СтрНайти(СвойстваФайла.Расширение, ".") > 0, СвойстваФайла.Расширение, "." + СвойстваФайла.Расширение);

	ОбщегоНазначения.СократитьИмяФайла(ИмяФайла);

	Попытка
		Возврат КорневойКаталог
			+ РаботаСФайламиСлужебныйКлиентСервер.УникальноеИмяСПутем(КорневойКаталог, ИмяФайла);
	Исключение
		Том = Новый Файл(ПолныйПутьТома);
		Если Не Том.Существует() Или Не Том.ЭтоКаталог() Тогда
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не существует сетевой каталог для тома хранения файлов ""%1"": %2
					|Обратитесь к администратору.'"), СвойстваФайла.Том, ПолныйПутьТома);
		КонецЕсли;
		ВызватьИсключение;
	КонецПопытки
КонецФункции

// Возвращает полный путь к корневому каталогу тома хранения файлов.
//
// Параметры:
//   Том - СправочникСсылка.ТомаХраненияФайлов - том, путь к корневому каталогу которого необходимо получить.
//
// Возвращаемое значение:
//   Строка - полный путь к корневому каталогу тома.
//


Процедура ПолеПредпросмотраПеретаскивание(Форма, Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка) Экспорт

	СтандартнаяОбработка = Ложь;
	Если Форма.ТолькоПросмотр Или Элемент.ТолькоПросмотр Тогда
		Возврат;
	КонецЕсли;

	НомерЭлемента = Число(СтрЗаменить(Элемент.Имя, "ПолеКартинкиПрисоединенногоФайла", ""));
	ТолькоОдинФайл = Форма.ПараметрыРаботыСФайлами.ОписанияЭлементовФормы[НомерЭлемента].ТолькоОдинФайл;
	ВладелецПрисоединенныхФайлов = ЗначениеПараметраПрисоединенногоФайла(Форма, Число(НомерЭлемента), "ПутьКДаннымВладельца");

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

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

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

// Обработчик проверки перетаскивания на поле предпросмотра.
//
// Параметры:
//  Форма                   - ФормаКлиентскогоПриложения - форма владельца файла.
//  Элемент                 - ПолеФормы - поле предпросмотра.
//  ПараметрыПеретаскивания - ПараметрыПеретаскивания - стандартный параметр события Проверка
//                          перетаскивания поля формы.
//  СтандартнаяОбработка    - Булево - стандартный параметр события Проверка перетаскивания поля формы.
//

Процедура ПолеПредпросмотраПроверкаПеретаскивания(Форма, Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка) Экспорт

	СтандартнаяОбработка = Ложь;

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

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

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

// Устарела. Следует использовать РаботаСФайламиКлиент.ОткрытьФормуФайла
// Открывает форму файла из формы элемента справочника файлов. Форма элемента закрывается.
//
// Параметры:
//  Форма     - ФормаКлиентскогоПриложения - форма справочника присоединенных файлов.
//

Процедура ПерейтиКФормеФайла(Знач Форма) Экспорт

	ПрисоединенныйФайл = Форма.Ключ;

	Форма.Закрыть();

	Для Каждого ОкноПриложения Из ПолучитьОкна() Цикл

		Содержимое = ОкноПриложения.ПолучитьСодержимое();

		Если Содержимое = Неопределено Тогда
			Продолжить;
		КонецЕсли;

		Если Содержимое.ИмяФормы = "Обработка.РаботаСФайлами.Форма.ПрисоединенныйФайл" Тогда
			Если Содержимое.Параметры.Свойство("ПрисоединенныйФайл")
				И Содержимое.Параметры.ПрисоединенныйФайл = ПрисоединенныйФайл Тогда
				ОкноПриложения.Активизировать();
				Возврат;
			КонецЕсли;
		КонецЕсли;

	КонецЦикла;

	ОткрытьФормуФайла(ПрисоединенныйФайл);

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

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

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

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

// Процедура предназначена для печати файла соответствующим приложением
//
// Параметры:
//  ДанныеФайла          - см. РаботаСФайлами.ДанныеФайла.
//  ИмяОткрываемогоФайла - Строка.
//

Процедура НапечататьФайлПриложением(ДанныеФайла, ИмяОткрываемогоФайла)

#Если МобильныйКлиент Тогда
	ПоказатьПредупреждение(, НСтр("ru = 'Печать файлов данного типа возможна только из приложения для Windows или Linux.'"));
	Возврат;
#Иначе
	РасширенияИсключения =
		" m3u, m4a, mid, midi, mp2, mp3, mpa, rmi, wav, wma,
		| 3g2, 3gp, 3gp2, 3gpp, asf, asx, avi, m1v, m2t, m2ts, m2v, m4v, mkv, mov, mp2v, mp4, mp4v, mpe, mpeg, mts, vob, wm, wmv, wmx, wvx,
		| 7z, zip, rar, arc, arh, arj, ark, p7m, pak, package,
		| app, com, exe, jar, dll, res, iso, isz, mdf, mds,
		| cf, dt, epf, erf";

	Расширение = НРег(ДанныеФайла.Расширение);

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

	Попытка

		Если ОбщегоНазначенияКлиент.ЭтоWindowsКлиент() Тогда
			ИмяОткрываемогоФайла = СтрЗаменить(ИмяОткрываемогоФайла, "/", "\");
		КонецЕсли;

		НапечататьИзПриложенияПоИмениФайла(ИмяОткрываемогоФайла);

	Исключение
		ПоказатьПредупреждение(, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось распечатать файл по причине:
				|%1'"), ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке())));

	КонецПопытки;
#КонецЕсли

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

// Процедура печати Файла
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//  ПараметрыВыполнения  - Структура:
//        * НомерФайла               - Число - номер текущего файла.
//        * ДанныеФайла              - Структура
//        * УникальныйИдентификатор  - УникальныйИдентификатор.
//

Процедура НапечататьФайлыВыполнение(ОбработчикРезультата, ПараметрыВыполнения) Экспорт

	ОбработкаПрерыванияПользователя();

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

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

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

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

// Процедура печати Файла после получения на компьютер.
//
// Параметры:
//  Результат - Структура:
//    * ФайлПолучен - Булево
//    * ПолноеИмяФайла - Строка
//  ПараметрыВыполнения  - Структура:
//    * НомерФайла               - Число - номер текущего файла.
//    * ДанныеФайла              - Структура
//    * УникальныйИдентификатор  - УникальныйИдентификатор.
//

Процедура НапечататьФайлПослеПолученияВерсииВРабочийКаталог(Результат, ПараметрыВыполнения) Экспорт

	Если Результат.ФайлПолучен Тогда

		Если ПараметрыВыполнения.НомерФайла >= ПараметрыВыполнения.ДанныеФайлов.Количество() Тогда
			Возврат;
		КонецЕсли;

		НапечататьФайлПриложением(ПараметрыВыполнения.ДанныеФайла, Результат.ПолноеИмяФайла);

	КонецЕсли;

	// переходим к печати следующего файла.
	ПараметрыВыполнения.НомерФайла = ПараметрыВыполнения.НомерФайла + 1;
	Обработчик = Новый ОписаниеОповещения("НапечататьФайлыВыполнение", ЭтотОбъект, ПараметрыВыполнения);
	ВыполнитьОбработкуОповещения(Обработчик);

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

// Выполняет печать файла внешним приложением.
//
// Параметры:
//  ИмяОткрываемогоФайла - Строка
//