1============================================================= 2Tutorial - Adding Python code to an existing ObjC application 3============================================================= 4 5In this tutorial we are going to take an existing ObjC application and 6add Python and PyObjC to it. One of the reasons why you may want to do 7this is because some things are much simpler in Python than in ObjC, mainly 8due to the rich library Python has. 9 10To follow the tutorial you need: 11 12 * PyObjC 1.3.1 13 * py2app 0.2 or later (included in the binary installer for PyObjC) 14 * Python 2.3 or later (note: PyObjC is NOT compatible with MacPython-OS9) 15 * Mac OS X 10.3 or later 16 * Xcode Tools 17 18If you do not have a ``/Developer`` folder, then you do not have Xcode Tools 19installed. See `Getting the Xcode Tools`_. 20 21.. _`Getting the Xcode Tools`: http://developer.apple.com/tools/download/ 22 23The application we are going to modify is Apple's SimpleComboBox example. 24This example shows you how to use combo boxes, but that is not what interests 25us right now: the application pretends to be a database application that allows 26you to keep notes (such as track list) for your CD collection. With such an 27application it feels silly that even though you want to type notes on 28the CD you are currently playing in iTunes you still have to retype 29album title, artist and genre. This is what we are going to fix: we 30are going to add a button "ask iTunes", which will use Python's 31AppleScript support to ask iTunes about the currently playing track 32and fill in the fields for you. 33 34Follow these steps: 35 361. Make a copy of ``/Developer/Examples/AppKit/SimpleComboBox`` to work on. 37 Let's call this ``SimpleComboBoxPlus``: 38 39 .. sourcecode: sh 40 41 $ cp -R /Developer/Examples/AppKit/SimpleComboBox SimpleComboBoxPlus 42 43 From this point on, all shell commands take place from this 44 ``SimpleComboBoxPlus`` folder. 45 462. Open it in Xcode, build it, and see what it does. 47 483. Open ``CDInfoDocument.nib``. Select the Class View, ``NSObject``, subclass 49 as ``ITunesCommunication``. Give the class an ``askITunes:`` action. 50 Instantiate the class as object ``ITunesCommunication``. This wll be the 51 class that we write in Python. 52 534. Go to the object view again, open the Window. 54 555. Move the text box down a bit to make space, add a button "ask iTunes". 56 576. Connect this button to the ``askITunes:`` action of the 58 ``ITunesCommunication`` object. 59 607. We now need to write the code implementing the ``ITunesCommunication`` 61 class. As this tutorial is about using PyObjC in existing ObjC programs 62 and not about PyObjC itself, we are going to skip writing the code and 63 simply copy ``ITunesCommunication_1.py`` to ``ITunesCommunication.py``. 64 658. Now we need to create the build script for our plugin, create a file named 66 ``setup.py`` with the following contents: 67 68 69 .. sourcecode:: python 70 71 from distutils.core import setup 72 import py2app 73 74 setup( 75 plugin = ['ITunesCommunication.py'] 76 ) 77 78 You may also copy this file from ``setup.py``. 79 809. Run the setup script to create a temporary plugin bundle for development: 81 82 .. sourcecode: sh 83 84 $ python setup.py py2app -A 85 86 Note that we use the ``-A`` argument to create an alias plugin bundle at 87 ``dist/ITunesCommunication.py``. Alias bundles contain an alias to the 88 main script (``ITunesCommunication.py``) and symlinks to the data files 89 (none in this case). This allows us to keep working on the source files 90 without having to rebuild the application. This alias bundle is similar 91 to a ZeroLink executable in Xcode - it is for DEVELOPMENT ONLY, and will 92 not work on other machines. 93 9410. Add ``dist/ITunesCommunication.plugin`` to the Resources folder in your 95 Xcode project. You can do this by ctrl-clicking the Resources folder 96 and choosing "Add Existing Files...". Make sure to choose 97 "Create Folder References for any added folders". 98 9911. Open ``main.m``, it is in the "Other Sources" folder in your Xcode 100 project, and change the main(...) function to the following: 101 102 .. sourcecode:: objective-c 103 104 int main(int argc, const char *argv[]) { 105 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 106 NSString *pluginPath = [[NSBundle mainBundle] 107 pathForResource:@"ITunesCommunication" 108 ofType:@"plugin"]; 109 NSBundle *pluginBundle = [NSBundle bundleWithPath:pluginPath]; 110 [pluginBundle load]; 111 [pool release]; 112 return NSApplicationMain(argc, argv); 113 } 114 115 116 You may also copy a full main.m from ``main.m``. This code ensures 117 that our ITunesCommunication plugin is loaded before the nib 118 files. 119 12012. Build and run. When you press the "Ask iTunes" the "CD Title" and 121 "Band Name" fields will be filled with one of the best albums of the last 122 few years :-) 123 12413. Now we need to make the program talk to iTunes. The current MacPython 125 interface to the Open Scripting Architecture requires an extra step when 126 compared to AppleScript: you need to manually generate a Python package 127 that wraps all the AppleScript terminology for an application. To make 128 matters more complicated iTunes is one of those special cases where the 129 standard way to generate this package (start the application, ask it for 130 its terminology) does not work, so we have to actually look into the 131 bowels of ``iTunes.app``. This leads to the following hefty command line 132 which you should run in the ``SimpleComboBoxPlus`` directory: 133 134 .. sourcecode:: sh 135 136 $ cd SimpleComboBoxPlus 137 $ pythonw -c "from gensuitemodule import main;main()" \ 138 --output iTunes --creator hook --resource \ 139 /Applications/iTunes.app/Contents/Resources/iTunes.rsrc 140 14114. Finally, add the code to ``ITunesCommunication.py`` to actually communicate 142 with iTunes. We cop out and copy it from ``ITunesCommunication_2.py``. 143 14415. Build and run. If you press the button when iTunes is playing the Title 145 and Band names will be filled, otherwise they will be cleared. In a real 146 application you would disable the "Ask iTunes" button unless iTunes was 147 active. All that is left as an exercise to the reader. 148 14916. To make this application redistributable, perform the following commands 150 to make the plugin redistributable: 151 152 .. sourcecode:: sh 153 154 $ rm -rf dist 155 $ python setup.py py2app 156 157 Then, from Xcode, clean your project (shift-cmd-K), switch to Deployment 158 mode, and rebuild. 159 160A minor variation 161----------------- 162 163There a several projects that improve upon the built-in AppleScript support 164(or to be more precise "application scripting support"). One of those is 165`AppScript`_. 166 167.. _`AppScript`: http://freespace.virgin.net/hamish.sanderson/appscript.html 168 169When you have this module installed you can replace the contents of 170``ITunesCommuncation.py`` with ``ITunesCommunication_AppScript.py``, 171and you can skip step 13 entirely. 172