Monday, September 13, 2010

Looking for a bargain? Try the MacUpdate Bundle...

I decided to buy the new MacUpdate Bundle and surprisingly I didn't regret it five minutes later like I usually do after an impulse purchase.

For $49.99 you get $443 worth of apps and if you are one of the first 20.000 buyers you get two bonus apps. The loot is as follows:





ShareTool from YazSoft - Securely connect to your home or office network
via Bonjour from any location. 
Backup Pro from Belight Software - Synchronization and backup utility
that gives you more options that Time Machine does.

Voila from Global Delight Technologies - Capture and record, edit,
annotate, organize and share images and video.

Espionage from Tao Effect - Not quite what the name suggests, this is an
encryption application. It lets you encrypt and password protect individual
folders and files. Integrates with Finder and various other applications. The
app also features an auto backup feature.
My Living Destop from Amuse Inc. - Does just what the name says, features
25 different scenes and lets you import your own videos. Also includes a
video screensaver.
Mind Node Pro by Markus Müller -  Mind mapping application. Pretty
straight forward and most of all simple, quick and easy to use. Just the way
I like it.
Toast 10 Titanium from Roxio - This hardly needs introduction, standard CD &
DVD burning suite for OS X. Ships with a gaggle of secondary utilities
including a Disk Cover editor.
Concentrate  - Workflow and productivity app that helps you
streamline your workflow. Does things like block distracting websites and
lets you define an activity and launches the apps and websites required.

Cashculator from Apparent Software - Who doesn't need to organize
their finances? The interface is clean, simple and intuitive the only data export 
option is *.csv format. This forces you to do use Excel's lame import wizard if 
you ever feel the need to do analyze your expenses with a heavy duty app.  
It would be cool to have an iPhone/iPod counterpart for this CashCulator.
Live interior 3D standard from Beligth Software - Easy to use 3D interior
design app. Not exactly something I'll use a lot but it looks pretty impressive.
Bonus: Vitamin R from publicspace.net - A productivity app that basically
aims to help you to organize your tasks and increase your productivity using
time-slicing.
Bonus: Compartments from LittleFin software - A Home Inventory program.
Need to organize your possessions?

I can find a use for all of these apps but the highlights for me are Mind Node ProBackup Pro, EspionageShareTool and Toast 10 Titanium in that order. The offer expires in 9 days from the time of writing so don't wait too long.

Tuesday, September 7, 2010

Steve Jobs zapped my iPod icon

My old iPod used to appear as an icon, like a USB drive, on my desktop when I plugged it into my MacBook which allowed me to eject the thing irrespective of which space I was in by simply going to the desktop selecting the thing and hitting [CMD] + [E]. When Apple removed that feature it annoyed me somewhat since I now had to switch spaces, find the iTunes window, locate the iPod (or iPhone these days) and eject it. I wasn't too fond of the idea of using one of those menu applets (although there are some nice ones) so I finally got around to creating a little application that ejects the iPod.

Fire up the AppleScript Editor:




Copy the following code into the edit window:

1:  tell application "iTunes"  
2:      repeat with s in sources  
3:          if (kind of s is iPod) then eject s  
4:      end repeat  
5:  end tell  

Save the script with the following settings:


Finally let's change the default icon, the easiest way to achieve this is to click the "Bundle Contents" button in the upper right corner. Delete the applet.icns icon using the right click menu, drag and drop the Eject iPod.icns file (which you can download here) into the "Bundle Contents" pane and rename it to applet.icns. Finally save the AppleScript app again. I like to keep this thing in the dock although I ususally prefer to run it through Spotlight which is the reason I created this app in the first place. Quick and easy. If you are lazy you can also download this crappy little app here.

Friday, June 11, 2010

Integrating Doxygen with Xcode

I recenty went looking for a good tool to document my Cocoa project and quickly found out that there seem to be two widely used documentation generators for Objective C:
  • HeaderDoc - A Documentation utility maintained by Apple.
  • Doxygen - A widely used open source document generator.
I decided to go with Doxygen both because It seems to have more features than HeaderDoc and because I have used it in the past. Xcode does not have support for Doxygen out of the box which means one is in for a tedious setup procedure. There is a tutorial on Apple's developer site which takes you through a few different ways of using Doxygen to generate documentation with Xcode ranging from using Doxygen's external GUI tool fully integrating Doxygen with Xcode using docsets. I decided that I wanted full integration since this allows you to right click on your own classes and select "Find Text in Documentation".

Unfortunately there are a few problems with Apple's tutorial. Firstly, the Run-Script they provide fails if you have a space in your project name or any of the file system paths you are using. Secondly, I didn't like the way the script configures Doxygen. Thirdly, the script in Apple's tutorial simply appends lines to the Doxygen configuration file which means those lines are duplicated in the file.

Step 1. Installing Doxygen
There are two ways to instally Doxygen. You can either install the Doxygen GUI application for OS X or you can also compile Doxygen from source. Binaries, sources and compile instructions are available on the Doxygen the project downloadpage.

Step 2 - Xcode integration
Once you have installed Doxygen on your Mac you have to configure Xcode. There are a few tasks you must perform:
  1. Create a new Xcode Target and an associated Run-Script item which you’ll use to trigger document generation.
  2. Add a couple of User-Defined Settings (a couple of environmental variables the shell script embedded  in the Run-Script item will read).
  3. Install the script text into the Run-Script item.
  4. Modify the Doxygen configuration options in the script.

