mirror of
https://github.com/ModOrganizer2/modorganizer.git
synced 2026-07-27 13:58:24 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee4c364ccc | ||
|
|
607fafa364 | ||
|
|
7dc28b10d9 | ||
|
|
9f0c8c31a6 | ||
|
|
2fe627c261 | ||
|
|
879c37984e | ||
|
|
1cf8a2bfee | ||
|
|
7531a860cf | ||
|
|
31c8415e88 | ||
|
|
48274f3357 | ||
|
|
f486e6fa4e | ||
|
|
9e5a64b545 | ||
|
|
3dd05ff869 | ||
|
|
eba98e8469 | ||
|
|
73418ec616 | ||
|
|
7283e6c3ba | ||
|
|
d179ad01c8 | ||
|
|
04d80bb567 | ||
|
|
595f6eccf6 | ||
|
|
f058125e66 | ||
|
|
7d36bc20d0 |
+3
-3
@@ -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: >-
|
||||
|
||||
@@ -18,6 +18,7 @@ add_filter(NAME src/application GROUPS
|
||||
multiprocess
|
||||
sanitychecks
|
||||
selfupdater
|
||||
updatedialog
|
||||
)
|
||||
|
||||
add_filter(NAME src/browser GROUPS
|
||||
|
||||
+5
-6
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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());
|
||||
|
||||
@@ -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()));
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
/**
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user