void Profile::dumpModStatus() const { for (unsigned int i = 0; i < m_ModStatus.size(); ++i) { ModInfo::Ptr info = ModInfo::getByIndex(i); qWarning("%d: %s - %d (%s)", i, info->name().toUtf8().constData(), m_ModStatus[i].m_Priority, m_ModStatus[i].m_Enabled ? "enabled" : "disabled"); } }
void OverwriteInfoDialog::setModInfo(ModInfo::Ptr modInfo) { m_ModInfo = modInfo; if (QDir(modInfo->absolutePath()).exists()) { m_FileSystemModel->setRootPath(modInfo->absolutePath()); } else { throw MyException(tr("%1 not found").arg(modInfo->absolutePath())); } }
void DirectoryRefresher::setMods(const std::vector<std::tuple<QString, QString, int> > &mods , const std::set<QString> &managedArchives) { QMutexLocker locker(&m_RefreshLock); m_Mods.clear(); for (auto mod = mods.begin(); mod != mods.end(); ++mod) { QString name = std::get<0>(*mod); ModInfo::Ptr info = ModInfo::getByIndex(ModInfo::getIndex(name)); m_Mods.push_back(EntryInfo(name, std::get<1>(*mod), info->stealFiles(), info->archives(), std::get<2>(*mod))); } m_EnabledArchives = managedArchives; }
size_t ModFlagIconDelegate::getNumIcons(const QModelIndex &index) const { unsigned int modIdx = index.data(Qt::UserRole + 1).toInt(); if (modIdx < ModInfo::getNumMods()) { ModInfo::Ptr info = ModInfo::getByIndex(modIdx); std::vector<ModInfo::EFlag> flags = info->getFlags(); int count = flags.size(); if (std::find_first_of(flags.begin(), flags.end(), m_ConflictFlags, m_ConflictFlags + 4) == flags.end()) { ++count; } return count; } else { return 0; } }
void Profile::mergeTweaks(ModInfo::Ptr modInfo, const QString &tweakedIni) const { std::vector<QString> iniTweaks = modInfo->getIniTweaks(); for (std::vector<QString>::iterator iter = iniTweaks.begin(); iter != iniTweaks.end(); ++iter) { mergeTweak(*iter, tweakedIni); } }
void Profile::setModEnabled(unsigned int index, bool enabled) { if (index >= m_ModStatus.size()) { throw MyException(tr("invalid index %1").arg(index)); } ModInfo::Ptr modInfo = ModInfo::getByIndex(index); // we could quit in the following case, this shouldn't be a change anyway, // but at least this allows the situation to be fixed in case of an error if (modInfo->alwaysEnabled()) { enabled = true; } if (enabled != m_ModStatus[index].m_Enabled) { m_ModStatus[index].m_Enabled = enabled; emit modStatusChanged(index); } }
void Profile::writeModlistNow() { if (!m_Directory.exists()) return; try { QString fileName = getModlistFileName(); SafeWriteFile file(fileName); file->write(QString("# This file was automatically generated by Mod Organizer.\r\n").toUtf8()); if (m_ModStatus.empty()) { return; } for (int i = m_ModStatus.size() - 1; i >= 0; --i) { // the priority order was inverted on load so it has to be inverted again unsigned int index = m_ModIndexByPriority[i]; if (index != UINT_MAX) { ModInfo::Ptr modInfo = ModInfo::getByIndex(index); std::vector<ModInfo::EFlag> flags = modInfo->getFlags(); if ((modInfo->getFixedPriority() == INT_MIN)) { if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_FOREIGN) != flags.end()) { file->write("*"); } else if (m_ModStatus[index].m_Enabled) { file->write("+"); } else { file->write("-"); } file->write(modInfo->name().toUtf8()); file->write("\r\n"); } } } if (file.commitIfDifferent(m_LastModlistHash)) { qDebug("%s saved", QDir::toNativeSeparators(fileName).toUtf8().constData()); } } catch (const std::exception &e) { reportError(tr("failed to write mod list: %1").arg(e.what())); return; } }
bool ModListSortProxy::filterMatchesMod(ModInfo::Ptr info, bool enabled) const { if (!m_CurrentFilter.isEmpty() && !info->name().contains(m_CurrentFilter, Qt::CaseInsensitive)) { return false; } if (m_FilterMode == FILTER_AND) { return filterMatchesModAnd(info, enabled); } else { return filterMatchesModOr(info, enabled); } }
QList<QString> ModFlagIconDelegate::getIcons(const QModelIndex &index) const { QList<QString> result; QVariant modid = index.data(Qt::UserRole + 1); if (modid.isValid()) { ModInfo::Ptr info = ModInfo::getByIndex(modid.toInt()); std::vector<ModInfo::EFlag> flags = info->getFlags(); { // insert conflict icon first to provide nicer alignment auto iter = std::find_first_of(flags.begin(), flags.end(), m_ConflictFlags, m_ConflictFlags + 4); if (iter != flags.end()) { result.append(getFlagIcon(*iter)); flags.erase(iter); } else { result.append(QString()); } } for (auto iter = flags.begin(); iter != flags.end(); ++iter) { result.append(getFlagIcon(*iter)); } } return result; }
OverwriteInfoDialog::OverwriteInfoDialog(ModInfo::Ptr modInfo, QWidget *parent) : QDialog(parent), ui(new Ui::OverwriteInfoDialog), m_FileSystemModel(nullptr), m_DeleteAction(nullptr), m_RenameAction(nullptr), m_OpenAction(nullptr) { ui->setupUi(this); this->setWindowModality(Qt::NonModal); m_FileSystemModel = new MyFileSystemModel(this); m_FileSystemModel->setReadOnly(false); setModInfo(modInfo); ui->filesView->setModel(m_FileSystemModel); ui->filesView->setRootIndex(m_FileSystemModel->index(modInfo->absolutePath())); ui->filesView->setColumnWidth(0, 250); m_DeleteAction = new QAction(tr("&Delete"), ui->filesView); m_RenameAction = new QAction(tr("&Rename"), ui->filesView); m_OpenAction = new QAction(tr("&Open"), ui->filesView); m_NewFolderAction = new QAction(tr("&New Folder"), ui->filesView); QObject::connect(m_DeleteAction, SIGNAL(triggered()), this, SLOT(deleteTriggered())); QObject::connect(m_RenameAction, SIGNAL(triggered()), this, SLOT(renameTriggered())); QObject::connect(m_OpenAction, SIGNAL(triggered()), this, SLOT(openTriggered())); QObject::connect(m_NewFolderAction, SIGNAL(triggered()), this, SLOT(createDirectoryTriggered())); }
std::vector<std::tuple<QString, QString, int> > Profile::getActiveMods() { std::vector<std::tuple<QString, QString, int> > result; for (std::vector<unsigned int>::const_iterator iter = m_ModIndexByPriority.begin(); iter != m_ModIndexByPriority.end(); ++iter) { if ((*iter != UINT_MAX) && m_ModStatus[*iter].m_Enabled) { ModInfo::Ptr modInfo = ModInfo::getByIndex(*iter); result.push_back(std::make_tuple(modInfo->internalName(), modInfo->absolutePath(), m_ModStatus[*iter].m_Priority)); } } unsigned int overwriteIndex = ModInfo::findMod([](ModInfo::Ptr mod) -> bool { std::vector<ModInfo::EFlag> flags = mod->getFlags(); return std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end(); }); if (overwriteIndex != UINT_MAX) { ModInfo::Ptr overwriteInfo = ModInfo::getByIndex(overwriteIndex); result.push_back(std::make_tuple(overwriteInfo->name(), overwriteInfo->absolutePath(), UINT_MAX)); } else { reportError(tr("Overwrite directory couldn't be parsed")); } return result; }
void PluginList::refresh(const QString &profileName , const DirectoryEntry &baseDirectory , const QString &pluginsFile , const QString &loadOrderFile , const QString &lockedOrderFile) { ChangeBracket<PluginList> layoutChange(this); m_ESPsByName.clear(); m_ESPsByPriority.clear(); m_ESPs.clear(); QStringList primaryPlugins = m_GamePlugin->primaryPlugins(); m_CurrentProfile = profileName; std::vector<FileEntry::Ptr> files = baseDirectory.getFiles(); for (auto iter = files.begin(); iter != files.end(); ++iter) { FileEntry::Ptr current = *iter; if (current.get() == nullptr) { continue; } QString filename = ToQString(current->getName()); QString extension = filename.right(3).toLower(); if ((extension == "esp") || (extension == "esm")) { bool forceEnabled = Settings::instance().forceEnableCoreFiles() && std::find(primaryPlugins.begin(), primaryPlugins.end(), filename.toLower()) != primaryPlugins.end(); bool archive = false; try { FilesOrigin &origin = baseDirectory.getOriginByID(current->getOrigin(archive)); QString iniPath = QFileInfo(filename).baseName() + ".ini"; bool hasIni = baseDirectory.findFile(ToWString(iniPath)).get() != nullptr; QString originName = ToQString(origin.getName()); unsigned int modIndex = ModInfo::getIndex(originName); if (modIndex != UINT_MAX) { ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); originName = modInfo->name(); } m_ESPs.push_back(ESPInfo(filename, forceEnabled, originName, ToQString(current->getFullPath()), hasIni)); } catch (const std::exception &e) { reportError(tr("failed to update esp info for file %1 (source id: %2), error: %3").arg(filename).arg(current->getOrigin(archive)).arg(e.what())); } } } if (readLoadOrder(loadOrderFile)) { int maxPriority = 0; // assign known load orders for (std::vector<ESPInfo>::iterator espIter = m_ESPs.begin(); espIter != m_ESPs.end(); ++espIter) { std::map<QString, int>::const_iterator priorityIter = m_ESPLoadOrder.find(espIter->m_Name.toLower()); if (priorityIter != m_ESPLoadOrder.end()) { if (priorityIter->second > maxPriority) { maxPriority = priorityIter->second; } espIter->m_Priority = priorityIter->second; } else { espIter->m_Priority = -1; } } ++maxPriority; // assign maximum priorities for plugins with unknown priority for (std::vector<ESPInfo>::iterator espIter = m_ESPs.begin(); espIter != m_ESPs.end(); ++espIter) { if (espIter->m_Priority == -1) { espIter->m_Priority = maxPriority++; } } } else { // no load order stored, determine by date std::sort(m_ESPs.begin(), m_ESPs.end(), ByDate); for (size_t i = 0; i < m_ESPs.size(); ++i) { m_ESPs[i].m_Priority = i; } } std::sort(m_ESPs.begin(), m_ESPs.end(), ByPriority); // first, sort by priority // remove gaps from the priorities so we can use them as array indices without overflow for (int i = 0; i < static_cast<int>(m_ESPs.size()); ++i) { m_ESPs[i].m_Priority = i; } std::sort(m_ESPs.begin(), m_ESPs.end(), ByName); // sort by name so alphabetical sorting works updateIndices(); readEnabledFrom(pluginsFile); readLockedOrderFrom(lockedOrderFile); layoutChange.finish(); refreshLoadOrder(); emit dataChanged(this->index(0, 0), this->index(m_ESPs.size(), columnCount())); m_Refreshed(); }
void Profile::refreshModStatus() { QFile file(getModlistFileName()); if (!file.open(QIODevice::ReadOnly)) { throw MyException(tr("\"%1\" is missing or inaccessible").arg(getModlistFileName())); } bool modStatusModified = false; m_ModStatus.clear(); m_ModStatus.resize(ModInfo::getNumMods()); std::set<QString> namesRead; // load mods from file and update enabled state and priority for them int index = 0; while (!file.atEnd()) { QByteArray line = file.readLine().trimmed(); bool enabled = true; QString modName; if (line.length() == 0) { // empty line continue; } else if (line.at(0) == '#') { // comment line continue; } else if (line.at(0) == '-') { enabled = false; modName = QString::fromUtf8(line.mid(1).trimmed().constData()); } else if ((line.at(0) == '+') || (line.at(0) == '*')) { modName = QString::fromUtf8(line.mid(1).trimmed().constData()); } else { modName = QString::fromUtf8(line.trimmed().constData()); } if (modName.size() > 0) { QString lookupName = modName; if (namesRead.find(lookupName) != namesRead.end()) { continue; } else { namesRead.insert(lookupName); } unsigned int modIndex = ModInfo::getIndex(lookupName); if (modIndex != UINT_MAX) { ModInfo::Ptr info = ModInfo::getByIndex(modIndex); if ((modIndex < m_ModStatus.size()) && (info->getFixedPriority() == INT_MIN)) { m_ModStatus[modIndex].m_Enabled = enabled; if (m_ModStatus[modIndex].m_Priority == -1) { if (static_cast<size_t>(index) >= m_ModStatus.size()) { throw MyException(tr("invalid index %1").arg(index)); } m_ModStatus[modIndex].m_Priority = index++; } } else { qWarning("no mod state for \"%s\" (profile \"%s\")", qPrintable(modName), m_Directory.path().toUtf8().constData()); // need to rewrite the modlist to fix this modStatusModified = true; } } else { qDebug("mod \"%s\" (profile \"%s\") not found", qPrintable(modName), m_Directory.path().toUtf8().constData()); // need to rewrite the modlist to fix this modStatusModified = true; } } } int numKnownMods = index; int topInsert = 0; // invert priority order to match that of the pluginlist. Also // give priorities to mods not referenced in the profile for (size_t i = 0; i < m_ModStatus.size(); ++i) { ModInfo::Ptr modInfo = ModInfo::getByIndex(i); if (modInfo->alwaysEnabled()) { m_ModStatus[i].m_Enabled = true; } if (modInfo->getFixedPriority() == INT_MAX) { continue; } if (m_ModStatus[i].m_Priority != -1) { m_ModStatus[i].m_Priority = numKnownMods - m_ModStatus[i].m_Priority - 1; } else { if (static_cast<size_t>(index) >= m_ModStatus.size()) { throw MyException(tr("invalid index %1").arg(index)); } if (modInfo->hasFlag(ModInfo::FLAG_FOREIGN)) { m_ModStatus[i].m_Priority = --topInsert; } else { m_ModStatus[i].m_Priority = index++; } // also, mark the mod-list as changed modStatusModified = true; } } // to support insertion of new mods at the top we may now have mods with negative priority. shift them all up // to align priority with 0 if (topInsert < 0) { int offset = topInsert * -1; for (size_t i = 0; i < m_ModStatus.size(); ++i) { ModInfo::Ptr modInfo = ModInfo::getByIndex(i); if (modInfo->getFixedPriority() == INT_MAX) { continue; } m_ModStatus[i].m_Priority += offset; } } file.close(); updateIndices(); if (modStatusModified) { m_ModListWriter.write(); } }
bool ModListSortProxy::filterMatchesModOr(ModInfo::Ptr info, bool enabled) const { for (auto iter = m_CategoryFilter.begin(); iter != m_CategoryFilter.end(); ++iter) { switch (*iter) { case CategoryFactory::CATEGORY_SPECIAL_CHECKED: { if (enabled || info->alwaysEnabled()) return true; } break; case CategoryFactory::CATEGORY_SPECIAL_UNCHECKED: { if (!enabled && !info->alwaysEnabled()) return true; } break; case CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE: { if (info->updateAvailable() || info->downgradeAvailable()) return true; } break; case CategoryFactory::CATEGORY_SPECIAL_NOCATEGORY: { if (info->getCategories().size() == 0) return true; } break; case CategoryFactory::CATEGORY_SPECIAL_CONFLICT: { if (hasConflictFlag(info->getFlags())) return true; } break; case CategoryFactory::CATEGORY_SPECIAL_NOTENDORSED: { ModInfo::EEndorsedState state = info->endorsedState(); if ((state == ModInfo::ENDORSED_FALSE) || (state == ModInfo::ENDORSED_NEVER)) return true; } break; case CategoryFactory::CATEGORY_SPECIAL_MANAGED: { if (!info->hasFlag(ModInfo::FLAG_FOREIGN)) return true; } break; case CategoryFactory::CATEGORY_SPECIAL_UNMANAGED: { if (info->hasFlag(ModInfo::FLAG_FOREIGN)) return true; } break; default: { if (info->categorySet(*iter)) return true; } break; } } foreach (int content, m_ContentFilter) { if (info->hasContent(static_cast<ModInfo::EContent>(content))) return true; } return false; }
bool ModListSortProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const { if (sourceModel()->hasChildren(left) || sourceModel()->hasChildren(right)) { return QSortFilterProxyModel::lessThan(left, right); } bool lOk, rOk; int leftIndex = left.data(Qt::UserRole + 1).toInt(&lOk); int rightIndex = right.data(Qt::UserRole + 1).toInt(&rOk); if (!lOk || !rOk) { return false; } ModInfo::Ptr leftMod = ModInfo::getByIndex(leftIndex); ModInfo::Ptr rightMod = ModInfo::getByIndex(rightIndex); bool lt = false; { QModelIndex leftPrioIdx = left.sibling(left.row(), ModList::COL_PRIORITY); QVariant leftPrio = leftPrioIdx.data(); if (!leftPrio.isValid()) leftPrio = left.data(Qt::UserRole); QModelIndex rightPrioIdx = right.sibling(right.row(), ModList::COL_PRIORITY); QVariant rightPrio = rightPrioIdx.data(); if (!rightPrio.isValid()) rightPrio = right.data(Qt::UserRole); lt = leftPrio.toInt() < rightPrio.toInt(); } switch (left.column()) { case ModList::COL_FLAGS: { std::vector<ModInfo::EFlag> leftFlags = leftMod->getFlags(); std::vector<ModInfo::EFlag> rightFlags = rightMod->getFlags(); if (leftFlags.size() != rightFlags.size()) { lt = leftFlags.size() < rightFlags.size(); } else { lt = flagsId(leftFlags) < flagsId(rightFlags); } } break; case ModList::COL_CONTENT: { std::vector<ModInfo::EContent> lContent = leftMod->getContents(); std::vector<ModInfo::EContent> rContent = rightMod->getContents(); if (lContent.size() != rContent.size()) { lt = lContent.size() < rContent.size(); } int lValue = 0; int rValue = 0; for (ModInfo::EContent content : lContent) { lValue += 2 << (unsigned int)content; } for (ModInfo::EContent content : rContent) { rValue += 2 << (unsigned int)content; } lt = lValue < rValue; } break; case ModList::COL_NAME: { int comp = QString::compare(leftMod->name(), rightMod->name(), Qt::CaseInsensitive); if (comp != 0) lt = comp < 0; } break; case ModList::COL_CATEGORY: { if (leftMod->getPrimaryCategory() != rightMod->getPrimaryCategory()) { if (leftMod->getPrimaryCategory() < 0) lt = false; else if (rightMod->getPrimaryCategory() < 0) lt = true; else { try { CategoryFactory &categories = CategoryFactory::instance(); QString leftCatName = categories.getCategoryName(categories.getCategoryIndex(leftMod->getPrimaryCategory())); QString rightCatName = categories.getCategoryName(categories.getCategoryIndex(rightMod->getPrimaryCategory())); lt = leftCatName < rightCatName; } catch (const std::exception &e) { qCritical("failed to compare categories: %s", e.what()); } } } } break; case ModList::COL_MODID: { if (leftMod->getNexusID() != rightMod->getNexusID()) lt = leftMod->getNexusID() < rightMod->getNexusID(); } break; case ModList::COL_VERSION: { if (leftMod->getVersion() != rightMod->getVersion()) lt = leftMod->getVersion() < rightMod->getVersion(); } break; case ModList::COL_INSTALLTIME: { QDateTime leftTime = left.data().toDateTime(); QDateTime rightTime = right.data().toDateTime(); if (leftTime != rightTime) return leftTime < rightTime; } break; case ModList::COL_PRIORITY: { // nop, already compared by priority } break; } return lt; }