Script: Create or change smart group(s)

Script: Create or change smart group(s)

This script creates smart groups in selected group(s) or if nothing is selected a database-global smart group. It creates a meta group to hold database-global smart groups and a meta smart group which collects all group-specific smart groups.

2

If a smart group is selected it can be used to change the query and/or name. That’s especially useful to change existing smart group names to their query. To do so add a space to the query in the query dialog, this opens the name dialog. Also handy to update the name after changing a query via smart group editor. I find using the query as name (or part of the name) makes learning the syntax much easier.

As syntax mistakes happen quite easy and often over here there’s a help button which opens DEVONthink’s “search prefixes” page in the default browser. Property theHelpFileOrRefURL accepts a reference URL or URL too so a custom help resource could be used.

1

If text is selected it is used as default answer.

There are different modes to reveal/open created smart groups, however it’s not easy (for me) to choose one as each has advantages and disadvantages depending on the situation.

To make the meta group stick out a thumbnail can be set in a template record, “Smart” in the first capture is actually a group with a smart group thumbnail.

By the way @ngan made a script for normal searches.

-- Create or change smart group(s)

property theMetaGroupName : "Smart"
property theSmartGroupName : "_Subsets"
property revealInCurrentWindow : true
property openInCurrentWindow : false
property openInNewWindow : false
property openInNewWindows : false
property theHelpFileOrRefURL : ((POSIX path of (path to application id "DNtp") as text) & "/Contents/Resources/DEVONthink.help/Contents/Resources/pgs/appendix-searchprefixes.html") as string
property theIconPath : (((path to application id "DNtp") & "Contents:Resources:DEVONthink 3.icns:") as string) as alias
property theTemplateThumbnailUUID : ""

tell application id "DNtp"
	try
		set theSearchGroups to selection of viewer window 1
		
		if (count theSearchGroups) = 1 then
			set theType to type of item 1 of theSearchGroups as string
			if (theType = "smart group" or theType = "«constant ****DTsg»") then
				my updateSmartGroup(item 1 of theSearchGroups)
				return
			end if
		end if
		
		set scopeDatabase to false
		set theDatabase to current database
		if theSearchGroups = {} then
			set theSearchGroups to root of window 1
			try
				set theSearchGroups to theSearchGroups as list
			on error
				display alert "Hoppla!" buttons {"OK"} default button 1 message "Mehrfachauswahl in Seitenleiste nicht möglich." as informational
				return
			end try
			set scopeDatabase to true
			set theType to type of item 1 of theSearchGroups as string
			if theType = "group" or theType = "«constant ****DTgr»" then set scopeDatabase to false
			if uuid of item 1 of theSearchGroups = (uuid of theDatabase) then set scopeDatabase to true
		else
			repeat with thisSearchGroup in theSearchGroups
				set theType to type of thisSearchGroup as string
				if theType = "group" or theType = "«constant ****DTgr»" then set scopeDatabase to false
			end repeat
		end if
		
		try
			set selectedText to selected text of window 1 & "" as string
			set defaultAnswer to selectedText
			set scopeDatabase to true
			set theSearchGroups to {theDatabase}
		on error
			set defaultAnswer to ""
		end try
		set dialogButtons to {"Hilfe", "Abbrechen", "OK"}
		set theDialog to display dialog "Suche:" default answer defaultAnswer buttons dialogButtons default button 3 with title "" with icon theIconPath
		set {theButton, theQuery} to {button returned, text returned} of theDialog
		if theButton = item 1 of dialogButtons then
			do shell script "open " & quoted form of theHelpFileOrRefURL
			return
		else if theButton = item 2 of dialogButtons then
			return
		else
			if theQuery = "" then return
		end if
		
		set theMetaGroup to create location ("/" & theMetaGroupName) in theDatabase
		if theTemplateThumbnailUUID ≠ "" then set thumbnail of theMetaGroup to thumbnail of (get record with uuid theTemplateThumbnailUUID)
		
		if scopeDatabase = true then
			set theSubsetsSmartGroup to {}
			set theSmartGroups to (smart groups of theDatabase whose location is ("/" & theMetaGroupName & "/") and search predicates = theQuery)
			if theSmartGroups = {} then
				set theSmartGroup to create record with {type:smart group, search predicates:theQuery, search group:item 1 of theSearchGroups, name:theQuery, exclude from search:true} in theMetaGroup
			else
				set theSmartGroup to item 1 of theSmartGroups
			end if
		else
			if not (exists record at ("/" & theMetaGroupName & "/" & theSmartGroupName) in theDatabase) then
				set theSubsetsSmartGroup to create record with {type:smart group, search predicates:"kind:smart group", search group:theDatabase, name:theSmartGroupName, exclude from search:true} in theMetaGroup
			else
				set theSubsetsSmartGroup to get record at ("/" & theMetaGroupName & "/" & theSmartGroupName) in theDatabase
			end if
			set newSmartGroups to {}
			repeat with thisSearchGroup in theSearchGroups
				set theSmartGroups to (smart groups of theDatabase whose location is (location of thisSearchGroup & name of thisSearchGroup & "/") and search predicates = theQuery)
				if theSmartGroups = {} then
					set theSmartGroup to create record with {type:smart group, search predicates:theQuery, search group:thisSearchGroup, name:theQuery & " in: " & name of thisSearchGroup} in thisSearchGroup
				else
					set theSmartGroup to item 1 of theSmartGroups
				end if
				set end of newSmartGroups to theSmartGroup
			end repeat
		end if
		
		if revealInCurrentWindow = true then
			if (count theSearchGroups) = 1 then
				set selection of window 1 to {theSmartGroup}
			else
				set root of window 1 to theSubsetsSmartGroup
				set selection of window 1 to newSmartGroups
			end if
		else if openInCurrentWindow = true then
			if (count theSearchGroups) = 1 then
				set root of window 1 to theSmartGroup
			else
				set root of window 1 to theSubsetsSmartGroup
				set selection of window 1 to newSmartGroups
			end if
		else if openInNewWindow = true then
			if (count theSearchGroups) = 1 then
				open window for record theSmartGroup
			else
				open window for record theSubsetsSmartGroup
				set selection of window 1 to newSmartGroups
			end if
		else if openInNewWindows = true then
			if (count theSearchGroups) = 1 then
				open window for record theSmartGroup
			else
				repeat with thisSmartGroup in newSmartGroups
					open window for record thisSmartGroup
				end repeat
			end if
		end if
		
	on error error_message number error_number
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		return
	end try
