четверг, 16 января 2020 г.

Почему последний выбранный файл появляется первым, когда я выбираю несколько файлов в диалоге открытия файла?

Это перевод When I select multiple files in the File Open dialog, why does the last item come first? Автор: Реймонд Чен.

Если у вас есть диалог открытия файла, который поддерживает множественный выбор, и вы выбираете несколько файлов, вы можете заметить, что файл, выбранный последним, указывается первым. Это раздражает, если порядок файлов при выборе является важным (прим. пер.: например, при добавлении фото в альбом). Почему последний выбранный элемент становится первым в списке?

Это случай утечки абстракции.

Диалог открытия файлов показывает список выбранных элементов в том же порядке, в котором они возвращаются методом IShellView.GetItemObject расширения пространства имён:
var
  pdto: IDataObject;
begin
  ShellView.GetItemObject(SVGIO_SELECTION, IID_PPV_ARGS, pdto);
Если используется расширение, предоставленное системой, то оно возвращает выбранные элементы в том порядке, в котором они отображаются в представлении (view), за исключением того, что текущий фокусированный элемент всегда идёт первым.

Хорошо, тогда почему сфокусированный предмет стоит первым?

Для того, чтобы получить лучшее контекстное меню.

Когда вы вызываете контекстное меню для группы файлов, оболочка должна решить, какой обработчик контекстного меню будет вызван для предоставления действий (verb). К примеру, вы могли бы запросить своё контекстное меню у каждого отдельного файла, а затем как-то получить итоговое меню. Возможно, вы показали бы пересечение всех контекстных меню (общие элементы). Может быть, вы показали бы объединение всех контекстных меню - и если пользователь выбирает действие, которое недоступно для каких-то элементов, то вы просто игнорируете элементы, которые не могут его выполнить.

Но всё это было бы достаточно сложно, хотя бы потому, что сопоставление действий с другом контекстном меню - это эвристика и догадки. Если в двух контекстных меню есть действие "Сделать текущим" - означает ли это, что они эквивалентны?

Поэтому, вместо того, чтобы создавать большое количество контекстных меню и пытаться объединить их не совсем бессмысленным способом, оболочка просто выбирает один из элементов и говорит: "Окей, ты - ответственный за меню". И действия от этого файла будут действиями для всего выделения. (Также не забывайте, что у нас было аж 4 МБ памяти для работы).

Окей, мы приближаемся к ответу.

Если вы выберете несколько файлов, а затем щёлкните правой кнопкой мыши на выделении, оболочка должна выбрать кого-то, кто будет создавать контекстное меню. И алгоритм, который она использует - это "Я выберу сфокусированный элемент". А способ выбора, заключается в установке сфокусированного элемента в качестве первого элемента.

Теперь мы можем раскручиваться в обратную сторону. Сфокусированный элемент ставится первым элементом при выборе. В диалоге открытия файлы элементы в строке ввода идут в том же порядке, в котором они отображаются при выборе. В результате сфокусированный элемент (a.k.a. последний выбранный) появляется первым в строке редактирования.

Какое-то время спустя (я не знаю когда точно), в метод IShellView.GetItemObject был добавлен флаг SVGIO_FLAG_VIEWORDER, который сообщает представлению: "Не помещай сфокусированный элемент первым. Просто верни мне всё в том же порядке, в котором они отображаются".

Когда этот флаг был добавлен, никто не почесался модифицировать диалог открытия файла, чтобы тот использовал его. Диалог по-прежнему запрашивает выбранные элементы старомодным способом, а старомодный способ - вернуть выбранный элемент первым.

Но подождите, вы здесь не совсем беспомощны. Если вы так возмущены, то можете отправить просьбу использовать флаг SVGIO_FLAG_VIEWORDER в диалоге открытия файла, чтобы выбранные элементы отображались бы в том же порядке. Если эта просьба получит достаточно голосов, то что-нибудь произойдёт (может быть). Эй, это сработало для персидского календаря.

Комментариев нет:

Отправка комментария

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку.

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.