Archive for June, 2010

June 26th, 2010  Posted at   AppleScript, OS X
   |   No Comments

My previous post described an AppleScript Folder Action I created to automatically rename a certain file on my Desktop. That script used a utility “library” (which is just another script with functions we can call). In this post I’ll elaborate on the utility library.

AppleScript provides the date and time via “current date”. set datetime to current date. That produces something like this: “Saturday, June 26, 2010 4:19:43 PM”. I wanted that formatted like this instead: “20100626_161943″ so I could use it as part of a filename.

So I created a function called datestamp(). datestamp() gets the current date and time and returns a string of the format YYYYMMDD_HHMMSS (where HH is 24 hour based). Within that datestamp() function I found myself needed to pad strings, such that month 4 becomes “04″. Thus, I created three utility functions to meet my needs.

Please note that I’m brand new to AppleScript. Surprisingly, I find the language very complicated and convoluted (probably because I’m new to it), despite the fact that I am comfortable doing real work in many other languages (Ruby, Java, Python, C/C++, and more). It’s quite possible that I have reinvented the wheel or otherwise done things the hard way because of my ignorance :) .

Here’s the full text of my utility library, named “mt_util_library.scpt”.

----------------------------------------------------------------
on repeatStr(s, cnt)
	-- Repeat a string s cnt times.
	-- repeatStr("*",4) -> "****"
	-- repatStr("12",3) -> "121212"
	set outStr to ""

	repeat cnt times
		set outStr to s & outStr
	end repeat

	return outStr
end repeatStr

----------------------------------------------------------------
on padIntStr(n, c, totalLen)
	-- Return an integer represented as a string, with leading spaces padded
	--   as necessary to make the string at least totalLen in length.
	-- n = the number to pad
	-- c = the character to pad with (usually "0")
	-- totalLen = the total length of the string when finished
	-- padIntStr(34,"0",4) -> "0034"

	set s to (n as string)

	if length of s < totalLen then
		-- FIXME: We probably should ensure that c is just one char...
		set padLen to totalLen - (length of s)
		set pad to repeatStr(c, padLen)
		set s to pad & s
	end if

	return s
end padIntStr

