Blog

Mori v1.6.9 is Being Packaged for Release

This has taken much longer than I hoped for, and it lacks the features I wanted to add in there, but due to another empty-window bug I’m releasing Mori 1.6.9 today as a stopgap measure.

I had hoped for a quick release to get the fix out to those who are upgrading now (particularly from older, Hog Bay Software versions), but I had upgraded my Xcode installation mid-stream, which is generally a bad idea if you can’t test the effects a tool migration will have on your projects. And Mori is quite unique in the way it’s constructed, being almost entirely plugins, and plugins which run plugins.

It took a week to resolve unit testing problems, some of which were due to Mori’s unique project files, some of which were due to changes in the layout of Xcode’s tools directories and one due to a bug in the unit tests for the ‘Check and Repair Notebooks’ functionality (which I wasn’t going to risk going out with a bug whose cause I hadn’t determined).

Anyway, testing problems aside, I’m packaging the latest for release now. You’ll be able to read the release info shortly.

Solving a New Event Bug Present in iCal When Scripting

While trying to solve a user’s problem with an mGTD script, I came across a subtle issue that demonstrates some issues that arise when violating a programming philosophy, tackling bugs in other people’s code, and general uncertainty whenever coding in AppleScript.

Working with AppleScript is generally considered iffy, because a lot seems ambiguous and so much is dependent on how the dialect is interpreted and how scriptable apps handle some of the application events which scripting is dependent on. I’ve written scripts before, some I’m pretty awed by (that it works, actually, but also what it does), but I’m still hesitant to tackle some scripting issues. In addition, being a GTD greenhorn, and an mGTD noob made trying to respond to this issue authoritatively very questionable.

Thankfully, BMEGuy, mGTD’s author and all-around community nice guy, tackled the question with a quick solution. But the updated script was still problematic, and so I felt I really needed to participate in coming up with a solution.

Again, being an mGTD noob and all, it took me at least half an hour to figure out how the plugin worked, and the script on top of that. Then, after I was able to get the script to run, it worked for me. Hmm.

But that’s because I was testing with an entry with a date due of today. Once I switched it to later in the week, the entry was still showing up for today. Isn’t that odd? It seemed I had inadvertently left in the date line from the original script. When I removed it, I witnessed the same problem.

It turns out there’s a bug in MOX 10.4.11’s iCal 2.0.5 (I’m guessing it’s present in earlier versions as well) where it doesn’t properly update the calendar display for new events made by the script. You won’t see it in the monthly view. However, you might notice a little oddness in the weekly view.

You can see the event if you add ’show theEvent’ after the script makes a new display alarm for the event (between the 2nd and 3rd ‘end tell’ up from the bottom). This will display it’s properties in the info drawer, but you won’t see the event anywhere on the calendar (in either week or month view) until iCal is restarted.

Running the script in monthly view doesn’t show any artifact in the calendar, but the data is shown in the info drawer.

You could also run the script in the weekly view and then switch to the monthly view, in which case you get this:

So now that the question of the event’s presence in the calendar was settled in my mind, I had to figure out why my faulty script displayed the event, but not the proper one; and how to coax iCal to display it.

Being unfamiliar with mGTD still, I tried to figure out the difference between the attribute name “dateDue” and due datedue date is one of the standard properties for entries in a Mori document. attribute name “dateDue” is a user column added in the example mGTD notebook. You can view them all the user columns by selecting the menu item Edit > Edit Notebook Columns…

Okay, good so far, but why would one cause iCal to display properly and not the other? After moving the due date line about for a while, I checked Script Editor’s Event Log, and saw

The event reply for the due date had a missing value! Mori wasn’t returning a value for the due date property because it wasn’t set (and wouldn’t be in the example notebook). Now I had to find a way to use one of those missing values to make theEvent visible without setting it to the wrong date. And the problem with that is most of the properties used in Mori’s entries aren’t appropriate for an iCal event.

I eventually thought about re-ordering the messages to iCal instead of being so fixated on a change in the messages to Mori or playing with the properties being set in creating the event. What I came up with was a plan to use the messed up missing value date as before to make the event visible first, and then set the date correctly. The code turned out like this:

tell application "Mori"
	tell current entry
		set theDate to (get attribute name "dateDue")
		set faultyDate to due date
		set theName to name
		set theNote to note
	end tell
end tell
tell application "iCal"
	tell calendar "Scramble" -- the user should specify the name of the target calendar here
		set theEvent to make new event at end with properties {description:theNote, summary:theName, start date:faultyDate, allday event:true}
		tell theEvent
			make new display alarm at end with properties {trigger date:theDate}
		end tell
		-- show theEvent
		set theEvent's start date to theDate
	end tell
