diff options
| author | isanae <14251494+isanae@users.noreply.github.com> | 2020-01-22 02:54:29 -0500 |
|---|---|---|
| committer | isanae <14251494+isanae@users.noreply.github.com> | 2020-02-04 03:33:22 -0500 |
| commit | 2a0e78e3cf0c1106a1fb7e470148f6e0b093b2b1 (patch) | |
| tree | aa0ce69d111a22d232dc1589fa707855bddc53b0 /src | |
| parent | 6005da618775d545c664371f53571a75eacab7f2 (diff) | |
fixed bad path for alternate origins
finished ShellMenuCollection, had to split a bunch of things
Diffstat (limited to 'src')
| -rw-r--r-- | src/envshell.cpp | 499 | ||||
| -rw-r--r-- | src/envshell.h | 36 | ||||
| -rw-r--r-- | src/filetree.cpp | 60 | ||||
| -rw-r--r-- | src/shared/directoryentry.cpp | 14 | ||||
| -rw-r--r-- | src/shared/directoryentry.h | 7 |
5 files changed, 358 insertions, 258 deletions
diff --git a/src/envshell.cpp b/src/envshell.cpp index 58948d31..e01bb804 100644 --- a/src/envshell.cpp +++ b/src/envshell.cpp @@ -62,17 +62,12 @@ struct IdlsFreer class WndProcFilter : public QAbstractNativeEventFilter { public: - WndProcFilter(QMainWindow* mw, IContextMenu* cm) - : m_mw(mw), m_cm(cm), m_cm2(nullptr), m_cm3(nullptr) - { - createInterfaces(); - } + using function_type = std::function< + bool (HWND hwnd, UINT m, WPARAM wp, LPARAM lp, LRESULT* out)>; - ~WndProcFilter() + WndProcFilter(function_type f) + : m_f(std::move(f)) { - if (auto* sb=m_mw->statusBar()) { - sb->clearMessage(); - } } bool nativeEventFilter(const QByteArray& type, void* m, long* lresultOut) override @@ -82,194 +77,116 @@ public: return false; } - if (msg->message == WM_MENUSELECT) { - HANDLE_WM_MENUSELECT(msg->hwnd, msg->wParam, msg->lParam, onMenuSelect); - return true; - } - - if (m_cm3) { - LRESULT lresult = 0; + LRESULT lr = 0; - const auto r = m_cm3->HandleMenuMsg2( - msg->message, msg->wParam, msg->lParam, &lresult); + const bool r = m_f(msg->hwnd, msg->message, msg->wParam, msg->lParam, &lr); - if (SUCCEEDED(r)) { - if (lresultOut) { - *lresultOut = lresult; - } - - return true; - } + if (lresultOut) { + *lresultOut = lr; } - if (m_cm2) { - const auto r = m_cm2->HandleMenuMsg( - msg->message, msg->wParam, msg->lParam); - - if (SUCCEEDED(r)) { - if (lresultOut) { - *lresultOut = 0; - } - - return true; - } - } - - return false; + return r; } private: - QMainWindow* m_mw; - IContextMenu* m_cm; - COMPtr<IContextMenu2> m_cm2; - COMPtr<IContextMenu3> m_cm3; - - void createInterfaces() - { - if (!m_cm) { - return; - } - - IContextMenu2* cm2 = nullptr; - if (SUCCEEDED(m_cm->QueryInterface(IID_IContextMenu2, (void**)&cm2))) { - m_cm2.reset(cm2); - } - - IContextMenu3* cm3 = nullptr; - if (SUCCEEDED(m_cm->QueryInterface(IID_IContextMenu3, (void**)&cm3))) { - m_cm3.reset(cm3); - } - } + function_type m_f; +}; - // adapted from - // https://devblogs.microsoft.com/oldnewthing/20040928-00/?p=37723 - // - void onMenuSelect( - HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags) - { - if (m_cm && item >= QCM_FIRST && item <= QCM_LAST) { - WCHAR szBuf[MAX_PATH]; - const auto r = IContextMenu_GetCommandString( - m_cm, item - QCM_FIRST, GCS_HELPTEXTW, NULL, szBuf, MAX_PATH); - if (FAILED(r)) { - lstrcpynW(szBuf, L"No help available.", MAX_PATH); - } - if (m_mw) { - if (auto* sb=m_mw->statusBar()) { - sb->showMessage(QString::fromWCharArray(szBuf)); - } - } - } +HWND getHWND(QMainWindow* mw) +{ + if (mw) { + return (HWND)mw->winId(); + } else { + return 0; } +} - // adapted from - // https://devblogs.microsoft.com/oldnewthing/20040928-00/?p=37723 - // - HRESULT IContextMenu_GetCommandString( - IContextMenu *pcm, UINT_PTR idCmd, UINT uFlags, - UINT *pwReserved, LPWSTR pszName, UINT cchMax) - { - // Callers are expected to be using Unicode. - if (!(uFlags & GCS_UNICODE)) { - return E_INVALIDARG; - } +// adapted from +// https://devblogs.microsoft.com/oldnewthing/20040928-00/?p=37723 +// +HRESULT IContextMenu_GetCommandString( + IContextMenu *pcm, UINT_PTR idCmd, UINT uFlags, + UINT *pwReserved, LPWSTR pszName, UINT cchMax) +{ + // Callers are expected to be using Unicode. + if (!(uFlags & GCS_UNICODE)) { + return E_INVALIDARG; + } - // Some context menu handlers have off-by-one bugs and will - // overflow the output buffer. Let’s artificially reduce the - // buffer size so a one-character overflow won’t corrupt memory. - if (cchMax <= 1) { - return E_FAIL; - } + // Some context menu handlers have off-by-one bugs and will + // overflow the output buffer. Let’s artificially reduce the + // buffer size so a one-character overflow won’t corrupt memory. + if (cchMax <= 1) { + return E_FAIL; + } - cchMax--; + cchMax--; - // First try the Unicode message. Preset the output buffer - // with a known value because some handlers return S_OK without - // doing anything. - pszName[0] = L'\0'; + // First try the Unicode message. Preset the output buffer + // with a known value because some handlers return S_OK without + // doing anything. + pszName[0] = L'\0'; - HRESULT hr = pcm->GetCommandString( - idCmd, uFlags, pwReserved, (LPSTR)pszName, cchMax); + HRESULT hr = pcm->GetCommandString( + idCmd, uFlags, pwReserved, (LPSTR)pszName, cchMax); - if (SUCCEEDED(hr) && pszName[0] == L'\0') { - // Rats, a buggy IContextMenu handler that returned success - // even though it failed. - hr = E_NOTIMPL; - } + if (SUCCEEDED(hr) && pszName[0] == L'\0') { + // Rats, a buggy IContextMenu handler that returned success + // even though it failed. + hr = E_NOTIMPL; + } - if (FAILED(hr)) { - // try again with ANSI – pad the buffer with one extra character - // to compensate for context menu handlers that overflow by - // one character. - LPSTR pszAnsi = (LPSTR)LocalAlloc( - LMEM_FIXED, (cchMax + 1) * sizeof(CHAR)); + if (FAILED(hr)) { + // try again with ANSI – pad the buffer with one extra character + // to compensate for context menu handlers that overflow by + // one character. + LPSTR pszAnsi = (LPSTR)LocalAlloc( + LMEM_FIXED, (cchMax + 1) * sizeof(CHAR)); - if (pszAnsi) { - pszAnsi[0] = '\0'; + if (pszAnsi) { + pszAnsi[0] = '\0'; - hr = pcm->GetCommandString( - idCmd, uFlags & ~GCS_UNICODE, pwReserved, pszAnsi, cchMax); + hr = pcm->GetCommandString( + idCmd, uFlags & ~GCS_UNICODE, pwReserved, pszAnsi, cchMax); - if (SUCCEEDED(hr) && pszAnsi[0] == '\0') { - // Rats, a buggy IContextMenu handler that returned success - // even though it failed. - hr = E_NOTIMPL; - } + if (SUCCEEDED(hr) && pszAnsi[0] == '\0') { + // Rats, a buggy IContextMenu handler that returned success + // even though it failed. + hr = E_NOTIMPL; + } - if (SUCCEEDED(hr)) { - if (MultiByteToWideChar(CP_ACP, 0, pszAnsi, -1, pszName, cchMax) == 0) { - hr = E_FAIL; - } + if (SUCCEEDED(hr)) { + if (MultiByteToWideChar(CP_ACP, 0, pszAnsi, -1, pszName, cchMax) == 0) { + hr = E_FAIL; } - - LocalFree(pszAnsi); - - } else { - hr = E_OUTOFMEMORY; } - } - - return hr; - } -}; + LocalFree(pszAnsi); -QMainWindow* getMainWindow(QWidget* w) -{ - QWidget* p = w; - - while (p) { - if (auto* mw=dynamic_cast<QMainWindow*>(p)) { - return mw; + } else { + hr = E_OUTOFMEMORY; } - - p = p->parentWidget(); } - return nullptr; + return hr; } -HWND getHWND(QMainWindow* mw) + +ShellMenu::ShellMenu(QMainWindow* mw) + : m_mw(mw) { - if (mw) { - return (HWND)mw->winId(); - } else { - return 0; - } } - void ShellMenu::addFile(QFileInfo fi) { m_files.emplace_back(std::move(fi)); } -void ShellMenu::exec(QWidget* parent, const QPoint& pos) +void ShellMenu::exec(const QPoint& pos) { - auto* mw = getMainWindow(parent); HMENU menu = getMenu(); if (!menu) { return; @@ -277,12 +194,29 @@ void ShellMenu::exec(QWidget* parent, const QPoint& pos) try { - const int cmd = runMenu(mw, m_cm.get(), m_menu.get(), pos); + const auto hwnd = getHWND(m_mw); + + auto filter = std::make_unique<WndProcFilter>( + [&](HWND h, UINT m, WPARAM wp, LPARAM lp, LRESULT* out) { + return wndProc(h, m, wp, lp, out); + }); + + QCoreApplication::instance()->installNativeEventFilter(filter.get()); + + const int cmd = TrackPopupMenuEx( + menu, TPM_RETURNCMD, pos.x(), pos.y(), hwnd, nullptr); + + if (m_mw) { + if (auto* sb=m_mw->statusBar()) { + sb->clearMessage(); + } + } + if (cmd <= 0) { return; } - invoke(mw, pos, cmd - QCM_FIRST, m_cm.get()); + invoke(pos, cmd - QCM_FIRST); } catch(MenuFailed& e) { @@ -301,13 +235,67 @@ void ShellMenu::exec(QWidget* parent, const QPoint& pos) HMENU ShellMenu::getMenu() { if (!m_menu) { - createMenu(); + create(); } return m_menu.get(); } -void ShellMenu::createMenu() +bool ShellMenu::wndProc(HWND h, UINT m, WPARAM wp, LPARAM lp, LRESULT* out) +{ + if (m == WM_MENUSELECT) { + HANDLE_WM_MENUSELECT(h, wp, lp, onMenuSelect); + return true; + } + + if (m_cm3) { + const auto r = m_cm3->HandleMenuMsg2(m, wp, lp, out); + + if (SUCCEEDED(r)) { + return true; + } + } + + if (m_cm2) { + const auto r = m_cm2->HandleMenuMsg(m, wp, lp); + + if (SUCCEEDED(r)) { + if (out) { + *out = 0; + } + + return true; + } + } + + return false; +} + +// adapted from +// https://devblogs.microsoft.com/oldnewthing/20040928-00/?p=37723 +// +void ShellMenu::onMenuSelect( + HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags) +{ + if (m_cm && item >= QCM_FIRST && item <= QCM_LAST) { + WCHAR szBuf[MAX_PATH]; + + const auto r = IContextMenu_GetCommandString( + m_cm.get(), item - QCM_FIRST, GCS_HELPTEXTW, NULL, szBuf, MAX_PATH); + + if (FAILED(r)) { + lstrcpynW(szBuf, L"No help available.", MAX_PATH); + } + + if (m_mw) { + if (auto* sb=m_mw->statusBar()) { + sb->showMessage(QString::fromWCharArray(szBuf)); + } + } + } +} + +void ShellMenu::create() { if (m_files.empty()) { log::warn("showShellMenu(): no files given"); @@ -326,8 +314,9 @@ void ShellMenu::createMenu() IdlsFreer freer(idls); auto array = createItemArray(idls); - m_cm = createContextMenu(array.get()); - m_menu = createMenu(m_cm.get()); + + createContextMenu(array.get()); + createPopupMenu(m_cm.get()); } catch(DummyMenu& dm) { @@ -375,44 +364,6 @@ HMenuPtr ShellMenu::createDummyMenu(const QString& what) } } -COMPtr<IShellItem> ShellMenu::createShellItem(const std::wstring& path) -{ - IShellItem* item = nullptr; - - auto r = SHCreateItemFromParsingName( - path.c_str(), nullptr, IID_IShellItem, (void**)&item); - - if (FAILED(r)) { - throw MenuFailed(r, "SHCreateItemFromParsingName failed"); - } - - return COMPtr<IShellItem>(item); -} - -COMPtr<IPersistIDList> ShellMenu::getPersistIDList(IShellItem* item) -{ - IPersistIDList* idl = nullptr; - auto r = item->QueryInterface(IID_IPersistIDList, (void**)&idl); - - if (FAILED(r)) { - throw MenuFailed(r, "QueryInterface IID_IPersistIDList failed"); - } - - return COMPtr<IPersistIDList>(idl); -} - -CoTaskMemPtr<LPITEMIDLIST> ShellMenu::getIDList(IPersistIDList* pidlist) -{ - LPITEMIDLIST absIdl = nullptr; - auto r = pidlist->GetIDList(&absIdl); - - if (FAILED(r)) { - throw MenuFailed(r, "GetIDList failed"); - } - - return CoTaskMemPtr<LPITEMIDLIST>(absIdl); -} - std::vector<LPCITEMIDLIST> ShellMenu::createIdls( const std::vector<QFileInfo>& files) { @@ -455,7 +406,7 @@ COMPtr<IShellItemArray> ShellMenu::createItemArray( return COMPtr<IShellItemArray>(array); } -COMPtr<IContextMenu> ShellMenu::createContextMenu(IShellItemArray* array) +void ShellMenu::createContextMenu(IShellItemArray* array) { IContextMenu* cm = nullptr; @@ -466,10 +417,24 @@ COMPtr<IContextMenu> ShellMenu::createContextMenu(IShellItemArray* array) throw MenuFailed(r, "BindToHandler failed"); } - return COMPtr<IContextMenu>(cm); + m_cm.reset(cm); + + { + IContextMenu2* cm2 = nullptr; + if (SUCCEEDED(m_cm->QueryInterface(IID_IContextMenu2, (void**)&cm2))) { + m_cm2.reset(cm2); + } + } + + { + IContextMenu3* cm3 = nullptr; + if (SUCCEEDED(m_cm->QueryInterface(IID_IContextMenu3, (void**)&cm3))) { + m_cm3.reset(cm3); + } + } } -HMenuPtr ShellMenu::createMenu(IContextMenu* cm) +void ShellMenu::createPopupMenu(IContextMenu* cm) { HMENU hmenu = CreatePopupMenu(); if (!hmenu) { @@ -484,24 +449,50 @@ HMenuPtr ShellMenu::createMenu(IContextMenu* cm) throw MenuFailed(r, "QueryContextMenu failed"); } - return HMenuPtr(hmenu); + m_menu.reset(hmenu); } -int ShellMenu::runMenu( - QMainWindow* mw, IContextMenu* cm, HMENU menu, const QPoint& p) +COMPtr<IShellItem> ShellMenu::createShellItem(const std::wstring& path) { - const auto hwnd = getHWND(mw); + IShellItem* item = nullptr; - auto filter = std::make_unique<WndProcFilter>(mw, cm); - QCoreApplication::instance()->installNativeEventFilter(filter.get()); + auto r = SHCreateItemFromParsingName( + path.c_str(), nullptr, IID_IShellItem, (void**)&item); + + if (FAILED(r)) { + throw MenuFailed(r, "SHCreateItemFromParsingName failed"); + } + + return COMPtr<IShellItem>(item); +} + +COMPtr<IPersistIDList> ShellMenu::getPersistIDList(IShellItem* item) +{ + IPersistIDList* idl = nullptr; + auto r = item->QueryInterface(IID_IPersistIDList, (void**)&idl); + + if (FAILED(r)) { + throw MenuFailed(r, "QueryInterface IID_IPersistIDList failed"); + } - return TrackPopupMenuEx(menu, TPM_RETURNCMD, p.x(), p.y(), hwnd, nullptr); + return COMPtr<IPersistIDList>(idl); } -void ShellMenu::invoke( - QMainWindow* mw, const QPoint& p, int cmd, IContextMenu* cm) +CoTaskMemPtr<LPITEMIDLIST> ShellMenu::getIDList(IPersistIDList* pidlist) { - const auto hwnd = getHWND(mw); + LPITEMIDLIST absIdl = nullptr; + auto r = pidlist->GetIDList(&absIdl); + + if (FAILED(r)) { + throw MenuFailed(r, "GetIDList failed"); + } + + return CoTaskMemPtr<LPITEMIDLIST>(absIdl); +} + +void ShellMenu::invoke(const QPoint& p, int cmd) +{ + const auto hwnd = getHWND(m_mw); CMINVOKECOMMANDINFOEX info = {}; @@ -525,7 +516,7 @@ void ShellMenu::invoke( info.fMask |= CMIC_MASK_CONTROL_DOWN; } - const auto r = cm->InvokeCommand((CMINVOKECOMMANDINFO*)&info); + const auto r = m_cm->InvokeCommand((CMINVOKECOMMANDINFO*)&info); if (FAILED(r)) { throw MenuFailed(r, fmt::format("InvokeCommand failed, verb={}", cmd)); @@ -533,12 +524,17 @@ void ShellMenu::invoke( } +ShellMenuCollection::ShellMenuCollection(QMainWindow* mw) + : m_mw(mw), m_active(nullptr) +{ +} + void ShellMenuCollection::add(QString name, ShellMenu m) { m_menus.push_back({name, std::move(m)}); } -void ShellMenuCollection::exec(QWidget* parent, const QPoint& pos) +void ShellMenuCollection::exec(const QPoint& pos) { HMENU menu = ::CreatePopupMenu(); if (!menu) { @@ -572,10 +568,77 @@ void ShellMenuCollection::exec(QWidget* parent, const QPoint& pos) } } - auto* mw = getMainWindow(parent); - auto hwnd = getHWND(mw); + auto hwnd = getHWND(m_mw); + + auto filter = std::make_unique<WndProcFilter>( + [&](HWND h, UINT m, WPARAM wp, LPARAM lp, LRESULT* out) { + return wndProc(h, m, wp, lp, out); + }); + + QCoreApplication::instance()->installNativeEventFilter(filter.get()); + + const int cmd = TrackPopupMenuEx( + menu, TPM_RETURNCMD, pos.x(), pos.y(), hwnd, nullptr); + + if (m_mw) { + if (auto* sb=m_mw->statusBar()) { + sb->clearMessage(); + } + } + + if (cmd <= 0) { + return; + } + + if (!m_active) { + log::debug("SMC: command {} selected without active submenu"); + return; + } + + const auto realCmd = cmd - QCM_FIRST; + + log::debug("SMC: invoking {} on {}", realCmd, m_active->name); + m_active->menu.invoke(pos, realCmd); +} + +bool ShellMenuCollection::wndProc( + HWND h, UINT m, WPARAM wp, LPARAM lp, LRESULT* out) +{ + if (m == WM_MENUSELECT) { + auto* oldActive = m_active; + m_active = nullptr; - TrackPopupMenuEx(menu, TPM_RETURNCMD, pos.x(), pos.y(), hwnd, nullptr); + HANDLE_WM_MENUSELECT(h, wp, lp, onMenuSelect); + + if (!m_active && oldActive) { + // this was not a top level, forward to active + m_active = oldActive; + } else if (m_active && m_active == oldActive) { + // same top level menu was selected twice, ignore + return true; + } else if (m_active && m_active != oldActive) { + // new top level selected + log::debug("SMC: switching to {}", m_active->name); + } + } + + if (!m_active) { + // no active menu, forward it to the default handler + return false; + } + + return m_active->menu.wndProc(h, m, wp, lp, out); +} + +void ShellMenuCollection::onMenuSelect( + HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags) +{ + for (auto&& m : m_menus) { + if (m.menu.getMenu() == hmenuPopup) { + m_active = &m; + break; + } + } } } // namespace diff --git a/src/envshell.h b/src/envshell.h index 79dce552..52125a5c 100644 --- a/src/envshell.h +++ b/src/envshell.h @@ -11,7 +11,7 @@ namespace env class ShellMenu { public: - ShellMenu() = default; + ShellMenu(QMainWindow* mw); // noncopyable ShellMenu(const ShellMenu&) = delete; @@ -21,35 +21,44 @@ public: void addFile(QFileInfo fi); - void exec(QWidget* parent, const QPoint& pos); + void exec(const QPoint& pos); HMENU getMenu(); + bool wndProc(HWND hwnd, UINT m, WPARAM wp, LPARAM lp, LRESULT* out); + void invoke(const QPoint& p, int cmd); private: + QMainWindow* m_mw; std::vector<QFileInfo> m_files; COMPtr<IContextMenu> m_cm; + COMPtr<IContextMenu2> m_cm2; + COMPtr<IContextMenu3> m_cm3; HMenuPtr m_menu; - void createMenu(); + void create(); + + std::vector<LPCITEMIDLIST> createIdls(const std::vector<QFileInfo>& files); + COMPtr<IShellItemArray> createItemArray(std::vector<LPCITEMIDLIST>& idls); + + void createContextMenu(IShellItemArray* array); + void createPopupMenu(IContextMenu* cm); COMPtr<IShellItem> createShellItem(const std::wstring& path); COMPtr<IPersistIDList> getPersistIDList(IShellItem* item); CoTaskMemPtr<LPITEMIDLIST> getIDList(IPersistIDList* pidlist); - std::vector<LPCITEMIDLIST> createIdls(const std::vector<QFileInfo>& files); - COMPtr<IShellItemArray> createItemArray(std::vector<LPCITEMIDLIST>& idls); - COMPtr<IContextMenu> createContextMenu(IShellItemArray* array); - HMenuPtr createMenu(IContextMenu* cm); HMenuPtr createDummyMenu(const QString& what); - int runMenu(QMainWindow* mw, IContextMenu* cm, HMENU menu, const QPoint& p); - void invoke(QMainWindow* mw, const QPoint& p, int cmd, IContextMenu* cm); + void onMenuSelect( + HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags); }; class ShellMenuCollection { public: + ShellMenuCollection(QMainWindow* mw); + void add(QString name, ShellMenu m); - void exec(QWidget* parent, const QPoint& pos); + void exec(const QPoint& pos); private: struct MenuInfo @@ -58,7 +67,14 @@ private: ShellMenu menu; }; + QMainWindow* m_mw; std::vector<MenuInfo> m_menus; + MenuInfo* m_active; + + bool wndProc(HWND hwnd, UINT m, WPARAM wp, LPARAM lp, LRESULT* out); + + void onMenuSelect( + HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags); }; } // namespace diff --git a/src/filetree.cpp b/src/filetree.cpp index 543be82b..4e3db1f7 100644 --- a/src/filetree.cpp +++ b/src/filetree.cpp @@ -466,8 +466,25 @@ void FileTree::onContextMenu(const QPoint &pos) menu.exec(m_tree->viewport()->mapToGlobal(pos)); } +QMainWindow* getMainWindow(QWidget* w) +{ + QWidget* p = w; + + while (p) { + if (auto* mw=dynamic_cast<QMainWindow*>(p)) { + return mw; + } + + p = p->parentWidget(); + } + + return nullptr; +} + void FileTree::showShellMenu(QPoint pos) { + auto* mw = getMainWindow(m_tree); + // menus by origin std::map<int, env::ShellMenu> menus; @@ -477,7 +494,12 @@ void FileTree::showShellMenu(QPoint pos) continue; } - menus[item->originID()].addFile(item->realPath()); + auto itor = menus.find(item->originID()); + if (itor == menus.end()) { + itor = menus.emplace(item->originID(), mw).first; + } + + itor->second.addFile(item->realPath()); if (item->isConflicted()) { const auto file = m_core.directoryStructure()->searchFile( @@ -499,35 +521,21 @@ void FileTree::showShellMenu(QPoint pos) } for (auto&& alt : alts) { - auto* dir = file->getParent(); - if (!dir) { - log::error( - "file {} from origin {} has no parent", - item->dataRelativeFilePath(), alt.first); - - continue; + auto itor = menus.find(alt.first); + if (itor == menus.end()) { + itor = menus.emplace(alt.first, mw).first; } - const auto* origin = dir->findOriginByID(alt.first); - if (!origin) { + const auto fullPath = file->getFullPath(alt.first); + if (fullPath.empty()) { log::error( - "origin {} for file {} cannot be found", - alt.first, item->dataRelativeFilePath()); - - continue; - } - - const auto originFile = origin->findFile(file->getIndex()); - if (!originFile) { - log::error( - "file {} not found in origin {} ({})", - item->dataRelativeFilePath(), origin->getName(), file->getIndex()); + "file {} not found in origin {}", + item->dataRelativeFilePath(), alt.first); continue; } - menus[alt.first].addFile( - QString::fromStdWString(originFile->getFullPath())); + itor->second.addFile(QString::fromStdWString(fullPath)); } } } @@ -538,9 +546,9 @@ void FileTree::showShellMenu(QPoint pos) } else if (menus.size() == 1) { auto& menu = menus.begin()->second; - menu.exec(m_tree, m_tree->viewport()->mapToGlobal(pos)); + menu.exec(m_tree->viewport()->mapToGlobal(pos)); } else { - env::ShellMenuCollection mc; + env::ShellMenuCollection mc(mw); for (auto&& m : menus) { const auto* origin = m_core.directoryStructure()->findOriginByID(m.first); @@ -552,7 +560,7 @@ void FileTree::showShellMenu(QPoint pos) mc.add(QString::fromStdWString(origin->getName()), std::move(m.second)); } - mc.exec(m_tree, m_tree->viewport()->mapToGlobal(pos)); + mc.exec(m_tree->viewport()->mapToGlobal(pos)); } } diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp index 460431a4..4181098c 100644 --- a/src/shared/directoryentry.cpp +++ b/src/shared/directoryentry.cpp @@ -354,12 +354,20 @@ bool FileEntry::isFromArchive(std::wstring archiveName) const return false;
}
-std::wstring FileEntry::getFullPath() const
+std::wstring FileEntry::getFullPath(int originID) const
{
- bool ignore = false;
+ if (originID == -1) {
+ bool ignore = false;
+ originID = getOrigin(ignore);
+ }
// base directory for origin
- std::wstring result = m_Parent->getOriginByID(getOrigin(ignore)).getPath();
+ const auto* o = m_Parent->findOriginByID(originID);
+ if (!o) {
+ return {};
+ }
+
+ std::wstring result = o->getPath();
// all intermediate directories
recurseParents(result, m_Parent);
diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h index 69eb7574..6102c88f 100644 --- a/src/shared/directoryentry.h +++ b/src/shared/directoryentry.h @@ -127,7 +127,12 @@ public: }
bool isFromArchive(std::wstring archiveName = L"") const;
- std::wstring getFullPath() const;
+
+ // if originID is -1, uses the main origin; if this file doesn't exist in the
+ // given origin, returns an empty string
+ //
+ std::wstring getFullPath(int originID=-1) const;
+
std::wstring getRelativePath() const;
DirectoryEntry *getParent()
|
