Skip to content

Commit

Permalink
Refresh Callback (+ Extra for AboutToRun) (#1884)
Browse files Browse the repository at this point in the history
* Add working directory and arguments to onAboutToRun (optional).

* Add onRefreshCallback functionality.
  • Loading branch information
Holt59 authored Sep 29, 2023
1 parent 63f663a commit ff0eb2f
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 77 deletions.
12 changes: 8 additions & 4 deletions src/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1803,7 +1803,9 @@ void MainWindow::on_profileBox_currentIndexChanged(int index)
m_OrganizerCore.managedGame()->feature<BSAInvalidation>();
if (invalidation != nullptr) {
if (invalidation->prepareProfile(m_OrganizerCore.currentProfile())) {
QTimer::singleShot(5, &m_OrganizerCore, SLOT(profileRefresh()));
QTimer::singleShot(5, [this] {
m_OrganizerCore.refresh();
});
}
}
}
Expand Down Expand Up @@ -2389,7 +2391,9 @@ void MainWindow::on_actionAdd_Profile_triggered()
m_OrganizerCore.managedGame()->feature<BSAInvalidation>();
if (invalidation != nullptr) {
if (invalidation->prepareProfile(m_OrganizerCore.currentProfile())) {
QTimer::singleShot(5, &m_OrganizerCore, SLOT(profileRefresh()));
QTimer::singleShot(5, [this] {
m_OrganizerCore.refresh();
});
}
}
}
Expand Down Expand Up @@ -2549,7 +2553,7 @@ void MainWindow::setWindowEnabled(bool enabled)

void MainWindow::refreshProfile_activated()
{
m_OrganizerCore.profileRefresh();
m_OrganizerCore.refresh();
}

void MainWindow::saveArchiveList()
Expand Down Expand Up @@ -2776,7 +2780,7 @@ void MainWindow::on_actionSettings_triggered()

if ((settings.paths().mods() != oldModDirectory) ||
(settings.interface().displayForeign() != oldDisplayForeign)) {
m_OrganizerCore.profileRefresh();
m_OrganizerCore.refresh();
}

const auto state = settings.archiveParsing();
Expand Down
2 changes: 1 addition & 1 deletion src/modlistcontextmenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ void ModListGlobalContextMenu::populate(OrganizerCore& core, ModListView* view,
addAction(tr("Auto assign categories"), [=]() {
view->actions().assignCategories();
});
addAction(tr("Refresh"), &core, &OrganizerCore::profileRefresh);
addAction(tr("Refresh"), &core, &OrganizerCore::refresh);
addAction(tr("Export to csv..."), [=]() {
view->actions().exportModListCSV();
});
Expand Down
99 changes: 47 additions & 52 deletions src/organizercore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ OrganizerCore::OrganizerCore(Settings& settings)

connect(&m_DownloadManager, SIGNAL(downloadSpeed(QString, int)), this,
SLOT(downloadSpeed(QString, int)));
connect(m_DirectoryRefresher.get(), SIGNAL(refreshed()), this,
SLOT(directory_refreshed()));

connect(m_DirectoryRefresher.get(), &DirectoryRefresher::refreshed, [this]() {
onDirectoryRefreshed();
});
connect(&m_ModList, SIGNAL(removeOrigin(QString)), this, SLOT(removeOrigin(QString)));
connect(&m_ModList, &ModList::modStatesChanged, [=] {
currentProfile()->writeModlist();
Expand Down Expand Up @@ -1134,8 +1134,8 @@ bool OrganizerCore::previewFile(QWidget* parent, const QString& originName,
return true;
}

boost::signals2::connection
OrganizerCore::onAboutToRun(const std::function<bool(const QString&)>& func)
boost::signals2::connection OrganizerCore::onAboutToRun(
const std::function<bool(const QString&, const QDir&, const QString&)>& func)
{
return m_AboutToRun.connect(func);
}
Expand Down Expand Up @@ -1195,6 +1195,18 @@ OrganizerCore::onPluginDisabled(std::function<void(const IPlugin*)> const& func)
return m_PluginDisabled.connect(func);
}

boost::signals2::connection
OrganizerCore::onNextRefresh(std::function<void()> const& func,
RefreshCallbackGroup group, RefreshCallbackMode mode)
{
if (m_DirectoryUpdate || mode == RefreshCallbackMode::FORCE_WAIT_FOR_REFRESH) {
return m_OnNextRefreshCallbacks.connect(static_cast<int>(group), func);
} else {
func();
return {};
}
}

void OrganizerCore::refresh(bool saveChanges)
{
// don't lose changes!
Expand All @@ -1212,25 +1224,21 @@ void OrganizerCore::refresh(bool saveChanges)

void OrganizerCore::refreshESPList(bool force)
{
TimeThis tt("OrganizerCore::refreshESPList()");
onNextRefresh(
[this, force] {
TimeThis tt("OrganizerCore::refreshESPList()");

if (m_DirectoryUpdate) {
// don't mess up the esp list if we're currently updating the directory
// structure
m_PostRefreshTasks.append([=]() {
this->refreshESPList(force);
});
return;
}
m_CurrentProfile->writeModlist();
m_CurrentProfile->writeModlist();

// clear list
try {
m_PluginList.refresh(m_CurrentProfile->name(), *m_DirectoryStructure,
m_CurrentProfile->getLockedOrderFileName(), force);
} catch (const std::exception& e) {
reportError(tr("Failed to refresh list of esps: %1").arg(e.what()));
}
// clear list
try {
m_PluginList.refresh(m_CurrentProfile->name(), *m_DirectoryStructure,
m_CurrentProfile->getLockedOrderFileName(), force);
} catch (const std::exception& e) {
reportError(tr("Failed to refresh list of esps: %1").arg(e.what()));
}
},
RefreshCallbackGroup::CORE, RefreshCallbackMode::RUN_NOW_IF_POSSIBLE);
}

void OrganizerCore::refreshBSAList()
Expand Down Expand Up @@ -1513,13 +1521,13 @@ void OrganizerCore::refreshDirectoryStructure()
std::set<QString>(archives.begin(), archives.end()));

// runs refresh() in a thread
QTimer::singleShot(0, m_DirectoryRefresher.get(), SLOT(refresh()));
QTimer::singleShot(0, m_DirectoryRefresher.get(), &DirectoryRefresher::refresh);
}

void OrganizerCore::directory_refreshed()
void OrganizerCore::onDirectoryRefreshed()
{
log::debug("directory refreshed, finishing up");
TimeThis tt("OrganizerCore::directory_refreshed()");
TimeThis tt("OrganizerCore::onDirectoryRefreshed()");

DirectoryEntry* newStructure = m_DirectoryRefresher->stealDirectoryStructure();
Q_ASSERT(newStructure != m_DirectoryStructure);
Expand All @@ -1543,23 +1551,18 @@ void OrganizerCore::directory_refreshed()
log::debug("structure deleter thread done");
});