----------------------------------------------------------------
on datestamp()
	-- Return the current date and time as a string formatted like this:
	--   "YYYYMMDD_HHMMSS" -> "20100626_150537"

	-- Get the current datetime.
	set theDate to current date

	-- Get the year.
	set y to year of theDate

	-- Get the month.
	-- AppleScript only gives the month name, but it
	--   converts to a month number when cast as integer.
	set m to month of theDate
	set intM to (m as integer) -- Convert from month name to number.
	set strM to padIntStr(intM, "0", 2) -- zero-pad month number (04) = April

	-- Get the day.
	set d to day of theDate
	set strD to padIntStr(d, "0", 2) -- zero-pad it

	-- Get the time (in seconds since midnight... the only way it's offered :(  ).
	set t to time of theDate

	-- Calculate the hour.
	set h to round (t / 60 / 60 as real) rounding toward zero
	set strH to padIntStr(h, "0", 2) -- zero-pad it

	-- Calculate the minutes.
	set mins to round (((t / 60 / 60 as real) - h) * 60) rounding toward zero
	set strMins to padIntStr(mins, "0", 2) -- zero-pad it

	-- Calculate the seconds.
	set s to round (((((t / 60 / 60 as real) - h) * 60) - mins) * 60) rounding toward zero
	set strS to padIntStr(s, "0", 2) -- zero-pad it

	set datestamp to (y & strM & d & "_" & strH & strMins & strS as text)

	return datestamp
end datestamp

They are pretty much self-documented, so I’ll just note the purpose of each.
datestamp() creates a string with the date/time formatted as mentioned above.
padIntStr() takes an integer, pads it according to the length and using the character specified, then outputs a string.
repeatStr() takes a string (or character) and outputs a string consisting of the input repeated some number of times.

I’m sure this utility library will grow in time, assuming I do more AppleScript work. If so, future posts will show what’s new.

June 26th, 2010  Posted at   AppleScript, OS X
   |   1 Comment

In my last post I described my goal to make an auto-rename Folder Action for my Desktop folder, specifically for handing scan files generated by Image Capture.

Now it’s time to talk about the actual script that does the work. The script is called whenever new files are added to the Desktop folder. If the file to be renamed exists, the script does its work.

First activity is to get the date and time and format them into a string as I desire. The default date/time string given by AppleScript looks like this: Saturday, June 26, 2010 4:02:15 PM. That’s lovely for humans to see in a document, but far from what I want in a filename. I want this: 20100626_160215.

So I get the datetime, format it, make a new filename with the formatted datestamp in it, and tell Finder to rename the file. The main Folder Action handler script is below.

on adding folder items to this_folder after receiving added_items
	try
		set oldFileName to "scan_to_auto_rename.pdf"
		set oldFilePath to ((path to desktop folder as text) & oldFileName)

		tell application "Finder"
			if not (exists file oldFilePath) then
				return -- nothing to do
			end if
		end tell

		-- Build the pathname to the util library.
		set utilLibPath to ((path to home folder as string) & "Scripts:mt_util_library.scpt")

		-- Open the util library.
		set utilLib to load script (alias utilLibPath)

		set ds to utilLib's datestamp()

		set newFileName to "scan_" & ds & ".pdf"

		tell application "Finder"
			set name of file oldFilePath to newFileName
		end tell

	end try
end adding folder items to

Here’s a more detailed breakdown of what’s happening in the script.

1. Make sure file to rename exists. Exit if it doesn’t.
2. Since I moved the datestamp formatting function to its own file, we must open that file (“library”).
3. Get the formatted datestamp string.
4. Create the new filename.
5. Tell Finder to change the name of the old file to the new name.

See the next post for details on my utility script that provides the datestamp formatting.

June 26th, 2010  Posted at   Uncategorized
   |   1 Comment

As mentioned on my previous post, I began an effort to write some AppleScript to help me with some auto file naming on scanning I was doing. The general method I decided to employ was to build a Folder Action that would watch for new files to be added to the Desktop, and then if a file matching a certain obscure name existed, rename it automatically.

So I would make Image Capture write its output to a file called “scan_to_auto_rename.pdf” in the Desktop folder. The new folder action would see this file appear, then rename it to something like this: scan_yyyymmdd_hhmmss.pdf. In human that’s “scan_” plus the year, month, day, hours, minutes, and seconds.

To accomplish this, I had to write an AppleScript, drop it into /Library/Scripts/Folder Action Scripts/, then add the Folder Action via the UI. To add the action (assuming the script is written (correctly :) and located in the right place), go into Finder and right click the folder to which you want to add the action.

So I went to my home directory, right clicked on the Desktop folder, and selected “Folder Actions Setup…”. That popped up a dialog with a list of available scripts I could add. I scrolled down and found mine, aptly named “rename_scan_file.scpt”, selected it, and clicked Attach. That applied my script to the folder, and assuming my script was written correctly it would do something useful based on events taking place within/on that folder.

See next post for a look at the script itself.

June 26th, 2010  Posted at   AppleScript, OS X
   |   No Comments

As may be apparent by my lack of continued posts related to Adobe Flex, my Flex activities were put on hold a while back. The project I was looking at got canceled.

I have lots of projects in mind, so my future posts will reflect that with tips, discoveries, and such on various technologies (Objective-C, iPhone development, Ruby on Rails work, etc.)

Yesterday I was struggling to do some scanning on my Mac. The Snow Leopard (that’s OS X 10.6 for the non-Mac folks) built-in app for scanning is called Image Capture. It’s very rudimentary, having two glaring feature omissions: inability to create multi-page PDF scans, and inability to define an auto file naming scheme. For the multi-page issue I decided I could live without it because I’m just scanning things to get rid of paper. I can always go back and join PDFs if I really care.

But the file naming thing was really bothering me. The old junky Epson software I used here could do it, but now I’m using some HP all-in-one printer/scanner thing, and the HP software doesn’t provide scanning tools. Thus I’m stuck with what OS X provides. I could just can all files to the same name, and the OS will number them itself (“scan 1.pdf”, “scan 2.pdf”, etc.). But I don’t like spaces in filenames, and I wanted something more clever such as the datestamp in the filename.

Thus began my very frustrating foray into AppleScript. See the few following posts for details on that, along with things I’ve learned and code I would like to share.