Move | Duplicate| Replicate selected records [+LaunchBar]

Quick question. I cannot edit the .scpt file in either Applescript Editor or Textmate. Although the script is brilliant and includes duplicate and replicate on the fly with d[space] or r[space], I was working on my database yesterday and was replicating like a storm and wanted to temporarily switch the default functions in the script.

I have upgraded to Yosemite 10.10 and cannot confirm whether I had the ability to edit the .scpt file. Any ideas?

The cause should be most probably the lacking of Growl on your system (that the script needs for reporting the outcome of the action).

Here is a copy where I commented out the reporting section


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.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 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 "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

If you want you can add reporting based on OS X notification center.

johseb, that did the trick. Thank you for taking the time to edit the script for me. I have not heard of scripts being unable to be opened due to lack of Growl.

FWIW I’ll take a look at that in the next week or two and remove the Growl dependency from the Github copy.

OS X notifications make more sense now.

Is anybody else having trouble running this script since the 2.8.4 release of DTPO?

I am able to enter a search string in the box but then no feedback after hitting Enter. I get the following errors when running repeatedly from either LaunchBar or the AppleScript editor:

[b]Error Number: -2763

No result was returned from some part of this expression.[/b]

or

Can’t make «class DTpr» id 16323 of «class DTkb» id 3 of application “DEVONthink Pro” into type vector.
When run from Script Editor.app, the focus turns to the word “database” in the script as “this expression.”

You can tell from my post that I am an AppleScript neophyte. I’d appreciate any help, since this script is my primary tool for shuffling items around my databases.

Yes, I am having the same issue.

Its a great script, and the one I absolutely use the most.

Also inexperienced with AppleScript, so working hard to figure it out without much luck.

I’ve found that if I use a search string of one or two characters, AND those characters are in the open databases’ names, it works and opens every group with those characters.

If I use three characters, I get the error.

If I use one or two characters that are not in the name of an open database, I get the error.

I have been trying to dissect the script to figure out why the number of characters matters and the relationship to the open databases matters, but just don’t know enough to figure it out yet.

I also confirm the issue on 2.8.4. Seems to work only with input up to 2 characters maximum, provided a matching entry exists in the database. Could not figure out a fix so far.

The script works as long as more than one matching group is found. In case of only one group AppleScript suddenly returns this group instead of a list containing the group. Still have to figure out why.

Interesting, but the only thing that works at all for me is typing “re,” which returns results, but then when I highlight one and click ok, I get the error messages mentioned in this forum. Typing any other one, two, three letter combo only returns errors regardless of whether one or more matching groups exist.

For what it’s worth.

In previous builds this worked as a way of finding matching folders

-- AND FOLDERS WITH MATCHING NAMES
    repeat with oDb in its databases
        set lstParent to lstParent & (parents of oDb where name contains strFind)
    end repeat

It still finds the correct number of matches but no longer returns good references to them. In lieu of a list of two folder references, for example, the 2.8.4 Applescript API is now returning a list of two empty/null values:


[ null(), null() ]

or, if you like:


{,}

I understand that this glitch in the 2.8.4 Applescript interface will be fixed in the next maintenance release of DEVONthink.

We should find that the Move | Duplicate | Replicate script is back in business at that point.

Fantastic news, thanks for sharing it!

That’s really welcome news.

Thanks to houthakker and the DevonThink team!

Wanted to report back in to say that yes, in v2.8.5, this script now works both from the Menu selection and wrapped in a Keyboard Maestro macro. Thanks, DEVONtech!

This script would work nicely with Keyboard Maestro (KM) if KM could see and enter text into the dialog box that this script evokes. This would allow selecting a record and moving it to Group with a single keystroke from within DT (without LaunchBar) which I think is the ultimate goal behind this post.

As it is I can get KM to drag a selected record from anywhere to a Group I favored in the sidebar as inelegant and limited as that is.

Any thought about how to get KM to input into the dialog this script creates? I’ll check the KM forum for ideas as well…

I am sure you are right, and it may well be a good idea …

Ars longa vita brevis … always very happy to share the things which I write for my own purposes, and I generally do try to fix them if OS or app changes break them (especially if I still need them myself), but perhaps I’m not the right person to turn for for bespoke software creation (software is not my industry, as it happens).

The script seems to be working (in its limited way) for me. I have no doubt that it could be improved, and the source code is there, for anyone who wants to do that.

You clearly do have interesting ideas for script development, and perhaps this is a good time to learn some basic elements of scripting ?

JavaScript is a very approachable language, and now reaps quite rich rewards not only on web pages (a useful extension to core literacy these days) but also in iOS and OS X application use generally.

All best, Rob

(Twitter:ComplexPoint)

Greetings all, and thanks for such a fantastic script, I use it literally all the time.

I’m getting an error when I run this script – the script is successfully moving items to destination groups, but is not giving a notification of success nor is it shifting focus to the destination group. Have I missed an updated version of the script that changes it to Apple’s Notifications, or no notification, rather than Growl? I do not have growl installed on my system now.

This is the text of the error message:

“An Error Occurred while running DT_Move [what I have named this script]. See Console logs for further information.”

The console log reports this:

1/25/16 6:29:05.110 PM LaunchBar[410]: Error while executing AppleScript: {
NSAppleScriptErrorBriefMessage = “Can\U2019t make \U00abclass DTpr\U00bb id 9 of \U00abclass DTkb\U00bb id 2 of application “DEVONthink Pro” into the expected type.”;
NSAppleScriptErrorMessage = “Can\U2019t make \U00abclass DTpr\U00bb id 9 of \U00abclass DTkb\U00bb id 2 of application “DEVONthink Pro” into the expected type.”;
NSAppleScriptErrorNumber = “-1700”;
NSAppleScriptErrorRange = “NSRange: {0, 0}”;
}

Here is my system and app info:
OS X 10.11.3
DTPO v. 2.8.8
Launchbar v. 6.5 (6122)
using the latest version of the script in this thread, I believe

As I mentioned, script successfully moves the item, but does not shift focus to the destination group or give a notification of success, and it always gives the error message quoted above. I’m happy to live with it but thought maybe I had missed something.

Thanks for your help, and for the indispensable script!
Jeremy

Should be quick enough switch out Growl for OS X notifications. I’ll take a look at the weekend, and check which version is the latest.

@houthakker, thanks so much! The log error message doesn’t mean much to me – do you think the notification issue is what is causing the error?