m_DirectoryUpdate = false;

log::debug("clearing caches");
for (int i = 0; i < m_ModList.rowCount(); ++i) {
ModInfo::Ptr modInfo = ModInfo::getByIndex(i);
modInfo->clearCaches();
}

if (!m_PostRefreshTasks.empty()) {
log::debug("running {} post refresh tasks", m_PostRefreshTasks.size());

for (auto task : m_PostRefreshTasks) {
task();
}
// needs to be done before post refresh tasks
m_DirectoryUpdate = false;

m_PostRefreshTasks.clear();
}
log::debug("running {} post refresh tasks");
m_OnNextRefreshCallbacks();
m_OnNextRefreshCallbacks.disconnect_all_slots();

if (m_CurrentProfile != nullptr) {
log::debug("refreshing lists");
Expand All @@ -1571,11 +1574,6 @@ void OrganizerCore::directory_refreshed()
log::debug("refresh done");
}

void OrganizerCore::profileRefresh()
{
refresh();
}

void OrganizerCore::clearCaches(std::vector<unsigned int> const& indices) const
{
const auto insert = [](auto& dest, const auto& from) {
Expand Down Expand Up @@ -1891,15 +1889,12 @@ bool OrganizerCore::saveCurrentLists()

void OrganizerCore::savePluginList()
{
if (m_DirectoryUpdate) {
// delay save till after directory update
m_PostRefreshTasks.append([this]() {
this->savePluginList();
});
return;
}
m_PluginList.saveTo(m_CurrentProfile->getLockedOrderFileName());
m_PluginList.saveLoadOrder(*m_DirectoryStructure);
onNextRefresh(
[this]() {
m_PluginList.saveTo(m_CurrentProfile->getLockedOrderFileName());
m_PluginList.saveLoadOrder(*m_DirectoryStructure);
},
RefreshCallbackGroup::CORE, RefreshCallbackMode::RUN_NOW_IF_POSSIBLE);
}

void OrganizerCore::saveCurrentProfile()
Expand All @@ -1920,7 +1915,8 @@ ProcessRunner OrganizerCore::processRunner()
}

bool OrganizerCore::beforeRun(
const QFileInfo& binary, const QString& profileName, const QString& customOverwrite,
const QFileInfo& binary, const QDir& cwd, const QString& arguments,
const QString& profileName, const QString& customOverwrite,
const QList<MOBase::ExecutableForcedLoadSetting>& forcedLibraries)
{
saveCurrentProfile();
Expand All @@ -1938,8 +1934,7 @@ bool OrganizerCore::beforeRun(
m_CurrentProfile->writeModlistNow(true);
}

// TODO: should also pass arguments
if (!m_AboutToRun(binary.absoluteFilePath())) {
if (!m_AboutToRun(binary.absoluteFilePath(), cwd, arguments)) {
log::debug("start of \"{}\" cancelled by plugin", binary.absoluteFilePath());
return false;
}
Expand Down
54 changes: 44 additions & 10 deletions src/organizercore.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ class OrganizerCore : public QObject, public MOBase::IPluginDiagnose

private:
using SignalAboutToRunApplication =
boost::signals2::signal<bool(const QString&), SignalCombinerAnd>;
boost::signals2::signal<bool(const QString&, const QDir&, const QString&),
SignalCombinerAnd>;
using SignalFinishedRunApplication =
boost::signals2::signal<void(const QString&, unsigned int)>;
using SignalUserInterfaceInitialized = boost::signals2::signal<void(QMainWindow*)>;
Expand Down Expand Up @@ -211,6 +212,31 @@ class OrganizerCore : public QObject, public MOBase::IPluginDiagnose
friend class OrganizerCore;
};

// enumeration for the mode when adding refresh callbacks
//
enum class RefreshCallbackMode : int
{
// run the callbacks immediately if no refresh is running
RUN_NOW_IF_POSSIBLE = 0,

// wait for the next refresh if none is running
FORCE_WAIT_FOR_REFRESH = 1
};

// enumeration for the groups where refresh callbacks can be put
//
enum class RefreshCallbackGroup : int
{
// for callbacks by the core itself, highest priority
CORE = 0,

// internal MO2 callbacks
INTERNAL = 1,

// external callbacks, typically MO2 plugins
EXTERNAL = 2
};

public:
OrganizerCore(Settings& settings);

Expand Down Expand Up @@ -269,8 +295,8 @@ class OrganizerCore : public QObject, public MOBase::IPluginDiagnose

ProcessRunner processRunner();

bool beforeRun(const QFileInfo& binary, const QString& profileName,
const QString& customOverwrite,
bool beforeRun(const QFileInfo& binary, const QDir& cwd, const QString& arguments,
const QString& profileName, const QString& customOverwrite,
const QList<MOBase::ExecutableForcedLoadSetting>& forcedLibraries);

void afterRun(const QFileInfo& binary, DWORD exitCode);
Expand Down Expand Up @@ -356,8 +382,8 @@ class OrganizerCore : public QObject, public MOBase::IPluginDiagnose
ModList* modList();
void refresh(bool saveChanges = true);

boost::signals2::connection
onAboutToRun(const std::function<bool(const QString&)>& func);
boost::signals2::connection onAboutToRun(
const std::function<bool(const QString&, const QDir&, const QString&)>& func);
boost::signals2::connection
onFinishedRun(const std::function<void(const QString&, unsigned int)>& func);
boost::signals2::connection
Expand All @@ -379,6 +405,15 @@ class OrganizerCore : public QObject, public MOBase::IPluginDiagnose
boost::signals2::connection
onPluginDisabled(std::function<void(const MOBase::IPlugin*)> const& func);

// add a function to be called after the next refresh is done
//
// - group to add the function to
// - if immediateIfReady is true, the function will be called immediately if no
// directory update is running
boost::signals2::connection onNextRefresh(std::function<void()> const& func,
RefreshCallbackGroup group,
RefreshCallbackMode mode);

public: // IPluginDiagnose interface
virtual std::vector<unsigned int> activeProblems() const;
virtual QString shortDescription(unsigned int key) const;
Expand All @@ -388,8 +423,6 @@ class OrganizerCore : public QObject, public MOBase::IPluginDiagnose

public slots:

void profileRefresh();

void syncOverwrite();

void savePluginList();
Expand Down Expand Up @@ -472,7 +505,7 @@ public slots:

private slots:

void directory_refreshed();
void onDirectoryRefreshed();
void downloadRequested(QNetworkReply* reply, QString gameName, int modID,
const QString& fileName);
void removeOrigin(const QString& name);
Expand Down Expand Up @@ -507,11 +540,12 @@ private slots:
SignalPluginEnabled m_PluginEnabled;
SignalPluginEnabled m_PluginDisabled;

boost::signals2::signal<void()> m_OnNextRefreshCallbacks;

ModList m_ModList;
PluginList m_PluginList;

QList<std::function<void()>> m_PostLoginTasks;
QList<std::function<void()>> m_PostRefreshTasks;

ExecutablesList m_ExecutablesList;
QStringList m_PendingDownloads;
Expand All @@ -529,7 +563,7 @@ private slots:

std::thread m_StructureDeleter;

bool m_DirectoryUpdate;
std::atomic<bool> m_DirectoryUpdate;
bool m_ArchivesInit;

MOBase::DelayedFileWriter m_PluginListsWriter;
Expand Down
Loading

0 comments on commit ff0eb2f

Please sign in to comment.