end tell

on updateSmartGroup(theRecord)
	tell application id "DNtp"
		try
			set {theName, theQuery} to {name, search predicates} of theRecord
			set dialogButtons to {"Hilfe", "Abbrechen", "OK"}
			set theDialog to display dialog theQuery default answer theQuery buttons dialogButtons default button 3 with title theName with icon theIconPath
			set {theButton, newQuery} to {button returned, text returned} of theDialog
			if theButton = item 1 of dialogButtons then
				do shell script "open " & quoted form of theHelpFileOrRefURL
				return
			else if theButton = item 2 of dialogButtons then
				return
			else
				considering case
					if newQuery = theQuery or newQuery = "" then return
				end considering
				set search predicates of theRecord to newQuery
				set dialogButtons to {"Abbrechen", "OK"}
				set theDialog to display dialog "Name:" default answer newQuery buttons dialogButtons default button 2 with title theName with icon theIconPath
				set {theButton, newName} to {button returned, text returned} of theDialog
				if theButton = item 1 of dialogButtons then
					return
				else if theButton = item 2 of dialogButtons then
					if newName = "" then return
					if location of theRecord = ("/" & theMetaGroupName & "/") then
						set name of theRecord to newName
					else
						set name of theRecord to newName & " in: " & name of parent 1 of theRecord
					end if
				end if
			end if
			
		on error error_message number error_number
			error number -128
		end try
	end tell
end updateSmartGroup
1 Like

This

& this

are very handy!

1 Like

Updated the script. If no group is selected it creates a database-global smart group. Especially useful to create new smart groups when a smart group is selected in the sidebar.

Updated. Now also uses raw syntax to check the record type.

In case you tried to run the script you’ve found that it doesn’t work as expected in DEVONthink 3.6.

There’s a problem with creating Smart Groups via AppleScript, see Are Smart Groups in DEVONthink 3.6 broken?.

Updated the script with a workaround.

-- Create or change smart group(s)

property theMetaGroupName : "Smart"
property theSmartGroupName : "_Subsets"
property revealInCurrentWindow : true
property openInCurrentWindow : false
property openInNewWindow : false
property openInNewWindows : false
property theHelpFileOrRefURL : ((POSIX path of (path to application id "DNtp") as text) & "/Contents/Resources/DEVONthink.help/Contents/Resources/pgs/appendix-searchprefixes.html") as string
property theIconPath : (((path to application id "DNtp") & "Contents:Resources:DEVONthink 3.icns:") as string) as alias
property theTemplateThumbnailUUID : ""

