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