В этом блоге хочу рассказать о развитии Drag&Drop в версии 3.4.x+
Никому не секрет, что DataGrid «умеет» принимать файлы с помощью Drag&Drop. Такая функциональность реализована на детали «Файлы». Но, для того, чтобы файлы извлечь с детали «Файлы», к примеру, прикрепить к письму, требуется совершать операции по сохранению его на жесткий диск, а уж потом перемещать куда нужно. Данный способ манипулирования файлами занимает много времени. Поэтому, в DataGrid был добавлен функционал полноценного Drag&Drop. Теперь есть возможность сохранять файлы только с помощью мыши. Также, весьма немаловажным бонусом, появилась возможность копировать и вставлять файлы с помощью комбинаций Ctrl+C/Ctrl+V. Именно с помощью этих операций не обойтись при переносе файлов внутри системы (файлы из одной записи в другую, из одного раздела – в другой). Плюс к выше сказанному появилась «автогенерация файлов по формату». Т.е., при нажатии Ctrl+V система анализирует содержимое буфера и генерирует (+ сохраняет) файл нужного формата.
Поддерживаемые форматы:
- Все изображения. Любое изображение будет сохранено в PNG формате (даже если Вы нажали Print Screen, то система сгенерирует Вам готовый файл)
- RTF. Любой форматированный текст буде сохранен в формате *.rtf
- HTML. Любой текст с HTML разметкой будет сохранен в *.html файл
- TEXT. Любой текст, который не является RTF – будет сохранен в *.txt файл
Дальше речь пойдет о реализации этих возможностей. Для начала пройдемся по имеющимся, а также новым свойствам:
- CanCopySystemObjects – свойство, которое разрешает или запрещает копирование с помощью Ctrl+C
- CanDragDropSystemObjects – знакомое свойство с предыдущих версий, которое разрешает или запрещает Drag&Drop в систему. Однако, в 3.4.x оно еще отвечает и за Drag&Drop из системы
- CanPasteSystemObjects – свойство, которое разрешает или запрещает вставку с помощью Ctrl-V
Также, помимо свойств, появились новые события:
- OnGetSystemObjectNames – в обработчике события нужно заполнить имена файлов, которые будут копироваться (файлы будут сохранены под этими именами и расширениями). По количеству имен в списке будут генерироваться события OnGetSystemObjectData
- OnGetSystemObjectData - это событие придет столько раз, сколько было задано имен файлов в обработчике события OnGetSystemObjectNames. И при каждом вызове будет прислан Index файла, данные которого нужны. В обработчике необходимо вернуть поток данных согласно индексу файла
- OnPasteSystemObject – данное событие будет генерироваться при нажатии Ctrl+V. В него будет передан список файлов, которые нужно сохранить
- OnGetSystemObjectText – данное событие генерируется в том случае, когда «приемник» файла не может принять файл, но может принять текст. Поэтому в обработчике можно изменить текст, который будет передан
Маленьким, но приятным бонусом, появилась возможность отображать иконки, зарегистрированные в Windows согласно расширению файла:
Для того, нужно в обработчике OnGetRowDrawInfo, параметру ImageName нужно установить значение имени файла с расширением. Причем имя значения не имеет, так как поиск будет происходить только по расширению файла. Пример:
function OnGetRowDrawInfo(DataGrid, Color, TextColor, ImageName, Font) {
ImageName.Value = 'File.docx'; //Все элементы будут отображать иконку Word’а
ImageName.Value = 'File.xls' //Все будут отображать иконку Excel
}
Перед тем, как подвести итог, я предоставлю код реализации этих возможностей:
//Эта функция идентична для сохранения файлов как на
//событие OnDragDropSystemObjects, так и на OnPasteSystemObjects
function InsertSystemObjects(SystemObjectsList) {
var FilesArray = SystemObjectsList.CommaText.split(',');
var FileNames = System.CreateObject('TSObjectLibrary.StringsList');
for (var i = 0; i FilesArray.length; i++) {
FileNames.Clear();
var Path = FilesArray[i];
while (Path.indexOf('"', 0) != -1) {
Path = Path.replace('"', '')
}
FileNames.Add(Path);
if (!CheckFileExists(Path)) {
AddObject(ft_FolderLink, Path, 1, null);
} else {
AddObject(ft_File, FileNames, 1, null);
}
}
}
//Реакция на Drag&Drop
function grdDataOnDragDropSystemObjects(DataGrid, DataGridColumn, SystemObjectsList, DestinationRowID, DropMode, WithCtrl) {
InsertSystemObjects(SystemObjectsList);
}
//Реакция на Ctrl+V
function grdDataOnPasteSystemObjects(DataGrid, DataGridColumn, SystemObjectsList, SelectedIDs) {
InsertSystemObjects(SystemObjectsList);
}
//Запрос имен объектов, который нужно копировать
//Если, в обработчике , вы запретите копировать какой-то
//файл (не передадите его имя), то в обработчике события
//OnGetSystemObjectData вам также нужно реализовывать
//дополнительные проверки
function grdDataOnGetSystemObjectNames(DataGrid, SourceDataGrid, SelectedIDs, SystemObjectNames) {
var Dataset = GetSingleItemByCode('ds_Files', 'SystemObjectsFileDetail');
var FileDataDataField = Dataset.DataFields.ItemsByName('FileData');
EnableDatasetFilters(Dataset, false, 'ID');
EnableDatasetField(Dataset, FileDataDataField, false);
Dataset.Open();
for (var i = 0; i SelectedIDs.Count; i++) {
if (!Dataset.Locate('ID', SelectedIDs(i))) {
continue;
}
SystemObjectNames.Add(Dataset('Link'));
}
Dataset.Close();
}
//Как было сказано выше - это событие генерируется для
//каждого файла, имя которого было указано в обработчике
//события OnGetSystemObjectNames. Порядок в списке
//файлов совпадает с порядком генерации события.
//Т.е., параметр SystemObjectIndex – это индекс в списке имен файлов
function grdDataOnGetSystemObjectData(DataGrid, SourceDataGrid, SelectedIDs, SystemObjectIndex, SystemObjectData) {
if (!SelectedIDs) {
return;
}
if (SystemObjectIndex >= SelectedIDs.Count) {
return;
}
var RecordID = SelectedIDs(SystemObjectIndex);
var Dataset = GetSingleItemByCode('ds_Files', 'SystemObjectsFileDetail');
var FileDataDataField = Dataset.DataFields.ItemsByName('FileData');
ApplyDatasetFilter(Dataset, 'ID', RecordID, true);
EnableDatasetField(Dataset, FileDataDataField, true);
Dataset.Open();
//Из Blob поля мы просто сохраняем значение в поток SystemObjectData
Dataset.DataFields.ItemsByName('FileData').GetValAsBlob(SystemObjectData);
Dataset.Close();
}
Важно для разработчика:
- События OnGetSystemObjectNames, OnGetSystemObjectData и OnGetSystemObjectText начинают приходить только после того, как вы нажали Ctrl+V или отпустили кнопку мыши (при перетаскивании файлов) вне зависимости от того наше ли это приложение, или же стороннее
- События OnGetSystemObjectNames, OnGetSystemObjectData и OnGetSyestemObjectText в качестве параметра SelectedIDs принимают список IDs записей, которые действительно были скопированы (это важно). Этот список может не совпадать с DataGrid.SelectedIDs или SourceDataGrid.SelectedIDs. Связано это с тем, что вы можете переносить файлы, к примеру, с одного договора – в другой, и при этом DataGrid == SourceDataGrid (ведь это та же деталь), а при переходе на другую запись основного реестра применится фильтр для детали, и SourceDataGrid .SelectedIDs уже будет содержать совершенно другие значения
- В событие OnGetSystemObjectNames в качестве параметра SystemObjectNames приходит уже созданный IStringsList, Вам не нужно его создавать или же уничтожать – нужно только заполнить
- В событие OnGetSystemObjectData в качестве параметра SystemObjectData приходит уже созданный IStream. Вам достаточно просто записать в него значение. Создавать или уничтожать его также не нужно
- Событие OnGetSystemObjectText приходит только тогда, когда «приемник» не может принять файл(ы) (к примеру, при вставке в открытый документ Word). В нем можно указать текст, который необходимо вставить
- Вы можете пропустить копирование какого-либо файла. Для этого достаточно внести изменения в код обработчика OnGetSystemObjectData:
//Чтобы отменить копирование файла не обязательно его
//отсутствие в списке файлов, достаточно отменить его по индексу
function grdDataOnGetSystemObjectData(DataGrid, SourceDataGrid, SelectedIDs, SystemObjectIndex, SystemObjectData) {
if (!SelectedIDs) {
return;
}
if (SystemObjectIndex >= SelectedIDs.Count) {
return;
}
//К примеру мне не хочется, чтобы пользователь
//скопировал 2-й выбранный файл
//Для этого достаточно выйти из функции, не
//заполняя поток SystemObjectData
If (SystemObjectIndex == 1) {
return;
}
- Перемещение между DataGrid внутри системы осуществляется разными способами, в зависимости от установленных свойств. Рассмотрим 2 случая:
- Перемещение по умолчанию
- Копирование файла(ов)
При манипуляции комбинациями Ctrl+C/Ctrl+V все аналогично, только учитывается свойство CanPasteSystemObjects
Собственно, это все, что я хотел рассказать о развитии Drag&Drop’а.
Приятной работы!
P.S. Вся функциональность доступна в версиях 3.4.0.99+ и 3.4.1.16+