Joris Kluivers

I like to build software.

Automator Command Line Utility Bug?

OS X comes with a commant line utility, /usr/bin/automator to execute Automator workflows from the command line. This is what man automator has to say:
NAME
automator -- runs an Automator workflow

SYNOPSIS
automator document

DESCRIPTION
automator runs the specified workflow document. To create or edit a
workflow, use the Automator application. There are no options.

Not very usefull. All we know now is how to specify which workflow we want to be run, no information on how to add input to the workflow, like a list of url’s or a list of files.

I created a simple test workflow that display’s two confirmation boxes. When the first one is dismissed with a negative response, the second one shouldn’t appear. This works fine in Automator, when run I am presented with a dialog, when I click OK I get to see the second dialog. But when I run the workflow using /usr/bin/automator I never see the second dialog.

Some research using strings /usr/bin/automator reveals the presence of applicationShouldTerminateAfterLastWindowClosed: So perhaps this selector causes /usr/bin/automator to terminate after a dialog is closed, even before the Automator action is completed succesfully.

Interface Builder and Custom NSViews

My previous post was about JKDistributedView, my custom layout view I use in one of my applications. In my layout code I loop thru all subviews added in Interface Builder to calculate their sizes. I still don’t know why but today an error occured that wasn’t there before. The initial layout was totally messed up and instead of three views layed out vertically some random gaps seemed to appear between the views. It appeared JKDistributedView didn’t have three subviews like I added in Interface Builder but it had four subviews. And even stranger, on the next layout the fourth unknown subview was gone all the sudden. After some debugging I found out what this fourth subview was.

Loading Resources: What Happens When a Nib File is Loaded
When you drag a standard object into the design window, Interface Builder encodes the actual class for that object, initializing the object as it builds the nib file. For custom subclasses of such objects, Interface Builder encodes the standard object but tells the archiver to swap in your custom class when the object is unarchived. These objects are also initialized when the nib file is built. Therefore, when the nib file is loaded, initWithFrame: is not called for either standard objects or custom subclasses of standard objects.

On the other hand, because the actual code for your subclass of NSView is not resident in Interface Builder, it does not encode the actual subclass when you drag a custom view object into the design window. Instead, it encodes a special object called NSCustomView that knows how to build the real custom view subclass. After NSCustomView has been instantiated by initWithCoder:, it calls alloc and initWithFrame: for the real class, and swaps in the real instance.

So when your nib file contains a subclass of NSView this class will be initiated using initWithFrame: by a NSCustomView instance that was saved in the nib file as a temporary replacement for your custom NSView.

Normally you shouldn’t need to worry about NSCustomView but JKDistributedView contained a custom view and my layout code was performed before the temporary NSCustomView for this custom view had the time to clean up itself. The NSCustomView was layed out like all other subviews causing an empty space to appear. This was easily fixed by skipping all NSCustomView instances in the layout code:
if ([subview isKindOfClass:NSClassFromString(@"NSCustomView")]) { 
continue; /* skip this loop */
}

JKDistributedView

While trying to duplicate the RuleView used by Apple in the Finder for example I ran into the problem of resizing views. The RuleView needs to grow in size when a new rule is added. Each view following the RuleView needs to be resized to to create space for the RuleView. Since layout in InterfaceBuilder works using springs, but you can’t attach two edges of view together, I created a helper view called JKDistributedView which helps me resize and reposition it’s children views.



To use JKDistributedView you add a NSView subclass to Interface Builder and set it’s custom class to JKDistributedView. Every nsview added to JKDistributedView will be layout according to the following rules:
  • top to bottom
  • Every view will get it’s preferred height
  • When a views vertical springs are dynamic the view will fill all remaining vertical space after the fixed height views are sized.
When a rule is added to the JKRuleView it needs to grow in size. JKRuleView calls descendantFrameChanged: on it’s parent view (JKDistributedView) to indicate all children of JKDistributedView need to be resized and repositioned.

So the finder smart folder view would be created using 3 views as subviews in a JKDistributedView. The JKRuleView, the NSOutlineView (using a dynamic vertical resize hint) and a third view at the bottom to display the path of the selected file. JKDistributedView makes sure the JKRuleView and the path view have a fixed size, the NSOutlineView will fill all space in between. Now when you click the add button in the JKRuleView a new rule will be added, JKDistributedView will increase JKRuleViews height and decrease the height of the NSOutlineView

Cocoa UI Spit & Polish

