summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/datatab.cpp189
-rw-r--r--src/datatab.h5
-rw-r--r--src/filetree.cpp300
-rw-r--r--src/filetree.h46
-rw-r--r--src/iconfetcher.cpp156
-rw-r--r--src/main.cpp2
-rw-r--r--src/modinfodialog.cpp3
-rw-r--r--src/modinfodialogfwd.h2
-rw-r--r--src/shared/directoryentry.cpp2
-rw-r--r--src/shared/directoryentry.h2
-rw-r--r--src/spawn.cpp9
-rw-r--r--src/spawn.h2
12 files changed, 523 insertions, 195 deletions
diff --git a/src/datatab.cpp b/src/datatab.cpp
index b351923c..c8c7bbfa 100644
--- a/src/datatab.cpp
+++ b/src/datatab.cpp
@@ -19,30 +19,21 @@ DataTab::DataTab(
OrganizerCore& core, PluginContainer& pc,
QWidget* parent, Ui::MainWindow* mwui) :
m_core(core), m_pluginContainer(pc), m_parent(parent),
- m_model(new FileTreeModel(core)),
ui{
mwui->btnRefreshData, mwui->dataTree,
mwui->conflictsCheckBox, mwui->showArchiveDataCheckBox}
{
- ui.tree->setModel(m_model);
+ m_filetree.reset(new FileTree(core, m_pluginContainer, ui.tree));
connect(
ui.refresh, &QPushButton::clicked,
[&]{ onRefresh(); });
//connect(
- // ui.tree, &QTreeWidget::itemExpanded,
- // [&](auto* item){ onItemExpanded(item); });
- //
- //connect(
// ui.tree, &QTreeWidget::itemActivated,
// [&](auto* item, int col){ onItemActivated(item, col); });
connect(
- ui.tree, &QTreeWidget::customContextMenuRequested,
- [&](auto pos){ onContextMenu(pos); });
-
- connect(
ui.conflicts, &QCheckBox::toggled,
[&]{ onConflicts(); });
@@ -79,28 +70,10 @@ QTreeWidgetItem* DataTab::singleSelection()
void DataTab::openSelection()
{
- if (auto* item=singleSelection()) {
- open(item);
- }
}
void DataTab::open(QTreeWidgetItem* item)
{
- const auto isArchive = item->data(0, Qt::UserRole + 1).toBool();
- const auto isDirectory = item->data(0, Qt::UserRole + 3).toBool();
-
- if (isArchive || isDirectory) {
- return;
- }
-
- const QString path = item->data(0, Qt::UserRole).toString();
- const QFileInfo targetInfo(path);
-
- m_core.processRunner()
- .setFromFile(m_parent, targetInfo)
- .setHooked(false)
- .setWaitForCompletion(ProcessRunner::Refresh)
- .run();
}
void DataTab::runSelectionHooked()
@@ -112,21 +85,6 @@ void DataTab::runSelectionHooked()
void DataTab::runHooked(QTreeWidgetItem* item)
{
- const auto isArchive = item->data(0, Qt::UserRole + 1).toBool();
- const auto isDirectory = item->data(0, Qt::UserRole + 3).toBool();
-
- if (isArchive || isDirectory) {
- return;
- }
-
- const QString path = item->data(0, Qt::UserRole).toString();
- const QFileInfo targetInfo(path);
-
- m_core.processRunner()
- .setFromFile(m_parent, targetInfo)
- .setHooked(true)
- .setWaitForCompletion(ProcessRunner::Refresh)
- .run();
}
void DataTab::previewSelection()
@@ -138,8 +96,6 @@ void DataTab::previewSelection()
void DataTab::preview(QTreeWidgetItem* item)
{
- QString fileName = QDir::fromNativeSeparators(item->data(0, Qt::UserRole).toString());
- m_core.previewFileWithAlternatives(m_parent, fileName);
}
void DataTab::onRefresh()
@@ -149,13 +105,13 @@ void DataTab::onRefresh()
void DataTab::refreshDataTree()
{
- m_model->refresh();
+ m_filetree->refresh();
}
void DataTab::refreshDataTreeKeepExpandedNodes()
{
//m_model->refreshKeepExpandedNodes();
- m_model->refresh(); // temp
+ m_filetree->refresh(); // temp
/*QIcon folderIcon = (new QFileIconProvider())->icon(QFileIconProvider::Folder);
QIcon fileIcon = (new QFileIconProvider())->icon(QFileIconProvider::File);
@@ -245,101 +201,6 @@ void DataTab::onItemActivated(QTreeWidgetItem *item, int column)
}
}
-void DataTab::onContextMenu(const QPoint &pos)
-{
- QTreeWidgetItem* item = nullptr;//ui.tree->itemAt(pos.x(), pos.y());
-
- QMenu menu;
- if ((item != nullptr) && (item->childCount() == 0)
- && (item->data(0, Qt::UserRole + 3).toBool() != true)) {
- QString fileName = item->text(0);
- const auto isArchive = item->data(0, Qt::UserRole + 1).toBool();
- const auto isDirectory = item->data(0, Qt::UserRole + 3).toBool();
-
- QAction* open = nullptr;
- QAction* runHooked = nullptr;
- QAction* preview = nullptr;
-
- if (canRunFile(isArchive, fileName)) {
- open = new QAction(tr("&Execute"), ui.tree);
- runHooked = new QAction(tr("Execute with &VFS"), ui.tree);
- } else if (canOpenFile(isArchive, fileName)) {
- open = new QAction(tr("&Open"), ui.tree);
- runHooked = new QAction(tr("Open with &VFS"), ui.tree);
- }
-
- if (m_pluginContainer.previewGenerator().previewSupported(QFileInfo(fileName).suffix())) {
- preview = new QAction(tr("Preview"), ui.tree);
- }
-
- if (open) {
- connect(open, &QAction::triggered, [&]{ openSelection(); });
- }
-
- if (runHooked) {
- connect(runHooked, &QAction::triggered, [&]{ runSelectionHooked(); });
- }
-
- if (preview) {
- connect(preview, &QAction::triggered, [&]{ previewSelection(); });
- }
-
- if (open && preview) {
- if (m_core.settings().interface().doubleClicksOpenPreviews()) {
- menu.addAction(preview);
- menu.addAction(open);
- } else {
- menu.addAction(open);
- menu.addAction(preview);
- }
- } else {
- if (open) {
- menu.addAction(open);
- }
-
- if (preview) {
- menu.addAction(preview);
- }
- }
-
- if (runHooked) {
- menu.addAction(runHooked);
- }
-
- menu.addAction(tr("&Add as Executable"), [&]{ addAsExecutable(); });
-
- if (!isArchive && !isDirectory) {
- menu.addAction("Open Origin in Explorer", [&]{ openOriginInExplorer(); });
- }
-
- menu.addAction("Open Mod Info", [&]{ openModInfo(); });
-
- menu.addSeparator();
-
- // offer to hide/unhide file, but not for files from archives
- if (!isArchive) {
- if (item->text(0).endsWith(ModInfo::s_HiddenExt)) {
- menu.addAction(tr("Un-Hide"), [&]{ unhideFile(); });
- } else {
- menu.addAction(tr("Hide"), [&]{ hideFile(); });
- }
- }
-
- if (open || preview || runHooked) {
- // bold the first option
- auto* top = menu.actions()[0];
- auto f = top->font();
- f.setBold(true);
- top->setFont(f);
- }
- }
-
- menu.addAction(tr("Write To File..."), [&]{ writeDataToFile(); });
- menu.addAction(tr("Refresh"), [&]{ onRefresh(); });
-
- menu.exec(ui.tree->viewport()->mapToGlobal(pos));
-}
-
void DataTab::onConflicts()
{
updateOptions();
@@ -362,54 +223,12 @@ void DataTab::updateOptions()
flags |= FileTreeModel::Archives;
}
- m_model->setFlags(flags);
+ m_filetree->setFlags(flags);
refreshDataTree();
}
void DataTab::addAsExecutable()
{
- auto* item = singleSelection();
- if (!item) {
- return;
- }
-
- const QFileInfo target(item->data(0, Qt::UserRole).toString());
- const auto fec = spawn::getFileExecutionContext(m_parent, target);
-
- switch (fec.type)
- {
- case spawn::FileExecutionTypes::Executable:
- {
- const QString name = QInputDialog::getText(
- m_parent, tr("Enter Name"),
- tr("Enter a name for the executable"),
- QLineEdit::Normal,
- target.completeBaseName());
-
- if (!name.isEmpty()) {
- //Note: If this already exists, you'll lose custom settings
- m_core.executablesList()->setExecutable(Executable()
- .title(name)
- .binaryInfo(fec.binary)
- .arguments(fec.arguments)
- .workingDirectory(target.absolutePath()));
-
- emit executablesChanged();
- }
-
- break;
- }
-
- case spawn::FileExecutionTypes::Other: // fall-through
- default:
- {
- QMessageBox::information(
- m_parent, tr("Not an executable"),
- tr("This is not a recognized executable."));
-
- break;
- }
- }
}
void DataTab::openOriginInExplorer()
diff --git a/src/datatab.h b/src/datatab.h
index de38cc8f..f92d713e 100644
--- a/src/datatab.h
+++ b/src/datatab.h
@@ -8,7 +8,7 @@ namespace Ui { class MainWindow; }
class OrganizerCore;
class Settings;
class PluginContainer;
-class FileTreeModel;
+class FileTree;
namespace MOShared { class DirectoryEntry; }
@@ -45,14 +45,13 @@ private:
OrganizerCore& m_core;
PluginContainer& m_pluginContainer;
QWidget* m_parent;
- FileTreeModel* m_model;
DataTabUi ui;
+ std::unique_ptr<FileTree> m_filetree;
std::vector<QTreeWidgetItem*> m_removeLater;
void onRefresh();
void onItemExpanded(QTreeWidgetItem* item);
void onItemActivated(QTreeWidgetItem* item, int col);
- void onContextMenu(const QPoint &pos);
void onConflicts();
void onArchives();
void updateOptions();
diff --git a/src/filetree.cpp b/src/filetree.cpp
index f99ae8cd..16542734 100644
--- a/src/filetree.cpp
+++ b/src/filetree.cpp
@@ -1,5 +1,6 @@
#include "filetree.h"
#include "organizercore.h"
+#include "modinfodialogfwd.h"
#include <log.h>
using namespace MOShared;
@@ -9,6 +10,33 @@ using namespace MOBase;
QString UnmanagedModName();
+bool canPreviewFile(const PluginContainer& pc, const FileEntry& file)
+{
+ return canPreviewFile(
+ pc, file.isFromArchive(), QString::fromStdWString(file.getName()));
+}
+
+bool canRunFile(const FileEntry& file)
+{
+ return canRunFile(file.isFromArchive(), QString::fromStdWString(file.getName()));
+}
+
+bool canOpenFile(const FileEntry& file)
+{
+ return canOpenFile(file.isFromArchive(), QString::fromStdWString(file.getName()));
+}
+
+bool isHidden(const FileEntry& file)
+{
+ return (QString::fromStdWString(file.getName()).endsWith(ModInfo::s_HiddenExt));
+}
+
+bool canExploreFile(const FileEntry& file);
+bool canHideFile(const FileEntry& file);
+bool canUnhideFile(const FileEntry& file);
+
+
+
FileTreeItem::FileTreeItem()
: m_flags(NoFlags), m_loaded(false)
{
@@ -674,3 +702,275 @@ Qt::ItemFlags FileTreeModel::flags(const QModelIndex& index) const
return f;
}
+
+
+FileTree::FileTree(OrganizerCore& core, PluginContainer& pc, QTreeView* tree)
+ : m_core(core), m_plugins(pc), m_tree(tree), m_model(new FileTreeModel(core))
+{
+ m_tree->setModel(m_model);
+
+ QObject::connect(
+ m_tree, &QTreeWidget::customContextMenuRequested,
+ [&](auto pos){ onContextMenu(pos); });
+}
+
+void FileTree::setFlags(FileTreeModel::Flags flags)
+{
+ m_model->setFlags(flags);
+}
+
+void FileTree::refresh()
+{
+ m_model->refresh();
+}
+
+FileTreeItem* FileTree::singleSelection()
+{
+ const auto sel = m_tree->selectionModel()->selectedRows();
+ if (sel.size() == 1) {
+ return m_model->itemFromIndex(sel[0]);
+ }
+
+ return nullptr;
+}
+
+void FileTree::open()
+{
+ if (auto* item=singleSelection()) {
+ if (item->isFromArchive() || item->isDirectory()) {
+ return;
+ }
+
+ const QString path = item->realPath();
+ const QFileInfo targetInfo(path);
+
+ m_core.processRunner()
+ .setFromFile(m_tree->window(), targetInfo)
+ .setHooked(false)
+ .setWaitForCompletion(ProcessRunner::Refresh)
+ .run();
+ }
+}
+
+void FileTree::openHooked()
+{
+ if (auto* item=singleSelection()) {
+ if (item->isFromArchive() || item->isDirectory()) {
+ return;
+ }
+
+ const QString path = item->realPath();
+ const QFileInfo targetInfo(path);
+
+ m_core.processRunner()
+ .setFromFile(m_tree->window(), targetInfo)
+ .setHooked(true)
+ .setWaitForCompletion(ProcessRunner::Refresh)
+ .run();
+ }
+}
+
+void FileTree::preview()
+{
+ if (auto* item=singleSelection()) {
+ const QString path = item->dataRelativeFilePath();
+ m_core.previewFileWithAlternatives(m_tree->window(), path);
+ }
+}
+
+void FileTree::addAsExecutable()
+{
+ auto* item = singleSelection();
+ if (!item) {
+ return;
+ }
+
+ const QString path = item->realPath();
+ const QFileInfo target(path);
+ const auto fec = spawn::getFileExecutionContext(m_tree->window(), target);
+
+ switch (fec.type)
+ {
+ case spawn::FileExecutionTypes::Executable:
+ {
+ const QString name = QInputDialog::getText(
+ m_tree->window(), QObject::tr("Enter Name"),
+ QObject::tr("Enter a name for the executable"),
+ QLineEdit::Normal,
+ target.completeBaseName());
+
+ if (!name.isEmpty()) {
+ //Note: If this already exists, you'll lose custom settings
+ m_core.executablesList()->setExecutable(Executable()
+ .title(name)
+ .binaryInfo(fec.binary)
+ .arguments(fec.arguments)
+ .workingDirectory(target.absolutePath()));
+
+ // todo
+ //emit executablesChanged();
+ }
+
+ break;
+ }
+
+ case spawn::FileExecutionTypes::Other: // fall-through
+ default:
+ {
+ QMessageBox::information(
+ m_tree->window(), QObject::tr("Not an executable"),
+ QObject::tr("This is not a recognized executable."));
+
+ break;
+ }
+ }
+}
+
+void FileTree::exploreOrigin()
+{
+}
+
+void FileTree::openModInfo()
+{
+}
+
+void FileTree::toggleVisibility()
+{
+}
+
+void FileTree::hide()
+{
+}
+
+void FileTree::unhide()
+{
+}
+
+void FileTree::dumpToFile()
+{
+}
+
+void FileTree::onContextMenu(const QPoint &pos)
+{
+ QMenu menu;
+
+ if (auto* item=singleSelection()) {
+ if (item->isDirectory()) {
+ addDirectoryMenus(menu, *item);
+ } else {
+ const auto file = m_core.directoryStructure()->searchFile(
+ item->dataRelativeFilePath().toStdWString(), nullptr);
+
+ if (file) {
+ addFileMenus(menu, *file, item->originID());
+ }
+ }
+ }
+
+ addCommonMenus(menu);
+
+ menu.exec(m_tree->viewport()->mapToGlobal(pos));
+}
+
+void FileTree::addDirectoryMenus(QMenu&, FileTreeItem&)
+{
+ // noop
+}
+
+void FileTree::addFileMenus(QMenu& menu, const FileEntry& file, int originID)
+{
+ using namespace spawn;
+
+ addOpenMenus(menu, file);
+
+ menu.addSeparator();
+
+ const QFileInfo target(QString::fromStdWString(file.getFullPath()));
+ if (getFileExecutionType(target) == FileExecutionTypes::Executable) {
+ menu.addAction(QObject::tr("&Add as Executable"), [&]{ addAsExecutable(); });
+ }
+
+ if (!file.isFromArchive()) {
+ menu.addAction(QObject::tr("Open Origin in Explorer"), [&]{ exploreOrigin(); });
+ }
+
+ if (originID != 0) {
+ menu.addAction(QObject::tr("Open Mod Info"), [&]{ openModInfo(); });
+ }
+
+ // offer to hide/unhide file, but not for files from archives
+ if (!file.isFromArchive()) {
+ if (isHidden(file)) {
+ menu.addAction(QObject::tr("Un-Hide"), [&]{ hide(); });
+ } else {
+ menu.addAction(QObject::tr("Hide"), [&]{ unhide(); });
+ }
+ }
+}
+
+void FileTree::addOpenMenus(QMenu& menu, const MOShared::FileEntry& file)
+{
+ QAction* openMenu = nullptr;
+ QAction* openHookedMenu = nullptr;
+
+ if (canRunFile(file)) {
+ openMenu = new QAction(QObject::tr("&Execute"), m_tree);
+ openHookedMenu = new QAction(QObject::tr("Execute with &VFS"), m_tree);
+ } else if (canOpenFile(file)) {
+ openMenu = new QAction(QObject::tr("&Open"), m_tree);
+ openHookedMenu = new QAction(QObject::tr("Open with &VFS"), m_tree);
+ }
+
+ QAction* previewMenu = nullptr;
+ if (canPreviewFile(m_plugins, file)) {
+ previewMenu = new QAction(QObject::tr("Preview"), m_tree);
+ }
+
+ if (openMenu && previewMenu) {
+ if (m_core.settings().interface().doubleClicksOpenPreviews()) {
+ menu.addAction(previewMenu);
+ menu.addAction(openMenu);
+ } else {
+ menu.addAction(openMenu);
+ menu.addAction(previewMenu);
+ }
+ } else {
+ if (openMenu) {
+ menu.addAction(openMenu);
+ }
+
+ if (previewMenu) {
+ menu.addAction(previewMenu);
+ }
+ }
+
+ if (openHookedMenu) {
+ menu.addAction(openHookedMenu);
+ }
+
+
+ if (openMenu) {
+ QObject::connect(openMenu, &QAction::triggered, [&]{ open(); });
+ }
+
+ if (openHookedMenu) {
+ QObject::connect(openHookedMenu, &QAction::triggered, [&]{ openHooked(); });
+ }
+
+ if (previewMenu) {
+ QObject::connect(previewMenu, &QAction::triggered, [&]{ preview(); });
+ }
+
+
+ // bold the first option
+ auto* top = menu.actions()[0];
+ auto f = top->font();
+ f.setBold(true);
+ top->setFont(f);
+}
+
+void FileTree::addCommonMenus(QMenu& menu)
+{
+ menu.addAction(QObject::tr("Write To File..."), [&]{ dumpToFile(); });
+ menu.addAction(QObject::tr("Refresh"), [&]{ refresh(); });
+}
diff --git a/src/filetree.h b/src/filetree.h
index 108c5843..41592d82 100644
--- a/src/filetree.h
+++ b/src/filetree.h
@@ -1,8 +1,12 @@
+#ifndef MODORGANIZER_FILETREE_INCLUDED
+#define MODORGANIZER_FILETREE_INCLUDED
+
#include "directoryentry.h"
#include "iconfetcher.h"
#include <QAbstractItemModel>
class OrganizerCore;
+class PluginContainer;
class FileTreeItem
{
@@ -96,6 +100,7 @@ public:
QVariant data(const QModelIndex& index, int role=Qt::DisplayRole) const override;
QVariant headerData(int i, Qt::Orientation ori, int role=Qt::DisplayRole) const override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
+ FileTreeItem* itemFromIndex(const QModelIndex& index) const;
private:
enum class FillFlag
@@ -131,7 +136,6 @@ private:
std::wstring makeModName(const MOShared::FileEntry& file, int originID) const;
- FileTreeItem* itemFromIndex(const QModelIndex& index) const;
void ensureLoaded(FileTreeItem* item) const;
void updatePendingIcons();
@@ -143,3 +147,43 @@ private:
Q_DECLARE_OPERATORS_FOR_FLAGS(FileTreeModel::Flags);
Q_DECLARE_OPERATORS_FOR_FLAGS(FileTreeItem::Flags);
+
+
+class FileTree
+{
+public:
+ FileTree(OrganizerCore& core, PluginContainer& pc, QTreeView* tree);
+
+ void setFlags(FileTreeModel::Flags flags);
+ void refresh();
+
+ void open();
+ void openHooked();
+ void preview();
+
+ void addAsExecutable();
+ void exploreOrigin();
+ void openModInfo();
+
+ void toggleVisibility();
+ void hide();
+ void unhide();
+
+ void dumpToFile();
+
+private:
+ OrganizerCore& m_core;
+ PluginContainer& m_plugins;
+ QTreeView* m_tree;
+ FileTreeModel* m_model;
+
+ FileTreeItem* singleSelection();
+ void onContextMenu(const QPoint &pos);
+
+ void addDirectoryMenus(QMenu& menu, FileTreeItem& item);
+ void addFileMenus(QMenu& menu, const MOShared::FileEntry& file, int originID);
+ void addOpenMenus(QMenu& menu, const MOShared::FileEntry& file);
+ void addCommonMenus(QMenu& menu);
+};
+
+#endif // MODORGANIZER_FILETREE_INCLUDED
diff --git a/src/iconfetcher.cpp b/src/iconfetcher.cpp
new file mode 100644
index 00000000..9f8e348a
--- /dev/null
+++ b/src/iconfetcher.cpp
@@ -0,0 +1,156 @@
+#include "iconfetcher.h"
+
+void IconFetcher::Waiter::wait()
+{
+ std::unique_lock lock(m_wakeUpMutex);
+ m_wakeUp.wait(lock, [&]{ return m_queueAvailable; });
+ m_queueAvailable = false;
+}
+
+void IconFetcher::Waiter::wakeUp()
+{
+ {
+ std::scoped_lock lock(m_wakeUpMutex);
+ m_queueAvailable = true;
+ }
+
+ m_wakeUp.notify_one();
+}
+
+
+IconFetcher::IconFetcher()
+ : m_iconSize(GetSystemMetrics(SM_CXSMICON)), m_stop(false)
+{
+ m_quickCache.file = getPixmapIcon(QFileIconProvider::File);
+ m_quickCache.directory = getPixmapIcon(QFileIconProvider::Folder);
+
+ m_thread = std::thread([&]{ threadFun(); });
+}
+
+IconFetcher::~IconFetcher()
+{
+ stop();
+ m_thread.join();
+}
+
+void IconFetcher::stop()
+{
+ m_stop = true;
+ m_waiter.wakeUp();
+}
+
+QVariant IconFetcher::icon(const QString& path) const
+{
+ if (hasOwnIcon(path)) {
+ return fileIcon(path);
+ } else {
+ const auto dot = path.lastIndexOf(".");
+
+ if (dot == -1) {
+ // no extension
+ return m_quickCache.file;
+ }
+
+ return extensionIcon(path.midRef(dot));
+ }
+}
+
+QPixmap IconFetcher::genericFileIcon() const
+{
+ return m_quickCache.file;
+}
+
+QPixmap IconFetcher::genericDirectoryIcon() const
+{
+ return m_quickCache.directory;
+}
+
+bool IconFetcher::hasOwnIcon(const QString& path) const
+{
+ static const QString exe = ".exe";
+ static const QString lnk = ".lnk";
+ static const QString ico = ".ico";
+
+ return
+ path.endsWith(exe, Qt::CaseInsensitive) ||
+ path.endsWith(lnk, Qt::CaseInsensitive) ||
+ path.endsWith(ico, Qt::CaseInsensitive);
+}
+
+void IconFetcher::threadFun()
+{
+ while (!m_stop) {
+ m_waiter.wait();
+ if (m_stop) {
+ break;
+ }
+
+ checkCache(m_extensionCache);
+ checkCache(m_fileCache);
+ }
+}
+
+void IconFetcher::checkCache(Cache& cache)
+{
+ std::set<QString> queue;
+
+ {
+ std::scoped_lock lock(cache.queueMutex);
+ queue = std::move(cache.queue);
+ cache.queue.clear();
+ }
+
+ if (queue.empty()) {
+ return;
+ }
+
+ std::map<QString, QPixmap> map;
+ for (auto&& ext : queue) {
+ map.emplace(std::move(ext), getPixmapIcon(ext));
+ }
+
+ {
+ std::scoped_lock lock(cache.mapMutex);
+ for (auto&& p : map) {
+ cache.map.insert(std::move(p));
+ }
+ }
+}
+
+void IconFetcher::queue(Cache& cache, QString path) const
+{
+ {
+ std::scoped_lock lock(cache.queueMutex);
+ cache.queue.insert(std::move(path));
+ }
+
+ m_waiter.wakeUp();
+}
+
+QVariant IconFetcher::fileIcon(const QString& path) const
+{
+ {
+ std::scoped_lock lock(m_fileCache.mapMutex);
+ auto itor = m_fileCache.map.find(path);
+ if (itor != m_fileCache.map.end()) {
+ return itor->second;
+ }
+ }
+
+ queue(m_fileCache, path);
+ return {};
+}
+
+QVariant IconFetcher::extensionIcon(const QStringRef& ext) const
+{
+ {
+ std::scoped_lock lock(m_extensionCache.mapMutex);
+ auto itor = m_extensionCache.map.find(ext);
+ if (itor != m_extensionCache.map.end()) {
+ return itor->second;
+ }
+ }
+
+ queue(m_extensionCache, ext.toString());
+ return {};
+}
diff --git a/src/main.cpp b/src/main.cpp
index 29d2d02c..2f4c80a1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -635,8 +635,6 @@ int runApplication(MOApplication &application, SingleInstance &instance,
}
}
- Q_ASSERT(!edition.isEmpty());
-
game->setGameVariant(edition);
log::info(
diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp
index 302175aa..b0a4248e 100644
--- a/src/modinfodialog.cpp
+++ b/src/modinfodialog.cpp
@@ -51,7 +51,8 @@ int naturalCompare(const QString& a, const QString& b)
}
bool canPreviewFile(
- PluginContainer& pluginContainer, bool isArchive, const QString& filename)
+ const PluginContainer& pluginContainer,
+ bool isArchive, const QString& filename)
{
if (isArchive) {
return false;
diff --git a/src/modinfodialogfwd.h b/src/modinfodialogfwd.h
index 1086e740..c758573c 100644
--- a/src/modinfodialogfwd.h
+++ b/src/modinfodialogfwd.h
@@ -23,7 +23,7 @@ enum class ModInfoTabIDs
class PluginContainer;
-bool canPreviewFile(PluginContainer& pluginContainer, bool isArchive, const QString& filename);
+bool canPreviewFile(const PluginContainer& pluginContainer, bool isArchive, const QString& filename);
bool canRunFile(bool isArchive, const QString& filename);
bool canOpenFile(bool isArchive, const QString& filename);
bool canExploreFile(bool isArchive, const QString& filename);
diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp
index 00bf319e..9d49ce1e 100644
--- a/src/shared/directoryentry.cpp
+++ b/src/shared/directoryentry.cpp
@@ -433,7 +433,7 @@ std::wstring FileEntry::getRelativePath() const
return result + L"\\" + m_Name;
}
-bool FileEntry::isFromArchive(std::wstring archiveName)
+bool FileEntry::isFromArchive(std::wstring archiveName) const
{
if (archiveName.length() == 0) return m_Archive.first.length() != 0;
if (m_Archive.first.compare(archiveName) == 0) return true;
diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h
index 0e6b20f0..8766f0c6 100644
--- a/src/shared/directoryentry.h
+++ b/src/shared/directoryentry.h
@@ -78,7 +78,7 @@ public:
int getOrigin() const { return m_Origin; }
int getOrigin(bool &archive) const { archive = (m_Archive.first.length() != 0); return m_Origin; }
const std::pair<std::wstring, int> &getArchive() const { return m_Archive; }
- bool isFromArchive(std::wstring archiveName = L"");
+ bool isFromArchive(std::wstring archiveName = L"") const;
std::wstring getFullPath() const;
std::wstring getRelativePath() const;
DirectoryEntry *getParent() { return m_Parent; }
diff --git a/src/spawn.cpp b/src/spawn.cpp
index 33bdbc05..df6fa379 100644
--- a/src/spawn.cpp
+++ b/src/spawn.cpp
@@ -924,6 +924,15 @@ QFileInfo getCmdPath()
return systemDirectory + "cmd.exe";
}
+FileExecutionTypes getFileExecutionType(const QFileInfo& target)
+{
+ if (isExeFile(target) || isBatchFile(target) || isJavaFile(target)) {
+ return FileExecutionTypes::Executable;
+ }
+
+ return FileExecutionTypes::Other;
+}
+
FileExecutionContext getFileExecutionContext(
QWidget* parent, const QFileInfo& target)
{
diff --git a/src/spawn.h b/src/spawn.h
index a615b5ff..0628781e 100644
--- a/src/spawn.h
+++ b/src/spawn.h
@@ -85,6 +85,8 @@ QString findJavaInstallation(const QString& jarFile);
FileExecutionContext getFileExecutionContext(
QWidget* parent, const QFileInfo& target);
+FileExecutionTypes getFileExecutionType(const QFileInfo& target);
+
} // namespace