<commit_before>#include <algorithm>
#include <QDir>
#include <QProcess>
#include <QStandardPaths>
#include <QDateTime>
#include "debug.h"
#include "settingsmodel.h"
#include "settingsmodel.h"
#include "repository.h"
#include "installer.h"
#include "modadapter.h"

Repository::Repository(const QString& name, const QString& serverAddress, unsigned port,
                      QString password, RootItem* parent):
    SyncItem(name, parent),
    sync_(parent->sync()),
    serverAddress_(serverAddress),
    port_(port),
    password_(password),
    ready_(true),
    battlEyeEnabled_(true)
{
    DBG << "Created repo name =" << name;
    update();
    if (ticked())
        startUpdates();
}

void Repository::update()
{
    updateEtaAndStatus();
    updateView(this);
}

void Repository::stopUpdates()
{
    DBG;
    for (Mod* mod : mods())
    {
        mod->stopUpdates();
    }
}

void Repository::setBattlEyeEnabled(bool battleEyeEnabled)
{
    battlEyeEnabled_ = battleEyeEnabled;
}

void Repository::startUpdates()
{
    DBG;
    for (Mod* mod : mods())
    {
        mod->startUpdates();
    }
    parentItem()->startUpdateTimers();
}


Repository::~Repository()
{
    DBG << "name =" << name();
    for (Mod* mod : mods())
    {
        removeMod(mod->key());
    }
    RootItem* parent = parentItem();
    parent->removeChild(this);
    parent->rowsChanged();
}

void Repository::processCompletion()
{
    ready_ = true;
    for (Mod* mod : mods())
    {
        mod->processCompletion();
    }
    SettingsModel::setInstallDate(name(), QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000);
}

void Repository::updateView(TreeItem* item, int row)
{
    parentItem()->updateView(item, row);
}

void Repository::changed(bool offline)
{
    for (Mod* mod : mods())
    {
        QMetaObject::invokeMethod(mod, "repositoryChanged",
                                  Qt::QueuedConnection, Q_ARG(bool, offline));
    }
}

void Repository::checkboxClicked(bool offline)
{
    SyncItem::checkboxClicked();
    //FIXME: Is this a crash risk?
    //updateTimer_.stop();
    setStatus("Processing new mods...");
    changed(offline);
    DBG << "checked()=" << ticked();
    update();
    if (!ticked())
        return;

    startUpdates();
}

void Repository::checkboxClicked()
{
    checkboxClicked(false);
}

void Repository::join()
{
    generalLaunch(joinParameters());
}

void Repository::launch()
{
    generalLaunch();
}

void Repository::generalLaunch(const QStringList& extraParams)
{
    QString executable = SettingsModel::arma3Path() + "\\arma3launcher.exe";
    QString steamExecutable = SettingsModel::steamPath() + "\\Steam.exe";
    QStringList arguments;

    //arma3launcher wont start the game with correct parameters
    //if steam isn't running.
    //Create tmp file containing parameters because steam.exe can only pass
    //~1000 characters in parameters
    QString paramsFile = createParFile(modsParameter());
    if (QFileInfo(steamExecutable).exists())
    {
        DBG << "Using params file";
        arguments << "-applaunch" << "107410" << "-par=" + paramsFile;
        executable = steamExecutable;
    }
    else if (modsParameter().size() > 0)
    {
        DBG << "Failsafe activated because parameter file path is incorrect. paramsFile =" << paramsFile;
        arguments << modsParameter();
    }
    arguments << "-noLauncher";
    if (battlEyeEnabled_)
        arguments << "-useBe";

    if (extraParams.size() > 0)
        arguments << extraParams;

    QString paramsString = SettingsModel::launchParameters();
    if (paramsString.size() > 0)
    {
        QStringList userParams = paramsString.split(" ");
        arguments << userParams;
    }
    DBG << " name() =" << name()
             << "executable =" << executable
             << "arguments =" << arguments;
    QProcess::startDetached(executable, arguments);
}

QString Repository::createParFile(const QString& parameters)
{
    QString fileName = "afiSyncParameters.txt";
    QString path = SettingsModel::arma3Path() + "/" + fileName;
    DBG << path;
    QFile file(path);
    file.remove();
    file.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream fileStream(&file);
    fileStream << parameters;
    file.close();
    return fileName;
}

