. .


The Joys of Selection Trackers, Part Two

December 15, 2010 21:28:11.052

Yesterday, I pushed up a post detailing a hack I did to make drag/drop in VisualWorks listboxes work more like they are expected to work. One problem though; my "fix" pretty much breaks select on down, which isn't really what you want.

As is usually the case with such things, if the fix seems overly complex, you're probably doing something wrong - and I certainly was here. The problem comes up in EmulatedSequenceTracker>>setUpDragDropFor:

setUpDragDropFor: aMouseButtonEvent 
	"If we are doing drag and drop, we don't have to do the preparation 

	self outside: false.
	(controller selectOnDownWithDrag and: [self view selectionIndex ~= self view targetIndex])
			[(self isTryingToGrabPreviouslySelectedAreaWith: aMouseButtonEvent)
				ifFalse: [self controller toggleTargetWithEvent: aMouseButtonEvent].
			selectionDone := true]

Notice the change from what I posted yesterday. Instead of outright ignoring the selection, I added a test - and the test method looks like this:

isTryingToGrabPreviouslySelectedAreaWith: anEvent
	"if the user is trying to grab a previously selected area, and drag/drop is on, answer true.  Otherwise answer false"

	| index indices |
	controller wantsToDrag
		ifFalse: [^false].
	index := self view targetIndex.
	indices := self view selectionChannel value.
	(self eventHasKeyboardOptionsDown: anEvent)
		ifTrue: [^false].
	^(indices includes: index)

Basically, you ask three questions:

  • Is drag/drop on? If not, just proceed normally
  • Is the user trying to select a previously selected thing (individually or a group)? If so, ignore that selection so that drag/drop can proceed.
  • With respect to the previous test, let the event proceed if a keyboard modifier is down

That test on keyboard modifier looks like this:

eventHasKeyboardOptionsDown: anEvent
	"we want keyboard modifiers to still affect the selection - the #respondsTo: test makes this
	work in both VW 7.6 (and older) and VW 7.7.1"

	^(anEvent respondsTo: #ctrlOrCommandDown)
		ifTrue: [anEvent ctrlOrCommandDown | anEvent shiftDown]
		ifFalse: [anEvent ctrlDown | anEvent altDown | anEvent shiftDown]

With that, it looks like things respond the way you would expect, and select on down works (unlike the hack I posted yesterday). I also think this is closer to a supportable fix - although I suspect a full rewrite of the controller and tracker are still a decent idea. You can find the code in the public repository as MultiSelectPatch. Kind of outside my scope though :)

posted by James Robertson

 Share Tweet This