Strange multiselect in Flex lists

With old halo lists mx:List you can allow the user to select multiple list items. Set allowMultipleSelection = true and you can add single items to the selected group via Ctrl + Click. Via Shift + Click you can select a set of items. Click on one item to select the first and then Shift + Click on another one to select the whole range of items between the first and last one (each included).

Nothing unexpected so far.

But if you do another Shift + Click to change the selected range, the Flex list reacts strangely. For example, say you’ve clicked on item 3 and then Shift + clicked on item 5, you select items 3 to 5. But what happens when you Shift + click on item 7 afterwards? Windows Explorer and MacOS X Finder will select items 3 to 7. If you then Shift + click on 1, they select 1 to 3. So, the general rule for those standard item lists is that you set an anchor with the first click and each following Shift + click selects all items between this anchor and the last clicked item.

But not so in the Flex list. mx:List resets the anchor with every Shift + click to the last clicked item. The following table highlights the described differences between Explorer/Finder and the Flex list:

Action Explorer Finder mx:List
click 3 3 3 3
shift+click 5 3-5 3-5 3-5
shift+click 7 3-7 3-7 5-7
shift+click 1 1-3 1-3 1-7

I think this is very confusing for the user, because there is no obvious reason for the flex lists to behave in a different way than the corresponding native lists of the operating system. So I wrote the following patch to fix this:

import mx.collections.CursorBookmark;
import mx.controls.List;
import mx.controls.listClasses.IListItemRenderer;

public class OSLikeList extends List {

    private var firstShiftClick:Boolean = true;
    private var oldAnchorBookmark:CursorBookmark;
    private var oldAnchorIndex:int;

    public function OSLikeList() {
        super();
    }

    override protected function selectItem(item:IListItemRenderer, shiftKey:Boolean, ctrlKey:Boolean, transition:Boolean = true):Boolean {
        if (shiftKey && allowMultipleSelection) {
            if (firstShiftClick) {
                oldAnchorBookmark = anchorBookmark;
                oldAnchorIndex = anchorIndex;
                firstShiftClick = false;
            } else {
                anchorIndex = oldAnchorIndex;
                anchorBookmark = oldAnchorBookmark;
            }
        } else {
            firstShiftClick = true;
        }
        return super.selectItem(item,  shiftKey, ctrlKey, transition);
    }

}
Advertisements