mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-23 13:54:54 +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 <stdexcept>
|
||||
#include <shlwapi.h>
|
||||
#include <shlobj.h>
|
||||
#include <uxtheme.h>
|
||||
#include <cassert>
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
|
||||
#include "StaticDialog.h"
|
||||
|
||||
#include "CustomFileDialog.h"
|
||||
#include "Common.h"
|
||||
#include "Utf8.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 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<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();
|
||||
::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<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;
|
||||
return folderBrowser(parent, TEXT("Select a folder"), 0, defaultDir);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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<std::pair<generic_string, generic_string>> _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<Impl>()}
|
||||
@ -185,6 +208,11 @@ CustomFileDialog::CustomFileDialog(HWND hwnd) : _impl{std::make_unique<Impl>()}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user