Compare commits

...
65 Commits
Author SHA1 Message Date
Mikaël Capelle 8a29bc5110 Bump to 2.4.1 RC2. 2021-03-14 20:08:58 +01:00
Mikaël Capelle 77dbd7ff31 Merge pull request #1465 from Holt59/fix-saves-tab-header
Stretch last section in the Saves tab.
2021-03-14 20:08:30 +01:00
Mikaël Capelle 7fab050adb Stretch last section in the Saves tab. 2021-03-14 20:07:09 +01:00
Mikaël Capelle b547045203 Bump to 2.4.1rc1.1. 2021-03-14 20:00:00 +01:00
Mikaël Capelle fcd2e1473f Merge pull request #1462 from Holt59/fix-stylesheets-qscrollarea
Remove border on QScrollArea from stylesheets.
2021-03-13 16:06:18 +01:00
Mikaël Capelle 287dd6d805 Remove border on QScrollArea from stylesheets. 2021-03-13 16:05:43 +01:00
Mikaël Capelle 717c2ca9cf Bump to 2.4.1rc1 and update translations. 2021-03-12 20:51:46 +01:00
Mikaël Capelle abd1a11768 Merge pull request #1449 from isanae/uilocker-disabled
Disabled uilocker for child dialogs
2021-03-03 18:52:55 +01:00
Mikaël Capelle 34636301ea Merge pull request #1447 from LostDragonist/settings_resize
Add scrollbars to some settings tabs to reduce minimum size
2021-03-03 18:52:46 +01:00
Mikaël Capelle f298ea0ae3 Merge pull request #1443 from Holt59/fix-savegame-name
Display savegame name and filepath in saves tab.
2021-03-03 18:52:28 +01:00
Chris Bessent eee1b4b3f1 Put stylesheet stuff into .ui file instead 2021-03-02 21:20:23 -07:00
isanae 00120605fb don't disable dialogs that are children of other dialogs 2021-03-02 14:41:23 -05:00
Mikaël Capelle 32088b47f1 Merge pull request #1446 from LostDragonist/disabled_plugins
Allow plugins to disable themselves by default
2021-03-02 19:27:24 +01:00
Chris Bessent 726b381ea7 Add scrollbars to some settings tabs to reduce minimum size
The previous minimum size was around 450 x 560px.  At a DPI scaling
of 200%, this means 900 x 1120px which extends off the typical 1080p
screen.  Why is someone using 200% scaling on a 1080p screen?  I have
no clue.

