The script is experimental and is probably for the more experienced and adventurous users. There are options for customisation, such as defining some specific groups that a user needs to conduct a search regularly
In my case, I have three preferred groups that I need to search frequently. I use the letter “p”,“w”, and “e” as the letter of entry to specify the group to search.
I assign a short-cut to the script so that I can search for items anywhere in DT. I no longer need to go to a view window for ad hoc search.
Noted that: (1) the boolean cmd fields of “readinglist” and “favorites” have to be created by the user ( it means that I don’t use the DT’s reading list and favourites anymore), and (2) the user needs to specify the uuid of the custom preferred groups in the script. User can use any letter to denote the frequently used groups except for the five reserved letters “a”,“d”,“i”,“r”,“f”.
I will use the script regularly and may make changes in the future.
Hope the script may be useful, or as a kick-starter for further modification, for some DT users.
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
-- By Ngan 2020.02.23
-- Universal search for items in database/databses, perferred group, reading list, and favorites
--v1b2 2020.02.24
-- add "c" as scope:selectoon
--simplify the search in "f":favorites by
--(1) use name:< if only one letter is entered
--(2) using name:~ as default
--v1b3 2020.02.25
--simplify the search in CMD field query
--(1) if only one item is found, open it
--v1b4 2020.02.27
--add "s" for listing all smart groups in current database
-- for theCustomScopeUUID, do not use "a","d","c","s","i","r","f", these 5 letters are reserved for std search prefix
property theCustomScope : {"p", "w", "e"}
property theCustomScopeUUID : ¬
{"82DB1186-ECFE-4D1A-9E1E-XXXXXXXXXXXX", ¬
"1A58150E-7F9A-4443-B691-XXXXXXXXXXXX", ¬
"C0EB6751-85BB-4611-87BE-XXXXXXXXXXXX"}
property cmdRead : "mdreadinglist"
property cmdFavorites : "mdfavorites"
property OpenExternallyForCMDSearch : {".doc", ".xls", ".cmap", ".scap"}
property openCMDDocInCurrentViewWin : false
property useFuzzyForCMDSearch : true
property showSmartGpLocation : true
property theInput : ""
global theDomain, thePredicates
global thePreferGroup
tell application id "DNtp"
set theDesc to "| a | d | c | s | i | r | f | for: " & return & "| DBs | DB | CurrentGp | SmartGroup | Inbox | Read | Favorites |"
set theInput to text returned of (display dialog theDesc with title "Universal Search" default answer theInput)
if theInput is "" then return
set theDomain to text 1 of theInput
if theDomain is not in (theCustomScope & {"a", "d", "c", "s", "i", "r", "f"}) then
display alert "The 1st letter is not defined in the script" giving up after 1
return
end if
-- if length of theInput > 1 then
if length of my trimText(theInput, " ") > 1 then
set thePredicates to texts 3 thru (length of theInput) of theInput
else
set thePredicates to ""
end if
if theDomain is in {"r", "f"} then
my searchCMDList(theDomain, thePredicates)
else if theDomain is "s" then
my searchSmartGp()
else
my searchInDB(theDomain, thePredicates)
end if
end tell
on searchInDB(theDomain, thePredicates)
local theScope
tell application id "DNtp"
if theDomain is not in {"a", "d", "c", "i"} then
set thePreferGroup to get record with uuid (item (my indexOfOneItem(theDomain, theCustomScope)) of theCustomScopeUUID)
set root of viewer window 1 to thePreferGroup
set theScope to " scope:selection "
else if theDomain is "d" then
set theScope to " scope:database "
else if theDomain is "a" then
set theScope to " scope:databases"
else if theDomain is "c" then
set theScope to " scope:selection"
else if theDomain is "i" then
set theScope to " scope:inbox"
end if
set thePredicates to thePredicates & theScope
set search query of viewer window 1 to thePredicates
-- set selection of viewer window 1 to {item 1 of search results of viewer window 1}
set index of viewer window 1 to 1
end tell
end searchInDB
on searchCMDList(theDomain, thePredicates)
local theList, l, theName, theLink, thePath
tell application id "DNtp"
set theScope to " scope:all Databases "
if theDomain is "r" then
set thePredicates to thePredicates & " " & theScope & cmdRead & "==1"
else if theDomain is "f" then
if length of thePredicates > 2 then
set thePredicates to "name:~" & thePredicates & " " & theScope & cmdFavorites & "==1"
else
set thePredicates to "name:<" & thePredicates & " " & theScope & cmdFavorites & "==1"
end if
end if
if useFuzzyForCMDSearch then
set theList to search thePredicates comparison (fuzzy)
else
set theList to search thePredicates
end if
if theList is {} then
display alert "No Items is Found" giving up after 1
return
else if length of theList is 1 then
set theLink to uuid of theList's item 1
set theRecord to get record with uuid theLink
else
set l to {}
repeat with each in theList
set the end of l to name of each
end repeat
set item1 to l's item 1
set l to my sortlist(l)
set theName to (choose from list l with prompt {"Choose Document"} default items item1 with empty selection allowed) as string
if theName is not "false" and theName is not "" then
repeat with each in theList
if theName = (each's name as string) then
set theLink to each's uuid
end if
end repeat
set theRecord to get record with uuid theLink
else
return
end if
end if
------
repeat with each in OpenExternallyForCMDSearch
if filename of theRecord contains each then
set thePath to (path of theRecord as string)
do shell script "open " & quoted form of thePath
return
end if
end repeat
if class of theRecord is in {parent, smart group} then
-- if not openCMDDocInCurrentViewWin then open window for record root of current database
-- if class of think window 1 is not viewer window then open window for record root of current database
set the root of viewer window 1 to theRecord
set the index of viewer window 1 to 1
else
if openCMDDocInCurrentViewWin then
set the root of think window 1 to (parent 1 of theRecord)
set selection of think window 1 to {theRecord}
set the index of viewer window 1 to 1
else
open tab for record theRecord
end if
end if
end tell
end searchCMDList
on searchSmartGp()
local ls, lsn, lsu, l, theGpNm, theGpUUID
set {ls, lsn, lsu, l} to {{}, {}, {}, {}}
tell application id "DNtp"
set ls to every smart group of current database
set ls to my sortObjlist(ls)
if showSmartGpLocation then
repeat with each in ls
set end of lsn to {(name of each & " | Where: " & location of each) & " |"}
set end of lsu to {uuid of each}
end repeat
else
repeat with each in ls
set end of lsn to {name of each}
set end of lsu to {uuid of each}
end repeat
end if
set theGpNm to (choose from list lsn with prompt {"Choose Smart Group"} with empty selection allowed) as string
set theIdx to my indexOfOneItem(theGpNm, lsn)
set theGp to get record with uuid (item theIdx of lsu as string)
set root of viewer window 1 to theGp
end tell
end searchSmartGp
on indexOfOneItem(theItem, theList)
-- credits Emmanuel Levy
set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, return}
set theList to return & theList & return
set AppleScript's text item delimiters to oTIDs
try
-1 + (count (paragraphs of (text 1 thru (offset of (return & theItem & return) in theList) of theList)))
on error
0
end try
end indexOfOneItem
on sortlist(theList)
set theIndexList to {}
set theSortedList to {}
repeat (length of theList) times
set theLowItem to ""
repeat with a from 1 to (length of theList)
if a is not in theIndexList then
set theCurrentItem to item a of theList as text
if theLowItem is "" then
set theLowItem to theCurrentItem
set theLowItemIndex to a
else if theCurrentItem comes before theLowItem then
set theLowItem to theCurrentItem
set theLowItemIndex to a
end if
end if
end repeat
set end of theSortedList to theLowItem
set end of theIndexList to theLowItemIndex
end repeat
return theSortedList
end sortlist
on sortObjlist(theList)
tell application id "DNtp"
set theIndexList to {}
set theSortedList to {}
repeat (length of theList) times
set theLowItem to ""
repeat with a from 1 to (length of theList)
if a is not in theIndexList then
set theCurrentItem to item a of theList
if theLowItem is "" then
set theLowItem to theCurrentItem
set theLowItemIndex to a
else if (name of theCurrentItem) comes before (name of theLowItem) then
set theLowItem to theCurrentItem
set theLowItemIndex to a
end if
end if
end repeat
set end of theSortedList to theLowItem
set end of theIndexList to theLowItemIndex
end repeat
return theSortedList
end tell
end sortObjlist
on trimText(theText, theTrim)
if theText is "" then return ""
set AppleScript's text item delimiters to the theTrim
set the item_list to every text item of theText
set AppleScript's text item delimiters to the ""
set theText to the item_list as string
set AppleScript's text item delimiters to ""
return theText
end trimText