Symbian developer community

 
wiki

Contacts and Calendar (Python on Symbian)

From Symbian Developer Community

Jump to: navigation, search

Original Author: Bogdan Galiceanu

Mobile devices are, for many people, the most important and personal tool that they own; holding all their important contacts, and used to organise their busy social and work lives. In consequence, the ability to interact with a user's contacts and calendar enables compelling, and very personal, applications to be developed.

PyS60 provides access to the user's contacts and calendar through the contacts and e32calendar modules.

Contents

Contacts

Overview

The contacts module provides an API that allows you to open the default phone book on the device, and then perform operations such as searching, reading, adding, modifying, and deleting entries.

The contact database is represented by a ContactDb. This contains a number of Contact objects, which in turn contain ContactField objects. The ContactDb is a dictionary-like object that is indexed by the unique IDs of its contained Contacts. Contacts are list-like objects which are indexed using the field indeces of the contained ContactField objects.

ContactDb represents a live view of the database - changes committed to the database are visible to outside applications immediately, and visa versa. Contacts are locked for editing before modification and released immediately afterwards.

The following sections explain how to search for, add, delete and modify contacts, and how to work with groups. There is more informaiton in the maemo garage here: http://pys60.garage.maemo.org/doc/s60/module-contacts.html

Opening the database

A database must be opened before any contacts operations can be performed. In order to open the device's default database, use the contacts module open() method as shown below:

 
import contacts
 
#Open the default contacts database
db = contacts.open()

In theory you can also create your own application specific database by passing the name of the database and a mode to the open() method. However this functionality is considered unreliable according to the official contacts documentation, and is in any case of limited use when compared to working with the user's live contact information.

There is no need to explicitly close the contact database; it will automatically be closed when the contacts object goes out of scope.

Adding a contact

To create a new contact, first open the database, create a Contact object, add the desired fields and values, and save it. The following code fragment creates a new contact, specifying a first name and mobile number:

import contacts
 
 
#Open the default contact database
db = contacts.open()
 
#Add new contact's details
c = db.add_contact()
c.add_field('first_name', 'Samantha')
c.add_field('mobile_number', '0123456789')
 
#And save the changes
c.commit()
 

The following table lists the most common field types available from S60 3rd Edition onwards. Fields with these types are added using the add_field() using the same syntax as in the above code fragment.

Table 5.1: Contact fields
citycompany_namecountrydate
dtmf_stringemail_addressextended_addressfax_number
first_namejob_titlelast_namemobile_number
notepager_numberphone_numberpo_box
postal_addresspostal_codestatestreet_address
urlvideo_numberpicturesecond_name
voipsip_idpersonal_ringtoneshare_view
prefixsuffixpush_to_talklocationid_indication


Deleting a contact

Contacts are deleted from the database by passing their ID to the __delitem__() method (finding the ID of a specific contact is shown in the next section).

The following code fragment shows how to delete the first Contact object which has "Samantha" in it's name:

 
import contacts
 
 
#Open the default contact database
db = contacts.open()
 
#Get its ID
c = db.find('Samantha')[0]
id = c.id
 
#Delete it
db.__delitem__(id)
 

Finding contacts

The contacts database can be queried for contacts that have a certain string in any of their fields using the find() method and passing the search string as its argument. The search can then be refined to see if a certain field matches the search criteria.

For example, the following code fragment first retrieves all contacts that have the text "James" in any field, and then displays information for those contacts that have "James" in the first_name field (only):

 
import contacts
 
#Open the database
db = contacts.open()
 
#Retrieve every contact that contains the name "James"
#and display those that have it in the first_name field
for c in db.find('James'):
if c.find('first_name')[0].value == u"James":
print c.find('first_name')[0].value + " " + c.find('last_name')[0].value + " " c.find('mobile_number')[0].value
 

Modifying existing contacts

New fields can be added, as shown in the section Adding a contact.

Existing field's labels and values can also be customized, as demonstrated in the following example:

 
import contacts
 
 
db = contacts.open()
c = db.find('Jim')[0]
 