When playing with Interface Builder to create a UI for my application I sometimes run into the problem of trying to recreate a visual element used in Apple software. There are a lot of buttons and gradients used repeatedly in several Apple applications. When adding buttons with similar functionality I try to use the same artwork Apple uses for consistency.

The problem is that most of the buttons for example are custom designed by Apple and are not available by drag-n-drop in Interface builder.

So here is a collection of some images and custom classes that can be used for free in you application to add the spit and polish that makes your application look like a real Apple application. (Be sure to read the licenses for the specifics on copyrights).

An effort to give developers guidelines for replicated Apple interface elements was started under the name IndieHIG:
The IndieHIG Wiki is a place where developers and UI designers can come together to create a new set of Human Interface Guidelines to supplement Appleā€™s guidelines. Apple has neglected to update their HIG with modern UI designs and controls, so developers have been forced to replicate these UI elements on their own to keep their applications from looking dated. Since each developer has slightly different implementations of these elements, it has resulted in a fairly inconsistent look and feel for Mac OS users.

Maybe it’s an idea to provide implementations of interface elements that follow these guidelines? For example the Polished Metal page describes the properties of a currect Polished window, for wich an implementation already exists in the form of TunesWindow.

I’m currently working on an implementation of a RuleEditor as used by the Finder to create smart folders:



When finished I’ll document the properties of a rule editor in the IndieHIG and publish the sources of this class.

Comments

Romain
Hi,

I would like to mention a similar open source project I am working on.

http://code.google.com/p/ruleeditor/

There is an example with NSTextField as the right expression but it virtually supports any control (stepper, date-picker ..) via the delegate object.
Mark Stultz
I’m still tackling the same type of thing. My rules need to support external plug-ins. These can add more entries to the popup lists, as well as other control inputs (additional popups, textfields, steppers, date-pickers, etc).

I need to dedicate some more thought on this, but I did decide against using the NSTableViews. I don’t believe the live-resize handles the way I want it do.
Joris Kluivers
I’m currently using my own NSView subclass, and another NSCell subclass that draws the rules and buttons within the rules. Probably not the best way to approach this, because I miss out on some functionality provided by NSTableView, but it does work.

I’m still strugling with the data structures for the rules created by the rule view. Any thoughts on how to handle this? I’m currently using a delegate for example that provides the searchable properties (nsarray of strings) that goes into the first popup.
Mark Stultz
I guess I should have stated the question was in reference to your Rule Editor.

I’m in the process of creating one. I’ve seen some implementations with table views, and so I’m curious if you are also purusing this route.
Mark Stultz
are you using a nstableview for this?

XCode Todo List

One of the things I use in TextMate regularly is the apple-cmd-b key combo, to bring up a todo list for the current project. Whenever I have something planned in my code, but don’t feel like implementing it yet I annotate this piece of code with a comment like:

1
2
// TODO: check if url exists before saving it
saveURL(url);

The todo plugin will list all these TODO’s from my code which gives me an indication on how to improve my code further.

The problem is that while I use TextMate for my web and java programming, I use XCode for most of the real programming done using Objective-C/Cocoa. But XCode doesn’t have the todo feature and there is no way to add plugin’s to XCode. Even a google search resulted in nothing on the subject.

