MacOSX: Address book integration

From Apache OpenOffice Wiki
Jump to: navigation, search

This page is part of Google Summer_of_Code_2007 proposal by Omer Bar-or and mentored by Sebastien Plisson


I propose to integrate the Mac OS X Address Book with (both Aqua and X11 versions), as described on the project page for the Google Summer of Code. This task would provide the equivalent of the Mozilla address book integration already found in, but using the Mac OS X Address Book API. Additionally, not mentioned in the project page, is the issue of combining two address books (Mozilla and OS X), which would require handling collisions or selecting one of the two address books to use.

This project has four phases, the first three of which are described briefly on's project page. a) Familiarize oneself with the current OOo Mozilla Address Book integration - this task belongs first because it will be a guide for exactly which parts of the Max OS X Address Book API are important (see (b)). This task involves first experimenting with the Mozilla address book implementation by changing bits of the code and seeing how those changes manifest in the OOo address book functionality, then creating an equivalent to the Mozilla address book integration that works with a text file (since nothing makes a person more familiar with code than building it). b) Familiarize oneself with the Mac OS X Address Book API - after (a), the information needed from the Mac OS X Address Book should be known, so this task is largely a matter of reading up on the API and seeing what is available and in what forms. One place to look, if the API itself is unclear, is Quicksilver's Apple Address Book Module, which uses the API. The result of this task is a small program that uses the Mac OS X Address Book API to create the text file from which the section of code created in task (a) reads. c) Make a prototype for OOo Mac OS X address book integration - given (a) and (b), this process is straightforward. One replaces the reading from and writing to a text file from (a) with the interaction with the Mac OS X Address Book API from (b). d) Develop strategies for handling conflicts between the two address books - this task first entails familiarizing oneself with OOo's strategies for conflict resolution, especially if a strategy is already in place for address book integration. If a strategy is not in place, the second part of this task involves creating a strategy specific to address books. And, finally, if time permits, completing this task means prototyping the strategy using the Mac OS X Address Book and Mozilla integrations.

Current Status

cws macaddressbook01 has been integrated into m229.

Affected Modules

  • connectivity: I created a new directory: source/drivers/macab/ and inside of it placed the files that comprise the driver itself. The structure is described below.
  • dbaccess: I essentially searched this module for "kab" (the KDE Address Book) and added the equivalent code for "macab" (the Mac OS X Address Book) just below it. As far as I can tell, all of the address book integrations are handled in the same way in these files because the relevant sections in them are largely concerned with what is and is not a valid data source and the path to follow when one of them is selected from a wizard.
  • extensions: I changed the address data source wizard to show the Mac OS X Address Book and associate it with the URL "sdbc::address::macab", which is a URL recognized only by the driver.
  • scp2: I added the two library files created in the driver to the list of library files to expect for a Mac OS X build (in source/ooo/file_library_ooo.scp), so that OOo links to them and adds the driver to its driver list at runtime. I also added the two files to a the list associated with gid_Module_Root_Files_5 (in source/ooo/module_hidden_ooo.scp), which is where the other address book drivers are added.

The structure of the Mac OS X Address Book driver

