Everytime I Think About You I Multitouch My Cell

February 28, 2008

multiclutch.jpgAfter apologizing for the title of this post, I am happy to announce the release of a new app which I am calling MultiClutch. It’s a beta, though it has been in testing privately since the first week I got my Macbook Air and put it together. In honor of the new multitouch-equipped Macbook Pros, I’m going to make it public in hopes that others will find it useful. Basically, MultiClutch allows you to assign custom keyboard shortcuts in a given app to a given gesture. Want swipes to change tabs in Safari? Done. The same in iChat? Done. Want zoom-in to open emails in Mail, zoom-out to close windows in every app, and a swipe down to bring up Quicksilver? Done done done.

MultiClutch works by installing a simple input manager that will catch a gesture events, looks to see what shortcut you’ve defined for it in the frontmost app (if you haven’t defined anything, it behaves in the standard manner), and performs that shortcut. You use a System Preference Pane to customize gestures with an interface similar to the shortcut-customization table in the Keyboard & Mouse pane. You can ‘bind’ gestures in a given Cocoa app (due to the nature of input managers, Carbon apps are not supported) or globally. In addition to zooming in and out, and rotaing in either direction, and the four swipe directions, I’ve been experimenting with ‘combo’ gestures. Right now, I’ve added the ‘zoom in, zoom out’ gesture (i.e., in one fluid motion) and vice-versa, with more perhaps to come if I find them to be intuitive and useful enough.

This app is currently in beta, so it should go without saying that you should use it at your own risk and have a backup before you install it. That being said, I and several other testers have been running the app smoothly on our systems for quite some time, and MultiClutch is very careful to be safe in the way that it supports gestures. Please get back to me with feedback if you have ideas or run into issues.

If you’d like to donate to help support the time I took developing MultiClutch (which was not insignificant), you may do so by following this Paypal link.

Download Multiclutch [255kb]
Dig this!
Use this app on iusethis

Update: There was a rare issue where binding certain key combinations could cause the preference pane to hang. A new beta fixing this issue is up and it is a recommended upgrade. MultiClutch will prompt you to install the new input manager when you install the preference pane.

Update 2: Fixed donation link =).

Note: Multiclutch uses a modified version of a bit code from shortcutrecorder to help display custom shortcuts to the user, and I thank those developers for their hard work in the frustrating area of converting keycodes to characters.


iPhone SDK Revisited

January 27, 2008

icon_iphonewebapp.pngI recently tried out Google’s new iPhone apps, and the gap between them and Apple’s native counterparts has grown smaller. I’m both a web developer and a Cocoa developer, and when Jobs got on stage this summer and told me I could write web apps for the iPhone, I was more than a little downtrodden. However, the more I think about it, the more it seems that web apps really are the way forward on the iPhone. Here are three key reasons:

  1. Ubiquitous data. This is obvious but cannot be overemphasized. Synching is the way of the past. The iPhone is great for making computing truly ubiquitous. The fact that our data is not seems almost an anachronism.
  2. Synching is constrictive. Not only does syncing suck for tying you down, but its harder and more closed as a technology. Say Apple comes up with an SDK that allows developers to sync arbitrary data from Macs (and PCs!) to their iPhone – this would be truly impressive. Yet even in this best-case scenario, developers would then have to write an iPhone client AND (presumably) a Mac/PC client to sync via.
  3. Cocoa programmers are hard to come by. It will be a lot harder for Apple to take over the smartphone market if its apps are difficult to write and require rather specialized knowledge of a huge framework and rather obscure (but awesome) language. Everybody, on the other hand, knows AJAX.

