зеркало из https://github.com/nextcloud/desktop.git
shell/windows: Use a submenu to include private link actions
Refactor things a bit to be able to reuse some code and clean things up.
This commit is contained in:
Родитель
389499d639
Коммит
7a4daf799a
|
@ -45,7 +45,7 @@ OCClientInterface::ContextMenuInfo OCClientInterface::FetchInfo()
|
|||
if (!socket.Connect(pipename)) {
|
||||
return {};
|
||||
}
|
||||
socket.SendMsg(L"SHARE_MENU_TITLE\n");
|
||||
socket.SendMsg(L"GET_STRINGS\n");
|
||||
|
||||
ContextMenuInfo info;
|
||||
std::wstring response;
|
||||
|
@ -56,9 +56,21 @@ OCClientInterface::ContextMenuInfo OCClientInterface::FetchInfo()
|
|||
wstring responsePath = response.substr(14); // length of REGISTER_PATH
|
||||
info.watchedDirectories.push_back(responsePath);
|
||||
}
|
||||
else if (StringUtil::begins_with(response, wstring(L"SHARE_MENU_TITLE:"))) {
|
||||
info.shareMenuTitle = response.substr(17); // length of SHARE_MENU_TITLE:
|
||||
break; // Stop once we received the last sent request
|
||||
else if (StringUtil::begins_with(response, wstring(L"STRING:"))) {
|
||||
wstring stringName, stringValue;
|
||||
if (!StringUtil::extractChunks(response, stringName, stringValue))
|
||||
continue;
|
||||
if (stringName == L"SHARE_MENU_TITLE")
|
||||
info.shareMenuTitle = move(stringValue);
|
||||
else if (stringName == L"CONTEXT_MENU_TITLE")
|
||||
info.contextMenuTitle = move(stringValue);
|
||||
else if (stringName == L"COPY_PRIVATE_LINK_TITLE")
|
||||
info.copyLinkMenuTitle = move(stringValue);
|
||||
else if (stringName == L"EMAIL_PRIVATE_LINK_TITLE")
|
||||
info.emailLinkMenuTitle = move(stringValue);
|
||||
}
|
||||
else if (StringUtil::begins_with(response, wstring(L"GET_STRINGS:END"))) {
|
||||
break; // Stop once we completely received the last sent request
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -69,7 +81,22 @@ OCClientInterface::ContextMenuInfo OCClientInterface::FetchInfo()
|
|||
return info;
|
||||
}
|
||||
|
||||
void OCClientInterface::ShareObject(const std::wstring &path)
|
||||
void OCClientInterface::RequestShare(const std::wstring &path)
|
||||
{
|
||||
SendRequest(L"SHARE", path);
|
||||
}
|
||||
|
||||
void OCClientInterface::RequestCopyLink(const std::wstring &path)
|
||||
{
|
||||
SendRequest(L"COPY_PRIVATE_LINK", path);
|
||||
}
|
||||
|
||||
void OCClientInterface::RequestEmailLink(const std::wstring &path)
|
||||
{
|
||||
SendRequest(L"EMAIL_PRIVATE_LINK", path);
|
||||
}
|
||||
|
||||
void OCClientInterface::SendRequest(wchar_t *verb, const std::wstring &path)
|
||||
{
|
||||
auto pipename = CommunicationSocket::DefaultPipePath();
|
||||
|
||||
|
@ -82,7 +109,7 @@ void OCClientInterface::ShareObject(const std::wstring &path)
|
|||
}
|
||||
|
||||
wchar_t msg[SOCK_BUFFER] = { 0 };
|
||||
if (SUCCEEDED(StringCchPrintf(msg, SOCK_BUFFER, L"SHARE:%s\n", path.c_str())))
|
||||
if (SUCCEEDED(StringCchPrintf(msg, SOCK_BUFFER, L"%s:%s\n", verb, path.c_str())))
|
||||
{
|
||||
socket.SendMsg(msg);
|
||||
}
|
||||
|
|
|
@ -45,10 +45,19 @@ class OCClientInterface
|
|||
public:
|
||||
struct ContextMenuInfo {
|
||||
std::vector<std::wstring> watchedDirectories;
|
||||
std::wstring contextMenuTitle;
|
||||
std::wstring shareMenuTitle;
|
||||
std::wstring copyLinkMenuTitle;
|
||||
std::wstring emailLinkMenuTitle;
|
||||
};
|
||||
static ContextMenuInfo FetchInfo();
|
||||
static void ShareObject(const std::wstring &path);
|
||||
|
||||
static void RequestShare(const std::wstring &path);
|
||||
static void RequestCopyLink(const std::wstring &path);
|
||||
static void RequestEmailLink(const std::wstring &path);
|
||||
|
||||
private:
|
||||
static void SendRequest(wchar_t *verb, const std::wstring &path);
|
||||
};
|
||||
|
||||
#endif //ABSTRACTSOCKETHANDLER_H
|
||||
|
|
|
@ -25,19 +25,12 @@
|
|||
extern HINSTANCE g_hInst;
|
||||
extern long g_cDllRef;
|
||||
|
||||
#define IDM_SHARE 0
|
||||
|
||||
|
||||
#define IDM_SHARE 0
|
||||
#define IDM_COPYLINK 1
|
||||
#define IDM_EMAILLINK 2
|
||||
|
||||
OCContextMenu::OCContextMenu(void)
|
||||
: m_cRef(1)
|
||||
, m_pszMenuText(L"&Share")
|
||||
, m_pszVerb("ocshare")
|
||||
, m_pwszVerb(L"ocshare")
|
||||
, m_pszVerbCanonicalName("OCShareViaOC")
|
||||
, m_pwszVerbCanonicalName(L"OCShareViaOC")
|
||||
, m_pszVerbHelpText("Share via ownCloud")
|
||||
, m_pwszVerbHelpText(L"Share via ownCloud")
|
||||
{
|
||||
InterlockedIncrement(&g_cDllRef);
|
||||
}
|
||||
|
@ -48,9 +41,19 @@ OCContextMenu::~OCContextMenu(void)
|
|||
}
|
||||
|
||||
|
||||
void OCContextMenu::OnVerbDisplayFileName(HWND hWnd)
|
||||
void OCContextMenu::OnVerbShare(HWND hWnd)
|
||||
{
|
||||
OCClientInterface::ShareObject(std::wstring(m_szSelectedFile));
|
||||
OCClientInterface::RequestShare(std::wstring(m_szSelectedFile));
|
||||
}
|
||||
|
||||
void OCContextMenu::OnVerbCopyLink(HWND hWnd)
|
||||
{
|
||||
OCClientInterface::RequestCopyLink(std::wstring(m_szSelectedFile));
|
||||
}
|
||||
|
||||
void OCContextMenu::OnVerbEmailLink(HWND hWnd)
|
||||
{
|
||||
OCClientInterface::RequestEmailLink(std::wstring(m_szSelectedFile));
|
||||
}
|
||||
|
||||
|
||||
|
@ -164,29 +167,61 @@ IFACEMETHODIMP OCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT
|
|||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
||||
}
|
||||
|
||||
InsertSeperator(hMenu, indexMenu);
|
||||
indexMenu++;
|
||||
InsertSeperator(hMenu, indexMenu++);
|
||||
|
||||
assert(!info.shareMenuTitle.empty());
|
||||
MENUITEMINFO mii = { sizeof(mii) };
|
||||
mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE;
|
||||
mii.wID = idCmdFirst + IDM_SHARE;
|
||||
mii.fType = MFT_STRING;
|
||||
mii.dwTypeData = &info.shareMenuTitle[0];
|
||||
mii.fState = MFS_ENABLED;
|
||||
if (!InsertMenuItem(hMenu, indexMenu, TRUE, &mii))
|
||||
HMENU hSubmenu = CreateMenu();
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
MENUITEMINFO mii = { sizeof(mii) };
|
||||
mii.fMask = MIIM_SUBMENU | MIIM_FTYPE | MIIM_STRING;
|
||||
mii.hSubMenu = hSubmenu;
|
||||
mii.fType = MFT_STRING;
|
||||
mii.dwTypeData = &info.contextMenuTitle[0];
|
||||
|
||||
indexMenu++;
|
||||
InsertSeperator(hMenu, indexMenu);
|
||||
if (!InsertMenuItem(hMenu, indexMenu++, TRUE, &mii))
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
InsertSeperator(hMenu, indexMenu++);
|
||||
|
||||
UINT indexSubMenu = 0;
|
||||
{
|
||||
assert(!info.shareMenuTitle.empty());
|
||||
MENUITEMINFO mii = { sizeof(mii) };
|
||||
mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING;
|
||||
mii.wID = idCmdFirst + IDM_SHARE;
|
||||
mii.fType = MFT_STRING;
|
||||
mii.dwTypeData = &info.shareMenuTitle[0];
|
||||
|
||||
if (!InsertMenuItem(hSubmenu, indexSubMenu++, TRUE, &mii))
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
{
|
||||
assert(!info.copyLinkMenuTitle.empty());
|
||||
MENUITEMINFO mii = { sizeof(mii) };
|
||||
mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING;
|
||||
mii.wID = idCmdFirst + IDM_COPYLINK;
|
||||
mii.fType = MFT_STRING;
|
||||
mii.dwTypeData = &info.copyLinkMenuTitle[0];
|
||||
|
||||
if (!InsertMenuItem(hSubmenu, indexSubMenu++, TRUE, &mii))
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
{
|
||||
assert(!info.emailLinkMenuTitle.empty());
|
||||
MENUITEMINFO mii = { sizeof(mii) };
|
||||
mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING;
|
||||
mii.wID = idCmdFirst + IDM_EMAILLINK;
|
||||
mii.fType = MFT_STRING;
|
||||
mii.dwTypeData = &info.emailLinkMenuTitle[0];
|
||||
|
||||
if (!InsertMenuItem(hSubmenu, indexSubMenu++, TRUE, &mii))
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
|
||||
// Return an HRESULT value with the severity set to SEVERITY_SUCCESS.
|
||||
// Set the code value to the offset of the largest command identifier
|
||||
// that was assigned, plus one (1).
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_SHARE + 1));
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_EMAILLINK + 1));
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
|
||||
|
@ -197,12 +232,16 @@ IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
|
|||
if (HIWORD(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW))
|
||||
{
|
||||
// Is the verb supported by this context menu extension?
|
||||
if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, m_pwszVerb) == 0)
|
||||
{
|
||||
OnVerbDisplayFileName(pici->hwnd);
|
||||
if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, L"ocshare") == 0) {
|
||||
OnVerbShare(pici->hwnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
else if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, L"occopylink") == 0) {
|
||||
OnVerbCopyLink(pici->hwnd);
|
||||
}
|
||||
else if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, L"ocemaillink") == 0) {
|
||||
OnVerbEmailLink(pici->hwnd);
|
||||
}
|
||||
else {
|
||||
// If the verb is not recognized by the context menu handler, it
|
||||
// must return E_FAIL to allow it to be passed on to the other
|
||||
// context menu handlers that might implement that verb.
|
||||
|
@ -216,12 +255,16 @@ IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
|
|||
{
|
||||
// Is the command identifier offset supported by this context menu
|
||||
// extension?
|
||||
if (LOWORD(pici->lpVerb) == IDM_SHARE)
|
||||
{
|
||||
OnVerbDisplayFileName(pici->hwnd);
|
||||
if (LOWORD(pici->lpVerb) == IDM_SHARE) {
|
||||
OnVerbShare(pici->hwnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
else if (LOWORD(pici->lpVerb) == IDM_COPYLINK) {
|
||||
OnVerbCopyLink(pici->hwnd);
|
||||
}
|
||||
else if (LOWORD(pici->lpVerb) == IDM_EMAILLINK) {
|
||||
OnVerbEmailLink(pici->hwnd);
|
||||
}
|
||||
else {
|
||||
// If the verb is not recognized by the context menu handler, it
|
||||
// must return E_FAIL to allow it to be passed on to the other
|
||||
// context menu handlers that might implement that verb.
|
||||
|
@ -237,31 +280,33 @@ IFACEMETHODIMP OCContextMenu::GetCommandString(UINT_PTR idCommand,
|
|||
{
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
|
||||
if (idCommand == IDM_SHARE)
|
||||
{
|
||||
switch (uFlags)
|
||||
{
|
||||
case GCS_HELPTEXTW:
|
||||
// Only useful for pre-Vista versions of Windows that have a
|
||||
// Status bar.
|
||||
hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax,
|
||||
m_pwszVerbHelpText);
|
||||
break;
|
||||
|
||||
case GCS_VERBW:
|
||||
// GCS_VERBW is an optional feature that enables a caller to
|
||||
// discover the canonical name for the verb passed in through
|
||||
switch (idCommand) {
|
||||
case IDM_SHARE:
|
||||
if (uFlags == GCS_VERBW) {
|
||||
// GCS_VERBW is an optional feature that enables a caller to
|
||||
// discover the canonical name for the verb passed in through
|
||||
// idCommand.
|
||||
hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax,
|
||||
m_pwszVerbCanonicalName);
|
||||
break;
|
||||
|
||||
default:
|
||||
hr = S_OK;
|
||||
L"OCShareViaOC");
|
||||
}
|
||||
break;
|
||||
case IDM_COPYLINK:
|
||||
if (uFlags == GCS_VERBW) {
|
||||
hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax,
|
||||
L"OCCopyLink");
|
||||
}
|
||||
break;
|
||||
case IDM_EMAILLINK:
|
||||
if (uFlags == GCS_VERBW) {
|
||||
hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax,
|
||||
L"OCEmailLink");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// If the command (idCommand) is not supported by this context menu
|
||||
// If the idCommand or uFlags is not supported by this context menu
|
||||
// extension handler, return E_INVALIDARG.
|
||||
|
||||
return hr;
|
||||
|
|
|
@ -46,8 +46,10 @@ private:
|
|||
// The name of the selected file.
|
||||
wchar_t m_szSelectedFile[MAX_PATH];
|
||||
|
||||
// The method that handles the "display" verb.
|
||||
void OnVerbDisplayFileName(HWND hWnd);
|
||||
// The method that handles the "ocshare" verb.
|
||||
void OnVerbShare(HWND hWnd);
|
||||
void OnVerbCopyLink(HWND hWnd);
|
||||
void OnVerbEmailLink(HWND hWnd);
|
||||
|
||||
PWSTR m_pszMenuText;
|
||||
PCSTR m_pszVerb;
|
||||
|
|
|
@ -111,17 +111,10 @@ void RemotePathChecker::workerThreadLoop()
|
|||
} else if (StringUtil::begins_with(response, wstring(L"STATUS:")) ||
|
||||
StringUtil::begins_with(response, wstring(L"BROADCAST:"))) {
|
||||
|
||||
auto statusBegin = response.find(L':', 0);
|
||||
assert(statusBegin != std::wstring::npos);
|
||||
|
||||
auto statusEnd = response.find(L':', statusBegin + 1);
|
||||
if (statusEnd == std::wstring::npos) {
|
||||
// the command do not contains two colon?
|
||||
wstring responseStatus, responsePath;
|
||||
if (!StringUtil::extractChunks(response, responseStatus, responsePath))
|
||||
continue;
|
||||
}
|
||||
|
||||
auto responseStatus = response.substr(statusBegin+1, statusEnd - statusBegin-1);
|
||||
auto responsePath = response.substr(statusEnd+1);
|
||||
auto state = _StrToFileState(responseStatus);
|
||||
bool wasAsked = asked.erase(responsePath) > 0;
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
class __declspec(dllexport) StringUtil {
|
||||
public:
|
||||
|
@ -44,6 +45,22 @@ public:
|
|||
return (childLength == parentLength || childLength > parentLength && (child[parentLength] == L'\\' || child[parentLength - 1] == L'\\'))
|
||||
&& wcsncmp(child, parent, parentLength) == 0;
|
||||
}
|
||||
|
||||
static bool extractChunks(const std::wstring &source, std::wstring &secondChunk, std::wstring &thirdChunk) {
|
||||
auto statusBegin = source.find(L':', 0);
|
||||
assert(statusBegin != std::wstring::npos);
|
||||
|
||||
auto statusEnd = source.find(L':', statusBegin + 1);
|
||||
if (statusEnd == std::wstring::npos) {
|
||||
// the command do not contains two colon?
|
||||
return false;
|
||||
}
|
||||
|
||||
// Assume the caller extracted the chunk before the first colon.
|
||||
secondChunk = source.substr(statusBegin + 1, statusEnd - statusBegin - 1);
|
||||
thirdChunk = source.substr(statusEnd + 1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // STRINGUTIL_H
|
||||
|
|
Загрузка…
Ссылка в новой задаче