View Single Post
The previous version of the script did not handle package files. There were two problems:
  • a package is basically a folder (trailing ":" or "/"), so exported files were created as file.graffle/.png, and
  • OG 4.1.2 has a "bug" in that its 'documents whose path ...' strips the trailing "/", which confuses the find-the-document-we-just-opened logic. I just loooove Applescript.

I've had to strip some comments to keep under the 10,000 character limit. Does Omni have a better place to contribute AS code to?

Code:
-- Watch and auto-export OmniGraffle files to web-friendly versions
-- files/folders to watch are to be dropped onto this script (saved as a Stay Open application)
--  if a folder is watched all OG files in the folder will be monitored
-- exported files are created alongside the originals, named with the export_format extension
--  multiple-canvas documents are exported as per the 'Entire Document' (subdirectory named after the OG file)
--  based on / hacked from the original from Greg Titus (http://forums.omnigroup.com/showthread.php?p=537)
-- Changelog:
-- 2006-04-19 BDL	added multiple canvases
-- 2006-04-21 BDL	removed per-canvas exporting (window flipping is too intrusive), replaced 
--					with export area = entire document; much mucking about with 'save in file'/folder business
-- 2006-05-17 BDL	added "support" for OG package files


-- a file extension which Graffle supports for export
property export_format : "png"

-- amount of time to wait in between checking for file changes
-- this is adaptive, and is reset to 10s when a change is detected and will ramp up to 300s
property idle_time : 10
property idle_time_min : 10
property idle_time_max : 300
property idle_time_inc : 5

-- list of 'aliases' (folders, files) to watch (added to via 'on open') 
property watch_files : {}
property watch_folders : {}

on run
	set t to "OmniGraffle Auto-Exporter" & return & ¬
		"Drop files/folders to be monitored on this script and they'll be automatically exported to " & export_format & ¬
		" versions." & return & return & ¬
		"This script will stay open whilst OmniGraffle is running." & return
	set t to t & "Currently monitoring " & (count watch_files) & " file(s) and " & (count watch_folders) & " folder(s). "
	if (count watch_files) > 0 or (count watch_folders) > 0 then
		set r to button returned of (display dialog t & "Keep these?" buttons {"Yes", "No", "Show"} default button "Yes" with icon note)
		if r is "Show" then
			tell application "Finder"
				activate
				reveal {watch_files, watch_folders} -- one hit, so they're all selected
			end tell
		end if
		if r is "No" then
			set watch_files to {}
			set watch_folders to {}
		end if
	else
		display dialog t buttons {"Ok"} with icon note
	end if
end run

on open item_list
	
	tell application "Finder"
		
		repeat with this_item in item_list
			
			-- need to be careful of the list operations on watch_files, watch_folders - make sure only to add aliases
			--   e.g. 'copy this_item to end of watch_files' corrupts the list on the second iteration, whereas
			--  'copy (this_item as alias) to end of watch_files' works fine
			-- think you can find documentation on this? hah! (the Wikipedia AppleScript page was the
			--  only reference I found that actually stated that 'on open' returns a list of aliases!)
			
			if kind of this_item is "OmniGraffle document" then
				if this_item is not in watch_files then copy (this_item as alias) to end of watch_files
			else if kind of this_item is "folder" then
				if this_item is not in watch_folders then copy (this_item as alias) to end of watch_folders
			end if
			
		end repeat
		
	end tell
end open

on idle
	
	-- if omnigraffle's not already running, close it after exporting the new files
	tell application "System Events"
		set isRunning to (name of processes) contains "OmniGraffle Professional"
	end tell
	
	tell application "Finder"
		-- gather list of files to update
		set file_list to watch_files
		repeat with this_folder in watch_folders
			-- display dialog "processing " & (this_folder as string) & "|" & class of this_folder
			-- 'files of' ... returns 'class docf' (file?) objects, not aliases
			set folder_files to (files of this_folder whose kind is "OmniGraffle document")
			repeat with this_file in folder_files
				set this_file to (this_file as alias)
				--display dialog "f: " & this_file & "|" & class of this_file
				if this_file is not in file_list then copy this_file to end of file_list
			end repeat
		end repeat
		
	end tell
	
	-- ok, now have list of candidate OG files (aliases)
	set processed_items to false
	repeat with this_file in file_list
		set processed_items to my process_item(this_file, export_format)
	end repeat
	
	
	if not isRunning and processed_items then -- will have started up OG, so close it
		tell application "OmniGraffle Professional"
			-- close the app (if there are no open files, which there shouldn't be, as OG wasn't running before we started it)
			--display dialog "ndocs: " & (count (document's modified))
			if (count (document's modified)) is 0 then
				quit
			end if
		end tell
	end if
	
	-- if files are being changed drop back to a fast idle time, otherwise decay
	if processed_items then
		set idle_time to idle_time_min
	else
		set idle_time to idle_time + idle_time_inc
		if idle_time > idle_time_max then
			set idle_time to idle_time_max
		end if
	end if
	
	return idle_time
	
end idle

on process_item(source_file, export_format)
	
	set processed_items to false
	
	-- file extension must be added to the destination filename, and must match the export 
	--  type (i.e. 'save doc as "png" in file "figure.graffle.png"')
	-- Note when saving a multi-page document, the destination filename will have the 
	--   export type extension removed, but *will not* have the .graffle extension removed. The 
	--   result will  be created as the directory to hold the exported canvas files. 
	--   e.g. if destination = figure.graffle.png => OG will try to create figure.graffle/, but will fail as 
	--   this is the name of the source file!
	--   OG strips the .graffle extension for the directory name automatically via the GUI, but not via AS
	-- simple solution: double up the extension (figure.graffle.png.png => figure.graffle.png/...) when saving
	--  (see export_item())
	
	-- ok, now to really complicate matters: some OG files are folders (packages) i.e. file.graffle may 
	--   actually be ":path:to:file.graffle:"
	-- - this stuffs up the export naming, so need to chomp any trailing path separators for package files
	-- note that there's no point trying to do chomp the alias, as AS will gleefully put back the ":"
	
	if package folder of (info for source_file) is true then
		-- package, chomp trailing ':'
		set new_name to (characters 1 through -2 of (source_file as string)) as string
		set new_name to new_name & "." & export_format
	else
		-- plain file
		set new_name to (source_file as string) & "." & export_format
	end if
	
	-- test if the target (new_name) needs to be updated
	tell application "Finder"
		-- if doesn't exist, need to update
		set need_update to not (exists item new_name)
		
		if not need_update then -- exists, but is it stale?
			--display dialog "target mod date: " & (modification date of item new_name)
			set need_update to modification date of source_file > modification date of item new_name
		end if
	end tell
	
	if need_update then
		my export_item(source_file, new_name, export_format)
		set processed_items to true
	end if
	
	return processed_items
	
end process_item



-- this sub-routine does the export 
on export_item(source_file, new_name, export_format)
	
	with timeout of 900 seconds
		tell application "OmniGraffle Professional"
			set oldAreaType to area type of current export settings
			
			-- open the file if it isn't already open
			-- 1. convert the source_file alias to a POSIX path ("/path/to/file.graffle")
			--    - OG's 'document path' property is a POSIX path
			-- 2. see if a file with that path is currently open
			-- 3. if not, open it
			-- 4. get a reference to the document object
			set the source_item to the POSIX path of the source_file
			
			-- OG 4.1.2 returns 'path of...' WITHOUT the trailing slash for package files, need to 
			-- chomp before we compare ('documents whose path is ...')
			if (package folder of (info for source_file) is true) and (character -1 of source_item is "/") then
				-- package, chomp trailing '/'
				set source_item to (characters 1 through -2 of source_item) as string
			end if
			
			set needToOpen to (count (documents whose path is source_item)) is 0
			if needToOpen then
				open source_file
			end if
			
			set theDocument to first item of (documents whose path is source_item)
			
			-- single or multipage?
			if (count of canvases of theDocument) = 1 then
				set area type of current export settings to all graphics
			else
				set area type of current export settings to entire document
				-- double up target directory name
				set new_name to new_name & "." & export_format
			end if
			
			save theDocument as export_format in file new_name
			
			-- if the file wasn't already open, close it again
			if needToOpen then
				close theDocument
			end if
			
			set area type of current export settings to oldAreaType
		end tell
	end timeout
	
end export_item