require 'todo_a'
require 'outline_html'
require 'benchmark'
class ActionBrowser < NSObject
attr_accessor :browserWindow, :filterView, :filterController, :outlineView, :outlineController, :taskView, :taskController, :contextController
attr_accessor :pickerPicker, :pickerView, :pickerLabel, :emailText
attr_accessor :quickSplitView, :deferView, :quickSplitText, :deferDate, :splitLabel
attr_accessor :filterSets,:tasks,:rootActions,:atdFilter, :atdControl, :splitViewV,:splitViewH, :filterGroup, :contextPopup, :projectPopup, :projectController
attr_accessor :focus
attr_accessor :allCountView,:ableCountView,:todoCountView,:doneCountView
kvc_accessor :todoCount,:actionableCount,:doneCount,:allCount
@@columnNames={ "name"=>"Name",
"done"=>"Done",
"note"=>"Note",
"context"=>"Context",
"project"=>"Project",
"important"=>"Important",
"urgent"=>"Urgent",
"createDate"=>"Creation Date",
"startDateDate"=>"Start Date",
"doDateDate"=>"Do On Date",
"dueDateDate"=>"Due Date",
"startDateDateOrNil"=>"Start Date",
"doDateDateOrNil"=>"Do On Date",
"dueDateDateOrNil"=>"Due Date",
"startDateTime"=>"Start Time",
"doDateTime"=>"Do On Time",
"dueDateTime"=>"Due Time",
"startDateTimeOrNil"=>"Start Time",
"doDateTimeOrNil"=>"Do On Time",
"dueDateTimeOrNil"=>"Due Time",
"finishDate"=>"Finish Date",
"recur"=>"Recurring?",
"recurReset"=>"Reset recur?",
"recurDays"=>"Recur Days",
"recurDeadline"=>"Recur Deadline",
"someday"=>"Someday?",
"template"=>"Template?",
"area"=>"Area?",
}
@@columnPaths={ "name"=>"name",
"done"=>"done",
"note"=>"noteString",
"context"=>"context.name",
"project"=>"parent.name",
"important"=>"isImportant",
"urgent"=>"isUrgent",
"createDate"=>"createDate",
"startDate"=>"startDate",
"doDate"=>"doDate",
"dueDate"=>"dueDate",
"finishDate"=>"finishDate",
"recur"=>"isRecurring",
"recurReset"=>"recurReset",
"rreset"=>"recurReset",
"rReset"=>"recurReset",
"recurDays"=>"recurDays",
"recurDelay"=>"recurDays",
"recurDeadline"=>"recurDeadline",
"rdeadline"=>"recurDeadline",
"someday"=>"isSomeday",
"template"=>"isTemplate",
"area"=>"isArea",
}
#kvc_accessor :taskSortDescriptors,:outlineSortDescriptors
@@dragTypes=["OutlineDrag"]
def windowNib
@windowNib ||= NSNib.alloc.initWithNibNamed_bundle('MainWindowL',nil)
end
def pickerNib
@pickerNib ||= NSNib.alloc.initWithNibNamed_bundle('ABPicker',nil)
end
def setup(appDelegate,nfocus=nil)
@appDelegate=appDelegate
@atdFilter=0
@focus=nfocus
@allCount=0
reset_newlyCreated
windowNib.instantiateNibWithOwner_topLevelObjects(self,nil)
browserWindow.setDelegate(self)
#@outlineController.setRootObjectsArray(rootActions)
@outlineController.setRootKeyPath("rootActions")
@outlineController.setFilterPredicate(NSPredicate.predicateWithValue(true))
@outlineView.setIsExpandedKeyPath("isExpanded")
@outlineView.setIsExpandedFilteredKeyPath("isExpanded")
@outlineView.setOutlineTableColumn(@outlineView.tableColumnWithIdentifier("name"))
@outlineView.restoreCollapsedItems
@outlineController.setSortDescriptors(outlineSortDescriptors)
@outlineView.registerForDraggedTypes(@@dragTypes)
@taskView.setDataSource(self)
@taskView.registerForDraggedTypes(@@dragTypes)
@taskView.setDraggingSourceOperationMask_forLocal(NSDragOperationEvery,true)
@taskView.setDraggingSourceOperationMask_forLocal(NSDragOperationCopy,false)
#@outlineView.setShouldEditNextItemWhenEditingEnds(false)
#@outlineView.setTypeAheadSelectionEnabled(true)
#@outlineView.setCreatesNewItemWithReturnKey(true)
if @focus
@browserWindow.setTitle("#{focus[0].name} Focus") if focus.size==1
@browserWindow.setTitle("#{focus[0].name} and Friends Focus") if focus.size > 1
else
@browserWindow.setTitle("Action Browser")
end
setupContextPopup
registerObservers
@browserWindow.makeKeyAndOrderFront(nil)
end
def setupProjectPopup
menu=NSMenu.alloc.init
menuItem=NSMenuItem.alloc.init
menuItem.setTitle("---")
menu.addItem(menuItem)
contexts=@projectController.arrangedObjects.sort_by {|c| c.name.to_s }
contexts.each do |c|
menuItem=NSMenuItem.alloc.init
menuItem.setTitle(c.name)
menuItem.setRepresentedObject(c)
menu.addItem(menuItem)
end
@projectPopup.setMenu(menu)
end
def setupContextPopup
menu=NSMenu.alloc.init
menuItem=NSMenuItem.alloc.init
menuItem.setTitle("-INBOX-")
menu.addItem(menuItem)
contexts=@contextController.arrangedObjects.sort_by {|c| c.name.to_s }
contexts.each do |c|
menuItem=NSMenuItem.alloc.init
menuItem.setTitle(c.name) if c.name
menuItem.setRepresentedObject(c)
menu.addItem(menuItem)
end
@contextPopup.setMenu(menu)
end
def registerObservers
#@filterController.addObserver_forKeyPath_options_context(self,"selection",NSKeyValueObservingOptionNew,nil)
@contextController.addObserver_forKeyPath_options_context(self,"arrangedObjects",NSKeyValueObservingOptionNew,nil)
@projectController.addObserver_forKeyPath_options_context(self,"arrangedObjects",NSKeyValueObservingOptionNew,nil)
end
def atdAllClick(sender)
@atdControl.selectSegmentWithTag(0)
atdClick(@atdControl)
end
def atdAbleClick(sender)
@atdControl.selectSegmentWithTag(1)
atdClick(@atdControl)
end
def atdTodoClick(sender)
@atdControl.selectSegmentWithTag(2)
atdClick(@atdControl)
end
def atdDoneClick(sender)
@atdControl.selectSegmentWithTag(3)
atdClick(@atdControl)
end
def atdClick(sender)
clicked=@atdControl.selectedSegment
(0..3).each{|s| @atdControl.setSelected_forSegment(false,s) if s != clicked }
filterSets
@filterSets['Completion'].filters.each do |f|
f.selected=0
end
filterChange #will build and set based on selected segments
end
def resetAtdFilter
willChangeValueForKey "atdFilter"
@atdFilter=0
didChangeValueForKey "atdFilter"
end
def toggleOutlineCollapse(sender)
return if RBSplitSubview.animating.to_i==1
if (@splitViewH.subviewWithIdentifier("flat").isCollapsed?) && !(@splitViewH.subviewWithIdentifier("outline").isCollapsed?)
## task view is already collapsed, so this won't do anything. Have it switch instead.
@splitViewH.subviewWithIdentifier("flat").toggleCollapseQuick(sender)
@splitViewH.subviewWithIdentifier("outline").collapse
else
@splitViewH.subviewWithIdentifier("outline").toggleCollapse(sender)
end
end
def toggleTaskCollapse(sender)
return if RBSplitSubview.animating.to_i==1
if (@splitViewH.subviewWithIdentifier("outline").isCollapsed?) && !(@splitViewH.subviewWithIdentifier("flat").isCollapsed?)
## outline view is already collapsed, so this won't do anything. Have it switch instead.
@splitViewH.subviewWithIdentifier("outline").toggleCollapseQuick(sender)
@splitViewH.subviewWithIdentifier("flat").collapse
else
@splitViewH.subviewWithIdentifier("flat").toggleCollapse(sender)
end
end
def reset_newlyCreated
@newlyCreated=Set.new
end
def showNote(sender)
case sender.__ocid__
when @outlineView.__ocid__
note=sender.originalItemAtRow(sender.clickedRow)
@addOutline=true
when @taskView.__ocid__
note=@taskController.arrangedObjects.objectAtIndex(sender.clickedRow)
@addOutline=false
end
note.openNoteReader if note
end
def filterClick(sender)
(0..3).each {|s| @atdControl.setSelected_forSegment(false,s) }
sender=@filterView.itemAtRow(sender.clickedRow).representedObject
sender.toggleSelected
filterChange
end
def showInfo(sender)
end
def reset_filters
@filterGroup = nil
filterGroup
end
def reset_outline_visible
reset_filters
#@outlineController.setFilterPredicate(self)
willChangeValueForKey "rootActions"
willChangeValueForKey "tasks"
@rootActions=nil
@tasks=nil
didChangeValueForKey "tasks"
didChangeValueForKey "rootActions"
end
def reset_visible_actions
$managedObjectContext.processPendingChanges
reset_outline_visible
end
def filterChange
reset_newlyCreated
reset_visible_actions
end
def observeValueForKeyPath_ofObject_change_context(keyPath,object,change,context)
if keyPath.to_s == "selection"
filterChange
elsif keyPath.to_s == "arrangedObjects"
setupContextPopup
setupProjectPopup
end
end
def managedObjectContext
@appDelegate.managedObjectContext
end
def processQuickEntry(sender)
newEntry=sender.stringValue
return if !newEntry || newEntry.length==0
print "Quick Entry: #{newEntry}\n"
newAction=createActionWithParentAtIndex(nil,0)
newAction.setParent(@focus[0]) if @focus && @focus.size==1
newAction.smartName= newEntry
newAction.setContext(newAction.parent.context()) if (newAction.parent? && !newAction.context? && newAction.parent.context?)
scrollToAction(newAction)
selectAction(newAction)
sender.setStringValue("")
newAction
end
def searchPredicate
@searchPredicate
end
def searchPredicate=(value)
willChangeValueForKey "searchPredicate"
@searchPredicate = value
didChangeValueForKey "searchPredicate"
@taskController.takeValue_forKey(@searchPredicate,"filterPredicate")
#@outlineController.setFilterPredicate(@searchPredicate? @searchPredicate: self)
reset_outline_visible
##reset_visible_actions #force recalc
end
def processCompletionFilter(sender)
reset_visible_actions #force recalc
end
def createActionWithParentAtIndex(parent,index)
newAction= NSEntityDescription.insertNewObjectForEntityForName_inManagedObjectContext("Action",managedObjectContext)
if parent
parent.bumpChildrenFromIndex_throughIndex(index,index+1) if index > parent.valueForKeyPath("children.@max.sequenceValue").to_i
newAction.sequenceValue= index
parent.addChildrenObject(newAction)
parent.resequence
end
willChangeValueForKey "tasks"
@tasks=nil
didChangeValueForKey "tasks"
if !parent
willChangeValueForKey "rootActions"
@rootActions << newAction if @rootActions!=nil
didChangeValueForKey "rootActions"
else
newAction.setContext(parent.context()) if (parent.context())
end
@newlyCreated << newAction
reset_visible_actions
newAction
end
def expandUp(action)
expandUp(action.parent) if (action.parent?)
@outlineView.expandItem(@outlineController.nodeForObservedObject(action)) if (!action.isExpanded?) && @outlineController.nodeForObservedObject(action)
@addOutline=true
end
def scrollTaskToAction(action)
row=@taskController.arrangedObjects.indexOfObject(action)
@taskView.scrollRowToVisible(row) if row != NSNotFound
end
def scrollOutlineToAction(action)
expandUp(action.parent) if (action.parent?)
row=@outlineView.rowForOriginalItem(action)
@outlineView.scrollRowToVisible(row) if row != NSNotFound
end
def scrollToAction(action)
expandUp(action.parent) if (action.parent?)
row=@outlineView.rowForOriginalItem(action)
@outlineView.scrollRowToVisible(row) if row != NSNotFound
row=@taskController.arrangedObjects.indexOfObject(action)
@taskView.scrollRowToVisible(row) if row != NSNotFound
end
def selectAction(result)
@outlineController.setSelectedObjects([result])
@taskController.setSelectedObjects([result])
end
def editAction(action)
selectAction(action)
if @splitViewH.subviewWithIdentifier("outline").isCollapsed? && @splitViewH.subviewWithIdentifier("outline").isCollapsed?!=0
@addOutline=false
else
@addOutline=true if @addOutline==nil
end
if (not @addOutline)
row=@taskController.arrangedObjects.indexOfObject(action)
@taskView.editColumn_row_withEvent_select(@taskView.columnWithIdentifier("name"),
row,nil,true) if row != NSNotFound
else
row=@outlineView.rowForOriginalItem(action)
@outlineView.editColumn_row_withEvent_select(@outlineView.columnWithIdentifier("name"),
row,nil,true) if row != NSNotFound && row > 0
end
end
def addChildToOutline(sender)
@addOutline=true
addChild(sender)
end
def addSiblingToOutline(sender)
@addOutline=true
addSibling(sender)
end
def addChildToTasks(sender)
@addOutline=false
addChild(sender)
end
def addSiblingToTasks(sender)
@addOutline=false
addSibling(sender)
end
def addChild(sender)
taskController.commitEditing
#outlineController.commitEditing
sel=outlineController.selectedObjects
sel=taskController.selectedObjects if sel==nil || sel.count==0
sel=nil if sel==nil || sel.count==0
actionParent=sel[0] if sel != nil
index=0
index=sel[0].valueForKeyPath("children.@max.sequenceValue").to_i+1 if sel != nil
result=createActionWithParentAtIndex(actionParent,index)
scrollToAction(result)
selectAction(result)
result.setName("-Enter Action Name-")
editAction(result)
result
end
def addSibling(sender)
taskController.commitEditing
#outlineController.commitEditing
actionParent=nil
sel=outlineController.selectedObjects
sel=taskController.selectedObjects if sel==nil || sel.count==0
sel=nil if sel==nil || sel.count==0
actionParent=sel[0].parent if sel != nil
index=999
index=sel[0].sequenceValue.to_i+1 if actionParent != nil
result=createActionWithParentAtIndex(actionParent,index)
scrollToAction(result)
selectAction(result)
result.setName("-Enter Action Name-")
editAction(result)
result
end
def group(sender)
taskController.commitEditing
#outlineController.commitEditing
actionParent=nil
sel=outlineController.selectedObjects
sel=taskController.selectedObjects if sel==nil || sel.count==0
sel=removeChildrenFromSelection(sel)
sel=nil if sel==nil || sel.count==0
actionParent=sel[0].parent if sel != nil
index=999
index=sel[0].sequenceValue.to_i+1 if actionParent != nil
result=createActionWithParentAtIndex(actionParent,index)
result.setName("-Enter Action Name-")
sel.each{|a| a.setParent(result)}
$managedObjectContext.processPendingChanges
scrollToAction(result)
selectAction(result)
editAction(result)
result
end
def ungroup(sender)
taskController.commitEditing
#outlineController.commitEditing
actionParent=nil
sel=outlineController.selectedObjects
sel=taskController.selectedObjects if sel==nil || sel.count==0
sel=removeChildrenFromSelection(sel)
sel=nil if sel==nil || sel.count==0
actionParent=sel[0].parent if sel != nil
index=999
index=sel[0].sequenceValue.to_i+1 if actionParent != nil
sel.each do |s|
kids=sel.kids
newParent=s.parent
index=sequencevalue.to_i+1
newParent.bumpChildrenFromIndex_throughIndex(index,index+kids.size) if newParent
kids.each do |k|
k.setParent(newParent)
k.setSequenceValue(index)
index=index+1
end
newParent.resequence
end
$managedObjectContext.processPendingChanges
end
def deleteButton(sender)
end
def addFilter(result,f)
result[f.category]= FilterCategory.alloc.init(f.category) unless result[f.category]
result[f.category].addFilter(f)
end
def addFilters(result,filters)
filters.each do |f|
addFilter(result,f)
end
end
def buildAllFilters(mc)
result={}
addFilters(result,ContextFilter::buildFilters(mc.objectsForEntityNamed('Context')))
addFilters(result,TimeFilter::buildFilters())
addFilters(result,AreaFilter::buildFilters(mc.objectsForEntityNamed('Action')))
addFilters(result,PriorityFilter::buildFilters())
addFilter(result,ActionableFilter.alloc.init())
addFilter(result,NextFilter.alloc.init())
addFilter(result,RecurringFilter.alloc.init())
addFilter(result,SomedayFilter.alloc.init())
addFilter(result,TaskFilter.alloc.init())
addFilter(result,TemplateFilter.alloc.init())
addFilter(result,CameFromEmailFilter.alloc.init())
addFilter(result,SentEmailFilter.alloc.init())
addFilter(result,DelegatedFromFilter.alloc.init())
addFilter(result,DelegatedToFilter.alloc.init())
addFilters(result,CompletionFilter.buildFilters())
result
end
def filterSets
@filterSets = buildAllFilters(managedObjectContext) if !@filterSets
@filterSets.values
end
def showActionable(sender)
@atdControl.setSelectedSegment(1)
atdClick
end
def showToDo(sender)
@atdControl.setSelectedSegment(2)
atdClick
end
def showDone(sender)
@atdControl.setSelectedSegment(3)
atdClick
end
def mapFilterControl
filterSets # force calc if not built
@filterSets['Completion'].filters.each do |f|
case f.rawName
when "Done"
f.selected=1 if @atdControl.isSelectedForSegment?(3)
when "To-Do"
f.selected=1 if @atdControl.isSelectedForSegment?(2)
when "Actionable"
f.selected=1 if @atdControl.isSelectedForSegment?(1)
else
print "unknown completion filter #{f.name}\n"
end
end
oneselected=false
@filterSets['Completion'].filters.each do |f|
case f.rawName
when "Done"
if f.selected.to_i==1
@atdControl.setSelected_forSegment(true,3)
oneselected=true
else
@atdControl.setSelected_forSegment(false,3)
end
when "To-Do"
if f.selected.to_i==1
@atdControl.setSelected_forSegment(true,2)
oneselected=true
else
@atdControl.setSelected_forSegment(false,2)
end
when "Actionable"
if f.selected.to_i==1
@atdControl.setSelected_forSegment(true,1)
oneselected=true
else
@atdControl.setSelected_forSegment(false,1)
end
else
print "unknown completion filter #{f.name}\n"
end
end
@atdControl.setSelected_forSegment(true,0) if not oneselected
end
def updateCountViews
allCountView.setStringValue("#{@allCount}") if @allCountView
ableCountView.setStringValue("#{@actionableCount}") if @ableCountView
todoCountView.setStringValue("#{@todoCount}") if @todoCountView
doneCountView.setStringValue("#{@doneCount}") if @doneCountView
end
def filterGroup
return @filterGroup if @filterGroup != nil
timetaken=Benchmark.measure do
mapFilterControl if (@atdControl) #atdControl may not be set yet from nib
@filterList=[]
filterSets.each do |c|
c.filters.each do |f|
@filterList << f if f.selected.to_i !=0
end
end
#@filterList.each {|f| resetAtdFilter if f.category=="Completion"} if (@atdFilter.to_i != 0)# UI tweak
#sTasks=startingTasks.find_all{|a| a.isTask? && (@atdFilter.to_i != 1 || a.isActionable?) && (@atdFilter.to_i != 2 || a.done?)}
sTasks=startingTasks.find_all{|a| a.isTask?}
tTasks=sTasks.find_all{|a| !a.done? }
dTasks=sTasks.find_all{|a| a.done? }
aTasks=sTasks.find_all{|a| a.isActionable? }
@todoCount=tTasks.size
@actionableCount=aTasks.size
@doneCount=dTasks.size
@allCount=sTasks.size
updateCountViews
# filterSets.each do |c|
# c.filters.each do |f|
# if f.category!="Completion"
# f.tcount=f.filterActions(tTasks).size
# f.dcount=f.filterActions(dTasks).size
# f.acount=f.filterActions(aTasks).size
# else
# case f.rawName
# when "To-Do"
# f.tcount=tTasks.size
# f.dcount=0
# f.acount=aTasks.size
# when "Actionable"
# f.tcount=tTasks.size
# f.dcount=0
# f.acount=aTasks.size
# when "Done"
# f.dcount=dTasks.size
# f.tcount=0
# f.acount=0
# end
# end
# end
# end
if (@filterList.size < 1)
@filterGroup = Set.new()
else
@filterGroup=Set.new(@filterList).divide {|x| x.category}
end
end
print "benchmarking filterGroup", timetaken
pred = filterGroupPredicate
@outlineController.setFilterPredicate(pred)
@filterGroup
end
def filterGroupPredicate
styles=filterGroup
tops=[]
tops << NSPredicate.predicateWithFormat("isTask == true")
if (styles.size)
subs=[]
styles.each do |s|
s.each { |f| subs << f.predicate }
tops << NSCompoundPredicate.orPredicateWithSubpredicates(subs)
end
end
tops << @searchPredicate if @searchPredicate
return NSCompoundPredicate.andPredicateWithSubpredicates_(tops) if tops.size
return NSPredicate.predicateWithValue(true)
end
def evaluateWithObject?(obj)
return testObject(obj) == true
end
def testObject(obj)
styles=filterGroup
result=true
return true if @newlyCreated!= nil && @newlyCreated.include?(obj)
if (styles.size)
styles.each do |s|
sresult = false
s.each do |f|
if f.showAction?(obj)
sresult ||= true
break
end
end
result &&= sresult
break if !result
end
end
#result &&= obj.isActionable? if (@atdFilter.to_i==1)
#result &&= obj.done? if (@atdFilter.to_i==2)
result &&= @searchPredicate.evaluateWithObject?(obj) if @searchPredicate
result
end
def filterTasks(actions)
result = nil
timetaken=Benchmark.measure do
if (filterGroup.size < 1)
result=Set.new(actions.find_all{|a| a.isTask?}) #default is EVERYTHING
result=Set.new(result.to_a.find_all{|a| @searchPredicate.evaluateWithObject(a)}) if (@searchPredicate)
else
pred = filterGroupPredicate
result = Set.new(NSArray.arrayWithArray(actions).filteredArrayUsingPredicate(pred))
result += @newlyCreated if @newlyCreated
# result=Set.new(actions.find_all{|a| a.isTask? && testObject(a)})
end
#result=Set.new(result.to_a.find_all{|a| a.isActionable?}) if (@atdFilter.to_i==1)
#result=Set.new(result.to_a.find_all{|a| a.done?}) if (@atdFilter.to_i==2)
end
print "benchmarking filterTasks", timetaken
result
end
def filterRootActions(actions)
result = nil
timetaken=Benchmark.measure do
if (@focus)
checkFocus
result=filterTasks(@focus)
result=result.to_a.sort_by {|x| x.sequencePath}
else
result=Set.new(filterTasks(actions).collect { |task| task.rootAction})
result=result.to_a.sort_by {|x| x.sequencePath }
end
end
print "benchmarking filterRootActions", timetaken
result
end
def startingTasks
sTasks=nil
if @focus
checkFocus
sTasks=[]
@focus.each{|a| a.selfPlusChildren(sTasks)}
else
timetaken=Benchmark.measure do
sTasks=managedObjectContext.objectsForEntityNamed('Action')
end
print "benchmarking startingTasks", timetaken
end
sTasks
end
def tasks
return @tasks.to_a if @tasks != nil
@tasks=filterTasks(startingTasks)
#result=$managedObjectContext.objectsForEntityNamed('Action')
@tasks += @newlyCreated
@tasks.to_a.sort_by {|x| x.sequencePath.to_i}
end
def rootActions
return @rootActions if @rootActions != nil
return @focus if @focus != nil
@rootActions=filterRootActions(tasks)
@rootActions
end
def rootObjects
#print "rootObjects pulled\n"
result = rootActions
#print result.size," root actions\n"
rootActions
end
def splitView_didCollapse(splitView,subView)
subView.setHidden(true)
end
def taskSortDescriptors
if @taskSortDescriptors ==nil
@taskSortDescriptors=[ NSSortDescriptor.alloc.initWithKey_ascending("context.name",true),
NSSortDescriptor.alloc.initWithKey_ascending("sequencePath",true),
NSSortDescriptor.alloc.initWithKey_ascending("priority",true) ]
end
@taskSortDescriptors
end
def outlineSortDescriptors
if @outlineSortDescriptors == nil
@outlineSortDescriptors=[NSSortDescriptor.alloc.initWithKey_ascending("sequencePath",true)]
end
@outlineSortDescriptors
end
def outlineSortDescriptors=(value)
#willChangeValueForKey "outlineSortDescriptors"
#@outlineSortDescriptors=value
#didChangeValueForKey "outlineSortDescriptors"
print "osd written back\n"
end
def taskSortDescriptors=(value)
willChangeValueForKey "taskSortDescriptors"
@taskSortDescriptors=value
didChangeValueForKey "taskSortDescriptors"
end
def contextNameSorter
@contextNameSorter=[ NSSortDescriptor.alloc.initWithKey_ascending("name",true)] unless @contextNameSorter
@contextNameSorter
end
def projectNameSorter
@projectNameSorter=[NSSortDescriptor.alloc.initWithKey_ascending("isArea",false),
NSSortDescriptor.alloc.initWithKey_ascending("name",true)] unless @projectNameSorter
@projectNameSorter
end
#def outlineView_willDisplayCell_forTableColumn_tableColumn_item(ov,cell,col,item)
# @outlineController.outlineView_willDisplayCell_forTableColumn_item(ov,cel,col,item) if @outlineController != nil
#end
def tableViewSelectionDidChange(notif)
if (!@selectionNotification)
@addOutline=false
@selectionNotification=true
taskController.selectedObjects.each {|a| scrollOutlineToAction(a); break } #scroll to first on the list
outlineController.setSelectedObjects(taskController.selectedObjects)
@selectionNotification=false
end
end
def outlineViewSelectionIsChanging(notif)
#if (notif.object == outlineView || notif.object.__ocid__ == outlineView.__ocid__) && !@selectionNotification
if (notif.object == outlineView ) && !@selectionNotification
@addOutline=true
@selectionNotification=true
outlineController.selectedObjects.each {|a| scrollTaskToAction(a); break } #scroll to first on the list
taskController.setSelectedObjects(outlineController.selectedObjects)
@selectionNotification=false
end
end
def validateMenuItem?(anItem)
print "validating #{anItem.action}\n"
if anItem.action == :delete
return outlineController.selectedObjects.count > 0;
else
return super_validateMenuItem(anItem);
end
end
def delete(sender)
objToDelete=outlineController.selectedObjects
outlineController.setSelectedObjects(nil)
taskController.setSelectedObjects(nil)
moc = $managedObjectContext
objToDelete.each {|a| @newlyCreated.delete(a) }
objToDelete=objToDelete.to_a
#remove any children from selection
objToDelete=objToDelete.reject{|a| objToDelete.any?{|a2| a != a2 && a.hasAncestor?(a2)}}
parent = objToDelete[0].parent if objToDelete.size > 0
objToDelete.each do |a|
moc.deleteObject(a) # should cascade delete
end
moc.processPendingChanges
reset_visible_actions
scrollToAction(parent) if parent
end
def tableView_writeRowsWithIndexes_toPasteboard(view,rows,pboard)
taskController.setSelectionIndexes(rows)
@@dragCopy=taskController.selectedObjects
data=NSKeyedArchiver.archivedDataWithRootObject(@@dragCopy.valueForKeyPath("uniqueID"))
return true
end
def tableView_acceptDrop_row_dropOperation(view,info,row,op)
index=999
case op
when NSTableViewDropAbove
if row==view.numberOfRows
# if view.numberOfRows
# newParent=taskController.arrangedObjects.objectAtIndex(row-1).parent
# end
elsif row==0
index=0
# newParent=nil
else
below=taskController.arrangedObjects.objectAtIndex(row-1)
above=taskController.arrangedObjects.objectAtIndex(row)
# newParent=above.parent
# newParent=below.parent if (above.parent != below.parent)
index=above.sequenceValue.to_i
end
@@dragCopy.each do |a|
a.setParentAtIndex(a.parent,index)
index += 1
end
else
newParent=taskController.arrangedObjects.objectAtIndex(row)
@@dragCopy.each do |a|
if (!newParent || !newParent.hasAncestor?(a) || newParent==a.parent)
a.setParentAtIndex(newParent,index)
a.setParentAtIndex(a.parent,index)
index += 1
end
end
end
@@dragCopy.each do |a|
if a.parent
a.parent.resequence
end
end
resequence
return true
end
def removeChildrenFromSelection(selection)
#remove children from selection so we don't do operations twice
selection2=selection.reject{|a| selection.any?{|a2| a != a2 && a.hasAncestor?(a2)}}
selection2
end
def outlineView_writeItems_toPasteboard(view,items,pboard)
data=NSKeyedArchiver.archivedDataWithRootObject(items.valueForKeyPath("representedObject.uniqueID"))
@@dragCopy=items.valueForKeyPath("representedObject")
@outlineController.setSelectedObjects(@@dragCopy)
#remove children of dragged objects from copy because moving a parent moves the children by implication
# but we don't want to adjust the parents of the children
@@dragCopy=@@dragCopy.reject{|a| @@dragCopy.any?{|a2| a != a2 && a.hasAncestor?(a2)}}
pboard.declareTypes_owner(@@dragTypes,self)
pboard.setData_forType(data,@@dragTypes[0])
return true
end
def tableView_validateDrop_proposedRow_proposedDropOperation(view,info,row,op)
newParent=nil
result=NSDragOperationGeneric
case op
when NSTableViewDropAbove
# if row==view.numberOfRows
# if view.numberOfRows
# newParent=taskController.arrangedObjects.objectAtIndex(row).parent
# end
# elsif row<2
# newParent=nil
# else
# below=taskController.arrangedObjects.objectAtIndex(row-1)
# above=taskController.arrangedObjects.objectAtIndex(row)
# newParent=above.parent
# newParent=below.parent if (above.parent != below.parent)
# end
else
newParent=taskController.arrangedObjects.objectAtIndex(row)
end
@@dragCopy.each do |a|
if (newParent && newParent.hasAncestor?(a) && newParent!=a.parent)
result=NSDragOperationNone
end
end
return result
end
def outlineView_validateDrop_proposedItem_proposedChildIndex(view,info,item,index)
return NSDragOperationGeneric if item == nil
newParent=item.representedObject
result=NSDragOperationGeneric
@@dragCopy.each{|a| result=NSDragOperationNone if newParent.hasAncestor?(a) }
result
end
def resequence
roots=Set.new(managedObjectContext.objectsForEntityNamed('Action').collect { |task| task.rootAction})
roots.to_a.sort_by {|x| x.sequencePath }
roots.each_with_index {|a,i| a.setSequenceValue(i)}
roots
end
def bumpRootsFromIndex_throughIndex(fromIndex,toIndex)
bump= toIndex-fromIndex+1
list= resequence
list.each{|a| a.sequenceValue= a.sequenceValue.to_i+bump if a.sequenceValue.to_i >=fromIndex && a.sequenceValue.to_i <= toIndex }
end
def outlineView_acceptDrop_item_childIndex(view,info,item,index)
newParent= item ? item.representedObject : nil
index=index+1 #our indexes start at 1
if !newParent
bumpRootsFromIndex_throughIndex(index,index+@@dragCopy.count)
end
print "New Parent: #{newParent.name} New Index: #{index}\n"
@@dragCopy.each do |a|
if (!newParent || !newParent.hasAncestor?(a) || newParent==a.parent)
a.setParentAtIndex(newParent,index)
index += 1
end
end
if newParent
newParent.reset_kids
newParent.resequence
end
resequence if !newParent
@@dragCopy.each do |a|
print "Final: New Parent: #{a.parent.name} New Index: #{a.sequenceValue}\n"
end
return true
end
def outlineView_didFinishDragOperation(view,operation)
@@dragCopy=nil
end
def tableView_didFinishDragOperation(view,operation)
@@dragCopy=nil
end
def newSchedulerWindow(sender)
Scheduler.alloc.initWithActions(@outlineController.selectedObjects) if @outlineController.selectedObjects.count
end
def newBrowserWindow(sender)
@appDelegate.newBrowserWindow(sender)
end
@@txtIcon=NSImage.imageNamed("txt")
@@notxtIcon=NSImage.imageNamed("notxt")
def tableView_willDisplayCell_forTableColumn_row(tv,cell,column,row)
obj=@taskController.arrangedObjects.objectAtIndex(row)
#print "display hoook #{column.identifier.to_s}\n"
if column.identifier.to_s == "note"
if obj.note?
cell.setImage(@@txtIcon)
else
cell.setImage(@@notxtIcon)
end
end
end
def outlineView_shouldCollapseItem?(ov,item)
return true
end
def outlineView_shouldSelectItem?(ov,item)
return true
end
#def outlineView_willDisplayOutlineCell_forTableColumn_item(ov,cell,column,item)
#end
#def outlineView_willDisplayCell_forTableColumn_item(ov,cell,column,item)
#end
def focusOnSelection(sender)
nfocus=@outlineController.selectedObjects.to_a
nfocus=nfocus.reject{|a| nfocus.any?{|a2| a != a2 && a.hasAncestor?(a2)}}
nfocus=nfocus.sort_by {|x| x.sequencePath }
nbw=@appDelegate.newFocusWindow(nfocus)
end
def checkFocus
if @focus
@focus.reject!{|a| @focus.any?{|a2| a != a2 && a.hasAncestor?(a2)}}
end
end
def openNotes(sender)
@outlineController.selectedObjects.each{ |a| a.openNoteReader }
end
def doToday(sender)
date = NSCalendarDate.calendarDate
@outlineController.selectedObjects.each{ |a| a.setDoDate(date) }
end
def doTomorrow(sender)
date = NSCalendarDate.calendarDate.dateByAddingDays(1)
@outlineController.selectedObjects.each{ |a| a.setDoDate(date) }
end
def setDoDateByDayOfWeek(dow)
date=NSCalendarDate.calendarDate
today=date.dayOfWeek
dow=0 if dow==7
dow=7 if dow==14
dow=dow-today
@outlineController.selectedObjects.takeValue_forKey(date.dateByAddingDays(dow),"doDateDate")
end
def doMonday(sender)
setDoDateByDayOfWeek(1)
end
def doTuesday(sender)
setDoDateByDayOfWeek(2)
end
def doWednesday(sender)
setDoDateByDayOfWeek(3)
end
def doThursday(sender)
setDoDateByDayOfWeek(4)
end
def doFriday(sender)
setDoDateByDayOfWeek(5)
end
def doSaturday(sender)
setDoDateByDayOfWeek(6)
end
def doSunday(sender)
setDoDateByDayOfWeek(7)
end
def doNextMonday(sender)
setDoDateByDayOfWeek(1+7)
end
def doNextTuesday(sender)
setDoDateByDayOfWeek(2+7)
end
def doNextWednesday(sender)
setDoDateByDayOfWeek(3+7)
end
def doNextThursday(sender)
setDoDateByDayOfWeek(4+7)
end
def doNextFriday(sender)
setDoDateByDayOfWeek(5+7)
end
def doNextSaturday(sender)
setDoDateByDayOfWeek(6+7)
end
def doNextSunday(sender)
setDoDateByDayOfWeek(7+7)
end
def startAction(sender)
date = NSCalendarDate.calendarDate
@outlineController.selectedObjects.each{ |a| a.setStartDate(date) }
end
def finishAction(sender)
date = NSCalendarDate.calendarDate
@outlineController.selectedObjects.each{ |a| a.setDone(1); a.setFinishDate(date) }
end
def actionImportant(sender)
value=1
value=0 if @outlineController.selectedObjects.all? {|a| a.isImportant?}
@outlineController.selectedObjects.each{ |a| a.setIsImportant(value) }
end
def actionUrgent(sender)
value=1
value=0 if @outlineController.selectedObjects.all? {|a| a.isUrgent?}
@outlineController.selectedObjects.each{ |a| a.setIsUrgent(value) }
end
def actionParallel(sender)
value=0
@outlineController.selectedObjects.each{ |a| a.setIsSequential(value) }
end
def actionSequential(sender)
value=1
@outlineController.selectedObjects.each{ |a| a.setIsSequential(value) }
end
def actionSomeday(sender)
value=1
value=0 if @outlineController.selectedObjects.all? {|a| a.isSomedayUp?}
@outlineController.selectedObjects.each{ |a| a.setIsSomeday(value) }
end
def actionArea(sender)
value=1
value=0 if @outlineController.selectedObjects.all? {|a| a.isArea?}
@outlineController.selectedObjects.each{ |a| a.setIsArea(value) }
end
def actionTemplate(sender)
value=1
value=0 if @outlineController.selectedObjects.all? {|a| a.isTemplateUp?}
@outlineController.selectedObjects.each{ |a| a.setIsTemplate(value) }
end
def buildTemplate(sender)
tParents= Set.new
@outlineController.selectedObjects.each do |a|
tParents << a.templateParent
end
newTasks=[]
tParents.each do |a|
newA=a.instantiateTemplate
newA.selfPlusChildren(newTasks)
end
@newlyCreated += newTasks
reset_visible_actions
end
def print_ToDoA(sender)
@printer=TemplatePrinter.alloc.init
@printer.printTasksWithTemplate(@taskController.arrangedObjects,ToDoTemplate_A.new)
end
def printOutline(sender)
template= OutlineHTML.new
html= template.buildHTMLForProjects(rootActions(),self)
newPrintWindow(html)
#@printer=TemplatePrinter.alloc.init
#@printer.printHTML(html)
end
def newPrintWindow(html)
hw=PrintWindow.alloc.init
hw.setupWithHTML(self,html)
hw
end
def tableViewDefaultColumnIdentifiers(tableview)
print "tableViewDefaultColumnIdentifiers called\n"
return ["done","note","name","context","project","important","urgent","startDate","doDate","dueDate"]
end
#objc_method :tableViewDefaultColumnIdentifiers,%w{id}
def tableViewTypeAheadSelectionColumn(tableview)
print "tableViewTypeAheadSelectionColumn id called\n"
tableview.columnWithIdentifier("name")
end
#objc_method :tableViewTypeAheadSelectionColumn,%w{id id}
def tableViewColumnIdentifiersForDragImage(tableview)
print "tableViewColumnIdentifiersForDragImage called\n"
return ["name"]
end
#objc_method :tableViewColumnIdentifiersForDragImage,%w{id id}
def configurableColumnTableView_menuStringForColumn(tableView,column)
return @@columnNames[column.identifier.to_s]
end
def configurableColumnOutlineView_menuStringForColumn(ov,column)
configurableColumnTableView_menuStringForColumn(ov,column)
end
#objc_method :configureableColumnTableView_menuStringForColumn,%w{id id id}
def configurableColumnTableView_shouldAllowTogglingColumn(tv,column)
which=column.identifier
case which.to_s
when "name"
return nil
when "done"
return nil
else
return 1
end
end
def configurableColumnOutlineView_shouldAllowTogglingColumn(ov,column)
configurableColumnTableView_shouldAllowTogglingColumn(ov,column)
end
#objc_method :configurableColumnTableView_shouldAllowTogglingColumn,%w{bool id id}
def nameForRow(row)
return @taskController.arrangedObjects.objectAtIndex(row).valueForKey("name")
end
# def tableView_objectValueForTableColumn_row(tv,column,row)
# print "obj Value #{column.identifier} #{@@columnPaths[column.identifier.to_s]}\n"
# return @taskController.arrangedObjects.objectAtIndex(row).valueForKeyPath(@@columnPaths[column.identifier.to_s])
# end
def outlineView_willDisplayCell_forTableColumn_item(ov,cell,column,item)
# print "outlineView_willDisplayCell_forTableColumn_item",ov,@filterView,(ov == @filterView),"\n"
# print "ids",ov.object_id,@filterView.object_id,(ov.object_id == @filterView.object_id),"\n"
# print "ocids",ov.__ocid__,@filterView.__ocid__,(ov.__ocid__ == @filterView.__ocid__),"\n"
case ov.__ocid__
when @filterView.__ocid__
cell.setTitle(item.representedObject.name)
cell.setState(item.representedObject.selected)
else
end
end
def viewsClick(sender)
which = sender.selectedSegment
case which
when 0
splitViewV.subviewAtPosition(0).toggleCollapse(sender)
when 1
splitViewH.subviewAtPosition(0).toggleCollapse(sender)
when 2
splitViewH.subviewAtPosition(1).toggleCollapse(sender)
end
end
def setDelegateTo_returnCode_context(picker,returncode,context)
case returncode
when 1
sel=outlineController.selectedObjects
sel=removeChildrenFromSelection(sel)
choice=pickerPicker.selectedRecords[0]
@emailText="" if @emailText=="Enter any extra text for the email here"
sel.each do |a|
a.doDelegateTo(choice,pickerPicker.selectedValues[0],@emailText)
end
when -1
sel=outlineController.selectedObjects
sel.each do |a|
a.delegatedToID=nil
end
end
return true
end
def setDelegateFrom_returnCode_context(picker,returncode,context)
case returncode
when 1
sel=outlineController.selectedObjects
choice=pickerPicker.selectedRecords[0]
sel.each do |a|
a.delegatedFromID=choice.uniqueId
end
when -1
sel=outlineController.selectedObjects
sel.each do |a|
a.delegatedFromID=nil
end
end
return true
end
def personChose(sender)
pickerView.endEditingFor(nil)
NSApplication.sharedApplication.endSheet_returnCode(pickerView,1)
pickerView.close
return true
end
def personCancel(sender)
print "got cancel"
NSApplication.sharedApplication.endSheet_returnCode(pickerView,0)
pickerView.close
return true
end
def personClear(sender)
NSApplication.sharedApplication.endSheet_returnCode(pickerView,-1)
pickerView.close
return true
end
def delegateItemsTo(sender)
@pickerLabel="Select the person to delegate to:"
@emailText=""
result=NSBundle.loadNibNamed_owner("ABPicker",self)
pickerPicker.setNameDoubleAction('personChose:')
pickerPicker.setTarget(self)
if (outlineController.selectedObjects && outlineController.selectedObjects.length > 0)
abperson=nil
sel=outlineController.selectedObjects[0]
abperson= sel.delegatedTo if sel.delegatedToID?
pickerPicker.selectRecord_byExtendingSelection(abperson,false) if abperson
end
NSApplication.sharedApplication.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo(pickerView,browserWindow,self,'setDelegateTo:returnCode:context:',nil)
end
def delegateItemsFrom(sender)
@pickerLabel="Select the person to delegate from:"
result=NSBundle.loadNibNamed_owner("ABPicker",self)
pickerPicker.setNameDoubleAction('personChose:')
pickerPicker.setTarget(self)
if (outlineController.selectedObjects && outlineController.selectedObjects.length > 0)
abperson=nil
sel=outlineController.selectedObjects[0]
abperson= sel.delegatedFrom if sel.delegatedFromID?
pickerPicker.selectRecord_byExtendingSelection(abperson,false) if abperson
end
NSApplication.sharedApplication.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo(pickerView,browserWindow,self,'setDelegateFrom:returnCode:context:',nil)
end
def doDefer_returnCode_context(picker,returncode,context)
case returncode
when 1
sel=outlineController.selectedObjects
sel.each do |a|
a.startDate=deferDate
end
end
end
def processQuickSplit(newEntry,parent)
print "Quick Split: #{newEntry}\n"
return if !newEntry || newEntry.length==0
newAction=createActionWithParentAtIndex(parent,0)
#newAction.setParent(parent)
newAction.smartName= newEntry
newAction.setContext(newAction.parent.context()) if (newAction.parent? && !newAction.context? && newAction.parent.context?)
$managedObjectContext.processPendingChanges
newAction
end
def doQuickSplit_returnCode_context(picker,returncode,context)
undoManager.endUndoGrouping
undoManager.setActionName("Quick Split")
case returncode
when 1
parent=outlineController.selectedObjects[0]
list=[]
quickSplitText.split("\n").each{ |s| list << processQuickSplit(s,parent) }
@outlineController.setSelectedObjects(list)
@taskController.setSelectedObjects(list)
scrollToAction(list[0]) if list[0]
end
end
def deferCancel(sender)
NSApplication.sharedApplication.endSheet_returnCode(deferView,-1)
deferView.close
return true
end
def deferDone(sender)
NSApplication.sharedApplication.endSheet_returnCode(deferView,1)
deferView.close
return true
end
def quickSplitDone(sender)
quickSplitView.endEditingFor(nil)
NSApplication.sharedApplication.endSheet_returnCode(quickSplitView,1)
quickSplitView.close
return true
end
def quickSplitCancel(sender)
NSApplication.sharedApplication.endSheet_returnCode(quickSplitView,-1)
quickSplitView.close
return true
end
def hasSelection?
if (outlineController.selectedObjects && outlineController.selectedObjects.length > 0)
return true
end
false
end
def deferItems(sender)
return unless hasSelection?
@deferDate=NSCalendarDate.date
result=NSBundle.loadNibNamed_owner('Defer',self)
NSApplication.sharedApplication.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo(deferView,browserWindow,self,'doDefer:returnCode:context:',nil)
end
def quickSplit(sender)
return unless hasSelection?
if (outlineController.selectedObjects && outlineController.selectedObjects.length == 1)
sel=outlineController.selectedObjects[0]
@splitLabel = "QuickSplitting: #{sel.name}"
@quickSplitText=""
end
undoManager.beginUndoGrouping
result=NSBundle.loadNibNamed_owner('QuickSplit',self)
NSApplication.sharedApplication.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo(quickSplitView,browserWindow,self,'doQuickSplit:returnCode:context:',nil)
end
def windowWillReturnUndoManager(window)
return undoManager
end
def undoManager
return managedObjectContext.undoManager
end
end