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