Step 2.1 - The Run-Script
I rewrote the script from Apples website so that it can now handle spaces in directory paths. It also uses sed for substitution rather than appending lines to the script. You must donwload the script before proceeding.
Once you have dowlnoaded the script you have to create a new Xcode target. Unfold the “Targets” item in the Xcode project navigator, right click it and select “Add > New Target...”.


In the “New Target” window select “Other” and “Shell Script Target” and click “Next”. This should take you to a new window. Name the target “Generate Docs” and click Finish.

You could also have created this Run-Script item under the Xcode Target that builds your application. This has the advantage that the documentation gets built every time you build your app. There are two downsides to this approach:
  1. It can take a long time to generate the documentation and rebuilding it every time you build the app is unnecessary and lengthens your build time even when you didn’t modify your Doxygen comments.
  2. For some reason it is sometimes necessary to restart Xcode before it becomes completely aware of the new docset. You can still activate the docset and browse it in the Xcode documentation browser but the search function may not work optimally.
By putting the documentation generation in a separate target you can re-build your docset only when necessary by selecting the correct target from the  drop down box at the top of the main Xcode window and pressing the Build button.





Step 2.2 - Create User-Defined Settings
When you closed the “New Target” wizard Xcode should have taken you to the “Target ‘Generate Docs’ Info” window. If it didn’t you can right click on you new Xcode Target and select “Get Info”. In the Info window select the “Build” tab and add a couple of new User-Defined setting using the drop down box in the lower left corner of the window.


Create the following User-Defined Settings:
  • DOXYGEN_DOCSET_BUNDLE_ID - This will become the name of the docset bundle, for example like a java style package name: 'com.yourorganization.yourproduct'.
  • DOXYGEN_PATH - This setting points the script to the location of the Doxygen command-line binary. Binary install locations are:
    • If you downloaded the Doxygen GUI app: /Applications/Doxygen.app/Contents/Resources/doxygen
    • If you build Doxygen from Source: /usr/local/bin/doxygen
Once you have created the setting close the Info window.


Step 2.3 - Script installation
Expand the “Generate Docs” target you just created, right click it and select “Get Info”.  Now open the script you downloaded above, highlight it and copy the script text and paste it into the script field in the Info window.

Step 2.4 - Modify Doxygen settings in the script
The settings in my version of this script are a bit different from the ones in the script provided by Apple which pretty much uses the default Doxygen configuration and which does not behave the way I want it to. With the default settings Doxygen will document methods that I want to keep hidden from the user. So far the only way I have discovered to change this behaviour is to make sure that the following Doxygen configuration options are set as follows:
  • EXTRACT_ALL = NO
  • HIDE_UNDOC_MEMBERS  = YES
  • HIDE_UNDOC_CLASSES     = YES

This causes Doxygen to hide all classes, methodd and other constructs that are not explicitly documented with comments. This also forces the user to explicitly comment/document all classes, methods and other constructs that he wants included in the docset.

Changing these settings as follows:
  • EXTRACT_ALL = NO
  • HIDE_UNDOC_MEMBERS  = NO
  • HIDE_UNDOC_CLASSES     = NO
Will cause Doxygen to include undocumented constructs but it will include methods in private interfaces which forces the user to explicitly instruct Doxygen to ignore them using the @cond command.

Setting EXTRACT_ALL = NO will cause  the settings for HIDE_UNDOC_MEMBERS and HIDE_UNDOC_CLASSES to be ignored and causes Doxygen to include absolutely everything in the docset it produces. This includes summaries for *.m files but excluding  private and static file members.


There are a few more interesting configuration options:
  • REPEAT_BRIEF = YES - Repeat @brief descriptions in the extended class and method descriptions.
  • JAVADOC_AUTOBRIEF = YES - Insert @brief descriptions into the class member list at the top of each class reference page.
  • INLINE_INHERITED_MEMB = YES - Causes inherited methods to be included in the class reference pages for child classes.
For more information on Doxygen configuration options see here.

Quirks
In conclusion I thought I’d include a few Doxygen quirks that I discovered while using this setup.

  • If you use HeaderDoc style comments (/*! comment */) the body of the comment will be assumed to be an extended description, if you use Doxygen/Javadoc style tags (/** comment */) the body of the comment will is assumed to be a @brief description. This means that if JAVADOC_AUTOBRIEF = YES, REPEAT_BRIEF = NO and you are using Doxygen style comments the method description is only inserted into the javadoc autobrief list. To get the brief in both places set YES, REPEAT_BRIEF = YES.
  • Doxygen puts documentation for #define clauses into the header file description. If you set EXTRACT_ALL = NO you will find that header file documentation is only generated if you insert the following Doxygen commands into the header file: 

                 /** @file FooClass.h
                       @brief testing defines
                        This is to test the documentation of defines.
                  */

                  @interface FooClass : NSObject{
                        double barVar;
                  }

                  /** @def KSGL_VECTOR_CLOCKW
                        @brief clockwise rotation.
                  */
                  #define SOME_DEFINE 1