main.py
from PyObjCTools import AppHelper
import objc; objc.setVerbose(True)
import AppController
import CalController
AppHelper.runEventLoop()
This is a Python version of the sample code in the CalendarStore Coding Headstart for WWDC‘07.
Note that this implementation is incomplete, the bits that should be implemented by the reader have not been implemented yet.
from Cocoa import *
from CalendarStore import *
class AppController (NSObject):
mainWindow = objc.IBOutlet()
taskCreationDialog = objc.IBOutlet()
priorityPopup = objc.IBOutlet()
eventCreationDialog = objc.IBOutlet()
calendarData = objc.IBOutlet()
calItemTitle = objc.ivar()
calItemStartDate = objc.ivar()
calItemEndDate = objc.ivar()
objc.synthesize('calItemTitle', copy=True)
objc.synthesize('calItemStartDate', copy=True)
objc.synthesize('calItemEndDate', copy=True)
@objc.IBAction
def showTaskCreationDialog_(self, sender):
# Set default values for the title, start date and priority
# Cocoa bindings will clear out the related fields in the sheet
self._.calItemTitle = None
self._.calItemStartDate = NSDate.date()
NSApp.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.taskCreationDialog, self.mainWindow,
self, 'didEndSheet:returnCode:contextInfo:', None)
@objc.IBAction
def showEventCreationDialog_(self, sender):
# Set default values for the title and start/end date
# Cocoa bindings will clear out the related fields in the sheet
self._.calItemTitle = None
self._.calItemStartDate = NSDate.date()
self._.calItemEndDate = NSDate.dateWithTimeIntervalSinceNow_(3600)
NSApp.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.eventCreationDialog, self.mainWindow, self,
'didEndSheet:returnCode:contextInfo:', None)
# Called when the "Add" button is pressed on the event/task entry sheet
# This starts the sheet dismissal process
@objc.IBAction
def dismissDialog_(self, sender):
NSApp.endSheet_(sender.window())
@objc.selectorFor(NSApplication.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo_)
def didEndSheet_returnCode_contextInfo_(self, sheet, returnCode, contextInfo):
# Find out which calendar was selected for the new event/task
# We do this using the calendarData array controller which is bound to
# the calendar popups in the sheet
selectedCalendar = None
count = len(self.calendarData.selectedObjects())
if count > 0:
selectedCalendarUID = self.calendarData.selectedObjects()[0].uid()
selectedCalendar = CalCalendarStore.defaultCalendarStore(
).calendarWithUID_(selectedCalendarUID)
# Create an event/task based on which sheet was used
if sheet is self.taskCreationDialog:
if self._.calItemTitle is None:
self._.calItemTitle = "My Task"
self.createNewTaskWithCalendar_title_priority_dueDate_(
selectedCalendar, self._.calItemTitle,
self.priorityPopup.selectedTag(),
self._.calItemStartDate)
else:
if self._.calItemTitle is None:
self._.calItemTitle = "My Event"
self.createNewEventWithCalendar_title_startDate_endDate_(
selectedCalendar, self._.calItemTitle,
self._.calItemStartDate, self._.calItemEndDate)
# Dismiss the sheet
sheet.orderOut_(self)
def createNewEventWithCalendar_title_startDate_endDate_(
self, calendar, title, startDate, endDate):
# Create a new CalEvent object
newEvent = CalEvent.event()
# Set the calendar, title, start date and end date on the new event
# using the parameters passed to this method
newEvent._.calendar = calendar;
newEvent._.title = title;
newEvent._.startDate = startDate;
newEvent._.endDate = endDate;
# Save the new event to the calendar store (CalCalendarStore) and
# return it
res, err = CalCalendarStore.defaultCalendarStore().saveEvent_span_error_(
newEvent, 0, None)
if res:
return newEvent
NSLog("error:%@", err.localizedDescription())
return None
def createNewTaskWithCalendar_title_priority_dueDate_(
self, calendar, title, priority, dueDate):
# Create a new CalTask object
newTask = CalTask.task()
# Set the calendar, title, priority and due date on the new task
# using the parameters passed to this method
newTask._.calendar = calendar
newTask._.title = title
newTask._.priority = priority
newTask._.dueDate = dueDate
# Save the new task to the calendar store (CalCalendarStore) and
# return it
res, err = CalCalendarStore.defaultCalendarStore().saveTask_error_(newTask, None)
if res:
return newTask
NSLog("error:%@", err.localizedDescription())
return None
"""
Bindings and notification support for Calendar data used
by this application. Exposes read-only collections
(calendars, events, tasks) as observable entities.
"""
from Cocoa import *
from CalendarStore import *
highPriority = "High"
normPriority = "Normal"
lowPriority = "Low"
nonePriority = "None"
# Transformer class for CalPriority->String conversion
class CalPriorityToStringTransformer (NSValueTransformer):
'''
The CalPriorityToStringTransformer class allows easy conversion between
CalPriority values (0-9) and human-readable priority strings (High,
Normal, Low, None). This allows us to populate the priority dropdown
using bindings
'''
@classmethod
def transformedValueClass(cls):
return type(NSString)
@classmethod
def allowsReverseTransformation(cls):
return False
def transformedValue_(self, value):
priority = value.unsignedIntValue()
if priority < CalPriorityHigh:
return nonePriority
elif priority < CalPriorityMedium:
return highPriority
elif priority == CalPriorityMedium:
return normPriority
return lowPriority
class CalController (NSObject):
def awakeFromNib(self):
# Register a transformer object for easy generation of
# human-readable priority strings
#
# See CalPriorityToStringTransformer implementation below
prioTransformer = CalPriorityToStringTransformer.alloc().init()
NSValueTransformer.setValueTransformer_forName_(
prioTransformer, "CalPriorityToStringTransformer")
# Register for notifications on calendars, events and tasks so we can
# update the GUI to reflect any changes beneath us
NSNotificationCenter.defaultCenter().addObserver_selector_name_object_(
self, 'calendarsChanged:',
CalCalendarsChangedExternallyNotification, None)
NSNotificationCenter.defaultCenter().addObserver_selector_name_object_(
self, 'calendarsChanged:',
CalCalendarsChangedNotification, None)
NSNotificationCenter.defaultCenter().addObserver_selector_name_object_(
self, 'eventsChanged:',
CalEventsChangedExternallyNotification, None)
NSNotificationCenter.defaultCenter().addObserver_selector_name_object_(
self, 'eventsChanged:',
CalEventsChangedNotification, None)
NSNotificationCenter.defaultCenter().addObserver_selector_name_object_(
self, 'tasksChanged:',
CalTasksChangedExternallyNotification, None)
NSNotificationCenter.defaultCenter().addObserver_selector_name_object_(
self, 'tasksChanged:',
CalTasksChangedNotification, None)
# Set up the read-only calendars/events/tasks arrays from Calendar Store
# as observable keys for Cocoa Bindings
# This in conjunction with the notifications will allow for immediate UI
# updates whenever calendar data changes outside of this app
def calendars(self):
return CalCalendarStore.defaultCalendarStore().calendars()
def events(self):
store = CalCalendarStore.defaultCalendarStore()
# Pull all events starting now from all calendars in the CalendarStore
allEventsPredicate = CalCalendarStore.eventPredicateWithStartDate_endDate_calendars_(
NSDate.date(), NSDate.distantFuture(), store.calendars())
return store.eventsWithPredicate_(allEventsPredicate)
def tasks(self):
store = CalCalendarStore.defaultCalendarStore()
# Pull all uncompleted tasks from all calendars in the CalendarStore
return store.tasksWithPredicate_(
CalCalendarStore.taskPredicateWithUncompletedTasks_(
store.calendars()))
# With the observable keys set up above and the appropriate bindings in IB,
# we can trigger UI updates just by signaling changes to the keys
def calendarsChanged_(self, notification):
self.willChangeValueForKey_("calendars")
self.didChangeValueForKey_("calendars")
def eventsChanged_(self, notification):
self.willChangeValueForKey_("events")
self.didChangeValueForKey_("events")
def tasksChanged_(self, notification):
self.willChangeValueForKey_("tasks")
self.didChangeValueForKey_("tasks")
from PyObjCTools import AppHelper
import objc; objc.setVerbose(True)
import AppController
import CalController
AppHelper.runEventLoop()
"""
Script for building the example.
Usage:
python setup.py py2app
"""
from distutils.core import setup
import py2app
setup(
name='PyCalendarStore',
app=["main.py"],
data_files=["English.lproj"],
)