« Likely in store. Likely? WTF? | Main | Always - on Print Preview »

Poking around in others' software is sometimes useful (and thanks to Zorn)

I need an NSNumberFormatter subclass for a PyObjC project I'm working on that reformats an NSNumber to hours:minutes:seconds. Thinking I've seen this before (and kind of hoping that there was some voodoo I was missing somewhere to make this simple), I decided to poke around in applications that deal with time. After a little head-scratching, I was reminded of that most useful time-tracking and invoicing application I've grown to love called Billable (Zorn!). On this screenshot (from the Clickable Bliss site) we see a field labeled "Time Spent:" with a "Start" button next to it. Thinking to myself, "I want that formatter!" I fired up F-Script Anywhere, injected it into Billable and dug down until I was the class name for the formatter. CBTimeLengthFormatter.jpg Time to pray to google. Ah! Zorn! You beautiful helpful coding-type person. You've pasted it for us. Thank you! Now all that is left is to pythonify it. (I made a few modifications to the behavior, but it's the same general idea)
#
#  CBTimeLengthFormatter.py
#  PuppyTracker
#
#  Created by Jonathan Saggau on 12/3/07.
#  Copyright (c) 2007 __MyCompanyName__. All rights reserved.


from Foundation import *
from math import floor

#modified from http://paste.lisp.org/display/21854
class CBTimeLengthFormatter(NSNumberFormatter):

    def stringForObjectValue_(self, anObject):
        if (not (anObject.isKindOfClass_(NSNumber))):
            return(None)
            
        if (anObject.intValue() <= 0):
            return("00:00:00")
        intval = int(floor(anObject))
        
        hours = intval / (60*60)
        minutes = (intval - (hours * 60 * 60)) / 60
        seconds = intval - (minutes * 60) - (hours * 60 * 60)
        string = "%02i:%02i:%02i" %((hours), (minutes), (seconds))
        return(string)
    
    def getObjectValue_forString_errorDescription_(self, objVal, inString, err):
        """Take a string like "00:00:00" and turns it into a NSNumber and returns YES
           Also able to handle 10:10 (as 10 minutes, 10 seconds) and 10 (as 10 seconds)"""
        
        string = NSString.stringWithString_(inString)
        
        #catch for nil or empty string
        if (string == None or string.isEqualToString_("")):
            return True, 0, None
        
        stringList = string.split(":")
        #make seconds first, instead of hours
        stringList.reverse()
        
        #turn each into an integer, filtering out empty strings
        try:
            stringList = [int(each) for each in stringList if each is not u'']
            
        #if we can't make any part of this into an int, bail
        except ValueError, e:
            return False, 0, None
        
        #make sure we have Seconds, Hours, Minutes by padding the list with zeros
        #in case we have (say) Seconds, Hours only
        while ( len(stringList) < 3):
            stringList.append(0)
        
                        #sec            #min               #hour
        timeInSeconds = stringList[0] + stringList[1]*60 + stringList[2]*60*60
        return True, timeInSeconds, None