EDITED: the completed script with the help of one crucial line from @BLUEFROG
I am trying to write a script to identify where are all the replicants of an item and go to one of those groups directly to decide whether I should keep/delete the instance. I am almost there except that I need one line of code to make the targeted item as the selected item in the viewer window. I search through the topics and it seems that “selection” in window 1 is a r/o property?
I write this script because it is easier to see a list of groups (that just focus on replicants) in one popup window, as comparing to seeing the groups from a drop-down list in the inspector bar (small fonts for my eyes and the list shows both reps and dups). And I can keep jumping to each group by running the script again and again. Just a personal preference.
Many thanks in advance!
The code:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
tell application id "DNtp"
try
if exists (content record) then
set theDoc to content record
else if (count of the selection) is 1 then
set theDoc to item 1 of ((the selection) as list)
else
error ("No document is selected. Please select a document, then try again.")
end if
set theParents to (parents of theDoc whose tag type is not ordinary tag)
set theList to {}
repeat with each in theParents
set theList to my sortlist(theList & {((location of each) & (name of each) as string)})
end repeat
set theDocParentLoc to (choose from list theList with prompt {"Choose which document to link: " & return & "(only select one)"} default items "" OK button name "Go To")
set theDocParent to get record at (theDocParentLoc as string)
set root of think window 1 to theDocParent
-- option 1: set the item as the selected item in the parent group in viewer window
set selection of think window 1 to {theDoc}
-- option 2: filter out the item as the only item in the parent group in viewer window
-- set the search query of think window 1 to "name:~" & (name of theDoc as string) & " scope: selection"
end try
end tell
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
Sure … Hope that’s doable…
Coz at this moment, a clumsy way is to have the script to invoke another search within the group, but I hope that there is a more straight forward way to do it.
EDITED: this line of code may get around with the issue by filtering the item out. But the most ideal outcome is to select the item but also showing the other items in the group.
set the search query of think window 1 to "name:~" & (name of theDoc as string) & " scope: selection"
I will preface this by saying it is usually not a wise idea to set selections in the interface because it causes people to think wrongly about automation. They want to reproduce the mechanical movements they make in an application and that is almost always a really poor idea. (And yes, this is why this is something I didn’t document, nor do I speak of it often.)
That being said… set selection of think window 1 to {theDoc}
I thought about that line (as a very wild guess) BUT the trick is the {}! I am curious to know why {} is still needed even when the var theDoc already contains a record?
Perhaps it’s because the selection is a “list” of record and therefore the syntax must choose an item within a list and not choosing a record?
A much simpler and useful version after a suggestion from @cgrunenberg in this post Experimental: Script to trace a backlink. All groups containing the replicants of an item will be shown in the viewer window. No advance search predicates in search field can produce this result - the DT dictionary is really comprehensive!
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
-- ngan 2019.08.21
tell application id "DNtp"
try
if exists (content record) then
set theDoc to content record
else if (count of the selection) > 1 then
set theDoc to item 1 of ((the selection) as list)
else
error ("No document is selected. Please select a document, then try again.")
end if
set theParents to (parents of theDoc whose tag type is not ordinary tag)
set search results of viewer window 1 to theParents
end try
end tell
Thanks for these scripts Ngan. I often want to see a list of all replicants, and quickly jump to them. While the “instances” tool in the inspector works, it’s not perfect for me — it only lets you jump to the parent folder, and the way it shows the file hierarchy makes it tough (for me) to quickly understand what I am seeing.
I’ve tried both of your scripts, and actually prefer the functionality original one! While I like how the second one uses the search results, you can’t then click on the result to go to that replicant. The first one is clean and quick to use.
Question for you and I could not figure it out - is it possible to modify this script to have it set the parent to only the selected item from the list and delete the other parent?
I think we need something along these lines delete parent of theDoc whose id is all of the other parents other than the ones just selected
But I do not know how to iterate over the list items that were not selected and what the exact command to delete parent connection will be. In fact, I need to figure out how to interpret some of these commands from the dictionary which I did look at.
The dictionary portion that I believe is relevant but don’t know how to use.
Did more research, and sounds like I need to loop over the other items in the list and use this command.
Ok so I think I may have figured it out.
If somebody here can confirm that this is the right code then I will run it. Thank you!
repeat with theParent in theParents
log ((location of theParent) & (name of theParent) as string)
if location of theParent is not equal to location of theDocParent then
log ((location of theParent) & (name of theParent) as string)
delete record theDoc in theParent
end if
end repeat
For some reason, in my database, I have replicants all over the place. I think it is a function of how items were moved to tags, and they stayed in the inbox of the database at the same time.
Now, to remove some replicants, I wrote a script as below. The script fails at the point where I try to check if a record pointing to a group, is contained in a list of other records that point to groups.
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
tell application id "DNtp"
# get selection
set mySelection to selection
repeat with theItem in mySelection
# now for every selection, get the list of groups the item belongs to
# and ask that user select groups that that the item should stay in
set theParents to (parents of theItem whose tag type is not ordinary tag) # this works for replicant
# create list of location and names of parents of theItem
set theList to {}
repeat with each in theParents
set theList to my sortlist(theList & {((location of each) & (name of each) as string)})
end repeat
set theParentNames to theList
set newParentNames to ¬
(choose from list theParentNames ¬
with prompt ¬
"Choose parent locations for -> " & (name of theItem) default items ¬
"" OK button name ¬
"Go To" with multiple selections allowed)
# we have names of newParents and now to convert them to the parent records
set theList to {}
repeat with each in newParentNames
set theList to (theList & {get record at (each as string)})
end repeat
set newParentRecords to theList
# now remove the parent that is not in the newParentRecords
repeat with theParent in theParents
# return (location of theParent)
# return name of item 1 of newParentRecords
log theParent
log "Deciding about " & ((location of theParent) & (name of theParent) as string)
if newParentRecords does not contain (theParent) then
log ("Deleting as parent location " & (location of theParent) & (name of theParent) as string)
# delete record theItem in theParent
end if
end repeat
end repeat
end tell
# sourced from https://discourse.devontechnologies.com/t/find-goto-parent-groups-of-all-replicants-of-an-item/49317
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
Near the end of the script, I try to check if a record exists in a list of records, and the script errors out. Is it because I cannot compare records like the way I am trying to? What is the best way to achieve the if statement below? Thank you!
The line below is what fails.
if newParentRecords does not contain (theParent) then
This is what is not working for me - checking if one group exists in a list of groups.
tell application id "DNtp"
# get selection
set mySelection to selection
set theItem to item 1 of mySelection
set theParents to (parents of theItem whose tag type is not ordinary tag) # this works for replicant
# return item 1 of theParents
set firstParent to item 1 of theParents
if firstParent is in theParents then
# also tried the if statement below
# if theParents contains firstParent
return "Contains"
else
return "Does not contain"
end if
end tell
Well, I did manage to address the if statement issue, by comparing “location and name” as string instead of trying to compare pointers. Would still like to know if somebody can comment as to why the pointers comparison did not work. May be it is not supposed to because only properties can be compared?
Anyhow, the code that should work. Not yet tested but posting here to change the question and answer it somewhat. Thanks for reading!
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
tell application id "DNtp"
# get selection
set mySelection to selection
repeat with theItem in mySelection
# now for every selection, get the list of groups the item belongs to
# and ask that user select groups that that the item should stay in
set theParents to (parents of theItem whose tag type is not ordinary tag) # this works for replicant
# create list of location and names of parents of theItem
set theList to {}
repeat with each in theParents
set theList to my sortlist(theList & {((location of each) & (name of each) as string)})
end repeat
set theParentNames to theList
set newParentNames to ¬
(choose from list theParentNames ¬
with prompt ¬
"Choose parent locations for -> " & (name of theItem) default items ¬
"" OK button name ¬
"Go To" with multiple selections allowed)
# we have names of newParents and now to convert them to the parent records
set theList to {}
repeat with each in newParentNames
set theList to (theList & {get record at (each as string)})
end repeat
set newParentRecords to theList
# now remove the parent that is not in the newParentRecords
repeat with theParentName in theParentNames
# return (location of theParent)
# return name of item 1 of newParentRecords
log theParentName
# log "Deciding about " & ((location of theParent) & (name of theParent) as string)
log "Deciding about " & theParentName
# if newParentRecords does not contain (theParent) then
if theParentName is not in newParentNames then
# log ("Deleting as parent location " & (location of theParent) & (name of theParent) as string)
log "Deleting as parent location" & theParentName
set theParent to (get record at (theParentName as string))
log "Deleting " & name of theParent as string
# delete record theItem in theParent
end if
end repeat
end repeat
end tell
on do_create_uuid_list(recordList)
set nameList to {}
repeat with each in recordList
set nameList to (nameList & {(location of each) & (name of each) as string})
end repeat
return nameList
end do_create_uuid_list
# sourced from https://discourse.devontechnologies.com/t/find-goto-parent-groups-of-all-replicants-of-an-item/49317
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