end tell

And to my surprise, it worked! So as I began gathering the materials together for my reply to the issue, I noticed something in the event’s info drawer that had escaped my attention before:

iCal, that’s just crazy talk! But at least it would explain why it would display traces of an event, if anything at all; and why it wasn’t noticeable earlier: iCal would correct the event data when reading it in when it started (”iCal database, that’s just crazy talk!”). But somebody forgot to add a sanity check when creating a new event from the properties passed to it by our script. (This is an example of why the Once and Only Once principle should be heeded. If there’s only one place where events are synthesized from pre-recorded values, whether those values are from a stored file, a script or the UI, then all those code paths will benefit from any sanity checks added to event creation.)

Knowing this, here’s another means of working around this bug, by sending iCal info that won’t confuse it:

tell application "Mori"
	tell current entry
		set theDate to (get attribute name "dateDue")
		-- set faultyDate to due date
		set theName to name
		set theNote to note
	end tell
end tell
tell application "iCal"
	tell calendar "Scramble" -- the user should specify the name of the target calendar here
		set theEvent to make new event at end with properties {description:theNote, summary:theName, start date:theDate, end date:(theDate + 1), allday event:true}
		tell theEvent
			make new display alarm at end with properties {trigger date:theDate}
		end tell
		-- show theEvent
		-- set theEvent's start date to theDate
	end tell
end tell

Thinking about these two solutions it’s clear that picking the latter one, with well-formed properties, is the safest choice to make. Here’s additional proof: the first solution, the one which plays with the start date to make the event appear, will indeed make the event appear. But if there’s less than 24 hours until the event begins, it will appear on the wrong date and still require iCal to be restarted to appear in the proper location!

It just goes to show you, while you might be able to get away with just the barest minimum, and someone else might normally clean up after you, it’s best if you did the job correctly from the start in case your safety net disappears from under you.

A Look (Back) at Mori’s Code

When I purchased Mori, one of the first things I did was generate some documents about its codebase. For this, the main tool I used was Xcode’s Class Model tool to generate charts of the various classes involved. I spent several days laying out the classes on the charts, then printing and then folding and taping the pages together. (This is a process which I am replacing with specific related classes that occupy only one or two pages, so I can keep them in a notebook; or sending a PDF to Kinko’s the next time I need to print the whole chart.) They helped me get an understanding of how code was laid out, and their relationships.

After a while, the tape that held the charts up on the wall would lose their adhesiveness and down they’d come…again and again, eventually falling into disuse. Having gotten a digital camera, I spent a day reassembling the crumpled remains of the charts about a week or so ago, and snapped a few shots which I present here.

There are 33 classes, and 25 protocols defined for the document back-end plugin, and quite a few supplementary category methods extending Cocoa’s foundation classes.

The user interface plugin has 85 classes, 18 protocols, and its own quantity of supplementary category methods.

At least, that’s what Mori’s classes looked like when the shots were taken. Today it looks a tad different.

Oneill, the branch for Mori 1.7 is under active development again and will bring substantial changes to the UI and back-end architecture. You shouldn’t notice any hiccups in the file format, but you should see better functionality and performance.

At least that’s what the testing support should help me do. Thankfully, I make heavy use of the Subversion SCM system. Just in case.

Double Vision in Xcode doesn’t Double Your Fun

The Mac developer scene is loaded with a lot of helpful and supportive developers out there, sharing ideas, code and encouragement with one another. I’ve benefitted from the development community, as have the Mori and Clockwork code. I say this not only as one who’s currently putting new code into them, but seeing the comments Jesse left in the code before me!

So I’d like to drop an idea into your lap you might find useful for the right type of application. As there are different types of software one can develop, e.g., operating systems, utilities, paint programs and the like, they have particular usage characteristics that they encourage. Some, like digital notebooks and desktop timers for example *cough*, tend to remain in operation while the user is logged into his account. Usually, this isn’t a problem for the user. Unless, of course, the user is also someone further developing said software. Then several questions have to be answered, such as, “How do I run unit tests on builds while still running a stable version of my app?” and “How do I try out the latest build without affecting the files which are currently open in my app?”

On operating systems based on more primitive process management, it isn’t troublesome because each built application is fairly independent of others, and often multiple invocations of a single app can be run concurrently. It wasn’t problematic on the Mac either back on MacOS 9 and earlier, and even in the early MOX releases. But now with Launch Services, running test versions of apps you run on an all-day basis can be problematic. It’s best to give that test version some different signature so its defaults and file changes don’t corrupt your normal environment.

