mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-23 22:04:55 +02:00
Use the mordern browse folder dialog to get folder path
Add new methods to CustomFileDialog: - setTitle() sets the dialog title - setFolder() sets an initial directory - pickFolder() shows a file open dialog to select a folder Use CustomFileDialog in folderBrowser(). Affected areas: - Search > Find in Files - File > Open Folder as Workspace - Preferences > Default Directory - Preferences > Backup > Custom Backup - Preferences > Cloud & Link Fix #8513, close #9378
This commit is contained in:
parent
38f6319f4e
commit
b58a5cc227
@ -27,14 +27,13 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
#include <shlobj.h>
|
|
||||||
#include <uxtheme.h>
|
#include <uxtheme.h>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
|
|
||||||
#include "StaticDialog.h"
|
#include "StaticDialog.h"
|
||||||
|
#include "CustomFileDialog.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Utf8.h"
|
#include "Utf8.h"
|
||||||
#include <Parameters.h>
|
#include <Parameters.h>
|
||||||
@ -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 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:
|
// Get an initial directory from the edit control or from argument provided
|
||||||
// http://www.bcbdev.com/faqs/faq62.htm
|
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
|
const TCHAR* szDir = dlg.pickFolder();
|
||||||
// allocated by the shell. Eventually, we will need to free this
|
if (szDir)
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
// If we were able to get the shell malloc object,
|
// Send the result back to the edit control
|
||||||
// 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];
|
|
||||||
if (outputCtrlID != 0)
|
if (outputCtrlID != 0)
|
||||||
::GetDlgItemText(parent, outputCtrlID, directory, _countof(directory));
|
::SetDlgItemText(parent, outputCtrlID, szDir);
|
||||||
directory[_countof(directory) - 1] = '\0';
|
folderName = szDir;
|
||||||
|
|
||||||
if (!directory[0] && defaultStr)
|
|
||||||
info.lParam = reinterpret_cast<LPARAM>(defaultStr);
|
|
||||||
else
|
|
||||||
info.lParam = reinterpret_cast<LPARAM>(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();
|
|
||||||
}
|
}
|
||||||
return dirStr;
|
return folderName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
generic_string getFolderName(HWND parent, const TCHAR *defaultDir)
|
generic_string getFolderName(HWND parent, const TCHAR *defaultDir)
|
||||||
{
|
{
|
||||||
generic_string folderName;
|
return folderBrowser(parent, TEXT("Select a folder"), 0, defaultDir);
|
||||||
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<LPARAM>(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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,16 +55,22 @@ public:
|
|||||||
_dialog->Release();
|
_dialog->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool initSave()
|
bool init(CLSID id)
|
||||||
{
|
{
|
||||||
if (_dialog)
|
if (_dialog)
|
||||||
return false; // Avoid double initizliation
|
return false; // Avoid double initizliation
|
||||||
|
|
||||||
HRESULT hr = CoCreateInstance(CLSID_FileSaveDialog,
|
HRESULT hr = CoCreateInstance(id,
|
||||||
NULL,
|
NULL,
|
||||||
CLSCTX_INPROC_SERVER,
|
CLSCTX_INPROC_SERVER,
|
||||||
IID_PPV_ARGS(&_dialog));
|
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')
|
if (SUCCEEDED(hr) && _defExt && _defExt[0] != '\0')
|
||||||
hr = _dialog->SetDefaultExtension(_defExt);
|
hr = _dialog->SetDefaultExtension(_defExt);
|
||||||
|
|
||||||
@ -79,7 +85,20 @@ public:
|
|||||||
if (SUCCEEDED(hr) && _fileTypeIndex >= 0)
|
if (SUCCEEDED(hr) && _fileTypeIndex >= 0)
|
||||||
hr = _dialog->SetFileTypeIndex(_fileTypeIndex + 1); // This index is 1-based
|
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)
|
bool addFlags(DWORD dwNewFlags)
|
||||||
@ -168,14 +187,18 @@ public:
|
|||||||
static const int IDC_FILE_CHECKBOX = 4;
|
static const int IDC_FILE_CHECKBOX = 4;
|
||||||
|
|
||||||
HWND _hwndOwner = nullptr;
|
HWND _hwndOwner = nullptr;
|
||||||
IFileDialog* _dialog = nullptr;
|
const TCHAR* _title = nullptr;
|
||||||
IFileDialogCustomize* _customize = nullptr;
|
|
||||||
const TCHAR* _defExt = nullptr;
|
const TCHAR* _defExt = nullptr;
|
||||||
|
const TCHAR* _folder = nullptr;
|
||||||
const TCHAR* _checkboxLabel = nullptr;
|
const TCHAR* _checkboxLabel = nullptr;
|
||||||
bool _isCheckboxActive = true;
|
bool _isCheckboxActive = true;
|
||||||
std::vector<std::pair<generic_string, generic_string>> _filterSpec; // text + extension
|
std::vector<std::pair<generic_string, generic_string>> _filterSpec; // text + extension
|
||||||
TCHAR _fileName[MAX_PATH * 8];
|
|
||||||
int _fileTypeIndex = -1;
|
int _fileTypeIndex = -1;
|
||||||
|
|
||||||
|
private:
|
||||||
|
IFileDialog* _dialog = nullptr;
|
||||||
|
IFileDialogCustomize* _customize = nullptr;
|
||||||
|
TCHAR _fileName[MAX_PATH * 8];
|
||||||
};
|
};
|
||||||
|
|
||||||
CustomFileDialog::CustomFileDialog(HWND hwnd) : _impl{std::make_unique<Impl>()}
|
CustomFileDialog::CustomFileDialog(HWND hwnd) : _impl{std::make_unique<Impl>()}
|
||||||
@ -185,6 +208,11 @@ CustomFileDialog::CustomFileDialog(HWND hwnd) : _impl{std::make_unique<Impl>()}
|
|||||||
|
|
||||||
CustomFileDialog::~CustomFileDialog() = default;
|
CustomFileDialog::~CustomFileDialog() = default;
|
||||||
|
|
||||||
|
void CustomFileDialog::setTitle(const TCHAR* title)
|
||||||
|
{
|
||||||
|
_impl->_title = title;
|
||||||
|
}
|
||||||
|
|
||||||
void CustomFileDialog::setExtFilter(const TCHAR *extText, const TCHAR *exts)
|
void CustomFileDialog::setExtFilter(const TCHAR *extText, const TCHAR *exts)
|
||||||
{
|
{
|
||||||
// Add an asterisk before each dot in file patterns
|
// Add an asterisk before each dot in file patterns
|
||||||
@ -209,6 +237,11 @@ void CustomFileDialog::setDefExt(const TCHAR* ext)
|
|||||||
_impl->_defExt = ext;
|
_impl->_defExt = ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CustomFileDialog::setFolder(const TCHAR* folder)
|
||||||
|
{
|
||||||
|
_impl->_folder = folder;
|
||||||
|
}
|
||||||
|
|
||||||
void CustomFileDialog::setCheckbox(const TCHAR* text, bool isActive)
|
void CustomFileDialog::setCheckbox(const TCHAR* text, bool isActive)
|
||||||
{
|
{
|
||||||
_impl->_checkboxLabel = text;
|
_impl->_checkboxLabel = text;
|
||||||
@ -237,7 +270,6 @@ const TCHAR* CustomFileDialog::doSaveDlg()
|
|||||||
_impl->setInitDir(params.getWorkingDir());
|
_impl->setInitDir(params.getWorkingDir());
|
||||||
|
|
||||||
_impl->addFlags(FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_FORCEFILESYSTEM);
|
_impl->addFlags(FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_FORCEFILESYSTEM);
|
||||||
_impl->addControls();
|
|
||||||
bool bOk = _impl->show();
|
bool bOk = _impl->show();
|
||||||
|
|
||||||
if (params.getNppGUI()._openSaveDir == dir_last)
|
if (params.getNppGUI()._openSaveDir == dir_last)
|
||||||
@ -249,3 +281,13 @@ const TCHAR* CustomFileDialog::doSaveDlg()
|
|||||||
|
|
||||||
return bOk ? _impl->getResultFilename() : nullptr;
|
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;
|
||||||
|
}
|
||||||
|
@ -40,12 +40,15 @@ class CustomFileDialog
|
|||||||
public:
|
public:
|
||||||
explicit CustomFileDialog(HWND hwnd);
|
explicit CustomFileDialog(HWND hwnd);
|
||||||
~CustomFileDialog();
|
~CustomFileDialog();
|
||||||
|
void setTitle(const TCHAR* title);
|
||||||
void setExtFilter(const TCHAR* text, const TCHAR* ext);
|
void setExtFilter(const TCHAR* text, const TCHAR* ext);
|
||||||
void setDefExt(const TCHAR* ext);
|
void setDefExt(const TCHAR* ext);
|
||||||
|
void setFolder(const TCHAR* folder);
|
||||||
void setCheckbox(const TCHAR* text, bool isActive = true);
|
void setCheckbox(const TCHAR* text, bool isActive = true);
|
||||||
void setExtIndex(int extTypeIndex);
|
void setExtIndex(int extTypeIndex);
|
||||||
|
|
||||||
const TCHAR* doSaveDlg();
|
const TCHAR* doSaveDlg();
|
||||||
|
const TCHAR* pickFolder();
|
||||||
|
|
||||||
bool getCheckboxState() const;
|
bool getCheckboxState() const;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user