AppleScript (CO12) to find Images not in any User Collection
***Edit*** 2020/07/05 The migrated version of this script likely will not complile because the Applescript symbols for "not equal", "less than" and "greater than" are not supported in the new forum
Here is an AppleScript to identify images (items) not in any user collection. This has been updated for Capture One 12; it won't run on Capture One 11. It makes use of the Capture One progress indicator, and I've cleaned up a few bits of code here and there.
This script is most useful if you have 1000's of images or 10's of 1000';s of images in a catalog, then items not in any user collection may never be found. Other operations such as splitting a catalog can also end up with a lot of files not in any useser catalog.
This AppleScript can report results by Dialog, by Notifications, through Text Edit, onthe ClipBoard, and by adding the images to a Capture One collection. It has its own GUI to configure its options and settings.
If there are a large number of items, adding the items to a user collection makes it easy to do something with them.
This Applescript can be compiled as an Application and added to the Capture One Scripts menu.
In implementing the GUI, the length of this Applescript has become 10% larger than PhaseOnes limit for a forum posting. Therefore I have broken it into two parts. The part in this posting is the first part, which is all the code specific to this AppleScript. The second part, which will be in a reply to this posting, is a common part which is used by all my AppleScripts.
Both parts should be copied and pasted into one OSX Script Editor document in sequence.
The First Part
## Applescript to search a Capture One Catalog for Images not in any User Collection
## Version 1.12.00 !! NO GUARANTEE OF SUPPORT !! Best effort
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
##
-- ***To Setup
-- Start Script Editor, open a new (blank) file, copy and paste all of this code into the file, compile (hammer symbol) and save.
-- Best if you make "Scripts" folder somewhere in your Documents or Desktop
-- This file is suitable to use as an application in Capture One Pro's Script Menu
-- *** Operation
-- Open the compiled and saved file
-- Open the Script Editor log window, and select the messages tab
-- Select only a small number of variants, from any collection
-- Run the script
-- Results can appear in Notifications, the Script Editor Log and the Text Edit document when the search for each variant is completed, and in the Clipboard and Display Dialog Window when all searching is completed
-- This script does not write or delete any information in the COP Catalog or Session or the image file
--
-- The user may elect to set defaults for enabling or disabling results in Notifications, TextEdit and Script Editor by setting the "enable" variables at beginning of the script
-- The user may change the default amount of reporting by setting the "debugLogLevel" and "ResultsFileMaxDebug" variables at beginning of the script
-- There is a GUI which allows the user to modify settings
-- If you are having some issues, then set debugLogLevel to 3 and send me the results from Script Editors log window, or Text Edit.
## Values in this section are safe to change, within limits indicated. Support is likely but no commitment
use AppleScript version "2.5"
use scripting additions
set debugLogLevel to 0 -- 1...6 Increasing values result in increasing amounts of debug data that takes longer to report
set enableResultsFile to true -- Enables Results in Textedit file (true/false)
set enableResultsByDialog to false -- (true/false)
set enableResultsByClipboard to false -- (true/false)
set enableNotifications to false -- (true/false)
set enableResultsInCollection to true -- (true/false)
set ResultsFileMaxDebug to 3 -- 1...6
set enableFastGUI to true -- (true/false)
set notificationUpdateInterval to 90 -- update interval for notification
set ExcludedSubCollectionNames to {} -- The collections in this list will not be searched
## ***** Not safe to change stuff below this line, unless you have some background in SW development.
## I generally won't help much if you change stuff below this line. I may explain the design intent.
set maxSearchlevel to 100 -- Reduce if you only want to search top level collections or if you start getting stack overflow messages Range 1....... Verified to 100
set cacheMaxLength to 25 -- the number of collections which are saved in the cache. These are the collections where the last images were found.
set SearchDiskFileSystem to false -- (true/false)
set SearchRecentImports to false -- doesn't work in CO 11 (true/false)
set SearchRecentCaptures to false -- (true/false)
set SearchTrash to false -- (true/false)
set enableCacheLevelList to (get debugLogLevel ≥ 2)
tell application "System Events" to set parent_name to name of current application
tell application "Finder" to set script_path to path to me
set Script_Title to (get last word of (get script_path as text))
set SE_Parent to (parent_name = "Script Editor")
set SE_Logging to SE_Parent as boolean
set COPisParent to (get parent_name begins with "Capture One") -- version independent
set Result_DocName to "COP_Image_Search.txt"
set Result_AlbumRoot to "NotInUserCollection"
set Result_ProjectName to "ScriptSearchResults"
set ResultMethod to my InitializeLoqqing3(Result_DocName, Script_Title)
loq_Results2(0, false, ("Started from: " & parent_name & " Action: Find images which are not in any user collection"))
set minCOPversion to "12"
set maxCOPversion to "12"
validateCOP2(minCOPversion, maxCOPversion)
validateCOPdoc3({"catalog"})
validateCOPcollections3()
tell application "Capture One 12" to tell document COPDocName to tell collection "All Images" to set count_All_Images to get count of every image
CO_settingHandler()
if enableResultsInCollection then
set Result_AlbumRoot to "NotInUserCollection"
set Result_ProjectName to "ScriptSearchResults"
set Coll_Init_Text to "Images not in a User Collection"
InitializeResultsCollection(Result_ProjectName, Result_AlbumRoot, Coll_Init_Text)
--tell application "Capture One 12" to tell COPDocRef to set current collection to Ref2ResultAlbum -- causes a problem with the CO progress display
end if
set ExcludedTopCollectionNames to {"In Catalog", "Catalog", "All Images", Result_ProjectName}
if SearchDiskFileSystem then
set ExcludedTopCollectionKinds to {""}
else
set ExcludedTopCollectionKinds to {"catalog folder"}
end if
if not SearchRecentImports then set ExcludedTopCollectionNames to ExcludedTopCollectionNames & "Recent Imports"
if not SearchRecentCaptures then set ExcludedTopCollectionNames to ExcludedTopCollectionNames & "Recent Captures"
if not SearchTrash then set ExcludedTopCollectionNames to ExcludedTopCollectionNames & "Trash"
if not SearchDiskFileSystem then
set max_search_coll_index to topUserCollectionIndex
else
if selectedCollectionMirroredAtTopLast then
set max_search_coll_index to countTopCollections - 1
else
set max_search_coll_index to countTopCollections
end if
end if
set Mark1 to GetTick_Now()
tell application "Capture One 12"
tell document COPDocName to set AllImagesCollection to get the collection "All Images"
tell AllImagesCollection to set {All_Images_Name, All_Images_ID} to get the {name, id} of every image
end tell
--set count_All_Images to get count of All_Images_ID
loq_Results2(3, false, ("In this window " & count_All_Images & " Images"))
if count_All_Images = 0 then
display alert "Catalog is empty, there are no images"
loqqedErrorHalt3("No images in catalog")
end if
set startTime to get time of (get current date)
set search_executed to false
set lastSearchCollctn to ""
set cacheCollectionList to {}
set cacheLevelList to {}
set cacheNameList to {}
set cacheKindList to {}
set cacheLength to 0
set lastSearchLevel to 0
set CacheHitRate to 0
set CacheEfficency to 0
if SE_Parent then
set progress total steps to count_All_Images
set progress completed steps to 0
set progress description to "Searching ..."
end if
tell application "Capture One 12"
set visible of viewer of current document to true
set progress text to "Searching ..."
set progress total units to (get count_All_Images) as integer
set progress completed units to 1
delay 1
end tell
copy startTime to lastnotificationTime
set cacheHitSuccess to 0
set cacheHitAttempts to 0
set hitListFail to 0
set countNotFound to 0
set Mark2 to GetTick_Now()
repeat with imageIndex from 1 to count_All_Images
set searchedImageID to item imageIndex of All_Images_ID
set searchedImageName to item imageIndex of All_Images_Name
if imageIndex > 1 then set CacheHitRate to (100 * cacheHitSuccess / (imageIndex - 1)) as integer
if cacheHitSuccess > 0 then set CacheEfficency to ((10 * cacheHitAttempts / cacheHitSuccess) as integer) / 10
if SE_Parent then
set progress completed steps to imageIndex
if 2 ≤ debugLogLevel then
set progress additional description to ("Image#" & imageIndex & " Cache: " & CacheHitRate & "% - " & CacheEfficency & "x " & cacheLength)
else
set progress additional description to ("Image#" & imageIndex & " " & searchedImageName)
end if
end if
tell application "Capture One 12"
set progress completed units to imageIndex
if 2 ≤ debugLogLevel then
set progress additional text to ("Image#" & imageIndex & " Cache: " & CacheHitRate & "% - " & CacheEfficency & "x " & cacheLength)
else
set progress additional text to ("Image#" & imageIndex & " " & searchedImageName)
end if
end tell
if enableNotifications then
set notificationTime to (get time of (get current date))
if (0 < notificationUpdateInterval) and (notificationTime - lastnotificationTime) ≥ notificationUpdateInterval then
display notification "Searching for Image#" & imageIndex & " of " & count_All_Images & " (Cache Hit rate: " & CacheHitRate & "% - Efficiency" & CacheEfficency & "x Length " & cacheLength & ")"
set lastnotificationTime to notificationTime
end if
end if
loq_Results2(2, false, ("Searching for Image " & imageIndex & ": " & searchedImageID))
set isFound to false
if 2 ≤ debugLogLevel then loq_Results2(5, false, ({"Cache("} & cacheLength & "): " & cacheNameList))
repeat with cachePointer from 1 to cacheLength
if (2 ≤ debugLogLevel) and (cacheLength ≠(get length of cacheCollectionList)) then ¬
loqqedErrorHalt3({"Cache Length Fault", cacheLength, (get length of cacheCollectionList), cacheNameList})
set cacheHitAttempts to cacheHitAttempts + 1
set thisSubCollection to item cachePointer of cacheCollectionList
set subCollName to item cachePointer of cacheNameList
set subCollKind_s to item cachePointer of cacheKindList
if enableCacheLevelList then
set thisSubCollection_level to item cachePointer of cacheLevelList
else
set thisSubCollection_level to 0
end if
set isFound to my search_collection(thisSubCollection, thisSubCollection_level, subCollName, subCollKind_s, true)
if isFound then
if (get debugLogLevel ≥ 2) then loq_Results2(3, false, (searchedImageName & " found in cache " & subCollKind_s & " " & subCollName))
set cacheHitSuccess to cacheHitSuccess + 1
if cachePointer ≠1 then -- if the last hit is not first on the hit list, then move it to first
if cachePointer ≠cacheLength then -- if the last hit is not last on the hit list
set cacheCollectionList to {lastSearchCollctn} & (items 1 thru (cachePointer - 1) of cacheCollectionList) & (items (cachePointer + 1) thru cacheLength of cacheCollectionList)
set cacheNameList to {lastSearchName} & (items 1 thru (cachePointer - 1) of cacheNameList) & (items (cachePointer + 1) thru cacheLength of cacheNameList)
set cacheKindList to {lastSearchKind_s} & (items 1 thru (cachePointer - 1) of cacheKindList) & (items (cachePointer + 1) thru cacheLength of cacheKindList)
if enableCacheLevelList then
set cacheLevelList to {lastSearchLevel} & (items 1 thru (cachePointer - 1) of cacheLevelList) & (items (cachePointer + 1) thru cacheLength of cacheLevelList)
end if
else -- the last hit is last on the hit list
set cacheCollectionList to {lastSearchCollctn} & (items 1 thru (cachePointer - 1) of cacheCollectionList)
set cacheNameList to {lastSearchName} & (items 1 thru (cachePointer - 1) of cacheNameList)
set cacheKindList to {lastSearchKind_s} & (items 1 thru (cachePointer - 1) of cacheKindList)
if enableCacheLevelList then
set cacheLevelList to {lastSearchLevel} & (items 1 thru (cachePointer - 1) of cacheLevelList)
end if
end if
end if
exit repeat
else
loq_Results2(3, false, (searchedImageName & " not found in previous location " & subCollKind_s & " " & subCollName))
set hitListFail to hitListFail + 1
end if
end repeat
if not isFound then
set SearchLevel to 0
set nextSearchLevel to SearchLevel + 1
repeat with c_Counter from 1 to count of everyTopCollection
set thisTopCollection to item c_Counter of everyTopCollection
set topCollName to item c_Counter of namesTopCollections
set topCollKind_s to my convertKind(item c_Counter of kindsTopCollections_p)
if (ExcludedTopCollectionNames does not contain topCollName) and (ExcludedTopCollectionKinds does not contain topCollKind_s) then
set search_executed to true
set isFound to my search_collection(thisTopCollection, nextSearchLevel, topCollName, topCollKind_s, false)
if isFound then
loq_Results2(3, false, (searchedImageName & " found in " & topCollKind_s & " " & topCollName))
if cacheLength < cacheMaxLength then
set beginning of cacheCollectionList to lastSearchCollctn
set beginning of cacheNameList to lastSearchName
set beginning of cacheKindList to lastSearchKind_s
if enableCacheLevelList then
set beginning of cacheLevelList to lastSearchLevel
end if
set cacheLength to (get length of cacheCollectionList)
else
copy cacheNameList to startlist
set cacheCollectionList to {lastSearchCollctn} & items 1 thru (cacheMaxLength - 1) of cacheCollectionList
set cacheNameList to {lastSearchName} & items 1 thru (cacheMaxLength - 1) of cacheNameList
set cacheKindList to {lastSearchKind_s} & items 1 thru (cacheMaxLength - 1) of cacheKindList
if enableCacheLevelList then
set cacheLevelList to {lastSearchLevel} & items 1 thru (cacheMaxLength - 1) of cacheLevelList
end if
if cacheLength ≠(get length of cacheCollectionList) then
log {"Search trap 3", cacheLength, (get length of cacheCollectionList), cacheLength, lastSearchName, cacheNameList}
log {startlist, (get length of cacheCollectionList), cachePointer}
end if
end if
exit repeat
else
loq_Results2(3, false, (searchedImageName & " not found in " & topCollKind_s & " " & topCollName))
end if
end if
end repeat
end if
if not search_executed then -- there are no top level collections to search - don't keep searching
loqqedErrorHalt3("No Top Level Collections to Search")
end if
if isFound then
if debugLogLevel ≥ 2 then
set notification_text to searchedImageName & " was found in a User Collection"
my loq_Results2(2, false, notification_text)
end if
else
if enableResultsInCollection then
tell application "Capture One 12" to ¬
add inside Ref2ResultAlbum variants (get variants of (get first image of AllImagesCollection whose id is searchedImageID))
tell application "Capture One 12" to tell COPDocRef to set current collection to Ref2ResultAlbum
end if
set notification_text to (searchedImageName & " was not found anywhere")
my loq_Results2(0, false, notification_text)
if enableNotifications then display notification notification_text
set countNotFound to countNotFound + 1
end if
end repeat
set Mark3 to GetTick_Now()
tell application "System Events" to set frontmost of process theAppName to true
tell current application to set date_string to (current date) as text
set elapsedTime1s to roundDecimals(Mark2 - Mark1, 3)
set elapsedTime2s to roundDecimals(Mark3 - Mark2, 3)
if count_All_Images > 0 then
set searchTimePerVariant to get ((Mark3 - Mark2) / count_All_Images) -- update the property to provide a time estimate for the next run
set searchTimePerVariantDisplay to roundDecimals(searchTimePerVariant, 3)
else
set searchTimePerVariantDisplay to "--"
end if
loq_Results2(1, false, (return & "SetupTime: " & elapsedTime1s & "sec Process time: " & elapsedTime2s & "sec per Variant: " & searchTimePerVariantDisplay & "sec"))
loq_Results2(0, true, (return & "*** Done on " & date_string & " *** " & countNotFound & " of " & count_All_Images & " variants not found" & return & return))
finalCleanup() -- cleanup large arrays to avoid the situation where the script cannot be saved
## Arrange the windows to show results on top
tell application "System Events" to set frontmost of process theAppName to true
if enableResultsFile then
tell application "System Events" to set frontmost of process "TextEdit" to true
else
tell application "System Events" to set frontmost of process parent_name to true
end if
######################
## Script Specific Handlers
on search_collection(thisCollection, SearchLevel, thisCollName, thisCollKind_s, isCachedSearch)
-- recursive handler to search a collection and it's subcollections
-- if successful, returns a list of paths each as a text string
global debugLogLevel, SE_Logging, SE_Parent, maxSearchlevel, searchedImageID, searchedImageName, COPDocName, ExcludedSubCollectionNames, enableNotifications
global lastSearchCollctn, lastSearchLevel, lastSearchName, lastSearchKind_s, cacheCollectionList
if (ExcludedSubCollectionNames contains thisCollName) then return false
set debugenable to (debugLogLevel ≥ 2)
## if SE_Parent then set progress additional description to thisCollKind & " " & thisCollName
if (not isCachedSearch) and (get (cacheCollectionList contains {thisCollection})) then
## do nothing
loq_Results2(4, false, ("Skipping image search in cached collection " & thisCollKind_s & " " & thisCollName))
set isFound to false
else
tell application "Capture One 12" to tell document COPDocName to tell thisCollection to set searchImageIDhits to count of (get every image whose id is searchedImageID)
set isFound to (get searchImageIDhits > 0)
if debugLogLevel ≥ 5 then
tell application "Capture One 12" to tell document COPDocName to tell thisCollection
set countImages to count of every image
set countVariants to count of every variant
set countSubcollsthisColl to count of every collection
end tell
loq_Results2(5, false, ("In " & thisCollKind_s & " " & thisCollName & " at level " & SearchLevel & " found " & countImages & " images ," & countVariants & " variants ," & countSubcollsthisColl & " collections"))
end if
if isFound then
if debugLogLevel ≥ 3 then
if enableNotifications then display notification searchedImageName & " found in: " & thisCollKind_s & " '" & thisCollName & "'"
loq_Results2(3, false, ("Found " & searchImageIDhits & " hits in " & thisCollKind_s & " " & thisCollName))
end if
--if SE_Parent then set progress description to "Found in " & thisCollKind_s & " " & thisCollName
set lastSearchCollctn to thisCollection
set lastSearchLevel to SearchLevel
set lastSearchName to thisCollName
set lastSearchKind_s to thisCollKind_s
return isFound
end if
end if
if isCachedSearch then return isFound -- do not search under cached collections - can't avoid searching them later
if {"album", "smart album"} contains thisCollKind_s then return isFound -- albums and smart albums do not contain collections
tell application "Capture One 12" to tell thisCollection
set countSubcollsthisColl to count of every collection
if countSubcollsthisColl = 0 then return isFound -- if no subcollections, return
set listSubcollsthisColl to every collection
set {namesSubcollsthisColl, kindsSubcollsthisColl_p} to {name, kind} of every collection
end tell
set nextSearchLevel to SearchLevel + 1
if (nextSearchLevel ≤ maxSearchlevel) then
if debugenable then loq_Results2(5, false, ("Searching Collections in " & thisCollKind_s & " " & thisCollName & " at level " & SearchLevel & " found " & countSubcollsthisColl & " collections"), false, 5)
repeat with c_Counter from 1 to countSubcollsthisColl
set searchColl to item c_Counter of listSubcollsthisColl
set searchCollName to item c_Counter of namesSubcollsthisColl
set searchCollKind_s to convertKind(get item c_Counter of kindsSubcollsthisColl_p)
if (ExcludedSubCollectionNames contains searchCollName) ¬
or ((thisCollKind_s = "project") and (searchCollKind_s = "album")) ¬
then
if debugenable then loq_Results2(4, false, ("Skipping " & searchCollKind_s & " " & searchCollName))
else
if debugenable then loq_Results2(4, false, ("Starting search in " & searchCollName & " (" & searchCollKind_s & ") "))
set isFound to my search_collection(searchColl, nextSearchLevel, searchCollName, searchCollKind_s, false) -- the search
if debugenable then loq_Results2(3, false, ("Result of search in " & searchCollName & " (" & searchCollKind_s & ") is: " & isFound))
if isFound then return isFound
end if
end repeat
end if
## isFound is FALSE
return isFound
end search_collection
on finalCleanup()
## clean up the large arrays to avoid a large stack that may prevent AppleScript from saving the script
global All_Images_Name, All_Images_ID, everyTopCollection, namesTopCollections, namesTopCollections, kindsTopCollections_p, cacheCollectionList, cacheLevelList, earch_name_list, cacheKindList
## Cleanup Memory to avoid Script Editor having a stack overflow error on saving; this data will be dirty on the next run anyway
set All_Images_Name to {}
set All_Images_ID to {}
set everyTopCollection to {}
set namesTopCollections to {}
set kindsTopCollections_p to {}
set cacheCollectionList to {}
set cacheLevelList to {}
set cacheNameList to {}
set cacheKindList to {}
end finalCleanup
on CO_settingHandler()
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## Initialisation Handler for scripts using Capture One Pro
## Collects and sets up information about the Script settings for the GUI handler
global parent_name, Script_Title, enableFastGUI, debugLogLevel, ResultsFileMaxDebug, count_All_Images, notificationUpdateInterval
global theAppName, copVersion, COPDocName, COPDocKind_s, COPDocRef
global namesTopCollections, bottomUserCollectionIndex, topUserCollectionIndex, selectedCollectionRef, nameSelectedCollection, selectedCollectionIsUser, kindSelectedCollection_s
global SearchDiskFileSystem, SearchRecentImports, SearchRecentCaptures, SearchTrash, ExcludedSubCollectionNames, maxSearchlevel
global SE_Logging, SE_Parent, enableResultsFile, enableResultsByDialog, enableResultsByClipboard, enableNotifications, ResultMethod, Result_DocName, enableResultsInCollection
set basic_setting_list to {}
set end of basic_setting_list to {SettingName:(get copVersion & " in " & COPDocKind_s & " "" & COPDocName & """)}
set end of basic_setting_list to {SettingName:(get " "" & "All Images" & "" with " & count_All_Images & " Images")}
set end of basic_setting_list to {SettingName:"Debug Level", SettingValue:debugLogLevel}
set end of basic_setting_list to {SettingName:"Results by " & ResultMethod}
if settingGUI_Bypass(basic_setting_list) then
loq_Results2(0, false, joinListToString(basic_setting_list, return))
return
end if
set helpdebugLogLevel to "the amount of debug info reported"
set helpmaxSearchlevel to "lowest subcollection level which is searched"
set helpExcludedCollection to "collections with these names will not be searched"
set helpResultsInCollection to "images not in any user collection will be added to the results album"
set helpFastGUI to "enable faster GUI response, with less help text"
set nameUserCollections to {nameSelectedCollection} & (get items bottomUserCollectionIndex thru topUserCollectionIndex of namesTopCollections)
if selectedCollectionIsUser then tell application "Capture One 12" to tell selectedCollectionRef to ¬
set nameUserCollections to nameUserCollections & (get name of every collection)
set initialLogging to {(get enableNotifications as boolean), (get enableResultsByDialog as boolean), (get enableResultsFile as boolean), (get enableResultsByClipboard as boolean), (get SE_Logging as boolean)}
set setting_list to {}
set end of setting_list to {SettingID:1, SettingName:"Parent Application", SettingValue:(""" & parent_name & """), UserSet:false}
set end of setting_list to {SettingID:2, SettingName:"Document", SettingValue:(COPDocKind_s & " "" & COPDocName & """), UserSet:false}
set end of setting_list to {SettingID:3, SettingName:"Collection", SettingValue:""All Images" with " & count_All_Images & " Images", UserSet:false}
set end of setting_list to {SettingID:4, SettingName:"Search Managed Files", SettingHelp:"", SettingValue:false, UserSet:true, SettingClass:"Boolean"}
set end of setting_list to {SettingID:11, SettingName:"Collections not searched", SettingHelp:"", SettingValue:(a reference to ExcludedSubCollectionNames), UserSet:true, SettingClass:"List_Text", SettingLimited:"List&Free", SettingLimit_L:nameUserCollections}
set end of setting_list to {SettingID:12, SettingName:"Debug Level", SettingHelp:helpdebugLogLevel, SettingValue:(a reference to debugLogLevel), UserSet:true, SettingClass:"Integer", SettingLimited:"Min_Max", SettingLimit_L:{0, 6}}
set end of setting_list to {SettingID:13, SettingName:"Highest Debug Level in Result File", SettingHelp:"", SettingValue:(a reference to ResultsFileMaxDebug), UserSet:true, SettingClass:"Integer", SettingLimited:"Min_Max", SettingLimit_L:{1, 6}}
set end of setting_list to {SettingID:14, SettingName:"Maximum Search Level", SettingHelp:helpmaxSearchlevel, SettingValue:(a reference to maxSearchlevel), UserSet:true, SettingClass:"Boolean"}
set end of setting_list to {SettingID:15, SettingName:"Enable Results in Collection", SettingHelp:helpResultsInCollection, SettingValue:(a reference to enableResultsInCollection), UserSet:true, SettingClass:"Boolean"}
set end of setting_list to {SettingID:16, SettingName:"Enable Results in Text Edit", SettingHelp:"", SettingValue:(a reference to enableResultsFile), UserSet:true, SettingClass:"Boolean"}
set end of setting_list to {SettingID:17, SettingName:"Enable Results in Dialog", SettingHelp:"", SettingValue:(a reference to enableResultsByDialog), UserSet:true, SettingClass:"Boolean"}
set end of setting_list to {SettingID:18, SettingName:"Enable Results in Clipboard", SettingHelp:"", SettingValue:(a reference to enableResultsByClipboard), UserSet:true, SettingClass:"Boolean"}
set end of setting_list to {SettingID:19, SettingName:"Enable Results in Notifications", SettingHelp:"", SettingValue:(a reference to enableNotifications), UserSet:true, SettingClass:"Boolean"}
set end of setting_list to {SettingID:20, SettingName:"Results Logged by Script Editor", SettingValue:(a reference to SE_Logging), UserSet:SE_Parent, SettingClass:"Boolean"}
set end of setting_list to {SettingID:22, SettingName:"Notification Update Interval", SettingHelp:"", SettingValue:(a reference to notificationUpdateInterval), UserSet:true, SettingClass:"Integer", SettingLimited:"Min", SettingLimit_L:{15}}
set end of setting_list to {SettingID:23, SettingName:"Enable Fast GUI Response", SettingHelp:helpFastGUI, SettingValue:(a reference to enableFastGUI), UserSet:true, SettingClass:"Boolean"}
set settings_display_string to settingGUI(setting_list)
if ((not (get enableNotifications as boolean)) and (not (get enableResultsByDialog as boolean)) and (not (get enableResultsFile as boolean)) and (not (get SE_Logging as boolean))) then
display alert "You have turned off all methods of reporting results!! " message "Turning on results by Dialog Display" as critical giving up after 30
set enableResultsByDialog to true
end if
if (initialLogging ≠{(get enableNotifications as boolean), (get enableResultsByDialog as boolean), (get enableResultsFile as boolean), (get enableResultsByClipboard as boolean), (get SE_Logging as boolean)}) then
set ResultMethod to my InitializeLoqqing3(Result_DocName, Script_Title)
end if
set settings_display_string to settings_display_string & "Result Logging Methods: " & ResultMethod & return
loq_Results2(1, false, (return & "Settings:" & return & settings_display_string))
end CO_settingHandler
-
The Second (Common) Part
This applescript is a common set of functions (handles) used by all my AppleScripts. Several other postings might refer to this one. Copy and paste this code at the end of the other Applescript.
Note that this is a version 2 months newer than that in my my last posting. Use this version with the script section, above, not the older version.
###########################
## Capture One General Handlers Version 2018/12/02
on validateCOP2(minCOPversionstr, maxCOPversionstr)
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General purpose initialisation handler for scripts using Capture One Pro
## Extract and check basic information about the Capture One application
global debugLogLevel, theAppName, copVersion, copDetailedVersion, enableNotifications
tell application "System Events"
set COPProcList to every process whose name contains "Capture One" and background only is false
if debugLogLevel ≥ 2 then
set COPProcNameList to name of every process whose name contains "Capture One" and background only is false
my loq_Results2(2, false, ("COP Processes:" & COPProcNameList))
end if
end tell
if (count of COPProcList) = 0 then my loqqed_Error_Halt3(true, "COP is not running")
if (count of COPProcList) ≠1 then my loqqed_Error_Halt3(true, "Unexpected: >1 COP instances")
set theAppRef to item 1 of COPProcList
tell application "System Events" to set theAppName to ((get name of theAppRef) as text)
tell application "System Events" to set copDetailedVersion to get version of my application theAppName
tell application "Capture One 12" to set copVersion to (get app version)
if debugLogLevel ≥ 2 then
tell application "System Events"
my loq_Results2(2, false, ("All Processes: " & (get my joinListToString((get name of every process whose background only is false), ", "))))
end tell
loq_Results2(2, false, ("theAppName: " & theAppName))
loq_Results2(2, false, ("COP Version: " & copVersion))
loq_Results2(2, false, ("COP Detailed Version: " & copDetailedVersion))
end if
set numCOPversion to (splitStringToList((word -1 of copVersion), "."))
set minCOPversion to (splitStringToList(minCOPversionstr, "."))
set maxCOPversion to (splitStringToList(maxCOPversionstr, "."))
set digit_mult to 1000000
set Version_digit to 0
repeat with dig_ctr from 1 to count of numCOPversion
set digit_mult to digit_mult / 100
set Version_digit to Version_digit + (get item dig_ctr of numCOPversion as integer) * digit_mult
end repeat
set digit_mult to 1000000
set min_digit to 0
repeat with dig_ctr from 1 to count of minCOPversion
set digit_mult to digit_mult / 100
set min_digit to min_digit + (get item dig_ctr of minCOPversion as integer) * digit_mult
end repeat
set digit_mult to 1000000
set max_digit to 0
set digit_count to count of maxCOPversion
repeat with dig_ctr from 1 to digit_count
set digit_mult to digit_mult / 100
set max_digit to max_digit + (get item dig_ctr of maxCOPversion as integer) * digit_mult
if (dig_ctr = digit_count) then set max_digit to max_digit + digit_mult
end repeat
if (Version_digit < min_digit) or (Version_digit ≥ max_digit) then
if enableNotifications then display notification "COP Version is unsupported"
my loqqed_Error_Halt3(true, "This COP Version is " & copDetailedVersion & " - the supported COP versions are from " & minCOPversionstr & " to " & maxCOPversionstr)
end if
tell application "System Events" to set frontmost of process theAppName to true
loq_Results2(1, false, ("Capture One version: " & copDetailedVersion))
end validateCOP2
on validateCOPdoc3(COP_kind_list)
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General purpose initialisation handler for scripts using Capture One Pro
## Extract and check basic information about the current document
global debugLogLevel, COPDocName, COPDocKind_s, COPDocRef, theAppName
try
tell application "Capture One 12" to set COPDocName to get name of current document
on error
loqqed_Error_Halt3(true, "The Script could not retrieve the Capture One document - Perhaps a Capture One Dialog window is open?")
end try
tell application "Capture One 12"
set current_doc_kind_p to (get kind of current document)
set current_doc_ref_list to (get every document whose name is COPDocName and kind is current_doc_kind_p)
set number_of_hits to count of current_doc_ref_list
end tell
set COPDocKind_s to convertKind(current_doc_kind_p)
if COPDocKind_s = "session" then set COPDocName to text 1 thru ((offset of "." in COPDocName) - 1) of COPDocName
loq_Results2(2, false, ("Is: " & COPDocKind_s & " was: " & (get current_doc_kind_p as text)))
loq_Results2(2, false, ("Found Documents: " & number_of_hits))
if COP_kind_list does not contain COPDocKind_s then loq_Results2(0, false, (COPDocName & " is a " & COPDocKind_s & " -- unsupported type of document"))
if number_of_hits = 0 then
loqqed_Error_Halt3(false, "Could not find find " & COPDocKind_s & COPDocName)
error "Could not find find " & COPDocKind_s & COPDocName
else if number_of_hits > 1 then
loqqed_Error_Halt3(false, "Found more than one " & COPDocKind_s & " with the name " & COPDocName)
error "Found more than one " & COPDocKind_s & " with the name " & COPDocName
else
tell application "Capture One 12" to set COPDocRef to item 1 of current_doc_ref_list
end if
loq_Results2(1, false, ("CO Document: " & COPDocKind_s & " " & COPDocName))
end validateCOPdoc3
on validateCOPcollections3()
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General purpose initialisation handler for scripts using Capture One Pro
## Extract basic information regarding the current collection, and thhe top level collections
global debugLogLevel, COPDocName, COPDocKind_s, COPDocRef, enableNotifications
global everyTopCollection, namesTopCollections, kindsTopCollections_p, countTopCollections, selectedCollectionRef, selectedCollectionIndex, kindSelectedCollection_s, nameSelectedCollection
global selectedCollectionMirroredAtTopLast, selectedCollectionIsUser, bottomUserCollectionIndex, topUserCollectionIndex
-- selectedCollectionMirroredAtTopLast replaces selectedCollectionAtTopEnd
-- bottomUserCollectionIndex, topUserCollectionIndex replaces indexInCatalog
tell application "Capture One 12" to tell COPDocRef
set selectedCollectionRef to get current collection
if (missing value = selectedCollectionRef) then
set current collection to collection 1
set selectedCollectionRef to get current collection
end if
set {nameSelectedCollection, kindSelectedCollection_p} to {name, kind} of selectedCollectionRef
set everyTopCollection to get every collection
set {namesTopCollections, kindsTopCollections_p} to {name, kind} of every collection
end tell
set kindSelectedCollection_s to convertKind(kindSelectedCollection_p)
set countTopCollections to count of namesTopCollections
repeat with collectionCounter from 1 to countTopCollections
if (nameSelectedCollection = item collectionCounter of namesTopCollections) and (kindSelectedCollection_s = convertKind(item collectionCounter of kindsTopCollections_p)) then
set selectedCollectionIndex to collectionCounter
exit repeat
end if
end repeat
if COPDocKind_s = "catalog" then
repeat with collectionCounter from countTopCollections to 1 by -1
if ("in Catalog" = item collectionCounter of namesTopCollections) and ("smart album" = convertKind(item collectionCounter of kindsTopCollections_p)) then
set topUserCollectionIndex to collectionCounter - 1
exit repeat
end if
end repeat
repeat with collectionCounter from 1 to countTopCollections
if ("Trash" = item collectionCounter of namesTopCollections) and ("smart album" = convertKind(item collectionCounter of kindsTopCollections_p)) then
set bottomUserCollectionIndex to collectionCounter + 1
exit repeat
end if
end repeat
set selectedCollectionMirroredAtTopLast to (selectedCollectionIndex = countTopCollections) and ({"catalog folder", "favorite"} does not contain convertKind(last item of kindsTopCollections_p))
set selectedCollectionIsUser to (selectedCollectionMirroredAtTopLast or ((selectedCollectionIndex ≥ bottomUserCollectionIndex) and (selectedCollectionIndex ≤ topUserCollectionIndex)))
else if COPDocKind_s = "session" then
repeat with collectionCounter from countTopCollections to 1 by -1
if ("favorite" ≠convertKind(item collectionCounter of kindsTopCollections_p)) then
set topUserCollectionIndex to collectionCounter
exit repeat
end if
end repeat
repeat with collectionCounter from 1 to countTopCollections
if ("Trash" = item collectionCounter of namesTopCollections) and ("favorite" = convertKind(item collectionCounter of kindsTopCollections_p)) then
set bottomUserCollectionIndex to collectionCounter + 1
exit repeat
end if
end repeat
set selectedCollectionMirroredAtTopLast to false
set selectedCollectionIsUser to ({"project", "album", "group", "smart album"} contains kindSelectedCollection_s)
end if
end validateCOPcollections3
on validateCOPvariant(theVariant, theVariantID)
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General Purpose Handler for scripts using Capture One Pro
## Capture One identifies a variant as "variant n of collrction m of ..."
## If the user changes the order of variant of a collection, "variant n" refers to a different variant, and a running script will behave unpredicatably
## The usefulness of this handler depends on some other part of the script obtaining a list of the variant IDs when the script starts
## The handler is provided with the variant reference and the original variant ID.
## This handler obtains the variant's ID from Capture One, and compares that to the original variant ID. If there is a difference, the script is halted
## This handler should be called when processing of a variant starts, and just before any operation that change something of the variant
global COPisParent, enableNotifications
if COPisParent then return -- when Capture One is running a script, the GUI is locked ... no need to check
tell application "Capture One 12" to tell theVariant to if theVariantID = id then return
loqqed_Error_Halt3(true, "Variant ID Mismatch, most likely due to manipulation of Capture One by the user while the script is running")
end validateCOPvariant
on convertKind(kind_p)
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General Purpose Handler for scripts using Capture One Pro
## Release 11 of Capture One returns the chevron form of the property "kind" when AppleScript is run as an Application
## This script converts the chevron form into the expected string
## Code looks ugly but executes in under 0.25 msec
set kind_s to kind_p as text
if (get text 1 of kind_s) ≠"«" then return kind_s -- Check if the first character is a Chevron. If not, return the same string
## minimum 6 characters for valid logic. Normally 19
if 6 > length of kind_s then loqqed_Error_Halt3(true, "convertKind received an unexpected Kind string: " & kind_s)
set code_start to (get length of kind_s) - 4
set kind_code to get (text code_start thru (code_start + 3) of kind_s)
set kind_type to get text 1 thru 2 of kind_code
set fail_flag to false
if kind_type = "CC" then ## Collection Kinds
if kind_code = "CCpj" then
set kind_res to "project"
else if kind_code = "CCgp" then
set kind_res to "group"
else if kind_code = "CCal" then
set kind_res to "album"
else if kind_code = "CCsm" then
set kind_res to "smart album"
else if kind_code = "CCfv" then
set kind_res to "favorite"
else if kind_code = "CCff" then
set kind_res to "catalog folder"
else
set fail_flag to true
end if
else if kind_type = "CL" then ## Layer Kinds
if kind_code = "CLbg" then
set kind_res to "background"
else if kind_code = "CLnm" then
set kind_res to "adjustment"
else if kind_code = "CLcl" then
set kind_res to "clone"
else if kind_code = "CLhl" then
set kind_res to "heal"
else
set fail_flag to true
end if
else if kind_type = "CR" then ## Watermark Kinds
if kind_code = "CRWn" then
set kind_res to "none"
else if kind_code = "CRWt" then
set kind_res to "textual"
else if kind_code = "CRWi" then
set kind_res to "imagery"
else
set fail_flag to true
end if
else if kind_type = "CO" then ## Document Kinds
if kind_code = "COct" then
set kind_res to "catalog"
else if kind_code = "COsd" then
set kind_res to "session"
else
set fail_flag to true
end if
else
set fail_flag to true
end if
if fail_flag then loqqed_Error_Halt3(true, "convertKind received an unexpected Kind string: " & kind_s)
return kind_res
end convertKind
on InitializeResultsCollection(nameResultProject, nameResultAlbumRoot, Coll_Init_Text)
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General Purpose Handler for scripts using Capture One Pro
## Sets up a project and albums for collecting images
global debugLogLevel, COPDocRef, Ref2ResultAlbum, enableNotifications
tell application "Capture One 12" to tell COPDocRef
if not (exists collection named (get nameResultProject)) then
set ref2ResultProject to make new collection with properties {kind:project, name:nameResultProject}
else
if ("project" = my convertKind(kind of (get collection named nameResultProject))) then
set ref2ResultProject to collection named nameResultProject
else
my loqqed_Error_Halt3(true, ("A collection named "" & nameResultProject & "" already exists, and it is not a project."))
end if
end if
end tell
set coll_ctr to 1
set nameResultAlbum to nameResultAlbumRoot & "_" & (get short date string of (get current date)) & "_"
repeat
tell application "Capture One 12" to tell ref2ResultProject
if not (exists collection named (get nameResultAlbum & coll_ctr)) then
set nameResultAlbum to (get nameResultAlbum & coll_ctr)
set Ref2ResultAlbum to make new collection with properties {kind:album, name:nameResultAlbum}
exit repeat
else
set coll_ctr to coll_ctr + 1
end if
end tell
end repeat
if enableNotifications then display notification (Coll_Init_Text & " " & nameResultProject & ">" & nameResultAlbum)
loq_Results2(1, false, (Coll_Init_Text & " " & nameResultProject & ">" & nameResultAlbum))
end InitializeResultsCollection
#################
## General Handlers Version 2018/08/26
on settingGUI_Bypass(theSettingList)
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General Purpose handler that provides a bypass to settingGUI()
####
## The Setting record
## SettingName Name of the Setting (text)
## SettingValue Value of the Setting (text)
global debugLogLevel, parent_name, Script_Title
tell application "System Events" to set frontmost of process parent_name to true
set settings_display_string to ""
repeat with theSetting_r in theSettingList
set settings_display_string to settings_display_string & theSetting_r's SettingName
try
set theValueString to joinListToString(theSetting_r's SettingValue, ", ")
if 0 < length of theValueString then set settings_display_string to settings_display_string & ": " & theValueString
end try
set settings_display_string to settings_display_string & return
end repeat
set debugButtonName to "Configure"
set legendString to return & "Click "" & debugButtonName & "" to configure settings; "OK" to continue"
try
set dialog_result to display dialog settings_display_string & legendString with title "Settings for " & Script_Title ¬
buttons {"Cancel", "OK", debugButtonName} default button "OK" cancel button "Cancel"
on error errmess
my loqqed_Error_Halt3(true, "User Cancelled the Script")
end try
return ("OK" = (get button returned of dialog_result))
end settingGUI_Bypass
on settingGUI(theSettingList)
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General Purpose handler that provides a user interface to control AppleScript settings
#############
## The Setting record
## SettingID ID of the setting (integer)
## SettingName Name of the Setting (text)
## SettingHelp Help Text for the Setting
## SettingValue Value or Reference to the Global Variable which holds the option value (reference)
## UserSet True if the user can set this variable (boolean)
## SettingClass Class of the data representing the option {Boolean, Text, List_Text, Integer, Real} (text)
## SettingLimited How are the option values constrained {false, List&Free, List, Min_Max, Min, Max}
## SettingLimit_L The list of permissible values of the option (List of Text, List of Integer, List of Real, List of [Min],[Max])
#############
global debugLogLevel, parent_name, Script_Title, enableFastGUI
copy {} to settings_ID_List
repeat with theSetting_r in theSettingList -- Duplicate setting IDs cause subtle and bizarre errors - catch this problem
set theSettingID to (get (theSetting_r's SettingID) as text)
if settings_ID_List contains theSettingID then error "Duplicate Setting ID!! " & theSettingID
set the end of settings_ID_List to theSettingID
end repeat
repeat
tell application "System Events" to set frontmost of process parent_name to true
set settings_display_string to ""
repeat with theSetting_r in theSettingList
set settings_display_string to settings_display_string & (theSetting_r's SettingName) & ": " & joinListToString((get contents of theSetting_r's SettingValue), ";")
if theSetting_r's UserSet then set settings_display_string to settings_display_string & " *"
set settings_display_string to settings_display_string & return
end repeat
set legendString to return & "Click "Edit" to edit items with an *asterisk*" & return & "Click "OK" to continue without editing settings"
try
set dialog_result to display dialog settings_display_string & legendString with title "Settings for " & Script_Title ¬
buttons {"Cancel", "OK", "Edit"} default button "OK" cancel button "Cancel"
on error errmess
my loqqed_Error_Halt3(true, "User Cancelled the Script")
end try
if "OK" = (get button returned of dialog_result) then exit repeat -- Exit 3 of 3 from the handler
set userCancelled to false
repeat while userCancelled is false
copy {} to settings_choose_List
repeat with theSetting_r in theSettingList
##!!!## Do NOT screw with this line, or the list of text editing starts losing information ##!!!##
if theSetting_r's UserSet then ¬
copy (get ((theSetting_r's SettingID as text) & ": " & (theSetting_r's SettingName as text) & ": " & joinListToString((contents of theSetting_r's SettingValue), "; "))) to ¬
the end of settings_choose_List
end repeat
set ChooseResult to (get choose from list settings_choose_List with title "Settings for " & Script_Title with prompt "Select an Item to Edit" cancel button name "Done" OK button name "Edit")
if ChooseResult = false then exit repeat --main exit from this repeat loop
set selectedSetting to item 1 of ChooseResult
set selectedSettingID to get ((item 1 of (splitStringToList(selectedSetting, ":"))) as integer)
set settingFound to false
repeat with selectedSetting_r in theSettingList
if selectedSettingID = (get selectedSetting_r's SettingID) then
set settingFound to true
exit repeat
end if
end repeat
if not settingFound then
loqqed_Error_Halt3(false, "Unexpected value found while finding setting: " & selectedSettingID)
error "SW Error 1"
end if
set selectedSettingName to selectedSetting_r's SettingName as text
set setting_Class to selectedSetting_r's SettingClass as text
set hasFreeInput to true
set hasSettingLimitType to false
set hasSettingMin to false
set hasSettingMax to false
set hasSettingLimitList to false
set theSettingMin to missing value
set theSettingMax to missing value
set theSettingLimitList to missing value
try
set SettingLimitType to get selectedSetting_r's SettingLimited as text -- this works even if the class is boolean
set hasSettingLimitType to true
if false = (get SettingLimitType as boolean) then set hasSettingLimitType to false
end try
if hasSettingLimitType then
if ("Min_Max" = SettingLimitType) then
set hasFreeInput to true
set hasSettingMin to true
set hasSettingMax to true
set theSettingMin to get item 1 of (get selectedSetting_r's SettingLimit_L as list)
set theSettingMax to get item 2 of (get selectedSetting_r's SettingLimit_L as list)
else if ("Min" = SettingLimitType) then
set hasFreeInput to true
set hasSettingMin to true
set theSettingMin to get item 1 of (get selectedSetting_r's SettingLimit_L as list)
else if ("Max" = SettingLimitType) then
set hasFreeInput to true
set hasSettingMax to true
set theSettingMax to get item 1 of (get selectedSetting_r's SettingLimit_L as list)
else if ("List" = SettingLimitType) then
set hasFreeInput to false
set hasSettingLimitList to true
set theSettingLimitList to (get selectedSetting_r's SettingLimit_L) as list
else if ("List&Free" = SettingLimitType) then
set hasFreeInput to (not enableFastGUI)
set hasSettingLimitList to true
set theSettingLimitList to (get selectedSetting_r's SettingLimit_L) as list
else
loqqed_Error_Halt3(false, "Unexpected value found while evaluating Setting Limit. Type: " & SettingLimitType & " Length: " & (length of selectedSetting_r's SettingLimit_L))
error "SW Error 4"
end if
end if
set settingAddTitle to "Enter New Value"
set settingChooseTitle to "Select New Item"
set settingDeleteTitle to "Select Item to be removed"
set settingEditPrompt to "for setting #" & selectedSettingID & ": " & selectedSettingName
set settingDeletePrompt to "from setting #" & selectedSettingID & ": " & selectedSettingName
if (not enableFastGUI) and (0 < (count of selectedSetting_r's SettingHelp)) then set settingEditPrompt to ¬
settingEditPrompt & return & " (" & (get (selectedSetting_r's SettingHelp) as text) & ")"
set userCancelled to false
set hasNewSettingValue to false
if setting_Class = "Boolean" then
set selectedSettingValue to (selectedSetting_r's SettingValue) as boolean
if enableFastGUI then
set the contents of selectedSetting_r's SettingValue to not selectedSettingValue
else
set ChooseResult to (get choose from list {"True", "False"} with prompt settingEditPrompt with title settingChooseTitle OK button name "Select" default items {(get selectedSettingValue as text)})
if ChooseResult = false then
set userCancelled to true
else
set newSettingValue to item 1 of ChooseResult
if "True" = (get newSettingValue) then
set the contents of selectedSetting_r's SettingValue to true
set hasNewSettingValue to true
else if "False" = (get newSettingValue) then
set the contents of selectedSetting_r's SettingValue to false
set hasNewSettingValue to true
else
loqqed_Error_Halt3(false, "Unexpected value found while editing Boolean: " & newSettingValue)
error "SW Error 2"
end if
end if
end if
else if setting_Class = "Integer" then
set selectedSettingValue to (get selectedSetting_r's SettingValue) as integer
if hasSettingLimitList then
set ChooseResult to (get choose from list theSettingLimitList with prompt settingEditPrompt with title settingChooseTitle OK button name "Select")
if ChooseResult = false then
set userCancelled to true
else
if (0 ≤ (count of ChooseResult)) then set contents of selectedSetting_r's SettingValue to (get item 1 of ChooseResult) as integer
set hasNewSettingValue to true
set selectedSettingValue to (get item 1 of ChooseResult) as integer
end if
end if
if hasFreeInput then
set settingEditPrompt to settingEditPrompt & return
if hasSettingMin then set settingEditPrompt to settingEditPrompt & "Minimum: " & (get theSettingMin as integer)
if hasSettingMax then
if hasSettingMin then set settingEditPrompt to settingEditPrompt & " "
set settingEditPrompt to settingEditPrompt & "Maximum: " & (get theSettingMax as integer)
end if
repeat while not hasNewSettingValue
try
set dialog_result to display dialog settingEditPrompt with title settingAddTitle default answer selectedSettingValue
on error
set userCancelled to true
exit repeat
end try
try
if 0 < (length of text returned of dialog_result) then
set newSettingValue to get (text returned of dialog_result) as integer
else
copy (get selectedSettingValue as integer) to newSettingValue
end if
set hasNewSettingValue to true
on error
display dialog (settingEditPrompt & return & "Unable to convert " & (get text returned of dialog_result) & " to an integer") with title "Press OK to try again" buttons {"OK"} default button "OK"
end try
if hasNewSettingValue then
if (hasSettingMin and (newSettingValue < theSettingMin)) or (hasSettingMax and (newSettingValue > theSettingMax)) then
set hasNewSettingValue to false
display dialog (settingEditPrompt & return & "The value " & newSettingValue & " is below the Min or above the Max") with title "Press OK to try again" buttons {"OK"} default button "OK"
else
set contents of selectedSetting_r's SettingValue to newSettingValue
end if
end if
end repeat
end if
else if setting_Class = "Real" then
set selectedSettingValue to (get selectedSetting_r's SettingValue) as real
if hasSettingLimitList then
set ChooseResult to (get choose from list theSettingLimitList with prompt settingEditPrompt with title settingChooseTitle OK button name "Select")
if ChooseResult = false then
set userCancelled to true
else
if (0 ≤ (count of ChooseResult)) then set contents of selectedSetting_r's SettingValue to (get item 1 of ChooseResult) as real
set hasNewSettingValue to true
set selectedSettingValue to (get item 1 of ChooseResult) as real
end if
end if
if hasFreeInput then
set settingEditPrompt to settingEditPrompt & return
if hasSettingMin then set settingEditPrompt to settingEditPrompt & "Minimum: " & (get theSettingMin as real)
if hasSettingMax then
if hasSettingMin then set settingEditPrompt to settingEditPrompt & " "
set settingEditPrompt to settingEditPrompt & "Maximum: " & (get theSettingMax as real)
end if
repeat while not hasNewSettingValue
try
set dialog_result to display dialog settingEditPrompt with title settingAddTitle default answer selectedSettingValue
on error
set userCancelled to true
exit repeat
end try
try
if 0 < (length of text returned of dialog_result) then
set newSettingValue to get (text returned of dialog_result) as real
else
copy (get selectedSettingValue as real) to newSettingValue
end if
set hasNewSettingValue to true
on error
display dialog (settingEditPrompt & return & "Unable to convert " & (get text returned of dialog_result) & " to an real") with title "Press OK to try again" buttons {"OK"} default button "OK"
end try
if hasNewSettingValue then
if (hasSettingMin and (newSettingValue < theSettingMin)) or (hasSettingMax and (newSettingValue > theSettingMax)) then
set hasNewSettingValue to false
display dialog (settingEditPrompt & return & "The value " & newSettingValue & " is below the Min or above the Max") with title "Press OK to try again" buttons {"OK"} default button "OK"
else
set contents of selectedSetting_r's SettingValue to newSettingValue
end if
end if
end repeat
end if
else if setting_Class = "Text" then
set selectedSettingValue to (get selectedSetting_r's SettingValue) as text
if hasSettingLimitList then
set ChooseResult to (get choose from list theSettingLimitList with prompt settingEditPrompt with title settingChooseTitle OK button name "Select")
if ChooseResult = false then
set userCancelled to true
else
if (0 ≤ (count of ChooseResult)) then
set contents of selectedSetting_r's SettingValue to (get item 1 of ChooseResult)
set hasNewSettingValue to true
set selectedSettingValue to (get item 1 of ChooseResult) as text
end if
end if
end if
if hasFreeInput then
try
set dialog_result to display dialog settingEditPrompt with title settingAddTitle default answer selectedSettingValue
set contents of selectedSetting_r's SettingValue to get (text returned of dialog_result)
set hasNewSettingValue to true
on error
set userCancelled to true
end try
end if
else if setting_Class = "List_Text" then
copy ((get contents of selectedSetting_r's SettingValue) as list) to selectedSettingValueList
if (count of selectedSettingValueList) = 0 then
set deleteList to {}
else
set deleteList to (get choose from list selectedSettingValueList ¬
with prompt (settingDeletePrompt & return & "(empty selection ok)") ¬
with title settingDeleteTitle OK button name "Remove" cancel button name "Skip" with multiple selections allowed and empty selection allowed)
if (deleteList = false) then
set deleteList to {}
else
if (count of deleteList) > 0 then set hasNewSettingValue to true
end if
end if
set newSettingValueList to {}
repeat with theValueString in selectedSettingValueList
if deleteList does not contain theValueString then copy (get theValueString as text) to the end of newSettingValueList
end repeat
set addedSettingValueList to {}
if hasSettingLimitList then
set ChooseResult to (get choose from list theSettingLimitList with prompt settingEditPrompt ¬
with title settingChooseTitle OK button name "Add" with empty selection allowed and multiple selections allowed)
if ChooseResult = false then
set userCancelled to true
else
set addedSettingValueList to (get ChooseResult as list)
end if
end if
if hasFreeInput then
try
set dialog_result to display dialog settingEditPrompt with title settingAddTitle default answer ""
set addedSettingValueList to addedSettingValueList & splitStringToList((get text returned of dialog_result), ";")
on error
set userCancelled to true
end try
end if
if userCancelled then
set hasNewSettingValue to false
else
repeat with theValueString in addedSettingValueList
set theValueString to removeLeadingTrailingSpaces(theValueString)
## Don't add zero length strings and strings already in the list
if (0 < (count of theValueString)) and ¬
newSettingValueList does not contain theValueString then
copy (get theValueString as text) to the end of newSettingValueList
set hasNewSettingValue to true
end if
end repeat
if hasNewSettingValue and (newSettingValueList ≠selectedSettingValueList) then
set the contents of selectedSetting_r's SettingValue to {}
copy (get newSettingValueList as list) to contents of selectedSetting_r's SettingValue
end if
end if
else
loqqed_Error_Halt3(false, "Unexpected class found while editing Boolean: " & setting_Class)
error "SW Error 3"
end if
end repeat
if enableFastGUI then exit repeat
end repeat
set settings_display_string to ""
repeat with theSetting_r in theSettingList
set settings_display_string to settings_display_string & (get SettingName of theSetting_r) & ": " & (get contents of (SettingValue of theSetting_r)) & return
end repeat
return settings_display_string ## Exit point
end settingGUI
on InitializeLoqqing3(DocName_Ext, sourceTitle)
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General purpose handler to set up Text Editor document for logging results
global debugLogLevel, Script_Title, Result_Doc_ref, SE_Logging, enableResultsFile, enableResultsByDialog, enableResultsByClipboard, DialogTextList, enableNotifications
global initEnableResultsByDialog, initEnableResultsByClipboard, initEnableNotifications
tell current application to set date_string to (current date) as text
set LogMethods to {}
set LogHeader to (sourceTitle & " results on " & date_string)
if enableResultsFile then
set end of LogMethods to DocName_Ext
set targetFileWasCreated to false
set ResultDocIsOpen to false
## Check if TextEdit is already open and has the document open
tell application "System Events" to set TextEditlist to get background only of every application process whose name is "TextEdit"
if (0 < (count of TextEditlist)) and not item 1 of TextEditlist then
if (DocName_Ext is in (get name of documents of application "TextEdit")) then
tell application "TextEdit" to set Result_Doc_ref to document DocName_Ext
set ResultDocIsOpen to true
end if
end if
if not ResultDocIsOpen then
-- create the document and the folder if necessary
-- Do not use finder to test for the file existence because it has a bug that ignores leading 0's
-- https://www.macscripter.net/viewtopic.php?id=45178
set target_folder_parent_a to alias (get path to desktop folder as text)
set target_folder_parent_p to get POSIX path of target_folder_parent_a
set target_folder_name to "ScriptReports"
set target_folder_p to (target_folder_parent_p & target_folder_name)
set Result_Doc_Path_p to target_folder_p & "/" & DocName_Ext
try
set Result_Doc_Path_a to (get alias POSIX file Result_Doc_Path_p)
on error
try
set target_folder_a to (get alias POSIX file target_folder_p) --x1
on error
tell application "Finder" to set newFolder to make new folder at target_folder_parent_a with properties {name:target_folder_name}
set target_folder_a to newFolder as alias
end try
tell application "Finder" to set newFile to make new file at target_folder_a with properties {name:DocName_Ext}
set Result_Doc_Path_a to newFile as alias
set targetFileWasCreated to true
end try
set First_line to ("Created by " & Script_Title & " on " & date_string)
tell application "TextEdit" -- open the document and add the first line if empty
activate
set Result_Doc_ref to open Result_Doc_Path_a
set ResultDocIsOpen to true -- For consistency
tell text of Result_Doc_ref
if targetFileWasCreated then
set paragraph 1 to First_line & return & return
tell me to if 2 ≤ debugLogLevel then log Result_Doc_Path_p & ": " & First_line
else
try
if (0 = (count of paragraphs)) then set paragraph 1 to First_line & return & return
on error
set paragraph 1 to First_line & return & return
end try
end if
end tell
end tell
end if
tell application "TextEdit" to tell text of Result_Doc_ref to ¬
set paragraph (1 + (count paragraphs)) to return & LogHeader & return
end if
if enableResultsByDialog then
set end of LogMethods to "Display Dialog"
try
initEnableResultsByDialog
set DialogTextList to DialogTextList & ""
set initEnableResultsByDialog to false
on error
set DialogTextList to {LogHeader}
set initEnableResultsByDialog to true
end try
end if
if enableResultsByClipboard then
set end of LogMethods to "Clipboard"
try
initEnableResultsByClipboard
set initEnableResultsByClipboard to false
on error
set the clipboard to LogHeader
set initEnableResultsByClipboard to true
end try
end if
if SE_Logging then -- if Script Editor logging, then open the Log History window
tell application "System Events" to tell application process "Script Editor"
if (get name of windows) does not contain "log History" then
click menu item "Log History" of menu "Window" of menu bar 1
end if
end tell
set end of LogMethods to " Script Editor Log"
end if
if enableNotifications then set end of LogMethods to "Notifications"
set LogMethods_S to joinListToString(LogMethods, ", ")
loq_Results2(2, false, ("Results by " & LogMethods_S))
return LogMethods_S
end InitializeLoqqing3
on loq_Results2(thisLogDebugLevel, MakeFront, log_Text)
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General purpose handler for logging results
## log results if the debug level of the message is below the the threshold set by debugLogLevel
## log the results by whatever mechanism is ebabled - {Script Editor Log, Text Editor Log, Display Dialog}
global Result_Doc_ref, debugLogLevel, SE_Logging, parent_name, ResultsFileMaxDebug, enableResultsFile, enableResultsByDialog, enableResultsByClipboard, DialogTextList, enableNotifications
if thisLogDebugLevel > debugLogLevel then return
set log_Text_S to joinListToString(log_Text, ", ")
if enableResultsFile and ((thisLogDebugLevel ≤ ResultsFileMaxDebug) or not SE_Logging) then
tell application "TextEdit" to tell text of Result_Doc_ref to ¬
set paragraph (1 + (count paragraphs)) to ((log_Text_S as text) & return)
tell application "System Events" to if MakeFront then set frontmost of process "TextEdit" to true
end if
if enableResultsByDialog and (1 ≥ thisLogDebugLevel) then
set DialogTextList to DialogTextList & log_Text_S
tell application "System Events" to set frontmost of process parent_name to true
display dialog joinListToString(DialogTextList, return)
end if
if enableResultsByClipboard and (1 ≥ thisLogDebugLevel) then set the clipboard to ((get the clipboard) & return & (log_Text_S as text))
if SE_Logging then log (log_Text_S as text)
end loq_Results2
on loqqed_Error_Halt3(createErrorHere, error_text)
## General purpose handler for logging during script termination
##
## found an error somewhere, so now we exit in a controlled fashion
## set createError to "false" to create a local error instead of here
global debugLogLevel, Script_Title, enableNotifications
tell current application to set date_string to (current date) as text
finalCleanup()
if enableNotifications then display notification error_text
if createErrorHere then
loq_Results2(0, true, ("Script "" & Script_Title & "" has halted at " & date_string & return & "Reason: " & error_text & return & return))
error error_text
else
loq_Results2(0, true, ("Script "" & Script_Title & "" is exitting at " & date_string & "Reason: " & error_text & return))
end if
end loqqed_Error_Halt3
on splitStringToList(theString, theDelim)
## Public Domain
set astid to AppleScript's text item delimiters
try
set AppleScript's text item delimiters to theDelim
set theList to text items of theString
on error
set AppleScript's text item delimiters to astid
end try
set AppleScript's text item delimiters to astid
return theList
end splitStringToList
to joinListToString(theList, theDelim)
## Public Domain
set theString to ""
set astid to AppleScript's text item delimiters
try
set AppleScript's text item delimiters to theDelim
set theString to theList as string
on error
set AppleScript's text item delimiters to astid
end try
set AppleScript's text item delimiters to astid
return theString
end joinListToString
on removeLeadingTrailingSpaces(theString)
## Public Domain, modified
repeat while theString begins with space
-- When the string is only 1 character long, then it is exactly 1 space, and the next operation willl crash. So return ""
if 1 ≥ (count of theString) then return ""
set theString to text 2 thru -1 of theString
end repeat
repeat while theString ends with space
set theString to text 1 thru -2 of theString
end repeat
return theString
end removeLeadingTrailingSpaces
on getIndexOf(theItem, theList)
## credits Emmanuel Levy
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to return
set theList to return & theList & return
set AppleScript's text item delimiters to astid
try
-1 + (count (paragraphs of (text 1 thru (offset of (return & theItem & return) in theList) of theList)))
on error
0
end try
end getIndexOf
on roundToQuantum(thisValue, quantum)
## Public domain author unknown
return (round (thisValue / quantum) rounding to nearest) * quantum
end roundToQuantum
on roundDecimals(n, numDecimals)
## Nigel Garvey, Macscripter
set x to 10 ^ numDecimals
tell n * x to return (it div 0.5 - it div 1) / x
end roundDecimals
on MSduration(firstTicks, lastTicks)
## Public domain
## returns duration in ms
## inputs are durations, in seconds, from GetTick's Now()
return (round (10000 * (lastTicks - firstTicks)) rounding to nearest) / 10
end MSduration
on GetTick_Now()
## From MacScripter Author "Jean.O.matiC"
## returns duration in seconds since since 00:00 January 2nd, 2000 GMT, calculated using computer ticks
script GetTick
property parent : a reference to current application
use framework "Foundation" --> for more precise timing calculations
on Now()
return (current application's NSDate's timeIntervalSinceReferenceDate) as real
end Now
end script
return GetTick's Now()
end GetTick_Now0 -
Here is an Applescript that runs over 10X as fast at the previous version. It has a completely different approach.
It finsishes my catalog with 16000 images and 1200 collections in 33 seconds. I haven't had a chance to add result reporting etc to it yet.
It will probably not run as an application until I add the "kindconverter" to it.
use AppleScript version "2.5"
use scripting additions
set debugEnable to false
tell application "Capture One 12" to set thisDocRef to get current document
log traceDocument(thisDocRef)
return
on traceDocument(thisDocRef)
global theVariantListSize, theVariantList, debugEnable
local theCollRefList, theMaxID, countVariants, theCollRefList, theCollKindList, theCollUserList, theCollCollRefList, collCtr, thisCollCollList, thisCollRef, thisCollKind, thisIDStringList
## The main Collection which is the document.
## ignore the remaining inputs
## bulk collection of information improves speed
tell application "Capture One 12" to tell thisDocRef to set {theCollRefList, theCollKindList, theCollUserList, theCollCollRefList} to ¬
{every collection, every collection's kind, every collection's user, every collection's collection}
## The variant list is created, but nothing gets changed here
tell application "Capture One 12" to tell thisDocRef to tell collection "All Images" to set countVariants to (get count of variants)
makeVariantList(countVariants)
repeat with collCtr from 1 to (count of theCollUserList)
if (get contents of theCollUserList's item collCtr) then
set thisCollCollList to (get contents of theCollCollRefList's item collCtr) --- a list
set thisCollRef to (get contents of theCollRefList's item collCtr) -- a CO reference
tell application "Capture One 12" to tell thisDocRef
set thisCollKind to (get (get contents of theCollKindList's item collCtr) as text) -- convert a kind to string
set thisIDStringList to get id of variants of thisCollRef
end tell
traceCollection(thisCollRef, thisCollKind, thisCollCollList, thisIDStringList)
end if
end repeat
local everyVariantIDList, notFoundIdList, notFoundIndexList, notFoundNameList, vctr, theVariantID, theVariantNameList, anIndex
tell application "Capture One 12" to tell thisDocRef to tell collection "All Images" to set everyVariantIDList to get id of variants
set notFoundIndexList to {}
repeat with vctr from 1 to countVariants
if not (get theVariantList's item (get (contents of everyVariantIDList's item vctr) as integer)) then copy (contents of vctr) to end of notFoundIndexList
end repeat
set everyVariantIDList to {} -- control AppleScript's memory utilization
set theVariantList to {} -- control AppleScript's memory utilization
set theVariantListSize to 0
set notFoundNameList to {}
if 0 < (count of notFoundIndexList) then
tell application "Capture One 12" to tell thisDocRef to tell collection "All Images" to tell variants to set {theVariantNameList, theVariantExtList} to {name of it, extension of parent image of it}
repeat with anIndex in notFoundIndexList
copy ((theVariantNameList's item (get contents of anIndex)) & "." & (theVariantExtList's item (get contents of anIndex))) to end of notFoundNameList
end repeat
end if
return notFoundNameList
end traceDocument
on traceCollection(ThisRef, theCollKind, theCollRefList, theIDStringList)
global theVariantListSize, theVariantList, debugEnable
## index the images if the collection holds images
local anIDString, theVariantID
tell application "Capture One 12" to tell ThisRef to if (0 < (get count of variants)) then
repeat with anIDString in theIDStringList
set theVariantID to (get contents of anIDString as integer)
if theVariantID > theVariantListSize then makeVariantList(theVariantID)
set theVariantList's item theVariantID to true
end repeat
end if
if (0 = (get count of theCollRefList)) or ("project" = theCollKind) then return -- don't search below this collection if it is a project, or has no collections
## bulk collection of information improves speed
tell application "Capture One 12" to tell ThisRef to set {theCollCollRefList, theCollKindList, theCollVariantIDList} to get {collection, kind, id of variant} of every collection
local collCtr
repeat with collCtr from 1 to (get count of theCollRefList)
traceCollection((get contents of theCollRefList's item collCtr), (get (contents of theCollKindList's item collCtr) as text), (get contents of theCollCollRefList's item collCtr), (get contents of theCollVariantIDList's item collCtr))
end repeat
end traceCollection
on makeVariantList(newImageListSize)
global theVariantListSize, theVariantList, debugEnable
try
theVariantList
on error
set theVariantList to {}
set theVariantListSize to 0
end try
if newImageListSize > theVariantListSize then
set theVariantList to theVariantList & makeList3((newImageListSize - theVariantListSize + 24), false) -- make some extras to avoid calling this repeatedly
set theVariantListSize to get count of theVariantList
end if
end makeVariantList
on makeList3(listLength, theElement)
-- Note that the theElement can even be a List
if listLength = 0 then return {}
if listLength = 1 then return {theElement}
set theList to {theElement}
repeat while (count of theList) < listLength / 2
copy contents of theList to ListB
copy theList & ListB to theList
end repeat
copy contents of theList to ListB
return (theList & items 1 thru (listLength - (count of ListB)) of ListB)
end makeList30 -
Here is an update that will run as an application and can be added to Capture One's Script Menu.
I generates notifications and copies the results to the clipboard.
DO NOT USE See posting below for a better version
use AppleScript version "2.5"
use scripting additions
set debugEnable to false
tell application "Capture One 12" to set thisDocRef to get current document
set notFoundNameList to searchDocument(thisDocRef)
set countNotFound to (count of notFoundNameList)
if 0 < countNotFound then
set displayString to (get countNotFound as text) & " Images not found in a User Collection: " & joinListToString(notFoundNameList, ",")
else
set displayString to "All Images found in a User Collection"
end if
set the clipboard to displayString
display notification displayString
return
on searchDocument(thisDocRef)
## Copyright 2019 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## Seach each user collection, and scheck the results
global theImageListSize, theImageList, debugEnable
local theCollRefList, countImages, theCollRefList, theCollKindList, theCollUserList, theCollCollRefList, thisCollCollList, theDocName
## bulk collection of information improves speed
## Do not collect Image ID lists as this will include All Images, Recent Imports and Catalog Folders (every image 3x or 4x)
tell application "Capture One 12" to tell thisDocRef to ¬
set {theCollRefList, theCollUserList, theCollCollRefList, theCollKindList} to ¬
{every collection, every collection's user, every collection's collection, my convertKindList(every collection's kind)}
## The image list is created, but nothing gets changed here
tell application "Capture One 12" to tell thisDocRef to tell collection "All Images" to set countImages to (get count of images)
set {theImageList, theImageListSize} to {{}, 0} -- initialise and clear the Image list
makeImageList(countImages)
tell application "Capture One 12" to tell thisDocRef to set theDocName to its name
display notification "Finding Images not in a user collection: " & countImages & " images of " & theDocName
local thisCollRef, thisCollImageIDList, collCtr
repeat with collCtr from 1 to (count of theCollUserList)
if (get contents of theCollUserList's item collCtr) then
set thisCollRef to (get contents of theCollRefList's item collCtr) -- a CO reference
tell application "Capture One 12" to tell thisDocRef to set thisCollImageIDList to get id of images of thisCollRef
searchCollection(thisCollRef, (theCollKindList's item collCtr), (theCollCollRefList's item collCtr), thisCollImageIDList)
end if
end repeat
display notification "Half done ..."
local everyImageIDList, notFoundIdList, notFoundIndexList, notFoundNameList, vctr, theImageID, theImageNameList, anIndex
tell application "Capture One 12" to tell thisDocRef to tell collection "All Images" to set {everyImageIDList, everyImageNameList} to {id of images, name of images}
set notFoundNameList to {}
repeat with vctr from 1 to countImages
if not (get theImageList's item (get (everyImageIDList's item vctr) as integer)) then ¬
copy (everyImageNameList's item vctr) to end of notFoundNameList
end repeat
set {theImageList, theImageListSize} to {{}, 0} -- clear large lists to control AppleScript's memory utilization
return notFoundNameList
end searchDocument
on searchCollection(ThisRef, theCollKind, theCollRefList, theIDStringList)
## Copyright 2019 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
global theImageListSize, theImageList, debugEnable
## index the images if the collection holds images
local anIDString, theImageID
tell application "Capture One 12" to tell ThisRef to if (0 < (get count of images)) then
repeat with anIDString in theIDStringList
set theImageID to (get anIDString as integer)
if theImageID > theImageListSize then makeImageList(theImageID)
set theImageList's item theImageID to true
end repeat
end if
if (0 = (get count of theCollRefList)) or ("project" = theCollKind) then return -- don't search below this collection if it is a project, or has no collections
## bulk collection of information improves speed
## This handler only handles user collections, so every subcollection is also a user collection
tell application "Capture One 12" to tell ThisRef to set {theCollCollRefList, theCollImageIDList, theCollKindList} to ¬
{every collection's collection, every collection's image's id, my convertKindList(every collection's kind)}
local collCtr
repeat with collCtr from 1 to (get count of theCollRefList)
searchCollection((theCollRefList's item collCtr), (theCollKindList's item collCtr), (theCollCollRefList's item collCtr), (theCollImageIDList's item collCtr))
end repeat
end searchCollection
on makeImageList(newImageListSize)
global theImageListSize, theImageList, debugEnable
## make some extras to avoid calling this repeatedly
set newImageListSize to newImageListSize + 24
if 0 < theImageListSize then
if newImageListSize > theImageListSize then set theImageList to theImageList & makeList3((newImageListSize - theImageListSize), false)
else
set theImageList to makeList3(newImageListSize, false)
end if
set theImageListSize to get count of theImageList
end makeImageList
on makeList3(listLength, theElement)
-- Note that the theElement can even be a List
if listLength = 0 then return {}
if listLength = 1 then return {theElement}
set theList to {theElement}
repeat while (count of theList) < listLength / 2
copy contents of theList to ListB
copy theList & ListB to theList
end repeat
copy contents of theList to ListB
return (theList & items 1 thru (listLength - (count of ListB)) of ListB)
end makeList3
on joinListToString(theList, theDelim)
## Public Domain
set theString to ""
set astid to AppleScript's text item delimiters
try
set AppleScript's text item delimiters to theDelim
set theString to theList as string
on error
set AppleScript's text item delimiters to astid
end try
set AppleScript's text item delimiters to astid
return theString
end joinListToString
on convertKindList(kind_list)
## Copyright 2019 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General Purpose Handler for scripts using Capture One Pro
## Capture One returns the chevron form of the "kind" property when AppleScript is run as an Application
## Unless care is taken to avoid text conversion of this property, this bug breaks script decisions based on "kind"
## This script converts text strings with the chevron form to strings with the expected text form
## The input may be a single string, a single enum, a list of strings or a list of enums
## The code is not compact but runs very fast, between 60us and 210us per item
set kind_s_list to {}
set input_is_list to ("list" = (get (class of kind_list) as text))
if input_is_list then
if ("text" = (get (class of item 1 of kind_list) as text)) and ¬
("«" ≠(get text 1 of item 1 of kind_list)) then return kind_list -- quick pass through if first item is OK
repeat with theItem in kind_list
tell application "Capture One 12" to set the end of kind_s_list to (get theItem as text)
end repeat
if ("«" ≠(get text 1 of item 1 of kind_s_list)) then return kind_s_list
else
if ("text" = (get (class of kind_list) as text)) and ¬
("«" ≠(get text 1 of kind_list)) then return kind_list -- quick pass through if first item is OK
tell application "Capture One 12" to set kind_s1 to (get kind_list as text)
if "«" ≠(get text 1 of kind_s1) then return kind_s1 -- quick pass through if input is OK
set kind_s_list to {kind_s1}
end if
set fail_flag to false
set code_start to -5
set kind_list to {}
repeat with Kind_s_item in kind_s_list
if "«" ≠(get text 1 of Kind_s_item) then loqqed_Error_Halt3(true, "convertKindList received an unexpected Kind string: " & Kind_s_item)
set kind_code to get (text code_start thru (code_start + 3) of Kind_s_item)
set kind_type to get (text code_start thru (code_start + 1) of Kind_s_item)
if kind_type = "CC" then ## Collection Kinds
if kind_code = "CCpj" then
set the end of kind_list to "project"
else if kind_code = "CCgp" then
set the end of kind_list to "group"
else if kind_code = "CCal" then
set the end of kind_list to "album"
else if kind_code = "CCsm" then
set the end of kind_list to "smart album"
else if kind_code = "CCfv" then
set the end of kind_list to "favorite"
else if kind_code = "CCff" then
set the end of kind_list to "catalog folder"
else
set fail_flag to true
end if
else if kind_type = "CL" then ## Layer Kinds
if kind_code = "CLbg" then
set the end of kind_list to "background"
else if kind_code = "CLnm" then
set the end of kind_list to "adjustment"
else if kind_code = "CLcl" then
set the end of kind_list to "clone"
else if kind_code = "CLhl" then
set the end of kind_list to "heal"
else
set fail_flag to true
end if
else if kind_type = "CR" then ## Watermark Kinds
if kind_code = "CRWn" then
set the end of kind_list to "none"
else if kind_code = "CRWt" then
set the end of kind_list to "textual"
else if kind_code = "CRWi" then
set the end of kind_list to "imagery"
else
set fail_flag to true
end if
else if kind_type = "CO" then ## Document Kinds
if kind_code = "COct" then
set the end of kind_list to "catalog"
else if kind_code = "COsd" then
set the end of kind_list to "session"
else
set fail_flag to true
end if
else
set fail_flag to true
end if
if fail_flag then loqqed_Error_Halt3(true, "convertKindList received an unexpected Kind string: " & Kind_s_item)
end repeat
if input_is_list then
return kind_list
else
return item 1 of kind_list
end if
end convertKindList0 -
Great work, guys. 0 -
Im using it. 0 -
The script in my previous posting above has a few bugs in it.
I have updated the script to remove the bugs, and also allowed it to run with Capture One 20.
I have tested it with Capture One 20.02 on OSX 10.14.6 by running it from Script Editor.
If you have successes or failures running the script, please post here.
We will also add it to the Capture One Github respsoitory as we get that going.
Note: Its not necessary to manually change the version of CaptureOne 20 in the Tell Application Statements to run the this script under CaptureOne 12 or any other version. When you laod the script into Script Editor, and some version of Capture One is running, the version is automatically updated. There are no text strings like "Capture One 20" in the script that wouuld require changing.
I plan to make a further update so that the found images can be put into a special user collection, add a progress bar, make it operate more easily with future versions, and add the latest version of my logging utilities.
But here is a version with bugs removed, for now.
[color=#FF0080:1v2pvj0n]Updated to version 12.07[/color:1v2pvj0n]
- added code to exclude the Project "ScriptSearchResults", and any other User Collections the user may add.
## Applescript to search a Capture One Catalog for variants not in a User Collection
## Version 1.12.07 NOTICE Best effort Support, no warranty
## Copyright 2020 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
##
## [1.12.07] added code to exclude the Project "ScriptSearchResults"
## [1.12.07] added global variable "ExcludedCollectionNames" to allow the user to add more exluded user collections
-- ***To Setup
-- Start Script Editor, open a new (blank) file, copy and paste both parts into one Script Editor Document, compile (hammer symbol) and save.
-- Best if you make "Scripts" folder somewhere in your Documents or Desktop
-- This file is suitable to use as an application in Capture One Pro's Script Menu
-- *** Operation in Script Editor
-- Open the compiled and saved file
-- Open the Script Editor log window, and select the messages tab
-- Select only a small number of variants, from any collection
-- Run the script
-- Results can appear in Notifications, the Script Editor Log and the Text Edit document when the search for each variant is completed, and in the Clipboard and Display Dialog Window when all searching is completed
--
-- The user may elect to set defaults for enabling or disabling results in Notifications, TextEdit and Script Editor by setting the "enable" variables at beginning of the script
-- The user may change the default amount of reporting by setting the "debugLogLevel" and "ResultsFileMaxDebug" variables at beginning of the script
-- If you are having some issues, then set debugLogLevel to 3 and send me the results from Script Editors log window, or Text Edit.
## Values in this section are safe to change, within limits indicated. Support is likely but no commitment
use AppleScript version "2.5"
use scripting additions
set debugLogLevel to 0 -- 1...6 Set to 1 to allow changing other settings. Increasing Values result in increasing amounts of debug data that takes longer to report
set enableResultsFile to true -- Enables Results in Textedit file (true/false)
set enableResultsByDialog to false -- (true/false)
set enableResultsByClipboard to false -- (true/false)
set enableNotifications to false -- (true/false)
set ResultsFileMaxDebug to 3 -- 1...6
set maxProgressLevel to 3 -- Levels shown in Script Editor's progress bar 1...6
set maxSearchlevel to 100 -- Reduce if you only want to search top level collections or if you start getting stack overflow messages Range 1....... Verified to 100
set enableFastGUI to true -- (true/false)
set ExcludedCollectionNames to {} -- Collections in this list will not be searched, nor will their collections
## ***** Not safe to change stuff below this line, unless you have some background in SW development.
## I generally won't help much if you change stuff below this line. I may explain the design intent.
tell application "Finder" to get count of windows
tell application "TextEdit" to get count of windows
tell application "System Events" to set parent_name to name of current application
set script_path to (path to me) as text
set astid to AppleScript's text item delimiters
try
set AppleScript's text item delimiters to ":"
if (script_path ends with ":") then
set Script_Title to text item -2 of script_path
else
set Script_Title to text item -1 of script_path
end if
end try
set AppleScript's text item delimiters to astid
--set Script_Title to (get name of me)
set SE_Parent to (parent_name = "Script Editor")
set SE_Logging to SE_Parent as boolean
set COPisParent to (get parent_name begins with "Capture One") -- version independent
set Result_DocName to "CO_Image_Search.txt"
set Result_ProjectName to "ScriptSearchResults"
set ResultMethod to my InitializeLoqqing3(Result_DocName, Script_Title)
loq_Results2(0, false, ("Started from: " & parent_name & " Action: Find Images not in a User Collection"))
set minCOPversion to "12"
set maxCOPversion to "21"
validateCOP2(minCOPversion, maxCOPversion)
validateCOPdoc3({"catalog", "session"})
tell application "Capture One 20" to set thisDocRef to get current document
set notFoundNameList to searchDocument(thisDocRef)
set countNotFound to (count of notFoundNameList)
if 0 < countNotFound then
set displayString to (get countNotFound as text) & " Images not found in a User Collection: " & joinListToString(notFoundNameList, ", ")
else
set displayString to "All Images found in a User Collection"
end if
loq_Results2(0, true, displayString)
return
## Script Specific Handlers ########
on searchDocument(thisDocRef)
## Copyright 2019 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## Seach each user collection, and scheck the results
global theImageListSize, theImageList, debugLogLevel, ExcludedCollectionNames
local theCollRefList, countImages, theCollKindList, theCollCollRefList, thisCollCollList, theDocName, theCollNameList
set ExcludedCollectionNames to ExcludedCollectionNames & {"ScriptSearchResults"}
## bulk collection of information improves speed
tell application "Capture One 20" to tell thisDocRef to tell (every collection whose user is true) to ¬
set {theCollRefList, theCollCollRefList, theCollKindList, theCollNameList} to ¬
{it, its collection, my convertKindList(its kind), its name}
## The image list is created, but nothing gets changed here
tell application "Capture One 20" to tell thisDocRef to tell collection "All Images" to set countImages to (get count of images)
set {theImageList, theImageListSize} to {{}, 0} -- initialise and clear the Image list
makeImageList(countImages)
tell application "Capture One 20" to tell thisDocRef to set theDocName to its name
display notification "Finding Images not in a user collection: " & countImages & " images of " & theDocName
display notification "Checking each collection"
local thisCollRef, thisCollImageIDList, collCtr
repeat with collCtr from 1 to (count of theCollRefList)
set thisCollRef to (get contents of theCollRefList's item collCtr) -- a CO reference
tell application "Capture One 20" to tell thisDocRef to set thisCollImageIDList to get id of images of thisCollRef
indexCollection(thisCollRef, (theCollKindList's item collCtr), (theCollCollRefList's item collCtr), thisCollImageIDList, (theCollNameList's item collCtr))
end repeat
display notification "Done Checking Collections, Now the analysis .."
local everyImageIDList, notFoundIdList, notFoundIndexList, notFoundNameList, vctr, theImageID, theImageNameList, anIndex
tell application "Capture One 20" to tell thisDocRef to tell collection "All Images" to set {everyImageIDList, everyImageNameList} to {id of images, name of images}
set notFoundNameList to {}
repeat with vctr from 1 to countImages
set thisImageID to (get (everyImageIDList's item vctr) as integer)
if thisImageID > theImageListSize then
copy (everyImageNameList's item vctr) to end of notFoundNameList
else
if not (get theImageList's item thisImageID) then ¬
copy (everyImageNameList's item vctr) to end of notFoundNameList
end if
end repeat
set {theImageList, everyImageNameList, everyImageIDList} to {null, null, null} -- clear large lists to control AppleScript's memory utilization
return notFoundNameList
end searchDocument
on indexCollection(ThisRef, theCollKind, theCollRefList, theIDStringList, thisCollName)
## Copyright 2019 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
global theImageListSize, theImageList, debugLogLevel, ExcludedCollectionNames
## index the images if the collection holds images
local anIDString, theImageID
if ExcludedCollectionNames contains thisCollName then return
tell application "Capture One 20" to tell ThisRef to if (0 < (get count of images)) then
repeat with anIDString in theIDStringList
set theImageID to (get anIDString as integer)
if theImageID > theImageListSize then my makeImageList(theImageID)
set theImageList's item theImageID to true
end repeat
end if
local theCollCollRefList, theCollImageIDList, theCollKindList, theCollNameList
if (0 = (get count of theCollRefList)) or ("project" = theCollKind) then return -- don't search below this collection if it is a project, or has no subcollections
## This handler only handles user collections, no need to check subcollections
tell application "Capture One 20" to tell ThisRef to set {theCollCollRefList, theCollImageIDList, theCollKindList, theCollNameList} to ¬
{every collection's collection, every collection's image's id, my convertKindList(every collection's kind), every collection's name}
local collCtr
repeat with collCtr from 1 to (get count of theCollRefList)
indexCollection((theCollRefList's item collCtr), (theCollKindList's item collCtr), (theCollCollRefList's item collCtr), (theCollImageIDList's item collCtr), (theCollNameList's item collCtr))
end repeat
return
end indexCollection
on makeImageList(newImageListSize)
global theImageListSize, theImageList, debugLogLevel
## make some extras to avoid calling this repeatedly
set newImageListSize to newImageListSize + 24
if 0 < theImageListSize then
if newImageListSize > theImageListSize then
set theImageList to theImageList & makeList3((newImageListSize - theImageListSize), false)
if debugLogLevel ≥ 2 then log "Increased image list from " & theImageListSize & " to " & newImageListSize
end if
else
set theImageList to makeList3(newImageListSize, false)
end if
set theImageListSize to get count of theImageList
end makeImageList
on finalCleanup()
global theImageList, everyImageNameList, everyImageIDList
set {theImageList, everyImageNameList, everyImageIDList} to {null, null, null}
end finalCleanup
###########################################################################################################################
## Capture One General Handlers Version 2018/12/16
on validateCOP2(minCOPversionstr, maxCOPversionstr)
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General purpose initialisation handler for scripts using Capture One Pro
## Extract and check basic information about the Capture One application
global debugLogLevel, theAppName, copVersion, copDetailedVersion, enableNotifications
tell application "System Events"
set COPProcList to every process whose name begins with "Capture One" and background only is false
if debugLogLevel ≥ 2 then
set COPProcNameList to name of every process whose name begins with "Capture One" and background only is false
my loq_Results2(2, false, ("COP Processes:" & COPProcNameList))
end if
end tell
if (count of COPProcList) = 0 then my loqqed_Error_Halt3(true, "COP is not running")
if (count of COPProcList) ≠1 then my loqqed_Error_Halt3(true, "Unexpected: >1 COP instances")
set theAppRef to item 1 of COPProcList
tell application "System Events" to set theAppName to ((get name of theAppRef) as text)
tell application "System Events" to set copDetailedVersion to get version of my application theAppName
tell application "Capture One 20" to set copVersion to (get app version)
if debugLogLevel ≥ 2 then
tell application "System Events"
my loq_Results2(2, false, ("All Processes: " & (get my joinListToString((get name of every process whose background only is false), ", "))))
end tell
loq_Results2(2, false, ("theAppName: " & theAppName))
loq_Results2(2, false, ("COP Version: " & copVersion))
loq_Results2(2, false, ("COP Detailed Version: " & copDetailedVersion))
end if
set numCOPversion to (splitstringtolist((word -1 of copVersion), "."))
set minCOPversion to (splitstringtolist(minCOPversionstr, "."))
set maxCOPversion to (splitstringtolist(maxCOPversionstr, "."))
set digit_mult to 1000000
set Version_digit to 0
repeat with dig_ctr from 1 to count of numCOPversion
set digit_mult to digit_mult / 100
set Version_digit to Version_digit + (get item dig_ctr of numCOPversion as integer) * digit_mult
end repeat
set digit_mult to 1000000
set min_digit to 0
repeat with dig_ctr from 1 to count of minCOPversion
set digit_mult to digit_mult / 100
set min_digit to min_digit + (get item dig_ctr of minCOPversion as integer) * digit_mult
end repeat
set digit_mult to 1000000
set max_digit to 0
set digit_count to count of maxCOPversion
repeat with dig_ctr from 1 to digit_count
set digit_mult to digit_mult / 100
set max_digit to max_digit + (get item dig_ctr of maxCOPversion as integer) * digit_mult
if (dig_ctr = digit_count) then set max_digit to max_digit + digit_mult
end repeat
if (Version_digit < min_digit) or (Version_digit ≥ max_digit) then
if enableNotifications then display notification "COP Version is unsupported"
my loqqed_Error_Halt3(true, "This COP Version is " & copDetailedVersion & " - the supported COP versions are from " & minCOPversionstr & " to " & maxCOPversionstr)
end if
tell application "System Events" to set frontmost of process theAppName to true
loq_Results2(1, false, ("Capture One version: " & copDetailedVersion))
end validateCOP2
on validateCOPdoc3(COP_kind_list)
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General purpose initialisation handler for scripts using Capture One Pro
## Extract and check basic information about the current document
global debugLogLevel, COPDocName, COPDocKind_s, COPDocRef, theAppName
try
tell application "Capture One 20" to set COPDocName to get name of current document
on error
loqqed_Error_Halt3(true, "The Script could not retrieve the Capture One document - Perhaps a Capture One Dialog window is open?")
end try
tell application "Capture One 20"
set current_doc_kind_p to (get kind of current document)
set current_doc_ref_list to (get every document whose name is COPDocName and kind is current_doc_kind_p)
set number_of_hits to count of current_doc_ref_list
end tell
set COPDocKind_s to convertKindList(current_doc_kind_p)
if COPDocKind_s = "session" then set COPDocName to text 1 thru ((offset of "." in COPDocName) - 1) of COPDocName
loq_Results2(2, false, ("Found Documents: " & number_of_hits))
if COP_kind_list does not contain COPDocKind_s then loq_Results2(0, false, (COPDocName & " is a " & COPDocKind_s & " -- unsupported type of document"))
if number_of_hits = 0 then
loqqed_Error_Halt3(false, "Could not find find " & COPDocKind_s & COPDocName)
error "Could not find find " & COPDocKind_s & COPDocName
else if number_of_hits > 1 then
loqqed_Error_Halt3(false, "Found more than one " & COPDocKind_s & " with the name " & COPDocName)
error "Found more than one " & COPDocKind_s & " with the name " & COPDocName
else
tell application "Capture One 20" to set COPDocRef to item 1 of current_doc_ref_list
end if
loq_Results2(1, false, ("CO Document: " & COPDocKind_s & " " & COPDocName))
end validateCOPdoc3
on validateCOPcollections3()
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General purpose initialisation handler for scripts using Capture One Pro
## Extract basic information regarding the current collection, and thhe top level collections
global debugLogLevel, COPDocName, COPDocKind_s, COPDocRef, enableNotifications
global everyTopCollection, namesTopCollections, kindsTopCollections_s, countTopCollections, selectedCollectionRef, selectedCollectionIndex, kindSelectedCollection_s, nameSelectedCollection
global selectedCollectionMirroredAtTopLast, selectedCollectionIsUser, bottomUserCollectionIndex, topUserCollectionIndex
-- selectedCollectionMirroredAtTopLast replaces selectedCollectionAtTopEnd
-- bottomUserCollectionIndex, topUserCollectionIndex replaces indexInCatalog
tell application "Capture One 20" to tell COPDocRef
set selectedCollectionRef to get current collection
if (missing value = selectedCollectionRef) then
set current collection to collection 1
set selectedCollectionRef to get current collection
end if
set nameSelectedCollection to name of selectedCollectionRef
set kindSelectedCollection_s to my convertKindList(kind of selectedCollectionRef)
set {everyTopCollection, namesTopCollections} to {it, name} of every collection
set kindsTopCollections_s to my convertKindList(kind of every collection)
end tell
set countTopCollections to count of namesTopCollections
repeat with collectionCounter from 1 to countTopCollections
if (nameSelectedCollection = item collectionCounter of namesTopCollections) and ¬
(kindSelectedCollection_s = item collectionCounter of kindsTopCollections_s) then
set selectedCollectionIndex to collectionCounter
exit repeat
end if
end repeat
if COPDocKind_s = "catalog" then
repeat with collectionCounter from countTopCollections to 1 by -1
if ("in Catalog" = item collectionCounter of namesTopCollections) and ¬
("smart album" = item collectionCounter of kindsTopCollections_s) then
set topUserCollectionIndex to collectionCounter - 1
exit repeat
end if
end repeat
repeat with collectionCounter from 1 to countTopCollections
if ("Trash" = item collectionCounter of namesTopCollections) and ¬
("smart album" = item collectionCounter of kindsTopCollections_s) then
set bottomUserCollectionIndex to collectionCounter + 1
exit repeat
end if
end repeat
set selectedCollectionMirroredAtTopLast to ¬
(selectedCollectionIndex = countTopCollections) and ¬
({"catalog folder", "favorite"} does not contain last item of kindsTopCollections_s)
set selectedCollectionIsUser to ¬
(selectedCollectionMirroredAtTopLast or ((selectedCollectionIndex ≥ bottomUserCollectionIndex) and ¬
(selectedCollectionIndex ≤ topUserCollectionIndex)))
else if COPDocKind_s = "session" then
repeat with collectionCounter from countTopCollections to 1 by -1
if ("favorite" ≠item collectionCounter of kindsTopCollections_s) then
set topUserCollectionIndex to collectionCounter
exit repeat
end if
end repeat
repeat with collectionCounter from 1 to countTopCollections
if ("Trash" = item collectionCounter of namesTopCollections) and ¬
("favorite" = item collectionCounter of kindsTopCollections_s) then
set bottomUserCollectionIndex to collectionCounter + 1
exit repeat
end if
end repeat
set selectedCollectionMirroredAtTopLast to false
set selectedCollectionIsUser to ({"project", "album", "group", "smart album"} contains kindSelectedCollection_s)
end if
end validateCOPcollections3
on convertKindList(kind_list)
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General Purpose Handler for scripts using Capture One Pro
## Many releases of Capture One return the chevron form of the property "kind" when AppleScript is run as an Application
## This script converts a list of kind enums to text, handling the chevron form correctly
## Assume that the list either contains the plain text enums or the chevron form enums, but not both
## Assume that the list contains the kind enums from the same class
if "list" = (get (class of kind_list) as text) then
set input_is_list to true
else
set kind_list to {kind_list}
set input_is_list to false
end if
set kind_s1 to (item 1 of kind_list) as text
set kind_s_list to {}
set fail_flag to false
if "«" ≠(get text 1 of kind_s1) then
repeat with Kind_item in kind_list
set the end of kind_s_list to (get Kind_item as text)
end repeat
else
## minimum 6 characters for valid logic. Normally 19
if 6 > length of kind_s1 then loqqed_Error_Halt3(true, "convertKind received an unexpected Kind string: " & kind_s1)
set code_start to (get length of kind_s1) - 4
set kind_type to get (text code_start thru (code_start + 1) of kind_s1)
repeat with Kind_item in kind_list
set kind_s to Kind_item as text
set kind_code to get (text code_start thru (code_start + 3) of kind_s)
if kind_type = "CC" then ## Collection Kinds
if kind_code = "CCpj" then
set the end of kind_s_list to "project"
else if kind_code = "CCgp" then
set the end of kind_s_list to "group"
else if kind_code = "CCal" then
set the end of kind_s_list to "album"
else if kind_code = "CCsm" then
set the end of kind_s_list to "smart album"
else if kind_code = "CCfv" then
set the end of kind_s_list to "favorite"
else if kind_code = "CCff" then
set the end of kind_s_list to "catalog folder"
else
set fail_flag to true
end if
else if kind_type = "CL" then ## Layer Kinds
if kind_code = "CLbg" then
set the end of kind_s_list to "background"
else if kind_code = "CLnm" then
set the end of kind_s_list to "adjustment"
else if kind_code = "CLcl" then
set the end of kind_s_list to "clone"
else if kind_code = "CLhl" then
set the end of kind_s_list to "heal"
else
set fail_flag to true
end if
else if kind_type = "CR" then ## Watermark Kinds
if kind_code = "CRWn" then
set the end of kind_s_list to "none"
else if kind_code = "CRWt" then
set the end of kind_s_list to "textual"
else if kind_code = "CRWi" then
set the end of kind_s_list to "imagery"
else
set fail_flag to true
end if
else if kind_type = "CO" then ## Document Kinds
if kind_code = "COct" then
set the end of kind_s_list to "catalog"
else if kind_code = "COsd" then
set the end of kind_s_list to "session"
else
set fail_flag to true
end if
else
set fail_flag to true
end if
if fail_flag then loqqed_Error_Halt3(true, "convertKindList received an unexpected Kind string: " & kind_s)
end repeat
end if
if input_is_list then
return kind_s_list
else
return item 1 of kind_s_list
end if
end convertKindList
on InitializeResultsCollection(nameResultProject, nameResultAlbumRoot, Coll_Init_Text)
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General Purpose Handler for scripts using Capture One Pro
## Sets up a project and albums for collecting images
global debugLogLevel, COPDocRef, Ref2ResultAlbum, enableNotifications
tell application "Capture One 20" to tell COPDocRef
if not (exists collection named (get nameResultProject)) then
set ref2ResultProject to make new collection with properties {kind:project, name:nameResultProject}
else
if ("project" = my convertKindList(kind of (get collection named nameResultProject))) then
set ref2ResultProject to collection named nameResultProject
else
my loqqed_Error_Halt3(true, ("A collection named "" & nameResultProject & "" already exists, and it is not a project."))
end if
end if
end tell
set coll_ctr to 1
set nameResultAlbum to nameResultAlbumRoot & "_" & (get short date string of (get current date)) & "_"
repeat
tell application "Capture One 20" to tell ref2ResultProject
if not (exists collection named (get nameResultAlbum & coll_ctr)) then
set nameResultAlbum to (get nameResultAlbum & coll_ctr)
set Ref2ResultAlbum to make new collection with properties {kind:album, name:nameResultAlbum}
exit repeat
else
set coll_ctr to coll_ctr + 1
end if
end tell
end repeat
if enableNotifications then display notification (Coll_Init_Text & " " & nameResultProject & ">" & nameResultAlbum)
loq_Results2(1, false, (Coll_Init_Text & " " & nameResultProject & ">" & nameResultAlbum))
end InitializeResultsCollection
###########################################################################################################################
## General Handlers Version 2019/11/6
on InitializeLoqqing3(DocName_Ext, sourceTitle)
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General purpose handler to set up Text Editor document for logging results
global debugLogLevel, Script_Title, Result_Doc_ref, SE_Logging, enableResultsFile, enableResultsByDialog, enableResultsByClipboard, DialogTextList, enableNotifications
global initEnableResultsByDialog, initEnableResultsByClipboard
tell current application to set date_string to (current date) as text
set LogMethods to {}
set LogHeader to (sourceTitle & " results on " & date_string)
if enableResultsFile then
set end of LogMethods to DocName_Ext
set targetFileWasCreated to false
set ResultDocIsOpen to false
## Check if TextEdit is already open and has the document open
tell application "System Events" to set TextEditlist to get background only of every application process whose name is "TextEdit"
if (0 < (count of TextEditlist)) and not item 1 of TextEditlist then
if (DocName_Ext is in (get name of documents of application "TextEdit")) then
tell application "TextEdit" to set Result_Doc_ref to document DocName_Ext
set ResultDocIsOpen to true
end if
end if
if not ResultDocIsOpen then
-- create the document and the folder if necessary
-- Do not use finder to test for the file existence because it has a bug that ignores leading 0's
-- https://www.macscripter.net/viewtopic.php?id=45178
set target_folder_parent_a to alias (get path to desktop folder as text)
set target_folder_parent_p to get POSIX path of target_folder_parent_a
set target_folder_name to "ScriptReports"
set target_folder_p to (target_folder_parent_p & target_folder_name)
set Result_Doc_Path_p to target_folder_p & "/" & DocName_Ext
try
set Result_Doc_Path_a to (get alias POSIX file Result_Doc_Path_p)
on error
try
set target_folder_a to (get alias POSIX file target_folder_p) --x1
on error
tell application "Finder" to set newFolder to make new folder at target_folder_parent_a with properties {name:target_folder_name}
set target_folder_a to newFolder as alias
end try
tell application "Finder" to set newFile to make new file at target_folder_a with properties {name:DocName_Ext}
set Result_Doc_Path_a to newFile as alias
set targetFileWasCreated to true
end try
set First_line to ("Created by " & Script_Title & " on " & date_string)
tell application "TextEdit" -- open the document and add the first line if empty
activate
set Result_Doc_ref to open Result_Doc_Path_a
set ResultDocIsOpen to true -- For consistency
tell text of Result_Doc_ref
if targetFileWasCreated then
set paragraph 1 to First_line & return & return
tell me to if 2 ≤ debugLogLevel then log Result_Doc_Path_p & ": " & First_line
else
try
if (0 = (count of paragraphs)) then set paragraph 1 to First_line & return & return
on error
set paragraph 1 to First_line & return & return
end try
end if
end tell
end tell
end if
tell application "TextEdit" to tell text of Result_Doc_ref to ¬
set paragraph (1 + (count paragraphs)) to return & LogHeader & return
end if
if enableResultsByDialog then
set end of LogMethods to "Display Dialog"
try
initEnableResultsByDialog
set DialogTextList to DialogTextList & ""
set initEnableResultsByDialog to false
on error
set DialogTextList to {LogHeader}
set initEnableResultsByDialog to true
end try
end if
if enableResultsByClipboard then
set end of LogMethods to "Clipboard"
try
initEnableResultsByClipboard
set initEnableResultsByClipboard to false
on error
set the clipboard to LogHeader
set initEnableResultsByClipboard to true
end try
end if
if SE_Logging then -- if Script Editor logging, then open the Log History window
try
tell application "System Events" to tell application process "Script Editor"
if (get name of windows) does not contain "log History" then
click menu item "Log History" of menu "Window" of menu bar 1
end if
end tell
end try
set end of LogMethods to " Script Editor Log"
end if
set LogMethods_S to joinListToString(LogMethods, ", ")
loq_Results2(2, false, ("Results by " & LogMethods_S))
return LogMethods_S
end InitializeLoqqing3
on loq_Results2(thisLogDebugLevel, MakeFront, log_Text)
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## General purpose handler for logging results
## log results if the debug level of the message is below the the threshold set by debugLogLevel
## log the results by whatever mechanism is ebabled - {Script Editor Log, Text Editor Log, Display Dialog}
global Result_Doc_ref, debugLogLevel, SE_Logging, parent_name, ResultsFileMaxDebug, enableResultsFile, enableResultsByDialog, enableResultsByClipboard, DialogTextList
if thisLogDebugLevel > debugLogLevel then return
set log_Text_S to joinListToString(log_Text, ", ")
if enableResultsFile and ((thisLogDebugLevel ≤ ResultsFileMaxDebug) or not SE_Logging) then
tell application "TextEdit" to tell text of Result_Doc_ref to ¬
set paragraph (1 + (count paragraphs)) to ((log_Text_S as text) & return)
tell application "System Events" to if MakeFront then set frontmost of process "TextEdit" to true
end if
if enableResultsByDialog and (1 ≥ thisLogDebugLevel) then
set DialogTextList to DialogTextList & log_Text_S
tell application "System Events" to set frontmost of process parent_name to true
display dialog joinListToString(DialogTextList, return)
end if
if enableResultsByClipboard and (1 ≥ thisLogDebugLevel) then set the clipboard to ((get the clipboard) & return & (log_Text_S as text))
if SE_Logging then log (log_Text_S as text)
end loq_Results2
on loqqed_Error_Halt3(createErrorHere, error_text)
## General purpose handler for logging during script termination
##
## found an error somewhere, so now we exit in a controlled fashion
## set createError to "false" to create a local error instead of here
global debugLogLevel, Script_Title, enableNotifications
tell current application to set date_string to (current date) as text
finalCleanup()
if enableNotifications then display notification error_text
if createErrorHere then
loq_Results2(0, true, ("Script "" & Script_Title & "" has halted at " & date_string & return & "Reason: " & error_text & return & return))
error error_text
else
loq_Results2(0, true, ("Script "" & Script_Title & "" is exitting at " & date_string & "Reason: " & error_text & return))
end if
end loqqed_Error_Halt3
on splitstringtolist(theString, theDelim)
## Public Domain
set astid to AppleScript's text item delimiters
try
set AppleScript's text item delimiters to theDelim
set theList to text items of theString
on error
set AppleScript's text item delimiters to astid
end try
set AppleScript's text item delimiters to astid
return theList
end splitstringtolist
to joinListToString(theList, theDelim)
## Public Domain
set theString to ""
set astid to AppleScript's text item delimiters
try
set AppleScript's text item delimiters to theDelim
set theString to theList as string
on error
set AppleScript's text item delimiters to astid
end try
set AppleScript's text item delimiters to astid
return theString
end joinListToString
on makeList3(listLength, theElement)
-- Note that the theElement can even be a List
if listLength = 0 then return {}
if listLength = 1 then return {theElement}
set theList to {theElement}
repeat while (count of theList) < listLength / 2
copy contents of theList to ListB
copy theList & ListB to theList
end repeat
copy contents of theList to ListB
return (theList & items 1 thru (listLength - (count of ListB)) of ListB)
end makeList30 -
Script has been updateed (see post above) 0
Post is closed for comments.
Comments
7 comments