Note that this tip doesn’t prevent two versions from munging the same files; even two unrelated apps can mess up a data file if they’re updating it at the same time. What this tip does is provide an alternate identity, if you will, for test builds so MOX doesn’t try to hand it the same data set it gives the release builds of your app. You mustn’t try to open files in the test build that are currently opened by a release build.

Here’s how I do it:

1. In the Info.plist file, use the C pre-processor’s conditional compilation directive to give your app its normal metadata when a release build is made, but a special set of metadata for all other build configurations:

#if defined(Release)
<key>CFBundleIdentifier</key>
<string>com.apokalypsesoftware.Mori</string>
#else
<key>CFBundleIdentifier</key>
<string>com.apokalypsesoftware.Mori-debug</string>
#endif

Update: I forgot to mention that Xcode 3 and later versions now use specialized editors for the Info.plist files. To override this editor selection, bring up the file’s Info window (by selecting the file and pressing cmd-I) or the Inspector window and change the File Typesetting from “text.plist.whatever” to “text”. Once you add the conditional to Info.plist you can change File Type back and access Info.plist in its raw form from its target’s Properties tab. That way, you can view it in either mode within Xcode. However, making any changes in Xcode’s plist editor will wipe out any conditional directive in the file, so use it only for reviewing current settings, not for actual editing!

2. In the Target Info window (brought up via the ‘Project > Edit Active Target “Mori”‘ menu item), select the Build tab, specify “All Configurations” for the Configuration pop-up menu, and enter “plist” in the search toolbar widget to bring up the relevant setting items.

3. For the “Info.plist Other Preprocessor Flags” setting, enter -traditional as the value. While not needed to support the test version twin, it will help to prevent any URLs included in the Info.plist from being swallowed up by the pre-processor and possibly causing you sleepless nights because neither MOX nor the Xcode build system have the slightest idea of what the proper format for URLs are, but will behave erratically when it isn’t just so. So it’s best to make it a non-issue from the start. (No charge for that and other tips related to usage of the pre-processor you can find in Technical Note TN2175. Incidentally, TN2175 says to use “-traditional”, but I use “-CC”. Use whatever works for the version you’re on.)

4. For the Info.plist Preprocessor Definitions setting, enter $(CONFIGURATION). Xcode will change the display to read <multiple values>, but that’s okay because the value will vary according to the current build configuration. It will define a value that matches the build configuration that the pre-processor will test against in the Info.plist. (Try switching the setting in the Configuration pop-up menu of the Build tab to watch the value change to match the current setting.) This is what will direct the pre-processor to output the correct value for CFBundleIdentifier.

5. Check the Preprocess Info.plist File checkbox so Xcode invokes the pre-processor on the Info.plist before copying it to the application.

When built, you’ll be able to run the app concurrently with the release version, and without causing conflicts with data files in use by it. Of course, you won’t have your preferences set up, but that’s only a problem until you save preferences for the test version. (Remember, if you try to get around that problem by copying the release version’s defaults file that it also holds the recently opened files. Purge, close or what-have-you as appropriate!)

One of the extra things I attempted to do in this technique was to provide an alternate name for the private builds or test versions so they would be distinctly named for testers. We used to use naming conventions such as “Mori 1.7β4″ when distributing such versions back in the pre-MOX days, but including the metadata keys CFBundleExecutableCFBundleName, and CFBundleDisplayName don’t have any noticeable effect. Any tips in this regard would be greatly welcomed.

I had also attempted to get the pre-processor to generate the bundle identifier with “Mori-$(CONFIGURATION)” that fit whatever build configuration was in effect automatically, which would’ve avoided the use of the #if defined directive. Unfortunately, because the macro expansion would generate Mori-Release that method proved ineffective.

A corresponding idea is to use an alternate icon (via the CFBundleIconFile specifier) to represent the test version of your app. It helps you and your testers realize when odd behavior is due to running the wrong build just by looking at the dock or application-switcher. It’s also fun to double-click a document only to realize the test app is opening vital data meant only for the stable version. Hilarity is sure to ensue. But I’m a professional, don’t you kids try this at home!

