Move | Duplicate| Replicate selected records [+LaunchBar] update?

The script I use most often, by far, was written and updated by houthakker quite a few years ago:

Move/Replicate/Duplicate file to new group

I use this script with FastScripts by selecting a file or files in my Inbox, invoking the keyboard shortcut (which I assigned in FastScripts), and then typing in a part of the group name in the dialog box. This presents me with a short list of groups to which I can move the file/files, optionally replicating or duplicating, and optionally opening the selected group in a new window.

I have not downloaded the beta of DT3 (I have mission-critical data), but wanted to check if upgrading such a script would be challenging (I’m not very experienced with AppleScript), or if the new automation features would allow this sort of function without a script.

Thanks!

This is a third-party script, so we don’t support it in-house.

  • Updating to use tell application id "DNtp" is advisable.
  • Also, Growl is long dead, as far as I know.

You can move files in DEVONthink 3 via the Data > Move to popover, even searching for a group name to drop into.

Thank you, Bluefrog.

Does the ‘Move To…’ have an option to replicate or duplicate? Does it have an option to open the destination group?

Yes, Growl isn’t there. I haven’t looked at the script internal for a long time, as it just works.

Appreciate the help, and looking very much forward to upgrading to Version 3 when its ready!

Does the ‘Move To…’ have an option to replicate or duplicate? Does it have an option to open the destination group?

No, but you can use Go > Go to Group and pull it to hover it. This can be used to Option-drag and Option-Command-drag to it. And obviously, as the name implies, it’s how you can quickly open a group.

This version works for me in DT3 beta 7. I have not deprecated any of the Growl code for fear of breaking something.


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 parent group
-- (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 : "1.0"
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.think3"
		-- 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 PARENT DIRECTORY OF SELECTED ITEMS
		if strFind = ".." then set end of lstParent to first item of parents of (first item of lstSelns)
		-- 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 contain the string:" & "
    " & strFind & strRepNote buttons {"OK"} default button "OK" with title strVerb & pTitle
			end tell
		end if
	end tell
end ProcessSelns
on GetDevnSelns()
	tell application id "DNtp"
		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

Thanks for updating the script. It is SO useful to my workflow.

A couple of items/questions:

  1. This script moves the file to the new group AND opens that group.

  2. I removed the lines:

    – NOTIFY RESULT BY GROWL (IF INSTALLED) OR WITH DIALOG BOX
    my Announce(oTarget, strVerb, (length of lstSelns), strNames)
    and it works fine.

  3. I then duplicated the script and removed the lines:

    open window for record oTarget
    activate

which gave me a script to move a file to a new group, but to remain within the original group.

  1. Unfortunately, this latter script works almost perfectly, moving the file without opening the new group. BUT, DT3 loses focus, so I have to click in an empty space, or use the application switcher to move to another app, and then back again, at which time DT3 is now in focus.

So my question is, how do I instruct the second script to put the focus back on DT3? I’m sure its something silly, and I have tried my limited AppleScript vocabulary, but cannot get it to work.

Thanks!

Are you running this via LaunchBar? I run it through a Keyboard Maestro shortcut (used to use FastScripts), and lose window focus but am never taken to the receiving group.

Thanks. I run it through FastScripts. However, after your helpful response, I set it to run through KM, and then added an action at the end to activate DT3. I don’t know why this is necessary, unless the dialog box is somehow out of DT3, but it solved the issue. Now when the dialog box closes, I am back in DT3.

Cheers!