icon_safarimobile.pngNow, you might object to reasons 1 and 2 on grounds that perhaps Apple will allow apps to transmit data via the EDGE/WiFi connect and syncing could thus be done in that manner. We’ll see. And yet this seems like reinventing the wheel to me. What I’d really like to see, and what I think would be easier and more fruitful in the long run (much as I hate to say it as a dedicated Cocoa programmer thrilled at running Mac OS X in my pocket) is Apple’s SDK turning out to be a much deeper and more thorough implementation of the things they released last summer. For example, a Google-Gears (update: thanks to an astute reader for reminding me about this) type component for allowing offline access and better application responsiveness. In addition, it’d have better integration with some of the phone’s unique features (special javascript functions for detecting and handling multi-touch input springs to mind). Of course, those alone are some serious hurdles – its likely that javascript support on the phone would have to be greatly improved to achieve this, etc. Nevertheless, some of the much more difficult issues (as it seems to me) like distribution, syncing, and security would be trivialized. Perhaps we’ll see something akin to this when the SDK announcement happens. Perhaps it will be a Cocoa-based SDK after all. Perhaps both (I’d love that). Whatever the case, I’ve changed my tune on what I think would be the best single solution, and now I’m hoping Apple’s agrees. Their recent introduction of Webclips gives me hope – they’re giving developers the tools they need to close the gap between web app and native app. On the other hand, revisiting the WWDC keynote doesn’t give me an inkling of faith that Apple had such revolutionary plans: it just seemed like they didn’t have an SDK ready. Time will tell, but I for one won’t be among the moaners if it ends up being a (solid) extension to the web apps strategy.


setDoubleAction with Editable Cells in Leopard

December 19, 2007

If you set an NSTableView’s double action in Tiger or earlier by something like:

	[tasksTable setTarget:self];
	[myTable setDoubleAction:@selector(doDoubleClick:)];

doDoubleClick would only get fired for clicks on blank cells, headers, or uneditable cells. The documentation still reflects this. In Leopard, this is no longer the case: doDoubleClick gets called no matter what. If you want the old behavoir – that is, if you want the cells to receive the edit action, you must do it manually. Clickedrow is -1 for headers and empty cells. Thus, the code would look something like:

- (IBAction)doDoubleClick:(id)sender {
	if([sender clickedRow] == -1){
		//your special action goes here
	}
	else {
		[myTable editColumn:[sender clickedColumn]
				row:[sender clickedRow]
				withEvent:nil select:YES];
	}
}

Hope this helps somebody scratching their head with the same issue!


TaskView Application And Working with CalCalendarStore

December 18, 2007
picture-11.jpg

I’ve been really excited about some of the new features in Leopard and the Calendar Server is a big one. To try it out, I’m writing a simple GTD-inspired task manager that interacts with the calendar server so that events are pulled and pushed dynamically to and from the server. The idea here is an app that takes just the data from iCal’s todos and puts it into a view that is more GTD friendly. The benefits are that you never have to sync and all of your information is always in iCal (thus, it works great with iPhones, Blackberries, etc). On the other hand, you are limited to storing information that iCal tasks already have (see my implementation for Projects below).

I’m using Calendars for Contexts so any calendar with begining with an @ symbol will be picked up and treated as a context. The @Inbox calendar gets a special icon, and in the future I’ll be letting you set icons for different calendars and perhaps customize the Context tolken (ie ‘@’). If you really want custom icons now, open the resource bundle. You’ll see a file named @Inbox.png. If you drop another image in there – say named @Work.png – then your @Work calendar will get the image.

The eventual plan is to make the tasks viewable as projects in an hierachal (outline) view with clever delimiters in the task names to save state in. Thus, a project for mail a package might look something like this when you are viewing it in ical

1! Mail Package
1* Get Stamps
1* Find a box
1* Go to the post office

This later feature for project is not yet implemented, and I’d love some feedback if you have a better idea of how I might structure the delimter syntax for Projects. The goals would be that it is clear and obvious, and that it displays in the right order when tasks are sorted by name in iCal (I’m not sure what most phones use as a sort ordering, but i’d be good to obey that too!).
In the meantime, I thought I’d go along a post the app and the code, which might be helpful to people trying to understand the basics of interacting with the calendar server. Keep in mind that this code is UNFINISHED, has not been well tested, and MANIPULATES ITEMS IN THE CALENDAR SERVER. It should go without saying that you need to backup your iCal files if you want to try this app. Also, it requires OS 10.5, whence the Calendar server was introduced.
[Download the App]
[Download the Source Code]

How interacting with CalCalendarStore works:
About all that Tasks Controller class does is set a sort descriptor for the tasks and do the initial grab of the calendars from the server, telling each resulting context to initialize itself using the calendar. The Task and Project controllers are currently unimplemented. The Context class is where most of the magic happens.
In Context’s initializer, you’ll notice two things. First, we add the context class as an observer of changes to its ‘theTasks’ array. Because we are using Cocoa Bindings to handle adding and removing of tasks in the UI, we need to observe changes to the array so that when they happen, we can push them to the Calendar server. More on that below.

[self addObserver:self forKeyPath:@"theTasks"
			  options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
			  context:NULL];