So for now I’m using the Lightweight issue tracking bash script I found which seems like the only solution usable in combination with XCode.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# grep for "TODO" string
todo()
{
  if [ $# -lt 1 ]; then
      grep -R -n "TODO: " . | grep -v ".svn"
  else
      # loop through the args
      while [ -n "$1" ]
      do
        grep -R -n "TODO: " "$1" | grep -v ".svn"
        shift
      done
  fi
}

Add this script to your ~/.bash_profile to be able to execute the todo command that searches the current directory, or the directories given as argument for // TODO: lines.

XCode Animations - Core Graphics

XCode Animations - Core Graphics:
Ever wanted to be able to use fancy transitions and animations in your Xcode applications? This tutorial provides the method and the means to implement terrific flips and ripples throughout your app, showing window transition effects using both undocumented and documented Objective-C code that can be implemented anywhere quickly and efficiently.


A small, quickly readable eBook that teaches the use of undocumented Core Graphics functionality. This certainly falls in the category of Undocumented Goodness and usage is therefore discouraged. That being said, if you would like to add effects like the ones used in applications like Quicksilver, Virtue Desktops and certain Apple applications I recommend you read this eBook.

Download (zip | pdf)

Comments

Joris Kluivers
@ansgar: BTW, DemoReel on your website is a great video!
Joris Kluivers
Thanks for the comment, just updated the links
Ansgar
thanx for the useful link, the URL for the .pdf was changed to
http://pub.lipidity.com/Xcode Animations.pdf

greets
ansgar

RubyOSA on Rails

As posted before, I’m currently playing with with Ruby on Rails a lot. While doing so I discover more and more about the beauty of Ruby programming on Mac OS X (with or without rails). For example using the Ruby/Objective-C bridge it’s possible to use any Cocoa Framework in a Ruby script. Even better, Apple seems to like Ruby and already made it clear Ruby on rails will be included in the next version of OS X.

So while searching for Ruby and OS X using google I found another useful gem: RubyOSA, a Ruby/AppleScript bridge. The bridge makes it possible to use any scriptable application as an object in your script.

The RubyOSA website gives a simple example of using Ruby to control iTunes. As an experiment I created a Rails application to do the same, but from a remote location. Not very useful on a live website because RubyOSA commands might take some time to execute. But combined with a wifi enabled phone or pda it results in a nice remote control for iTunes in a home network.

Ruby on Rails

About 2 weeks ago I started looking into Ruby on Rails. I’ve programmed using ruby before, and I installed a rails based blog before, but I never used rails to develop something myself. What I’ve seen so far really makes me think why I didn’t start using Ruby on Rails before.

All the tools that come with Rails really make development much more easier than what I’ve used before. The scripts used to generate models, migrations and controllers from templates take away the need to repeat yourself with the most basic code.

More interesting is the tool called Capistrano. I just started using Capistrano only two weeks ago, but already I’m sold. Gone are the problems of releasing a new version and having a different version online then the one I’m working on. Since using Capistrano releasing websites to the web has become way more organized.

The current setup I’m using for the live server is an apache2 installation with 3 mongrel servers running in a cluster for each Rails application.

I develop the Rails application on my powerbook and test it using mongrel installed using Locomotive. The Rails installation is of course stored in a subversion repository. As soon as I think the current development version is ready for a release (feature complete and the tests show no errors occur) I tell Capistrano to deploy. A few seconds later my new version is online without me ever starting a ftp application. The database tables are updated automatically, files are checked out from subversion and all I have to do is sit and watch. And if somehow my unit tests didn’t catch a bug, or something else has gone wrong, I’m back at the old version within 2 seconds. No more troubles with ftp, searching for the files that caused the error.

Because of all the information available on the internet you don’t need a book nowadays to start programming a new language or to start learning a new framework. I usually find using Google to find API documentation is much faster then browsing a book. Tutorials on the web are usually more updated and provide useful user feedback in the comments. That’s why you won’t find much books at my place about programming.

I do buy books on occasion that provide me with information not available on the web. That’s why I bought the book Rails Recipes. I read several positive reviews and after reading through the book myself I immediately felt like I would use it for each rails project. The book contains small ‘recipes’ usually not longer than 2 or 3 pages that provide snippets of code that show how an experienced Rails developer would solve a specific problem.




I own the book for two days now, and already I’ve learned more from it than from all the tutorials I’ve read. So if you know Rails already from the tutorials you’ve ready, but you’re looking for more interesting pieces of code to read and use check out Rails Recipes.

WWDC Videos (2)

As of a few days ago, around 70 sessions from WWDC 2005 and WWDC 2004 have been posted on iTunes under the Foundational Sessions. This obviously answers a question I got as a comment on my previous post about the WWDC Videos:
Any mention of sessions from previous WWDCs ending up on ADC on iTunes?

Let’s see what usefull resources Apple will post on iTunes after this.

More on SimilarTunes

Currently SimilarTunes is a very simple application to help you create playlists with somehow similar songs from your own library. After searching for an artist you set the similarity slider to the percentage of similarity of the songs and you create the playlist. To figure out how similar songs are, SimilarTunes uses several webservices like Last.fm and MusicMobs.

After posting this software on osx.iusethis.com, I received a few positive reactions. SimilarTunes was even mentioned on the MusicMobs weblog. I’m currently working on fixing one known problem: SimilarTunes only creates empty playlists for one user. I’m also working on some additional features, like adding the original artists searched for to the playlist.

Competition
There is some competition out there trying to reach the same goal, automatically create playlists with similar music:
While I use webservices based on social community input to determine similarity, most other software use properties like beat per minute count of a song to find similar music.

One particular interesting application is Tangerine recently introduced by Potion Factory. It’s the only mac application in the list. Like most others it analyzes the BPM count of a song but it really adds a innovative and delicious UI.