diff --git a/docs/changes.txt b/docs/changes.txt index dc315b10a5..61a5b46395 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -50,6 +50,7 @@ Changes in behaviour which may result in build errors All: - Add UTF-8 and ZIP 64 support to wxZip{Input,Output}Stream (Tobias Taschner). +- Add wxStandardPaths::GetUserDir() (Tobias Taschner). - Allow calling wxItemContainer::Add() and similar with std::vector<> argument. - Add "%z" support to printf()-like functions like wxString::Format() (RIVDSL). - Add DOCTYPE support to wxXmlDocument (Nick Matthews). diff --git a/include/wx/msw/stdpaths.h b/include/wx/msw/stdpaths.h index 80ad985044..8ae99f2207 100644 --- a/include/wx/msw/stdpaths.h +++ b/include/wx/msw/stdpaths.h @@ -26,7 +26,7 @@ public: virtual wxString GetUserDataDir() const; virtual wxString GetUserLocalDataDir() const; virtual wxString GetPluginsDir() const; - virtual wxString GetDocumentsDir() const; + virtual wxString GetUserDir(Dir userDir) const wxOVERRIDE; // MSW-specific methods @@ -72,6 +72,8 @@ protected: // get the path corresponding to the given standard CSIDL_XXX constant static wxString DoGetDirectory(int csidl); + static wxString DoGetKnownFolder(const GUID& rfid); + // return the directory of the application itself wxString GetAppDir() const; diff --git a/include/wx/osx/core/stdpaths.h b/include/wx/osx/core/stdpaths.h index 8ebe071e9c..fd8078e5f1 100644 --- a/include/wx/osx/core/stdpaths.h +++ b/include/wx/osx/core/stdpaths.h @@ -52,7 +52,7 @@ public: virtual wxString GetLocalizedResourcesDir(const wxString& lang, ResourceCat category = ResourceCat_None) const; - virtual wxString GetDocumentsDir() const; + virtual wxString GetUserDir(Dir userDir) const wxOVERRIDE; protected: // Ctor is protected, use wxStandardPaths::Get() instead of instantiating diff --git a/include/wx/stdpaths.h b/include/wx/stdpaths.h index 7f44468d29..f064abe5e9 100644 --- a/include/wx/stdpaths.h +++ b/include/wx/stdpaths.h @@ -49,6 +49,15 @@ public: AppInfo_VendorName = 2 // the vendor name }; + enum Dir + { + Dir_Documents, + Dir_Desktop, + Dir_Downloads, + Dir_Music, + Dir_Pictures, + Dir_Videos + }; // return the global standard paths object static wxStandardPaths& Get(); @@ -130,7 +139,10 @@ public: // // C:\Documents and Settings\username\My Documents under Windows, // $HOME under Unix and ~/Documents under Mac - virtual wxString GetDocumentsDir() const; + virtual wxString GetDocumentsDir() const + { + return GetUserDir(Dir_Documents); + } // return the directory for the documents files used by this application: // it's a subdirectory of GetDocumentsDir() constructed using the @@ -140,6 +152,7 @@ public: // return the temporary directory for the current user virtual wxString GetTempDir() const; + virtual wxString GetUserDir(Dir userDir) const; // virtual dtor for the base class virtual ~wxStandardPathsBase(); @@ -205,7 +218,7 @@ public: virtual wxString GetLocalDataDir() const { return m_prefix; } virtual wxString GetUserDataDir() const { return m_prefix; } virtual wxString GetPluginsDir() const { return m_prefix; } - virtual wxString GetDocumentsDir() const { return m_prefix; } + virtual wxString GetUserDir(Dir WXUNUSED(userDir)) const { return m_prefix; } protected: // Ctor is protected because wxStandardPaths::Get() should always be used diff --git a/include/wx/unix/stdpaths.h b/include/wx/unix/stdpaths.h index 3e97725abd..74f915398c 100644 --- a/include/wx/unix/stdpaths.h +++ b/include/wx/unix/stdpaths.h @@ -47,7 +47,7 @@ public: virtual wxString GetLocalizedResourcesDir(const wxString& lang, ResourceCat category) const wxOVERRIDE; #ifndef __VMS - virtual wxString GetDocumentsDir() const wxOVERRIDE; + virtual wxString GetUserDir(Dir userDir) const wxOVERRIDE; #endif protected: diff --git a/interface/wx/stdpaths.h b/interface/wx/stdpaths.h index f5fcedb740..c95d7b28d0 100644 --- a/interface/wx/stdpaths.h +++ b/interface/wx/stdpaths.h @@ -66,6 +66,64 @@ public: ResourceCat_Messages }; + /// Possible values for userDir parameter of GetUserDir(). + enum Dir + { + /** + Directory containing user documents. + + Example return values: + - Unix/Mac: @c ~/Documents + - Windows: @c "C:\Users\username\Documents" + */ + Dir_Documents, + + /** + Directory containing files on the users desktop. + + Example return values: + - Unix/Mac: @c ~/Desktop + - Windows: @c "C:\Users\username\Desktop" + */ + Dir_Desktop, + + /** + Directory for downloaded files + + Example return values: + - Unix/Mac: @c ~/Downloads + - Windows: @c "C:\Users\username\Downloads" (Only available on Vista and newer) + */ + Dir_Downloads, + + /** + Directory containing music files. + + Example return values: + - Unix/Mac: @c ~/Music + - Windows: @c "C:\Users\username\Music" + */ + Dir_Music, + + /** + Directory containing picture files. + + Example return values: + - Unix/Mac: @c ~/Pictures + - Windows: @c "C:\Users\username\Pictures" + */ + Dir_Pictures, + + /** + Directory containing video files. + + Example return values: + - Unix: @c ~/Videos + - Windows: @c "C:\Users\username\Videos" + - Mac: @c ~/Movies + */ + Dir_Videos + }; /** MSW-specific function undoing the effect of IgnoreAppSubDir() calls. @@ -138,17 +196,11 @@ public: virtual wxString GetDataDir() const; /** - Return the directory containing the current user's documents. - - Example return values: - - Unix: @c ~ (the home directory) - - Windows: @c "C:\Users\username\Documents" or - @c "C:\Documents and Settings\username\My Documents" - - Mac: @c ~/Documents + Same as calling GetUserDir() with Dir_Documents parameter. @since 2.7.0 - @see GetAppDocumentsDir() + @see GetAppDocumentsDir(), GetUserDir() */ virtual wxString GetDocumentsDir() const; @@ -259,6 +311,17 @@ public: */ virtual wxString GetUserDataDir() const; + /** + Return the path of the specified user data directory. + + If the value could not be determined the users home directory is returned. + + @note On Unix this supports the xdg user dirs specification. + + @since 3.1.0 + */ + virtual wxString GetUserDir(Dir userDir) const; + /** Return the directory for user data files which shouldn't be shared with the other machines. diff --git a/src/common/stdpbase.cpp b/src/common/stdpbase.cpp index 41e27e7724..143c4f117c 100644 --- a/src/common/stdpbase.cpp +++ b/src/common/stdpbase.cpp @@ -114,11 +114,6 @@ wxString wxStandardPathsBase::GetUserLocalDataDir() const return GetUserDataDir(); } -wxString wxStandardPathsBase::GetDocumentsDir() const -{ - return wxFileName::GetHomeDir(); -} - wxString wxStandardPathsBase::GetAppDocumentsDir() const { const wxString docsDir = GetDocumentsDir(); @@ -133,6 +128,11 @@ wxString wxStandardPathsBase::GetTempDir() const return wxFileName::GetTempDir(); } +wxString wxStandardPathsBase::GetUserDir(Dir WXUNUSED(userDir)) const +{ + return wxFileName::GetHomeDir(); +} + /* static */ wxString wxStandardPathsBase::AppendPathComponent(const wxString& dir, diff --git a/src/msw/stdpaths.cpp b/src/msw/stdpaths.cpp index ee8c601f18..8e03fcf6fe 100644 --- a/src/msw/stdpaths.cpp +++ b/src/msw/stdpaths.cpp @@ -36,6 +36,7 @@ #include "wx/msw/private.h" #include "wx/msw/wrapshl.h" +#include // ---------------------------------------------------------------------------- // types @@ -43,6 +44,7 @@ typedef HRESULT (WINAPI *SHGetFolderPath_t)(HWND, int, HANDLE, DWORD, LPTSTR); typedef HRESULT (WINAPI *SHGetSpecialFolderPath_t)(HWND, LPTSTR, int, BOOL); +typedef HRESULT (WINAPI *SHGetKnownFolderPath_t)(const GUID&, DWORD, HANDLE, PWSTR *); // ---------------------------------------------------------------------------- // constants @@ -86,6 +88,9 @@ typedef HRESULT (WINAPI *SHGetSpecialFolderPath_t)(HWND, LPTSTR, int, BOOL); namespace { +DEFINE_GUID(wxFOLDERID_Downloads, + 0x374de290, 0x123f, 0x4565, 0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b); + struct ShellFunctions { ShellFunctions() @@ -97,6 +102,7 @@ struct ShellFunctions SHGetFolderPath_t pSHGetFolderPath; SHGetSpecialFolderPath_t pSHGetSpecialFolderPath; + SHGetKnownFolderPath_t pSHGetKnownFolderPath; bool initialized; }; @@ -146,6 +152,9 @@ void ResolveShellFunctions() dllShellFunctions.GetSymbol(funcname + UNICODE_SUFFIX); } + gs_shellFuncs.pSHGetKnownFolderPath = (SHGetKnownFolderPath_t) + dllShellFunctions.GetSymbol("SHGetKnownFolderPath"); + // finally we fall back on SHGetSpecialFolderLocation (shell32.dll 4.0), // but we don't need to test for it -- it is available even under Win95 @@ -242,6 +251,28 @@ wxString wxStandardPaths::DoGetDirectory(int csidl) return dir; } +wxString wxStandardPaths::DoGetKnownFolder(const GUID& rfid) +{ + if (!gs_shellFuncs.initialized) + ResolveShellFunctions(); + + wxString dir; + + if ( gs_shellFuncs.pSHGetKnownFolderPath ) + { + PWSTR pDir; + HRESULT hr = gs_shellFuncs.pSHGetKnownFolderPath(rfid, 0, 0, &pDir); + if ( SUCCEEDED(hr) ) + { + dir = pDir; + CoTaskMemFree(pDir); + } + } + + return dir; +} + + wxString wxStandardPaths::GetAppDir() const { if ( m_appDir.empty() ) @@ -252,9 +283,38 @@ wxString wxStandardPaths::GetAppDir() const return m_appDir; } -wxString wxStandardPaths::GetDocumentsDir() const +wxString wxStandardPaths::GetUserDir(Dir userDir) const { - return DoGetDirectory(CSIDL_PERSONAL); + int csidl; + switch (userDir) + { + case Dir_Desktop: + csidl = CSIDL_DESKTOPDIRECTORY; + break; + case Dir_Downloads: + { + csidl = CSIDL_PERSONAL; + // Downloads folder is only available since Vista + wxString dir = DoGetKnownFolder(wxFOLDERID_Downloads); + if ( !dir.empty() ) + return dir; + break; + } + case Dir_Music: + csidl = CSIDL_MYMUSIC; + break; + case Dir_Pictures: + csidl = CSIDL_MYPICTURES; + break; + case Dir_Videos: + csidl = CSIDL_MYVIDEO; + break; + default: + csidl = CSIDL_PERSONAL; + break; + } + + return DoGetDirectory(csidl); } // ---------------------------------------------------------------------------- diff --git a/src/osx/core/stdpaths_cf.cpp b/src/osx/core/stdpaths_cf.cpp index c5b4571bf0..85a165e25b 100644 --- a/src/osx/core/stdpaths_cf.cpp +++ b/src/osx/core/stdpaths_cf.cpp @@ -96,17 +96,62 @@ wxString wxStandardPathsCF::GetFromFunc(wxCFURLRef (*func)(wxCFBundleRef)) const return ret; } -wxString wxStandardPathsCF::GetDocumentsDir() const +wxString wxStandardPathsCF::GetUserDir(Dir userDir) const { #if defined( __WXMAC__ ) && wxOSX_USE_CARBON + OSType folderType; + switch (userDir) + { + case Dir_Desktop: + folderType = kDesktopFolderType; + break; + case Dir_Downloads: + folderType = kDownloadsFolderType; + break; + case Dir_Music: + folderType = kMusicDocumentsFolderType; + break; + case Dir_Pictures: + folderType = kPictureDocumentsFolderType; + break; + case Dir_Videos: + folderType = kMovieDocumentsFolderType; + break; + default: + folderType = kDocumentsFolderType; + break; + } + return wxMacFindFolderNoSeparator ( kUserDomain, - kDocumentsFolderType, + folderType, kCreateFolder ); #else - return wxFileName::GetHomeDir() + wxT("/Documents"); + wxString userDirName; + switch (userDir) + { + case Dir_Desktop: + userDirName = "Desktop"; + break; + case Dir_Downloads: + userDirName = "Downloads"; + break; + case Dir_Music: + userDirName = "Music"; + break; + case Dir_Pictures: + userDirName = "Pictures"; + break; + case Dir_Videos: + userDirName = "Movies"; + break; + default: + userDirName = "Documents"; + break; + } + return wxFileName::GetHomeDir() + "/" + userDirName; #endif } diff --git a/src/unix/stdpaths.cpp b/src/unix/stdpaths.cpp index 4e0c37b18f..2880ff9f41 100644 --- a/src/unix/stdpaths.cpp +++ b/src/unix/stdpaths.cpp @@ -233,7 +233,7 @@ wxStandardPaths::GetLocalizedResourcesDir(const wxString& lang, return GetInstallPrefix() + wxT("/share/locale/") + lang + wxT("/LC_MESSAGES"); } -wxString wxStandardPaths::GetDocumentsDir() const +wxString wxStandardPaths::GetUserDir(Dir userDir) const { { wxLogNull logNull; @@ -246,6 +246,29 @@ wxString wxStandardPaths::GetDocumentsDir() const wxString dirsFile = configPath + wxT("/user-dirs.dirs"); if (wxFileExists(dirsFile)) { + wxString userDirId; + switch (userDir) + { + case Dir_Desktop: + userDirId = "XDG_DESKTOP_DIR"; + break; + case Dir_Downloads: + userDirId = "XDG_DOWNLOAD_DIR"; + break; + case Dir_Music: + userDirId = "XDG_MUSIC_DIR"; + break; + case Dir_Pictures: + userDirId = "XDG_PICTURES_DIR"; + break; + case Dir_Videos: + userDirId = "XDG_VIDEOS_DIR"; + break; + default: + userDirId = "XDG_DOCUMENTS_DIR"; + break; + } + wxTextFile textFile; if (textFile.Open(dirsFile)) { @@ -253,13 +276,15 @@ wxString wxStandardPaths::GetDocumentsDir() const for (i = 0; i < textFile.GetLineCount(); i++) { wxString line(textFile[i]); - int pos = line.Find(wxT("XDG_DOCUMENTS_DIR")); + int pos = line.Find(userDirId); if (pos != wxNOT_FOUND) { wxString value = line.AfterFirst(wxT('=')); value.Replace(wxT("$HOME"), homeDir); value.Trim(true); value.Trim(false); + // Remove quotes + value.Replace("\"", "", true /* replace all */); if (!value.IsEmpty() && wxDirExists(value)) return value; else @@ -270,7 +295,7 @@ wxString wxStandardPaths::GetDocumentsDir() const } } - return wxStandardPathsBase::GetDocumentsDir(); + return wxStandardPathsBase::GetUserDir(userDir); } #endif // __VMS/!__VMS diff --git a/tests/interactive/output.cpp b/tests/interactive/output.cpp index d55764fba5..7c656ae677 100644 --- a/tests/interactive/output.cpp +++ b/tests/interactive/output.cpp @@ -404,6 +404,11 @@ void InteractiveOutputTestCase::TestStandardPaths() wxPrintf(wxT("Data dir (user):\t%s\n"), stdp.GetUserDataDir().c_str()); wxPrintf(wxT("Data dir (user local):\t%s\n"), stdp.GetUserLocalDataDir().c_str()); wxPrintf(wxT("Documents dir:\t\t%s\n"), stdp.GetDocumentsDir().c_str()); + wxPrintf(wxT("Desktop dir:\t\t%s\n"), stdp.GetUserDir(wxStandardPaths::Dir_Desktop).c_str()); + wxPrintf(wxT("Downloads dir:\t\t%s\n"), stdp.GetUserDir(wxStandardPaths::Dir_Downloads).c_str()); + wxPrintf(wxT("Music dir:\t\t%s\n"), stdp.GetUserDir(wxStandardPaths::Dir_Music).c_str()); + wxPrintf(wxT("Pictures dir:\t\t%s\n"), stdp.GetUserDir(wxStandardPaths::Dir_Pictures).c_str()); + wxPrintf(wxT("Videos dir:\t\t%s\n"), stdp.GetUserDir(wxStandardPaths::Dir_Videos).c_str()); wxPrintf(wxT("Executable path:\t%s\n"), stdp.GetExecutablePath().c_str()); wxPrintf(wxT("Plugins dir:\t\t%s\n"), stdp.GetPluginsDir().c_str()); wxPrintf(wxT("Resources dir:\t\t%s\n"), stdp.GetResourcesDir().c_str());