Sometimes it is useful to display a file (and you have a FolderItem Reference) in its window…
I previously used FolderItem.Show to do that in the near past.
How can I do that today ?
Sometimes it is useful to display a file (and you have a FolderItem Reference) in its window…
I previously used FolderItem.Show to do that in the near past.
How can I do that today ?
Here is what I use:
Protected Sub doRevealFolderItem(f As FolderItem)
'www.xojoitaliablog.com/evidenziare-un-file-sul-desktop
If f = Nil Or Not f.Exists Then Return
#If TargetDesktop Then
If f.IsFolder Then
'if f.Name.IndexOf(0, ".") >= 0 then f = f.parent 'dot in folder name therefore reveal the parent e.g. pages
If f.isBundleMBS Then f = f.Parent
f.Open(True)
Return
Else
#If TargetMacOS Then
'[Fix] Reveal in Finder now highlights the file itself, not just opens the folder,
'using shell.execute(""open --reveal /path/to/my\ file"") or Var ok as Boolean, ok = sendItemAE(""misc"", ""mvis"", ""com.apple.finder"", f) or NSWorkSpaceMBS.selectFile"
'tempString = "open -R """ + f.NativePath + """"
'tempShell.Execute(tempString)
'if tempShell.ExitCode <> 0 then
'f.parent.Open
'end if
'tempShell
'Return
Call NSWorkSpaceMBS.selectFile(f)
Return
#ElseIf TargetWindows Then
Var tempShell As New Shell 'used by Linux
Var tempString As String 'used by Linux
'returnValue = WinOpenFolderAndSelectItemsMBS(f.parent, Array(f))
'if returnValue <> 0 then
'f.parent.Open
'end if
'tempString = "explorer.exe /select," + f.NativePath 'not revealing folder for MVV
'tempString = "explorer.exe /select,""" + f.NativePath + """"
tempString = "explorer.exe /root,/separate,/select,""" + f.NativePath + """" 'run on separate new process
tempShell.Execute(tempString)
'If tempShell.ExitCode <> 0 Then
If tempShell.ExitCode > 1 Then 'Error 1 seems to be success, so don't open the window twice!
f.Parent.Open(True)
End If
tempShell.Close
Return
#ElseIf TargetLinux Then
Var tempShell As New Shell 'used by Linux
Var tempString As String 'used by Linux
tempString = "xdg-open """ + f.Parent.NativePath + """"
tempShell.Execute(tempString)
If tempShell.ExitCode <> 0 Then
f.parent.Open
End If
Return
#Else
f = f.Parent
f.Open
#EndIf
End If
#EndIf
End Sub
For Windows, you can use WinOpenFolderAndSelectItemsMBS function in MBS Xojo Plugin, which may be better than your explorer.exe trick.
Thank you for your answers.
I am retired (nearly 70) and do not have money to invest (sorry Christian).
My workaround is to use:
If Reference_File_FI.Parent <> Nil Then
Reference_File_FI.Parent.Open
End If
Reference_File_FI is the file FolderItem.
Better than nothing; of course it does not select the target file, but at last, it open and display its window.
David, I have a function I made with the help I found here on this forum, and someone gave me the Windows instruction:
CdeShell.execute("explorer.exe /select, " + CetElt.shellpath)
why do you write:
"explorer.exe /root,/separate,/select,""" + f.NativePath + """"
?
What means " /root,/separate," please? Should I add it?
Emile, you can download on my webpage my “Zx_External” Module which contains a function “RevealEltFinder” (I repeat, I made it with the help of the Xojo community gave me on this forum). I think you will understand how to use the function. But you can download one of my project in which I may use this function like (example my project " ScreenCaptCoord"). My projects with a lock are protected because I spent many time on them.
Thanks Thomas.
IIFC the window might not appear unless it was launched by Explorer on its own process. I cannot remember where I found this out, possibly StackFlow. I seem to remember testing it until the file appeared correctly on Windows 10.
I’m using the following in macOS:
Public Sub showInFinder(f as FolderItem)
declare function objc_getClass lib "libobjc.dylib" (name as CString) as ptr
declare function sharedWorkspace Lib "AppKit" selector "sharedWorkspace" (obj As ptr) As ptr
declare function selectFile lib "AppKit" selector "selectFile:inFileViewerRootedAtPath:" (obj as ptr, fPath as CFStringRef, rootFullPath as CFStringRef) as boolean
var workspace as ptr = sharedWorkspace(objc_getClass("NSWorkspace"))
try
call selectFile(workspace, f.NativePath, "")
catch
System.DebugLog("showInFinder: error")
end try
End Sub
Grzegorz Pawlik, that’s exactly the code I pasted in my function, except I did not write the Try Catch for the call selectFile(workspace, f.NativePath, “”) . I never get an error, I suppose error are handles in the function selectFile and it return something depending of error or not. I don’t remember the Try Catch on the code I copy from this forum. I will search the topic where I got it.
Edit: I found, it was in this topic.
I have no idea why I’m using try-catch here, it must have been my own overeager addition at the time I copied the code to my projects
In case f is nil
(not checked before ?)
I ´m not front of my computer but usually, in all those function (reveals in Finder, check if package, get extension, etc. ) in don’t check in the function but I have to do it before. Like the function included in Xogo like get the path, get the parent, get the name , etc. )
Sometimes, people forget elementary stuff…
Like I do with a project for a Windows declare code (5 lines) who worked fine in Xojo 2015, but returns complains in far later Xojo.
Now I use #If TargetXXX even if this is a one OS runner around OS specific code…
Aren’t you asking for a macOS solution? Thomas’ is for Windows. At least you asked this in the mac sub forum, right?
Also, why not keep using the AppleScript? you know that you can run applescripts directly from Xojo, right?
I too used that code but sometime ago I replaced it with a shell:
Public Sub RevealInFinder(extends f as FolderItem)
//# Reveal the FolderItem in the Finder (or third party replacement)
//or a shell, accepted by MAS
Dim sh As New shell
sh.Execute "open -R "+chrb(34)+f.NativePath+chr(34)
'#if TargetMacOS
'Declare Function objc_getClass Lib “Cocoa” ( name As CString ) As ptr
'Declare Function sharedWorkspace Lib “AppKit” selector “sharedWorkspace” ( obj As ptr ) As ptr
'Declare Function selectFile Lib “AppKit” selector “selectFile:inFileViewerRootedAtPath:” ( obj As ptr, fPath As CFStringRef, rootFullPath As CFStringRef ) As Boolean
'Dim workspace As ptr = sharedWorkspace( objc_getClass( “NSWorkspace” ) )
’
'Call selectFile( workspace, f.Nativepath, “”)
'#else
'#pragma unused f
'#endif
End Sub
Yes, I’m using macOS.
Yes, I thank @ AppleScript, but I forgot how to use it, then search in the (new) documentation found nothing, then seach in docs (the previous one) and found it, search back in the new documentation and found the same page and stopped there (after adding an Issue, a premiere for all the past 5 ? years).
'm tired of spending hours researching documentation with interesting results.
I may go back there one day; I just show the folder (it’s much better than searching in Finder).
Thanks.
PS: I am not a searcher; I only want to develop applications (solutions)…
I have the Shell version but I don’t use it. And I copy from here (the Xojo forum) the method for the 3 plateform (I don’t use Linux). Here is the code which is in my Module I gave the link above:
If CetElt.Parent = Nil Then
If CetElt.DossPasPack_f Then ' C'est forcément un Dossier si pas de parent mais je teste quand même
CetElt.Open ' Comme c'est un dossier (un volume en fait) ça l'ouvre dans le Finder
Else
#If DebugBuild Then
MessageBox "Bizarre Tom, RevealEltFinder, '" + CetElt.AbsPath_f + "' n'a pas de parent (volume ?) et est un Package ???!!!"
#EndIf
End If
Else
#If TargetMacOS Then
#If True Then
Declare Function objc_getClass Lib "libobjc.dylib" ( name as CString ) as ptr
Declare Function sharedWorkspace Lib "AppKit" selector "sharedWorkspace" ( obj As ptr ) as ptr
Declare Function selectFile Lib "AppKit" selector "selectFile:inFileViewerRootedAtPath:" ( obj as ptr, fPath as CFStringRef, rootFullPath as CFStringRef ) as Boolean
Dim workspace as ptr = sharedWorkspace( objc_getClass( "NSWorkspace" ) )
' assert ( workspace <> nil, CurrentMethodName + " is Nil")
Call selectFile( workspace, CetElt.NativePath, "")
#ElseIf False Then ' Autre méthode via Cde Shell :
Dim CdeShell as New Shell
CdeShell.Execute "open -R " + CetElt.ShellPath
' TampNbre = CdeShell.ErrorCode
' TampText = CdeShell.Result
CdeShell.Close
#Else ' Ancienne méthode via AppleScript :
CetElt.Parent.Launch ' Launch le dossier parent donc l'ouvre dans le Finder, et ne place que cette fenêtre au 1er plan, pas toutes celles du Finder comme
Activate d'AppleScript. Mais le Reveal d'AppleScript ci-dessous ne fait qu'ouvrir la fenêtre du dossier, ça ne la place pas au 1er plan
RevealThisItem(CetElt.NativePath) ' .ShellPath_fAS) ' Mieux que ci-dessus, en plus d'ouvrir la fenêtre du dossier, ça sélectionne l'élément dans la fenêtre, n'existe pas dans RealBasicEn
#EndIf
#ElseIf TargetWindows Then
#If True Then
Dim CdeShell as New Shell ' https://winaero.com/file-explorer-command-line-arguments-in-windows-10/
' J'ai rajouté "/root,/separate," : CdeShell.execute("explorer.exe /select, " + CetElt.shellpath) ' Les espaces sont déjà escapés, inutile de mettre Encodings.UTF8.Chr(34)
' Inutile, voir commentaire ci-dessus : CdeShell.execute("explorer.exe /select, " + Encodings.UTF8.Chr(34) + CetElt.shellpath + Encodings.UTF8.Chr(34))
CdeShell.execute("explorer.exe /root,/separate,/select, " + CetElt.shellpath) ' Ajouter "/root," pour afficher le path depuis /root , et ajouter "/separate," pour ouvrir une nouvelle fenêtre
' TampNbre = CdeShell.ErrorCode
' TampText = CdeShell.Result
CdeShell.Close
#Else ' Merde parfois
' ***** This is a cheap way of doing things, which has its problems *****
' 1. Can only select one file
' 2. If folder is already opened, it doesn't select the file
Declare Function ShellExecuteW lib "shell32" (hwnd as Integer, lpOperation as WString, lpFile as WString, lpParameters as WString, lpDirectory as Integer, nShowCmnd as Integer) as Integer
Dim TpErrNo as Integer
Dim TpParam As String
TpParam = "/select, " + Encodings.UTF8.Chr(34) + CetElt.NativePath + Encodings.UTF8.Chr(34) ' CetElt.AbsolutePath
TpErrNo = ShellExecuteW(App.WindowAt(0).Handle.Integer, "Open", "explorer", TpParam, 0, 1)
#EndIf
#ElseIf TargetLinux Then
' Use xdg-open which is desktop-independent, and should be available in most newer distros
' Otherwise fallback on the two major desktop dependent command tools
Dim CdeShell As New Shell
Dim CommandTools() As String = Array( "xdg-open", "gnome-open", "kde-open" )
For Each TpTool As String In CommandTools
CdeShell.Execute("which " + TpTool)
If CdeShell.Result.Left(1) = "/" Then
CdeShell.Execute(TpTool + " " + CetElt.Parent.ShellPath)
Exit
End If
Next
#Else ' ???
CetElt.Parent.Open ' Launch le dossier parent donc l'ouvre dans le Finder
MessageBox "Error ! Please contact the authors, RevealEltFinder, '" + CetElt.AbsPath_f + "' Which Target ???!!!"
#EndIf
End If
I forgot but I have to put the code of a function I call (this function return true if the Folderitem is a folder but not a package):
Public Function DossPasPack_f(Extends CetElt as FolderItem) As Boolean
Dim TampDrap as Boolean ' Retourne Vrai si CetElt est un directory mais pas un Package
If CetElt.IsFolder Then
TampDrap = (not CetElt.IsPackage_f) ' Si pas TargetMacOS ça retourne (not False) donc True
Else
TampDrap = False
End If
' Je pourrais faire : TampDrap = CetElt.IsFolder and (not CetElt.IsPackage_f) car si 1er test à False alors on ne fait pas le 2ième mais je n'aime pas
Return TampDrap
End Function
And this function call the function I copy from here (the Xojo forum) which return True if the FolderItem (which must be a folder) is a package :
Public Function IsPackage_f(Extends CetElt as FolderItem) As Boolean
Dim DrapPackage as Boolean ' Retourne Vrai si CetElt est un Package (.app .rtfd . pkg .mpkg etc.) et Faux sinon. Note : J'utilise Extends pour pouvoir écrire MonElt.IsPackage_f
#If DebugBuild Then ' Si CetElt n'existe pas ça plantera, doit être testé avant
If not CetElt.IsFolder Then MessageBox "Problème Tom, IsPackage_f , tu ne devrais (dois ?) y tester que des dossiers !"
#EndIf
#If TargetMacOS Then
' #If RBVersion < 2013 Then ' RealStudio donc 10.5 (et +) ' If TargetCarbon Then
' Declare Function LSCopyItemInfoForRef lib "ApplicationServices" (ref as Ptr, whichInfo as Integer, info as Ptr) as Integer
' Dim err as Integer
' Dim rec as New MemoryBlock(24)
'
' err = LSCopyItemInfoForRef(CetElt.FSRef_f, &h4, rec)
' DrapPackage = not(Bitwise.BitAnd(rec.Long(0), 2) = 0)
'
' #Else ' Xojo donc 10.6 et + ' #If TargetCocoa Then
Declare Function boolValue Lib "Foundation" selector "boolValue" ( obj As ptr ) As Boolean
Dim isPackage As ptr
If GetFileValue(CetElt, "NSURLIsPackageKey", isPackage) Then
DrapPackage = boolValue(isPackage)
Else
' At this point, isPackage isa NSError. Do something with it or just assume that it's not a package.
DrapPackage = False
End If
' #EndIf ' Xojo ou RealStudio
#Else ' Windows , Linux
DrapPackage = False
#EndIf
' Méthose Commande Shell
'#If TargetMacOS Then
'Dim CdeShell as New Shell
'' NE PAS utiliser "'" + MonFolderItem.NativePath = MonFolderItem.ShellPath_fAS + "'"
'' NON : CdeShell.Execute "mdls -name kMDItemContentTypeTree '" + CetElt.ShellPath + "'"
'' On n'utilise pas le Quotedform avec ' ' car s'il y a un ' dans le nom ça merde
'' CdeShell.Execute "mdls " + CetElt.ShellPath
'' MessageBox CdeShell.Result
'' Avant : CdeShell.Execute "mdls -name kMDItemContentType -raw " + CetElt.ShellPath
'CdeShell.Execute "mdls -name kMDItemContentTypeTree " + CetElt.ShellPath
'If CdeShell.ErrorCode = 0 Then
'' MessageBox CdeShell.Result
'DrapPackage = not(CdeShell.Result.IndexOf("com.apple.package", ComparisonOptions.CaseInsensitive, AlocaleProg) = -1)
'' Avant : DrapPackage = not((CdeShell.Result = "public.folder") or (CdeShell.Result = "public.volume"))
'Else ' Dossier sur lequel on n'a pas les droits ou etc.
'DrapPackage = False
'' MessageBox "Error code : " + Str(CdeShell.ErrorCode)
'End If
'CdeShell.Close
'
'' Avant avec AppleScript mais c'est plus lent :
'' DrapPackage = (IsPackage_s(CetElt.NativePath = CetElt.ShellPath_fAS) = "True") ' Méthode AppleScript plus lente que méthode avec Carbon
'
'#Else
'DrapPackage = False
'
'#EndIf
Return DrapPackage
End Function