|Home » Learning Curve » Hotspots
Happy Valentine's 10.5.
This article is actually a developers article but it concerns Leofart and it also concerns ordinary users so please read along.
It's got to do with the infamous Cocoa table view. This table view shouldn't be infamous because it's a chief mainstay of the system but nevertheless it is. Back in the autumn of 2002 a number of remarks from this website brought the fanboys out of the snake pits in a royal stink; again right around the holiday season Scot Hacker of BeOS fame found the same anomaly, got a lot of traction for his published article, got Apple to admit off the record they were aware of the issue, and got a promise they'd look into it.
But that was then and this is now. Things aren't better - they're just different. OK that's not true. Actually they're worse. Much worse. Sorry but it's true. A table view that started behaving five years ago and basically hasn't caused any trouble in all that time - and now it's time to 'improve' things again. It's time for 'progress'.
The Cocoa table view is found everywhere. It's one of the most obsequious 'controls' used in NeXTSTEP Cocoa - and all the more surprising Aaron Hillegass' less than excellent first Cocoa book doesn't even mention it. But it's there and it has to be used and it is used - extensively.
You can see it in use in programs like CLIX and in iTunes.
Essentially it holds a kind of 'flat database': the rows in the view are the records and the columns are the fields in each record.
It's quite common to use a so called 'master detail' design where the detail for the purpose of saving screen real estate is hidden from view. In the case of CLIX and similar programs it's a 'double click' which summons up the detail view in the form of a 'sheet'.
For this purpose the table view admits of a way to configure the 'double action'.
This method is also shared by the classes NSBrowser, NSMatrix, and NSStatusItem.
What you're doing here is 'connecting' the 'action' of the double click with an 'event handler' in the controller code. The argument 'aSelector' is a @selector value to the code method in the controller class that will accept notifications there's been a double click.
When the application gets told there's been a double click it performs the intended action such as summoning up a detail sheet.
Prior to Leofart there was a caveat that meant a bit of band-aid code: quickly clicking on a column header in a table view would not only send away the message there'd been a click (or two) in a column header - it would also use the 'double action' channel. Bummer. So ISV code had to make sure the 'row' being clicked was in fact valid.
There are two ways to check which row's been clicked up to Leofart, both in practice equivalent. The one asked for the clicked row and the other asked for the selected row. And as any click on any row automatically changes the selection they were in fact equivalent. In practice.
Leofart's Cocoa brings with it a new 'enhancement'. And unusually enough it's not turned off by default so as to be backward compatible - it's turned on. Obviously somebody was really in love with their handiwork and wanted everybody to use it (or suffer by it). This little gem is something copied from Windows where it's been in use for the past fifteen years or so - but oddly enough never before on OS X with Cocoa.
It's the 'mnemonic' - or as the new Cocoa API calls it: 'allowsTypeSelect'. And it's on by default.
When you hit any key on your keyboard - any key at all - the table view will attempt to find the corresponding character in the first position in any field of any record (any column of any row) after your current selection. And if there's a hit it will scoot your selection there.
Sounds good so far. But let's make it really user friendly. And for the record: a lot of ISVs have implemented this on their own long before (and a lot better too).
What happens now is the programmer is suddenly apprehensive. After all these fields in these records can also be configured so they're directly editable - that's one reason. Another might be you're scared of repeating keys. Whatever. The trick is a timer is used on this function - a timer that demands a full second of inactivity before it does anything. Right up until that one second expires all keyboard input is discarded.
You can try this on both Tiger and Leofart and compare. On Tiger nothing will happen; on Leofart you'll see your selection bar scoot along - as long as you wait the perfunctory one second between keyboard hits.
Now there's an incredible snag coming up and you surely realise that. For otherwise this article is little more than a Mac OS X Hints post. But the caveat is it's already been tested and what you've just learned above is not connected with what you're about to learn - at least not to the extent you can turn this other 'feature' off.
For it turns out the mouse is also burdened by a timer in Leofart as well. And this timer - and it can very well be the same timer so as to conserve rather expensive resources - also forces a one second delay.
Try it on both Tiger and Leofart and compare. Start a program like CLIX, load a file that consumes the entire document window, and select all. You'll see all your rows (records) selected.
Now single click a row in the the middle at random. On Tiger you'll see the behaviour you're accustomed to. And of course you're accustomed to it. All platforms work this way. And always have.
Now try the same thing on Leofart. And you'll notice a one second delay before your old selection disappears and your new selection takes its place.
The Band-Aid Tree
ISV code for OS X Cocoa is more and more resembling a band-aid tree. Time and again there's a blooper been done in the loop and people have to patch their code with workarounds. And this isn't temporary either as Apple by definition almost never go back and correct or roll back their gaffes. Meaning people on legacy platforms still need the band-aid code.
It gets messy.
Here's where the new gaffe comes in. The delay to readjust the selection in a Leofart table view is set arbitrarily at one second; but the accepted interval for a double click is a fraction of a second.
A double click by definition is the sequence 'mouse down', 'mouse up', and 'mouse down' and all within a defined interval and within a defined on screen rectangle such as 4 x 4 pixels. [The final 'mouse up' is ignored.]
This means if you don't jitter your mouse too much and you click fast enough two successive mouse down events will be regarded as a double click.
Most often on most platforms there's one way or another to define both the accepted interval and the accepted on screen rectangle.
And by now you see the catch. When you 'select all' or select more than one record in a table view and then decide to double click a row / record your double click has to be completed before the table view is programmed to react to the first mouse down message.
This presents an issue to both the programmer and the user. For the user it means you won't be able to see what it was you double clicked on. Already all those rows look identical even if one in theory is -the- selected row (the row in focus) and the others are just ordinary 'selected rows'. But you won't even get what you got before - they're still all selected!
And naturally if you're a programmer and have been using -(int)[NSTableView selectedRow] instead of -(int)[NSTableView clickedRow] you'll have to change your code; but odds are you won't want to stop there either as your leaving things in that state will make matters too confusing for your users.
The 'band-aid' you have to apply is to always check first there's only one row selected before you act on the 'double click' message.
And this in turn is going to further aggravate the end user. As said user must now separately and demonstrably #1) click on the desired row; #2) wait one second for the selection to change; and #3) double click on the same row again.
Again: this isn't a rare occurrence - most major titles use the table view in one way or another. And the Cocoa outline view inherits from the table view and on Leofart exhibits even wackier behaviour. It's at least tens of thousands of applications that at this point are going to have to be recoded, new senseless band-aids applied. And all for this arbitrary and indefensible one second delay that in the best of all possible worlds collides head on with the system's double click timer anyway.
It's called 'proper management of human resources'; it's called 'organisation'; it's called 'testing designs properly before issuing any go-ahead'.
And it's called 'progress'.
Some say that's progress
I say that's cruel
- Peter Garrett