Skip to content

Commit

Permalink
Merge pull request #979 from vktr/feature/better-open-file-dialog
Browse files Browse the repository at this point in the history
Use the Common Item Dialog to support more files being opened
  • Loading branch information
vktr committed Oct 16, 2020
2 parents f181624 + ffa30ef commit 3b20888
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 22 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,9 @@ add_executable(
src/picotorrent/ui/torrentfilelistview
src/picotorrent/ui/torrentlistview
src/picotorrent/ui/translator

# Win32 specific stuff
src/picotorrent/ui/win32/openfiledialog
)

target_compile_definitions(
Expand Down Expand Up @@ -249,6 +252,7 @@ target_link_libraries(
crypt32
iphlpapi
legacy_stdio_definitions
propsys
shlwapi
wininet
winhttp
Expand Down
40 changes: 18 additions & 22 deletions src/picotorrent/ui/mainframe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
#include "torrentlistview.hpp"
#include "translator.hpp"

#include "win32/openfiledialog.hpp"

namespace fs = std::filesystem;
using pt::UI::MainFrame;

Expand Down Expand Up @@ -648,33 +650,27 @@ void MainFrame::OnFileAddMagnetLink(wxCommandEvent&)

void MainFrame::OnFileAddTorrent(wxCommandEvent&)
{
wxFileDialog openDialog(
this,
i18n("add_torrent_s"),
wxEmptyString,
wxEmptyString,
"Torrent files (*.torrent)|*.torrent|All files (*.*)|*.*",
wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE);

if (openDialog.ShowModal() != wxID_OK)
Win32::OpenFileDialog ofd;

ofd.SetFileTypes({
std::make_tuple(L"Torrent files", L"*.torrent"),
std::make_tuple(L"All files (*.*)", L"*.*")
});

ofd.SetOption(Win32::OpenFileDialog::Option::Multi);
ofd.SetTitle(i18n("add_torrent_s"));
ofd.Show(this);

std::vector<std::string> files;
ofd.GetFiles(files);

if (files.empty())
{
return;
}

wxArrayString paths;
openDialog.GetPaths(paths);

std::vector<std::string> converted;
std::for_each(
paths.begin(),
paths.end(),
[&converted](wxString const& str)
{
converted.push_back(Utils::toStdString(str.wc_str()));
});

std::vector<lt::add_torrent_params> params;
this->ParseTorrentFiles(params, converted);
this->ParseTorrentFiles(params, files);
this->AddTorrents(params);
}

Expand Down
104 changes: 104 additions & 0 deletions src/picotorrent/ui/win32/openfiledialog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#include "openfiledialog.hpp"

#define STRICT_TYPED_ITEMIDS
#include <shlobj.h>
#include <objbase.h> // For COM headers
#include <shobjidl.h> // for IFileDialogEvents and IFileDialogControlEvents
#include <shlwapi.h>
#include <knownfolders.h> // for KnownFolder APIs/datatypes/function headers
#include <propvarutil.h> // for PROPVAR-related functions
#include <propkey.h> // for the Property key APIs/datatypes
#include <propidl.h> // for the Property System APIs
#include <strsafe.h> // for StringCchPrintfW
#include <shtypes.h> // for COMDLG_FILTERSPEC

#include <string>

#include "../../core/utils.hpp"

using pt::UI::Win32::OpenFileDialog;

OpenFileDialog::OpenFileDialog()
: m_wrappedDialog(nullptr)
{
if (!SUCCEEDED(CoCreateInstance(CLSID_FileOpenDialog,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&m_wrappedDialog))))
{
throw std::exception();
}
}

OpenFileDialog::~OpenFileDialog()
{
m_wrappedDialog->Release();
}

void OpenFileDialog::GetFiles(std::vector<std::string>& files)
{
IShellItemArray* results = nullptr;

if (!SUCCEEDED(m_wrappedDialog->GetResults(&results))
|| results == nullptr)
{
return;
}

DWORD count;
results->GetCount(&count);

files.reserve(count);

for (size_t i = 0; i < count; i++)
{
PWSTR path = nullptr;

IShellItem* item;
results->GetItemAt(i, &item);

if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &path))
&& path != nullptr)
{
files.push_back(
Utils::toStdString(path));
CoTaskMemFree(path);
}

item->Release();
}

results->Release();
}

void OpenFileDialog::SetFileTypes(std::vector<std::tuple<std::wstring, std::wstring>> const& types)
{
std::vector<COMDLG_FILTERSPEC> spec;

for (auto const& t : types)
{
spec.push_back({
std::get<0>(t).c_str(),
std::get<1>(t).c_str() });
}

m_wrappedDialog->SetFileTypes(spec.size(), spec.data());
}

void OpenFileDialog::SetOption(OpenFileDialog::Option option)
{
DWORD dwOptions;
m_wrappedDialog->GetOptions(&dwOptions);
if (option == Option::Multi) { dwOptions |= FOS_ALLOWMULTISELECT; }
m_wrappedDialog->SetOptions(dwOptions);
}

void OpenFileDialog::SetTitle(std::wstring const& title)
{
m_wrappedDialog->SetTitle(title.c_str());
}

void OpenFileDialog::Show(wxWindow* parent)
{
m_wrappedDialog->Show(parent->GetHWND());
}
37 changes: 37 additions & 0 deletions src/picotorrent/ui/win32/openfiledialog.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif

#include <string>
#include <tuple>
#include <vector>

struct IFileOpenDialog;

namespace pt::UI::Win32
{
class OpenFileDialog
{
public:
enum class Option
{
Multi
};

OpenFileDialog();
~OpenFileDialog();

void GetFiles(std::vector<std::string>& files);

void SetFileTypes(std::vector<std::tuple<std::wstring, std::wstring>> const& types);
void SetOption(Option opt);
void SetTitle(std::wstring const& title);
void Show(wxWindow* parent);

private:
IFileOpenDialog* m_wrappedDialog;
};
}

0 comments on commit 3b20888

Please sign in to comment.