diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index 842d85a9e..104e7874c 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -27,14 +27,13 @@ #include #include #include -#include #include #include #include #include #include "StaticDialog.h" - +#include "CustomFileDialog.h" #include "Common.h" #include "Utf8.h" #include @@ -142,113 +141,37 @@ void writeLog(const TCHAR *logFileName, const char *log2write) } -// Set a call back with the handle after init to set the path. -// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/callbackfunctions/browsecallbackproc.asp -static int __stdcall BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM, LPARAM pData) -{ - if (uMsg == BFFM_INITIALIZED && pData != 0) - ::SendMessage(hwnd, BFFM_SETSELECTION, TRUE, pData); - return 0; -}; - - generic_string folderBrowser(HWND parent, const generic_string & title, int outputCtrlID, const TCHAR *defaultStr) { - generic_string dirStr; + generic_string folderName; + CustomFileDialog dlg(parent); + dlg.setTitle(title.c_str()); - // This code was copied and slightly modifed from: - // http://www.bcbdev.com/faqs/faq62.htm + // Get an initial directory from the edit control or from argument provided + TCHAR directory[MAX_PATH] = {}; + if (outputCtrlID != 0) + ::GetDlgItemText(parent, outputCtrlID, directory, _countof(directory)); + directory[_countof(directory) - 1] = '\0'; + if (!directory[0] && defaultStr) + dlg.setFolder(defaultStr); + else if (directory[0]) + dlg.setFolder(directory); - // SHBrowseForFolder returns a PIDL. The memory for the PIDL is - // allocated by the shell. Eventually, we will need to free this - // memory, so we need to get a pointer to the shell malloc COM - // object that will free the PIDL later on. - LPMALLOC pShellMalloc = 0; - if (::SHGetMalloc(&pShellMalloc) == NO_ERROR) + const TCHAR* szDir = dlg.pickFolder(); + if (szDir) { - // If we were able to get the shell malloc object, - // then proceed by initializing the BROWSEINFO stuct - BROWSEINFO info; - memset(&info, 0, sizeof(info)); - info.hwndOwner = parent; - info.pidlRoot = NULL; - TCHAR szDisplayName[MAX_PATH]; - info.pszDisplayName = szDisplayName; - info.lpszTitle = title.c_str(); - info.ulFlags = BIF_USENEWUI | BIF_NONEWFOLDERBUTTON; - info.lpfn = BrowseCallbackProc; - - TCHAR directory[MAX_PATH]; + // Send the result back to the edit control if (outputCtrlID != 0) - ::GetDlgItemText(parent, outputCtrlID, directory, _countof(directory)); - directory[_countof(directory) - 1] = '\0'; - - if (!directory[0] && defaultStr) - info.lParam = reinterpret_cast(defaultStr); - else - info.lParam = reinterpret_cast(directory); - - // Execute the browsing dialog. - LPITEMIDLIST pidl = ::SHBrowseForFolder(&info); - - // pidl will be null if they cancel the browse dialog. - // pidl will be not null when they select a folder. - if (pidl) - { - // Try to convert the pidl to a display generic_string. - // Return is true if success. - TCHAR szDir[MAX_PATH]; - if (::SHGetPathFromIDList(pidl, szDir)) - { - // Set edit control to the directory path. - if (outputCtrlID != 0) - ::SetDlgItemText(parent, outputCtrlID, szDir); - dirStr = szDir; - } - pShellMalloc->Free(pidl); - } - pShellMalloc->Release(); + ::SetDlgItemText(parent, outputCtrlID, szDir); + folderName = szDir; } - return dirStr; + return folderName; } generic_string getFolderName(HWND parent, const TCHAR *defaultDir) { - generic_string folderName; - LPMALLOC pShellMalloc = 0; - - if (::SHGetMalloc(&pShellMalloc) == NO_ERROR) - { - BROWSEINFO info; - memset(&info, 0, sizeof(info)); - info.hwndOwner = parent; - info.pidlRoot = NULL; - TCHAR szDisplayName[MAX_PATH]; - info.pszDisplayName = szDisplayName; - info.lpszTitle = TEXT("Select a folder"); - info.ulFlags = 0; - info.lpfn = BrowseCallbackProc; - info.lParam = reinterpret_cast(defaultDir); - - // Execute the browsing dialog. - LPITEMIDLIST pidl = ::SHBrowseForFolder(&info); - - // pidl will be null if they cancel the browse dialog. - // pidl will be not null when they select a folder. - if (pidl) - { - // Try to convert the pidl to a display generic_string. - // Return is true if success. - TCHAR szDir[MAX_PATH]; - if (::SHGetPathFromIDList(pidl, szDir)) - // Set edit control to the directory path. - folderName = szDir; - pShellMalloc->Free(pidl); - } - pShellMalloc->Release(); - } - return folderName; + return folderBrowser(parent, TEXT("Select a folder"), 0, defaultDir); } diff --git a/PowerEditor/src/WinControls/OpenSaveFileDialog/CustomFileDialog.cpp b/PowerEditor/src/WinControls/OpenSaveFileDialog/CustomFileDialog.cpp index 4cf2593ef..0f83b6fce 100644 --- a/PowerEditor/src/WinControls/OpenSaveFileDialog/CustomFileDialog.cpp +++ b/PowerEditor/src/WinControls/OpenSaveFileDialog/CustomFileDialog.cpp @@ -55,16 +55,22 @@ public: _dialog->Release(); } - bool initSave() + bool init(CLSID id) { if (_dialog) return false; // Avoid double initizliation - HRESULT hr = CoCreateInstance(CLSID_FileSaveDialog, + HRESULT hr = CoCreateInstance(id, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&_dialog)); + if (SUCCEEDED(hr) && _title) + hr = _dialog->SetTitle(_title); + + if (SUCCEEDED(hr) && _folder) + hr = setInitDir(_folder) ? S_OK : E_FAIL; + if (SUCCEEDED(hr) && _defExt && _defExt[0] != '\0') hr = _dialog->SetDefaultExtension(_defExt); @@ -79,7 +85,20 @@ public: if (SUCCEEDED(hr) && _fileTypeIndex >= 0) hr = _dialog->SetFileTypeIndex(_fileTypeIndex + 1); // This index is 1-based - return SUCCEEDED(hr); + if (SUCCEEDED(hr)) + return addControls(); + + return false; + } + + bool initSave() + { + return init(CLSID_FileSaveDialog); + } + + bool initOpen() + { + return init(CLSID_FileOpenDialog); } bool addFlags(DWORD dwNewFlags) @@ -168,14 +187,18 @@ public: static const int IDC_FILE_CHECKBOX = 4; HWND _hwndOwner = nullptr; - IFileDialog* _dialog = nullptr; - IFileDialogCustomize* _customize = nullptr; + const TCHAR* _title = nullptr; const TCHAR* _defExt = nullptr; + const TCHAR* _folder = nullptr; const TCHAR* _checkboxLabel = nullptr; bool _isCheckboxActive = true; std::vector> _filterSpec; // text + extension - TCHAR _fileName[MAX_PATH * 8]; int _fileTypeIndex = -1; + +private: + IFileDialog* _dialog = nullptr; + IFileDialogCustomize* _customize = nullptr; + TCHAR _fileName[MAX_PATH * 8]; }; CustomFileDialog::CustomFileDialog(HWND hwnd) : _impl{std::make_unique()} @@ -185,6 +208,11 @@ CustomFileDialog::CustomFileDialog(HWND hwnd) : _impl{std::make_unique()} CustomFileDialog::~CustomFileDialog() = default; +void CustomFileDialog::setTitle(const TCHAR* title) +{ + _impl->_title = title; +} + void CustomFileDialog::setExtFilter(const TCHAR *extText, const TCHAR *exts) { // Add an asterisk before each dot in file patterns @@ -209,6 +237,11 @@ void CustomFileDialog::setDefExt(const TCHAR* ext) _impl->_defExt = ext; } +void CustomFileDialog::setFolder(const TCHAR* folder) +{ + _impl->_folder = folder; +} + void CustomFileDialog::setCheckbox(const TCHAR* text, bool isActive) { _impl->_checkboxLabel = text; @@ -237,7 +270,6 @@ const TCHAR* CustomFileDialog::doSaveDlg() _impl->setInitDir(params.getWorkingDir()); _impl->addFlags(FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_FORCEFILESYSTEM); - _impl->addControls(); bool bOk = _impl->show(); if (params.getNppGUI()._openSaveDir == dir_last) @@ -249,3 +281,13 @@ const TCHAR* CustomFileDialog::doSaveDlg() return bOk ? _impl->getResultFilename() : nullptr; } + +const TCHAR* CustomFileDialog::pickFolder() +{ + if (!_impl->initOpen()) + return nullptr; + + _impl->addFlags(FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_FORCEFILESYSTEM | FOS_PICKFOLDERS); + bool bOk = _impl->show(); + return bOk ? _impl->getResultFilename() : nullptr; +} diff --git a/PowerEditor/src/WinControls/OpenSaveFileDialog/CustomFileDialog.h b/PowerEditor/src/WinControls/OpenSaveFileDialog/CustomFileDialog.h index 1436c8320..8318573f2 100644 --- a/PowerEditor/src/WinControls/OpenSaveFileDialog/CustomFileDialog.h +++ b/PowerEditor/src/WinControls/OpenSaveFileDialog/CustomFileDialog.h @@ -40,12 +40,15 @@ class CustomFileDialog public: explicit CustomFileDialog(HWND hwnd); ~CustomFileDialog(); + void setTitle(const TCHAR* title); void setExtFilter(const TCHAR* text, const TCHAR* ext); void setDefExt(const TCHAR* ext); + void setFolder(const TCHAR* folder); void setCheckbox(const TCHAR* text, bool isActive = true); void setExtIndex(int extTypeIndex); const TCHAR* doSaveDlg(); + const TCHAR* pickFolder(); bool getCheckboxState() const;