tell application id "DNtp"
	try
		set theSearchGroups to selection of viewer window 1
		
		if (count theSearchGroups) = 1 then
			set theType to type of item 1 of theSearchGroups as string
			if (theType = "smart group" or theType = "«constant ****DTsg»") then
				my updateSmartGroup(item 1 of theSearchGroups)
				return
			end if
		end if
		
		set scopeDatabase to false
		set theDatabase to current database
		if theSearchGroups = {} then
			set theSearchGroups to root of window 1
			try
				set theSearchGroups to theSearchGroups as list
			on error
				display alert "Hoppla!" buttons {"OK"} default button 1 message "Mehrfachauswahl in Seitenleiste nicht möglich." as informational
				return
			end try
			set scopeDatabase to true
			set theType to type of item 1 of theSearchGroups as string
			if theType = "group" or theType = "«constant ****DTgr»" then set scopeDatabase to false
			if uuid of item 1 of theSearchGroups = (uuid of theDatabase) then set scopeDatabase to true
		else
			repeat with thisSearchGroup in theSearchGroups
				set theType to type of thisSearchGroup as string
				if theType = "group" or theType = "«constant ****DTgr»" then set scopeDatabase to false
			end repeat
		end if
		
		try
			set selectedText to selected text of window 1 & "" as string
			set defaultAnswer to selectedText
			set scopeDatabase to true
			set theSearchGroups to {theDatabase}
		on error
			set defaultAnswer to ""
		end try
		set dialogButtons to {"Hilfe", "Abbrechen", "OK"}
		set theDialog to display dialog "Suche:" default answer defaultAnswer buttons dialogButtons default button 3 with title "" with icon theIconPath
		set {theButton, theQuery} to {button returned, text returned} of theDialog
		if theButton = item 1 of dialogButtons then
			do shell script "open " & quoted form of theHelpFileOrRefURL
			return
		else if theButton = item 2 of dialogButtons then
			return
		else
			if theQuery = "" then return
		end if
		
		set theMetaGroup to create location ("/" & theMetaGroupName) in theDatabase
		if theTemplateThumbnailUUID ≠ "" then set thumbnail of theMetaGroup to thumbnail of (get record with uuid theTemplateThumbnailUUID)
		
		if scopeDatabase = true then
			set theSubsetsSmartGroup to {}
			set theSmartGroups to (smart groups of theDatabase whose location is ("/" & theMetaGroupName & "/") and search predicates = theQuery)
			if theSmartGroups = {} then
				set theSmartGroup to create record with {type:smart group, search predicates:theQuery, name:theQuery, exclude from search:true} in theMetaGroup
				set search group of theSmartGroup to (item 1 of theSearchGroups)
			else
				set theSmartGroup to item 1 of theSmartGroups
			end if
		else
			if not (exists record at ("/" & theMetaGroupName & "/" & theSmartGroupName) in theDatabase) then
				set theSubsetsSmartGroup to create record with {type:smart group, search predicates:"kind:smart group", name:theSmartGroupName, exclude from search:true} in theMetaGroup
				set search group of theSubsetsSmartGroup to theDatabase
			else
				set theSubsetsSmartGroup to get record at ("/" & theMetaGroupName & "/" & theSmartGroupName) in theDatabase
			end if
			set newSmartGroups to {}
			repeat with thisSearchGroup in theSearchGroups
				set theSmartGroups to (smart groups of theDatabase whose location is (location of thisSearchGroup & name of thisSearchGroup & "/") and search predicates = theQuery)
				if theSmartGroups = {} then
					set theSmartGroup to create record with {type:smart group, search predicates:theQuery, name:theQuery & " in: " & name of thisSearchGroup} in thisSearchGroup
					set search group of theSmartGroup to thisSearchGroup
				else
					set theSmartGroup to item 1 of theSmartGroups
				end if
				set end of newSmartGroups to theSmartGroup
			end repeat
		end if
		
		if revealInCurrentWindow = true then
			if (count theSearchGroups) = 1 then
				set selection of window 1 to {theSmartGroup}
			else
				set root of window 1 to theSubsetsSmartGroup
				set selection of window 1 to newSmartGroups
			end if
		else if openInCurrentWindow = true then
			if (count theSearchGroups) = 1 then
				set root of window 1 to theSmartGroup
			else
				set root of window 1 to theSubsetsSmartGroup
				set selection of window 1 to newSmartGroups
			end if
		else if openInNewWindow = true then
			if (count theSearchGroups) = 1 then
				open window for record theSmartGroup
			else
				open window for record theSubsetsSmartGroup
				set selection of window 1 to newSmartGroups
			end if
		else if openInNewWindows = true then
			if (count theSearchGroups) = 1 then
				open window for record theSmartGroup
			else
				repeat with thisSmartGroup in newSmartGroups
					open window for record thisSmartGroup
				end repeat
			end if
		end if
		
	on error error_message number error_number
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		return
	end try
end tell

on updateSmartGroup(theRecord)
	tell application id "DNtp"
		try
			set {theName, theQuery} to {name, search predicates} of theRecord
			set dialogButtons to {"Hilfe", "Abbrechen", "OK"}
			set theDialog to display dialog theQuery default answer theQuery buttons dialogButtons default button 3 with title theName with icon theIconPath
			set {theButton, newQuery} to {button returned, text returned} of theDialog
			if theButton = item 1 of dialogButtons then
				do shell script "open " & quoted form of theHelpFileOrRefURL
				return
			else if theButton = item 2 of dialogButtons then
				return
			else
				considering case
					if newQuery = theQuery or newQuery = "" then return
				end considering
				set search predicates of theRecord to newQuery
				set dialogButtons to {"Abbrechen", "OK"}
				set theDialog to display dialog "Name:" default answer newQuery buttons dialogButtons default button 2 with title theName with icon theIconPath
				set {theButton, newName} to {button returned, text returned} of theDialog
				if theButton = item 1 of dialogButtons then
					return
				else if theButton = item 2 of dialogButtons then
					if newName = "" then return
					if location of theRecord = ("/" & theMetaGroupName & "/") then
						set name of theRecord to newName
					else
						set name of theRecord to newName & " in: " & name of parent 1 of theRecord
					end if
				end if
			end if
			
		on error error_message number error_number
			error number -128
		end try
	end tell
end updateSmartGroup