require "Machine_Action.rb" OSX.require_framework 'AddressBook' class Action < Machine_Action_rb attr_accessor :doneCalc, :noteReader #@@dueColor=NSColor.redColor.blendedColorWithFraction(0.5, ofColor:NSColor.blackColor) @@dueColor=NSColor.redColor.blendedColorWithFraction_ofColor(0.5,NSColor.blackColor) @@beforeStartColor=NSColor.lightGrayColor @@nextColor=NSColor.purpleColor.blendedColorWithFraction_ofColor(0.5,NSColor.blackColor) @@doneColor=NSColor.greenColor.blendedColorWithFraction_ofColor(0.5,NSColor.blackColor) @@todayColor=NSColor.alternateSelectedControlColor @@uiColor=NSColor.orangeColor.blendedColorWithFraction_ofColor(0.5,NSColor.blackColor) @@iColor=NSColor.blueColor.blendedColorWithFraction_ofColor(0.5,NSColor.blackColor) @@uColor=NSColor.yellowColor.blendedColorWithFraction_ofColor(0.5,NSColor.blackColor) @@txtIcon=NSImage.imageNamed("txt") @@notxtIcon=NSImage.imageNamed("notxt") @@syncing=false def Action.startSync @@syncing=true end def Action.endSync @@syncing=false end def syncing? return @@syncing end Action.setKeys_triggerChangeNotificationsForDependentKey(["dueDate","doDate","done","startDate","parent","sequenceValue","isImportant","isUrgent"],"textColor") Action.setKeys_triggerChangeNotificationsForDependentKey(["dueDate"],"dueDateDate") Action.setKeys_triggerChangeNotificationsForDependentKey(["dueDate"],"dueDateTime") Action.setKeys_triggerChangeNotificationsForDependentKey(["dueDate"],"dueDateDateOrNil") Action.setKeys_triggerChangeNotificationsForDependentKey(["dueDate"],"dueDateTimeOrNil") Action.setKeys_triggerChangeNotificationsForDependentKey(["doDate"],"doDateDate") Action.setKeys_triggerChangeNotificationsForDependentKey(["doDate"],"doDateTime") Action.setKeys_triggerChangeNotificationsForDependentKey(["doDate"],"doDateDateOrNil") Action.setKeys_triggerChangeNotificationsForDependentKey(["doDate"],"doDateTimeOrNil") Action.setKeys_triggerChangeNotificationsForDependentKey(["startDate"],"startDateDate") Action.setKeys_triggerChangeNotificationsForDependentKey(["startDate"],"startDateTime") Action.setKeys_triggerChangeNotificationsForDependentKey(["startDate"],"startDateDateOrNil") Action.setKeys_triggerChangeNotificationsForDependentKey(["startDate"],"startDateTimeOrNil") Action.setKeys_triggerChangeNotificationsForDependentKey(["parent","sequenceValue"],"sequencePath") ["do","due","start"].each do |d| ["#{d}Hour","#{d}Minute","#{d}DateDate"].each do |k| Action.setKeys_triggerChangeNotificationsForDependentKey(["doDate"],k) end end def self.==(obj) self.isEqual(obj) end def reset_caches resetProjectCalc reset_kids reset_actionable reset_actionableKids reset_childDate reset_dateQuestions reset_doneCalc reset_actionable reset_textColor resetTemplateCache @parentQ=nil end def parentChangeKey(key) reset_caches kids.each{|c| c.parentChangeKey(key)} if children? end def childChangeKey(key) reset_caches parent.childChangeKey(key) if parent? && !syncing? end def siblingChangeKey(key) case key when "done" if isSequential? reset_actionable parent.reset_actionableKids if parent? end reset_textColor end end def didChangeValueForKey(key) if (!syncing?) then reset_caches if parent? parent.childChangeKey(key) parent.kids.each{|c| c.siblingChangeKey(key)} if parent.children? end kids.each{|c| c.parentChangeKey(key)} if children? super_didChangeValueForKey(key) end end def openJustNotes @noteReader ||= NoteReader.alloc.initWithAction(self) @noteReader.show setNoteOpen(true) end def openNoteReader if inMailMessageID? then link = "message://%3c#{inMailMessageID}%3e" print "opening mail link: #{link}\n" link = NSURL.URLWithString(link) NSWorkspace.sharedWorkspace.openURL?(link) if link end @noteReader ||= NoteReader.alloc.initWithAction(self) @noteReader.show setNoteOpen(true) end def closeNoteReader setNoteOpen(false) @noteReader = nil end # find accesor for key-value coding # "key" must be a ruby string # def kvc_getter_method(key) # [key, key + '?'].each do |m| # return m if respond_to? m # end # return nil # accessor not found # end # # def kvc_setter_method(key) # [kvc_internal_setter(key), key + '='].each do |m| # return m if respond_to? m # end # return nil # end # # def kvc_accessor_notfound(key) # fmt = '%s: this class is not key value coding-compliant for the key "%s"' # raise sprintf(fmt, self.class, key.to_s) # end # # def rbSetValue_forKey(value, key) # if m = kvc_setter_method(key.to_s) # send(m, value) # else # kvc_accessor_notfound(key) # end # end # def rbValue_forKey(value, key) # print "rbValueForKey\n" # if m = kvc_getter_method(key.to_s) # send(m, value) # else # kvc_accessor_notfound(key) # end # end # # def valueForKey(key) # print "vfk ",key,"\n" # if m = kvc_getter_method(key.to_s) # return send(m) # else # #super_valueForKey(key) # reurn objc_send(key.to_s) # end # end # # def setValue_forKey(value,key) # if m = kvc_setter_method(key.to_s) # send(m,value) # else # super # end # end # # # def valueForUndefinedKey(key) # if m = kvc_getter_method(key.to_s) # return send(m) # else # super # end # end # # def setValue_forUndefinedKey(value,key) # if m_kvc_setter_method(key.to_s) # send(m,value) # else # super # end # end # def awakeFromInsert #super setCreateDate(NSCalendarDate.calendarDate) end # def context # result=super_context # return parent.context if result==nil && parent? # return result # end def appleScriptName "actions" end def parent? #cache to avoid crossing bridge return @parentQ if @parentQ != nil @parentQ= (self.parent != nil) @parentQ end def children? return @childrenQ if @childrenQ != nil kids= self.children @childrenQ=(kids != nil && kids.count > 0) end def sequencePath if parent? then result="%s.%03d" % [parent.sequencePath,sequenceValue] else result="%03d" % sequenceValue end end def namePath(sep) if parent? then result = "%s%s%s" % [parent.namePath(sep),sep,name] else result = name end result end def sequenceValue result=super_sequenceValue result = 999 if (result==nil || result.to_i==0) result end def reset_kids @kids=nil @actionableKids=nil end def kids return @kids if @kids return nil if !children? @kids=children.allObjects.sort_by {|x| x.sequenceValue.to_i} @kids end def checkSequential? return true if !parent? pkids= parent.kids pkids.each do |a| return false if a != self && !a.done? # sequential items can only start after previous items complete return true if a==self # if we're the first undone item, we can go! end end def reset_actionableKids @actionableKids=nil end def actionableKids return @actionableKids if @actionableKids return nil if !children? @actionableKids= kids.select {|x| x.isActionable?} @actionableKids end def isNext? return false if isArea? || !isActionable? return false if !parent? return parent.actionableKids[0]==self if parent.actionableKids return false end def bumpChildrenFromIndex_throughIndex(fromIndex,toIndex) #print "bumping #{fromIndex} to #{toIndex}\n" bump=toIndex-fromIndex+1 list= kids list.each{|a| a.sequenceValue= a.sequenceValue.to_i+bump if a.sequenceValue.to_i >=fromIndex } if list end def resequence #print "resequencing\n" list= kids list.each_with_index {|a,index| a.sequenceValue=index+1} if list end def resequenceAll self.resequence children.each { |x| resequenceAll} if (children?) end def isSomedayUp? return isSomeday? || (parent? && parent.isSomedayUp?) end def isTemplateUp return isTemplateUp? end def isTemplateUp? return @isTemplateUpCache if @isTemplateUpCache !=nil @isTemplateUpCache=isTemplate? || (parent? && parent.isTemplateUp?) return @isTemplateUpCache end def resetTemplateCache @isTemplateUpCache=nil end def templateParent return parent.templateParent if (parent? && parent.isTemplate?) return self end def isTemplateRoot return isTemplateRoot? end def isTemplateRoot? return isTemplate? && !(parent.isTemplateUp?) end def isSomedayUp=(value) if (!value || value.to_i==0) then if (parent? && parent.isSomedayUp?) parent.isSomedayUp=value #recurse up to disable if parent is set else setIsSomeday(value) end else setIsSomeday(value) end end def setIsSomedayUp=(value) isSomedayUp=(value) end def isTemplateUp=(value) if (!value || value.to_i==0) then if (parent? && parent.isTemplateUp) parent.isTemplateUp=value #recurse up to disable if parent is set else setIsTemplate(value) end else setIsTemplate(value) end end def setIsTemplateUp=(value) isTemplateUp=(value) end def isArea? isArea.boolValue end def isProject? (!isArea?) && children? end def isProject isProject? end def isTask? ! (isArea? || children?) end def reset_actionable @actionable=nil end def isActionable? return @actionable if @actionable !=nil @actionable=actionableCalc end def actionableCalc ! (done? || isArea? || children? || isSomedayUp? || isTemplateUp? || beforeStart? || (isSequential? && !checkSequential? )) end def isTask isTask? end def rootAction return parent.rootAction if parent? self end def resetProjectCalc @projectCalc=nil @parentQ=nil @childrenQ=nil end def setIsArea(value) super_setIsArea(value) end def project return @projectCalc if @projectCalc if parent? && !(parent.isArea?) @projectCalc=parent.project else @projectCalc=self end end def project=(value) setParent(value) end def setProject(value) setParent(value) end def setParentAtIndex(value,index) return if value.hasAncestor?(self) resetProjectCalc value.bumpChildrenFromIndex_throughIndex(index,index+1) if value value.reset_kids if value parentChange(parent,value) super_setParent(value) setSequenceValue(index) end def setParent(value) if !syncing? return if value && value.hasAncestor?(self) else print "setting parent in sync\n" print "oldparent #{parent}\n" print "newparent #{value}\n" end oldparent = parent reset_caches sequenceValue= 999 # throw to the bottom of the list parentChange(parent,value) super_setParent(value) parent.resequence if parent? oldparent.resequence if oldparent != nil end def area return if parent? && !isArea? self end def depth depth=1 p=parent while(p) do depth++ p=parent end depth end def done? done.to_i==1 end def finishOrDoDate result=nil if done? then result=finishDate elsif doDate then result=doDate elsif startDate then result=startDate else result=dueDate end result end def isToday? today=NSDate.date.dayNumber return ( (doDate && doDate.dayNumber==today) || (startDate && startDate.dayNumber==today) || (finishDate && finishDate.dayNumber==today)|| (!done? && ((doDate && doDate.dayNumber<=today) || (dueDate && dueDate.dayNumber<=today))) ) end def isDue? return @isDue if @isDue != nil @isDue= (!done? && dueDate && dueDate.dayNumber <= NSDate.date.dayNumber) @isDue end def reset_dateQuestions @beforeStart=nil @isDue=nil end def beforeStart? return @beforeStart if @beforeStart != nil @beforeStart = (startDate && !done? && startDate.dayNumber > NSDate.date.dayNumber) @beforeStart end def hasAncestor?(ancestor) if ancestor==self then return true else return parent !=nil && parent.hasAncestor?(ancestor) end end def hasChild?(child) child.hasAncestor?(self) end def primitiveDone willAccessValueForKey "done" result = primitiveValueForKey "done" didAccessValueForKey "done" result end def reset_nextCalc reset_doneCalc reset_dateQuestions if actionableKids && actionableKids.size > 0 nextAction=actionableKids[0] nextAction.willChangeValueForKey "textColor" nextAction.didChangeValueForKey "textColor" end end def reset_doneCalc @doneCalc=nil reset_actionableKids parent.reset_doneCalc if parent? && parent != nil # recurion might not have reset everything end def doneCalc return @doneCalc if @doneCalc!= nil mx=self.valueForKeyPath("children.@min.done") mn=self.valueForKeyPath("children.@max.done") @doneCalc=mx @doneCalc= -1 if (mn!=mx) @doneCalc end def done result=super_done result=doneCalc if children? #recurring items "reset" when asked if they're done if result.to_i > 0 && isRecurring? && recurReset? && doDate != nil && doDate.dayNumber.to_i <= NSDate.date.dayNumber.to_i setDone(0) setFinishDate(nil) result=0 end result end def doInstantiateTemplate newAction=cloneOfSelf newAction.setCreateDate(NSCalendarDate.calendarDate) newAction.setIsTemplate(false) newAction.setDone(0) if children? kids.each do |a| newA=a.doInstantiateTemplate newA.setParent(newAction) end end newAction end def instantiateTemplate newA = doInstantiateTemplate AppDelegate.newActionFocusWindow(newA) end def editTemplate AppDelegate.newActionFocusWindow(self) end def markedDoneTransition setFinishDate(NSCalendarDate.calendarDate) NSNotificationCenter.defaultCenter.postNotificationName_object("markedDoneTransition",self); end def markedUndoneTransition setFinishDate(nil) NSNotificationCenter.defaultCenter.postNotificationName_object("markedUndoneTransition",self); end def setDone(value) value=1 if (-1 == value.to_i) # mixed state checkboxes do 0->-1->1, we only want 0->1 oldvalue=primitiveDone wasNext= (oldvalue.to_i==0 && value.to_i > 0 && isNext?) super_setDone(value) if (oldvalue.to_i != value.to_i && !syncing?) then if (1 == value.to_i) markedDoneTransition if isRecurring? offset=1 deadline=0 offset=recurDays.to_i if recurDays? deadline=recurDeadline.to_i if recurDeadline? if !recurReset clone=cloneOfSelf clone.setDone(0) clone.setFinishDate(0) clone.setStartDate(NSDate.date.dateByAddingDays(offset)) clone.setDoDate(NSDate.date.dateByAddingDays(offset)) clone.setDueDate(NSDate.date.dateByAddingDays(offset+deadline)) if dueDate? setIsRecurring(0) else setStartDate(NSDate.date.dateByAddingDays(offset)) setDoDate(NSDate.date.dateByAddingDays(offset)) setDueDate(NSDate.date.dateByAddingDays(offset+deadline)) if dueDate? end end else markedUndoneTransition end if parent? if (wasNext) parent.reset_nextCalc else parent.reset_doneCalc end parent.willChangeValueForKey "done" parent.didChangeValueForKey "done" end end end def parentChange(oldParent,newParent) if oldParent oldParent.reset_childDate oldParent.reset_caches end if newParent newParent.reset_childDate newParent.reset_caches end @isTemplateUpCache=nil end def dueDate date=super_dueDate if children? then @childDueDate=self.valueForKeyPath("children.@max.dueDate") date=@childDueDate if @childDueDate && (!date || !(@childDueDate.compare(date) < 0)) end date end def reset_childDate @childStartDate=nil @childDueDate=nil reset_dateQuestions end def startDate date=super_startDate if children? @childStartDate=self.valueForKeyPath("children.@min.startDate") if not @childStartDate date=@childStartDate if @childStartDate && (!date || !(@childStartDate.compare(date) < 0)) end date end def priority p = 4 p -= 1 if isUrgent? p -= 2 if isImportant? p end def deepEach yield(self) #yield once for me self.children.allObjects.to_a.each{|c| c.deepEach { |x| yield(x)} } if children? end def eachTask yield(self) if isTask? if children? self.children.allObjects.to_a.each do |c| c.eachTask{ |x| yield(x) } end end end def hasChildren children? end def setSmartName(value) smartName= value end def smartName=(value) value=parseSmartString(value) super_setName(value) end def smartName(value) name end def setName(value) value=parseSmartString(value) super_setName(value) end def findObjectByName(entity,value) moc=self.managedObjectContext ed=NSEntityDescription.entityForName_inManagedObjectContext(entity,moc) request=NSFetchRequest.alloc.init request.setEntity(ed) pred=NSPredicate.predicateWithFormat_argumentArray("name BEGINSWITH[c] %@",[value]) request.setPredicate(pred) sort=NSSortDescriptor.alloc.initWithKey_ascending("name",true) request.setSortDescriptors([sort]) error=0 result=moc.executeFetchRequest_error(request,nil) return result[0] if result && result.count > 0 return nil end def findContext(value) value.strip! result=findObjectByName("Context",value) #print "Found Context #{result.name} for #{value}\n" if result #print "Couldn't find '#{value}'\n" unless result result end def findProject(value) value.strip! result=findObjectByName("Action",value) #print "Found Project #{result.name} for #{value}\n" if result #print "Couldn't find '#{value}'\n" unless result result end def parseDate(value) df=NSDateFormatter.alloc.initWithDateFormat_allowNaturalLanguage("%a %b %e %I%:%M%p",true) result=df.dateFromString(value) print "Turned #{value} into #{result}\n" print "Couldn't parse #{value}\n" unless result result end def parseSmartString(value) value=value.to_s #make sure its a ruby string markdone=0 value.sub!(/^[ \t]*did[ \t]+/) {|s| markdone=1; ''} value.sub!(/^[ \t]*Did[ \t]+/) {|s| markdone=1; ''} # process action name to produce new value # @ context will search for the matching context, or :context, or :c # > Project will search for the matching project, or :project, or :p # :due will try to set the due date, i.e. :due tues # :start will try to set the start date, i.e. :start mon # :on will try to set the do on date, i.e. :on mon or :do # :i will set "is important" # :u will set "is urgent" # :ui, :will set both # :someday # :template # :recur # :reset # :area contextr= %r{((@[ \t]*)|(\:context|:c))[ \t]*([^:@>\n\r]+)}i projectr= %r{((>[ \t]*)|(\:project|:p))[ \t]*([^:@>\n\r]+)}i duer=%r{(:due)[ \t]*(((\d{1,2}:\d\d)|[^:@>\n\r])+)}i startr=%r{(\:start)[ \t]*(((\d{1,2}:\d\d)|[^:@>\n\r])+)}i doner=%r{(\:done)[ \t]*}i onr=%r{(\:on)[ \t]*(((\d{1,2}:\d\d)|[^:@>\n\r])+)}i priorityr=%r{(\:iu|:ui|:i|:u)[ \t]*}i somedayr=%r{(\:someday)[ \t]*}i templater=%r{(\:templ*a*t*e*)[ \t]*}i recurr=%r{(\:recur)[ \t]*}i resetr=%r{(\:reset)[ \t]*}i arear=%r{(\:area)[ \t]*}i noter=%r{(:note|\n|\r)[ \t]*(.*)}i regex=Regexp.union(contextr,projectr,duer,startr,onr,priorityr,somedayr,templater,recurr,resetr,arear,doner,noter) value.gsub!(regex) do #print "match: ",$&,"\n" #print "list: 1#{$1} 2#{$2} 3#{$3} 4#{$4}" match=$~.to_a match.shift match=match.select{|x| x} managedObjectContext.processPendingChanges() # best to process changes as we manipulate relationships case match[0] when /@|:c/i ##print "Context: #{match[1]} #{match[2]}\n" setContext(findContext(match[2])) when />|:p/i ##print "Project: #{match[1]} #{match[2]}\n" setParent(findProject(match[2])) when /:due/i ##print "Due: #{match[1]}\n" ddate= parseDate(match[1]) setDueDate(ddate) when /:start/i ##print "Start: #{match[1]}\n" sdate= parseDate(match[1]) print "got a start date #{sdate}\n" setStartDate(sdate) print "now date #{startDate}\n" when /:done/i markdone=1 when /:on|:do/ ##print "Do: #{match[1]}\n" ddate= parseDate(match[1]) setDoDate(ddate) when /:iu|:ui/i setIsImportant(1) setIsUrgent(1) when /:i/i setIsImportant(1) when /:u/i setIsUrgent(1) when /:someday/i setIsSomeday(1) when /:temp/i setIsTemplate(1) when /:recur/i setIsRecurring(1) when /:reset/i setRecurReset(1) when /:area/i setIsArea(1) when /:note|\n|\r/i setNoteString(match[1]) end #print "Match #{match}\n\n" '' end managedObjectContext.processPendingChanges() # best to process changes as we manipulate relationships super_setName(value) setDone(1) if (markdone==1) value end def isUrgent result = super_isUrgent result = 0 unless result != nil result end def isImportant result=super_isImportant result=0 unless result != nil result end def smartNameTest string = " did stuff @work @ play > Project >project4 :project Project2 :p project3 :c work :due Feb 3 4:00pm :done :i :u :ui :someday :template :recur :reset :area" string.sub!(/^[ \t]*did[ \t]*/) {|s| print "found did\n"; ''} # @ context will search for the matching context, or :context, or :c # > Project will search for the matching project, or :project, or :p # :due will try to set the due date, i.e. :due tues # :start will try to set the start date, i.e. :start mon # :on will try to set the do on date, i.e. :on mon # :i will set "is important" # :u will set "is urgent" # :ui, :will set both # :someday # :temp[late] # :recur # :reset # :area contextr= %r{((@[ \t]*)|(\:context|:c))[ \t]*([^:@>]+)}i projectr= %r{((>[ \t]*)|(\:project|:p))[ \t]*([^:@>]+)}i duer=%r{(:due)[ \t]*(((\d{1,2}:\d\d)|[^:@>])+)}i startr=%r{(\:start)[ \t]*(((\d{1,2}:\d\d)|[^:@>])+)}i doner=%r{(\:done)[ \t]*}i onr=%r{(\:on|:do)[ \t]*(((\d{1,2}:\d\d)|[^:@>])+)}i priorityr=%r{(\:iu|:ui|:i|:u)[ \t]*}i somedayr=%r{(\:someday)[ \t]*}i templater=%r{(\:templ*a*t*e*)[ \t]*}i recurr=%r{(\:recur)[ \t]*}i resetr=%r{(\:reset)[ \t]*}i arear=%r{(\:area)[ \t]*}i regex=Regexp.union(contextr,projectr,duer,startr,onr,priorityr,somedayr,templater,recurr,resetr,arear,doner) string.gsub!(regex) do #print "match: ",$&,"\n" #print "list: 1#{$1} 2#{$2} 3#{$3} 4#{$4}" match=$~.to_a match.shift match=match.select{|x| x} case match[0] when /@|:c/ print "Context: #{match[1]} #{match[2]}\n" when /\>/ print "Project: #{match[1]} #{match[2]}\n" when /:p/i print "Project: #{match[1]} #{match[2]}\n" when /:due/ print "Due: #{match[1]}\n" when /:start/ print "Start: #{match[1]}\n" when /:on|do/ print "Do On: #{match[1]}\n" when /:done/ print "Done\n" when /:iu|:ui/ print "UI\n" when /:i/ print "important\n" when /:u/ print "Urgent\n" when /:someday/ print "someday\n" when /:temp/ print "template\n" when /:recur/ print "recur\n" when /:reset/ print "reset\n" when /:area/ print "area\n" else print "No Match? " match.each_with_index {|i,m| print "#{i}:#{m} "} print "\n" end print "Match #{match}\n\n" '' end print string end def addChildrenObject(value) super_addChildrenObject(value) reset_kids end def removeChildrenObject(value) super_removeChildrenObject(value) reset_kids end def reset_textColor @textColor=nil end def textColorCalc return @@dueColor if isDue? return @@beforeStartColor if beforeStart? return @@nextColor if isNext? return @@doneColor if done? return @@uiColor if isUrgent? && isImportant? return @@iColor if isImportant? return @@uColor if isUrgent? return @@todayColor if isToday? return @@beforeStartColor if isTemplateUp? return NSColor.blackColor end def textColor return @textColor if @textColor @textColor=textColorCalc @textColor end objc_method :textColor,%w{id} def actionState return "stateDue" if isDue? return "stateBeforeStart" if beforeStart? return "stateNext" if isNext? return "stateDone" if done? return "stateUI" if isUrgent? && isImportant? return "stateI" if isImportant? return "stateU" if isUrgent? return "stateToday" if isToday? return "stateTemplate" if isTemplateUp? return "stateNone" end def itemState return "itemDone" if done? return "itemToDo" end def selfPlusChildren(array) array << self kids.each {|a| a.selfPlusChildren(array)} if children? array end def Action.loadDefaults defaults=NSUserDefaultsController.sharedUserDefaultsController.values @@dueColor= NSUnarchiver.unarchiveObjectWithData(defaults.valueForKey("dueColor")) if defaults.valueForKey("dueColor") @@beforeStartColor= NSUnarchiver.unarchiveObjectWithData(defaults.valueForKey("beforeStartColor")) if defaults.valueForKey("beforeStartColor") @@nextColor= NSUnarchiver.unarchiveObjectWithData(defaults.valueForKey("nextColor")) if defaults.valueForKey("nextColor") @@doneColor= NSUnarchiver.unarchiveObjectWithData(defaults.valueForKey("doneColor")) if defaults.valueForKey("doneColor") @@uiColor= NSUnarchiver.unarchiveObjectWithData(defaults.valueForKey("UIColor")) if defaults.valueForKey("UIColor") @@iColor=NSUnarchiver.unarchiveObjectWithData(defaults.valueForKey("IColor")) if defaults.valueForKey("IColor") @@uColor= NSUnarchiver.unarchiveObjectWithData(defaults.valueForKey("UColor")) if defaults.valueForKey("UColor") @@todayColor= NSUnarchiver.unarchiveObjectWithData(defaults.valueForKey("todayColor")) if defaults.valueForKey("todayColor") end def appLaunch setIsUrgent(0) if self.isUrgent==nil setIsImportant(0) if self.isImportant==nil end def doDelegateTo(abperson,bestEmail,extraText) now = NSCalendarDate.date #print "best email #{bestEmail}\n" defaults=NSUserDefaults.standardUserDefaults delay = defaults.integerForKey("delegateFollowUpDelay") email = defaults.boolForKey("delegateShouldGenerateEmail") delay = 7 if not delay future = now.dateByAddingDays(delay) self.delegatedToID=abperson.uniqueId if (self.dueDate?) then if (self.dueDate.dayNumber > future) self.startDate=future else self.startDate=self.dueDate end else self.startDate = future end n = self.name n = n.sub("Fup: ","") n = "Fup: " << n name=n kids.each {|a| a.doDelegateTo(abperson) } if kids #print "Properties #{ABPerson.properties}\n" #print "Person: #{abperson}\n" #print "Person email: #{abperson.valueForProperty('Email')}\n" if (!bestEmail) then emailAddresses=abperson.valueForProperty("Email") bestEmail = emailAddresses.valueAtIndex(emailAddresses.indexForIdentifier(emailAddresses.primaryIdentifier)) end if email && !done? MailSyncer.singleton.sendDelegateMail(bestEmail,self,extraText,delay) self.delegatedToEmail=bestEmail end end def setDelegatedToID(value) @delegatedTo=nil super_setDelegatedToID(value) end def setDelegatedFromID(value) @delegatedFrom=nil super_setDelegatedFromID(value) end def delegatedTo return nil unless delegatedToID? @delgatedTo=ABAddressBook.sharedAddressBook.recordForUniqueId(delegatedToID) unless @delegatedTo @delegateTo end def delegatedFrom return nil unless delegatedFromID? @delgatedFrom=ABAddressBook.sharedAddressBook.recordForUniqueId(delgatedFromID) unless @delgatedFrom @delegatedFrom end def rootProject project end def rootArea p = project.parent return p if p && p.isArea? return nil end #def objectEnumerator # return nil #end end