If you have a File Open dialog that supports multiple selections, and you select multiple files, you may notice that the file you selected last is listed first. This is annoying when the order of the files in the selection is significant. Why does the last item selected become the first item listed?
This is a case of a leaky abstraction.
The File.Open dialog shows the list of selected items in the order they are provided by the namespace extension’s IShellView::GetItemObject()
method:
IDataObject *pdto; shellView-->GetItemObject(SVGIO_SELECTION, IID_PPV_ARGS(&pdto));
The system-provided filesystem namespace extension returns the selected items in the order they appear in the view, with the exception that the current focused item always comes first.
Okay, so why does the focused item come first?
In order to get a better context menu.
When you ask for the context menu of a group of files, the shell needs to decide which context menu handler will be asked to provide the verbs. One idea would be to ask each individual file for its context menu, and then combine all the context menus somehow. Maybe you show the intersection of all of the context menus. Maybe you show the union of all the context menus, and if the user picks an action that is not available on all items, it just ignores the items that can’t do it.
But all of that would have been a lot of work, especially since matching up verbs on different context menu is a bit of guesswork. If two context menus have a verb called “Make Current”, does that mean that they are equivalent? What if one of them is a verb on a database, and “Add Table” adds a table to the database; whereas the other one is a verb on a 3D model, and “Add Table” adds a piece of furniture to the model.
Rather than creating a large number of context menus and trying to merge them in a not-completely-nonsensical way, the shell just picks one of the items and says, “Okay, you are the one in control.” And the verbs that come from that file are the verbs for the entire selection. (Don’t forget, we had 4MB of memory to work with.)
Okay, we’re getting closer.
If you select a bunch of files, and then right-click the selection, the shell has to pick somebody to be the one that sets the context menu. And the algorithm it uses is “I’ll pick the item that has focus.” And the way the view conveys this is by setting the focus item as the first item.
Okay, so now we can start unwinding. The focus item is the first item in the selection. And the File Open dialog lists the items in its edit box in the order they appear in the selection. The result is that the focus item appears first in the edit box.
Sometime later (I don’t know exactly when), the flag SVGIO_FLAG_VIEWORDER
was added to the IShellView::GetItemObject
method, which tells the view, “Don’t put the focus item first. Just give me the items in the order they appear in the view.”
When this flag was added, nobody went back and retrofitted the File Open dialog to use it. It still asks for the selected items the old-fashioned way, and the old-fashioned way is to return the focus item first.
But wait, you’re not entirely helpless here. If you are so moved, you could submit feedback requesting that the File Open dialog use the SVGIO_FLAG_VIEWORDER
flag so that the selected items show up in view order. Maybe if it gets enough votes, something will happen. Hey, it worked for the Persian calendar.
It’s kind of funny that about half of my “daily driver” programs invert this behavior, expecting it to happen. The end result is that now I never know if I’ll get the first or last selected item at the top of my upload queue!
Was the term “leaky abstraction” borrowed from Joel Spolsky or it’s the other way around?
That’s why I always select from bottom to top instead of top to bottom.
The whole story of context menu for multiple items is more complicated, and some verbs/submenus are suppressed from the context menu even if you just select multiple PDFs. I remember when I was a naive programmer, I just decided to move the first item last to get the “correct” order. Didn’t know this was related to focus!
Before Vista, the NSE helper function that creates the menu for you was limited to about 20 HKEYs so even if you wanted to, you could not put all the commands from all the different file extensions in one menu.
Hey, that’s cool that my submitted question was answered. Just for context, the reason I find this behavior annoying is when selecting a block of mp3s to play it will play the last one first (sometimes unimportant, but when the order of files is important (chapters, sountracks, musicals) can be irksome).
I read it several times but still do not fathom why it has to set the focsed item first just because it want to showi the context menu menu for the focused item.
I think a better explanation can be:
some code want to show the context menu but it only has a list of items. it pick the first item.
some other code is handling gui selection. it always put the focused item at...
Alternatively use Ctrl+Click to deselect and then reselect whichever item you want to appear first. It will then have the focus. That’s what I do. (I figured out what it was doing).
Alternatively select the items from bottom to top so that the focused item is the first item.