Compare commits

...
21 Commits
Author SHA1 Message Date
Mikaël Capelle ee4c364ccc Bump version to 2.4.0rc2 and update translations. 2021-02-12 18:18:19 +01:00
Mikaël Capelle 607fafa364 Merge pull request #1408 from isanae/portable-shortcuts
Fixes for portable shortcuts
2021-02-12 18:09:15 +01:00
Mikaël Capelle 7dc28b10d9 Merge pull request #1407 from isanae/processes-in-job
Fixes for processesInJob()
2021-02-12 18:09:05 +01:00
Mikaël Capelle 9f0c8c31a6 Merge pull request #1405 from LostDragonist/update_fixes
Fixes for the update dialog window
2021-02-12 18:08:54 +01:00
Mikaël Capelle 2fe627c261 Merge pull request #1404 from Al12rs/fix_update_filter
Hopefully fix update filter not showing new mod updates.
2021-02-12 18:08:41 +01:00
Mikaël Capelle 879c37984e Merge pull request #1403 from Holt59/fix-steamappid-env-error
Do not return previous value in env::set and env::setPath.
2021-02-12 18:08:25 +01:00
Mikaël Capelle 1cf8a2bfee Merge pull request #1401 from ModOrganizer2/Al12rs-appveyorFix
Appveyor: artifact only the exe
2021-02-12 18:08:07 +01:00
Mikaël Capelle 7531a860cf Merge pull request #1400 from Holt59/fix-markers-conflicts-refresh
Better refresh of override markers and conflicts.
2021-02-12 18:07:56 +01:00
Chris Bessent 31c8415e88 Use release name for changelogs 2021-02-12 01:31:41 -07:00
isanae 48274f3357 - renamed instance::name() to displayName() to reduce confusion with portable instances
- better errors when running incorrect shortcuts
- fixed shortcuts being created with moshortcut://Portable:exe instead of an empty instance name for portable instances
2021-02-12 03:22:52 -05:00
Chris Bessent f486e6fa4e Updates to text, title and buttons 2021-02-11 18:39:06 -07:00
Chris Bessent 9e5a64b545 Update CMakeLists.txt 2021-02-11 18:09:19 -07:00
Chris Bessent 3dd05ff869 Create a new dialog for the update window
The idea here is to be able to resize the window and better handle
markdown formatting.  Everything was stolen from the LOOT dialog.
2021-02-11 17:58:10 -07:00
AL eba98e8469 Remove unused variable 2021-02-11 16:34:43 +01:00
AL 73418ec616 Hopefully fix update filter not showing new mod updates.
Notify all the mods that have had their info checked, not just the ones that have been found with an update. This is because Mo2 also shows mods that have had their files deleted or moved to Old as updateAvailable, in which case there is no update but the filter still needs to be notified to include the mod.
2021-02-11 16:29:32 +01:00
Mikaël Capelle 7283e6c3ba Do not return previous value in env::set and env::setPath (avoid error log when not previously set). 2021-02-10 19:17:21 +01:00
isanae d179ad01c8 maxIds was local to the loop, not doubled
handle ERROR_MORE_DATA, it seems to sometimes happen, not sure why
added more logging, a user actually got that error
2021-02-10 10:01:39 -05:00
Al 04d80bb567 Appveyor: artifact only the exe
The entire build is too big and we get over the limit too fast
2021-02-09 22:01:24 +01:00
Mikaël Capelle 595f6eccf6 Better refresh of override markers and conflicts. 2021-02-09 20:23:42 +01:00
Chris Bessent f058125e66 Fix concatenating update logs 2021-02-08 06:09:06 -07:00
Mikaël Capelle 7d36bc20d0 Bump version to 2.4.0rc1.1. 2021-02-07 18:47:00 +01:00
31 changed files with 750 additions and 353 deletions
+3 -3
View File
@@ -52,10 +52,10 @@ build_script:
if($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode ) }
test: off
artifacts:
- path: '\modorganizer-build\install\bin'
- path: '\modorganizer-build\install\bin\ModOrganizer.exe'
name: Mod.Organizer-$(APPVEYOR_BUILD_VERSION)
- path: '\modorganizer-build\install\pdb'
name: PDBs-Mod.Organizer-$(APPVEYOR_BUILD_VERSION)
- path: '\modorganizer-build\install\pdb\ModOrganizer.pdb'
name: PDB-Mod.Organizer-$(APPVEYOR_BUILD_VERSION)
deploy: off
on_success:
- ps: >-
+1
View File
@@ -18,6 +18,7 @@ add_filter(NAME src/application GROUPS
multiprocess
sanitychecks
selfupdater
updatedialog
)
add_filter(NAME src/browser GROUPS
+5 -6
View File
@@ -251,7 +251,7 @@ std::optional<int> CommandLine::runPostApplication(MOApplication& a)
env::Console c;
if (auto i=InstanceManager::singleton().currentInstance()) {
std::cout << i->name().toStdString() << "\n";
std::cout << i->displayName().toStdString() << "\n";
} else {
std::cout << "no instance configured\n";
}
@@ -289,9 +289,8 @@ std::optional<int> CommandLine::runPostOrganizer(OrganizerCore& core)
return 0;
}
catch (const std::exception &e) {
reportError(
QObject::tr("failed to start shortcut: %1").arg(e.what()));
catch (std::exception&) {
// user was already warned
return 1;
}
}
@@ -451,7 +450,7 @@ std::optional<QString> CommandLine::instance() const
// note that moshortcut:// overrides -i
if (m_shortcut.isValid() && m_shortcut.hasInstance()) {
return m_shortcut.instance();
return m_shortcut.instanceName();
} else if (m_vm.count("instance")) {
return QString::fromStdString(m_vm["instance"].as<std::string>());
}
@@ -817,7 +816,7 @@ std::optional<int> RunCommand::runPostOrganizer(OrganizerCore& core)
reportError(
QObject::tr("Executable '%1' not found in instance '%2'.")
.arg(program)
.arg(InstanceManager::singleton().currentInstance()->name()));
.arg(InstanceManager::singleton().currentInstance()->displayName()));
return 1;
}
+3 -5
View File
@@ -418,9 +418,9 @@ QString prependToPath(const QString& s)
return old;
}
QString setPath(const QString& s)
void setPath(const QString& s)
{
return set("PATH", s);
set("PATH", s);
}
QString get(const QString& name)
@@ -457,11 +457,9 @@ QString get(const QString& name)
return QString::fromWCharArray(buffer.get(), realSize);
}
QString set(const QString& n, const QString& v)
void set(const QString& n, const QString& v)
{
auto old = get(n);
::SetEnvironmentVariableW(n.toStdWString().c_str(), v.toStdWString().c_str());
return old;
}
+2 -2
View File
@@ -233,12 +233,12 @@ private:
// environment variables
//
QString get(const QString& name);
QString set(const QString& name, const QString& value);
void set(const QString& name, const QString& value);
QString path();
QString appendToPath(const QString& s);
QString prependToPath(const QString& s);
QString setPath(const QString& s);
void setPath(const QString& s);
class Service
+21 -5
View File
@@ -603,9 +603,16 @@ Process getProcessTreeFromProcess(HANDLE h)
std::vector<DWORD> processesInJob(HANDLE h)
{
for (int tries=0; tries<5; ++tries) {
DWORD maxIds = 100;
const int MaxTries = 5;
// doubled MaxTries times on failure
DWORD maxIds = 100;
// for logging
DWORD lastCount=0, lastAssigned=0;
for (int tries=0; tries<MaxTries; ++tries) {
const DWORD idsSize = sizeof(ULONG_PTR) * maxIds;
const DWORD bufferSize = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + idsSize;
@@ -617,8 +624,10 @@ std::vector<DWORD> processesInJob(HANDLE h)
if (!r) {
const auto e = GetLastError();
log::error("failed to get process ids in job, {}", formatSystemMessage(e));
return {};
if (e != ERROR_MORE_DATA) {
log::error("failed to get process ids in job, {}", formatSystemMessage(e));
return {};
}
}
if (ids->NumberOfProcessIdsInList >= ids->NumberOfAssignedProcesses) {
@@ -632,9 +641,16 @@ std::vector<DWORD> processesInJob(HANDLE h)
// try again with a larger buffer
maxIds *= 2;
// for logging
lastCount = ids->NumberOfProcessIdsInList;
lastAssigned = ids->NumberOfAssignedProcesses;
}
log::error("failed to get processes in job, can't get a buffer large enough");
log::error(
"failed to get processes in job, can't get a buffer large enough, "
"{}/{} ids", lastCount, lastAssigned);
return {};
}
+3 -1
View File
@@ -145,11 +145,13 @@ Shortcut::Shortcut()
Shortcut::Shortcut(const Executable& exe)
: Shortcut()
{
const auto i = *InstanceManager::singleton().currentInstance();
m_name = exe.title();
m_target = QFileInfo(qApp->applicationFilePath()).absoluteFilePath();
m_arguments = QString("\"moshortcut://%1:%2\"")
.arg(InstanceManager::singleton().currentInstance()->name())
.arg(i.isPortable() ? "" : i.displayName())
.arg(exe.title());
m_description = QString("Run %1 with ModOrganizer").arg(exe.title());
+8 -8
View File
@@ -48,7 +48,7 @@ Instance::Instance(QString dir, bool portable, QString profileName) :
{
}
QString Instance::name() const
QString Instance::displayName() const
{
if (isPortable())
return QObject::tr("Portable");
@@ -105,7 +105,7 @@ bool Instance::isActive() const
if (m_portable) {
return i->isPortable();
} else {
return (i->name() == name());
return (i->displayName() == displayName());
}
}
@@ -822,7 +822,7 @@ SetupInstanceResults selectGame(Instance& instance, PluginContainer& pc)
CreateInstanceDialog dlg(pc, nullptr);
// only show the game page
dlg.setSinglePage<cid::GamePage>(instance.name());
dlg.setSinglePage<cid::GamePage>(instance.displayName());
dlg.show();
dlg.activateWindow();
@@ -860,7 +860,7 @@ SetupInstanceResults selectVariant(Instance& instance, PluginContainer& pc)
instance.gamePlugin(), instance.gameDirectory());
// only show the variant page
dlg.setSinglePage<cid::VariantsPage>(instance.name());
dlg.setSinglePage<cid::VariantsPage>(instance.displayName());
dlg.show();
dlg.activateWindow();
@@ -897,7 +897,7 @@ SetupInstanceResults setupInstance(Instance& instance, PluginContainer& pc)
reportError(
QObject::tr("Cannot open instance '%1', failed to read INI file %2.")
.arg(instance.name()).arg(instance.iniPath()));
.arg(instance.displayName()).arg(instance.iniPath()));
return SetupInstanceResults::SelectAnother;
}
@@ -914,7 +914,7 @@ SetupInstanceResults setupInstance(Instance& instance, PluginContainer& pc)
QObject::tr(
"Cannot open instance '%1', the managed game was not found in the INI "
"file %2. Select the game managed by this instance.")
.arg(instance.name()).arg(instance.iniPath()));
.arg(instance.displayName()).arg(instance.iniPath()));
return selectGame(instance, pc);
}
@@ -928,7 +928,7 @@ SetupInstanceResults setupInstance(Instance& instance, PluginContainer& pc)
QObject::tr(
"Cannot open instance '%1', the game plugin '%2' doesn't exist. It "
"may have been deleted by an antivirus. Select another instance.")
.arg(instance.name()).arg(instance.gameName()));
.arg(instance.displayName()).arg(instance.gameName()));
return SetupInstanceResults::SelectAnother;
}
@@ -943,7 +943,7 @@ SetupInstanceResults setupInstance(Instance& instance, PluginContainer& pc)
"Cannot open instance '%1', the game directory '%2' doesn't exist or "
"the game plugin '%3' doesn't recognize it. Select the game managed "
"by this instance.")
.arg(instance.name())
.arg(instance.displayName())
.arg(instance.gameDirectory())
.arg(instance.gameName()));
+6 -1
View File
@@ -132,9 +132,14 @@ public:
// returns the instance name; this is the directory name or "Portable" for
// portable instances
//
// be careful when using this function to check whether two instances are the
// same, some parts of MO use an empty string to represent portable instances,
// but this function will return "Portable" for them; it's safer to check
// for isPortable() first
//
// can be called without setup()
//
QString name() const;
QString displayName() const;
// returns either:
// 1) the game name from the INI, if readFromIni() was called;
+8 -8
View File
@@ -221,7 +221,7 @@ void InstanceManagerDialog::updateInstances()
// sort first, prepend portable after so it's always on top
std::sort(m_instances.begin(), m_instances.end(), [](auto&& a, auto&& b) {
return (MOBase::naturalCompare(a->name(), b->name()) < 0);
return (MOBase::naturalCompare(a->displayName(), b->displayName()) < 0);
});
if (m.portableInstanceExists()) {
@@ -249,7 +249,7 @@ void InstanceManagerDialog::updateList()
for (std::size_t i=0; i<m_instances.size(); ++i) {
const auto& ii = *m_instances[i];
auto* item = new QStandardItem(ii.name());
auto* item = new QStandardItem(ii.displayName());
item->setIcon(instanceIcon(m_pc, ii));
m_model->appendRow(item);
@@ -295,7 +295,7 @@ void InstanceManagerDialog::select(std::size_t i)
void InstanceManagerDialog::select(const QString& name)
{
for (std::size_t i=0; i<m_instances.size(); ++i) {
if (m_instances[i]->name() == name) {
if (m_instances[i]->displayName() == name) {
select(i);
return;
}
@@ -310,7 +310,7 @@ void InstanceManagerDialog::selectActiveInstance()
if (active) {
for (std::size_t i=0; i<m_instances.size(); ++i) {
if (m_instances[i]->name() == active->name()) {
if (m_instances[i]->displayName() == active->displayName()) {
select(i);
ui->list->scrollTo(
@@ -340,7 +340,7 @@ void InstanceManagerDialog::openSelectedInstance()
if (to.isPortable()) {
InstanceManager::singleton().setCurrentInstance("");
} else {
InstanceManager::singleton().setCurrentInstance(to.name());
InstanceManager::singleton().setCurrentInstance(to.displayName());
}
if (m_restartOnSelect) {
@@ -372,7 +372,7 @@ bool InstanceManagerDialog::confirmSwitch(const Instance& to)
const auto r = dlg
.title(tr("Switching instances"))
.main(tr("Mod Organizer must restart to manage the instance '%1'.")
.arg(to.name()))
.arg(to.displayName()))
.content(tr("This confirmation can be disabled in the settings."))
.icon(QMessageBox::Question)
.button({tr("Restart Mod Organizer"), QMessageBox::Ok})
@@ -401,7 +401,7 @@ void InstanceManagerDialog::rename()
// getting new name
const auto newName = getInstanceName(
this, tr("Rename instance"), "", tr("Instance name"), i->name());
this, tr("Rename instance"), "", tr("Instance name"), i->displayName());
if (newName.isEmpty()) {
return;
@@ -661,7 +661,7 @@ const Instance* InstanceManagerDialog::singleSelection() const
void InstanceManagerDialog::fillData(const Instance& ii)
{
ui->name->setText(ii.name());
ui->name->setText(ii.displayName());
ui->location->setText(ii.directory());
ui->baseDirectory->setText(ii.baseDirectory());
ui->gameName->setText(ii.gameName());
+1 -5
View File
@@ -2951,7 +2951,6 @@ void MainWindow::nxmModInfoAvailable(QString gameName, int modID, QVariant userD
}
std::vector<ModInfo::Ptr> modsList = ModInfo::getByModID(gameNameReal, modID);
for (auto mod : modsList) {
bool foundUpdate = false;
QDateTime now = QDateTime::currentDateTimeUtc();
QDateTime updateTarget = mod->getExpires();
if (now >= updateTarget) {
@@ -2959,7 +2958,6 @@ void MainWindow::nxmModInfoAvailable(QString gameName, int modID, QVariant userD
// with an older version than the main mod version.
if (mod->getNexusFileStatus() != 3 && mod->getNexusFileStatus() != 5) {
mod->setNewestVersion(result["version"].toString());
foundUpdate = true;
}
// update the LastNexusUpdate time in any case since we did perform the check.
mod->setLastNexusUpdate(QDateTime::currentDateTimeUtc());
@@ -2979,9 +2977,7 @@ void MainWindow::nxmModInfoAvailable(QString gameName, int modID, QVariant userD
mod->setNexusLastModified(QDateTime::fromSecsSinceEpoch(result["updated_timestamp"].toInt(), Qt::UTC));
mod->saveMeta();
if (foundUpdate) {
m_OrganizerCore.modList()->notifyChange(ModInfo::getIndex(mod->name()));
}
m_OrganizerCore.modList()->notifyChange(ModInfo::getIndex(mod->name()));
}
}
+10 -6
View File
@@ -392,10 +392,14 @@ void MOApplication::externalMessage(const QString& message)
if (moshortcut.isValid()) {
if(moshortcut.hasExecutable()) {
m_core->processRunner()
.setFromShortcut(moshortcut)
.setWaitForCompletion(ProcessRunner::TriggerRefresh)
.run();
try {
m_core->processRunner()
.setFromShortcut(moshortcut)
.setWaitForCompletion(ProcessRunner::TriggerRefresh)
.run();
} catch(std::exception&) {
// user was already warned
}
}
} else if (isNxmLink(message)) {
MessageDialog::showMessage(tr("Download started"), qApp->activeWindow(), false);
@@ -414,11 +418,11 @@ void MOApplication::externalMessage(const QString& message)
if (auto i=cl.instance()) {
const auto ci = InstanceManager::singleton().currentInstance();
if (*i != ci->name()) {
if (*i != ci->displayName()) {
reportError(tr(
"This shortcut or command line is for instance '%1', but the current "
"instance is '%2'.")
.arg(*i).arg(ci->name()));
.arg(*i).arg(ci->displayName()));
return;
}
-5
View File
@@ -897,11 +897,6 @@ public: // Conflicts
//
virtual const std::set<unsigned int>& getModArchiveLooseOverwritten() const { return s_EmptySet; }
/**
* @brief Update conflict information.
*/
virtual void doConflictCheck() const {}
public slots:
/**
+39 -68
View File
@@ -19,11 +19,11 @@ ModInfoWithConflictInfo::ModInfoWithConflictInfo(OrganizerCore& core) :
m_FileTree([this]() { return QDirFileTree::makeTree(absolutePath()); }),
m_Valid([this]() { return doIsValid(); }),
m_Contents([this]() { return doGetContents(); }),
m_HasLooseOverwrite(false), m_HasHiddenFiles(false) {}
m_Conflicts([this]() { return doConflictCheck(); }) { }
void ModInfoWithConflictInfo::clearCaches()
{
m_LastConflictCheck = QTime();
m_Conflicts.invalidate();
}
std::vector<ModInfo::EFlag> ModInfoWithConflictInfo::getFlags() const
@@ -82,14 +82,9 @@ std::vector<ModInfo::EConflictFlag> ModInfoWithConflictInfo::getConflictFlags()
}
void ModInfoWithConflictInfo::doConflictCheck() const
ModInfoWithConflictInfo::Conflicts ModInfoWithConflictInfo::doConflictCheck() const
{
m_OverwriteList.clear();
m_OverwrittenList.clear();
m_ArchiveOverwriteList.clear();
m_ArchiveOverwrittenList.clear();
m_ArchiveLooseOverwriteList.clear();
m_ArchiveLooseOverwrittenList.clear();
Conflicts conflicts;
bool providesAnything = false;
bool hasHiddenFiles = false;
@@ -102,10 +97,6 @@ void ModInfoWithConflictInfo::doConflictCheck() const
std::wstring name = ToWString(this->name());
const std::wstring hideExt = ToWString(ModInfo::s_HiddenExt);
m_CurrentConflictState = CONFLICT_NONE;
m_ArchiveConflictState = CONFLICT_NONE;
m_ArchiveConflictLooseState = CONFLICT_NONE;
if (m_Core.directoryStructure()->originExists(name)) {
FilesOrigin &origin = m_Core.directoryStructure()->getOriginByName(name);
std::vector<FileEntryPtr> files = origin.getFiles();
@@ -168,12 +159,12 @@ void ModInfoWithConflictInfo::doConflictCheck() const
unsigned int altIndex = ModInfo::getIndex(ToQString(altOrigin.getName()));
if (!file->isFromArchive()) {
if (!archiveData.isValid())
m_OverwrittenList.insert(altIndex);
conflicts.m_OverwrittenList.insert(altIndex);
else
m_ArchiveLooseOverwrittenList.insert(altIndex);
conflicts.m_ArchiveLooseOverwrittenList.insert(altIndex);
}
else {
m_ArchiveOverwrittenList.insert(altIndex);
conflicts.m_ArchiveOverwrittenList.insert(altIndex);
}
} else {
providesAnything = true;
@@ -188,21 +179,21 @@ void ModInfoWithConflictInfo::doConflictCheck() const
if (!altInfo.isFromArchive()) {
if (!archiveData.isValid()) {
if (origin.getPriority() > altOrigin.getPriority()) {
m_OverwriteList.insert(altIndex);
conflicts.m_OverwriteList.insert(altIndex);
} else {
m_OverwrittenList.insert(altIndex);
conflicts.m_OverwrittenList.insert(altIndex);
}
} else {
m_ArchiveLooseOverwrittenList.insert(altIndex);
conflicts.m_ArchiveLooseOverwrittenList.insert(altIndex);
}
} else {
if (!archiveData.isValid()) {
m_ArchiveLooseOverwriteList.insert(altIndex);
conflicts.m_ArchiveLooseOverwriteList.insert(altIndex);
} else {
if (archiveData.order() > altInfo.archive().order()) {
m_ArchiveOverwriteList.insert(altIndex);
conflicts.m_ArchiveOverwriteList.insert(altIndex);
} else if (archiveData.order() < altInfo.archive().order()) {
m_ArchiveOverwrittenList.insert(altIndex);
conflicts.m_ArchiveOverwrittenList.insert(altIndex);
}
}
}
@@ -210,66 +201,51 @@ void ModInfoWithConflictInfo::doConflictCheck() const
}
}
}
m_LastConflictCheck = QTime::currentTime();
if (files.size() != 0) {
if (!providesAnything)
m_CurrentConflictState = CONFLICT_REDUNDANT;
else if (!m_OverwriteList.empty() && !m_OverwrittenList.empty())
m_CurrentConflictState = CONFLICT_MIXED;
else if (!m_OverwriteList.empty())
m_CurrentConflictState = CONFLICT_OVERWRITE;
else if (!m_OverwrittenList.empty())
m_CurrentConflictState = CONFLICT_OVERWRITTEN;
conflicts.m_CurrentConflictState = CONFLICT_REDUNDANT;
else if (!conflicts.m_OverwriteList.empty() && !conflicts.m_OverwrittenList.empty())
conflicts.m_CurrentConflictState = CONFLICT_MIXED;
else if (!conflicts.m_OverwriteList.empty())
conflicts.m_CurrentConflictState = CONFLICT_OVERWRITE;
else if (!conflicts.m_OverwrittenList.empty())
conflicts.m_CurrentConflictState = CONFLICT_OVERWRITTEN;
if (!m_ArchiveOverwriteList.empty() && !m_ArchiveOverwrittenList.empty())
m_ArchiveConflictState = CONFLICT_MIXED;
else if (!m_ArchiveOverwriteList.empty())
m_ArchiveConflictState = CONFLICT_OVERWRITE;
else if (!m_ArchiveOverwrittenList.empty())
m_ArchiveConflictState = CONFLICT_OVERWRITTEN;
if (!conflicts.m_ArchiveOverwriteList.empty() && !conflicts.m_ArchiveOverwrittenList.empty())
conflicts.m_ArchiveConflictState = CONFLICT_MIXED;
else if (!conflicts.m_ArchiveOverwriteList.empty())
conflicts.m_ArchiveConflictState = CONFLICT_OVERWRITE;
else if (!conflicts.m_ArchiveOverwrittenList.empty())
conflicts.m_ArchiveConflictState = CONFLICT_OVERWRITTEN;
if (!m_ArchiveLooseOverwrittenList.empty() && !m_ArchiveLooseOverwriteList.empty())
m_ArchiveConflictLooseState = CONFLICT_MIXED;
else if (!m_ArchiveLooseOverwrittenList.empty())
m_ArchiveConflictLooseState = CONFLICT_OVERWRITTEN;
else if (!m_ArchiveLooseOverwriteList.empty())
m_ArchiveConflictLooseState = CONFLICT_OVERWRITE;
if (!conflicts.m_ArchiveLooseOverwrittenList.empty() && !conflicts.m_ArchiveLooseOverwriteList.empty())
conflicts.m_ArchiveConflictLooseState = CONFLICT_MIXED;
else if (!conflicts.m_ArchiveLooseOverwrittenList.empty())
conflicts.m_ArchiveConflictLooseState = CONFLICT_OVERWRITTEN;
else if (!conflicts.m_ArchiveLooseOverwriteList.empty())
conflicts.m_ArchiveConflictLooseState = CONFLICT_OVERWRITE;
m_HasHiddenFiles = hasHiddenFiles;
conflicts.m_HasHiddenFiles = hasHiddenFiles;
}
}
return conflicts;
}
ModInfoWithConflictInfo::EConflictType ModInfoWithConflictInfo::isConflicted() const
{
// this is costy so cache the result
QTime now = QTime::currentTime();
if (m_LastConflictCheck.isNull() || (m_LastConflictCheck.secsTo(now) > 10)) {
doConflictCheck();
}
return m_CurrentConflictState;
return m_Conflicts.value().m_CurrentConflictState;
}
ModInfoWithConflictInfo::EConflictType ModInfoWithConflictInfo::isArchiveConflicted() const
{
QTime now = QTime::currentTime();
if (m_LastConflictCheck.isNull() || (m_LastConflictCheck.secsTo(now) > 10)) {
doConflictCheck();
}
return m_ArchiveConflictState;
return m_Conflicts.value().m_ArchiveConflictState;
}
ModInfoWithConflictInfo::EConflictType ModInfoWithConflictInfo::isLooseArchiveConflicted() const
{
QTime now = QTime::currentTime();
if (m_LastConflictCheck.isNull() || (m_LastConflictCheck.secsTo(now) > 10)) {
doConflictCheck();
}
return m_ArchiveConflictLooseState;
return m_Conflicts.value().m_ArchiveConflictLooseState;
}
@@ -294,12 +270,7 @@ bool ModInfoWithConflictInfo::isRedundant() const
bool ModInfoWithConflictInfo::hasHiddenFiles() const
{
QTime now = QTime::currentTime();
if (m_LastConflictCheck.isNull() || (m_LastConflictCheck.secsTo(now) > 10)) {
doConflictCheck();
}
return m_HasHiddenFiles;
return m_Conflicts.value().m_HasHiddenFiles;
}
void ModInfoWithConflictInfo::diskContentModified() {
+26 -27
View File
@@ -54,14 +54,12 @@ public:
*/
void clearCaches() override;
const std::set<unsigned int>& getModOverwrite() const override { return m_OverwriteList; }
const std::set<unsigned int>& getModOverwritten() const override { return m_OverwrittenList; }
const std::set<unsigned int>& getModArchiveOverwrite() const override { return m_ArchiveOverwriteList; }
const std::set<unsigned int>& getModArchiveOverwritten() const override { return m_ArchiveOverwrittenList; }
const std::set<unsigned int>& getModArchiveLooseOverwrite() const override { return m_ArchiveLooseOverwriteList; }
const std::set<unsigned int>& getModArchiveLooseOverwritten() const override { return m_ArchiveLooseOverwrittenList; }
void doConflictCheck() const override;
const std::set<unsigned int>& getModOverwrite() const override { return m_Conflicts.value().m_OverwriteList; }
const std::set<unsigned int>& getModOverwritten() const override { return m_Conflicts.value().m_OverwrittenList; }
const std::set<unsigned int>& getModArchiveOverwrite() const override { return m_Conflicts.value().m_ArchiveOverwriteList; }
const std::set<unsigned int>& getModArchiveOverwritten() const override { return m_Conflicts.value().m_ArchiveOverwrittenList; }
const std::set<unsigned int>& getModArchiveLooseOverwrite() const override { return m_Conflicts.value().m_ArchiveLooseOverwriteList; }
const std::set<unsigned int>& getModArchiveLooseOverwritten() const override { return m_Conflicts.value().m_ArchiveLooseOverwrittenList; }
public slots:
@@ -72,11 +70,8 @@ public slots:
protected:
/**
* @brief Check if the content of this mod is valid.
*
* @return true if the content is valid, false otherwise.
**/
// check if the content of this mod is valid
//
virtual bool doIsValid() const;
/**
@@ -136,23 +131,27 @@ protected:
private:
struct Conflicts {
EConflictType m_CurrentConflictState = CONFLICT_NONE;
EConflictType m_ArchiveConflictState = CONFLICT_NONE;
EConflictType m_ArchiveConflictLooseState = CONFLICT_NONE;
bool m_HasLooseOverwrite = false;
bool m_HasHiddenFiles = false;
std::set<unsigned int> m_OverwriteList; // indices of mods overritten by this mod
std::set<unsigned int> m_OverwrittenList; // indices of mods overwriting this mod
std::set<unsigned int> m_ArchiveOverwriteList; // indices of mods with archive files overritten by this mod
std::set<unsigned int> m_ArchiveOverwrittenList; // indices of mods with archive files overwriting this mod
std::set<unsigned int> m_ArchiveLooseOverwriteList; // indices of mods with archives being overwritten by this mod's loose files
std::set<unsigned int> m_ArchiveLooseOverwrittenList; // indices of mods with loose files overwriting this mod's archive files
};
Conflicts doConflictCheck() const;
MOBase::MemoizedLocked<std::shared_ptr<const MOBase::IFileTree>> m_FileTree;
MOBase::MemoizedLocked<bool> m_Valid;
MOBase::MemoizedLocked<std::set<int>> m_Contents;
mutable EConflictType m_CurrentConflictState;
mutable EConflictType m_ArchiveConflictState;
mutable EConflictType m_ArchiveConflictLooseState;
mutable bool m_HasLooseOverwrite;
mutable bool m_HasHiddenFiles;
mutable QTime m_LastConflictCheck;
mutable std::set<unsigned int> m_OverwriteList; // indices of mods overritten by this mod
mutable std::set<unsigned int> m_OverwrittenList; // indices of mods overwriting this mod
mutable std::set<unsigned int> m_ArchiveOverwriteList; // indices of mods with archive files overritten by this mod
mutable std::set<unsigned int> m_ArchiveOverwrittenList; // indices of mods with archive files overwriting this mod
mutable std::set<unsigned int> m_ArchiveLooseOverwriteList; // indices of mods with archives being overwritten by this mod's loose files
mutable std::set<unsigned int> m_ArchiveLooseOverwrittenList; // indices of mods with loose files overwriting this mod's archive files
MOBase::MemoizedLocked<Conflicts> m_Conflicts;
};
+4 -4
View File
@@ -549,7 +549,6 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
m_Profile->setModEnabled(modID, enabled);
m_Modified = true;
m_LastCheck.restart();
emit modStatesChanged({ index });
emit tutorialModlistUpdate();
}
result = true;
@@ -997,11 +996,15 @@ void ModList::notifyModRemoved(QString const& modName) const
void ModList::notifyModStateChanged(QList<unsigned int> modIndices) const
{
QModelIndexList indices;
std::map<QString, IModList::ModStates> mods;
for (auto modIndex : modIndices) {
indices.append(index(modIndex, 0));
ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
mods.emplace(modInfo->name(), state(modIndex));
}
emit modStatesChanged(indices);
m_ModStateChanged(mods);
}
@@ -1404,7 +1407,6 @@ bool ModList::toggleState(const QModelIndexList& indices)
m_Profile->setModsEnabled(modsToEnable, modsToDisable);
emit modStatesChanged(indices);
emit tutorialModlistUpdate();
m_Modified = true;
@@ -1430,6 +1432,4 @@ void ModList::setActive(const QModelIndexList& indices, bool active)
else {
m_Profile->setModsEnabled({}, mods);
}
emit modStatesChanged(indices);
}
+2 -2
View File
@@ -258,11 +258,11 @@ signals:
// the sorting of the list can only be manually changed if the list is sorted by priority
// in which case the move is intended to change the priority of a mod.
//
void modPrioritiesChanged(const QModelIndexList& indices);
void modPrioritiesChanged(const QModelIndexList& indices) const;
// emitted when the state (active/inactive) of one or multiple mods have changed
//
void modStatesChanged(const QModelIndexList& indices);
void modStatesChanged(const QModelIndexList& indices) const;
/**
* @brief emitted when the model wants a text to be displayed by the UI
+4 -1
View File
@@ -689,7 +689,10 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo
connect(m_core, &OrganizerCore::profileChanged, this, &ModListView::onProfileChanged);
connect(core.modList(), &ModList::modPrioritiesChanged, [=](auto&& indices) { onModPrioritiesChanged(indices); });
connect(core.modList(), &ModList::clearOverwrite, [=] { m_actions->clearOverwrite(); });
connect(core.modList(), &ModList::modStatesChanged, [=] { updateModCount(); });
connect(core.modList(), &ModList::modStatesChanged, [=] {
updateModCount();
setOverwriteMarkers(selectionModel()->selectedRows());
});
connect(core.modList(), &ModList::modelReset, [=] { clearOverwriteMarkers(); });
// proxy for various group by
+46 -21
View File
@@ -1,25 +1,5 @@
/*
Copyright (C) 2016 Sebastian Herbord. All rights reserved.
This file is part of Mod Organizer.
Mod Organizer is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Mod Organizer is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "moshortcut.h"
#include "instancemanager.h"
MOShortcut::MOShortcut(const QString& link)
: m_valid(link.startsWith("moshortcut://"))
@@ -41,6 +21,51 @@ MOShortcut::MOShortcut(const QString& link)
}
}
bool MOShortcut::isValid() const
{
return m_valid;
}
bool MOShortcut::hasInstance() const
{
return m_hasInstance;
}
bool MOShortcut::hasExecutable() const
{
return m_hasExecutable;
}
QString MOShortcut::instanceDisplayName() const
{
return (m_instance == "" ? QObject::tr("Portable") : m_instance);
}
const QString& MOShortcut::instanceName() const
{
return m_instance;
}
const QString& MOShortcut::executableName() const
{
return m_executable;
}
bool MOShortcut::isForInstance(const Instance& i) const
{
if (!m_hasInstance) {
// no instance name was specified, so the current one is fine
return true;
}
if (m_instance == "") {
// empty instance name means portable
return i.isPortable();
} else {
return (i.displayName() == m_instance);
}
}
QString MOShortcut::toString() const
{
if (m_hasInstance) {
+27 -6
View File
@@ -3,21 +3,42 @@
#include <QString>
class Instance;
class MOShortcut
{
public:
MOShortcut(const QString& link={});
/// true iff intialized using a valid moshortcut link
bool isValid() const { return m_valid; }
// true if initialized using a valid moshortcut link
//
bool isValid() const;
bool hasInstance() const { return m_hasInstance; }
// whether an instance name was given
//
bool hasInstance() const;
bool hasExecutable() const { return m_hasExecutable; }
// whether an executable name was given
//
bool hasExecutable() const;
const QString& instance() const { return m_instance; }
// name of the instance given, "Portable" for portable; undefined if
// hasInstance() returns false
//
QString instanceDisplayName() const;
const QString& executable() const { return m_executable; }
// name of the instance given, empty for portable; undefined if hasInstance()
// returns false
//
const QString& instanceName() const;
// name of the executable given
//
const QString& executableName() const;
// whether this shortcut is for the given instance
//
bool isForInstance(const Instance& i) const;
QString toString() const;

Some files were not shown because too many files have changed in this diff Show More