diff --git a/src/dialogs_win.cc b/src/dialogs_win.cc index d5c11f6..554cfd5 100644 --- a/src/dialogs_win.cc +++ b/src/dialogs_win.cc @@ -13,155 +13,141 @@ #include //TODO: remove using namespace std; //TODO: remove -class CommonDialog { +class Win32Dialog { public: - CommonDialog(CLSID type); - ~CommonDialog() { + Win32Dialog() {}; + + bool init(CLSID type) { + if(CoCreateInstance(type, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&dialog))!=S_OK) + return false; + if(dialog->GetOptions(&options)!=S_OK) + return false; + return true; + } + + ~Win32Dialog() { if(dialog!=nullptr) dialog->Release(); } + /** available options are listed at https://msdn.microsoft.com/en-gb/library/windows/desktop/dn457282(v=vs.85).aspx */ - void add_option(unsigned option); - void set_title(const std::wstring &title); - /** Sets the extensions the browser can find */ - void set_default_file_extension(const std::wstring &file_extension); - /** Sets the directory to start browsing */ - void set_folder(const std::wstring &directory_path); - /** Returns the selected item's path as a string */ - std::string show(); - -protected: - IFileDialog *dialog=nullptr; - DWORD options; - bool error=false; -}; - -class OpenDialog : public CommonDialog { -public: - OpenDialog(const std::wstring &title, unsigned option=0); -}; - -class SaveDialog : public CommonDialog { -public: - SaveDialog(const std::wstring &title, const boost::filesystem::path &file_path="", unsigned option=0); -private: - std::vector extensions; -}; - -CommonDialog::CommonDialog(CLSID type) { - if(CoCreateInstance(type, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&dialog))!=S_OK) { - error=true; - return; + bool add_option(unsigned option) { + if(dialog->SetOptions(options | option)!=S_OK) + return false; + return true; } - if(dialog->GetOptions(&options)!=S_OK) - error=true; -} - -void CommonDialog::set_title(const std::wstring &title) { - if(error) return; - if(dialog->SetTitle(title.c_str())!=S_OK) - error=true; -} - -void CommonDialog::add_option(unsigned option) { - if(error) return; - if(dialog->SetOptions(options | option)!=S_OK) - error=true; -} - -void CommonDialog::set_default_file_extension(const std::wstring &file_extension) { - if(error) return; - if(dialog->SetDefaultExtension(file_extension.c_str())!=S_OK) - error=true; -} - -void CommonDialog::set_folder(const std::wstring &directory_path) { - if(error) return; - std::wstring path=directory_path; - size_t pos=0; - while((pos=path.find(L'/', pos))!=std::wstring::npos) {//TODO: issue bug report on boost::filesystem::path::native on MSYS2 - path.replace(pos, 1, L"\\"); - pos++; + bool set_title(const std::wstring &title) { + if(dialog->SetTitle(title.c_str())!=S_OK) + return false; + return true; } - IShellItem * folder = nullptr; - if(SHCreateItemFromParsingName(path.c_str(), nullptr, IID_PPV_ARGS(&folder))!=S_OK) { - error=true; - return; - } - auto hresult=dialog->SetFolder(folder); - folder->Release(); - if(hresult!=S_OK) - error=true; -} - -std::string CommonDialog::show() { - if(error) return ""; - if(dialog->Show(nullptr)!=S_OK) { - return ""; - } - IShellItem *result = nullptr; - if(dialog->GetResult(&result)!=S_OK) { - result->Release(); - return ""; + /** Sets the extensions the browser can find */ + bool set_default_file_extension(const std::wstring &file_extension) { + if(dialog->SetDefaultExtension(file_extension.c_str())!=S_OK) + return false; + return true; } - LPWSTR str = nullptr; - auto hresult=result->GetDisplayName(SIGDN_FILESYSPATH, &str); - result->Release(); - if(hresult!=S_OK) - return ""; - std::wstring wstr(str); - std::string res(wstr.begin(), wstr.end()); - CoTaskMemFree(str); - return res; -} - -OpenDialog::OpenDialog(const std::wstring &title, unsigned option) : CommonDialog(CLSID_FileOpenDialog) { - set_title(title); - add_option(option); - auto dirs = Singleton::directories->current_path; - set_folder(dirs.empty() ? boost::filesystem::current_path().native() : dirs.native()); -} - -SaveDialog::SaveDialog(const std::wstring &title, const boost::filesystem::path &file_path, unsigned option) : CommonDialog(CLSID_FileSaveDialog) { - set_title(title); - add_option(option); - if(!file_path.empty()) { - set_folder(file_path.parent_path().native()); - if(file_path.has_extension() && file_path.filename()!=file_path.extension()) { - auto extension=(L"*"+file_path.extension().native()).c_str(); - extensions.emplace_back(COMDLG_FILTERSPEC{extension, extension}); - set_default_file_extension(extension); + /** Sets the directory to start browsing */ + bool set_folder(const std::wstring &directory_path) { + std::wstring path=directory_path; + size_t pos=0; + while((pos=path.find(L'/', pos))!=std::wstring::npos) {//TODO: issue bug report on boost::filesystem::path::native on MSYS2 + path.replace(pos, 1, L"\\"); + pos++; } + + IShellItem *folder = nullptr; + if(SHCreateItemFromParsingName(path.c_str(), nullptr, IID_PPV_ARGS(&folder))!=S_OK) + return false; + if(dialog->SetFolder(folder)!=S_OK) + return false; + folder->Release(); + return true; } - else { + + /** Returns the selected item's path as a string */ + std::string open(const std::wstring &title, unsigned option=0) { + if(!init(CLSID_FileOpenDialog)) + return ""; + + if(!set_title(title) || !add_option(option)) + return ""; auto dirs = Singleton::directories->current_path; - set_folder(dirs.empty() ? boost::filesystem::current_path().native() : dirs.native()); + if(!set_folder(dirs.empty() ? boost::filesystem::current_path().native() : dirs.native())) + return ""; + + return show(); } - extensions.emplace_back(COMDLG_FILTERSPEC{L"All files", L"*.*"}); - if(dialog->SetFileTypes(extensions.size(), extensions.data())!=S_OK) { - error=true; - return; + + std::string save(const std::wstring &title, const boost::filesystem::path &file_path="", unsigned option=0) { + if(!init(CLSID_FileSaveDialog)) + return ""; + + if(!set_title(title) || !add_option(option)) + return ""; + std::vector extensions; + if(!file_path.empty()) { + if(!set_folder(file_path.parent_path().native())) + return ""; + if(file_path.has_extension() && file_path.filename()!=file_path.extension()) { + auto extension=(L"*"+file_path.extension().native()).c_str(); + extensions.emplace_back(COMDLG_FILTERSPEC{extension, extension}); + if(!set_default_file_extension(extension)) + return ""; + } + } + else { + auto dirs = Singleton::directories->current_path; + if(!set_folder(dirs.empty() ? boost::filesystem::current_path().native() : dirs.native())) + return ""; + } + extensions.emplace_back(COMDLG_FILTERSPEC{L"All files", L"*.*"}); + if(dialog->SetFileTypes(extensions.size(), extensions.data())!=S_OK) + return ""; + + return show(); } -} + +private: + std::string show() { + if(dialog->Show(nullptr)!=S_OK) + return ""; + IShellItem *result = nullptr; + if(dialog->GetResult(&result)!=S_OK) + return ""; + LPWSTR file_path = nullptr; + auto hresult=result->GetDisplayName(SIGDN_FILESYSPATH, &file_path); + result->Release(); + if(hresult!=S_OK) + return ""; + std::wstring file_path_wstring(file_path); + std::string file_path_string(file_path_wstring.begin(), file_path_wstring.end()); + CoTaskMemFree(file_path); + return file_path_string; + } + + IFileDialog *dialog=nullptr; + DWORD options; +}; std::string Dialog::open_folder() { - return (OpenDialog(L"Open Folder", FOS_PICKFOLDERS)).show(); + return Win32Dialog().open(L"Open Folder", FOS_PICKFOLDERS); } std::string Dialog::new_file() { - return (SaveDialog(L"New File")).show(); + return Win32Dialog().save(L"New File"); } std::string Dialog::new_folder() { - return (OpenDialog(L"New Folder", FOS_PICKFOLDERS)).show(); + return Win32Dialog().open(L"New Folder", FOS_PICKFOLDERS); //TODO: this is not working correctly yet } std::string Dialog::open_file() { - return (OpenDialog(L"Open File")).show(); + return Win32Dialog().open(L"Open File"); } std::string Dialog::save_file_as(const boost::filesystem::path &file_path) { - return (SaveDialog(L"Save File As", file_path)).show(); + return Win32Dialog().save(L"Save File As", file_path); }