If you also suffer from subfolder creation sickness, then I might have a cure for you
Overview
subidoo is an AppleScript that simplifies the creation of subfolders in Mac OS X. Especially in list view, subfolders are tedious to create. subidoo can create multiple subfolders in multiple locations at once, saves the names of the last 300 subfolders created and supports convenient folder sets, which can contain collections of frequently used subfolders.
You can download subidoo for free right here:
subidoo - Enhanced subfolder creation for Mac OS X (v1.5, ca. 137 KB)
System Requirements
Mac OS X 10.5.1 or later
- subidoo may run on other systems as well, but I did/could not test it
- subidoo was tested on Intel- and PowerPC-based Macs
Installation
Just drag the script into your Applications/Scripts folder (or wherever you like to put it).
Afterwards you »can«:
a) drag subidoo into the toolbar of a Finder window to use it as a Toolbar Script.
b) drag subidoo into the Dock to use it as a Dock Item.
I find both solutions very convenient for creating subfolders, but personally think, that subidoo works best when used from the toolbar.
Usage
¢ Options panel:
To invoke the options panel in order to manage and create folder sets, just start subidoo by double-clicking its icon without any items selected in the Finder (except subidoo itself).
¢ Toolbar Script/Dock Item:
Select folder items in the frontmost Finder window. Then start subidoo by clicking its icon in the dock or toolbar. After providing names for subfolders or choosing folder sets, they will be created within the selected folder items.
If you don’t select any items in the Finder, the options panel for managing your folder sets will be displayed.
¢ Droplet:
subidoo also works extremely well as a droplet. Therefor you can simply drag & drop folder items onto it. After providing names for subfolders or choosing folder sets, they will be created within the folder items, which you dragged & dropped onto the script.
Folder Sets
subidoo now supports convenient folder sets, which can contain collections of frequently used folder names. This is very useful, when you need to create the same bunch of subfolders over and over again. System administrators will love this! For example, if you are often creating the same set of subfolders representing the 12 months of a year, e.g. ‘01 January’, ‘02 February’, ‘03 March’, then just save them in a folder set named ‘Months’! Now you can choose to create this folder set in chosen folders whenever you want by just a click!
To manage, create and edit your folder sets, just start subidoo without selecting any items in The Finder.
Tips
When you are asked to provide subfolder names, you can enter multiple entries separated by a colon. Nested subfolder structures can be entered by separating subfolder names by a slash.
If you want to manually edit the database file containing the folder sets, you can find it here:
/Users/yourname/Library/Application Support/subidoo/foldersets.db
After manipulating the database file, please always save it with UTF-8 text encoding.
Known Problems
If you select folder items in the Finder and then start subidoo out of a Finder window, it will not recognize the selected folders. This is because AppleScript seems to be unable to recognize selected items in ‘background’ Finder windows (when you start subidoo out of a Finder window, it is itself the frontmost selection). This does not happen if you are using subidoo as a Toolbar Script or Dock Item. So this is absolutely recommended.
Troubleshoot/Help
-/-
Version History
¢ Version 1.5b
- subidoo now finally supports folder sets! wohoo!
- (sub)folders are not anymore created with the Finder,
but using «mkdir -p» on the command line - subidoo now supports relative subfolder structures, so
that you can create subfolders in subfolders in subfolders in…
¢ Version 1.0 - upon request of my wife, I removed the gave-up mode in the dialog, where the user can enter the subfoldernames. now the user has ‘endless’ time to enter the subfoldernames without the dialog suddenly disappearing after 50 seconds.
¢ Version 0.9b - First public release! Yo!
Important: Opening and saving the below script code in Script Editor won’t result in a usable AppleScript! That is because subidoo internally relies on a Python script, which is located inside its Application bundle. Therefor please download the complete script here.
-- created: 07.12.2005
-- modified: 18.02.2008
-- version: 1.5
-- tested with:
-- ¢ Mac OS X 10.5.1
-- ¢ Intel and PowerPC based Macs
-- history:
-- v1.5 (18.02.2008):
-- ¢ finally subidoo supports folder sets! wohoo!
-- ¢ subidoo now supports relative folder structures, so
-- you can also create subfolders in subfolders in subfolders...
-- ¢ (sub)folders are now created using the «mkdir -p»-command
-- -->> type 'man mkdir' into a Terminal window
-- v1.0 (11.02.2006):
-- ¢ upon request of my wife, I removed the gave-up mode in the dialog,
-- where the user enters the subfolder names. now the user has 'endless'
-- time to enter the subfoler names without the dialog window suddenly
-- disappearing after 50 seconds.
-- future:
-- ¢ icon, icon, icon!
-- some basic properties
property mytitle : "subidoo"
property mydomain : "com.jos." & mytitle
property myversion : "1.5b"
-- handler called when Finder items are dropped onto the script icon
on open dropitems
set mode to "on open"
my main(mode, dropitems)
end open
-- handler called when the script is opened with a double-click onto its icon
on run
set mode to "on run"
set args to missing value
my main(mode, args)
end run
-- I am the main function of the script and control the application flow
on main(mode, args)
try
-- creating application support folder & copying default database file if necessary
my initialize()
-- user dropped Finder items onto the script
if mode is "on open" then
-- process dropped Finder items
my procselitems(mode, args)
-- user opened the script with a double-click
else if mode is "on run" then
-- the user might have selected items in the Finder
tell application "Finder"
set selitems to selection as list
end tell
if selitems is {} then
-- dock item?
my guiloop()
else
-- is the script itself the selected item or are there no selected items at all?
-- > in this case we display the options panel
set myname to name of (info for (path to me))
set selitemname to name of (info for ((item 1 of selitems) as alias))
if length of selitems = 1 and myname = selitemname then
my guiloop()
else
-- process selected Finder items
my procselitems(mode, selitems)
end if
end if
end if
-- catching unexpected errors, hopefully not too often
on error errmsg number errnum
my dsperrmsg(errmsg, errnum)
end try
end main
-- I am initializing the script, taking precautions for a successful operation
on initialize()
-- path to my own application support folder
set myasfpath to (((path to application support folder from user domain) as Unicode text) & mytitle & ":")
-- if the application support folder does not yet exist, we try to create it
-- occuring errors (missing permissions?) will be catched by
-- the try/on error-block of the main function
try
set myasfalias to myasfpath as alias
on error
do shell script "mkdir -p" & space & quoted form of (POSIX path of myasfpath)
-- if the script's application support folder did not exist so far, then
-- chances are good, that the user uses the script for the very first time,
-- so we display an inviting welcome message
my dspwelcomemsg()
end try
-- path to the user's database file inside the application support folder, which contains the folder sets
set dbfilepath to myasfpath & "foldersets.db"
-- path to the default database file inside the script's package folder
set defdbfilepath to (((path to me) as Unicode text) & "Contents:Resources:foldersets.db")
-- if the user's database file does not yet exist, we copy the default database file to the
-- application support folder
try
set dbfilealias to dbfilepath as alias
on error
do shell script "cp" & space & quoted form of (POSIX path of defdbfilepath) & space & quoted form of (POSIX path of dbfilepath)
end try
end initialize
-- I am processing the selected/dropped Finder items and create the chosen subfolders
-- therein if possible
on procselitems(mode, selitems)
-- we are only interested in dropped/selected folder items
set selfolders to {}
repeat with selitem in selitems
try
set selinfo to (info for (selitem as alias))
if folder of selinfo and name of selinfo does not end with ".app" then
set selfolders to selfolders & (selitem as Unicode text)
end if
end try
end repeat
-- unfortunately the user only selected/dropped files
if selfolders is {} then
if mode is "on run" then
set errmsg to "You did only select non-folder items in the Finder." & return & return & "Please try again by selecting folders only."
else if mode is "on open" then
set errmsg to "You did only drop non-folder items onto " & mytitle & "." & return & return & "Please try again by dropping folders only."
end if
my dsperrmsg(errmsg, "--")
-- early finish
return
-- we found selected/dropped folders!
else
-- asking the user to provide (sub)folder names to be created inside
-- the dropped or selected folders
set countselfolders to length of selfolders
set relfoldernames to my askforrelfoldernames(mode, countselfolders)
if relfoldernames is not missing value then
-- so now that we got (sub)folder names, we have to create a string
-- of quoted folder paths to be used with the mkdir-command below
repeat with selfolder in selfolders
set stringfolders to ""
set countrelfoldernames to length of relfoldernames
repeat with i from 1 to countrelfoldernames
-- .e.g. 'Invoices/2008/01 January/'
set relfoldername to item i of relfoldernames
-- e.g. '/Users/martin/Documents/Customers/BigCompany/Invoices/2008/01 January/'
set newpath to quoted form of ((POSIX path of selfolder) & relfoldername)
if i is not equal to countrelfoldernames then
set stringfolders to stringfolders & newpath & space
else
set stringfolders to stringfolders & newpath
end if
end repeat
-- finally creating the subfolders using the mkdir-command with the p-option
set command to "mkdir -p" & space & stringfolders
set command to command as «class utf8»
set shellresult to do shell script command
end repeat
end if
end if
end procselitems
-- I am displaying the options panel and trigger actions on the basis of
-- the chosen menu items
on guiloop()
set chosenmenuitem to my dspoptionsmenu()
if chosenmenuitem is missing value then
return
else
if chosenmenuitem is "Add folder set" then
my miaddfset()
else if chosenmenuitem is "Delete folder set(s)" then
my midelfsets()
else if chosenmenuitem is "Rename folder set" then
my mirenfset()
else if chosenmenuitem is "Show folder sets" then
my mishowfsets()
else if chosenmenuitem is "Add folder name(s) to folder set" then
my miaddfolderstofset()
else if chosenmenuitem is "Delete folder name(s) from folder set" then
my midelfoldersfromfset()
else if chosenmenuitem is "Create folder set from recent folder names" then
my micrtfsetfromsysfolders("Recent folder names")
else if chosenmenuitem is "Add recent folder names to a folder set" then
my miaddsysfolderstofset("Recent folder names")
else if chosenmenuitem is "Create folder set from last folder names" then
my micrtfsetfromsysfolders("Last folder names")
else if chosenmenuitem is "Add last folder names to a folder set" then
my miaddsysfolderstofset("Last folder names")
else if chosenmenuitem is "Open database file" then
my miopendbfile()
end if
end if
my guiloop()
end guiloop
-- I am displaying the options menu and return the chosen menu items
on dspoptionsmenu()
set spacer to "....................."
set menuitems to {"Add folder set", "Delete folder set(s)", "Rename folder set", "Show folder sets", spacer, "Add folder name(s) to folder set", "Delete folder name(s) from folder set", spacer, "Create folder set from recent folder names", "Add recent folder names to a folder set", spacer, "Create folder set from last folder names", "Add last folder names to a folder set", spacer, "Open database file"}
choose from list menuitems with title mytitle with prompt "Please choose an option:" without multiple selections allowed and empty selection allowed
set choice to result
if choice is not false then
set chosenmenuitem to item 1 of choice
return chosenmenuitem
else
return missing value
end if
end dspoptionsmenu
-- I am asking the user to choose a single folder set name from a list
-- of existing folder set names
on choosefoldersetname(showhidden)
set foldersetnames to my getfoldersetnames(showhidden)
if foldersetnames is missing value then
return missing value
else
choose from list foldersetnames with title mytitle with prompt "Please choose a folder set:" without multiple selections allowed and empty selection allowed
set choice to result
if choice is not false then
set chosenfoldersetname to item 1 of choice
return chosenfoldersetname
else
return missing value
end if
end if
end choosefoldersetname
-- I am asking the user to choose one or more folder set names from a list
-- of existing folder set names
on choosefoldersetnames(showhidden)
set foldersetnames to my getfoldersetnames(showhidden)
if foldersetnames is missing value then
return missing value
else
choose from list foldersetnames with title mytitle with prompt "Please choose one or more folder sets:" with multiple selections allowed without empty selection allowed
set choice to result
if choice is not false then
set chosenfoldersetnames to (choice as list)
return chosenfoldersetnames
else
return missing value
end if
end if
end choosefoldersetnames
-- I am adding a new folder set to the existing database of
-- folder sets
on miaddfset()
set srcfolder to my choosesrcfolder()
if srcfolder is not missing value then
set relfolders to my searchrelfolders(srcfolder)
if relfolders is not missing value then
-- for enhanced convenience, we suggest the user to use
-- the name of the above chosen source folder for the
-- new folder set
set srcfolderinfo to info for (srcfolder as alias)
set srcfoldername to displayed name of srcfolderinfo
set newfoldersetname to my getnewfoldersetname(srcfoldername)
if newfoldersetname is not missing value then
my addfolderset(newfoldersetname, relfolders)
end if
end if
end if
end miaddfset
-- I am deleting one or more chosen folder sets from the database file
on midelfsets()
-- we don't want the user to delete the internally used folder set names
-- ('Last folder names', 'Recent folder names'), so we set
-- «showhidden» to false
set showhidden to false
set chosenfoldersetnames to my choosefoldersetnames(showhidden)
if chosenfoldersetnames is not missing value then
repeat with chosenfoldersetname in chosenfoldersetnames
my delfolderset(chosenfoldersetname)
end repeat
end if
end midelfsets
-- I am renaming an existing folder set
on mirenfset()
-- we don't want the user to rename the internally used folder set names
-- ('Last folder names', 'Recent folder names'), so we set
-- «showhidden» to false
set showhidden to false
set oldfoldersetname to my choosefoldersetname(showhidden)
if oldfoldersetname is not missing value then
set newfoldersetname to my getnewfoldersetname(oldfoldersetname)
if newfoldersetname is not missing value then
my renamefolderset(oldfoldersetname, newfoldersetname)
end if
end if
end mirenfset
-- I am displaying a list of available folder sets
on mishowfsets()
-- let's hide the internally used folder sets from the user's eyes
set showhidden to false
set foldersetname to my choosefoldersetname(showhidden)
if foldersetname is not missing value then
set relfolders to my getfolderset(foldersetname)
if relfolders is {} then
set errmsg to "Sorry, the folder set '" & foldersetname & "' does not contain any folder names."
my dsperrmsg(errmsg, "--")
else
choose from list relfolders with title mytitle with prompt "Folder names of folder set '" & foldersetname & "':" with empty selection allowed
end if
end if
end mishowfsets
-- I am adding new folder names to an already existing folder set
on miaddfolderstofset()
-- let's hide the internally used folder sets from the user's eyes
set showhidden to false
set foldersetname to my choosefoldersetname(showhidden)
if foldersetname is not missing value then
tell me
activate
display dialog "Do you want to manually enter the additional folder names or do you want to choose a folder?" buttons {"Choose folder", "Enter manually"} default button 2 with title mytitle
set dlgresult to result
end tell
if button returned of dlgresult is "Choose folder" then
set srcfolder to my choosesrcfolder()
if srcfolder is not missing value then
set relfolders to my searchrelfolders(srcfolder)
else
set relfolders to missing value
end if
else if button returned of dlgresult is "Enter manually" then
set relfolders to my askforfoldernames()
end if
if relfolders is not missing value then
my addrelfolderstofolderset(foldersetname, relfolders)
end if
end if
end miaddfolderstofset
-- I am removing selected folder names from a folder set
on midelfoldersfromfset()
-- let's hide the internally used folder sets from the user's eyes
set showhidden to false
set foldersetname to my choosefoldersetname(showhidden)
if foldersetname is not missing value then
set relfolders to my getfolderset(foldersetname)
if relfolders is {} then
set errmsg to "Sorry, the folder set '" & foldersetname & "' does not contain any folder names."
my dsperrmsg(errmsg, "--")
else
choose from list relfolders with title mytitle with prompt "Please choose folder names to delete from the folder set '" & foldersetname & "':" cancel button name "Cancel" OK button name "Delete" with multiple selections allowed without empty selection allowed
set choice to result
if choice is not false then
set relfolders to (choice as list)
my delrelfoldersfromfolderset(foldersetname, relfolders)
end if
end if
end if
end midelfoldersfromfset
-- I am creating a new folder set from selected recent or last folder names
on micrtfsetfromsysfolders(foldersetname)
if not my foldersetnameexists(foldersetname) then
set errmsg to "Sorry, the folder set '" & foldersetname & "' does not exist in the database."
my dsperrmsg(errmsg, "--")
else
set relfolders to my getfolderset(foldersetname)
if relfolders is {} then
set errmsg to "Sorry, the folder set '" & foldersetname & "' does not contain any folder names."
my dsperrmsg(errmsg, "--")
else
choose from list relfolders with title mytitle with prompt "Please choose folder names from the folder set '" & foldersetname & "' to create a new folder set:" with multiple selections allowed without empty selection allowed
set choice to result
if choice is not false then
set relfolders to (choice as list)
set newfoldersetname to my getnewfoldersetname("")
if newfoldersetname is not missing value then
my addfolderset(newfoldersetname, relfolders)
end if
end if
end if
end if
end micrtfsetfromsysfolders
-- I am adding selected recent or last folder names to an existing folder set
on miaddsysfolderstofset(foldersetname)
if not my foldersetnameexists(foldersetname) then
set errmsg to "Sorry, the folder set '" & foldersetname & "' does not exist in the database."
my dsperrmsg(errmsg, "--")
else
set relfolders to my getfolderset(foldersetname)
if relfolders is {} then
set errmsg to "Sorry, the folder set '" & foldersetname & "' does not contain any folder names."
my dsperrmsg(errmsg, "--")
else
choose from list relfolders with title mytitle with prompt "Please choose folder names from the folder set '" & foldersetname & "' to add them to an existing folder set:" with multiple selections allowed without empty selection allowed
set choice to result
if choice is not false then
set relfolders to (choice as list)
-- let's hide the internally used folder sets from the user's eyes
set showhidden to false
set foldersetname to my choosefoldersetname(showhidden)
if foldersetname is not missing value then
my addrelfolderstofolderset(foldersetname, relfolders)
end if
end if
end if
end if
end miaddsysfolderstofset
-- I am opening the database file in the default application
on miopendbfile()
-- path to my application support folder
set myasfpath to (((path to application support folder from user domain) as Unicode text) & mytitle & ":")
-- path to the database file located in my application support folder
set dbfilepath to quoted form of (POSIX path of (myasfpath & "foldersets.db"))
set command to "open" & space & dbfilepath
set command to command as «class utf8»
do shell script command
end miopendbfile
-- I am asking the user to provide a new folder set name
on getnewfoldersetname(suggestion)
try
tell me
display dialog "Please choose a name for your new folder set:" default answer suggestion buttons {"Cancel", "Select"} default button 2 with title mytitle
set dlgresult to result
end tell
on error errmsg number errnum
if errnum is equal to -128 then
return missing value
else
error errmsg number errnum
end if
end try
set newfoldersetname to text returned of dlgresult
if newfoldersetname is "" then
my getnewfoldersetname(suggestion)
else
if my foldersetnameexists(newfoldersetname) then
set errmsg to "The chosen folder set name '" & newfoldersetname & "' already exists in the database. " & return & return & newfoldersetname & return & return & "Please choose a different folder set name."
my dsperrmsg(errmsg, "--")
my getnewfoldersetname(suggestion)
else
return newfoldersetname
end if
end if
end getnewfoldersetname
-- I am asking the user to choose a source folder to search for contained (sub)folder names
on choosesrcfolder()
try
set srcfolder to choose folder with prompt "Please choose a source folder:" without multiple selections allowed
return srcfolder
on error errmsg number errnum
if errnum is equal to -128 then
return missing value
end if
end try
end choosesrcfolder
-- I am asking the user to choose a folder and return the relative folders contained therein
on searchrelfolders(srcfolder)
set srcfolder to POSIX path of (srcfolder as Unicode text)
tell me
activate
display dialog "Do you want to scan for subfolders beyond the first level?" buttons {"Yes", "No"} default button 2 with title mytitle
set dlgresult to result
end tell
-- if the user choosed to scan subfolders, we set a warn level
-- if we find more folders than set by the warn level (e.g. > 250),
-- we display a dialog and ask the user if we should continue the scan process
-- this is to avoid problems, that might occur, when the user accidently choosed
-- the wrong source folder, e.g. the hard disk itself...
if button returned of dlgresult is "Yes" then
set subfolders to true
set warnlevel to 250
else if button returned of dlgresult is "No" then
set subfolders to false
set warnlevel to false
end if
set relfolders to my aspybridge("getrelfolders", {srcfolder, subfolders, warnlevel}, "lines")
if relfolders is {} then
set errmsg to "Sorry, your source folder did not contain any folders."
my dsperrmsg(errmsg, "--")
return missing value
else if (item 1 of relfolders) begins with "<<Error>>" then
set warnmsg to "Warning: " & return & return & ((characters 11 through -1 of (item 1 of relfolders)) as Unicode text) & return & return & "Do you want to continue anyway?"
try
tell me
activate
display dialog warnmsg buttons {"Cancel", "Continue"} default button 1 with title mytitle with icon caution
end tell
on error errmsg number errnum
if errnum is equal to -128 then
return missing value
else
error errmsg number errnum
end if
end try
set warnlevel to false
set relfolders to my aspybridge("getrelfolders", {srcfolder, subfolders, warnlevel}, "lines")
return relfolders
else
return relfolders
end if
end searchrelfolders
-- I am asking the user to provide (sub)folder names, either by entering
-- them manually or by choosing an existing folder set
-- Yes, I am ugly...
on askforrelfoldernames(mode, countselfolders)
if countselfolders is equal to 1 then
if mode is "on run" then
set selfoldmsg to "» You have selected 1 folder in the Finder «"
else if mode is "on open" then
set selfoldmsg to "» You dropped 1 folder onto " & mytitle & " «"
end if
else
if mode is "on run" then
set selfoldmsg to "» You have selected " & countselfolders & " folders in the Finder «"
else if mode is "on open" then
set selfoldmsg to "» You dropped " & countselfolders & " folders onto " & mytitle & " «"
end if
end if
-- if the folder set 'Last folder names' exists and contains
-- folder names, we conveniently use them for the default answer
set defanswer to ""
set foldersetname to "Last folder names"
if my foldersetnameexists(foldersetname) then
set relfolders to my getfolderset(foldersetname)
if relfolders is not {} then
set countrelfolders to length of relfolders
repeat with i from 1 to countrelfolders
set relfolder to item i of relfolders
if i is equal to countrelfolders then
set defanswer to defanswer & relfolder
else
set defanswer to defanswer & relfolder & ":"
end if
end repeat
end if
end if
-- if no folder sets exist so far, we do not show the «Folder sets»-button
set showhidden to true
set foldersetnames to my aspybridge("getfsetnames", {showhidden}, "lines")
if foldersetnames is {} then
set dlgbuttons to {"Cancel", "Enter"}
else
set dlgbuttons to {"Folder sets", "Cancel", "Enter"}
end if
-- the dialog
try
set msg to "Please enter your desired folder names manually or choose folder sets:" & return & return & "(Enter multiple folder names separated by a colon," & return & "enter subfolder names separated by a slash)" & return & return & selfoldmsg
tell me
activate
display dialog msg default answer defanswer buttons {"Folder sets", "Cancel", "Enter"} default button 3 with title mytitle
set dlgresult to result
end tell
on error errmsg number errnum
if errnum is equal to -128 then
return missing value
else
error errmsg number errnum
end if
end try
if button returned of dlgresult is "Enter" then
set usrinput to text returned of dlgresult
if usrinput is "" then
my askforrelfoldernames(mode, countselfolders)
else
set relfoldernames to my checkenteredfoldernames(usrinput)
-- oops, no valid folder names
if relfoldernames is {} then
my askforrelfoldernames(mode, countselfolders)
else
-- saving entered folder names to the 'Last folder names'-folder set
if my foldersetnameexists("Last folder names") then
my delfolderset("Last folder names")
end if
my addfolderset("Last folder names", relfoldernames)
-- saving entered folder names to the 'Recent folder names'-folder set
if my foldersetnameexists("Recent folder names") then
my addrelfolderstofolderset("Recent folder names", relfoldernames)
else
my addfolderset("Recent folder names", relfoldernames)
end if
return relfoldernames
end if
end if
else if button returned of dlgresult is "Folder sets" then
-- we want the user to see the internally used folder sets, so that
-- he can choose folder names from them
set showhidden to true
set foldersetnames to my choosefoldersetnames(showhidden)
if foldersetnames is missing value then
my askforrelfoldernames(mode, countselfolders)
else
set relfoldernames to {}
repeat with foldersetname in foldersetnames
set relfolders to my getfolderset(foldersetname)
if relfolders is {} then
set errmsg to "Sorry, the folder set '" & foldersetname & "' does not contain any folder names."
my dsperrmsg(errmsg, "--")
else
if foldersetname is in {"Last folder names", "Recent folder names"} then
choose from list relfolders with prompt "Please choose folder names from the folder set '" & foldersetname & "':" with title mytitle with multiple selections allowed without empty selection allowed
set choice to result
if choice is not false then
set relfolders to (choice as list)
else
set relfolders to {}
end if
end if
repeat with relfolder in relfolders
if relfolder is not in relfoldernames then
set relfoldernames to relfoldernames & relfolder
end if
end repeat
end if
end repeat
if relfoldernames is {} then
my askforrelfoldernames(mode, countselfolders)
else
return relfoldernames
end if
end if
end if
end askforrelfoldernames
-- I am also asking the user to provide (sub)folder names, but am used
-- from within the options panel
on askforfoldernames()
set msg to "Please enter your desired folder names:" & return & return & "(Enter multiple folder names separated by a colon," & return & "enter subfolders separated by a slash)"
try
tell me
activate
display dialog msg default answer "" buttons {"Cancel", "Enter"} default button 2 with title mytitle
set dlgresult to result
end tell
on error errmsg number errnum
if errnum is equal to -128 then
return missing value
else
error errmsg number errnum
end if
end try
set usrinput to text returned of dlgresult
if usrinput is "" then
my askforfoldernames()
else
set foldernames to my checkenteredfoldernames(usrinput)
-- oops, no valid folder names
if foldernames is {} then
my askforfoldernames()
else
return foldernames
end if
end if
end askforfoldernames
-- I am validating the entered folder names
on checkenteredfoldernames(usrinput)
considering case, diacriticals and punctuation
set olddelims to AppleScript's text item delimiters
set AppleScript's text item delimiters to ":"
set inputfoldernames to text items of usrinput
set AppleScript's text item delimiters to olddelims
end considering
-- sorting out 'empty' entries, deleting double entries, ignoring invalid entries
set foldernames to {}
repeat with inputfoldername in inputfoldernames
set inputfoldername to inputfoldername as Unicode text
if inputfoldername is not "" and inputfoldername is not in foldernames and inputfoldername does not start with "/" then
set foldernames to foldernames & inputfoldername
end if
end repeat
return foldernames
end checkenteredfoldernames
-- I am returning a list of available folder set names in the database file
-- If there are no folder set names available, I display an error message and
-- return «missing value»
on getfoldersetnames(showhidden)
set foldersetnames to my aspybridge("getfsetnames", {showhidden}, "lines")
if foldersetnames is {} then
set errmsg to "Your database file does not contain any folder set names."
my dsperrmsg(errmsg, "--")
return missing value
else
return foldersetnames
end if
end getfoldersetnames
-- I am adding a new folder set to the database file
on addfolderset(foldersetname, relfolders)
my aspybridge("addfset", {foldersetname, relfolders}, missing value)
end addfolderset
-- I am deleting a folder set
on delfolderset(foldersetname)
my aspybridge("delfset", {foldersetname}, missing value)
end delfolderset
-- I am renaming a folder set
on renamefolderset(oldfoldersetname, newfoldersetname)
my aspybridge("renfset", {oldfoldersetname, newfoldersetname}, missing value)
end renamefolderset
-- I am returning the folder names saved in a given folder set (name)
on getfolderset(foldersetname)
set relfolders to my aspybridge("getfset", {foldersetname}, "lines")
return relfolders
end getfolderset
-- I am adding a list of folder names to a given folder set (name)
on addrelfolderstofolderset(foldersetname, relfolders)
my aspybridge("addrelfolderstofset", {foldersetname, relfolders}, missing value)
end addrelfolderstofolderset
-- I am deleting a list of folder names from a given folder set (name)
on delrelfoldersfromfolderset(foldersetname, relfolders)
my aspybridge("delrelfoldersfromfset", {foldersetname, relfolders}, missing value)
end delrelfoldersfromfolderset
on foldersetnameexists(foldersetname)
return (my aspybridge("hasfsetname", {foldersetname}, "boolean"))
end foldersetnameexists
on getquotedstringfolders(relfolders)
set countrelfolders to length of relfolders
set quotedstringfolders to ""
repeat with i from 1 to countrelfolders
set relfolder to item i of relfolders
if i is equal to countrelfolders then
set quotedstringfolders to quotedstringfolders & quoted form of relfolder
else
set quotedstringfolders to quotedstringfolders & quoted form of relfolder & space
end if
end repeat
return quotedstringfolders
end getquotedstringfolders
-- I am the connection to the Python script controlling and managing the
-- database file. Yes, I am ugly, but I am hard-working and busy as a bee.
on aspybridge(action, args, returntype)
-- pyth to myself
set mypath to ((path to me) as Unicode text)
-- path to the Python script
set pyscriptpath to quoted form of (POSIX path of (mypath & "Contents:Resources:Scripts:aspybridge.py"))
-- path to my application support folder
set myasfpath to (((path to application support folder from user domain) as Unicode text) & mytitle & ":")
-- path to the database file located in my application support folder
set dbfilepath to quoted form of (POSIX path of (myasfpath & "foldersets.db"))
if action is "getfsetnames" then
set showhidden to item 1 of args
set command to "python" & space & pyscriptpath & space & action & space & showhidden & space & dbfilepath
else if action is "addfset" then
set foldersetname to item 1 of args
set quotedstringfolders to my getquotedstringfolders(item 2 of args)
set command to "python" & space & pyscriptpath & space & action & space & quoted form of foldersetname & space & quotedstringfolders & space & dbfilepath
else if action is "delfset" then
set foldersetname to item 1 of args
set command to "python" & space & pyscriptpath & space & action & space & quoted form of foldersetname & space & dbfilepath
else if action is "getrelfolders" then
set srcfolder to item 1 of args
set subfolders to (item 2 of args) as Unicode text
set warnlevel to (item 3 of args) as Unicode text
set command to "python" & space & pyscriptpath & space & action & space & quoted form of srcfolder & space & subfolders & space & warnlevel & space & dbfilepath
else if action is "hasfsetname" then
set foldersetname to item 1 of args
set command to "python" & space & pyscriptpath & space & action & space & quoted form of foldersetname & space & dbfilepath
else if action is "renfset" then
set oldfoldersetname to item 1 of args
set newfoldersetname to item 2 of args
set command to "python" & space & pyscriptpath & space & action & space & quoted form of oldfoldersetname & space & quoted form of newfoldersetname & space & dbfilepath
else if action is "addrelfolderstofset" then
set foldersetname to item 1 of args
set quotedstringfolders to my getquotedstringfolders(item 2 of args)
set command to "python" & space & pyscriptpath & space & action & space & quoted form of foldersetname & space & quotedstringfolders & space & dbfilepath
else if action is "delrelfoldersfromfset" then
set foldersetname to item 1 of args
set quotedstringfolders to my getquotedstringfolders(item 2 of args)
set command to "python" & space & pyscriptpath & space & action & space & quoted form of foldersetname & space & quotedstringfolders & space & dbfilepath
else if action is "getfset" then
set foldersetname to item 1 of args
set command to "python" & space & pyscriptpath & space & action & space & quoted form of foldersetname & space & dbfilepath
end if
set command to command as «class utf8»
set shellresult to do shell script command
if returntype is "lines" then
return (paragraphs of shellresult)
else if returntype is "boolean" then
if shellresult is in {"True", "1"} then
return true
else if shellresult is in {"False", "0"} then
return false
end if
else
return shellresult
end if
end aspybridge
-- I am displaying a welcome message to uses who start subidoo for the first time
on dspwelcomemsg()
tell application "System Events"
set usrname to (full name of current user) as Unicode text
end tell
set welcomemsg to "Hello " & usrname & ", and welcome to " & mytitle & "." & return & return & "It seems, that you are using this application for the first time." & return & return & "If you want to manage your folder sets, just start the application by double-clicking its icon without any items selected in the Finder." & return & return & "If you want to create subfolders, just drop folders onto " & mytitle & "'s icon or select folders in the Finder before starting " & mytitle & "." & return & return & "Have fun!"
tell me
activate
display dialog welcomemsg with title mytitle buttons {"OK"} default button 1
end tell
end dspwelcomemsg
-- I am displaying error messages
on dsperrmsg(errmsg, errnum)
tell me
activate
display dialog "Sorry, an error occured:" & return & return & errmsg & " (" & errnum & ")" buttons {"Never mind"} default button 1 with icon stop with title mytitle
end tell
end dsperrmsg