diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/envshell.cpp | 128 | ||||
| -rw-r--r-- | src/envshell.h | 9 | ||||
| -rw-r--r-- | src/filetree.cpp | 68 | ||||
| -rw-r--r-- | src/shared/directoryentry.cpp | 16 | ||||
| -rw-r--r-- | src/shared/directoryentry.h | 12 |
5 files changed, 185 insertions, 48 deletions
diff --git a/src/envshell.cpp b/src/envshell.cpp index 7754928e..992ce1ef 100644 --- a/src/envshell.cpp +++ b/src/envshell.cpp @@ -65,15 +65,7 @@ public: WndProcFilter(QMainWindow* mw, IContextMenu* cm) : m_mw(mw), m_cm(cm), m_cm2(nullptr), m_cm3(nullptr) { - IContextMenu2* cm2 = nullptr; - if (SUCCEEDED(cm->QueryInterface(IID_IContextMenu2, (void**)&cm2))) { - m_cm2.reset(cm2); - } - - IContextMenu3* cm3 = nullptr; - if (SUCCEEDED(cm->QueryInterface(IID_IContextMenu3, (void**)&cm3))) { - m_cm3.reset(cm3); - } + createInterfaces(); } ~WndProcFilter() @@ -86,6 +78,9 @@ public: bool nativeEventFilter(const QByteArray& type, void* m, long* lresultOut) override { MSG* msg = (MSG*)m; + if (!msg) { + return false; + } if (msg->message == WM_MENUSELECT) { HANDLE_WM_MENUSELECT(msg->hwnd, msg->wParam, msg->lParam, onMenuSelect); @@ -129,6 +124,23 @@ private: 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); + } + } + // adapted from // https://devblogs.microsoft.com/oldnewthing/20040928-00/?p=37723 // @@ -233,13 +245,51 @@ void ShellMenu::addFile(QFileInfo fi) void ShellMenu::exec(QWidget* parent, const QPoint& pos) { + auto* mw = getMainWindow(parent); + HMENU menu = getMenu(); + if (!menu) { + return; + } + + try + { + const int cmd = runMenu(mw, m_cm.get(), m_menu.get(), pos); + if (cmd <= 0) { + return; + } + + invoke(mw, pos, cmd - QCM_FIRST, m_cm.get()); + } + catch(MenuFailed& e) + { + if (m_files.size() == 1) { + log::error( + "can't exec shell menu for '{}': {}", + QDir::toNativeSeparators(m_files[0].absoluteFilePath()), e.what()); + } else { + log::error( + "can't exec shell menu for {} files: {}", + m_files.size(), e.what()); + } + } +} + +HMENU ShellMenu::getMenu() +{ + if (!m_menu) { + createMenu(); + } + + return m_menu.get(); +} + +void ShellMenu::createMenu() +{ if (m_files.empty()) { log::warn("showShellMenu(): no files given"); return; } - auto* mw = getMainWindow(parent); - try { auto idls = createIdls(m_files); @@ -252,27 +302,12 @@ void ShellMenu::exec(QWidget* parent, const QPoint& pos) IdlsFreer freer(idls); auto array = createItemArray(idls); - auto cm = createContextMenu(array.get()); - auto hmenu = createMenu(cm.get()); - - const int cmd = runMenu(mw, cm.get(), hmenu.get(), pos); - if (cmd <= 0) { - return; - } - - invoke(mw, pos, cmd - QCM_FIRST, cm.get()); + m_cm = createContextMenu(array.get()); + m_menu = createMenu(m_cm.get()); } catch(DummyMenu& dm) { - try - { - showDummyMenu(mw, pos, dm.what()); - } - catch(MenuFailed& e) - { - log::error("{}", dm.what()); - log::error("additionally, creating the dummy menu failed: {}", e.what()); - } + m_menu = createDummyMenu(dm.what()); } catch(MenuFailed& e) { @@ -285,27 +320,34 @@ void ShellMenu::exec(QWidget* parent, const QPoint& pos) "can't create shell menu for {} files: {}", m_files.size(), e.what()); } + + m_menu = createDummyMenu(QObject::tr("No menu available")); } } -void ShellMenu::showDummyMenu( - QMainWindow* mw, const QPoint& pos, const QString& what) +HMenuPtr ShellMenu::createDummyMenu(const QString& what) { - HMENU menu = CreatePopupMenu(); - if (!menu) { - const auto e = GetLastError(); - throw MenuFailed(e, "CreatePopupMenu failed"); - } + try + { + HMENU menu = CreatePopupMenu(); + if (!menu) { + const auto e = GetLastError(); + throw MenuFailed(e, "CreatePopupMenu failed"); + } - if (!AppendMenuW(menu, MF_STRING | MF_DISABLED, 0, what.toStdWString().c_str())) { - const auto e = GetLastError(); - throw MenuFailed(e, "AppendMenuW failed"); + if (!AppendMenuW(menu, MF_STRING | MF_DISABLED, 0, what.toStdWString().c_str())) { + const auto e = GetLastError(); + throw MenuFailed(e, "AppendMenuW failed"); + } + + return HMenuPtr(menu); } + catch(MenuFailed& e) + { + log::error("{}", what); + log::error("additionally, creating the dummy menu failed: {}", e.what()); - const auto hwnd = (HWND)mw->winId(); - if (!TrackPopupMenuEx(menu, 0, pos.x(), pos.y(), hwnd, nullptr)) { - const auto e = GetLastError(); - throw MenuFailed(e, "TrackPopupMenuEx failed"); + return {}; } } diff --git a/src/envshell.h b/src/envshell.h index 86d9b0fc..f25aeda7 100644 --- a/src/envshell.h +++ b/src/envshell.h @@ -12,10 +12,16 @@ class ShellMenu { public: void addFile(QFileInfo fi); + void exec(QWidget* parent, const QPoint& pos); + HMENU getMenu(); private: std::vector<QFileInfo> m_files; + COMPtr<IContextMenu> m_cm; + HMenuPtr m_menu; + + void createMenu(); QMainWindow* getMainWindow(QWidget* w); COMPtr<IShellItem> createShellItem(const std::wstring& path); @@ -25,9 +31,10 @@ private: 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 showDummyMenu(QMainWindow* mw, const QPoint& pos, const QString& what); }; } // namespace diff --git a/src/filetree.cpp b/src/filetree.cpp index 404c994b..7128665d 100644 --- a/src/filetree.cpp +++ b/src/filetree.cpp @@ -468,7 +468,8 @@ void FileTree::onContextMenu(const QPoint &pos) void FileTree::showShellMenu(QPoint pos) { - env::ShellMenu menu; + // menus by origin + std::map<int, env::ShellMenu> menus; for (auto&& index : m_tree->selectionModel()->selectedRows()) { auto* item = m_model->itemFromIndex(index); @@ -476,10 +477,71 @@ void FileTree::showShellMenu(QPoint pos) continue; } - menu.addFile(item->realPath()); + menus[item->originID()].addFile(item->realPath()); + + if (item->isConflicted()) { + const auto file = m_core.directoryStructure()->searchFile( + item->dataRelativeFilePath().toStdWString(), nullptr); + + if (!file) { + log::error( + "file '{}' not found, data path={}, real path={}", + item->filename(), item->dataRelativeFilePath(), item->realPath()); + + continue; + } + + const auto alts = file->getAlternatives(); + if (alts.empty()) { + log::warn( + "file '{}' has no alternative origins but is marked as conflicted", + item->dataRelativeFilePath()); + } + + for (auto&& alt : alts) { + auto* dir = file->getParent(); + if (!dir) { + log::error( + "file {} from origin {} has no parent", + item->dataRelativeFilePath(), alt.first); + + continue; + } + + const auto* origin = dir->findOriginByID(alt.first); + if (!origin) { + 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()); + + continue; + } + + menus[alt.first].addFile( + QString::fromStdWString(originFile->getFullPath())); + } + } } - menu.exec(m_tree, m_tree->viewport()->mapToGlobal(pos)); + if (menus.empty()) { + log::warn("no menus to show"); + return; + } + else if (menus.size() == 1) { + auto& menu = menus.begin()->second; + menu.exec(m_tree, m_tree->viewport()->mapToGlobal(pos)); + } else { + + } } void FileTree::addDirectoryMenus(QMenu&, FileTreeItem&) diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp index 819075ae..460431a4 100644 --- a/src/shared/directoryentry.cpp +++ b/src/shared/directoryentry.cpp @@ -104,6 +104,17 @@ public: return m_Origins[ID];
}
+ const FilesOrigin* findByID(Index ID) const
+ {
+ auto itor = m_Origins.find(ID);
+
+ if (itor == m_Origins.end()) {
+ return nullptr;
+ } else {
+ return &itor->second;
+ }
+ }
+
FilesOrigin &getByName(const std::wstring &name)
{
std::map<std::wstring, int>::iterator iter = m_OriginsNameMap.find(name);
@@ -736,6 +747,11 @@ FilesOrigin &DirectoryEntry::getOriginByName(const std::wstring &name) const return m_OriginConnection->getByName(name);
}
+const FilesOrigin* DirectoryEntry::findOriginByID(int ID) const
+{
+ return m_OriginConnection->findByID(ID);
+}
+
int DirectoryEntry::anyOrigin() const
{
bool ignore;
diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h index b5a1dced..69eb7574 100644 --- a/src/shared/directoryentry.h +++ b/src/shared/directoryentry.h @@ -63,7 +63,16 @@ class FileEntry public:
typedef unsigned int Index;
typedef boost::shared_ptr<FileEntry> Ptr;
- typedef std::vector<std::pair<int, std::pair<std::wstring, int>>> AlternativesVector;
+
+ // a vector of {originId, {archiveName, order}}
+ //
+ // if a file is in an archive, archiveName is the name of the bsa and order
+ // is the order of the associated plugin in the plugins list
+ //
+ // is a file is not in an archive, archiveName is empty and order is usually
+ // -1
+ typedef std::vector<std::pair<int, std::pair<std::wstring, int>>>
+ AlternativesVector;
FileEntry();
FileEntry(Index index, const std::wstring &name, DirectoryEntry *parent);
@@ -339,6 +348,7 @@ public: bool originExists(const std::wstring &name) const;
FilesOrigin &getOriginByID(int ID) const;
FilesOrigin &getOriginByName(const std::wstring &name) const;
+ const FilesOrigin* findOriginByID(int ID) const;
int anyOrigin() const;
|
