예제 #1
0
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;
  }
}
예제 #5
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);
  }
}
예제 #6
0
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);
  }
}
예제 #7
0
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()));
}
예제 #11
0
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;
}
예제 #12
0
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();
}
예제 #13
0
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;
}