Additionally, we want to observe changes to the tasks themselves, which is why when we add them to theTasks, we also call addTaskAsObserver on them, which adds observers of the tasks’s ‘iscompleted’, ‘title’, and ‘datestamp’ properties.

-(void) addTaskAsObserver:(CalTask *)task {
	[task addObserver:self forKeyPath:@"isCompleted"
			  options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
			  context:NULL];
	[task addObserver:self forKeyPath:@"title"
			  options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
			  context:NULL];
	[task addObserver:self forKeyPath:@"dateStamp"
			  options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
			  context:NULL];
}

Going the other way, we just register with the notification center to receive updates when the external calendar store changes. When that happens, we call the method updateTasks.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateTasks:)
												 name:CalTasksChangedExternallyNotification object:[CalCalendarStore defaultCalendarStore]];

The first thing to note in the updateTasks method is that it removes itself as an observer of changes to theTasks at the begining of the block and adds itself again at the end. This is to prevent an inifinite loop of notifications that would happen if theTasks was trying to save back to the server the updates we are about to do to it.
We look at the three types of possible updates: added tasks, deleted tasks, and removing tasks. This code is based on the example code in Simple Calendar, which is a good resource for learning about the Calendar server, although the code seems a bit dated. For example, our code for adding task objects when there are new tasks on the calendar server (note that the addTask method below calls addTaskAsObserver on the new task!):

 NSArray *insertedTasks = [[notification userInfo] valueForKey:CalInsertedRecordsKey];
    if (insertedTasks){
		for(NSString *uid in insertedTasks) {
			CalTask *task = [[CalCalendarStore defaultCalendarStore] taskWithUID:uid];
			if([task.calendar.title isEqualToString:self.title]) {
				[self addTask:task];
			}
		}
    }

The other big chunk of code is implementing observeValueForKeyPath, which is called when the things we observed above change (ie the user makes a change in the UI to theTasks or its tasks). Again, we need to avoid an infite loop, so it temporarily halts change notifications from the server that we are about to save to. The object that is changed and thus received by observeValueForKeyPath can be of two types: CalTask or Context – the former if the user changed a task’s properties, and the latter if they added or removed a task to theTask. We check to see which one is the case and then do the appropriate thing. For example, if the object is a CalTask, do something like:

if ([[CalCalendarStore defaultCalendarStore] saveTask:[object copy] error:&taskSavingError] == NO){
			NSAlert *alertPanel = [NSAlert alertWithError:taskSavingError];
			(void) [alertPanel runModal];
		}

The other case is a little trickier, but it is self-explanitory and I won’t post it here.

All in all, its not too hard to interact with the Calendar Server, and I expect there will be a lot of really great apps that result from this awesome new feature in Leopard. Please post comments, questions, bug reports or ideas!

Update: A little bug fix in the code and above explination. dueDate saving was turned off and when I turned it on I was getting infinite calls of observeValueForKeyPath. Why? It turns out that saveTask does not make a copy of the object getting passed, so when the dueDate was getting validated by iCal it was causing the original object to get updated, which then got revalidated by the bindings NSDateFormatter, ad infinitum! The new code properly saves dueDates, and saves a copy of the task instead of the original to prevent the original from being edited by iCal. I’ve updated by example code above to reflect this, and posted new versions of the code and app.


Code Posting in WordPress (with Marsedit), Recap

December 12, 2007

Picture 1.jpg
So I had a brief issue with a previous post after migrating to wordpress – it converted all my quotes to fancy quotes and thus made the code unpasteworthy. My first reaction was to hard code all the quotes and that did work, but a little more research reveal that wordpress.com now has built-in source code displaying (including syntax highlighting) via the sourcecode tag. Using Marsedit, you can define a macro that does it all for you, as follows:
Opening Tag:


Closing Tag:

Here’s how some Ruby code might look:

def extended_euclid(a,b)
  x,y,r,m = a, b, a % b, Matrix.identity(2)
  while r > 0
    q = (x/y).to_i
    x,y,r,m = y, r, y % r, m * Matrix[[0,1],[1,-1 * q]]
  end
  return [y,m]
end

Preview.app now supports auto-reloading!

November 6, 2007

Nice new feature in Leopard I haven’t seen mentioned anywhere: Preview.app now supports auto-reloading for PDF’s. This is great for anyone that uses LaTex, and it just might make TextMate-Latex Bundle-Preview.app the ultimate Texing enviornment.


