Previous  |  Main  |  Next
AppleScript Logo

Open Special

Script for: BBEdit
Copyright: Matthias Steffens, use at your own risk!
Description: A kind of automated Open Several function!

Let's you specify file matching criteria such as creator and file type(s) and
provides the restriction of file selection to a certain string. All files matching
these criteria will be collected from a specified folder.

Found files can be opened by its default application or within BBEdit directly.
Alternatively, you can get a path list of these files in BBEdit, from where you can
open or reveal files individually.
Necessary: StandardAdditions.hqx from MacOS 8.5.x or greater  (command: "choose from list")
Tanaka's osax 2.0  (command: "MT List Files")
ACME Script Widgets 2.5 (or greater)  (command: "tokenize").
Note that the ACME Scripting Addition is shareware.
Download: OpenSpecial_v1.6.hqx
History: v1.6  -  works now with both BBEdit 5.x and 6.x
v1.5  -  first version released on this site
The Script:
property TheFolderToSearch : 0
property TheSearchText : ""

-- these are the creator & file type lists that are initially available (they can be edited easily from within the script):
property AvailableCreators : {"ttxt", "R*ch", "CARO", "ART5", "rbDG", "MOSS", "MSIE", "iCAB"}
property AvailableFileTypes : {"ttro", "TEXT", "PDF ", "EPSF", "PICT"}

-- change this property ("true" by default) to "false" if you want to restrict the file search to first folder level:
property SearchWithRecursion : true

-- change this property to "false" if you don't wish the new BBEdit window,
-- which lists the files found, to get zoomed:
property ResultsWindowToFullScreen : true

property TheCreatorList : {}
property TheCreators : {}
property TheTypeList : {}
property TheFileTypes : {}
property LimitToCreator : false
property LimitToType : false
property ShowCreatorLimitInfo : ""
property ShowTypeLimitInfo : ""

global AppBBEdit, fileList, FileListNumber, TheSearchFolderName