#Retrieve the "last_name" field if it exists, change its value to some other name and its label to "Surname"
if c.find("last_name"):
c.find("last_name")[0].value = u"Cohen"
c.find("last_name")[0].label = u"Surname"
 
#Save the changes
c.commit()
 

Lastly, individual fields can be removed from the contact using the __delitem__(fieldindex) method.

Working with groups

PyS60 allows you to create and access related contacts using Group objects, and the set of Groups using the Groups object.

In simple terms, a Group is a list-like object containing the Ids of Contact objects belonging to the group. A Groups object is a dictionary-like collection of all the Group objects from the database, accessed using the Group unique Id.

As with any contact operation, the database must be opened before any of the group operations may be performed.

Creating a new group

After creating a Groups object, its add_group(name) method is used to create a new group (a new Group object).

The following code fragment adds the group "My new group" to the Groups object (and hence to the database):

 
import contacts
 
 
#Open the database
db = contacts.open()
 
#Instantiate a Groups object
groups = db.Groups(db)
 
#Add a new group
group = groups.add_group(u"My new group")
 

Retrieving existing groups

Groups are identified by their unique ID. A list of the unique group IDs can be obtained by calling Python's built-in list function on the iterator object returned by calling Python's built-in iter function on the Groups object.

The following code fragment uses the list iterator to print out the names of all the groups, based on their id:

 
import contacts
 
 
#Open the database
db = contacts.open()
 
#Get a list of IDs of the available groups
ids = list(iter(db.groups))
 
#Show the names of the groups
for id in ids:
print db.groups[id].name
 

Deleting a group

A group is deleted from its corresponding Groups object and, simultaneously, from the database by using Python's del operator. The following code fragment gets the list of available groups by ID, then calls del on the Group object:

 
import contacts
 
 
#Open the database
db = contacts.open()
 
#Get a list of IDs of the available groups
ids = list(iter(db.groups))
 
#Remove the group whose ID is first in the list
del db.groups[ids[0]]
 

Adding and removing contacts from a group

Calling the append(id) method of a Group object adds the contact with that ID to the group.

 
import contacts
 
 
#Open the database
db = contacts.open()
 
#Get a list of IDs of the available groups
group_ids = list(iter(db.groups))
 
#Open the first group in the list
group = db.groups[group_ids[0]]
 
#Get a list of all the contact IDs
contact_ids = contacts.open().keys()
 
#Add the first contact in the list
group.append(contact_ids[0])
 

To remove a contact from a group, we use the del operator on the group subscripted with that contact's ID.

Calendar

Overview

The calendar module is used in much the same way as the contacts module. The calendar is represented by a CalendarDb object that contains (Entry objects). Any new entries or changes saved to existing entries in a Python application appear in the device's native Calendar application, and visa versa

The available entry types are classes derived from the main Entry class. They are:

  • AppointmentEntry - returned by the add_appointment() method
  • EventEntry - returned by the add_event() method
  • AnniversaryEntry - returned by the add_anniversary() method
  • ReminderEntry - returned by the add_reminder() method
  • ToDoEntry - returned by the add_todo() method

Adding entries

Creating an entry is simple: open a database, call one of its methods (depending on what type of entry we opt for), optionally give values to the attributes of the entry, and save the changes.

The following snippet demonstrates how to add an appointment that expires at a certain time with information input by the user. The content attribute of the Entry class is used to specify the subject of the appointment – a short description that will be shown in the phone’s Calendar application. location is used to specify the location of the appointment. The set_time() function is used to specify the time frame during which the appointment entry will be valid. After creating the entry it is important to save it using the commit() method.

 
import e32calendar, appuifw
 
 
#Open the database
db = e32calendar.open()
 
#Create an appointment entry
appointment = db.add_appointment()
 
#Add the regular information
appointment.content = appuifw.query(u"Enter subject", "text")
appointment.location = appuifw.query(u"Enter location", "text")
 
