summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2020-01-22 01:03:00 -0500
committerisanae <14251494+isanae@users.noreply.github.com>2020-02-04 03:33:21 -0500
commita7a406e5538b343d87b3221b13b7bf3503bbfd70 (patch)
tree0e4f5cc1bb25197bb6b7102016bfee09d6aceedb
parent0f6205bea500169b48b86e321d4d3f650603da2d (diff)
preparing for multiple origins shell menus
split exec() from createMenu()
-rw-r--r--src/envshell.cpp128
-rw-r--r--src/envshell.h9
-rw-r--r--src/filetree.cpp68
-rw-r--r--src/shared/directoryentry.cpp16
-rw-r--r--src/shared/directoryentry.h12
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;