Hello Barbara.
Surprise
Needless to say: you make a copy of your files and tries the script on the copy first!.
I have no belief in that this is finished in anyway - but I still have tested it as thoroughly
as I could here.
I do believe that this script should do the “trick” for you in a short amount of time/dialogue/debugging session.
I finally stuck around to make a solution for your now old problem (14 days +).
Lets hope that those who waits waits for something good.
The script should be stored in your User scripts folder or your Machine/Local scripts folder.
It is made so that you can call it from any application as a “timesaving step”.
(Maybe you are looking at some photographs or whatever from within a folder or subfolder you want to
use as a template from lets say Preview or similar.)
I’m following my own conventions for the UI: You just quit the script if you hit
escape when prompted for a folder, no more questions.
When you have chosen a folder or confirmed the scripts deductions then you are good to go.
I have also perceived that your work is stored per year, under a main section like “Outdoors” followed by a subsection like “Mechanicals” ( then the year follows on the next level) then
the folder for the actual job.
Below is the outline of an algorithm for choosing the right folder for a job.
Study it carefully.
Context: You have just selected the script from the script menu.
If you started the script for the first time, then you are asked to select the
parent folder for all your jobs, which in your case should be the folder “Marketing”.
Assuming that application is not finder and that the application has a document window open,
the script will get the path of that document, and if that path is a path which is “under” your
jobs folder it will create a new job based on the files of that path**.
If the current application is Finder it will check to see if there is a folder selected and if it is,check to see if that path is within your jobs folder. -If no folder is selected, will use the
folder which is displayed in the window and use that for further study of wether the path is
within your jobs folder or not.
We come here if we can make a positive deduction that a folder can be used as a template.
If one of the above cases leads to an “acknowledged” path (within your jobs hierarchy) then
you will get a question about wether to use this as a template.
(-I have pondered this verification abit, and drew the conclusion that it ought to be there.)
-If you refuse to use this “assumed” folder then you will be asked for a folder to use:
This choose folder dialog will start out with the section above the folder you declined to use.
This is the step from above where we couldn’t deduce any folder to use:
Should none of the above cases lead to an “acknowledged” path because: there were no match between a folder in the active app for whatever reason (the app could be a “document less” one), you will get a request for a folder for which to use, as a template for the new job.
And this folder you choose will not be used unless that folder can be “acknowledged” as well.
(It has to follow the naming conventions for a folder that stores a job.)
Assuming you didn’t abort the script at any time by pressing escape we should be here.
We will first deduce the name of the folder to copy the files into.
Lets assume that you want to use the contents of the folder
/Marketing/Outdoor/Sports/2008/08-PP-03 as a template for the new job.
And that you haven’t done any Sports in 2010: Then the folder 2010 and the folder 10-PP-01
will be created. So that the copied files will be stored under: /Marketing/Outdoor/Sports/2010/10-PP-01
If you had say 9 jobs from 01 thru 09 then then the new job will be named 10 that is 10-PP-10
The files in the folder will be named accordingly:
A document originally named “08-PP-03#1” will get the new name "10-PP-01#1 and so on.
** This might not allways work as I have sometimes experienced problems with identifying
the correct front finder window when the finder window is residing in another space.
– Then you will get to select the folder to use as a template anyway, so it isn´t that much
of a problem really :).
If there is anything you think you should be different please don’t hesitate!
property INITIAL_PATH : {} -- This path is the initial path to where your files are stored
property PREVIOUS_PATH : {}
property EXISTING_FOLDER : "Outdoor_TEST"
property script_title : "Make New Quark Job:"
property template_folder_level : 3 -- level below the last folder in the initial path -- the level the folders to copy are at.
on run
global docFolderName, aSecName, shortYear, theFullYear, aSecName, curDocPath, targetFoldersParent, FOLDER_NR_IN_PATH, theStemName, sourceChildFolderName, thisJobNumber, pathToTargetFolder
local tids
set AppleScript's text item delimiters to ""
set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, ""}
if INITIAL_PATH is {} then
set INITIAL_PATH to select_initial_path_qualified_by_a_child_folder(EXISTING_FOLDER, script_title) -- the script is aborted if user fails to supply a correct path
end if
set AppleScript's text item delimiters to ":"
set initial_folder_count to count of text items of INITIAL_PATH
set FOLDER_NR_IN_PATH to initial_folder_count + template_folder_level -- just to find the static number cant be used dynamically!
set AppleScript's text item delimiters to "" -- no tids is the way internally
set currAppsName to getCurrentAppsName()
-- Convention: We first try to find a path which is initially ok by being a subfolder of the root of our subtree.
-- Then we verify the folder name.in the step two we ask the user if the folder is ok.
set curDocPath to ""
if currAppsName does not contain "Finder" then -- check fo the selected folder or container of current selection.
set curDocPath to getHfsPathofCurrentDocumentFilesFolder(currAppsName, tids)
set curDocPath to getTemplateFolder(INITIAL_PATH, curDocPath, tids, true, false, script_title, FOLDER_NR_IN_PATH)
end if
if curDocPath is "" or currAppsName contains "Finder" then
set curFolderPath to my getHFsPathOfFindersCurrentFolder()
set curDocPath to getTemplateFolder(INITIAL_PATH, curFolderPath, tids, true, false, script_title, FOLDER_NR_IN_PATH)
if curDocPath is "" and curFolderPath contains INITIAL_PATH then
set starterPath to curFolderPath
else
if not PREVIOUS_PATH is {} then
set starterPath to PREVIOUS_PATH
else
set starterPath to INITIAL_PATH
end if
end if
-- If a path from finder should be partly right, then we really should save that path and use it for
-- further exploration when we are manually selecting.
repeat while curDocPath is ""
-- we couldn't deduce any path so we start from the top of the subtree.
set curDocPath to select_template_folder_from_within_a_subtree(INITIAL_PATH, starterPath, script_title, FOLDER_NR_IN_PATH)
set curDocPath to getTemplateFolder(INITIAL_PATH, curDocPath, tids, false, true, script_title, FOLDER_NR_IN_PATH)
end repeat
end if
-- So we are finished with getting the folder to use as a template and has qualified as an ok folder to copy from.
-- We now need to deduce which folder to create and copy the files too.
-- We need to decide the parent folder to wich we will copy.
-- and create interwening folders too
-- we check out the current year, if the year is the same.
--years can lag one behind. We copy to the next number of the highest year.
-- if there isnt anything in there, we take the current year number and cretates with
-- the stuff in between the year and the index number.
-- HERE WE DO MAKE UP THE NEW FOLDER NAME.
set sourceChildFolderName to getTextItemOfHFS(curDocPath, FOLDER_NR_IN_PATH, tids)
set originalJobNumber to theJobNumber(sourceChildFolderName)
set theFullYear to year of (current date) as text
set AppleScript's text item delimiters to ""
set shortYear to characters -2 thru -1 of theFullYear as text
set mainSecName to getMainSectionName(INITIAL_PATH, curDocPath, tids)
set subSecName to getSubSectionName(INITIAL_PATH, curDocPath, tids)
-- We must be certain that this path for this year actually exist.
set pathToParentFolder to INITIAL_PATH & mainSecName & ":" & subSecName & ":" & theFullYear & ":"
set PREVIOUS_PATH to pathToParentFolder
-- REVISION: as opposed to previous version, we now use use the number of the template folder
-- as our starting point for making a new number.
set hadFullYear to true
try
pathToParentFolder as alias
on error
set tmp to POSIX path of pathToParentFolder
set res to do shell script "mkdir -p " & quoted form of POSIX path of pathToParentFolder
set hadFullYear to false
-- the do shell script thing.
end try
-- we now must decide the name on the target folder based on wether we had the folder for this year or not.
-- In this part of the code we figure out the new number for the folder that represents the new job created.
set theStemName to getStemName(sourceChildFolderName)
if not hadFullYear then
-- set thisJobNumber to "01"
set thisJobNumber to "1" -- Barbara doesn't use leading zeros
set newFolderName to shortYear & theStemName & thisJobNumber
else
-- REVISION 24.06 : What Barabara needs is a folder number with next higher number.
-- We now use the existing folder number as a starting point and uses the next higher number which is not taken.
(* Old version which just got the next higher number.
tell application "Finder"
set listOfFiles to (sort (every folder in folder pathToParentFolder whose name begins with (shortYear & theStemName)) by name)
end tell
set thisJobNumber to (count of listOfFiles) + 1
set listOfFiles to missing value -- disposes the list.
*)
set thisJobNumber to originalJobNumber
repeat
set thisJobNumber to thisJobNumber + 1
set newFolderName to shortYear & theStemName & thisJobNumber
set DBGnewFullpath to (pathToParentFolder & newFolderName)
try
(pathToParentFolder & newFolderName) as alias
on error
exit repeat
end try
end repeat
-- NB! we postively assume strict consecutive numbered folders here!
-- set newFolderName to shortYear & theStemName & twoDigitStr(thisJobNumber)
-- set newFolderName to shortYear & theStemName & thisJobNumber
end if
-- if this new folder name exists ... then there are something very wrong. we won't destroy anything that is in there.
set pathToTargetFolder to pathToParentFolder & newFolderName
set targetPosix to quoted form of POSIX path of pathToTargetFolder
set sourcePosix to quoted form of POSIX path of curDocPath
do shell script "ditto " & sourcePosix & " " & targetPosix
-- we are finally about to rename the files according to the path
-- will rename every file with new year as opposite to the old
set oldYear to characters 1 thru 2 of sourceChildFolderName as text
tell application "Finder"
set listOfFiles to (sort (every file in folder pathToTargetFolder whose name begins with (oldYear & theStemName)) by name)
end tell
tell application "Finder"
repeat with aFile in listOfFiles
set theFFile to (contents of aFile)
if my isQxdFile((theFFile as alias)) then
set oldName to name of theFFile
-- as far as im concerned we have to change both the year, if that has changed, and the
set AppleScript's text item delimiters to "-"
set lastPart to text item -1 of oldName -- getting a new stemname because it can be different.
-- set stemName to "-" & text items 2 thru -2 of oldName & "-" as text
set AppleScript's text item delimiters to "#"
set fileNumberPart to text item -1 of lastPart
set AppleScript's text item delimiters to ""
set fileNumberPart to thisJobNumber & "#" & fileNumberPart as text
set newName to shortYear & theStemName & fileNumberPart
try
set itsOldeName to name of theFFile as text -- just for logging purposes
set name of theFFile to newName
on error e number n
tell me
activate
display dialog "Im not allowd to do that: " & e & " number " & n
end tell
end try
end if
end repeat
end tell
set AppleScript's text item delimiters to tids
tell application "Finder"
activate
open folder pathToTargetFolder
end tell
end run
on isQxdFile(aFileAlias)
local finfo, utitype, nmext
tell application "System Events"
set finfo to properties of aFileAlias
set nmext to name extension of finfo
set utitype to type identifier of finfo
end tell
if nmext is "qxd" or utitype is "dyn.agk8zuycwmk" then
return true
else
return false
end if
end isQxdFile
on getStemName(aFileName)
local tids, theName
set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, "-"}
set theName to "-" & text items 2 thru -2 of aFileName & "-" as text
set AppleScript's text item delimiters to tids
return theName
end getStemName
-- REVISION: function for returning the number of a folder.
-- Will only work on a folder, since a folder name has a trailing ":"
on theJobNumber(aFolderName)
local tids, jobNumber
set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, "-"}
set jobNumber to text item -1 of aFolderName as text as number
set AppleScript's text item delimiters to tids
return jobNumber
end theJobNumber
-- More general stuff that can be adapted to scripts with similiar functionality. -In order of appearance.
on select_initial_path_qualified_by_a_child_folder(existing_child_folder, main_title)
-- This handler is called the first time the script is beeing run after editing in order to set the initial path
-- to the root of the subtree which all files in the system are within.
-- Returns a chosen path if the path contains the folder EXISTING_FOLDER.
-- Parameters: existing_child_folder : the folder used to qualify the path.
-- main_title :Title of your app/script.
local new_path
set selection_title to main_title & ": Select the parent folder of folder \"" & existing_child_folder & " \""
set ok_path to false
repeat
set new_path to getFolder(selection_title, "/")
tell application "Finder"
if (count of (every folder of folder new_path whose name is existing_child_folder)) is 1 then
set ok_path to true
end if
end tell
if ok_path is true then
return new_path
else
beep 2
tell me
try
set theButton to the button returned of (display dialog "The chosen folder does not contain the folder " & existing_child_folder & " which is how we determine the correct path to our filesystem . Please try again!" with title selection_title buttons {"Exit", "Try Again"} default button 2 cancel button {"Exit"} with icon 2)
on error number -128
tell me to quit
end try
end tell
end if
end repeat
end select_initial_path_qualified_by_a_child_folder
on getCurrentAppsName()
tell application (path to frontmost application as Unicode text) to get name -- from the post :
return the result
end getCurrentAppsName
on getHfsPathofCurrentDocumentFilesFolder(anAppName, theTids)
set theCurfolder to ""
try
tell application named anAppName
if (count of its documents) ≥ 1 then
set docName to POSIX file (path of its front document) as text
set theCurfolder to my getTextItemRangeOfHfs(docName, 1, -2, theTids) & ":"
end if
end tell
end try
return theCurfolder
end getHfsPathofCurrentDocumentFilesFolder
-- This is step two in verifying a folder for using it as a template folder.
-- We have a folder when we arrive here. talkative is important here, as this should be silent if everything goes ok
-- when we have manually chosen a subfolder.
-- ** Doc foldername
-- added for the case that we are in a subfolder within the template folder.
-- the askForConfirmation toggles whether to confirm a path.
-- the displayErrorMessage toggles whether to show an errorMessage or not.
-- we do allways confirm that a path does exist.
on getTemplateFolder(subTreeRoot, docPath, theTids, askForConfirmation, displayErrorMsg, theScriptTitle, Folder_level)
local docFolderName
set docFolderName to getTextItemOfHFS(docPath, Folder_level, theTids)
if docPath contains subTreeRoot and docFolderName is not "" then -- IS THIS NECCESSARY -- YES BECAUSE OF the usage of the finder thing.
-- repeat
-- fckp here when no docFoldername given.
if okFormatOnTemplateFoldersName(docFolderName) and askForConfirmation then
set docPath to getTextItemRangeOfHfs(docPath, 1, Folder_level, theTids)
tell me
activate
try
beep 2
set theButton to the button returned of (display dialog "Do you want to use:\n " & (POSIX path of docPath) & "\nfor a new job?" with title script_title buttons {"Quit", "No", "Ok"} default button 3 cancel button {"Quit"} with icon 1)
on error e number n
tell me to quit
end try
end tell
if theButton is "No" then -- choose from folder above
set docPath to getTextItemRangeOfHfs(docPath, 1, (Folder_level - 2), theTids)
set docPath to select_template_folder_from_within_a_subtree(subTreeRoot, docPath, theScriptTitle, Folder_level)
end if
end if
else
if displayErrorMsg is true and docFolderName is not "" then
tell me
try
beep 2
set theButton to the button returned of (display dialog "The foldername : " & docFolderName & " is not following the naming convention for a folder to copy from." with title theScriptTitle buttons {"Exit", "Choose Template"} default button 2 cancel button {"Exit"} with icon 2)
on error e number n
tell me to quit
end try
end tell
end if
set docPath to "" -- Doc of curapp not within the root filesystem we use; tries with frontmost finder window for better luck.
end if
return docPath
end getTemplateFolder
on getHFsPathOfFindersCurrentFolder()
set theCurfolder to ""
tell application "Finder"
set theSel to get its selection
if (count of its Finder windows) ≥ 1 then
if (theSel) ≠{} then
set tf to item (item 1 of theSel as text)
if kind of tf is "folder" then
set theCurfolder to tf as text
else
set theCurfolder to target of its front window as text
end if
else
set theCurfolder to target of its front window as text
end if
end if
end tell
return theCurfolder
end getHFsPathOfFindersCurrentFolder
-- almost the same handler as getTemplate folder but with the difference that this one really is interactive
-- so we won't have the confirm question.
-- We end up into this one when noNE of our previous tries led to the resolve of a template folder.
-- IF we get here by finder and finder was into the subtree path but not deep enough; we continue from there. See "Run"
-- this handler is called when we can make no assumptions about which folder to copy from.
--if everything is all right then we go silently out of this and over to confirmation.
-- Returns a chosen folder as text from within subtree_root
-- Parameters : subtree_root : the folder which every other folder of this file system is within. Else invalid folder.
-- : section_folder : the folder which contains the starting point for the search for the template folder.
-- : main_title :title of our script.
-- : Folder_level : The depth we will find a valid template folder in the subtree.
on select_template_folder_from_within_a_subtree(subtree_root, section_folder, main_title, Folder_level)
local tids, new_path, docFolderName
set selection_title to main_title & " Select the folder which you will use as a template"
tell me
activate
repeat while true
set new_path to getFolder(selection_title, (POSIX path of section_folder))
if new_path contains subtree_root then
set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, ""}
set new_path to getTextItemRangeOfHfs(new_path, 1, Folder_level, tids) & ""
set docFolderName to getTextItemOfHFS(new_path, Folder_level, tids)
set AppleScript's text item delimiters to tids
if docFolderName is "" then -- it is TOO SHOORT.
try
beep 2
set theButton to the button returned of (display dialog "A: You can't use that folder as a template for new QXD job.\nPlease try again!" with title selection_title buttons {"Exit", "Try Again"} default button 2 cancel button {"Exit"} with icon 2)
on error e number n
tell me to quit
end try
set section_folder to new_path
else if okFormatOnTemplateFoldersName(docFolderName) then
exit repeat
else
try
beep 2
set theButton to the button returned of (display dialog "B: You can't use that folder as a template for new QXD job.\nPlease try again!" with title selection_title buttons {"Exit", "Try Again"} default button 2 cancel button {"Exit"} with icon 2)
on error e number n
tell me to quit
end try
end if
else -- selected folder didn't contain the subtree_root.
try
beep 2
set theButton to the button returned of (display dialog "The chosen folder does not exist within : " & subtree_root & ". Please try again!" with title selection_title buttons {"OK"} default button 1 with icon 2)
on error e number n
tell me to quit
end try
end if
end repeat
end tell
return new_path
end select_template_folder_from_within_a_subtree
-- Lower level handlers i truly regret using the handlers for getting HFSItems!
on getTextItemOfHFS(theText, theItemNUmber, theTids)
set AppleScript's text item delimiters to {":"}
if theItemNUmber ≤ (count of text items of theText) then
set theText to text item theItemNUmber of theText
set theText to theText as text
else
set theText to ""
end if
set AppleScript's text item delimiters to theTids
-- set theText to theText as text
return theText
end getTextItemOfHFS
on getTextItemRangeOfHfs(theText, startItemNo, endItemNo, theTids)
set AppleScript's text item delimiters to {":"}
set theText to text items startItemNo thru endItemNo of theText
set theText to theText as text
set AppleScript's text item delimiters to theTids
-- set theText to theText as text
return theText
end getTextItemRangeOfHfs
on isNumber(aStr)
try
aStr as number
return true
on error
return false
end try
end isNumber
-- its a generic hander for choosing a folder which can ask if your really want to quit, or just quits the script otherwise.
-- calls an on_quit handler for quitting when run as an applet. this can be configured by a variable is_Applet or just
-- uncomment som lines.
on getFolder(aTitle, aStartPath)
local new_path
tell me
activate
repeat while true
try
set new_path to (choose folder with prompt aTitle default location (POSIX file aStartPath) without invisibles) as text
return new_path
on error e number n
if n is -128 then
exit repeat
end if
end try
end repeat
end tell
tell me to quit
end getFolder
on quit
error number -128
-- uncomment line below when saved as a stay open applet.
-- continue quit
end quit
on twoDigitStr(theNumber)
if theNumber ≤ 9 then
return "0" & theNumber
else
return theNumber as text
end if
end twoDigitStr
-- Those functions are very specific for barbaras script.
on getSectionName(aFullHfsFolderName, subtreeHFsName, sectionNumber, theTids)
-- we basically will strip away the subtreeHFsName
local sectionName
set AppleScript's text item delimiters to {":"}
set theCount to (count of text items of aFullHfsFolderName) -- This code works because aFullHfsFolderName ends with : -> gives extra item.
set sectionName to text items theCount thru -1 of subtreeHFsName -- in the count.
set sectionName to text item sectionNumber of sectionName as text
set AppleScript's text item delimiters to theTids
-- set theText to theText as text
return sectionName
end getSectionName
-- this would return a folder on same level as "Outdoors.
on getMainSectionName(aFullHfsFolderName, subtreeHFsName, theTids)
return (getSectionName(aFullHfsFolderName, subtreeHFsName, 1, theTids))
end getMainSectionName
-- get a sectionname, which is a folder on the same level as "Mechanicals"
on getSubSectionName(aFullHfsFolderName, subtreeHFsName, theTids)
return (getSectionName(aFullHfsFolderName, subtreeHFsName, 2, theTids))
end getSubSectionName
-- this function is very specific for barbara's naming conventions.
-- if you want to adapt this code for your own needs and don't have
-- a specific naming conversion: yank out everything and hav it return true.
-- otherwise rewrite.
on okFormatOnTemplateFoldersName(aFolderName)
-- an ok format on a folder name is:
-- first item of name consist of digits only - at least one
-- next to last text item consist of PP ignoring case
-- the last text item first item of name consist of digits only - at least one
local tids, folderItems
if aFolderName is "" then return false
set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, "-"}
set folderItems to text items of aFolderName
set tmpText to text item 1 of text items of aFolderName
try
if not isNumber(tmpText) then error number 3000 -- "10"
set tmpText to text item -2 of folderItems
ignoring case
if tmpText is not "PP" then error number 3000 -- "PP"
end ignoring
set tmpText to text item -1 of folderItems -- "10"
if not isNumber(tmpText) then error number 3000
return true
on error e number n
if n is 3000 then
set AppleScript's text item delimiters to tids
return false
end if
end try
end okFormatOnTemplateFoldersName
Best Regards
McUsr