void Repository::updateEtaAndStatus()
{
    //Eta = max(active_folders) + sum(queued_folders)
    int maxEta = 0;
    int sumEta = 0;
    QSet<QString> modStatuses;
    for (Mod* item : mods())
    {
        if (item->status() == SyncStatus::QUEUED)
        {
            sumEta += item->eta();
        }
        else
        {
            maxEta = std::max(item->eta(), maxEta);
        }
        modStatuses.insert(item->status());
    }
    setEta(maxEta + sumEta);<commit_msg>Fingloid character support in mod paths.<commit_after>#include <algorithm>
#include <QDir>
#include <QProcess>
#include <QStandardPaths>
#include <QDateTime>
#include "debug.h"
#include "settingsmodel.h"
#include "settingsmodel.h"
#include "repository.h"
#include "installer.h"
#include "modadapter.h"

Repository::Repository(const QString& name, const QString& serverAddress, unsigned port,
                      QString password, RootItem* parent):
    SyncItem(name, parent),
    sync_(parent->sync()),
    serverAddress_(serverAddress),
    port_(port),
    password_(password),
    ready_(true),
    battlEyeEnabled_(true)
{
    DBG << "Created repo name =" << name;
    update();
    if (ticked())
        startUpdates();
}

void Repository::update()
{
    updateEtaAndStatus();
    updateView(this);
}

void Repository::stopUpdates()
{
    DBG;
    for (Mod* mod : mods())
    {
        mod->stopUpdates();
    }
}

void Repository::setBattlEyeEnabled(bool battleEyeEnabled)
{
    battlEyeEnabled_ = battleEyeEnabled;
}

void Repository::startUpdates()
{
    DBG;
    for (Mod* mod : mods())
    {
        mod->startUpdates();
    }
    parentItem()->startUpdateTimers();
}


Repository::~Repository()
{
    DBG << "name =" << name();
    for (Mod* mod : mods())
    {
        removeMod(mod->key());
    }
    RootItem* parent = parentItem();
    parent->removeChild(this);
    parent->rowsChanged();
}

void Repository::processCompletion()
{
    ready_ = true;
    for (Mod* mod : mods())
    {
        mod->processCompletion();
    }
    SettingsModel::setInstallDate(name(), QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000);
}

void Repository::updateView(TreeItem* item, int row)
{
    parentItem()->updateView(item, row);
}

void Repository::changed(bool offline)
{
    for (Mod* mod : mods())
    {
        QMetaObject::invokeMethod(mod, "repositoryChanged",
                                  Qt::QueuedConnection, Q_ARG(bool, offline));
    }
}

void Repository::checkboxClicked(bool offline)
{
    SyncItem::checkboxClicked();
    //FIXME: Is this a crash risk?
    //updateTimer_.stop();
    setStatus("Processing new mods...");
    changed(offline);
    DBG << "checked()=" << ticked();
    update();
    if (!ticked())
        return;

    startUpdates();
}

void Repository::checkboxClicked()
{
    checkboxClicked(false);
}

void Repository::join()
{
    generalLaunch(joinParameters());
}

void Repository::launch()
{
    generalLaunch();
}

void Repository::generalLaunch(const QStringList& extraParams)
{
    QString executable = SettingsModel::arma3Path() + "\\arma3launcher.exe";
    QString steamExecutable = SettingsModel::steamPath() + "\\Steam.exe";
    QStringList arguments;

    //arma3launcher wont start the game with correct parameters
    //if steam isn't running.
    //Create tmp file containing parameters because steam.exe can only pass
    //~1000 characters in parameters
    QString paramsFile = createParFile(modsParameter());
    if (QFileInfo(steamExecutable).exists())
    {
        DBG << "Using params file";
        arguments << "-applaunch" << "107410" << "-par=" + paramsFile;
        executable = steamExecutable;
    }
    else if (modsParameter().size() > 0)
    {
        DBG << "Failsafe activated because parameter file path is incorrect. paramsFile =" << paramsFile;
        arguments << modsParameter();
    }
    arguments << "-noLauncher";
    if (battlEyeEnabled_)
        arguments << "-useBe";

    if (extraParams.size() > 0)
        arguments << extraParams;

    QString paramsString = SettingsModel::launchParameters();
    if (paramsString.size() > 0)
    {
        QStringList userParams = paramsString.split(" ");
        arguments << userParams;
    }
    DBG << " name() =" << name()
             << "executable =" << executable
             << "arguments =" << arguments;
    QProcess::startDetached(executable, arguments);
}

QString Repository::createParFile(const QString& parameters)
{
    static const QString FILE_NAME = "afiSyncParameters.txt";

    QString path = SettingsModel::arma3Path() + "/" + FILE_NAME;
    DBG << path;
    QFile file(path);
    file.remove();
    file.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream fileStream(&file);
    fileStream.setCodec("UTF-8");
    fileStream << parameters;
    file.close();
    return FILE_NAME;
}

void Repository::updateEtaAndStatus()
{
    int maxEta = 0;
    int sumEta = 0;
    QSet<QString> modStatuses;

    for (Mod* item : mods())
    {
        if (item->status() == SyncStatus::QUEUED)
        {
            sumEta += item->eta();
        }
        else
        {
            maxEta = std::max(item->eta(), maxEta);
        }
        modStatuses.insert(item->status());
    }
    setEta(maxEta + sumEta);
{'fraction_non_alphanumeric': 0.1453628820502048, 'fraction_numerical': 0.004936456254595106, 'mean_word_length': 3.053639846743295, 'pattern_counts': {'":': 0, '<': 115, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3677979', 'n_tokens_mistral': 3011, 'n_tokens_neox': 2909, 'n_words': 628}