I have keyboard shortcuts assigned to this script and two variants of it (edit “Move” in the first line to “Duplicate” or “Replicate” to determine the script’s behaviour).
The built-in equivalents are fine, but I find it quicker to shun the mouse where possible, and prefer to type a few characters to specify the target.
property pMove : "Move"
property pDup : "Duplicate"
property pRep : "Replicate"
property pDefaultVerb : pMove -- Default verb: may be switched to Duplicate (pDup) or Replicate (pRep) at run-time
-- ver 1.0 Allows double dot (..) as short-hand for next group up in the hierarchy
-- (to facilitate moving selected records up one level in the group hierarchy)
-- ver 0.9 Fixed a big involving search strings which include a space
-- ver 0.8 Clarified the Growl message: bold header: [Verb]d [N] records to:, body:[Destination]/n[List of records]
-- ver 0.7 Enhanced the "Group not Found" message for replication to remind user that replication
-- is only possible within a single database.
-- ver 0.6 The default verb (Move) can be overridden by prefixing the search string with "d " or "r "
-- (for "Duplicate" or "Replicate") in LaunchBar or the standard dialog
-- (a single verb letter followed by a single space before the search string itself)
-- ver 0.5 Can get the search string from LaunchBar
-- ver 0.4 Allows target databases (where their names match) as well as target folders
-- (the default incoming group of the database is used as the destination)
property pVer : "0.9"
property pTitle : " to target group" & " " & pVer
property pstrDelim : " "
on run
set lstSelns to GetDevnSelns()
if lstSelns ≠ {} then
set strNames to GetNameList(lstSelns)
set strCmd to GetSearchString(pDefaultVerb, strNames)
if strCmd ≠ "" then
set {strVerb, strFind} to ParseCmd(strCmd)
if strFind ≠ "" then ProcessSelns(lstSelns, strNames, strVerb, strFind)
end if
end if
end run
-- GET THE TARGET GROUP SEARCH STRING FROM LAUNCHBAR
on handle_string(strCmd)
if strCmd ≠ "" then
set lstSelns to GetDevnSelns()
if lstSelns ≠ {} then
set {strVerb, strFind} to ParseCmd(strCmd)
if strFind ≠ "" then
set strNames to GetNameList(lstSelns)
ProcessSelns(lstSelns, strNames, strVerb, strFind)
end if
end if
end if
end handle_string
on ParseCmd(strCmd)
set {strVerb, strFind} to {pDefaultVerb, ""}
set text item delimiters to space
set lstParts to text items of strCmd
if length of lstParts > 1 then
set strFirst to first item of lstParts
ignoring case
if strFirst is in {"m", "d", "r"} then
if strFirst = "m" then
set strVerb to pMove
else if strFirst = "d" then
set strVerb to pDup
else if strFirst = "r" then
set strVerb to pRep
end if
set strFind to (items 2 thru end of lstParts) as string
else
set strFind to strCmd
end if
end ignoring
else
set strFind to strCmd
end if
{strVerb, strFind}
end ParseCmd
on ProcessSelns(lstSelns, strNames, strVerb, strFind)
-- CHECK THAT A KNOWN VERB IS SPECIFIED AT THE TOP OF THE SCRIPT
if strVerb is not in {pMove, pDup, pRep} then
tell application id "com.apple.systemevents"
activate
display dialog "\"" & strVerb & "\": unknown value for pDefaultVerb" & return & return & "Expected Move | Duplicate | Replicate"
end tell
return
end if
tell application id "com.devon-technologies.thinkpro2"
-- GET FILTERED SET OF POSSIBLE DESTINATIONS
if strVerb ≠ pRep then
-- BOTH OPEN DATABASES WITH MATCHING NAMES
set lstParent to (incoming group of databases where name contains strFind)
-- AND FOLDERS WITH MATCHING NAMES
repeat with oDb in databases
set lstParent to lstParent & (parents of oDb where name contains strFind)
end repeat
else -- OR, IN THE CASE OF REPLICATION, IN CURRENT DATABASE
set lstParent to (parents of current database where name contains strFind)
end if
-- ALLOW FOR DOUBLE DOT (..) AS REFERENCE TO NEXT GROUP UP IN THE HIERARCHY
if strFind = ".." then
set oSelnParent to first item of (parents of (first item of lstSelns))
set lstGrandParents to parents of oSelnParent
if lstGrandParents ≠ {} then set end of lstParent to first item of lstGrandParents
end if
-- BUILD NUMBERED MENU OF DESTINATION NAMES
set lngParents to length of lstParent
if lngParents > 0 then
set lngDigits to length of (lngParents as string)
set lstMenu to {}
repeat with i from 1 to lngParents
tell item i of lstParent
set strName to (name of its database) & its location & its name
end tell
if strName = "Inbox/Inbox" then set strName to "Global Inbox"
set end of lstMenu to my PadNum(i, lngDigits) & pstrDelim & strName
end repeat
-- CHOOSE DESTINATION
tell application id "com.apple.systemevents"
activate
set varTargets to choose from list lstMenu with title strVerb & pTitle with prompt strVerb & ":
" & strNames & "
to target group:" default items {first item of lstMenu} without multiple selections allowed
end tell
if varTargets is not false then
-- RETRIEVE CHOSEN DESTINATION BY NUMERIC INDEX
set my text item delimiters to space
set oTarget to item ((first text item of (first item of varTargets)) as integer) of lstParent
-- MOVE | DUPLICATE | REPLICATE SELECTED ITEMS TO DESTINATION
if strVerb = pMove then
repeat with oRec in lstSelns
move record oRec to oTarget
end repeat
else if strVerb = pDup then
repeat with oRec in lstSelns
duplicate record oRec to oTarget
end repeat
else if strVerb = pRep then
repeat with oRec in lstSelns
replicate record oRec to oTarget
end repeat
end if
-- NOTIFY RESULT BY GROWL (IF INSTALLED) OR WITH DIALOG BOX
my Announce(oTarget, strVerb, (length of lstSelns), strNames)
open window for record oTarget
activate
end if
else
if strVerb ≠ pRep then
set strRepNote to ""
else
set strRepNote to "
(If you were attempting to replicate to another open database, note that DevonThink only supports replication within a single database)"
end if
tell application id "com.apple.systemevents"
activate
display dialog "No open groups match:" & "
" & strFind & strRepNote buttons {"OK"} default button "OK" with title strVerb & pTitle
end tell
end if
end tell
end ProcessSelns
on GetDevnSelns()
tell application id "com.devon-technologies.thinkpro2"
return selection
end tell
end GetDevnSelns
on GetSearchString(strVerb, strNames)
set strFind to ""
-- GET SUB-STRING TO FILTER LIST OF TARGETS
tell application id "com.apple.systemevents"
activate
set strFind to text returned of (display dialog strVerb & ":" & return & return & strNames & return & ¬
"Enter search string to list target groups:" default answer "" buttons {"Cancel", "OK"} default button "OK" cancel button "Cancel" with title strVerb & pTitle)
end tell
return strFind
end GetSearchString
on GetNameList(lstSelns)
-- BUILD BULLETED LIST OF SELECTION NAMES
set strNames to ""
repeat with i from 1 to count of lstSelns
set strNames to strNames & "• " & name of (item i of lstSelns) & return
end repeat
return strNames
end GetNameList
-- REPORT RESULT
on Announce(oGroup, strVerb, lngRecords, strNames)
tell application id "com.devon-technologies.thinkpro2" to set {strDb, strPath, strFolder} to {name of database, location, name} of oGroup
set strGrowlTitle to strVerb & "d " & (lngRecords as string) & " records to:"
set strGrowlBody to strDb & strPath & strFolder & "
" & strNames
tell application id "com.apple.systemevents"
-- USE GROWL IF IT'S RUNNING
if (count of (every process whose name is "GrowlHelperApp")) > 0 then
tell application id "com.Growl.GrowlHelperApp"
register as application "houthakker scripts" all notifications {pTitle} default notifications {pTitle} icon of application "DEVONthink Pro"
notify with name pTitle title strGrowlTitle application name "houthakker scripts" description strGrowlBody
end tell
else
-- (OR USE A STANDARD DIALOG)
tell application id "com.apple.systemevents"
activate
display dialog strReport & "
(This script works best if Growl is installed)" buttons {"OK"} with title pTitle
end tell
end if
end tell
end Announce
-- GET A DIGIT STRING OF MINIMUM WIDTH (LEFT-PADDING WITH ZEROS WHERE NEEDED)
on PadNum(lngNum, lngDigits)
set strNum to lngNum as string
set lngGap to (lngDigits - (length of strNum))
repeat while lngGap > 0
set strNum to "0" & strNum
set lngGap to lngGap - 1
end repeat
strNum
end PadNum