Enhance FileDialog for allowing UNIX stile file path
And use modern CustomFileDialog istead of old FileDialog in Notepad++. In the file dialog, override window procedure for "OK" button and file name edit box to check for input. Transform forward slash file name to a Window path after input. Fix #9374, close #9403
This commit is contained in:
parent
ab5c1d3e2a
commit
e7079d57c6
|
@ -871,7 +871,6 @@ You can define several column markers by using white space to separate the diffe
|
|||
<Item id="6413" name="Default Open/Save file Directory"/>
|
||||
<Item id="6414" name="Follow current document"/>
|
||||
<Item id="6415" name="Remember last used directory"/>
|
||||
<Item id="6430" name="Use new style dialog (without Unix style path capacity)"/>
|
||||
<Item id="6431" name="Open all files of folder instead of launching Folder as Workspace on folder dropping"/>
|
||||
</DefaultDir>
|
||||
|
||||
|
|
|
@ -868,7 +868,6 @@ You can define several column markers by using white space to separate the diffe
|
|||
<Item id="6413" name="Default Directory (Open/Save)"/>
|
||||
<Item id="6414" name="Follow current document"/>
|
||||
<Item id="6415" name="Remember last used directory"/>
|
||||
<Item id="6430" name="Use new style dialog (without Unix style path capacity)"/>
|
||||
<Item id="6431" name="Open all files of folder instead of launching Folder as Workspace on folder dropping"/>
|
||||
</DefaultDir>
|
||||
|
||||
|
|
|
@ -146,13 +146,12 @@ generic_string folderBrowser(HWND parent, const generic_string & title, int outp
|
|||
else if (directory[0])
|
||||
dlg.setFolder(directory);
|
||||
|
||||
const TCHAR* szDir = dlg.pickFolder();
|
||||
if (szDir)
|
||||
folderName = dlg.pickFolder();
|
||||
if (!folderName.empty())
|
||||
{
|
||||
// Send the result back to the edit control
|
||||
if (outputCtrlID != 0)
|
||||
::SetDlgItemText(parent, outputCtrlID, szDir);
|
||||
folderName = szDir;
|
||||
::SetDlgItemText(parent, outputCtrlID, folderName.c_str());
|
||||
}
|
||||
return folderName;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "sha-256.h"
|
||||
#include "md5Dlgs.h"
|
||||
#include "md5Dlgs_rc.h"
|
||||
#include "FileDialog.h"
|
||||
#include "CustomFileDialog.h"
|
||||
#include "Parameters.h"
|
||||
#include <shlwapi.h>
|
||||
|
||||
|
@ -63,13 +63,14 @@ INT_PTR CALLBACK HashFromFilesDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
|
|||
|
||||
case IDC_HASH_FILEBROWSER_BUTTON:
|
||||
{
|
||||
FileDialog fDlg(_hSelf, ::GetModuleHandle(NULL));
|
||||
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"), NULL);
|
||||
CustomFileDialog fDlg(_hSelf);
|
||||
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"));
|
||||
|
||||
if (stringVector *pfns = fDlg.doOpenMultiFilesDlg())
|
||||
const auto& fns = fDlg.doOpenMultiFilesDlg();
|
||||
if (!fns.empty())
|
||||
{
|
||||
std::wstring files2check, hashResultStr;
|
||||
for (const auto& it : *pfns)
|
||||
for (const auto& it : fns)
|
||||
{
|
||||
if (_ht == hashType::hash_md5)
|
||||
{
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include <wininet.h>
|
||||
#include "Notepad_plus.h"
|
||||
#include "Notepad_plus_Window.h"
|
||||
#include "FileDialog.h"
|
||||
#include "CustomFileDialog.h"
|
||||
#include "Printer.h"
|
||||
#include "FileNameStringSplitter.h"
|
||||
#include "lesDlgs.h"
|
||||
|
@ -6022,12 +6022,13 @@ void Notepad_plus::setFindReplaceFolderFilter(const TCHAR *dir, const TCHAR *fil
|
|||
|
||||
vector<generic_string> Notepad_plus::addNppComponents(const TCHAR *destDir, const TCHAR *extFilterName, const TCHAR *extFilter)
|
||||
{
|
||||
FileDialog fDlg(_pPublicInterface->getHSelf(), _pPublicInterface->getHinst());
|
||||
fDlg.setExtFilter(extFilterName, extFilter, NULL);
|
||||
CustomFileDialog fDlg(_pPublicInterface->getHSelf());
|
||||
fDlg.setExtFilter(extFilterName, extFilter);
|
||||
|
||||
vector<generic_string> copiedFiles;
|
||||
|
||||
if (stringVector *pfns = fDlg.doOpenMultiFilesDlg())
|
||||
const auto& fns = fDlg.doOpenMultiFilesDlg();
|
||||
if (!fns.empty())
|
||||
{
|
||||
// Get plugins dir
|
||||
generic_string destDirName = (NppParameters::getInstance()).getNppPath();
|
||||
|
@ -6040,15 +6041,15 @@ vector<generic_string> Notepad_plus::addNppComponents(const TCHAR *destDir, cons
|
|||
|
||||
destDirName += TEXT("\\");
|
||||
|
||||
size_t sz = pfns->size();
|
||||
size_t sz = fns.size();
|
||||
for (size_t i = 0 ; i < sz ; ++i)
|
||||
{
|
||||
if (::PathFileExists(pfns->at(i).c_str()))
|
||||
if (::PathFileExists(fns.at(i).c_str()))
|
||||
{
|
||||
// copy to plugins directory
|
||||
generic_string destName = destDirName;
|
||||
destName += ::PathFindFileName(pfns->at(i).c_str());
|
||||
if (::CopyFile(pfns->at(i).c_str(), destName.c_str(), FALSE))
|
||||
destName += ::PathFindFileName(fns.at(i).c_str());
|
||||
if (::CopyFile(fns.at(i).c_str(), destName.c_str(), FALSE))
|
||||
copiedFiles.push_back(destName.c_str());
|
||||
}
|
||||
}
|
||||
|
@ -6058,12 +6059,13 @@ vector<generic_string> Notepad_plus::addNppComponents(const TCHAR *destDir, cons
|
|||
|
||||
vector<generic_string> Notepad_plus::addNppPlugins(const TCHAR *extFilterName, const TCHAR *extFilter)
|
||||
{
|
||||
FileDialog fDlg(_pPublicInterface->getHSelf(), _pPublicInterface->getHinst());
|
||||
fDlg.setExtFilter(extFilterName, extFilter, NULL);
|
||||
CustomFileDialog fDlg(_pPublicInterface->getHSelf());
|
||||
fDlg.setExtFilter(extFilterName, extFilter);
|
||||
|
||||
vector<generic_string> copiedFiles;
|
||||
|
||||
if (stringVector *pfns = fDlg.doOpenMultiFilesDlg())
|
||||
const auto& fns = fDlg.doOpenMultiFilesDlg();
|
||||
if (!fns.empty())
|
||||
{
|
||||
// Get plugins dir
|
||||
generic_string destDirName = (NppParameters::getInstance()).getPluginRootDir();
|
||||
|
@ -6073,15 +6075,15 @@ vector<generic_string> Notepad_plus::addNppPlugins(const TCHAR *extFilterName, c
|
|||
::CreateDirectory(destDirName.c_str(), NULL);
|
||||
}
|
||||
|
||||
size_t sz = pfns->size();
|
||||
size_t sz = fns.size();
|
||||
for (size_t i = 0 ; i < sz ; ++i)
|
||||
{
|
||||
if (::PathFileExists(pfns->at(i).c_str()))
|
||||
if (::PathFileExists(fns.at(i).c_str()))
|
||||
{
|
||||
// copy to plugins directory
|
||||
generic_string destName = destDirName;
|
||||
|
||||
generic_string nameExt = ::PathFindFileName(pfns->at(i).c_str());
|
||||
generic_string nameExt = ::PathFindFileName(fns.at(i).c_str());
|
||||
auto pos = nameExt.find_last_of(TEXT("."));
|
||||
if (pos == generic_string::npos)
|
||||
continue;
|
||||
|
@ -6094,7 +6096,7 @@ vector<generic_string> Notepad_plus::addNppPlugins(const TCHAR *extFilterName, c
|
|||
}
|
||||
PathAppend(destName, nameExt);
|
||||
|
||||
if (::CopyFile(pfns->at(i).c_str(), destName.c_str(), FALSE))
|
||||
if (::CopyFile(fns.at(i).c_str(), destName.c_str(), FALSE))
|
||||
copiedFiles.push_back(destName.c_str());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ struct QuoteParams
|
|||
const wchar_t* _quote = nullptr;
|
||||
};
|
||||
|
||||
class FileDialog;
|
||||
class CustomFileDialog;
|
||||
class Notepad_plus_Window;
|
||||
class AnsiCharPanel;
|
||||
class ClipboardHistoryPanel;
|
||||
|
@ -575,7 +575,7 @@ private:
|
|||
generic_string getLangFromMenu(const Buffer * buf);
|
||||
|
||||
generic_string exts2Filters(const generic_string& exts, int maxExtsLen = -1) const; // maxExtsLen default value -1 makes no limit of whole exts length
|
||||
int setFileOpenSaveDlgFilters(FileDialog & fDlg, bool showAllExt, int langType = -1); // showAllExt should be true if it's used for open file dialog - all set exts should be used for filtering files
|
||||
int setFileOpenSaveDlgFilters(CustomFileDialog & fDlg, bool showAllExt, int langType = -1); // showAllExt should be true if it's used for open file dialog - all set exts should be used for filtering files
|
||||
Style * getStyleFromName(const TCHAR *styleName);
|
||||
bool dumpFiles(const TCHAR * outdir, const TCHAR * fileprefix = TEXT("")); //helper func
|
||||
void drawTabbarColoursFromStylerArray();
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <shlwapi.h>
|
||||
#include <shlobj.h>
|
||||
#include "Notepad_plus_Window.h"
|
||||
#include "FileDialog.h"
|
||||
#include "CustomFileDialog.h"
|
||||
#include "EncodingMapper.h"
|
||||
#include "VerticalFileSwitcher.h"
|
||||
|
@ -825,7 +824,7 @@ generic_string Notepad_plus::exts2Filters(const generic_string& exts, int maxExt
|
|||
return filters;
|
||||
}
|
||||
|
||||
int Notepad_plus::setFileOpenSaveDlgFilters(FileDialog & fDlg, bool showAllExt, int langType)
|
||||
int Notepad_plus::setFileOpenSaveDlgFilters(CustomFileDialog & fDlg, bool showAllExt, int langType)
|
||||
{
|
||||
NppParameters& nppParam = NppParameters::getInstance();
|
||||
NppGUI & nppGUI = (NppGUI & )nppParam.getNppGUI();
|
||||
|
@ -875,7 +874,7 @@ int Notepad_plus::setFileOpenSaveDlgFilters(FileDialog & fDlg, bool showAllExt,
|
|||
const TCHAR *filters = stringFilters.c_str();
|
||||
if (filters[0])
|
||||
{
|
||||
fDlg.setExtsFilter(getLangDesc(lid, false).c_str(), filters);
|
||||
fDlg.setExtFilter(getLangDesc(lid, false).c_str(), filters);
|
||||
|
||||
//
|
||||
// Get index of lang type to find
|
||||
|
@ -1629,9 +1628,9 @@ bool Notepad_plus::fileSaveAs(BufferID id, bool isSaveCopy)
|
|||
bufferID = _pEditView->getCurrentBufferID();
|
||||
Buffer * buf = MainFileManager.getBufferByID(bufferID);
|
||||
|
||||
FileDialog fDlg(_pPublicInterface->getHSelf(), _pPublicInterface->getHinst());
|
||||
CustomFileDialog fDlg(_pPublicInterface->getHSelf());
|
||||
|
||||
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"), NULL);
|
||||
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"));
|
||||
|
||||
LangType langType = buf->getLangType();
|
||||
|
||||
|
@ -1650,20 +1649,20 @@ bool Notepad_plus::fileSaveAs(BufferID id, bool isSaveCopy)
|
|||
auto cdBefore = nppParam.getNppGUI()._fileAutoDetection;
|
||||
(const_cast<NppGUI &>(nppParam.getNppGUI()))._fileAutoDetection = cdDisabled;
|
||||
|
||||
TCHAR *pfn = fDlg.doSaveDlg();
|
||||
generic_string fn = fDlg.doSaveDlg();
|
||||
|
||||
// Enable file autodetection again.
|
||||
(const_cast<NppGUI &>(nppParam.getNppGUI()))._fileAutoDetection = cdBefore;
|
||||
|
||||
if (pfn)
|
||||
if (!fn.empty())
|
||||
{
|
||||
BufferID other = _pDocTab->findBufferByName(pfn);
|
||||
BufferID other = _pDocTab->findBufferByName(fn.c_str());
|
||||
if (other == BUFFER_INVALID)
|
||||
other = _pNonDocTab->findBufferByName(pfn);
|
||||
other = _pNonDocTab->findBufferByName(fn.c_str());
|
||||
|
||||
if (other == BUFFER_INVALID) //can save, as both (same and other) view don't contain buffer
|
||||
{
|
||||
bool res = doSave(bufferID, pfn, isSaveCopy);
|
||||
bool res = doSave(bufferID, fn.c_str(), isSaveCopy);
|
||||
//buf->setNeedsLexing(true); //commented to fix wrapping being removed after save as (due to SCI_CLEARSTYLE or something, seems to be Scintilla bug)
|
||||
//Changing lexer after save seems to work properly
|
||||
return res;
|
||||
|
@ -1703,16 +1702,16 @@ bool Notepad_plus::fileRename(BufferID id)
|
|||
bool isFileExisting = PathFileExists(buf->getFullPathName()) != FALSE;
|
||||
if (isFileExisting)
|
||||
{
|
||||
FileDialog fDlg(_pPublicInterface->getHSelf(), _pPublicInterface->getHinst());
|
||||
CustomFileDialog fDlg(_pPublicInterface->getHSelf());
|
||||
|
||||
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"), NULL);
|
||||
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"));
|
||||
setFileOpenSaveDlgFilters(fDlg, false);
|
||||
|
||||
fDlg.setDefFileName(buf->getFileName());
|
||||
TCHAR *pfn = fDlg.doSaveDlg();
|
||||
generic_string fn = fDlg.doSaveDlg();
|
||||
|
||||
if (pfn)
|
||||
success = MainFileManager.moveFile(bufferID, pfn);
|
||||
if (!fn.empty())
|
||||
success = MainFileManager.moveFile(bufferID, fn.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1830,22 +1829,20 @@ bool Notepad_plus::fileDelete(BufferID id)
|
|||
|
||||
void Notepad_plus::fileOpen()
|
||||
{
|
||||
FileDialog fDlg(_pPublicInterface->getHSelf(), _pPublicInterface->getHinst());
|
||||
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"), NULL);
|
||||
CustomFileDialog fDlg(_pPublicInterface->getHSelf());
|
||||
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"));
|
||||
|
||||
setFileOpenSaveDlgFilters(fDlg, true);
|
||||
|
||||
BufferID lastOpened = BUFFER_INVALID;
|
||||
if (stringVector *pfns = fDlg.doOpenMultiFilesDlg())
|
||||
{
|
||||
size_t sz = pfns->size();
|
||||
const auto& fns = fDlg.doOpenMultiFilesDlg();
|
||||
size_t sz = fns.size();
|
||||
for (size_t i = 0 ; i < sz ; ++i)
|
||||
{
|
||||
BufferID test = doOpen(pfns->at(i).c_str(), fDlg.isReadOnly());
|
||||
BufferID test = doOpen(fns.at(i).c_str(), fDlg.isReadOnly());
|
||||
if (test != BUFFER_INVALID)
|
||||
lastOpened = test;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastOpened != BUFFER_INVALID)
|
||||
{
|
||||
|
@ -2190,10 +2187,10 @@ bool Notepad_plus::loadSession(Session & session, bool isSnapshotMode, bool shou
|
|||
bool Notepad_plus::fileLoadSession(const TCHAR *fn)
|
||||
{
|
||||
bool result = false;
|
||||
const TCHAR *sessionFileName = NULL;
|
||||
generic_string sessionFileName;
|
||||
if (fn == NULL)
|
||||
{
|
||||
FileDialog fDlg(_pPublicInterface->getHSelf(), _pPublicInterface->getHinst());
|
||||
CustomFileDialog fDlg(_pPublicInterface->getHSelf());
|
||||
const TCHAR *ext = NppParameters::getInstance().getNppGUI()._definedSessionExt.c_str();
|
||||
generic_string sessionExt = TEXT("");
|
||||
if (*ext != '\0')
|
||||
|
@ -2201,10 +2198,10 @@ bool Notepad_plus::fileLoadSession(const TCHAR *fn)
|
|||
if (*ext != '.')
|
||||
sessionExt += TEXT(".");
|
||||
sessionExt += ext;
|
||||
fDlg.setExtFilter(TEXT("Session file"), sessionExt.c_str(), NULL);
|
||||
fDlg.setExtFilter(TEXT("Session file"), sessionExt.c_str());
|
||||
fDlg.setDefExt(ext);
|
||||
}
|
||||
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"), NULL);
|
||||
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"));
|
||||
sessionFileName = fDlg.doOpenSingleFileDlg();
|
||||
}
|
||||
else
|
||||
|
@ -2216,7 +2213,7 @@ bool Notepad_plus::fileLoadSession(const TCHAR *fn)
|
|||
|
||||
NppParameters& nppParam = NppParameters::getInstance();
|
||||
const NppGUI & nppGUI = nppParam.getNppGUI();
|
||||
if (sessionFileName)
|
||||
if (!sessionFileName.empty())
|
||||
{
|
||||
bool isEmptyNpp = false;
|
||||
if (_mainDocTab.nbItem() == 1 && _subDocTab.nbItem() == 1)
|
||||
|
@ -2243,7 +2240,7 @@ bool Notepad_plus::fileLoadSession(const TCHAR *fn)
|
|||
bool isAllSuccessful = true;
|
||||
Session session2Load;
|
||||
|
||||
if ((NppParameters::getInstance()).loadSession(session2Load, sessionFileName))
|
||||
if ((NppParameters::getInstance()).loadSession(session2Load, sessionFileName.c_str()))
|
||||
{
|
||||
const bool isSnapshotMode = false;
|
||||
const bool shouldLoadFileBrowser = true;
|
||||
|
@ -2251,7 +2248,7 @@ bool Notepad_plus::fileLoadSession(const TCHAR *fn)
|
|||
result = true;
|
||||
}
|
||||
if (!isAllSuccessful)
|
||||
(NppParameters::getInstance()).writeSession(session2Load, sessionFileName);
|
||||
(NppParameters::getInstance()).writeSession(session2Load, sessionFileName.c_str());
|
||||
}
|
||||
if (result == false)
|
||||
{
|
||||
|
@ -2299,8 +2296,6 @@ const TCHAR * Notepad_plus::fileSaveSession(size_t nbFile, TCHAR ** fileNames, c
|
|||
|
||||
const TCHAR * Notepad_plus::fileSaveSession(size_t nbFile, TCHAR ** fileNames)
|
||||
{
|
||||
const TCHAR *sessionFileName = NULL;
|
||||
|
||||
CustomFileDialog fDlg(_pPublicInterface->getHSelf());
|
||||
const TCHAR *ext = NppParameters::getInstance().getNppGUI()._definedSessionExt.c_str();
|
||||
|
||||
|
@ -2319,9 +2314,9 @@ const TCHAR * Notepad_plus::fileSaveSession(size_t nbFile, TCHAR ** fileNames)
|
|||
const generic_string checkboxLabel = _nativeLangSpeaker.getLocalizedStrFromID("session-save-folder-as-workspace",
|
||||
TEXT("Save Folder as Workspace"));
|
||||
fDlg.setCheckbox(checkboxLabel.c_str(), isCheckboxActive);
|
||||
sessionFileName = fDlg.doSaveDlg();
|
||||
generic_string sessionFileName = fDlg.doSaveDlg();
|
||||
|
||||
return fileSaveSession(nbFile, fileNames, sessionFileName, fDlg.getCheckboxState());
|
||||
return fileSaveSession(nbFile, fileNames, sessionFileName.c_str(), fDlg.getCheckboxState());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include <shlwapi.h>
|
||||
#include <shlobj.h>
|
||||
#include "Parameters.h"
|
||||
#include "FileDialog.h"
|
||||
#include "ScintillaEditView.h"
|
||||
#include "keys.h"
|
||||
#include "localization.h"
|
||||
|
@ -842,8 +841,6 @@ winVer NppParameters::getWindowsVersion()
|
|||
return WV_UNKNOWN;
|
||||
}
|
||||
|
||||
int FileDialog::_dialogFileBoxId = (NppParameters::getInstance()).getWinVersion() < WV_W2K?edt1:cmb13;
|
||||
|
||||
|
||||
NppParameters::NppParameters()
|
||||
{
|
||||
|
@ -5266,10 +5263,6 @@ void NppParameters::feedGUIParameters(TiXmlNode *node)
|
|||
if (optNameWriteTechnologyEngine)
|
||||
_nppGUI._writeTechnologyEngine = (lstrcmp(optNameWriteTechnologyEngine, TEXT("1")) == 0) ? directWriteTechnology : defaultTechnology;
|
||||
|
||||
const TCHAR * optNameNewStyleSaveDlg = element->Attribute(TEXT("newStyleSaveDlg"));
|
||||
if (optNameNewStyleSaveDlg)
|
||||
_nppGUI._useNewStyleSaveDlg = (lstrcmp(optNameNewStyleSaveDlg, TEXT("yes")) == 0);
|
||||
|
||||
const TCHAR * optNameFolderDroppedOpenFiles = element->Attribute(TEXT("isFolderDroppedOpenFiles"));
|
||||
if (optNameFolderDroppedOpenFiles)
|
||||
_nppGUI._isFolderDroppedOpenFiles = (lstrcmp(optNameFolderDroppedOpenFiles, TEXT("yes")) == 0);
|
||||
|
@ -6206,7 +6199,7 @@ void NppParameters::createXmlTreeFromGUIParams()
|
|||
GUIConfigElement->SetAttribute(TEXT("setting"), _nppGUI._multiInstSetting);
|
||||
}
|
||||
|
||||
// <GUIConfig name="MISC" fileSwitcherWithoutExtColumn="no" backSlashIsEscapeCharacterForSql="yes" newStyleSaveDlg="no" isFolderDroppedOpenFiles="no" saveDlgExtFilterToAllTypes="no" />
|
||||
// <GUIConfig name="MISC" fileSwitcherWithoutExtColumn="no" backSlashIsEscapeCharacterForSql="yes" isFolderDroppedOpenFiles="no" saveDlgExtFilterToAllTypes="no" />
|
||||
{
|
||||
TiXmlElement *GUIConfigElement = (newGUIRoot->InsertEndChild(TiXmlElement(TEXT("GUIConfig"))))->ToElement();
|
||||
GUIConfigElement->SetAttribute(TEXT("name"), TEXT("MISC"));
|
||||
|
@ -6214,7 +6207,6 @@ void NppParameters::createXmlTreeFromGUIParams()
|
|||
GUIConfigElement->SetAttribute(TEXT("fileSwitcherWithoutExtColumn"), _nppGUI._fileSwitcherWithoutExtColumn ? TEXT("yes") : TEXT("no"));
|
||||
GUIConfigElement->SetAttribute(TEXT("backSlashIsEscapeCharacterForSql"), _nppGUI._backSlashIsEscapeCharacterForSql ? TEXT("yes") : TEXT("no"));
|
||||
GUIConfigElement->SetAttribute(TEXT("writeTechnologyEngine"), _nppGUI._writeTechnologyEngine);
|
||||
GUIConfigElement->SetAttribute(TEXT("newStyleSaveDlg"), _nppGUI._useNewStyleSaveDlg ? TEXT("yes") : TEXT("no"));
|
||||
GUIConfigElement->SetAttribute(TEXT("isFolderDroppedOpenFiles"), _nppGUI._isFolderDroppedOpenFiles ? TEXT("yes") : TEXT("no"));
|
||||
GUIConfigElement->SetAttribute(TEXT("docPeekOnTab"), _nppGUI._isDocPeekOnTab ? TEXT("yes") : TEXT("no"));
|
||||
GUIConfigElement->SetAttribute(TEXT("docPeekOnMap"), _nppGUI._isDocPeekOnMap ? TEXT("yes") : TEXT("no"));
|
||||
|
|
|
@ -897,7 +897,6 @@ struct NppGUI final
|
|||
size_t _snapshotBackupTiming = 7000;
|
||||
generic_string _cloudPath; // this option will never be read/written from/to config.xml
|
||||
unsigned char _availableClouds = '\0'; // this option will never be read/written from/to config.xml
|
||||
bool _useNewStyleSaveDlg = true;
|
||||
|
||||
enum SearchEngineChoice{ se_custom = 0, se_duckDuckGo = 1, se_google = 2, se_bing = 3, se_yahoo = 4, se_stackoverflow = 5 };
|
||||
SearchEngineChoice _searchEngineChoice = se_google;
|
||||
|
@ -1664,14 +1663,6 @@ public:
|
|||
_currentDefaultFgColor = c;
|
||||
}
|
||||
|
||||
bool useNewStyleSaveDlg() const {
|
||||
return _nppGUI._useNewStyleSaveDlg;
|
||||
}
|
||||
|
||||
void setUseNewStyleSaveDlg(bool v) {
|
||||
_nppGUI._useNewStyleSaveDlg = v;
|
||||
}
|
||||
|
||||
void setCmdSettingsDir(const generic_string& settingsDir) {
|
||||
_cmdSettingsDir = settingsDir;
|
||||
};
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "Parameters.h"
|
||||
#include "resource.h"
|
||||
#include "Notepad_plus_msgs.h"
|
||||
#include "FileDialog.h"
|
||||
#include "CustomFileDialog.h"
|
||||
#include "Common.h"
|
||||
|
||||
using namespace std;
|
||||
|
@ -1260,11 +1260,10 @@ INT_PTR CALLBACK UserDefineDialog::run_dlgProc(UINT message, WPARAM wParam, LPAR
|
|||
}
|
||||
case IDC_IMPORT_BUTTON :
|
||||
{
|
||||
FileDialog fDlg(_hSelf, ::GetModuleHandle(NULL));
|
||||
fDlg.setExtFilter(TEXT("UDL"), TEXT(".xml"), NULL);
|
||||
TCHAR *fn = fDlg.doOpenSingleFileDlg();
|
||||
if (!fn) break;
|
||||
generic_string sourceFile = fn;
|
||||
CustomFileDialog fDlg(_hSelf);
|
||||
fDlg.setExtFilter(TEXT("UDL"), TEXT(".xml"));
|
||||
generic_string sourceFile = fDlg.doOpenSingleFileDlg();
|
||||
if (sourceFile.empty()) break;
|
||||
|
||||
bool isSuccessful = nppParam.importUDLFromFile(sourceFile);
|
||||
if (isSuccessful)
|
||||
|
@ -1291,12 +1290,11 @@ INT_PTR CALLBACK UserDefineDialog::run_dlgProc(UINT message, WPARAM wParam, LPAR
|
|||
break;
|
||||
}
|
||||
|
||||
FileDialog fDlg(_hSelf, ::GetModuleHandle(NULL));
|
||||
fDlg.setExtFilter(TEXT("UDL"), TEXT(".xml"), NULL);
|
||||
CustomFileDialog fDlg(_hSelf);
|
||||
fDlg.setExtFilter(TEXT("UDL"), TEXT(".xml"));
|
||||
fDlg.setExtIndex(0); // 0 Default index else file will be saved without extension
|
||||
TCHAR *fn = fDlg.doSaveDlg();
|
||||
if (!fn) break;
|
||||
generic_string fileName2save = fn;
|
||||
generic_string fileName2save = fDlg.doSaveDlg();
|
||||
if (fileName2save.empty()) break;
|
||||
|
||||
if (i2Export > 0)
|
||||
{
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "fileBrowser.h"
|
||||
#include "resource.h"
|
||||
#include "tinyxml.h"
|
||||
#include "FileDialog.h"
|
||||
#include "localization.h"
|
||||
#include "Parameters.h"
|
||||
#include "RunDlg.h"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// This file is part of Notepad++ project
|
||||
// Copyright (C)2021 Don HO <don.h@free.fr>
|
||||
// Copyright (C) 2021 The Notepad++ Contributors.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -15,39 +15,429 @@
|
|||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
// Windows Vista is a minimum required version for Common File Dialogs.
|
||||
// Define it only for current source file.
|
||||
#if defined(_WIN32_WINNT) && (!defined(_WIN32_WINNT_VISTA) || (_WIN32_WINNT < _WIN32_WINNT_VISTA))
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT _WIN32_WINNT_VISTA
|
||||
#endif
|
||||
|
||||
#include <shobjidl.h>
|
||||
#include <shlwapi.h> // PathIsDirectory
|
||||
#ifdef __MINGW32__
|
||||
#include <cwchar>
|
||||
#endif
|
||||
#include <comdef.h> // _com_error
|
||||
#include <comip.h> // _com_ptr_t
|
||||
|
||||
#include "CustomFileDialog.h"
|
||||
#include "Parameters.h"
|
||||
|
||||
// Private impelemnation to avoid pollution with includes and defines in header.
|
||||
// Workaround for MinGW because its implementation of __uuidof is different.
|
||||
template<class T>
|
||||
struct ComTraits
|
||||
{
|
||||
static const GUID uid;
|
||||
};
|
||||
template<class T>
|
||||
const GUID ComTraits<T>::uid = __uuidof(T);
|
||||
|
||||
// Smart pointer alias for COM objects that makes reference counting easier.
|
||||
template<class T>
|
||||
using com_ptr = _com_ptr_t<_com_IIID<T, &ComTraits<T>::uid>>;
|
||||
|
||||
|
||||
namespace // anonymous
|
||||
{
|
||||
// Note: these common functions could be moved to some header.
|
||||
|
||||
struct Filter
|
||||
{
|
||||
generic_string name;
|
||||
generic_string ext;
|
||||
};
|
||||
|
||||
// Returns a first extension from the extension specification string.
|
||||
// Multiple extensions are separated with ';'.
|
||||
// Example: input - ".c;.cpp;.h", output - ".c"
|
||||
generic_string get1stExt(const generic_string& extSpec)
|
||||
{
|
||||
size_t pos = extSpec.find('.');
|
||||
if (pos != generic_string::npos)
|
||||
{
|
||||
size_t posEnd = extSpec.find(';', pos + 1);
|
||||
if (posEnd != generic_string::npos)
|
||||
{
|
||||
size_t extLen = posEnd - pos;
|
||||
return extSpec.substr(pos, extLen);
|
||||
}
|
||||
return extSpec.substr(pos);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool replaceExt(generic_string& name, const generic_string& ext)
|
||||
{
|
||||
if (!name.empty() && !ext.empty())
|
||||
{
|
||||
// Remove an existing extension from the name.
|
||||
size_t posNameExt = name.find_last_of('.');
|
||||
if (posNameExt != generic_string::npos)
|
||||
name.erase(posNameExt);
|
||||
// Append a new extension.
|
||||
name += ext;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasExt(const generic_string& name)
|
||||
{
|
||||
return name.find_last_of('.') != generic_string::npos;
|
||||
}
|
||||
|
||||
bool endsWith(const generic_string& s, const generic_string& suffix)
|
||||
{
|
||||
#if defined(_MSVC_LANG) && (_MSVC_LANG > 201402L)
|
||||
#error Replace this function with basic_string::ends_with
|
||||
#endif
|
||||
size_t pos = s.find(suffix);
|
||||
return pos != s.npos && ((s.length() - pos) == suffix.length());
|
||||
}
|
||||
|
||||
bool setDialogFolder(IFileDialog* dialog, const TCHAR* folder)
|
||||
{
|
||||
IShellItem* psi = nullptr;
|
||||
HRESULT hr = SHCreateItemFromParsingName(folder,
|
||||
0,
|
||||
IID_IShellItem,
|
||||
reinterpret_cast<void**>(&psi));
|
||||
if (SUCCEEDED(hr))
|
||||
hr = dialog->SetFolder(psi);
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
generic_string getDialogFileName(IFileDialog* dialog)
|
||||
{
|
||||
PWSTR pszFilePath = nullptr;
|
||||
dialog->GetFileName(&pszFilePath);
|
||||
generic_string fileName = pszFilePath;
|
||||
CoTaskMemFree(pszFilePath);
|
||||
return fileName;
|
||||
}
|
||||
|
||||
// Backups the current directory in constructor and restores it in destructor.
|
||||
// This is needed in case dialog changes the current directory.
|
||||
class CurrentDirBackup
|
||||
{
|
||||
public:
|
||||
CurrentDirBackup()
|
||||
{
|
||||
::GetCurrentDirectory(MAX_PATH, _dir);
|
||||
}
|
||||
~CurrentDirBackup()
|
||||
{
|
||||
NppParameters& params = NppParameters::getInstance();
|
||||
if (params.getNppGUI()._openSaveDir == dir_last)
|
||||
{
|
||||
::GetCurrentDirectory(MAX_PATH, _dir);
|
||||
params.setWorkingDir(_dir);
|
||||
}
|
||||
::SetCurrentDirectory(_dir);
|
||||
}
|
||||
private:
|
||||
TCHAR _dir[MAX_PATH];
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class FileDialogEventHandler : public IFileDialogEvents
|
||||
{
|
||||
public:
|
||||
static HRESULT createInstance(const std::vector<Filter>& filterSpec, REFIID riid, void **ppv)
|
||||
{
|
||||
*ppv = nullptr;
|
||||
FileDialogEventHandler *pDialogEventHandler = new (std::nothrow) FileDialogEventHandler(filterSpec);
|
||||
HRESULT hr = pDialogEventHandler ? S_OK : E_OUTOFMEMORY;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pDialogEventHandler->QueryInterface(riid, ppv);
|
||||
pDialogEventHandler->Release();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
// IUnknown methods
|
||||
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) override
|
||||
{
|
||||
// Always set out parameter to NULL, validating it first.
|
||||
if (!ppv)
|
||||
return E_INVALIDARG;
|
||||
*ppv = nullptr;
|
||||
if (riid == __uuidof(IUnknown) || riid == __uuidof(IFileDialogEvents))
|
||||
{
|
||||
// Increment the reference count and return the pointer.
|
||||
*ppv = static_cast<IFileDialogEvents*>(this);
|
||||
AddRef();
|
||||
return NOERROR;
|
||||
}
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) AddRef() override
|
||||
{
|
||||
return InterlockedIncrement(&_cRef);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) Release() override
|
||||
{
|
||||
long cRef = InterlockedDecrement(&_cRef);
|
||||
if (!cRef)
|
||||
delete this;
|
||||
return cRef;
|
||||
}
|
||||
|
||||
// IFileDialogEvents methods
|
||||
|
||||
IFACEMETHODIMP OnFileOk(IFileDialog*) override
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
IFACEMETHODIMP OnFolderChange(IFileDialog* dlg) override
|
||||
{
|
||||
// First launch order: 3. Custom controls are added but inactive.
|
||||
if (!_dialog)
|
||||
initDialog(dlg);
|
||||
return S_OK;
|
||||
}
|
||||
IFACEMETHODIMP OnFolderChanging(IFileDialog*, IShellItem*) override
|
||||
{
|
||||
// First launch order: 2. Buttons are added, correct window title.
|
||||
return S_OK;
|
||||
}
|
||||
IFACEMETHODIMP OnSelectionChange(IFileDialog*) override
|
||||
{
|
||||
// First launch order: 4. Main window is shown.
|
||||
return S_OK;
|
||||
}
|
||||
IFACEMETHODIMP OnShareViolation(IFileDialog*, IShellItem*, FDE_SHAREVIOLATION_RESPONSE*) override
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
IFACEMETHODIMP OnTypeChange(IFileDialog* dlg) override
|
||||
{
|
||||
// First launch order: 1. Inactive, window title might be wrong.
|
||||
generic_string name = getDialogFileName(dlg);
|
||||
if (changeExt(name, dlg))
|
||||
dlg->SetFileName(name.c_str());
|
||||
return S_OK;
|
||||
}
|
||||
IFACEMETHODIMP OnOverwrite(IFileDialog*, IShellItem*, FDE_OVERWRITE_RESPONSE*) override
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Use createInstance() instead
|
||||
FileDialogEventHandler(const std::vector<Filter>& filterSpec) : _cRef(1), _filterSpec(filterSpec)
|
||||
{
|
||||
_staticThis = this;
|
||||
}
|
||||
~FileDialogEventHandler()
|
||||
{
|
||||
_staticThis = nullptr;
|
||||
}
|
||||
FileDialogEventHandler(const FileDialogEventHandler&) = delete;
|
||||
FileDialogEventHandler& operator=(const FileDialogEventHandler&) = delete;
|
||||
FileDialogEventHandler(FileDialogEventHandler&&) = delete;
|
||||
FileDialogEventHandler& operator=(FileDialogEventHandler&&) = delete;
|
||||
|
||||
void initDialog(IFileDialog * d)
|
||||
{
|
||||
assert(!_dialog);
|
||||
_dialog = d;
|
||||
_okButtonProc = nullptr;
|
||||
_fileNameProc = nullptr;
|
||||
com_ptr<IOleWindow> pOleWnd = _dialog;
|
||||
if (pOleWnd)
|
||||
{
|
||||
HWND hwndDlg = nullptr;
|
||||
HRESULT hr = pOleWnd->GetWindow(&hwndDlg);
|
||||
if (SUCCEEDED(hr) && hwndDlg)
|
||||
{
|
||||
EnumChildWindows(hwndDlg, &EnumChildProc, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Changes the name extension according to currently selected file type index.
|
||||
bool changeExt(generic_string& name, IFileDialog* dlg)
|
||||
{
|
||||
UINT typeIndex = 0;
|
||||
if (FAILED(dlg->GetFileTypeIndex(&typeIndex)))
|
||||
return false;
|
||||
// Index starts from 1
|
||||
if (typeIndex > 0 && typeIndex - 1 < _filterSpec.size())
|
||||
{
|
||||
const generic_string ext = get1stExt(_filterSpec[typeIndex - 1].ext);
|
||||
if (!endsWith(ext, _T(".*")))
|
||||
return replaceExt(name, ext);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Called after the user input but before OnFileOk() and before any name validation.
|
||||
// Prefer SendMessage communication with the edit box here rather than IFileDialog methods.
|
||||
// The setter methods post the message to the queue, and it may not be processed in time.
|
||||
void onPreFileOk()
|
||||
{
|
||||
if (!_dialog)
|
||||
return;
|
||||
// Get the entered name.
|
||||
generic_string fileName = getDialogFileName(_dialog);
|
||||
bool nameChanged = transformPath(fileName);
|
||||
// Update the controls.
|
||||
if (not ::PathIsDirectory(fileName.c_str()))
|
||||
{
|
||||
// Name is a file path.
|
||||
// Add file extension if missing.
|
||||
if (!hasExt(fileName))
|
||||
nameChanged |= changeExt(fileName, _dialog);
|
||||
}
|
||||
// Update the edit box text.
|
||||
// It will update the address if the path is a directory.
|
||||
if (nameChanged)
|
||||
sendDialogFileName(fileName.c_str());
|
||||
}
|
||||
|
||||
// Transforms a forward-slash path to a canonical Windows path.
|
||||
static bool transformPath(generic_string& fileName)
|
||||
{
|
||||
if (fileName.empty())
|
||||
return false;
|
||||
bool transformed = false;
|
||||
// Transform to a Windows path.
|
||||
size_t pos = 0;
|
||||
while ((pos = fileName.find('/', pos)) != generic_string::npos)
|
||||
{
|
||||
fileName[pos] = '\\';
|
||||
++pos;
|
||||
transformed = true;
|
||||
}
|
||||
// If there are two or more double backslash, then change it to single.
|
||||
while (fileName.find(_T("\\\\")) != generic_string::npos)
|
||||
{
|
||||
fileName.replace(fileName.find(_T("\\\\")), 2, _T("\\"));
|
||||
transformed = true;
|
||||
}
|
||||
return transformed;
|
||||
}
|
||||
|
||||
// Sets the file name and waits until it is processed by the edit control.
|
||||
void sendDialogFileName(const TCHAR* name)
|
||||
{
|
||||
::SendMessage(_hwndNameEdit, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(name));
|
||||
}
|
||||
|
||||
// Enumerates the child windows of a dialog.
|
||||
// Sets up window procedure overrides for "OK" button and file name edit box.
|
||||
static BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM)
|
||||
{
|
||||
const int bufferLen = MAX_PATH;
|
||||
static TCHAR buffer[bufferLen];
|
||||
if (GetClassName(hwnd, buffer, bufferLen) != 0)
|
||||
{
|
||||
if (lstrcmpi(buffer, _T("ComboBox")) == 0)
|
||||
{
|
||||
// The edit box of interest is a child of the combo box and has empty window text.
|
||||
// Note that file type dropdown is a combo box also (but without an edit box).
|
||||
HWND hwndChild = FindWindowEx(hwnd, nullptr, _T("Edit"), _T(""));
|
||||
if (hwndChild)
|
||||
{
|
||||
_fileNameProc = (WNDPROC)SetWindowLongPtr(hwndChild, GWLP_WNDPROC, (LPARAM)&FileNameWndProc);
|
||||
_staticThis->_hwndNameEdit = hwndChild;
|
||||
}
|
||||
}
|
||||
else if (lstrcmpi(buffer, _T("Button")) == 0)
|
||||
{
|
||||
// The button of interest has a focus by default.
|
||||
LONG style = GetWindowLong(hwnd, GWL_STYLE);
|
||||
if (style & BS_DEFPUSHBUTTON)
|
||||
_okButtonProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LPARAM)&OkButtonWndProc);
|
||||
}
|
||||
}
|
||||
if (_okButtonProc && _fileNameProc)
|
||||
return FALSE; // Found all children, stop enumeration.
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK OkButtonWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
if (msg == WM_LBUTTONDOWN)
|
||||
_staticThis->onPreFileOk();
|
||||
return CallWindowProc(_okButtonProc, hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK FileNameWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
// WM_KEYDOWN with wparam == VK_RETURN isn't delivered here.
|
||||
// So watch for the keyboard input while the control has focus.
|
||||
// Initially, the control has focus.
|
||||
// WM_SETFOCUS is sent if control regains focus after losing it.
|
||||
static bool processingReturn = false;
|
||||
switch (msg)
|
||||
{
|
||||
case WM_SETFOCUS:
|
||||
_staticThis->_monitorKeyboard = true;
|
||||
break;
|
||||
case WM_KILLFOCUS:
|
||||
_staticThis->_monitorKeyboard = false;
|
||||
break;
|
||||
}
|
||||
if (_staticThis->_monitorKeyboard && !processingReturn)
|
||||
{
|
||||
SHORT state = GetAsyncKeyState(VK_RETURN);
|
||||
if (state & 0x8000)
|
||||
{
|
||||
// Avoid re-entrance because the call might generate some messages.
|
||||
processingReturn = true;
|
||||
_staticThis->onPreFileOk();
|
||||
processingReturn = false;
|
||||
}
|
||||
}
|
||||
return CallWindowProc(_fileNameProc, hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
static WNDPROC _okButtonProc;
|
||||
static WNDPROC _fileNameProc;
|
||||
static FileDialogEventHandler* _staticThis;
|
||||
|
||||
long _cRef;
|
||||
IFileDialog* _dialog = nullptr;
|
||||
const std::vector<Filter> _filterSpec;
|
||||
HWND _hwndNameEdit = nullptr;
|
||||
bool _monitorKeyboard = true;
|
||||
};
|
||||
|
||||
WNDPROC FileDialogEventHandler::_okButtonProc;
|
||||
WNDPROC FileDialogEventHandler::_fileNameProc;
|
||||
FileDialogEventHandler* FileDialogEventHandler::_staticThis;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Private implementation to avoid pollution with includes and defines in header.
|
||||
class CustomFileDialog::Impl
|
||||
{
|
||||
public:
|
||||
Impl()
|
||||
{
|
||||
memset(_fileName, 0, std::size(_fileName));
|
||||
}
|
||||
Impl() = default;
|
||||
|
||||
~Impl()
|
||||
{
|
||||
if (_customize)
|
||||
_customize->Release();
|
||||
if (_dialog)
|
||||
_dialog->Release();
|
||||
}
|
||||
~Impl() = default;
|
||||
|
||||
bool init(CLSID id)
|
||||
{
|
||||
if (_dialog)
|
||||
return false; // Avoid double initizliation
|
||||
return false; // Avoid double initialization
|
||||
|
||||
// Sanitize data.
|
||||
if (_fileTypeIndex >= static_cast<int>(_filterSpec.size()))
|
||||
_fileTypeIndex = 0;
|
||||
|
||||
HRESULT hr = CoCreateInstance(id,
|
||||
NULL,
|
||||
|
@ -58,19 +448,36 @@ public:
|
|||
hr = _dialog->SetTitle(_title);
|
||||
|
||||
if (SUCCEEDED(hr) && _folder)
|
||||
hr = setInitDir(_folder) ? S_OK : E_FAIL;
|
||||
hr = setFolder(_folder) ? S_OK : E_FAIL;
|
||||
|
||||
if (SUCCEEDED(hr) && _defExt && _defExt[0] != '\0')
|
||||
hr = _dialog->SetDefaultExtension(_defExt);
|
||||
|
||||
if (SUCCEEDED(hr) && _initialFileName)
|
||||
{
|
||||
generic_string newFileName = _initialFileName;
|
||||
if (_fileTypeIndex >= 0 && _fileTypeIndex < static_cast<int>(_filterSpec.size()))
|
||||
{
|
||||
if (!hasExt(newFileName))
|
||||
{
|
||||
const generic_string ext = get1stExt(_filterSpec[_fileTypeIndex].ext);
|
||||
if (!endsWith(ext, _T(".*")))
|
||||
newFileName += ext;
|
||||
}
|
||||
}
|
||||
hr = _dialog->SetFileName(newFileName.c_str());
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr) && !_filterSpec.empty())
|
||||
{
|
||||
std::vector<COMDLG_FILTERSPEC> fileTypes;
|
||||
fileTypes.reserve(_filterSpec.size());
|
||||
for (auto&& filter : _filterSpec)
|
||||
fileTypes.push_back({ filter.first.data(), filter.second.data() });
|
||||
fileTypes.push_back({ filter.name.data(), filter.ext.data() });
|
||||
hr = _dialog->SetFileTypes(static_cast<UINT>(fileTypes.size()), fileTypes.data());
|
||||
}
|
||||
|
||||
// The selected index should be set after the file types are set.
|
||||
if (SUCCEEDED(hr) && _fileTypeIndex >= 0)
|
||||
hr = _dialog->SetFileTypeIndex(_fileTypeIndex + 1); // This index is 1-based
|
||||
|
||||
|
@ -103,38 +510,44 @@ public:
|
|||
|
||||
bool addControls()
|
||||
{
|
||||
HRESULT hr = _dialog->QueryInterface(IID_PPV_ARGS(&_customize));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
_customize = _dialog;
|
||||
if (!_customize)
|
||||
return false;
|
||||
if (_checkboxLabel && _checkboxLabel[0] != '\0')
|
||||
{
|
||||
const BOOL isChecked = FALSE;
|
||||
hr = _customize->AddCheckButton(IDC_FILE_CHECKBOX, _checkboxLabel, isChecked);
|
||||
HRESULT hr = _customize->AddCheckButton(IDC_FILE_CHECKBOX, _checkboxLabel, isChecked);
|
||||
if (SUCCEEDED(hr) && !_isCheckboxActive)
|
||||
{
|
||||
hr = _customize->SetControlState(IDC_FILE_CHECKBOX, CDCS_INACTIVE | CDCS_VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setInitDir(const TCHAR* dir)
|
||||
bool setFolder(const TCHAR* dir)
|
||||
{
|
||||
IShellItem* psi = nullptr;
|
||||
HRESULT hr = SHCreateItemFromParsingName(dir,
|
||||
0,
|
||||
IID_IShellItem,
|
||||
reinterpret_cast<void**>(&psi));
|
||||
if (SUCCEEDED(hr))
|
||||
hr = _dialog->SetFolder(psi);
|
||||
return SUCCEEDED(hr);
|
||||
return setDialogFolder(_dialog, dir);
|
||||
}
|
||||
|
||||
bool show()
|
||||
{
|
||||
HRESULT hr = _dialog->Show(_hwndOwner);
|
||||
return SUCCEEDED(hr);
|
||||
bool okPressed = false;
|
||||
HRESULT hr = FileDialogEventHandler::createInstance(_filterSpec, IID_PPV_ARGS(&_events));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
DWORD dwCookie;
|
||||
hr = _dialog->Advise(_events, &dwCookie);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = _dialog->Show(_hwndOwner);
|
||||
okPressed = SUCCEEDED(hr);
|
||||
|
||||
_dialog->Unadvise(dwCookie);
|
||||
}
|
||||
}
|
||||
return okPressed;
|
||||
}
|
||||
|
||||
BOOL getCheckboxState() const
|
||||
|
@ -149,28 +562,70 @@ public:
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
const TCHAR* getResultFilename()
|
||||
generic_string getResultFilename()
|
||||
{
|
||||
bool bOk = false;
|
||||
IShellItem* psiResult = nullptr;
|
||||
generic_string fileName;
|
||||
com_ptr<IShellItem> psiResult;
|
||||
HRESULT hr = _dialog->GetResult(&psiResult);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
PWSTR pszFilePath = NULL;
|
||||
hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
size_t len = pszFilePath ? wcslen(pszFilePath) : 0;
|
||||
if (len > 0 && len <= std::size(_fileName))
|
||||
{
|
||||
wcsncpy_s(_fileName, pszFilePath, len);
|
||||
bOk = true;
|
||||
fileName = getFilename(psiResult);
|
||||
_hasReadonly = hasReadonlyAttr(psiResult);
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
static generic_string getFilename(IShellItem* psi)
|
||||
{
|
||||
generic_string result;
|
||||
PWSTR pszFilePath = NULL;
|
||||
HRESULT hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
|
||||
if (SUCCEEDED(hr) && pszFilePath)
|
||||
{
|
||||
result = pszFilePath;
|
||||
CoTaskMemFree(pszFilePath);
|
||||
}
|
||||
psiResult->Release();
|
||||
return result;
|
||||
}
|
||||
return bOk ? _fileName : nullptr;
|
||||
|
||||
static bool hasReadonlyAttr(IShellItem* psi)
|
||||
{
|
||||
SFGAOF attrs = 0;
|
||||
HRESULT hr = psi->GetAttributes(SFGAO_READONLY, &attrs);
|
||||
if (SUCCEEDED(hr))
|
||||
return attrs & SFGAO_READONLY;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<generic_string> getFilenames()
|
||||
{
|
||||
std::vector<generic_string> result;
|
||||
// Only the open dialog can have multiple results.
|
||||
com_ptr<IFileOpenDialog> pfd = _dialog;
|
||||
if (pfd)
|
||||
{
|
||||
com_ptr<IShellItemArray> psiaResults;
|
||||
HRESULT hr = pfd->GetResults(&psiaResults);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
DWORD count = 0;
|
||||
hr = psiaResults->GetCount(&count);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
for (DWORD i = 0; i != count; ++i)
|
||||
{
|
||||
com_ptr<IShellItem> psi;
|
||||
hr = psiaResults->GetItemAt(i, &psi);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
_hasReadonly |= hasReadonlyAttr(psi);
|
||||
result.push_back(getFilename(psi));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static const int IDC_FILE_CHECKBOX = 4;
|
||||
|
@ -180,16 +635,20 @@ public:
|
|||
const TCHAR* _defExt = nullptr;
|
||||
const TCHAR* _folder = nullptr;
|
||||
const TCHAR* _checkboxLabel = nullptr;
|
||||
const TCHAR* _initialFileName = nullptr;
|
||||
bool _isCheckboxActive = true;
|
||||
std::vector<std::pair<generic_string, generic_string>> _filterSpec; // text + extension
|
||||
std::vector<Filter> _filterSpec;
|
||||
int _fileTypeIndex = -1;
|
||||
bool _hasReadonly = false; // set during the result handling
|
||||
|
||||
private:
|
||||
IFileDialog* _dialog = nullptr;
|
||||
IFileDialogCustomize* _customize = nullptr;
|
||||
TCHAR _fileName[MAX_PATH * 8];
|
||||
com_ptr<IFileDialog> _dialog;
|
||||
com_ptr<IFileDialogCustomize> _customize;
|
||||
com_ptr<IFileDialogEvents> _events;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CustomFileDialog::CustomFileDialog(HWND hwnd) : _impl{std::make_unique<Impl>()}
|
||||
{
|
||||
_impl->_hwndOwner = hwnd;
|
||||
|
@ -205,7 +664,7 @@ void CustomFileDialog::setTitle(const TCHAR* title)
|
|||
void CustomFileDialog::setExtFilter(const TCHAR *extText, const TCHAR *exts)
|
||||
{
|
||||
// Add an asterisk before each dot in file patterns
|
||||
generic_string newExts{ exts };
|
||||
generic_string newExts{ exts ? exts : _T("") };
|
||||
for (size_t pos = 0; pos < newExts.size(); ++pos)
|
||||
{
|
||||
pos = newExts.find(_T('.'), pos);
|
||||
|
@ -221,11 +680,29 @@ void CustomFileDialog::setExtFilter(const TCHAR *extText, const TCHAR *exts)
|
|||
_impl->_filterSpec.push_back({ extText, newExts });
|
||||
}
|
||||
|
||||
|
||||
void CustomFileDialog::setExtFilter(const TCHAR *extText, std::initializer_list<const TCHAR*> extList)
|
||||
{
|
||||
generic_string exts;
|
||||
for (auto&& x : extList)
|
||||
{
|
||||
exts += x;
|
||||
exts += _T(';');
|
||||
}
|
||||
exts.pop_back(); // remove the last ';'
|
||||
setExtFilter(extText, exts.c_str());
|
||||
}
|
||||
|
||||
void CustomFileDialog::setDefExt(const TCHAR* ext)
|
||||
{
|
||||
_impl->_defExt = ext;
|
||||
}
|
||||
|
||||
void CustomFileDialog::setDefFileName(const TCHAR* fn)
|
||||
{
|
||||
_impl->_initialFileName = fn;
|
||||
}
|
||||
|
||||
void CustomFileDialog::setFolder(const TCHAR* folder)
|
||||
{
|
||||
_impl->_folder = folder;
|
||||
|
@ -247,36 +724,64 @@ bool CustomFileDialog::getCheckboxState() const
|
|||
return _impl->getCheckboxState();
|
||||
}
|
||||
|
||||
const TCHAR* CustomFileDialog::doSaveDlg()
|
||||
bool CustomFileDialog::isReadOnly() const
|
||||
{
|
||||
return _impl->_hasReadonly;
|
||||
}
|
||||
|
||||
generic_string CustomFileDialog::doSaveDlg()
|
||||
{
|
||||
if (!_impl->initSave())
|
||||
return nullptr;
|
||||
return {};
|
||||
|
||||
TCHAR dir[MAX_PATH];
|
||||
::GetCurrentDirectory(MAX_PATH, dir);
|
||||
CurrentDirBackup backup;
|
||||
|
||||
NppParameters& params = NppParameters::getInstance();
|
||||
_impl->setInitDir(params.getWorkingDir());
|
||||
_impl->setFolder(params.getWorkingDir());
|
||||
|
||||
_impl->addFlags(FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_FORCEFILESYSTEM);
|
||||
bool bOk = _impl->show();
|
||||
|
||||
if (params.getNppGUI()._openSaveDir == dir_last)
|
||||
{
|
||||
::GetCurrentDirectory(MAX_PATH, dir);
|
||||
params.setWorkingDir(dir);
|
||||
}
|
||||
::SetCurrentDirectory(dir);
|
||||
|
||||
return bOk ? _impl->getResultFilename() : nullptr;
|
||||
return bOk ? _impl->getResultFilename() : _T("");
|
||||
}
|
||||
|
||||
const TCHAR* CustomFileDialog::pickFolder()
|
||||
generic_string CustomFileDialog::doOpenSingleFileDlg()
|
||||
{
|
||||
if (!_impl->initOpen())
|
||||
return nullptr;
|
||||
return {};
|
||||
|
||||
CurrentDirBackup backup;
|
||||
|
||||
NppParameters& params = NppParameters::getInstance();
|
||||
_impl->setFolder(params.getWorkingDir());
|
||||
|
||||
_impl->addFlags(FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_FORCEFILESYSTEM);
|
||||
bool bOk = _impl->show();
|
||||
return bOk ? _impl->getResultFilename() : _T("");
|
||||
}
|
||||
|
||||
std::vector<generic_string> CustomFileDialog::doOpenMultiFilesDlg()
|
||||
{
|
||||
if (!_impl->initOpen())
|
||||
return {};
|
||||
|
||||
CurrentDirBackup backup;
|
||||
|
||||
NppParameters& params = NppParameters::getInstance();
|
||||
_impl->setFolder(params.getWorkingDir());
|
||||
|
||||
_impl->addFlags(FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_FORCEFILESYSTEM | FOS_ALLOWMULTISELECT);
|
||||
bool bOk = _impl->show();
|
||||
if (bOk)
|
||||
return _impl->getFilenames();
|
||||
return {};
|
||||
}
|
||||
|
||||
generic_string CustomFileDialog::pickFolder()
|
||||
{
|
||||
if (!_impl->initOpen())
|
||||
return {};
|
||||
|
||||
_impl->addFlags(FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_FORCEFILESYSTEM | FOS_PICKFOLDERS);
|
||||
bool bOk = _impl->show();
|
||||
return bOk ? _impl->getResultFilename() : nullptr;
|
||||
return bOk ? _impl->getResultFilename() : _T("");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// This file is part of Notepad++ project
|
||||
// Copyright (C)2021 Don HO <don.h@free.fr>
|
||||
// Copyright (C) 2021 The Notepad++ Contributors.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -31,15 +31,21 @@ public:
|
|||
~CustomFileDialog();
|
||||
void setTitle(const TCHAR* title);
|
||||
void setExtFilter(const TCHAR* text, const TCHAR* ext);
|
||||
void setExtFilter(const TCHAR* text, std::initializer_list<const TCHAR*> exts);
|
||||
void setDefExt(const TCHAR* ext);
|
||||
void setDefFileName(const TCHAR *fn);
|
||||
void setFolder(const TCHAR* folder);
|
||||
void setCheckbox(const TCHAR* text, bool isActive = true);
|
||||
void setExtIndex(int extTypeIndex);
|
||||
|
||||
const TCHAR* doSaveDlg();
|
||||
const TCHAR* pickFolder();
|
||||
// Empty string is not a valid file name and may signal that the dialog was canceled.
|
||||
generic_string doSaveDlg();
|
||||
generic_string pickFolder();
|
||||
generic_string doOpenSingleFileDlg();
|
||||
std::vector<generic_string> doOpenMultiFilesDlg();
|
||||
|
||||
bool getCheckboxState() const;
|
||||
bool isReadOnly() const;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
|
|
|
@ -1,545 +0,0 @@
|
|||
// This file is part of Notepad++ project
|
||||
// Copyright (C)2021 Don HO <don.h@free.fr>
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// at your option any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include <shlwapi.h>
|
||||
|
||||
#include "FileDialog.h"
|
||||
#include "Parameters.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
FileDialog *FileDialog::staticThis = NULL;
|
||||
|
||||
FileDialog::FileDialog(HWND hwnd, HINSTANCE hInst)
|
||||
{
|
||||
staticThis = this;
|
||||
|
||||
memset(_fileName, 0, sizeof(_fileName));
|
||||
_winVersion = (NppParameters::getInstance()).getWinVersion();
|
||||
|
||||
_ofn.lStructSize = sizeof(_ofn);
|
||||
if (_winVersion < WV_W2K)
|
||||
_ofn.lStructSize = sizeof(OPENFILENAME);
|
||||
_ofn.hwndOwner = hwnd;
|
||||
_ofn.hInstance = hInst;
|
||||
_ofn.lpstrCustomFilter = (LPTSTR) NULL;
|
||||
_ofn.nMaxCustFilter = 0L;
|
||||
_ofn.nFilterIndex = 1L;
|
||||
_ofn.lpstrFile = _fileName;
|
||||
_ofn.nMaxFile = sizeof(_fileName)/sizeof(TCHAR);
|
||||
_ofn.lpstrFileTitle = NULL;
|
||||
_ofn.nMaxFileTitle = 0;
|
||||
_ofn.lpstrInitialDir = NULL;
|
||||
_ofn.lpstrTitle = NULL;
|
||||
_ofn.nFileOffset = 0;
|
||||
_ofn.nFileExtension = 0;
|
||||
_ofn.lpfnHook = NULL;
|
||||
_ofn.lpstrDefExt = NULL; // No default extension
|
||||
_ofn.lCustData = 0;
|
||||
_ofn.Flags = OFN_PATHMUSTEXIST | OFN_EXPLORER | OFN_LONGNAMES | OFN_HIDEREADONLY;
|
||||
_ofn.pvReserved = NULL;
|
||||
_ofn.dwReserved = 0;
|
||||
_ofn.FlagsEx = 0;
|
||||
}
|
||||
|
||||
FileDialog::~FileDialog()
|
||||
{
|
||||
delete[] _fileExt;
|
||||
_fileExt = NULL;
|
||||
}
|
||||
|
||||
// This function set and concatenate the filter into the list box of FileDialog.
|
||||
// The 1st parameter is the description of the file type, the 2nd .. Nth parameter(s) is (are)
|
||||
// the file extension which should be ".WHATEVER", otherwise it (they) will be considered as
|
||||
// a file name to filter. Since the nb of arguments is variable, you have to add NULL at the end.
|
||||
// example :
|
||||
// FileDialog.setExtFilter(TEXT("c/c++ src file"), TEXT(".c"), TEXT(".cpp"), TEXT(".cxx"), TEXT(".h"), NULL);
|
||||
// FileDialog.setExtFilter(TEXT("Makefile"), TEXT("makefile"), TEXT("GNUmakefile"), NULL);
|
||||
void FileDialog::setExtFilter(const TCHAR *extText, const TCHAR *ext, ...)
|
||||
{
|
||||
// fill out the ext array for save as file dialog
|
||||
generic_string exts;
|
||||
|
||||
va_list pArg;
|
||||
va_start(pArg, ext);
|
||||
|
||||
const TCHAR *ext2Concat;
|
||||
ext2Concat = ext;
|
||||
do
|
||||
{
|
||||
if (ext2Concat[0] == TEXT('.'))
|
||||
exts += TEXT("*");
|
||||
exts += ext2Concat;
|
||||
exts += TEXT(";");
|
||||
}
|
||||
while ( (ext2Concat = va_arg(pArg, const TCHAR *)) != NULL );
|
||||
|
||||
va_end(pArg);
|
||||
|
||||
// remove the last ';'
|
||||
exts = exts.substr(0, exts.length()-1);
|
||||
|
||||
setExtsFilter(extText, exts.c_str());
|
||||
}
|
||||
|
||||
int FileDialog::setExtsFilter(const TCHAR *extText, const TCHAR *exts)
|
||||
{
|
||||
// fill out the ext array for save as file dialog
|
||||
generic_string extFilter = extText;
|
||||
TCHAR *oldFilter = NULL;
|
||||
|
||||
extFilter += TEXT(" (");
|
||||
extFilter += exts;
|
||||
extFilter += TEXT(")");
|
||||
|
||||
// Resize filter buffer
|
||||
int nbCharAdditional = static_cast<int32_t>(extFilter.length() + _tcsclen(exts) + 3); // 3 additional for nulls
|
||||
if (_fileExt)
|
||||
{
|
||||
oldFilter = new TCHAR[_nbCharFileExt];
|
||||
memcpy(oldFilter, _fileExt, _nbCharFileExt * sizeof(TCHAR));
|
||||
|
||||
delete[] _fileExt;
|
||||
_fileExt = NULL;
|
||||
}
|
||||
|
||||
int nbCharNewFileExt = _nbCharFileExt + nbCharAdditional;
|
||||
_fileExt = new TCHAR[nbCharNewFileExt];
|
||||
memset(_fileExt, 0, nbCharNewFileExt * sizeof(TCHAR));
|
||||
|
||||
// Restore previous filters
|
||||
if (oldFilter)
|
||||
{
|
||||
memcpy(_fileExt, oldFilter, _nbCharFileExt * sizeof(TCHAR));
|
||||
delete[] oldFilter;
|
||||
oldFilter = NULL;
|
||||
}
|
||||
|
||||
// Append new filter
|
||||
TCHAR *pFileExt = _fileExt + _nbCharFileExt;
|
||||
auto curLen = extFilter.length() + 1;
|
||||
wcscpy_s(pFileExt, curLen, extFilter.c_str());
|
||||
_nbCharFileExt += static_cast<int32_t>(curLen);
|
||||
|
||||
pFileExt = _fileExt + _nbCharFileExt;
|
||||
curLen = _tcsclen(exts) + 1;
|
||||
wcscpy_s(pFileExt, curLen, exts);
|
||||
_nbCharFileExt += static_cast<int32_t>(curLen);
|
||||
|
||||
// Set file dialog pointer
|
||||
_ofn.lpstrFilter = _fileExt;
|
||||
|
||||
return _nbExt;
|
||||
}
|
||||
|
||||
TCHAR* FileDialog::doOpenSingleFileDlg()
|
||||
{
|
||||
TCHAR dir[MAX_PATH];
|
||||
::GetCurrentDirectory(MAX_PATH, dir);
|
||||
NppParameters& params = NppParameters::getInstance();
|
||||
_ofn.lpstrInitialDir = params.getWorkingDir();
|
||||
_ofn.lpstrDefExt = _defExt.c_str();
|
||||
|
||||
_ofn.Flags |= OFN_FILEMUSTEXIST;
|
||||
|
||||
if (!params.useNewStyleSaveDlg())
|
||||
{
|
||||
_ofn.Flags |= OFN_ENABLEHOOK | OFN_NOVALIDATE;
|
||||
_ofn.lpfnHook = OFNHookProc;
|
||||
}
|
||||
|
||||
TCHAR *fn = NULL;
|
||||
try
|
||||
{
|
||||
fn = ::GetOpenFileName(&_ofn) ? _fileName : NULL;
|
||||
|
||||
if (params.getNppGUI()._openSaveDir == dir_last)
|
||||
{
|
||||
::GetCurrentDirectory(MAX_PATH, dir);
|
||||
params.setWorkingDir(dir);
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
generic_string msg = TEXT("An exception occurred while opening file: ");
|
||||
msg += _fileName;
|
||||
msg += TEXT("\r\n\r\nException reason: ");
|
||||
msg += s2ws(e.what());
|
||||
|
||||
::MessageBox(NULL, msg.c_str(), TEXT("File Open Exception"), MB_OK);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
::MessageBox(NULL, TEXT("doOpenSingleFileDlg crashes!!!"), TEXT(""), MB_OK);
|
||||
}
|
||||
|
||||
::SetCurrentDirectory(dir);
|
||||
|
||||
return (fn);
|
||||
}
|
||||
|
||||
stringVector * FileDialog::doOpenMultiFilesDlg()
|
||||
{
|
||||
TCHAR dir[MAX_PATH];
|
||||
::GetCurrentDirectory(MAX_PATH, dir);
|
||||
|
||||
NppParameters& params = NppParameters::getInstance();
|
||||
_ofn.lpstrInitialDir = params.getWorkingDir();
|
||||
|
||||
_ofn.Flags |= OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_ENABLESIZING;
|
||||
|
||||
if (!params.useNewStyleSaveDlg())
|
||||
{
|
||||
_ofn.Flags |= OFN_ENABLEHOOK | OFN_NOVALIDATE;
|
||||
_ofn.lpfnHook = OFNHookProc;
|
||||
}
|
||||
|
||||
BOOL res = ::GetOpenFileName(&_ofn);
|
||||
if (params.getNppGUI()._openSaveDir == dir_last)
|
||||
{
|
||||
::GetCurrentDirectory(MAX_PATH, dir);
|
||||
params.setWorkingDir(dir);
|
||||
}
|
||||
::SetCurrentDirectory(dir);
|
||||
|
||||
if (res)
|
||||
{
|
||||
TCHAR* pFn = _fileName + lstrlen(_fileName) + 1;
|
||||
TCHAR fn[MAX_PATH*8];
|
||||
memset(fn, 0x0, sizeof(fn));
|
||||
|
||||
if (!(*pFn))
|
||||
{
|
||||
_fileNames.push_back(generic_string(_fileName));
|
||||
}
|
||||
else
|
||||
{
|
||||
wcscpy_s(fn, _fileName);
|
||||
if (fn[lstrlen(fn) - 1] != '\\')
|
||||
wcscat_s(fn, TEXT("\\"));
|
||||
}
|
||||
|
||||
int term = lstrlen(fn);
|
||||
|
||||
while (*pFn)
|
||||
{
|
||||
fn[term] = '\0';
|
||||
wcscat_s(fn, pFn);
|
||||
_fileNames.push_back(generic_string(fn));
|
||||
pFn += lstrlen(pFn) + 1;
|
||||
}
|
||||
|
||||
return &_fileNames;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
TCHAR * FileDialog::doSaveDlg()
|
||||
{
|
||||
TCHAR dir[MAX_PATH];
|
||||
::GetCurrentDirectory(MAX_PATH, dir);
|
||||
|
||||
NppParameters& params = NppParameters::getInstance();
|
||||
_ofn.lpstrInitialDir = params.getWorkingDir();
|
||||
_ofn.lpstrDefExt = _defExt.c_str();
|
||||
if (_extTypeIndex != -1)
|
||||
_ofn.nFilterIndex = _extTypeIndex + 1; // +1 for the file extension combobox index starts from 1
|
||||
|
||||
_ofn.Flags |= OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_ENABLESIZING;
|
||||
|
||||
if (!params.useNewStyleSaveDlg())
|
||||
{
|
||||
_ofn.Flags |= OFN_ENABLEHOOK | OFN_NOVALIDATE;
|
||||
_ofn.lpfnHook = OFNHookProc;
|
||||
}
|
||||
|
||||
TCHAR *fn = NULL;
|
||||
try
|
||||
{
|
||||
fn = ::GetSaveFileName(&_ofn) ? _fileName : NULL;
|
||||
if (params.getNppGUI()._openSaveDir == dir_last)
|
||||
{
|
||||
::GetCurrentDirectory(MAX_PATH, dir);
|
||||
params.setWorkingDir(dir);
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
generic_string msg = TEXT("An exception occurred while saving file: ");
|
||||
msg += _fileName;
|
||||
msg += TEXT("\r\n\r\nException reason: ");
|
||||
msg += s2ws(e.what());
|
||||
|
||||
::MessageBox(NULL, msg.c_str(), TEXT("File Save Exception"), MB_OK);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
::MessageBox(NULL, TEXT("GetSaveFileName crashes!!!"), TEXT(""), MB_OK);
|
||||
}
|
||||
|
||||
::SetCurrentDirectory(dir);
|
||||
|
||||
return (fn);
|
||||
}
|
||||
|
||||
static HWND hFileDlg = NULL;
|
||||
static WNDPROC oldProc = NULL;
|
||||
static generic_string currentExt = TEXT("");
|
||||
|
||||
|
||||
static LRESULT CALLBACK fileDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_COMMAND :
|
||||
{
|
||||
switch (wParam)
|
||||
{
|
||||
case IDOK :
|
||||
{
|
||||
HWND fnControl = ::GetDlgItem(hwnd, FileDialog::_dialogFileBoxId);
|
||||
TCHAR fn[MAX_PATH];
|
||||
::GetWindowText(fnControl, fn, MAX_PATH);
|
||||
|
||||
// Check condition to have the compability of default behaviour
|
||||
if (*fn == '\0')
|
||||
return oldProc(hwnd, message, wParam, lParam);
|
||||
else if (::PathIsDirectory(fn))
|
||||
return oldProc(hwnd, message, wParam, lParam);
|
||||
|
||||
// Process
|
||||
if (currentExt != TEXT(""))
|
||||
{
|
||||
generic_string fnExt = changeExt(fn, currentExt, false);
|
||||
::SetWindowText(fnControl, fnExt.c_str());
|
||||
}
|
||||
return oldProc(hwnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
default :
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return oldProc(hwnd, message, wParam, lParam);
|
||||
};
|
||||
|
||||
|
||||
static TCHAR * get1stExt(TCHAR *ext)
|
||||
{
|
||||
// precondition : ext should be under the format : Batch (*.bat;*.cmd;*.nt)
|
||||
TCHAR *begin = ext;
|
||||
for ( ; *begin != '.' ; begin++);
|
||||
TCHAR *end = ++begin;
|
||||
for ( ; *end != ';' && *end != ')' ; end++);
|
||||
*end = '\0';
|
||||
if (*begin == '*')
|
||||
*begin = '\0';
|
||||
return begin;
|
||||
};
|
||||
|
||||
static generic_string addExt(HWND textCtrl, HWND typeCtrl)
|
||||
{
|
||||
TCHAR fn[MAX_PATH];
|
||||
::GetWindowText(textCtrl, fn, MAX_PATH);
|
||||
|
||||
auto i = ::SendMessage(typeCtrl, CB_GETCURSEL, 0, 0);
|
||||
|
||||
auto cbTextLen = ::SendMessage(typeCtrl, CB_GETLBTEXTLEN, i, 0);
|
||||
TCHAR * ext = new TCHAR[cbTextLen + 1];
|
||||
::SendMessage(typeCtrl, CB_GETLBTEXT, i, reinterpret_cast<LPARAM>(ext));
|
||||
|
||||
TCHAR *pExt = get1stExt(ext);
|
||||
if (*fn != '\0')
|
||||
{
|
||||
generic_string fnExt = changeExt(fn, pExt);
|
||||
::SetWindowText(textCtrl, fnExt.c_str());
|
||||
}
|
||||
|
||||
generic_string returnExt = pExt;
|
||||
delete[] ext;
|
||||
return returnExt;
|
||||
};
|
||||
|
||||
UINT_PTR CALLBACK FileDialog::OFNHookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch(uMsg)
|
||||
{
|
||||
case WM_INITDIALOG :
|
||||
{
|
||||
NppParameters& nppParam = NppParameters::getInstance();
|
||||
int index = nppParam.getFileSaveDlgFilterIndex();
|
||||
|
||||
::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(staticThis));
|
||||
hFileDlg = ::GetParent(hWnd);
|
||||
goToCenter(hFileDlg);
|
||||
|
||||
if (index != -1)
|
||||
{
|
||||
HWND typeControl = ::GetDlgItem(hFileDlg, cmb1);
|
||||
::SendMessage(typeControl, CB_SETCURSEL, index, 0);
|
||||
}
|
||||
// Don't touch the following 3 lines, they are cursed !!!
|
||||
oldProc = reinterpret_cast<WNDPROC>(::GetWindowLongPtr(hFileDlg, GWLP_WNDPROC));
|
||||
if (oldProc)
|
||||
::SetWindowLongPtr(hFileDlg, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(fileDlgProc));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
default :
|
||||
{
|
||||
FileDialog *pFileDialog = reinterpret_cast<FileDialog *>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
|
||||
if (!pFileDialog)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
return pFileDialog->run(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL APIENTRY FileDialog::run(HWND hWnd, UINT uMsg, WPARAM, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_NOTIFY :
|
||||
{
|
||||
LPNMHDR pNmhdr = (LPNMHDR)lParam;
|
||||
switch(pNmhdr->code)
|
||||
{
|
||||
case CDN_INITDONE :
|
||||
{
|
||||
if (_extTypeIndex == -1)
|
||||
return TRUE;
|
||||
|
||||
HWND fnControl = ::GetDlgItem(::GetParent(hWnd), _dialogFileBoxId);
|
||||
HWND typeControl = ::GetDlgItem(::GetParent(hWnd), cmb1);
|
||||
::SendMessage(typeControl, CB_SETCURSEL, _extTypeIndex, 0);
|
||||
|
||||
currentExt = addExt(fnControl, typeControl);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case CDN_TYPECHANGE :
|
||||
{
|
||||
HWND fnControl = ::GetDlgItem(::GetParent(hWnd), _dialogFileBoxId);
|
||||
HWND typeControl = ::GetDlgItem(::GetParent(hWnd), cmb1);
|
||||
currentExt = addExt(fnControl, typeControl);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case CDN_FILEOK :
|
||||
{
|
||||
HWND typeControl = ::GetDlgItem(::GetParent(hWnd), cmb1);
|
||||
int index = static_cast<int32_t>(::SendMessage(typeControl, CB_GETCURSEL, 0, 0));
|
||||
NppParameters& nppParam = NppParameters::getInstance();
|
||||
nppParam.setFileSaveDlgFilterIndex(index);
|
||||
|
||||
// change forward-slash to back-slash directory paths so dialog can interpret
|
||||
OPENFILENAME* ofn = reinterpret_cast<LPOFNOTIFY>(lParam)->lpOFN;
|
||||
TCHAR* fileName = ofn->lpstrFile;
|
||||
|
||||
// note: this check is essential, because otherwise we could return True
|
||||
// with a OFN_NOVALIDATE dialog, which leads to opening every file
|
||||
// in the specified directory. Multi-select terminator is \0\0.
|
||||
if ((ofn->Flags & OFN_ALLOWMULTISELECT) &&
|
||||
(*(fileName + lstrlen(fileName) + 1) != '\0'))
|
||||
return FALSE;
|
||||
|
||||
if (::PathIsDirectory(fileName))
|
||||
{
|
||||
// change to backslash, and insert trailing '\' to indicate directory
|
||||
hFileDlg = ::GetParent(hWnd);
|
||||
std::wstring filePath(fileName);
|
||||
std::replace(filePath.begin(), filePath.end(), '/', '\\');
|
||||
|
||||
if (filePath.back() != '\\')
|
||||
filePath.insert(filePath.end(), '\\');
|
||||
|
||||
// There are two or more double backslash, then change it to single
|
||||
while (filePath.find(L"\\\\") != std::wstring::npos)
|
||||
filePath.replace(filePath.find(TEXT("\\\\")), 2, TEXT("\\"));
|
||||
|
||||
// change the dialog directory selection
|
||||
::SendMessage(hFileDlg, CDM_SETCONTROLTEXT, edt1,
|
||||
reinterpret_cast<LPARAM>(filePath.c_str()));
|
||||
::PostMessage(hFileDlg, WM_COMMAND, IDOK, 0);
|
||||
::SetWindowLongPtr(hWnd, 0 /*DWL_MSGRESULT*/, 1);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
default :
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
default :
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void goToCenter(HWND hwnd)
|
||||
{
|
||||
RECT rc;
|
||||
HWND hParent = ::GetParent(hwnd);
|
||||
::GetClientRect(hParent, &rc);
|
||||
|
||||
//If window coordinates are all zero(ie,window is minimised),then assign desktop as the parent window.
|
||||
if (rc.left == 0 && rc.right == 0 && rc.top == 0 && rc.bottom == 0)
|
||||
{
|
||||
//hParent = ::GetDesktopWindow();
|
||||
::ShowWindow(hParent, SW_SHOWNORMAL);
|
||||
::GetClientRect(hParent,&rc);
|
||||
}
|
||||
|
||||
POINT center;
|
||||
center.x = rc.left + (rc.right - rc.left)/2;
|
||||
center.y = rc.top + (rc.bottom - rc.top)/2;
|
||||
::ClientToScreen(hParent, ¢er);
|
||||
|
||||
RECT _rc;
|
||||
::GetWindowRect(hwnd, &_rc);
|
||||
int x = center.x - (_rc.right - _rc.left)/2;
|
||||
int y = center.y - (_rc.bottom - _rc.top)/2;
|
||||
|
||||
::SetWindowPos(hwnd, HWND_TOP, x, y, _rc.right - _rc.left, _rc.bottom - _rc.top, SWP_SHOWWINDOW);
|
||||
}
|
||||
|
||||
generic_string changeExt(generic_string fn, generic_string ext, bool forceReplaced)
|
||||
{
|
||||
if (ext == TEXT(""))
|
||||
return fn;
|
||||
|
||||
generic_string fnExt = fn;
|
||||
|
||||
auto index = fnExt.find_last_of(TEXT("."));
|
||||
generic_string extension = TEXT(".");
|
||||
extension += ext;
|
||||
if (index == generic_string::npos)
|
||||
{
|
||||
fnExt += extension;
|
||||
}
|
||||
else if (forceReplaced)
|
||||
{
|
||||
auto len = (extension.length() > fnExt.length() - index + 1)?extension.length():fnExt.length() - index + 1;
|
||||
fnExt.replace(index, len, extension);
|
||||
}
|
||||
return fnExt;
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
// This file is part of Notepad++ project
|
||||
// Copyright (C)2021 Don HO <don.h@free.fr>
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// at your option any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common.h"
|
||||
#include "Notepad_plus_msgs.h"
|
||||
|
||||
const int nbExtMax = 256;
|
||||
const int extLenMax = 64;
|
||||
|
||||
typedef std::vector<generic_string> stringVector;
|
||||
|
||||
generic_string changeExt(generic_string fn, generic_string ext, bool forceReplaced = true);
|
||||
void goToCenter(HWND hwnd);
|
||||
|
||||
|
||||
class FileDialog
|
||||
{
|
||||
public:
|
||||
FileDialog(HWND hwnd, HINSTANCE hInst);
|
||||
~FileDialog();
|
||||
void setExtFilter(const TCHAR *, const TCHAR *, ...);
|
||||
|
||||
int setExtsFilter(const TCHAR *extText, const TCHAR *exts);
|
||||
void setDefFileName(const TCHAR *fn){ wcscpy_s(_fileName, fn);}
|
||||
void setDefExt(const TCHAR *ext){ _defExt = ext;}
|
||||
|
||||
TCHAR * doSaveDlg();
|
||||
stringVector * doOpenMultiFilesDlg();
|
||||
TCHAR * doOpenSingleFileDlg();
|
||||
bool isReadOnly() {return _ofn.Flags & OFN_READONLY;};
|
||||
void setExtIndex(int extTypeIndex) {_extTypeIndex = extTypeIndex;};
|
||||
|
||||
static int _dialogFileBoxId;
|
||||
protected :
|
||||
static UINT_PTR CALLBACK OFNHookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
BOOL APIENTRY run(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
private:
|
||||
TCHAR _fileName[MAX_PATH*8];
|
||||
generic_string _defExt;
|
||||
|
||||
TCHAR * _fileExt = nullptr;
|
||||
int _nbCharFileExt = 0;
|
||||
|
||||
stringVector _fileNames;
|
||||
|
||||
OPENFILENAME _ofn;
|
||||
winVer _winVersion;
|
||||
|
||||
int _nbExt = 0;
|
||||
int _extTypeIndex = -1;
|
||||
static FileDialog *staticThis;
|
||||
};
|
||||
|
|
@ -150,8 +150,7 @@ BEGIN
|
|||
CONTROL "",IDC_OPENSAVEDIR_ALWAYSON_RADIO,"Button",BS_AUTORADIOBUTTON,118,89,11,10
|
||||
EDITTEXT IDC_OPENSAVEDIR_ALWAYSON_EDIT,134,88,179,14,ES_AUTOHSCROLL
|
||||
PUSHBUTTON "...",IDD_OPENSAVEDIR_ALWAYSON_BROWSE_BUTTON,320,87,16,14
|
||||
CONTROL "Use new style dialog (without Unix style path capacity)",IDC_OPENSAVEDIR_CHECK_USENEWSTYLESAVEDIALOG, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,145,342,10
|
||||
CONTROL "Open all files of folder instead of launching Folder as Workspace on folder dropping",IDC_OPENSAVEDIR_CHECK_DRROPFOLDEROPENFILES, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,158,342,10
|
||||
CONTROL "Open all files of folder instead of launching Folder as Workspace on folder dropping",IDC_OPENSAVEDIR_CHECK_DRROPFOLDEROPENFILES, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,110, 145,342,10
|
||||
END
|
||||
|
||||
|
||||
|
|
|
@ -1407,7 +1407,6 @@ INT_PTR CALLBACK DefaultDirectorySubDlg::run_dlgProc(UINT message, WPARAM wParam
|
|||
if (enableDlgTheme)
|
||||
enableDlgTheme(_hSelf, ETDT_ENABLETAB);
|
||||
|
||||
::SendDlgItemMessage(_hSelf, IDC_OPENSAVEDIR_CHECK_USENEWSTYLESAVEDIALOG, BM_SETCHECK, nppGUI._useNewStyleSaveDlg ? BST_CHECKED : BST_UNCHECKED, 0);
|
||||
::SendDlgItemMessage(_hSelf, IDC_OPENSAVEDIR_CHECK_DRROPFOLDEROPENFILES, BM_SETCHECK, nppGUI._isFolderDroppedOpenFiles ? BST_CHECKED : BST_UNCHECKED, 0);
|
||||
}
|
||||
|
||||
|
@ -1451,10 +1450,6 @@ INT_PTR CALLBACK DefaultDirectorySubDlg::run_dlgProc(UINT message, WPARAM wParam
|
|||
folderBrowser(_hSelf, TEXT("Select a folder as default directory"), IDC_OPENSAVEDIR_ALWAYSON_EDIT);
|
||||
return TRUE;
|
||||
|
||||
case IDC_OPENSAVEDIR_CHECK_USENEWSTYLESAVEDIALOG:
|
||||
nppGUI._useNewStyleSaveDlg = isCheckedOrNot(IDC_OPENSAVEDIR_CHECK_USENEWSTYLESAVEDIALOG);
|
||||
return TRUE;
|
||||
|
||||
case IDC_OPENSAVEDIR_CHECK_DRROPFOLDEROPENFILES:
|
||||
nppGUI._isFolderDroppedOpenFiles = isCheckedOrNot(IDC_OPENSAVEDIR_CHECK_DRROPFOLDEROPENFILES);
|
||||
return TRUE;
|
||||
|
|
|
@ -237,7 +237,6 @@
|
|||
#define IDC_RADIO_CUSTOMIZELENTH (IDD_PREFERENCE_SUB_NEWDOCUMENT + 27)
|
||||
#define IDC_CUSTOMIZELENGTHVAL_STATIC (IDD_PREFERENCE_SUB_NEWDOCUMENT + 28)
|
||||
#define IDC_DISPLAY_STATIC (IDD_PREFERENCE_SUB_NEWDOCUMENT + 29)
|
||||
#define IDC_OPENSAVEDIR_CHECK_USENEWSTYLESAVEDIALOG (IDD_PREFERENCE_SUB_NEWDOCUMENT + 30)
|
||||
#define IDC_OPENSAVEDIR_CHECK_DRROPFOLDEROPENFILES (IDD_PREFERENCE_SUB_NEWDOCUMENT + 31)
|
||||
|
||||
#define IDD_PREFERENCE_SUB_DEFAULTDIRECTORY 6450 //(IDD_PREFERENCE_BOX + 400)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "ProjectPanel.h"
|
||||
#include "resource.h"
|
||||
#include "tinyxml.h"
|
||||
#include "FileDialog.h"
|
||||
#include "CustomFileDialog.h"
|
||||
#include "localization.h"
|
||||
#include "Parameters.h"
|
||||
|
||||
|
@ -439,7 +439,7 @@ bool ProjectPanel::saveWorkSpace()
|
|||
}
|
||||
}
|
||||
|
||||
bool ProjectPanel::writeWorkSpace(TCHAR *projectFileName)
|
||||
bool ProjectPanel::writeWorkSpace(const TCHAR *projectFileName)
|
||||
{
|
||||
//write <NotepadPlus>: use the default file name if new file name is not given
|
||||
const TCHAR * fn2write = projectFileName?projectFileName:_workSpaceFilePath.c_str();
|
||||
|
@ -1032,11 +1032,12 @@ void ProjectPanel::popupMenuCmd(int cmdID)
|
|||
if (!saveWorkspaceRequest())
|
||||
break;
|
||||
|
||||
FileDialog fDlg(_hSelf, ::GetModuleHandle(NULL));
|
||||
CustomFileDialog fDlg(_hSelf);
|
||||
setFileExtFilter(fDlg);
|
||||
if (TCHAR *fn = fDlg.doOpenSingleFileDlg())
|
||||
const generic_string fn = fDlg.doOpenSingleFileDlg();
|
||||
if (!fn.empty())
|
||||
{
|
||||
if (!openWorkSpace(fn, true))
|
||||
if (!openWorkSpace(fn.c_str(), true))
|
||||
{
|
||||
NativeLangSpeaker *pNativeSpeaker = (NppParameters::getInstance()).getNativeLangSpeaker();
|
||||
pNativeSpeaker->messageBox("ProjectPanelOpenFailed",
|
||||
|
@ -1183,13 +1184,14 @@ void ProjectPanel::popupMenuCmd(int cmdID)
|
|||
|
||||
bool ProjectPanel::saveWorkSpaceAs(bool saveCopyAs)
|
||||
{
|
||||
FileDialog fDlg(_hSelf, ::GetModuleHandle(NULL));
|
||||
CustomFileDialog fDlg(_hSelf);
|
||||
setFileExtFilter(fDlg);
|
||||
fDlg.setExtIndex(0); // 0 index for "custom extention" type if any else for "All types *.*"
|
||||
|
||||
if (TCHAR *fn = fDlg.doSaveDlg())
|
||||
const generic_string fn = fDlg.doSaveDlg();
|
||||
if (!fn.empty())
|
||||
{
|
||||
writeWorkSpace(fn);
|
||||
writeWorkSpace(fn.c_str());
|
||||
if (!saveCopyAs)
|
||||
{
|
||||
_workSpaceFilePath = fn;
|
||||
|
@ -1200,7 +1202,7 @@ bool ProjectPanel::saveWorkSpaceAs(bool saveCopyAs)
|
|||
return false;
|
||||
}
|
||||
|
||||
void ProjectPanel::setFileExtFilter(FileDialog & fDlg)
|
||||
void ProjectPanel::setFileExtFilter(CustomFileDialog & fDlg)
|
||||
{
|
||||
const TCHAR *ext = NppParameters::getInstance().getNppGUI()._definedWorkspaceExt.c_str();
|
||||
generic_string workspaceExt = TEXT("");
|
||||
|
@ -1209,25 +1211,26 @@ void ProjectPanel::setFileExtFilter(FileDialog & fDlg)
|
|||
if (*ext != '.')
|
||||
workspaceExt += TEXT(".");
|
||||
workspaceExt += ext;
|
||||
fDlg.setExtFilter(TEXT("Workspace file"), workspaceExt.c_str(), NULL);
|
||||
fDlg.setExtFilter(TEXT("Workspace file"), workspaceExt.c_str());
|
||||
fDlg.setDefExt(ext);
|
||||
}
|
||||
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"), NULL);
|
||||
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"));
|
||||
}
|
||||
|
||||
void ProjectPanel::addFiles(HTREEITEM hTreeItem)
|
||||
{
|
||||
FileDialog fDlg(_hSelf, ::GetModuleHandle(NULL));
|
||||
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"), NULL);
|
||||
CustomFileDialog fDlg(_hSelf);
|
||||
fDlg.setExtFilter(TEXT("All types"), TEXT(".*"));
|
||||
|
||||
if (stringVector *pfns = fDlg.doOpenMultiFilesDlg())
|
||||
const auto& fns = fDlg.doOpenMultiFilesDlg();
|
||||
if (!fns.empty())
|
||||
{
|
||||
size_t sz = pfns->size();
|
||||
size_t sz = fns.size();
|
||||
for (size_t i = 0 ; i < sz ; ++i)
|
||||
{
|
||||
TCHAR *strValueLabel = ::PathFindFileName(pfns->at(i).c_str());
|
||||
TCHAR *strValueLabel = ::PathFindFileName(fns.at(i).c_str());
|
||||
|
||||
generic_string* pathFileStr = new generic_string(pfns->at(i));
|
||||
generic_string* pathFileStr = new generic_string(fns.at(i));
|
||||
fullPathStrs.push_back(pathFileStr);
|
||||
LPARAM lParamPathFileStr = reinterpret_cast<LPARAM>(pathFileStr);
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ enum NodeType {
|
|||
};
|
||||
|
||||
class TiXmlNode;
|
||||
class FileDialog;
|
||||
class CustomFileDialog;
|
||||
|
||||
class ProjectPanel : public DockingDlgInterface {
|
||||
public:
|
||||
|
@ -124,7 +124,7 @@ protected:
|
|||
void recursiveAddFilesFrom(const TCHAR *folderPath, HTREEITEM hTreeItem);
|
||||
HTREEITEM addFolder(HTREEITEM hTreeItem, const TCHAR *folderName);
|
||||
|
||||
bool writeWorkSpace(TCHAR *projectFileName = NULL);
|
||||
bool writeWorkSpace(const TCHAR *projectFileName = NULL);
|
||||
generic_string getRelativePath(const generic_string & fn, const TCHAR *workSpaceFileName);
|
||||
void buildProjectXml(TiXmlNode *root, HTREEITEM hItem, const TCHAR* fn2write);
|
||||
NodeType getNodeType(HTREEITEM hItem);
|
||||
|
@ -139,7 +139,7 @@ protected:
|
|||
HMENU getMenuHandler(HTREEITEM selectedItem);
|
||||
generic_string getAbsoluteFilePath(const TCHAR * relativePath);
|
||||
void openSelectFile();
|
||||
void setFileExtFilter(FileDialog & fDlg);
|
||||
void setFileExtFilter(CustomFileDialog & fDlg);
|
||||
std::vector<generic_string*> fullPathStrs;
|
||||
};
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
#include "StaticDialog.h"
|
||||
#include "RunDlg.h"
|
||||
#include "FileDialog.h"
|
||||
#include "CustomFileDialog.h"
|
||||
#include "Notepad_plus_msgs.h"
|
||||
#include "shortcut.h"
|
||||
#include "Parameters.h"
|
||||
|
@ -318,13 +318,14 @@ INT_PTR CALLBACK RunDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
|
|||
|
||||
case IDC_BUTTON_FILE_BROWSER :
|
||||
{
|
||||
FileDialog fd(_hSelf, _hInst);
|
||||
fd.setExtFilter(TEXT("Executable file : "), TEXT(".exe"), TEXT(".com"), TEXT(".cmd"), TEXT(".bat"), NULL);
|
||||
fd.setExtFilter(TEXT("All files : "), TEXT(".*"), NULL);
|
||||
CustomFileDialog fd(_hSelf);
|
||||
fd.setExtFilter(TEXT("Executable file : "), { TEXT(".exe"), TEXT(".com"), TEXT(".cmd"), TEXT(".bat") });
|
||||
fd.setExtFilter(TEXT("All files : "), TEXT(".*"));
|
||||
|
||||
if (const TCHAR *fn = fd.doOpenSingleFileDlg())
|
||||
generic_string fn = fd.doOpenSingleFileDlg();
|
||||
if (!fn.empty())
|
||||
{
|
||||
if (wcschr(fn, ' ') != NULL)
|
||||
if (fn.find(' ') != generic_string::npos)
|
||||
{
|
||||
generic_string fn_quotes(fn);
|
||||
fn_quotes = TEXT("\"") + fn_quotes + TEXT("\"");
|
||||
|
@ -332,7 +333,7 @@ INT_PTR CALLBACK RunDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
|
|||
}
|
||||
else
|
||||
{
|
||||
addTextToCombo(fn);
|
||||
addTextToCombo(fn.c_str());
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
|
|
|
@ -301,7 +301,6 @@ copy ..\src\contextMenu.xml ..\bin64\contextMenu.xml
|
|||
<ClCompile Include="..\src\ScitillaComponent\DocTabView.cpp" />
|
||||
<ClCompile Include="..\src\WinControls\DocumentMap\documentMap.cpp" />
|
||||
<ClCompile Include="..\src\EncodingMapper.cpp" />
|
||||
<ClCompile Include="..\src\WinControls\OpenSaveFileDialog\FileDialog.cpp" />
|
||||
<ClCompile Include="..\src\WinControls\FindCharsInRange\FindCharsInRange.cpp" />
|
||||
<ClCompile Include="..\src\ScitillaComponent\FindReplaceDlg.cpp" />
|
||||
<ClCompile Include="..\src\ScitillaComponent\FunctionCallTip.cpp" />
|
||||
|
@ -594,7 +593,6 @@ copy ..\src\contextMenu.xml ..\bin64\contextMenu.xml
|
|||
<ClInclude Include="..\src\ScitillaComponent\DocTabView.h" />
|
||||
<ClInclude Include="..\src\WinControls\DocumentMap\documentMap.h" />
|
||||
<ClInclude Include="..\src\EncodingMapper.h" />
|
||||
<ClInclude Include="..\src\WinControls\OpenSaveFileDialog\FileDialog.h" />
|
||||
<ClInclude Include="..\src\MISC\FileNameStringSplitter.h" />
|
||||
<ClInclude Include="..\src\WinControls\FindCharsInRange\FindCharsInRange.h" />
|
||||
<ClInclude Include="..\src\ScitillaComponent\FindReplaceDlg.h" />
|
||||
|
|
Loading…
Reference in New Issue