Fix regression: Handle "Default Directory" setting correctly in Open/Save File Dialog

IFileDialog doesn't modify the current directory unlike the old file
dialog. Now the last used directory is remembered each time the user
changes directory and then set as working directory if needed.

Fix #9767, close #9775
This commit is contained in:
mere-human 2021-04-15 11:09:50 +03:00 committed by Don HO
parent d0afc51621
commit acdc2517c6
2 changed files with 29 additions and 34 deletions

1
.gitignore vendored
View File

@ -95,6 +95,7 @@ PowerEditor/src/tools/NppShell/build_x64
# scintilla - generated files # scintilla - generated files
scintilla/bin/SciLexer.* scintilla/bin/SciLexer.*
scintilla/bin/Scintilla.* scintilla/bin/Scintilla.*
scintilla/bin/libscilexer.a
scintilla/bin/libscintilla.a scintilla/bin/libscintilla.a
scintilla/bin/libscintilla.lib scintilla/bin/libscintilla.lib
scintilla/win32/*.lib scintilla/win32/*.lib

View File

@ -36,9 +36,8 @@ template<class T>
const GUID ComTraits<T>::uid = __uuidof(T); const GUID ComTraits<T>::uid = __uuidof(T);
// Smart pointer alias for COM objects that makes reference counting easier. // Smart pointer alias for COM objects that makes reference counting easier.
template<class T> template<class T, class InterfaceT = T>
using com_ptr = _com_ptr_t<_com_IIID<T, &ComTraits<T>::uid>>; using com_ptr = _com_ptr_t<_com_IIID<T, &ComTraits<InterfaceT>::uid>>;
namespace // anonymous namespace // anonymous
{ {
@ -187,12 +186,6 @@ namespace // anonymous
} }
~CurrentDirBackup() ~CurrentDirBackup()
{ {
NppParameters& params = NppParameters::getInstance();
if (params.getNppGUI()._openSaveDir == dir_last)
{
::GetCurrentDirectory(MAX_PATH, _dir);
params.setWorkingDir(_dir);
}
::SetCurrentDirectory(_dir); ::SetCurrentDirectory(_dir);
} }
private: private:
@ -206,21 +199,6 @@ namespace // anonymous
class FileDialogEventHandler : public IFileDialogEvents, public IFileDialogControlEvents class FileDialogEventHandler : public IFileDialogEvents, public IFileDialogControlEvents
{ {
public: public:
static HRESULT createInstance(IFileDialog* dlg, const std::vector<Filter>& filterSpec,
int fileIndex, int wildcardIndex, REFIID riid, void **ppv)
{
*ppv = nullptr;
FileDialogEventHandler* pDialogEventHandler =
new (std::nothrow) FileDialogEventHandler(dlg, filterSpec, fileIndex, wildcardIndex);
HRESULT hr = pDialogEventHandler ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
hr = pDialogEventHandler->QueryInterface(riid, ppv);
pDialogEventHandler->Release();
}
return hr;
}
// IUnknown methods // IUnknown methods
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) override IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) override
@ -261,8 +239,9 @@ public:
// IFileDialogEvents methods // IFileDialogEvents methods
IFACEMETHODIMP OnFileOk(IFileDialog*) override IFACEMETHODIMP OnFileOk(IFileDialog* dlg) override
{ {
_lastUsedFolder = getDialogFolder(dlg);
return S_OK; return S_OK;
} }
IFACEMETHODIMP OnFolderChange(IFileDialog*) override IFACEMETHODIMP OnFolderChange(IFileDialog*) override
@ -270,9 +249,11 @@ public:
// First launch order: 3. Custom controls are added but inactive. // First launch order: 3. Custom controls are added but inactive.
return S_OK; return S_OK;
} }
IFACEMETHODIMP OnFolderChanging(IFileDialog*, IShellItem*) override IFACEMETHODIMP OnFolderChanging(IFileDialog*, IShellItem* psi) override
{ {
// Called when the current dialog folder is about to change.
// First launch order: 2. Buttons are added, correct window title. // First launch order: 2. Buttons are added, correct window title.
_lastUsedFolder = getFilename(psi);
return S_OK; return S_OK;
} }
IFACEMETHODIMP OnSelectionChange(IFileDialog*) override IFACEMETHODIMP OnSelectionChange(IFileDialog*) override
@ -354,19 +335,22 @@ public:
return E_NOTIMPL; return E_NOTIMPL;
} }
private:
// Use createInstance() instead
FileDialogEventHandler(IFileDialog* dlg, const std::vector<Filter>& filterSpec, int fileIndex, int wildcardIndex) FileDialogEventHandler(IFileDialog* dlg, const std::vector<Filter>& filterSpec, int fileIndex, int wildcardIndex)
: _cRef(1), _dialog(dlg), _customize(dlg), _filterSpec(filterSpec), _lastSelectedType(fileIndex + 1), : _cRef(1), _dialog(dlg), _customize(dlg), _filterSpec(filterSpec), _lastSelectedType(fileIndex + 1),
_wildcardType(wildcardIndex >= 0 ? wildcardIndex + 1 : 0) _wildcardType(wildcardIndex >= 0 ? wildcardIndex + 1 : 0)
{ {
_staticThis = this; _staticThis = this;
} }
~FileDialogEventHandler() ~FileDialogEventHandler()
{ {
_staticThis = nullptr; _staticThis = nullptr;
} }
const generic_string& getLastUsedFolder() const { return _lastUsedFolder; }
private:
FileDialogEventHandler(const FileDialogEventHandler&) = delete; FileDialogEventHandler(const FileDialogEventHandler&) = delete;
FileDialogEventHandler& operator=(const FileDialogEventHandler&) = delete; FileDialogEventHandler& operator=(const FileDialogEventHandler&) = delete;
FileDialogEventHandler(FileDialogEventHandler&&) = delete; FileDialogEventHandler(FileDialogEventHandler&&) = delete;
@ -572,6 +556,7 @@ private:
com_ptr<IFileDialog> _dialog; com_ptr<IFileDialog> _dialog;
com_ptr<IFileDialogCustomize> _customize; com_ptr<IFileDialogCustomize> _customize;
const std::vector<Filter> _filterSpec; const std::vector<Filter> _filterSpec;
generic_string _lastUsedFolder;
HWND _hwndNameEdit = nullptr; HWND _hwndNameEdit = nullptr;
bool _monitorKeyboard = true; bool _monitorKeyboard = true;
UINT _lastSelectedType = 0; UINT _lastSelectedType = 0;
@ -610,7 +595,7 @@ public:
// Init the event handler. // Init the event handler.
// Pass the initially selected file type. // Pass the initially selected file type.
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
hr = FileDialogEventHandler::createInstance(_dialog, _filterSpec, _fileTypeIndex, _wildcardIndex, IID_PPV_ARGS(&_events)); _events.Attach(new FileDialogEventHandler(_dialog, _filterSpec, _fileTypeIndex, _wildcardIndex));
// If "assign type" is OFF, then change the file type to *.* // If "assign type" is OFF, then change the file type to *.*
if (_enableFileTypeCheckbox && !_fileTypeCheckboxValue && _wildcardIndex >= 0) if (_enableFileTypeCheckbox && !_fileTypeCheckboxValue && _wildcardIndex >= 0)
@ -723,11 +708,12 @@ public:
HRESULT hr = S_OK; HRESULT hr = S_OK;
DWORD dwCookie = 0; DWORD dwCookie = 0;
if (_events) com_ptr<IFileDialogEvents> dialogEvents = _events;
if (dialogEvents)
{ {
hr = _dialog->Advise(_events, &dwCookie); hr = _dialog->Advise(dialogEvents, &dwCookie);
if (FAILED(hr)) if (FAILED(hr))
_events.Release(); dialogEvents.Release();
} }
bool okPressed = false; bool okPressed = false;
@ -735,9 +721,17 @@ public:
{ {
hr = _dialog->Show(_hwndOwner); hr = _dialog->Show(_hwndOwner);
okPressed = SUCCEEDED(hr); okPressed = SUCCEEDED(hr);
NppParameters& params = NppParameters::getInstance();
if (params.getNppGUI()._openSaveDir == dir_last)
{
// Note: IFileDialog doesn't modify the current directory.
// At least, after it is hidden, the current directory is the same as before it was shown.
params.setWorkingDir(_events->getLastUsedFolder().c_str());
}
} }
if (_events) if (dialogEvents)
_dialog->Unadvise(dwCookie); _dialog->Unadvise(dwCookie);
return okPressed; return okPressed;
@ -827,7 +821,7 @@ public:
private: private:
com_ptr<IFileDialog> _dialog; com_ptr<IFileDialog> _dialog;
com_ptr<IFileDialogCustomize> _customize; com_ptr<IFileDialogCustomize> _customize;
com_ptr<IFileDialogEvents> _events; com_ptr<FileDialogEventHandler, IFileDialogEvents> _events;
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////