#Ask the user for the start and end time
t1 = appuifw.query(u"Enter start hour", "time")
d1 = appuifw.query(u"Enter start date", "date")
t2 = appuifw.query(u"Enter end hour", "time")
d2 = appuifw.query(u"Enter end date", "date")
 
start_time = t1 + d1
end_time = t2 + d2
 
#Set the start and end time
appointment.set_time(start_time, end_time)
 
#Save the entry
appointment.commit()
 

Calendar entries are often have associated alarms for attracting the user’s attention. Alarms are set using the entry's alarm attribute. Note that alarms can only be enabled for entries of type AppointmentEntry and AnniversaryEntry - on other event types the alarm will not go off. Also, setting the alarm to None cancels it.

Below is an example of a calendar entry that is meant to remind to user to pick up a gift for an anniversary:

 
import e32calendar, time
 
 
#Open the database
db = e32calendar.open()
 
#Create an anniversary entry
anniversary = db.add_anniversary()
 
#Set the alarm for this time tomorrow, and give the entry highest priority
anniversary.set_time(time.time() + 86400)
anniversary.content = u"Pick up gift for Shelley"
anniversary.priority = 1
anniversary.alarm = time.time() + 86400
 
anniversary.commit()
 

Entries can also be repeated, which means they become active every at regular intervals based on associated repeat rules. For example, a person can have a calendar entry to remind them of another person's birthday. This entry should repeat every year on the same day.

 
import e32calendar, time
 
 
#Open the database
db = e32calendar.open()
 
#Add an anniversary entry
anniversary = db.add_anniversary()
 
anniversary.content = u"Hannah's birthday!"
anniversary.set_time(time.time() + 86400)
 
#Define the repeat rule
repeat = {"type":"yearly_by_date",
"start":time.time() + 86400,
"end":None,
"interval":1}
 
anniversary.set_repeat(repeat)
 
anniversary.commit()
 

Displaying and deleting entries

Finding all the calendar entries from within a time frame that match a certain search criteria is done using the find_instances(start_date, end_date, search_str=u[ ,appointments=0,events=0,anniversaries=0,todos=0,reminders=0]) method, called on the database. This returns a list of dictionaries that have the IDs of the entries. Then, using the subscript notation, the actual Entry object can be retrieved and its information can be displayed.

 
import e32calendar, appuifw, time
 
 
db = e32calendar.open()
 
#Find all entries between two dates given by the user that contain the word "birthday"
start = appuifw.query(u"Enter start date", "date")
end = appuifw.query(u"Enter end date", "date")
entries = db.find_instances(start, end, u"birthday")
 
#Display their subject and date
for i in entries:
print "Description: " + db[i["id"]].content
print "Date: " + time.strftime("%H:%M %m/%d/%Y", time.localtime(db[i["id"]].start_time))
 


Deleting an entry is similar to deleting a contact: once the ID is acquired, calling the del operator on the object subscripted with it removes the entry.

Conclusion

Comments

Hamishwillee said…

Hi Bogdan

  • Needs a Conclusion - I've added heading, please add some words
  • I've updated the introduction. Please confirm you think its an improvement. If not, please find new words, the old one didn't move me :-)
  • I thought that the fact that we're working on a live database is fairly important - so I've added that to the Contacts introduction - please check OK.
  • I thought it better to group the contacts and calendar related topics under those headings. Hope this looks OK to you.
  • I have written "There is no need to explicitly close the contact database; it will automatically be closed when the contacts object goes out of scope." Is this correct? Added new section just for opening the database.
  • I've stated that individual fields can be removed using __delitem__(fieldindex) - is it worth showing an example?
  • I've tried to remove cases where we refer to what the module documentation says - either by paraphrasing or using your clarifications.
  • Not sure what it means to say "subscripted with that contact's ID."
  • FYI, I've used () after every function - I think it makes things more readable.

Upshot, looks pretty good. Please check my changes are OK. Add a conclusion

Regards H

--Hamishwillee 05:34, 9 March 2010 (UTC)

Sign in to comment…