If you don’t have the construction guy handy, you can resort to the technique I used before I discovered Info.plist processing: MOX’s own stamping of missing dock files makes for a handy visual guide to your test app. To try it yourself, add the debug version from within your build/Debug folder to your dock items. That’s right, the debug version (or whatever you use for test builds). Now delete it and empty the trash. (You will be building new ones, won’t you?) Now click on the app icon you just added to the dock. It adds a big fat ‘?’ to your lovely icon, doesn’t it? (At least it should if you deleted the correct icon.) Now rebuild your app and run it from within Xcode.

Now bring up the application switcher (cmd-tab). What do you see? A big fat ol’ ‘?’ emblazoned on the debug version of your app! Oh, you don’t? You see the normal icon? Yeah, you’re on Leopard, aren’t you? This trick doesn’t work as well on Leopard because MOX validates the file state more often than Tiger did. Such as, starting the test build from the Dock instead of only within Xcode. On Leopard, clicking on the dock icon when there’s a built debug version of your app in the debug folder will restore its unstamped icon. But anytime the question mark goes away, just delete the debug version, empty the trash, and click on the dock icon again.

Have fun, and keep ‘em flying!

bitShifter Joins Apokalypse, Revamped/Pro Mori 1.7 Release Imminent, Cocoalogue: Our Smalltalk-based Scripting System, and a Cancer-Fighting Bundle

As you can see, another bevy of announcements all bunched up in one. Did you feel like it was time to unwind? Nope. Me neither!

First off, an announcement that I put off while other things had to be wrapped up: Apokalypse Software Corp. has acquired the rights and the code to bitShifter, the file encryption utility initially developed and marketed by MemSculpt and then ForgEdit. As with prior acquisitions, the current licensees’ purchases will be honored, updates will be made, etc. I’m still trying to understand what some of these licenses were (perpetual what, now?), but they won’t be problematic as the key is in gaining more licensees rather than bleeding the current userbase dry with the nickel-and-dime tactics I despise so much.

However, the name and logo will need to be changed, as the original developer cannot relinquish them…or something. (bitShifter is vague and ambiguous or too techie sounding, anyway.) It is being revamped, and will be re-launched shortly as an Apokalypse product. The price will likely remain $99 USD if I can figure out what type of license that bought. (Perpetual what, again?)

Now that Apokalypse has encryption technology, I’m putting Mori 1.7 out with encryption ASAP. Unfortunately, this means some of the really cool features I originally planned to incorporate in the release will be delayed until 1.8, including enumerated entries, and continuous text. What’s still in? LinkBack, customized labels, font settings for source & entry views, better keyboard navigation, outlining improvements, self-downloading updates, and now encryption.

I’ve also gone over the features of quite a few of Mori’s competitors, and realize how undervalued Mori is. So I’ll be creating a version with fewer capabilities at the current price to stay at the lower end, and the price of the full-featured version will be raised to $99.95 USD. On top of that, a Pro version will be released at $199.95 USD. Mori licensees will automatically be bumped up to the Pro license when the update is released; so as I promised you before, you won’t have to pay extra for the 1.7 upgrades. In fact, as I’m still planning to put out a 1.8 release, current licensees won’t have to pay for any 1.X upgrades.

Next on the list is the big project I had been working on when I purchased Mori and Clockwork from Jesse. It’s a programming system based on the Smalltalk programming language and it’s called Cocoalogue. What’s so special about it? It’s an interpretive system, with programs written in a shebang-prefixed text file like most scripting languages available on UNIX-like platforms. The Smalltalk-based syntax is virtually identical to Smalltalk-80 with extensions for declaring classes, methods and data types (with strong- and static-typing). It supports dynamic run-time features including blocks, automatic garbage-collection and data translation. And it has, as the name Cocoalogue would indicate, a bridge to Ma’s Cocoa frameworks. I’ll go into greater detail on these features and Cocoalogu’s current limitations in my next post. This product hasn’t been released yet, and will be priced at $129 when it is.

But I’m making the announcement now for a very good reason. You’ll be able to get a licensed copy of Cocoalogue today before it’s made available anywhere else, including the Apokalypse website, through the PMC Software Build Your Own Bundle program. Seth Dillingham, another indie Mac developer, has put together a special bundle where you can purchase Cocoalogue, Mori, Clockwork or a family pack at discounted prices. You could even get a discount on over 120 other fabulous programs from Mac indie developers as well! Not that you want to.

So go on to the bundle site, remembering that it’s the only way to get in on Cocoalogue now, and for the substantial savings you’ll get on Mori Pro 1.7 by getting a Mori license today.

And don’t forget: these sales are going to fund cancer research and treatment, so please don’t be stingy on what are already terrific deals. A lot of folks are counting on you!