SpecialFolder 'downloads' or 'Photos'?

I’m making a customised file browser.
One of the things it will do is limit the ‘parent’ folders to be specific starting points, like Documents and Desktop

I’m struggling to find a cross platform/cross user method to get
Downloads
Pictures (not the pseudo folder that MacOS gives from the Photos app)

Is there a system call/ MBS plugin /environment variable I can get at for these?

I use MBS to get the Photos Library (if that’s what you’re wanting.) That is Mac-specific, of course, not cross-platform.

“Quick and dirty” for Downloads would be SpecialFolder.UserHome.Child (“Downloads”), which would “usually” work. But the user could re-locate these, perhaps to another drive, especially on Windows and Linux. This works for me; I’m sure it can be tweaked. The Windows declare is one I cobbled (with just a little help from my friends) from a VB example.

Function getUserDownloadsFolder as FolderItem
Var f as FolderItem

#if TargetMacOS then
  Const kUserDomain = SpecialFolder.DomainUser
  Const kDownloadsFolderType = "down"
  
  f=SpecialFolder.GetFromDomainAndCode(kUserDomain, kDownloadsFolderType)
  
#ElseIf TargetWindows Then
  
  Var myID as Ptr=COM.IIDFromString("{374DE290-123F-4565-9164-39C4925E467B}")//"Official" Downloads Folder
  Var myCode as Int32
  Var myPath as WString
  Soft Declare Function SHGetKnownFolderPath Lib "Shell32" (theId as ptr, flags as Int32, ByVal theToken as Int32, ByRef thePath as WString) as Int32
  Soft Declare Sub CoTaskMemFree Lib "ole32" (byVal hMem as WString)
  myCode=SHGetKnownFolderPath(myID,0,0, myPath)
  
  if myCode=0 then
    f=New FolderItem(myPath,FolderItem.PathTypeNative)
  end if
  
  //Release the memory.  
  CoTaskMemFree(myPath)
  
#elseif TargetLinux Then
  
  Var ask as new Shell
  
  ' this gets the setting in ~/.config/user-dirs.dirs.  If the DOWNLOAD entry isn't there, or the file does not exist, it will just return the user root.
  ask.Execute ("xdg-user-dir DOWNLOAD")
  //MessageBox ask.Result
  if ask.ErrorCode=0 then
    Var thePath as String=ask.Result.ReplaceAll(EndOfLine,"")
    f=new FolderItem(thePath,FolderItem.PathModes.Native)
  end if
  
#EndIf

'last resort if we had some sort of weird error

if f=nil Then
  f=SpecialFolder.UserHome
end if

Return f
2 Likes

Thanks.
I’ll play about with this.

1 Like

If it was only for MacOS, you could implement various events of the NSOpenDialogMBS class to only allow the parent folders you want (disabling items outside of them, handling what appear in the navigation popup menu, etc.); I’ve done it in the past.
The benefit of that, obviously, is that all the shortcuts the user may know are handled, since it’s still the native dialog.
I, for one, usually don’t go further in an app when I see it uses non-native UI dialogs. I’m a fan of shortcuts (command-shift-N to create a new folder, drag&drop a folder from the Finder/window’s proxy to the dialog to move straight to it, command-up arrow to move to the parent folder) and, usually, the custom dialogs lack some of them, if not most. Then, I look for alternatives apps.
And I’m not alone in this case.

1 Like

Fair, but you aren’t my demographic, and this will be an optional preference setting anyway.

TBH… If I could assign custom icons by file (rather than by file type) in windows, or create a quickview module for OSX using Xojo, then I wouldn’t be considering it.

If you use File Packages, you don’t need to create a QuickLook plugin, you can customize the Info.plist and create a thumbnail and preview images.

thanks a lot, i’ve added this to my shared libs and credit due

1 Like

That’s rather interesting, but I couldn’t find documentation of this. I probably used the wrong terms in my searches.
I searched with terms such as “QuickLook thumbnail info.plist bundle” and no result found. Can you tell more about that, please?

If this is about Mac, you should switch channel to platforms/macOS.

On Windows, I use:

Specialfolder.Userhome.child("Downloads")
Specialfolder.Userhome.child("Pictures")

However, if the user has enabled OneDrive to save content, pictures may be in

SpecialFolder.UserHome.child("Onedrive").child("Pictures")

You may want to check if the folder contains files. When OneDrive is active the physical Pictures folder is empty.

Also, if OneDrive is active the second folderitem exists, otherwise not.

Does this work even when these folders are relocated (using the built-in option in Windows)?

No.

1 Like

Thanks. That’s the expected answer.

When the user messes up with folders in this fashion, any default becomes lost. The only recourse is to test the folderitem.exists, and if it does not exist, ask the user to point to the right folder with a dialog.

Michel, you and I had this discussion some time ago in another forum. I recall it being in response to my post, in which I was seeking help with the Windows “Downloads Folder” declare that I’ve shared above. I say now as then, that the user is not “messing up” the folders in any fashion. They are using an intrinsic OS function that allows them to set the folder’s location. You seem to be characterizing it as hacking.

In my view, the best practice is to ask the OS for the folder–not insist on it being where I think it “should” be.

Back to that other forum, if I recall correctly, it was a fellow named Jim McKay who gave me the “last little bit” that I lacked, for the declare to work. :slight_smile:

1 Like

Sadly I cannot; AFAIK it is undocumented. It’s one of those tricks that’s been around for decades, which very few people know about. However you can give it a try, you just have to make sure that document package is registered to an application. Download HDRtist NX from ohanaware.com, throw an image in and have a play, then save the file.

Right click the file to show contents, then have a tinker with the plist and swap the two image files for something else. IIRC HDRtist uses only image file and a symbolic link for the other. Icon might not update right away.

1 Like

Would it not be nice to post the code ?

Scroll up in the thread, my friend, scroll up. :slight_smile:

That’s right. Thanks.

By the way, maybe I did not use the proper term, but if the user customizes the download folder in such a way that specialfolder cannot find it, what is a programmer to do ?

Without some declare that points to the target folder, asking the user to point to it would be a valid workaround in my humble opinion.

1 Like

By the way, maybe I did not use the proper term, but if the user customizes the download folder in such a way that specialfolder cannot find it, what is a programmer to do ?

Well, other than providing some shorthand in the file path, “SpecialFolder” is not really doing anything here. You’re calling “SpecialFolder.UserHome.Child (“Downloads”)”, which is a different thing from something like “SpecialFolder.Downloads”. That last one doesn’t exist; I wish differently. So did VB6 users, where I found the VB example of what I reworked into the Xojo declare I’ve shared.

Without some declare that points to the target folder, asking the user to point to it would be a valid workaround in my humble opinion.

The Downloads folder is my default setting because, well, downloading is what my app does. But it is merely the default; my app prominently presents the user with the means of specifying a preferred location, which gets saved to preferences. And then, of course, the user has an option to restore defaults. :slight_smile:

In theory, the code you got should accommodate the user changing their “System” downloads folder. But you’ll never really know until you actually try it :slight_smile:

1 Like