The driver creates a table comprising of all records in the Mac OS X Address Book and a table for each group in the address boo comprising of all of its members. It is based significantly on the KDE Address Book integration, so much so that it is really the KDE Address Book integration's structure with Mac OS X Address Book data instead of KDE Address Book data and a few optimizations. The most significant place in which the two integrations diverge is that the KDE Address Book API makes it easy to access individual records and individual fields from them. The Mac OS X Address Book API, on the other hand, allows access to an array of all records or to the records that match a search criterion, and it supports several data types that cannot be represented in a single column (e.g., multivalues, which hold a list of variables of the same type and labels that go along with them). So, I built an intermediary structure that takes the array of all records and makes it easily accessible in the ways that OOo data sources expect. The intermediary structure consists of the following:

  • macabfield (defined in MacabRecord.hxx): A structure consisting of a Carbon data value and its type - each of these corresponds to a field in a table.
  • MacabRecord: A single record in a table in the address book - this class basically holds a list of macabfields and makes it easy to create, access, and manipulate them.
  • MacabHeader: The metadata for a table in the address book - this class is a subclass of MacabRecord, but each of the macabfields consists of a CFString for the name of a column and the type of data expected in that column. The organization of the macabfields here determines the order of them in each MacabRecord that this header describes, and it is also the order in which the columns will appear in OOo. For this reason, this class has its own sort and comparison functions.
  • MacabRecords: A class that holds an array of variables of type MacabRecord and the MacabHeader that describes them - this class basically corresponds to an entire table in the data source, but makes it easy to access a single record or a single field for a single record (by the column number or the column's name). It also contains an initialization function that creates the MacabHeader and each MacabRecord for all of the records in the Mac OS X Address Book. In other words, the initialization function creates a master table consisting of all of the information from the address book. As it creates these, it flattens the complex data types allowed by the Mac OS X Address Book into simple ones that can fit in one column in the data source and creates a unique column name for each. Also, because it creates the MacabHeader, it is in charge of which columns must appear in the table ("requiredProperties") and which should only appear if there is data contained in them ("nonRequiredProperties"). It requires some columns, because those columns are in turn required by make mail merge (see below). Finally, each MacabRecords also has its own name, which is how it is distinguished from the others in SQL calls.
  • MacabGroup: The same as a MacabRecords, but with a different constructor - this class corresponds to a table that holds the subset of the members of the address book that are members of a particular group (see: groups in the Mac OS X Address Book). It is its own class, separate from MacabRecords, because it is treated as logically different by the Mac OS X Address Book and also because the constructor for it expects a reference to the MacabRecords holding all of the address book records. That way, instead of rerunning the methods to create the MacabHeader and each MacabRecord (which are expensive because they convert complex data structures into simpler ones), the constructor simply goes through the list of members of the group, getting a UID for each, and then searches the MacabRecords with all address book records in it for that UID. When it finds it, the constructor adds a reference to the MacabRecord holding that UID to its own list. The disadvantage to this method is that the same MacabHeader is used for all tables, so a group comprising of one person who only has a first and last name will still contain empty fields for every other field that has data in it for some user. The advantage is that it is much more efficient.
  • MacabAddressBook: The single object that allows access to the rest of the intermediary structure. A reference to it is held in MacabConnection, and all of the other parts of the integration access the intermediary structure through MacabConnection. MacabAddressBook holds a reference to all of the main MacabRecords, which holds all of the records of the address book, and all of the MacabGroups. It is also in charge of creating them when requested if they do not already exist.
  • macabutilities.hxx: a header file that contains utilities used repeatedly by the other functions. Two of these functions (for converting between OUStrings and CFStrings) were built by Florian Heckl.

In addition, because the Mac OS X Address Book API is available as soon as a user logs in, I did not create an equivalent to KDEInit.cxx and KDEInit.h which are in charge of initiating the KDE Address Book if it is not already initiated.

What is done and at least partially tested

  • You can add the Mac OS X Address Book as a data source, in both Aqua and X11 builds (directions below)
    • Originally written by Omer Bar-or based on the KDE Address Book integration by Éric Bischoff
    • Debugging for a crash when a complex data type is requested but is empty by Patrick Luby
    • Functions to convert CFStrings to OUStrings that can handle non-ASCII characters by Florian Heckl
    • Testing for every type of fields available through the Mac OS X Address Book by Omer Bar-or
    • General debugging by Florian Heckl, Patrick Luby, and Omer Bar-or
  • You can get column names (elsewhere called "labels") to show up in any language supported by Mac OS X (directions below)
    • Issue discovered and solution found by Patrick Luby and Omer Bar-or
    • Patch written by Omer Bar-or
  • You can sort, filter, and do anything else that is available via the data source toolbar (as long as it is not grayed out). You can even sort by multiple columns (using the "AZ" button that has no arrows)
    • Testing and debugging by Omer Bar-or
    • The columns are optimized for mail merge based on a decision by Florian Heckl and Omer Bar-or
  • If you have two groups of the same name in your address book, or two fields of the same name in any record, the first group/field will show up normally, whereas the second will have a " (2)" appended to it. (The third would have a " (3)" and so forth.) For example, if I have two home phone numbers for someone, the first will be listed under "phone: home" and the second under "phone: home (2)", and if I have two groups named "friend" (for whatever reason), the first will be the table named "friend", and the second will be the table named "friend (2)".
    • Testing and debugging by Omer Bar-or
  • You can view data sources, hide data sources, refresh the data source, and change tables as much as you like.
    • Testing and debugging by Omer Bar-or
  • You can copy from the data source into your documents (note: you have to use ctrl-c to copy from the data source).
    • Testing by Omer Bar-or
  • You can write a limited set of queries for the data source in OOo Base
    • Testing by Omer Bar-or

Known issues

There are no known issues in cws macaddressbook01.

Directions for downloading (based on bash shell)

Please see AquaBuild (for Aqua) or MacOSXBuildInstructions (for X11)

Directions for adding the address book as a data source

  1. Open
  2. Go to "File"->"Wizards"->"Address Data Source..."
  3. Select "Mac OS X Address Book"
  4. Click "Next"
  5. If you have groups in your address book, choose one (the top one, "Address Book," is all of the records in your address book), and click "Next"
  6. If you want, change the name or file name of your data source.
  7. Click "Finish"
  8. View your data sources (either: press F4, click on the "Data Sources" icon in your toolbar, or go to "View"->"Data Sources"
  9. If the address book data source is not expanded automatically, expand it (by the name you gave it in 7), then expand "Tables" and click on a table of your choosing.
  10. You should see all of your address book records now in!

Directions for mail merge

  1. View your data sources and click on the Mail Merge button (or go to "Tools"->"Mail Merge Wizard")
  2. Click "Next" twice.
  3. If you opened the mail merge wizard via "Tools"->"Mail Merge Wizard," you'll need to select a data source by clicking on "Select Address List" and choosing the name of your data source.
  4. Click on "Match Fields"
  5. Match each field that the mail merge wizard requires with a column from the data source, until the preview (at the bottom) has no sections that read "not yet matched." The columns in the data source should be in an order very similar to the one expected by the mail merge wizard.
  6. Click "Next" until you cannot any longer (when you reach step 8 in the wizard)
  7. If you want, save, print, or send the record. (Otherwise, quit the wizard now.)
  8. If you did save, print, or send, click "Finish."

Directions for showing the column names in a non-English language

  1. Add language directories to OOo (since it does not yet support native localization)
    1. Close if it is open.
    2. View the contents of the "" package. e.g., cd /Applications/\
    3. Go into the "Contents" folder
    4. Go into the "Resources" folder
    5. Create a directory named "en.lproj"
    6. Create a directory with the code of the language you want followed by ".lproj" (e.g., "es.lproj" for Spanish, "fr.lproj" for French, &c.)
  2. Change your locale in System Preferences
    1. Go into System Preferences
    2. Go into the International preference pane
    3. Drag the language you want up to the top of the list
    4. Close System Preferences
  3. Open
  4. View your data sources
  5. The address book's column names should now be in the language you want (if it is supported by Mac OS X)!

Student Task List

The task is completed.

Personal tools