Now, the minimum size is around 450 x 410px for 900 x 820 px at 200%
scaling.  Which works for anything short of a 1376 x 768 screen at
200% scaling which I just don't really care about.
2021-03-02 04:07:46 -07:00
Chris Bessent 071550f7fb Allow plugins to disable themselves by default 2021-03-02 02:41:16 -07:00
Mikaël Capelle f8a50edd0f Merge pull request #1444 from LostDragonist/lockedorder
Fix load order when using locked plugins
2021-03-01 19:21:24 +01:00
Mikaël Capelle 08c7113ecb Merge pull request #1439 from Holt59/fix-downloadlist
Fix download list sorting.
2021-03-01 19:21:15 +01:00
Mikaël Capelle d436fe8cb3 Merge pull request #1442 from Holt59/fix-createempty-mod
Fix priority for 'Create Empty Mod'.
2021-03-01 19:21:06 +01:00
Chris Bessent d5183ebe6b Fix load order when using locked plugins 2021-02-27 18:50:45 -07:00
Mikaël Capelle c72326ee4b Display savegame name and filepath in saves tab. 2021-02-27 12:42:37 +01:00
Mikaël Capelle 75e90f2f3f Fix priority for 'Create Empty Mod'. 2021-02-27 10:36:17 +01:00
Mikaël Capelle be012715f3 Fix download list sorting. 2021-02-26 21:32:39 +01:00
Mikaël Capelle 2b86a14c86 Merge pull request #1437 from Holt59/fix-sendtoseparator
Fix 'Send to separator... ' in descending priority.
2021-02-26 21:12:04 +01:00
Mikaël Capelle c96c01f40e Fix 'Send to separator... ' in descending priority. 2021-02-24 20:07:55 +01:00
Mikaël Capelle d6edc5d6b7 Merge pull request #1433 from Holt59/fix-bycategory-sorting
Fix sorting by priority when grouping by priority.
2021-02-24 18:35:18 +01:00
isanae 4040dc12b7 Merge pull request #1436 from isanae/tutorial-fix
Fix tutorial stuck on mod info dialog
2021-02-24 05:46:48 -05:00
isanae d4fc7c3de1 emit modInfoDisplayed, it's required by the tutorial 2021-02-24 04:57:54 -05:00
Mikaël Capelle 27c4861907 Fix sorting by priority when grouping by priority. 2021-02-23 19:16:18 +01:00
Mikaël Capelle 8decb9df68 Merge pull request #1431 from Holt59/fix-update-filter
Switch back to invalidating filter when receiving mod updates.
2021-02-23 17:23:08 +01:00
Mikaël Capelle 8365f26d83 Merge pull request #1424 from isanae/dl-share
Network shares for envfs
2021-02-23 17:19:53 +01:00
Mikaël Capelle 0ca21d9a5e Merge pull request #1429 from Holt59/fix-stylesheets
Fix stylesheets for 2.4.
2021-02-23 17:19:43 +01:00
Mikaël Capelle f60d0e5ec6 Fix stylesheets for 2.4. 2021-02-23 09:38:52 +01:00
isanae d22d77d921 handle network shares for NtOpenFile()
changed error messages to use formatNtMessage(), which handles NTSTATUS errors
2021-02-22 18:28:07 -05:00
Mikaël Capelle 7084021067 Merge pull request #1418 from Holt59/master
Bump version to 2.4.0 and update translation.
2021-02-21 18:01:12 +01:00
Mikaël Capelle 1dd2acf07f Bump version to 2.4.0 and update translation. 2021-02-21 17:56:44 +01:00
isanae 3fad475013 Merge pull request #1416 from isanae/plugin-blacklist
Broken plugins blacklist
2021-02-21 11:50:32 -05:00
Mikaël Capelle 010a5d80d6 Switch back to invalidating filter when receiving mod updates. 2021-02-21 11:12:16 +01:00
isanae 2bd755743c clarified comment 2021-02-20 12:49:08 -05:00
isanae 9eb1dd0ec0 clearPlugins() must be called to load the blacklist or it will be empty when loadPlugins() runs 2021-02-20 05:03:17 -05:00
isanae e473caf14a Merge pull request #1415 from isanae/master
2.4rc3
2021-02-19 18:23:01 -05:00
isanae 1c87f1d8d4 rc3 2021-02-19 18:21:53 -05:00
Mikaël Capelle bb6cde175a Bump version to 2.4.0. 2021-02-19 20:08:47 +01:00
Mikaël Capelle bd93864ed2 Merge pull request #1409 from isanae/portable-loop
Portable instance loop.
2021-02-13 18:25:39 +01:00
isanae 406d6f28c0 force instance selection when the current instance cannot be used
the problem is that an empty instance name means the portable instance, but MO clears the name when it needs instance selection, which can create a loop if the portable instance can't be used
2021-02-13 07:54:05 -05:00
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
59 changed files with 2603 additions and 1968 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;
}
+2 -2
View File
@@ -226,7 +226,7 @@ bool DownloadList::lessThanPredicate(const QModelIndex &left, const QModelIndex
if ((leftIndex < m_manager.numTotalDownloads())
&& (rightIndex < m_manager.numTotalDownloads())) {
if (left.column() == DownloadList::COL_NAME) {
return m_manager.getFileName(left.row()).compare(m_manager.getFileName(right.row()), Qt::CaseInsensitive) < 0;
return left.data(Qt::DisplayRole).toString().compare(right.data(Qt::DisplayRole).toString(), Qt::CaseInsensitive) < 0;
} else if (left.column() == DownloadList::COL_MODNAME) {
QString leftName, rightName;
@@ -275,7 +275,7 @@ bool DownloadList::lessThanPredicate(const QModelIndex &left, const QModelIndex
if (leftState == rightState)
return m_manager.getFileTime(left.row()) < m_manager.getFileTime(right.row());
else
return leftState > rightState;
return leftState < rightState;
} else if (left.column() == DownloadList::COL_SIZE) {
return m_manager.getFileSize(left.row()) < m_manager.getFileSize(right.row());
} else if (left.column() == DownloadList::COL_FILETIME) {
+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
+23 -5
View File
@@ -232,8 +232,8 @@ void forEachEntryImpl(
if (status < 0) {
log::error(
"NtOpenFile() failed for '{}', {}",
toString(poa), formatSystemMessage(status));
"failed to open directory '{}': {}",
toString(poa), formatNtMessage(status));
return;
}
@@ -264,8 +264,9 @@ void forEachEntryImpl(
break;
} else if (status < 0) {
log::error(
"NtQueryDirectoryFile() failed for '{}', {}",
toString(poa), formatSystemMessage(status));
"failed to read directory '{}': {}",
toString(poa), formatNtMessage(status));
break;
}
@@ -321,6 +322,23 @@ void forEachEntryImpl(
}
}
std::wstring makeNtPath(const std::wstring& path)
{
constexpr const wchar_t* nt_prefix = L"\\??\\";
constexpr const wchar_t* nt_unc_prefix = L"\\??\\UNC\\";
constexpr const wchar_t* share_prefix = L"\\\\";
if (path.starts_with(nt_prefix)) {
// already an nt path
return path;
} else if (path.starts_with(share_prefix)) {
// network shared need \??\UNC\ as a prefix
return nt_unc_prefix + path.substr(2);
} else {
// prepend the \??\ prefix
return nt_prefix + path;
}
}
void DirectoryWalker::forEachEntry(
const std::wstring& path, void* cx,
@@ -335,7 +353,7 @@ void DirectoryWalker::forEachEntry(
NtClose = (NtClose_type)::GetProcAddress(m.get(), "NtClose");
}
const std::wstring ntpath = std::wstring(L"\\??\\") + path;
const std::wstring ntpath = makeNtPath(path);
UNICODE_STRING ObjectName = {};
ObjectName.Buffer = const_cast<wchar_t*>(ntpath.c_str());
+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());
+7 -2
View File
@@ -80,7 +80,8 @@ int run(int argc, char *argv[])
// stuff that's done only once, even if MO restarts in the loop below
app.firstTimeSetup(multiProcess);
// force the "Select instance" dialog on startup (only for first loop)
// force the "Select instance" dialog on startup, only for first loop or when
// the current instance cannot be used
bool pick = cl.pick();
// MO runs in a loop because it can be restarted in several ways, such as
@@ -105,13 +106,17 @@ int run(int argc, char *argv[])
const auto r = app.setup(multiProcess, pick);
pick = false;
if (r == RestartExitCode) {
if (r == RestartExitCode || r == ReselectExitCode) {
// resets things when MO is "restarted"
app.resetForRestart();
// don't reprocess command line
cl.clear();
if (r == ReselectExitCode) {
pick = true;
}
continue;
} else if (r != 0) {
// something failed, quit
+23 -25
View File
@@ -351,6 +351,7 @@ MainWindow::MainWindow(Settings &settings
}
settings.geometry().restoreState(ui->downloadView->header());
settings.geometry().restoreState(ui->savegameList->header());
ui->splitter->setStretchFactor(0, 3);
ui->splitter->setStretchFactor(1, 2);
@@ -512,6 +513,8 @@ void MainWindow::setupModList()
connect(&ui->modList->actions(), &ModListViewActions::overwriteCleared, [=]() { scheduleCheckForProblems(); });
connect(&ui->modList->actions(), &ModListViewActions::originModified, this, &MainWindow::originModified);
connect(&ui->modList->actions(), &ModListViewActions::modInfoDisplayed, this, &MainWindow::modInfoDisplayed);
connect(m_OrganizerCore.modList(), &ModList::modPrioritiesChanged, [&]() { m_ArchiveListWriter.write(); });
}
@@ -2003,6 +2006,7 @@ void MainWindow::storeSettings()
s.geometry().saveState(ui->espList->header());
s.geometry().saveState(ui->downloadView->header());
s.geometry().saveState(ui->savegameList->header());
s.widgets().saveIndex(ui->executablesListBox);
s.widgets().saveIndex(ui->tabWidget);
@@ -2819,41 +2823,37 @@ void MainWindow::nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVa
}
QVariantList resultList = resultData.toList();
QFutureWatcher<std::pair<QString, std::set<QSharedPointer<ModInfo>>>> *watcher = new QFutureWatcher<std::pair<QString, std::set<QSharedPointer<ModInfo>>>>();
QObject::connect(watcher, &QFutureWatcher<std::set<QSharedPointer<ModInfo>>>::finished, this, &MainWindow::finishUpdateInfo);
QFuture<std::pair<QString, std::set<QSharedPointer<ModInfo>>>> future = QtConcurrent::run([=]() -> std::pair<QString, std::set<QSharedPointer<ModInfo>>> {
return std::make_pair(gameNameReal, ModInfo::filteredMods(gameNameReal, resultList, userData.toBool(), true));
auto* watcher = new QFutureWatcher<NxmUpdateInfoData>();
QObject::connect(watcher, &QFutureWatcher<NxmUpdateInfoData>::finished, [this, watcher]() {
finishUpdateInfo(watcher->result());
watcher->deleteLater();
});
auto future = QtConcurrent::run([=]() {
return NxmUpdateInfoData{ gameNameReal, ModInfo::filteredMods(gameNameReal, resultList, userData.toBool(), true) };
});
watcher->setFuture(future);
ui->modList->invalidateFilter();
}
void MainWindow::finishUpdateInfo()
void MainWindow::finishUpdateInfo(const NxmUpdateInfoData& data)
{
QFutureWatcher<std::pair<QString, std::set<QSharedPointer<ModInfo>>>> *watcher = static_cast<QFutureWatcher<std::pair<QString, std::set<QSharedPointer<ModInfo>>>> *>(sender());
QString game = watcher->result().first;
auto finalMods = watcher->result().second;
if (finalMods.empty()) {
log::info("{}", tr("None of your %1 mods appear to have had recent file updates.").arg(game));
if (data.finalMods.empty()) {
log::info("{}", tr("None of your %1 mods appear to have had recent file updates.").arg(data.game));
}
std::set<std::pair<QString, int>> organizedGames;
for (auto mod : finalMods) {
for (auto& mod : data.finalMods) {
if (mod->canBeUpdated()) {
organizedGames.insert(std::make_pair<QString, int>(mod->gameName().toLower(), mod->nexusId()));
}
m_OrganizerCore.modList()->notifyChange(ModInfo::getIndex(mod->name()));
}
if (!finalMods.empty() && organizedGames.empty())
if (!data.finalMods.empty() && organizedGames.empty())
log::warn("{}", tr("All of your mods have been checked recently. We restrict update checks to help preserve your available API requests."));
for (auto game : organizedGames)
for (const auto& game : organizedGames) {
NexusInterface::instance().requestUpdates(game.second, this, QVariant(), game.first, QString());
disconnect(sender());
delete sender();
}
}
void MainWindow::nxmUpdatesAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID)
@@ -2928,13 +2928,15 @@ void MainWindow::nxmUpdatesAvailable(QString gameName, int modID, QVariant userD
if (foundUpdate) {
// Just get the standard data updates for endorsements and descriptions
mod->setLastNexusUpdate(QDateTime::currentDateTimeUtc());
m_OrganizerCore.modList()->notifyChange(ModInfo::getIndex(mod->name()));
} else {
// Scrape mod data here so we can use the mod version if no file update was located
requiresInfo = true;
}
}
// invalidate the filter to display mods with an update
ui->modList->invalidateFilter();
if (requiresInfo)
NexusInterface::instance().requestModInfo(gameNameReal, modID, this, QVariant(), QString());
}
@@ -2951,7 +2953,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 +2960,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 +2979,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()));
}
}
+12 -2
View File
@@ -143,6 +143,9 @@ public slots:
void refresherProgress(const DirectoryRefreshProgress* p);
signals:
// emitted after the information dialog has been closed, used by tutorials
//
void modInfoDisplayed();
/**
* @brief emitted when the selected style changes
@@ -224,6 +227,13 @@ private:
void toggleMO2EndorseState();
void toggleUpdateAction();
// update info
struct NxmUpdateInfoData {
QString game;
std::set<ModInfo::Ptr> finalMods;
};
void finishUpdateInfo(const NxmUpdateInfoData& data);
private:
static const char *PATTERN_BACKUP_GLOB;
@@ -331,10 +341,10 @@ private slots:
void modInstalled(const QString &modName);
void finishUpdateInfo();
// update info
void nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVariant resultData, int requestID);
void nxmEndorsementsAvailable(QVariant userData, QVariant resultData, int);
void nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVariant resultData, int requestID);
void nxmUpdatesAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID);
void nxmModInfoAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID);
void nxmEndorsementToggled(QString, int, QVariant, QVariant resultData, int);
+39 -2
View File
@@ -1199,7 +1199,7 @@ p, li { white-space: pre-wrap; }
<number>0</number>
</property>
<item>
<widget class="QListWidget" name="savegameList">
<widget class="QTreeWidget" name="savegameList">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
@@ -1215,6 +1215,9 @@ p, li { white-space: pre-wrap; }
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;If you click &amp;quot;Fix Mods...&amp;quot; in the context menu, MO will try to activate all mods and esps to fix those missing esps. It will not disable anything!&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustIgnored</enum>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
@@ -1224,9 +1227,43 @@ p, li { white-space: pre-wrap; }
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="uniformItemSizes">
<property name="indentation">
<number>0</number>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>false</bool>
</property>
<property name="columnCount">
<number>2</number>
</property>
<attribute name="headerCascadingSectionResizes">
<bool>false</bool>
</attribute>
<attribute name="headerStretchLastSection">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string>Name</string>
</property>
<property name="textAlignment">
<set>AlignLeading|AlignVCenter</set>
</property>
</column>
<column>
<property name="text">
<string>File</string>
</property>
<property name="textAlignment">
<set>AlignLeading|AlignVCenter</set>
</property>
</column>
</widget>
</item>
</layout>
+11 -7
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;
}
@@ -488,7 +492,7 @@ std::optional<int> MOApplication::setupInstanceLoop(
continue;
} else if (setupResult == SetupInstanceResults::SelectAnother) {
InstanceManager::singleton().clearCurrentInstance();
return RestartExitCode;
return ReselectExitCode;
} else {
return 1;
}
-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;
};

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