Still no leopard

October 28, 2007

While Apple has finally shared the GM build with its premier and select members as of yesterday evening (days after some consumers received it and the build leaked to the internets, and a week after journalists), student members will be waiting about a week to receive it in the mail. I wonder why they couldn’t allow us to download it now? I’ve been itching to install for months, and while student membership is a great deal, it sucks that its members – who are among the most enthusiastic users – have to wait the longest. Ah well. Anyone care to tell me if my software still works? On a side note, the PDX launch party was litterally swarmed with iphone-toting Mac nerds. Kind of a scary sight, but heart-warming all the same.


Why Mail.app is NOT your main workflow GTD app

May 6, 2007

485820115_ea8dced3a9_mSo I’m a big fan of using Mailtags to organize, tag, and archive my email, as well as to make events and todo’s out of my emails easily. I used to think that Mail.app would eventually be my central place for collecting, processing and executing a GTD workflow. However, I’ve been using a number of other GTD-sepcific apps (ie actiontastic, iGTD, etc., etc.) lately, and there are a number of reasons I now think that Mail.app is no substitute for them:

1. It doesn’t have the features of a GTD workflow app- ie a processing mode, the ability to view things by project or context, etc.
2. It shouldn’t have the features of a GTD app. Using Mail.app as a GTD processor forces you to either have multiple such apps (and nothing is worse than trying to manage your projects and actions across multiple apps!) or to try to shoe-horn all your other stuff into Mail.app (ie using NoteToSelf). Neither of these is ideal.
3. It has too many other features. One of the really beautiful things about a program like actiontastic is its utter simplicity. It allows you to focus on collecting you actions, organizing them, and finding the next one to do. Then it gets out of the way when you actually go and do things. Mail.app has other features that get in the way when you are processing your actions, and if you use it for GTD then you may find your GTD system getting in the way when you are trying to actually get things done. A case in point is the fact that Mail.app is an email client, as so as long as it is open, it is a potential source for distraction. I don’t want to have to have it open when I am trying to focus on getting a project done – it’d rather have another app sitting quietly in the background, bringing it up for the sole purpose of finding the next action, and opening Mail.app a couple times a day to fetch mail and burn through my inbox.

So what do I propose instead?
Certainly Mail.app is a valid inbox – that’s undeniable. Using Mailtags, its even possible to process things in Mail.app by tagging them and making them into todo’s, although I will bring up an alternative below. So here is an idea of a workflow:
Open Mail.app with the intention of fetching your email and processing your inbox to empty. If the email you are processing is an event, send it to iCal using Mailtags, and if its a task send it to your task inbox by making it into todos. Then tag the message and archive it. Done.
Actiontastic and any of the other utilities will automatically pick them up when they sync with iCal. Here you have a choice:485831505_0b4313faa9_m when you are making a todo in Mail.app, you could give you email a project by tagging it with one, and a context by associating it with a calendar, or you can just associate it with @inbox and process it later when you process your inbox in actiontastic. Personally I opt for the later, since I’d rather be making the simple decision: “is it actionable?” than the more complex one of where to do it, what project it goes under, etc. I worry about those things when I’m in my dedicated GTD app. On the other hand you might want to be able to search by project in Mail.app, so that a good reason to do it there (I can’t think of any reason to search by context in Mail.app though).
I’m not knocking Mail.app. Its a great program, great as an inbox (I mean, that’s one of its core functions) and fantastic for archiving (esp with Mailtags/Mail-act-on). You can always search via Spotlight and this is sweet – all your different archiving apps – Yojombo, Eaglefiler, various documents scattered on your hard drive, old events in iCal (note that I don’t think any of these are worth trying to shoehorn into a GTD system either – use them for what they are good at!) are all searchable in one place. That’s great. One of the point of getting your GTD workflow out of Mail.app is so that it can all in one place too.


Meditation Timer Source Code

April 3, 2007

As I promised, though certainly a bit late, I am releasing Meditation Timer’s source code today. You can use the code for anything you like; I suspect that the code for exporting to the iTunes may be particularly interesting to some. Please let me know if you have any questions, or you do something cool with it! [Download Source Code: 1.0MB]


Marsedit Finds a New Home

February 22, 2007

Congratulations to Daniel Jalkut on his recent acquisition of Marsedit. I can’t wait to see what he does with it. Maybe soon I’ll be titling my posts with it =)