-- First, get the currently running version of BBEdit
-- (or if BBEdit isn't running, get the newest version of BBEdit installed on this machine):
try -- this try/error block (as well as the "GetPSN" routine) is by Walter Ian Kaye!
	set AppBBEdit to GetPSN("R*ch")
on error number -1728
	beep
	with timeout of (30 * 60) seconds
		display dialog "This script requires BBEdit 5.x or 6.x!" buttons ¬
			{"I should buy it!"} default button 1 with icon note
	end timeout
	error number -128
end try


-- Let's get started and check if the formerly specified search folder exists:
tell application "Finder"
	try
		if (exists file TheFolderToSearch) then
			my OpenSpecialDialog()
		else
			-- if folder wasn't found (script was newly compiled or due to other errors) the script will ask for a search folder:
			my GetSearchFolder()
		end if
	on error ErrText number errNo
		if errNo is not -128 then -- if user didn't press 'cancel':
			if errNo is 32768029 then -- "file not found"
				my GetSearchFolder()
			else -- present an error message
				display dialog "The following error has occurred:" & return & return & ErrText & return & ¬
					"(Error Code: " & errNo & ")" with icon caution buttons {"OK"} default button 1
			end if
		end if
	end try
end tell


-- the main dialog:
on OpenSpecialDialog()
	if LimitToCreator or LimitToType then
		set ShowLimitInfo1 to "File search restricted to:"
		set ShowLimitInfo2 to "" & return & return
	else
		set ShowLimitInfo1 to ""
		set ShowLimitInfo2 to ""
	end if
	tell application "Finder" to set TheSearchFolderName to name of TheFolderToSearch
	set DialogResult to display dialog ¬
		"Search folder: \"" & TheSearchFolderName & "\"" & return & "(\"" & TheFolderToSearch & "\")" & return & return & ¬
		ShowLimitInfo1 & ShowCreatorLimitInfo & ShowTypeLimitInfo & ShowLimitInfo2 & ¬
		"Search files containing:" default answer TheSearchText with icon note ¬
		buttons {"Set Creator|File Type", "Choose Folder|Cancel", "OK"} default button 3
	set TheSearchText to the text returned of DialogResult
	if button returned of DialogResult is "Choose Folder|Cancel" then
		GetSearchFolder()
	end if
	if button returned of DialogResult is "Set Creator|File Type" then
		LimitToCreatorTypeDialog()
	end if
	if button returned of DialogResult is "OK" then
		CheckFiles()
	end if
end OpenSpecialDialog


-- the dialog to set the wished creator & file types:
on LimitToCreatorTypeDialog()
	if not LimitToCreator then
		set ShowCreatorLimitInfo to ""
	else
		set ShowCreatorLimitInfo to (return & "Creator: " & TheCreators as string)
	end if
	
	if not LimitToType then
		set ShowTypeLimitInfo to ""
	else
		set ShowTypeLimitInfo to (return & "File Type: " & TheFileTypes as string)
	end if
	
	if LimitToCreator or LimitToType then
		set ShowLimitInfo3 to "File search currently restricted to:" & return
	else
		set ShowLimitInfo3 to "The file search is not restricted." & return & return & ¬
			"Choose \"Set Creator\"|\"Set File Type\" to restrict file selection (multiple choice allowed)."
	end if
	
	set DialogResult to display dialog ¬
		ShowLimitInfo3 & ShowCreatorLimitInfo & ShowTypeLimitInfo with icon note ¬
		buttons {"Set Creator", "Set File Type", "OK"} default button 3
	
	if button returned of DialogResult is "Set File Type" then
		SetTypeDialog()
	end if
	if button returned of DialogResult is "Set Creator" then
		SetCreatorDialog()
	end if
	if button returned of DialogResult is "OK" then
		OpenSpecialDialog()
	end if
end LimitToCreatorTypeDialog


-- built a list dialog for specifying the creators:
on SetCreatorDialog()
	-- uses the "choose from list" command of the MacOS 8.5.x Scripting Addition "Standard Additions":
	set DialogResult to choose from list AvailableCreators with prompt ¬
		"Restrict to files with creator:" & return & "(no selection = all files)" OK button name "OK" cancel button name ¬
		"Edit List | Cancel" default items TheCreatorList with multiple selections allowed and empty selection allowed
	if DialogResult is not false then -- if false: user pressed "Edit List | Cancel"
		set TheCreatorList to DialogResult
		if TheCreatorList is {} then
			set LimitToCreator to false
		else
			set LimitToCreator to true
			-- building the list of creators (for display purposes):
			set TheCreators to my MergeForDisplay(TheCreatorList)
		end if
		LimitToCreatorTypeDialog()
	else
		set AvailableCreatorsForDisplay to my MergeForDisplay(AvailableCreators)
		set DialogResult to display dialog "Edit the list of available creators:" & return & ¬
			"(separating entries with spaces will suffice)" default answer (AvailableCreatorsForDisplay as text) with icon note buttons {"Cancel", "Back", "Change"} default button 3
		if button returned of DialogResult is "Change" then
			set AvailableCreators to tokenize (text returned of DialogResult) with delimiters {"\"", ",", " ", return} without null tokens -- uses "ACME Script Widgets"
			my SetCreatorDialog()
		else if button returned of DialogResult is "Back" then
			my SetCreatorDialog()
		end if
	end if
end SetCreatorDialog


-- built a list dialog for specifying the file types:
on SetTypeDialog()
	-- uses the "choose from list" command of the MacOS 8.5.x Scripting Addition "Standard Additions":
	set DialogResult to choose from list AvailableFileTypes with prompt ¬
		"Restrict to files with file type:" & return & "(no selection = all files)" OK button name "OK" cancel button name ¬
		"Edit List | Cancel" default items TheTypeList with multiple selections allowed and empty selection allowed
	if DialogResult is not false then -- if false: user pressed "Edit List | Cancel"
		set TheTypeList to DialogResult
		if TheTypeList is {} then
			set LimitToType to false
		else
			set LimitToType to true
			-- building the list of file types (for display purposes):
			set TheFileTypes to my MergeForDisplay(TheTypeList)
		end if
		LimitToCreatorTypeDialog()
	else
		set AvailableFileTypesForDisplay to my MergeForDisplay(AvailableFileTypes)
		set DialogResult to display dialog "Edit the list of available creators:" & return & ¬
			"(separating entries with spaces will suffice)" default answer (AvailableFileTypesForDisplay as text) with icon note buttons {"Cancel", "Back", "Change"} default button 3
		if button returned of DialogResult is "Change" then
			set AvailableFileTypes to tokenize (text returned of DialogResult) with delimiters {"\"", ",", " ", return} without null tokens -- uses "ACME Script Widgets"
			my SetTypeDialog()
		else if button returned of DialogResult is "Back" then
			my SetTypeDialog()
		end if
	end if
end SetTypeDialog


-- allright, let's built the file list according to the specified search criteria:
-- (uses the "MT List Files" command from "Tanaka's osax 2.0" scripting addition)
on CheckFiles()
	if LimitToCreator and LimitToType and TheSearchText is not "" then
		set fileList to (MT List Files TheFolderToSearch of type TheTypeList of creator TheCreatorList name contains TheSearchText of attribute {visible:true} sub folders SearchWithRecursion return as alias)
	end if
	
	if LimitToCreator and LimitToType and TheSearchText = "" then
		set fileList to (MT List Files TheFolderToSearch of type TheTypeList of creator TheCreatorList of attribute {visible:true} sub folders SearchWithRecursion return as alias)
	end if
	
	if not LimitToCreator and LimitToType and TheSearchText is not "" then
		set fileList to (MT List Files TheFolderToSearch of type TheTypeList name contains TheSearchText of attribute {visible:true} sub folders SearchWithRecursion return as alias)
	end if
	
	if LimitToCreator and not LimitToType and TheSearchText is not "" then
		set fileList to (MT List Files TheFolderToSearch of creator TheCreatorList name contains TheSearchText of attribute {visible:true} sub folders SearchWithRecursion return as alias)
	end if
	
	if LimitToCreator and not LimitToType and TheSearchText = "" then
		set fileList to (MT List Files TheFolderToSearch of creator TheCreatorList of attribute {visible:true} sub folders SearchWithRecursion return as alias)
	end if
	
	if not LimitToCreator and LimitToType and TheSearchText = "" then
		set fileList to (MT List Files TheFolderToSearch of type TheTypeList of attribute {visible:true} sub folders SearchWithRecursion return as alias)
	end if
	
	if not LimitToCreator and not LimitToType and TheSearchText is not "" then
		set fileList to (MT List Files TheFolderToSearch name contains TheSearchText of attribute {visible:true} sub folders SearchWithRecursion return as alias)
	end if
	
	if not LimitToCreator and not LimitToType and TheSearchText = "" then
		set fileList to (MT List Files TheFolderToSearch of attribute {visible:true} sub folders SearchWithRecursion return as alias)
	end if
	
	set FileListNumber to count items of fileList
	OpenFiles()
end CheckFiles


-- opening  | listing our files in BBEdit:
on OpenFiles()
	tell AppBBEdit
		if FileListNumber > 0 then
			if FileListNumber = 1 then
				set Plural to " was"
				set Plural_S to ""
			else
				set Plural to " were"
				set Plural_S to "s"
			end if
			set DialogResult to display dialog "" & FileListNumber & " file" & Plural_S & Plural & " found at:" & ¬
				return & return & "\"" & TheFolderToSearch & "\"" with icon note buttons {"Cancel", "Open File" & Plural_S, "List File" & Plural_S} ¬
				default button 3
			if button returned of DialogResult is not "Cancel" then
				if button returned of DialogResult is "Open File" & Plural_S then
					set DialogResult to display dialog "Open the file" & Plural_S & " in BBEdit or within default " & ¬
						"application?" with icon note buttons {"Cancel", "Default Application", "BBEdit"} default button 3
					if button returned of DialogResult is not "Cancel" then
						if button returned of DialogResult is "Default Application" then
							tell application "Finder" to open every item of fileList -- open files in default app
						else -- open files in BBEdit
							activate
							set win_ct to count windows -- "count text windows" would be better, but would be incompatible with BBEdit 5.x
							if win_ct > 0 then
								-- The following dialog will only appear when there are open windows in BBEdit:
								set DialogResult to display dialog "There are open windows in BBEdit." & return & "Close these" & ¬
									" windows (with save dialog if necessary) before opening the files" & return & ¬
									"found?" with icon caution buttons {"Cancel", "Yes", "No"} default button 3
								if button returned of DialogResult is "Cancel" then
									error number -128
								else if button returned of DialogResult is "Yes" then
									close every window
								end if
							end if
							if FileListNumber = 1 then
								open item 1 of fileList
							else
								open items of fileList
							end if
						end if
					end if
				else -- let's built a file listing in BBEdit
					-- first merge the files found:
					set old_delims to AppleScript's text item delimiters
					set AppleScript's text item delimiters to return
					copy fileList as text to fileList
					set AppleScript's text item delimiters to old_delims
					
					activate
					
					-- built and arrange the BBEdit window:
					make new window
					if ResultsWindowToFullScreen then
						tell application "Finder" to copy bounds of desktop's window to screenSize
						set bounds of window 1 to {0, 41, (item 3 of screenSize), (item 4 of screenSize)}
					end if
					
					-- the following section just builts the correct window title (according to the search criteria):
					set TheWindowTitle to {}
					if not LimitToCreator then
						copy {"Any Creator"} to TheWindowTitle
						if not LimitToType then
							copy {" & File Type"} to end of TheWindowTitle
						else
							copy {" / "} to end of TheWindowTitle
							copy {"Type: ", TheFileTypes} to end of TheWindowTitle
						end if
					else
						copy {"Creator: ", TheCreators} to TheWindowTitle
						copy {" / "} to end of TheWindowTitle
						if not LimitToType then
							copy {"Any Type"} to end of TheWindowTitle
						else
							copy {"Type: ", TheFileTypes} to end of TheWindowTitle
						end if
					end if
					if TheSearchText = "" then
						copy {" / "} to end of TheWindowTitle
						copy {"Any File Name"} to end of TheWindowTitle
					else
						copy {" / "} to end of TheWindowTitle
						copy {"File Names Containing: \"", TheSearchText, "\""} to end of TheWindowTitle
					end if
					set name of window 1 to TheWindowTitle as string
					-- end window title stuff
					
					-- build the header (folder name & path, files found and open | reveal info)
					set WindowHeader to ("Folder:" & tab & TheSearchFolderName & return & ¬
						"Path:" & tab & TheFolderToSearch as string) & return & return & ¬
						"No. of files found: " & FileListNumber & return & return & "Selecting the path and " & ¬
						"pressing \"Cmd-D\" (\"Cmd-Option-D\") will open (reveal) the file:" & return & return
					
					-- insert header and file paths:
					set contents of window 1 to (WindowHeader & fileList)
				end if
			end if
		else
			-- no files were found:
			beep
			set DialogResult to display dialog "No file matches were found at:" & ¬
				return & return & "\"" & TheFolderToSearch & "\"" with icon note buttons {"Start New Search", "OK"} ¬
				default button 2
			if button returned of DialogResult is "Start New Search" then
				my OpenSpecialDialog()
			end if
		end if
	end tell
end OpenFiles


on GetSearchFolder()
	set TheFolderToSearch to choose folder with prompt "Choose a search folder:"
	OpenSpecialDialog()
end GetSearchFolder


on MergeForDisplay(theList) -- merges the lists of creators / file types for display purposes
	set MergedList to {}
	repeat with i from 1 to count items of theList
		if i = 1 then
			copy ("\"" & (item i of theList) & "\"") to end of MergedList
		else
			copy (", \"" & (item i of theList) & "\"") to end of MergedList
		end if
	end repeat
	return MergedList
end MergeForDisplay


on GetPSN(AppCreator) -- get's the correct app name of any running (or installed) version of BBEdit 
	tell application "Finder"
		if not (exists (process 1 whose creator type is AppCreator)) then
			-- any *running* version of BBEdit will be preferred, which must not necessary be the newest one!
			open application file id AppCreator
		end if
		(process 1 whose creator type is AppCreator) as «class psn »
		-- >> returns: application "BBEdit 6.0" (or something similar; in any case the app name will be catched correctly)
	end tell
end GetPSN

 


Contact: Matthias Steffens  |  Previous  |  Main  |  Next  |  Last Updated: 15-Mar-05