<commit_before>#include <QtWidgets>
#include <iostream>
#include "Wizard.h"
#include "Libs/SteamVdfParse.hpp"
#include "Database.h"
#include "Library.h"
#include <boost/property_tree/info_parser.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/optional.hpp>
#include <thread>
#include <future>

namespace pt = boost::property_tree;

GameList addedVector;

Wizard::Wizard(QWidget* parent, QString dbPath) : QWizard(parent), db(dbPath + "ascension.db")
{
    drmPage = new DRMPage();
    resultsPage = new ResultsPage(db, *drmPage);
    finalPage = new FinalPage(db);
    setPage(pages::INTRO, new IntroPage());
    setPage(pages::DRM, drmPage);
    setPage(pages::RESULTS, resultsPage);
    setPage(pages::FINAL, finalPage);
    setWindowTitle("Project Ascension setup");
    setFixedSize(QSize(700, 450));
 }

IntroPage::IntroPage(QWidget* parent) : QWizardPage(parent)
{
    setTitle("Finding games");
    setSubTitle("This wizard will try to find all your games.");
    auto layout = new QGridLayout();
    auto label = new QLabel("Click next to attempt to find Steam, Origin and Uplay games where applicable.");
    layout->addWidget(label);
    setLayout(layout);
}

DRMPage::DRMPage(QWidget* parent) : QWizardPage(parent)
{
    setTitle("Checking for Steam");
    steamBox = new QCheckBox();
    originBox = new QCheckBox();
    uplayBox = new QCheckBox();
    registerField("steamFound", steamBox);
    registerField("uplayFound", uplayBox);
    registerField("originFound", originBox);
    layout = new QGridLayout();
    platformLabel = new QLabel("<b>Steam</b>");
    descLabel = new QLabel();
    statusLabel = new QLabel();
    platformLabel->setTextFormat(Qt::TextFormat::RichText);
    checkSteamExists();

#if defined(_WIN32) || defined(_WIN64) || defined(__APPLE__)
    setTitle(title() += ", Origin");
    platformLabel = new QLabel("<b>Origin</b>");
    statusLabel = new QLabel();
    checkOriginExists();
#endif

#if defined(_WIN32) || defined (_WIN64)
    setTitle(title() += " and Uplay.");
    platformLabel = new QLabel("<b>Uplay</b>");
    statusLabel = new QLabel();
    checkUplayExists();
#endif

    setLayout(layout);
}

void DRMPage::checkOriginExists()
{
    QDir originRoot;
    QDir originFolder;
#if defined(_WIN32) || defined(_WIN64)
    originRoot = QDir(qgetenv("APPDATA").append("/Origin"));
#else
    originRoot = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation).append("/Origin/");
#endif


    if (originRoot.exists())
    {
        pt::ptree originTree;
        read_xml(originRoot.filePath("local.xml").toLocal8Bit().constData(), originTree);


        for (auto &xmlIter : originTree.get_child("Settings"))
        {
            if (xmlIter.second.get<std::string>("<xmlattr>.key") == "DownloadInPlaceDir")
            {
                originFolder = QString::fromStdString(xmlIter.second.get<std::string>("<xmlattr>.value"));
                break;
            }
        }

        if (originFolder == QDir("."))
        {
            originFolder = QDir("C:\\Program Files (x86)\\Origin Games\\");
        }
    }

    if (originFolder.filePath("").trimmed() != "" && originFolder.exists())
    {
        statusLabel->setPixmap(QPixmap(":/SystemMenu/Icons/Tick.svg"));
        descLabel = new QLabel("Origin found in " + originFolder.filePath(""));
        originBox->setChecked(true);
        originPath = originFolder.filePath("");
    }
    else
    {
        statusLabel->setPixmap(QPixmap(":/SystemMenu/Icons/Cross.svg"));
        descLabel = new QLabel("Origin not found on the system. Install and try again.");
    }
    layout->addWidget(platformLabel, 3, 0, 0);
    layout->addWidget(descLabel, 4, 0, 0);
    layout->addWidget(statusLabel, 3, 1, 0);
}

void DRMPage::checkSteamExists()
{
    QDir steamFolder;

#if defined(__linux__)
    QProcess which;
    which.setProcessChannelMode(QProcess::MergedChannels);
    QStringList args;
    args << "steam";
    which.start("which", args);
    which.waitForFinished();
    if (which.exitCode() == 0)
    {
        steamFolder = QDir(QDir::homePath() + "/.local/share/Steam");
    }
#elif defined(_WIN32) || defined(_WIN64)
    QSettings settings("HKEY_CURRENT_USER\\Software\\Valve\\Steam", QSettings::NativeFormat);
    if (!settings.value("SteamPath").isNull())
    {
        steamFolder = QDir(settings.value("SteamPath").toString()).canonicalPath();
    }
#elif defined(__APPLE__)
    steamFolder = QDir(QDir::home().filePath("Library/Application Support/Steam"));
#endif

    if (steamFolder.filePath("").trimmed() != "" && steamFolder.exists())
    {
        statusLabel->setPixmap(QPixmap(":SystemMenu/Icons/Tick.svg"));
        descLabel = new QLabel("Steam root found in " + steamFolder.filePath(""));
        steamBox->setChecked(true);
        steamPath = steamFolder.filePath("");
    }
    else
    {
        statusLabel->setPixmap(QPixmap(":SystemMenu/Icons/Cross.svg"));
        descLabel = new QLabel("Steam not found, verify installation and try again.");
    }
    layout->addWidget(platformLabel, 0, 0, 0);
    layout->addWidget(descLabel, 1, 0, 0);
    layout->addWidget(statusLabel, 0, 1, 0);
}

void DRMPage::checkUplayExists()
{
    QDir uplayFolder;
    QDir uplayRoot = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation).append("/Ubisoft Game Launcher");
    if (uplayRoot.exists())
    {
        std::ifstream uplaySettings(uplayRoot.filePath("settings.yml").toLocal8Bit().constData(), std::ifstream::in);
        std::string line;
        if (uplaySettings.is_open())
        {
            while (std::getline(uplaySettings, line))
            {
                if (line.find("game_installation_path") != std::string::npos)
                {
                    std::vector<std::string> strSplit;
                    boost::split(strSplit, line, boost::is_any_of("\""));
                    uplayFolder = QDir(QString::fromStdString(strSplit.at(1)));
                    break;
                }
            }
        }

        if (uplayFolder == QDir("."))
        {
            QSettings settings("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Uplay", QSettings::NativeFormat);
            if (!settings.value("InstallLocation").isNull())
            {
                uplayFolder = QDir(settings.value("InstallLocation").toString());
            }
        }
    }

    if (uplayFolder.filePath("").trimmed() != "" && uplayFolder.exists())
    {
        statusLabel->setPixmap(QPixmap(":/SystemMenu/Icons/Tick.svg"));
        descLabel = new QLabel("Uplay found in " + uplayFolder.filePath(""));
        uplayBox->setChecked(true);
        uplayPath = uplayFolder.filePath("");
    }
    else
    {
        statusLabel->setPixmap(QPixmap(":/SystemMenu/Icons/Cross.svg"));
        descLabel = new QLabel("Uplay not found on the system. Install and try again.");
    }
    layout->addWidget(platformLabel, 5, 0, 0);
    layout->addWidget(descLabel, 6, 0, 0);
    layout->addWidget(statusLabel, 5, 1, 0);
}

ResultsPage::ResultsPage(Database db, DRMPage& drmPage, QWidget* parent) : QWizardPage(parent), db(db)
{
    setSubTitle("We found the following on your system.");
    steamRoot = drmPage.steamPath;
    originRoot = drmPage.originPath;
    uplayRoot = drmPage.uplayPath;
}

void ResultsPage::initializePage()
{
    if (field("steamFound").toBool())
    {
        auto t = std::async(&ResultsPage::findSteamGames, this);
        t.get();
    }

    if (field("originFound").toBool())
    {
        auto t = std::async(&ResultsPage::findOriginGames, this);
        t.get();
    }

    if (field("uplayFound").toBool())
    {
        auto t = std::async(&ResultsPage::findUplayGames, this);
        t.get();
    }

    setTitle(QString("We found ") + QString::number(steamVector.size()) + QString(" Steam game") + (steamVector.size() >= 2 ? QString("s."):QString(".")));
    setSubTitle("Change the title for each game by clicking the text box and editing.");
    btnGroup = new QButtonGroup();
    btnGroup->setExclusive(false);
    tabWidget = new QTabWidget();
    top_layout = new QGridLayout();
    steamLayout = new QGridLayout();
    originLayout = new QGridLayout();
    uplayLayout = new QGridLayout();
    steamScrollArea = new QScrollArea();
    originScrollArea = new QScrollArea();
    int row = 0;

    for (auto i : steamVector)
    {
        QCheckBox* checkBox = new QCheckBox("Executable not found");
        QLineEdit* name = new QLineEdit(i.gameName);
        name->setFixedWidth(350);
        checkBox->setStyleSheet("QLabel { color: red; }");
        for (auto dir : steamDirectoryList)
        {
            if (i.executablePath.contains(dir))
            {
                checkBox->setStyleSheet("QLabel { color: black; }");
                checkBox->setText("Executable:  " + i.executablePath.remove(QDir(dir).filePath("SteamApps/common")).remove(0, 1));
                break;
            }
        }
        steamLayout->addWidget(name, row, 0, Qt::AlignVCenter | Qt::AlignLeft);
        row++;
        steamLayout->addWidget(checkBox, row, 0, Qt::AlignVCenter | Qt::AlignLeft);
        row++;
        btnGroup->addButton(checkBox);
    }

    for (pt::ptree::value_type& games : originTree.get_child("games"))
    {
        boost::optional<std::string> exeTest = games.second.get_optional<std::string>("exes");
        if (exeTest)
        {
            QLineEdit* name = new QLineEdit(QString::fromStdString(games.second.get<std::string>("name")));
            name->setFixedWidth(350);
            QCheckBox* checkBox = new QCheckBox();
            for (auto exe : games.second.get_child("exes"))
            {
                checkBox = new QCheckBox("Executable: " + QString::fromStdString(exe.second.data()));
            }
            originLayout->addWidget(name, row, 0, Qt::AlignVCenter | Qt::AlignLeft);
            row++;
            originLayout->addWidget(checkBox, row, 0, Qt::AlignVCenter | Qt::AlignLeft);
            row++;
        }
    }

    steamViewport = new QWidget();
    originViewport = new QWidget();
    QPushButton* selectAllBtn = new QPushButton("Select all");
    QPushButton* deselectAllBtn = new QPushButton("Deselect all");
    QPushButton* invertBtn = new QPushButton("Invert selection");
    connect(selectAllBtn, SIGNAL(clicked()), this, SLOT(selectAll()));
    connect(deselectAllBtn, SIGNAL(clicked()), this, SLOT(deselectAll()));
    connect(invertBtn, SIGNAL(clicked()), this, SLOT(invert()));
    steamViewport->setLayout(steamLayout);
    steamScrollArea->setWidget(steamViewport);
    tabWidget->addTab(steamScrollArea, "Steam");

#if defined(_WIN32) || defined(_WIN64) || defined(__APPLE__)
    originViewport->setLayout(originLayout);
    originScrollArea->setWidget(originViewport);
    tabWidget->addTab(originScrollArea, "Origin");
#endif

#if defined(_WIN32) || defined(_WIN64)
    QLabel* uplayLabel = new QLabel("Uplay");
    tabWidget->addTab(uplayLabel, "Uplay");
#endif

    top_layout->addWidget(tabWidget);
    QHBoxLayout* boxLayout = new QHBoxLayout();
    boxLayout->addWidget(selectAllBtn);
    boxLayout->addWidget(deselectAllBtn);
    boxLayout->addWidget(invertBtn);
    top_layout->addLayout(boxLayout, 1, 0, 0);
    connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabSelected()));
    setLayout(top_layout);
}

int ResultsPage::nextId() const
{
    int offset = 0;
    for (auto i : btnGroup->buttons())
    {
        if(i->isChecked())
        {
            std::cout << "Adding " << i->text().toLocal8Bit().constData() << std::endl;
            addedVector.push_back(steamVector.at(offset));
        }
        offset++;
    }
    return pages::FINAL;
}

void ResultsPage::selectAll()
{
    for (auto i : btnGroup->buttons())
    {
        i->setChecked(true);
    }
}

void ResultsPage::deselectAll()
{
    for (auto i : btnGroup->buttons())
    {
        i->setChecked(false);
    }
}

void ResultsPage::invert()
{
    for (auto i : btnGroup->buttons())
    {
        i->setChecked(!i->isChecked());
    }
}

void ResultsPage::tabSelected()
{
    if (tabWidget->currentIndex() >= 1)
    {
        setSubTitle("Change the title for each game by clicking the text box and editing. Choose which executable to use from the tree view.");
    }
    else
    {
        setSubTitle("Change the title for each game by clicking the text box and editing.");
    }
}

void ResultsPage::findSteamGames()
{
    QDir steamAppsDir = steamRoot.filePath("steamapps");
    if (!steamAppsDir.exists())
    {
        steamAppsDir = steamRoot.filePath("SteamApps");
    }
    pt::ptree libraryFolders;
    pt::read_info(steamAppsDir.filePath("libraryfolders.vdf").toLocal8Bit().constData(), libraryFolders);
    steamDirectoryList.append(steamRoot.filePath(""));
    QString pathString = "" + steamDirectoryList.at(0) + "\n";

    for (auto kv : libraryFolders.get_child("LibraryFolders"))
    {
        if (std::isdigit(static_cast<int>(*kv.first.data())))
        {
            std::string path = kv.second.data();
            QDir dir(QString::fromStdString(path));
            if (dir.exists())
            {
                steamDirectoryList.append(dir.filePath(""));
                pathString += dir.filePath("");
                pathString += "\n";
            }
        }
    }

    parseAcf(steamRoot);
    std::sort(steamVector.begin(), steamVector.end(), [&](const Game& g1, const Game& g2){return g1.gameName < g2.gameName;});
}

void ResultsPage::findOriginGames()
{
    QStringList ignoreList;
    ignoreList << "Cleanup.exe"
               << "Touchup.exe"
               << "DXSETUP.exe"
               << "vcredist_x86.exe"
               << "vcredist_x64.exe"
               << "ActivationUI.exe"
               << "PatchProgress.exe"
               << "activation.exe"
               << "EACoreServer.exe"
               << "EAProxyInstaller.exe"
               << "D3D11Install.exe"
               << "ATISET.EXE"
               << "DOS4GW.EXE"
               << "INFO.EXE"
               << "INSTALL.EXE"
               << "INTRO.EXE"
               << "MUNGE.EXE"
               << "SC2K.EXE"
               << "UNIVBE.EXE"
               << "VDETECT.EXE"
               << "VRF_DLL.EXE"
               << "WILLTV.EXE";

    originRoot.setFilter(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
    QStringList folderList = originRoot.entryList();
    QHash<QString, QStringList> masterList;
    int id = 0;

    for (auto i : folderList)
    {
        if (i != "DownloadCache")
        {
            pt::ptree& node = originTree.add("games.game", "");
            QDir dir(originRoot.absoluteFilePath(i));
            dir.setNameFilters(QStringList("*.exe"));
            dir.setFilter(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
            qDebug() << "Looking in: " << dir.filePath("");
            QStringList test = recursiveFindFiles(dir, ignoreList);
            node.put("id", id);
            node.put("name", dir.dirName().toLocal8Bit().constData());
            for (auto exe : test)
            {
                node.add("exes.exe", exe.toLocal8Bit().constData());
            }
            id++;
        }
    }
}

void ResultsPage::findUplayGames()
{<commit_msg>Tweaked findOriginGames to allow import into DB soon<commit_after>#include <QtWidgets>
#include <iostream>
#include "Wizard.h"
#include "Libs/SteamVdfParse.hpp"
#include "Database.h"
#include "Library.h"
#include <boost/property_tree/info_parser.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/optional.hpp>
#include <thread>
#include <future>

namespace pt = boost::property_tree;

GameList addedVector;
QList<QButtonGroup*> btnGroupVector;

Wizard::Wizard(QWidget* parent, QString dbPath) : QWizard(parent), db(dbPath + "ascension.db")
{
    drmPage = new DRMPage();
    resultsPage = new ResultsPage(db, *drmPage);
    finalPage = new FinalPage(db);
//    setPage(pages::INTRO, new IntroPage());
    setPage(pages::DRM, drmPage);
    setPage(pages::RESULTS, resultsPage);
    setPage(pages::FINAL, finalPage);
    setWindowTitle("Project Ascension setup");
    setFixedSize(QSize(700, 450));
 }

IntroPage::IntroPage(QWidget* parent) : QWizardPage(parent)
{
    setTitle("Finding games");
    setSubTitle("This wizard will try to find all your games.");
    auto layout = new QGridLayout();
    auto label = new QLabel("Click next to attempt to find Steam, Origin and Uplay games where applicable.");
    layout->addWidget(label);
    setLayout(layout);
}

DRMPage::DRMPage(QWidget* parent) : QWizardPage(parent)
{
    setTitle("Checking for Steam");
    steamBox = new QCheckBox();
    originBox = new QCheckBox();
    uplayBox = new QCheckBox();
    registerField("steamFound", steamBox);
    registerField("uplayFound", uplayBox);
    registerField("originFound", originBox);
    layout = new QGridLayout();
    platformLabel = new QLabel("<b>Steam</b>");
    descLabel = new QLabel();
    statusLabel = new QLabel();
    platformLabel->setTextFormat(Qt::TextFormat::RichText);
    checkSteamExists();

#if defined(_WIN32) || defined(_WIN64) || defined(__APPLE__)
    setTitle(title() += ", Origin");
    platformLabel = new QLabel("<b>Origin</b>");
    statusLabel = new QLabel();
    checkOriginExists();
#endif

#if defined(_WIN32) || defined (_WIN64)
    setTitle(title() += " and Uplay.");
    platformLabel = new QLabel("<b>Uplay</b>");
    statusLabel = new QLabel();
    checkUplayExists();
#endif

    setLayout(layout);
}

void DRMPage::checkOriginExists()
{
    QDir originRoot;
    QDir originFolder;
#if defined(_WIN32) || defined(_WIN64)
    originRoot = QDir(qgetenv("APPDATA").append("/Origin"));
#else
    originRoot = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation).append("/Origin/");
#endif


    if (originRoot.exists())
    {
        pt::ptree originTree;
        read_xml(originRoot.filePath("local.xml").toLocal8Bit().constData(), originTree);


        for (auto &xmlIter : originTree.get_child("Settings"))
        {
            if (xmlIter.second.get<std::string>("<xmlattr>.key") == "DownloadInPlaceDir")
            {
                originFolder = QString::fromStdString(xmlIter.second.get<std::string>("<xmlattr>.value"));
                break;
            }
        }

        if (originFolder == QDir("."))
        {
            originFolder = QDir("C:\\Program Files (x86)\\Origin Games\\");
        }
    }

    if (originFolder.filePath("").trimmed() != "" && originFolder.exists())
    {
        statusLabel->setPixmap(QPixmap(":/SystemMenu/Icons/Tick.svg"));
        descLabel = new QLabel("Origin found in " + originFolder.filePath(""));
        originBox->setChecked(true);
        originPath = originFolder.filePath("");
    }
    else
    {
        statusLabel->setPixmap(QPixmap(":/SystemMenu/Icons/Cross.svg"));
        descLabel = new QLabel("Origin not found on the system. Install and try again.");
    }
    layout->addWidget(platformLabel, 3, 0, 0);
    layout->addWidget(descLabel, 4, 0, 0);
    layout->addWidget(statusLabel, 3, 1, 0);
}

void DRMPage::checkSteamExists()
{
    QDir steamFolder;

#if defined(__linux__)
    QProcess which;
    which.setProcessChannelMode(QProcess::MergedChannels);
    QStringList args;
    args << "steam";
    which.start("which", args);
    which.waitForFinished();
    if (which.exitCode() == 0)
    {
        steamFolder = QDir(QDir::homePath() + "/.local/share/Steam");
    }
#elif defined(_WIN32) || defined(_WIN64)
    QSettings settings("HKEY_CURRENT_USER\\Software\\Valve\\Steam", QSettings::NativeFormat);
    if (!settings.value("SteamPath").isNull())
    {
        steamFolder = QDir(settings.value("SteamPath").toString()).canonicalPath();
    }
#elif defined(__APPLE__)
    steamFolder = QDir(QDir::home().filePath("Library/Application Support/Steam"));
#endif

    if (steamFolder.filePath("").trimmed() != "" && steamFolder.exists())
    {
        statusLabel->setPixmap(QPixmap(":SystemMenu/Icons/Tick.svg"));
        descLabel = new QLabel("Steam root found in " + steamFolder.filePath(""));
        steamBox->setChecked(true);
        steamPath = steamFolder.filePath("");
    }
    else
    {
        statusLabel->setPixmap(QPixmap(":SystemMenu/Icons/Cross.svg"));
        descLabel = new QLabel("Steam not found, verify installation and try again.");
    }
    layout->addWidget(platformLabel, 0, 0, 0);
    layout->addWidget(descLabel, 1, 0, 0);
    layout->addWidget(statusLabel, 0, 1, 0);
}

void DRMPage::checkUplayExists()
{
    QDir uplayFolder;
    QDir uplayRoot = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation).append("/Ubisoft Game Launcher");
    if (uplayRoot.exists())
    {
        std::ifstream uplaySettings(uplayRoot.filePath("settings.yml").toLocal8Bit().constData(), std::ifstream::in);
        std::string line;
        if (uplaySettings.is_open())
        {
            while (std::getline(uplaySettings, line))
            {
                if (line.find("game_installation_path") != std::string::npos)
                {
                    std::vector<std::string> strSplit;
                    boost::split(strSplit, line, boost::is_any_of("\""));
                    uplayFolder = QDir(QString::fromStdString(strSplit.at(1)));
                    break;
                }
            }
        }

        if (uplayFolder == QDir("."))
        {
            QSettings settings("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Uplay", QSettings::NativeFormat);
            if (!settings.value("InstallLocation").isNull())
            {
                uplayFolder = QDir(settings.value("InstallLocation").toString());
            }
        }
    }

    if (uplayFolder.filePath("").trimmed() != "" && uplayFolder.exists())
    {
        statusLabel->setPixmap(QPixmap(":/SystemMenu/Icons/Tick.svg"));
        descLabel = new QLabel("Uplay found in " + uplayFolder.filePath(""));
        uplayBox->setChecked(true);
        uplayPath = uplayFolder.filePath("");
    }
    else
    {
        statusLabel->setPixmap(QPixmap(":/SystemMenu/Icons/Cross.svg"));
        descLabel = new QLabel("Uplay not found on the system. Install and try again.");
    }
    layout->addWidget(platformLabel, 5, 0, 0);
    layout->addWidget(descLabel, 6, 0, 0);
    layout->addWidget(statusLabel, 5, 1, 0);
}

ResultsPage::ResultsPage(Database db, DRMPage& drmPage, QWidget* parent) : QWizardPage(parent), db(db)
{
    setSubTitle("We found the following on your system.");
    steamRoot = drmPage.steamPath;
    originRoot = drmPage.originPath;
    uplayRoot = drmPage.uplayPath;
}

void ResultsPage::initializePage()
{
    setTitle("No games found");
    btnGroup = new QButtonGroup();
    btnGroup->setExclusive(false);
    tabWidget = new QTabWidget();
    top_layout = new QGridLayout();
    uplayLayout = new QGridLayout();
    if (field("steamFound").toBool())
    {
        steamLayout = new QGridLayout();
        steamScrollArea = new QScrollArea();
        steamViewport = new QWidget();
        auto t = std::async(&ResultsPage::findSteamGames, this);
        t.get();
        int row = 0;
        setTitle(QString("We found ") + QString::number(steamVector.size()) + QString(" Steam game") + (steamVector.size() >= 2 ? QString("s."):QString(".")));

        for (auto i : steamVector)
        {
            QCheckBox* checkBox = new QCheckBox("Executable not found");
            QLineEdit* name = new QLineEdit(i.gameName);
            name->setFixedWidth(350);
            checkBox->setStyleSheet("QLabel { color: red; }");
            for (auto dir : steamDirectoryList)
            {
                if (i.executablePath.contains(dir))
                {
                    checkBox->setStyleSheet("QLabel { color: black; }");
                    checkBox->setText("Executable:  " + i.executablePath.remove(QDir(dir).filePath("SteamApps/common")).remove(0, 1));
                    break;
                }
            }
            steamLayout->addWidget(name, row, 0, Qt::AlignVCenter | Qt::AlignLeft);
            row++;
            steamLayout->addWidget(checkBox, row, 0, Qt::AlignVCenter | Qt::AlignLeft);
            row++;
            btnGroup->addButton(checkBox);
        }
        steamViewport->setLayout(steamLayout);
        steamScrollArea->setWidget(steamViewport);
        tabWidget->addTab(steamScrollArea, "Steam");
    }

    if (field("originFound").toBool())
    {
        originScrollArea = new QScrollArea();
        originViewport = new QWidget();
        originLayout = new QGridLayout();
        auto t = std::async(&ResultsPage::findOriginGames, this);
        t.get();
        int row = 0;
        int count = originTree.get<int>("games.count");
        if (field("uplayFound").toBool())
        {
            setTitle(QString("We found ") + QString::number(steamVector.size()) + QString(" Steam game") + (steamVector.size() >= 2 ? QString("s and "):QString(" and ")) + QString::number(count) + QString(" Origin game") + (count >= 2 ? QString("s."):QString(".")));
        }
        else
        {
            setTitle(QString("We found ") + QString::number(steamVector.size()) + QString(" Steam game") + (steamVector.size() >= 2 ? QString("s, "):QString(", ")) + QString::number(count) + QString(" Origin game") + (count >= 2 ? QString("s."):QString(".")));
        }


        for (pt::ptree::value_type& games : originTree.get_child("games"))
        {
            boost::optional<std::string> exeTest = games.second.get_optional<std::string>("exes");
            if (exeTest)
            {
                QButtonGroup* group = new QButtonGroup();
                QLineEdit* name = new QLineEdit(QString::fromStdString(games.second.get<std::string>("name")));
                name->setFixedWidth(350);
                QCheckBox* checkBox = new QCheckBox();
                originLayout->addWidget(name, row, 0, Qt::AlignVCenter | Qt::AlignLeft);
                row++;
                for (auto exe : games.second.get_child("exes"))
                {
                    checkBox = new QCheckBox("Executable: " + QString::fromStdString(exe.second.data()));
                    group->addButton(checkBox);
                    originLayout->addWidget(checkBox, row, 0, Qt::AlignVCenter | Qt::AlignLeft);
                    row++;
                }
                if (group->buttons().size() <= 1)
                {
                    group->buttons().at(0)->setChecked(true);
                }
                btnGroupVector.push_back(group);
            }
        }
        originViewport->setLayout(originLayout);
        originScrollArea->setWidget(originViewport);
        tabWidget->addTab(originScrollArea, "Origin");
    }

    if (field("uplayFound").toBool())
    {
        auto t = std::async(&ResultsPage::findUplayGames, this);
        t.get();
    }

    setSubTitle("Change the title for each game by clicking the text box and editing.");
    QPushButton* selectAllBtn = new QPushButton("Select all");
    QPushButton* deselectAllBtn = new QPushButton("Deselect all");
    QPushButton* invertBtn = new QPushButton("Invert selection");
    connect(selectAllBtn, SIGNAL(clicked()), this, SLOT(selectAll()));
    connect(deselectAllBtn, SIGNAL(clicked()), this, SLOT(deselectAll()));
    connect(invertBtn, SIGNAL(clicked()), this, SLOT(invert()));

#if defined(_WIN32) || defined(_WIN64)
    QLabel* uplayLabel = new QLabel("Uplay");
    tabWidget->addTab(uplayLabel, "Uplay");
#endif

    top_layout->addWidget(tabWidget);
    QHBoxLayout* boxLayout = new QHBoxLayout();
    boxLayout->addWidget(selectAllBtn);
    boxLayout->addWidget(deselectAllBtn);
    boxLayout->addWidget(invertBtn);
    top_layout->addLayout(boxLayout, 1, 0, 0);
    connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabSelected()));
    setLayout(top_layout);
}

int ResultsPage::nextId() const
{
    int steamOffset = 0;
    for (auto i : btnGroup->buttons())
    {
        if(i->isChecked())
        {
            std::cout << "Adding " << i->text().toLocal8Bit().constData() << std::endl;
            addedVector.push_back(steamVector.at(steamOffset));
        }
        steamOffset++;
    }
    for (auto i : btnGroupVector)
    {
        int pass = 0;
        for (auto group : i->buttons())
        {
            if (group->isChecked())
            {
                QDir path = group->text().remove("Executable: ");
                std::string name = QString(QDir::cleanPath(path.filePath("").remove(originRoot.filePath((""))))).toLocal8Bit().constData();
                std::vector<std::string> strSplit;
                boost::split(strSplit, name, boost::is_any_of("/"));
                name = strSplit.at(1);

                qDebug() << "Name: " << QString::fromStdString(name);
                qDebug() << "Path: " << originRoot.filePath(QString::fromStdString(name));
                qDebug() << "Exe: " << path.filePath("");
            }
        }
    }
    return pages::FINAL;
}

void ResultsPage::selectAll()
{
    for (auto i : btnGroup->buttons())
    {
        i->setChecked(true);
    }
}

void ResultsPage::deselectAll()
{
    for (auto i : btnGroup->buttons())
    {
        i->setChecked(false);
    }
}

void ResultsPage::invert()
{
    for (auto i : btnGroup->buttons())
    {
        i->setChecked(!i->isChecked());
    }
}

void ResultsPage::tabSelected()
{
    if (tabWidget->currentIndex() >= 1)
    {
        setSubTitle("Change the title for each game by clicking the text box and editing. Choose which executable to use from the tree view.");
    }
    else
    {
        setSubTitle("Change the title for each game by clicking the text box and editing.");
    }
}

void ResultsPage::findSteamGames()
{
    QDir steamAppsDir = steamRoot.filePath("steamapps");
    if (!steamAppsDir.exists())
    {
        steamAppsDir = steamRoot.filePath("SteamApps");
    }
    pt::ptree libraryFolders;
    pt::read_info(steamAppsDir.filePath("libraryfolders.vdf").toLocal8Bit().constData(), libraryFolders);
    steamDirectoryList.append(steamRoot.filePath(""));
    QString pathString = "" + steamDirectoryList.at(0) + "\n";

    for (auto kv : libraryFolders.get_child("LibraryFolders"))
    {
        if (std::isdigit(static_cast<int>(*kv.first.data())))
        {
            std::string path = kv.second.data();
            QDir dir(QString::fromStdString(path));
            if (dir.exists())
            {
                steamDirectoryList.append(dir.filePath(""));
                pathString += dir.filePath("");
                pathString += "\n";
            }
        }
    }

    parseAcf(steamRoot);
    std::sort(steamVector.begin(), steamVector.end(), [&](const Game& g1, const Game& g2){return g1.gameName < g2.gameName;});
}

void ResultsPage::findOriginGames()
{
    QStringList ignoreList;
    ignoreList << "Cleanup.exe"
               << "Touchup.exe"
               << "DXSETUP.exe"
               << "vcredist_x86.exe"
               << "vcredist_x64.exe"
               << "ActivationUI.exe"
               << "PatchProgress.exe"
               << "activation.exe"
               << "EACoreServer.exe"
               << "EAProxyInstaller.exe"
               << "D3D11Install.exe"
               << "ATISET.EXE"
               << "DOS4GW.EXE"
               << "INFO.EXE"
               << "INSTALL.EXE"
               << "INTRO.EXE"
               << "MUNGE.EXE"
               << "SC2K.EXE"
               << "UNIVBE.EXE"
               << "VDETECT.EXE"
               << "VRF_DLL.EXE"
               << "WILLTV.EXE";

    originRoot.setFilter(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
    QStringList folderList = originRoot.entryList();
    QHash<QString, QStringList> masterList;
    int count = 0;

    for (auto i : folderList)
    {
        if (i != "DownloadCache")
        {
            pt::ptree& node = originTree.add("games.game", "");
            QDir dir(originRoot.absoluteFilePath(i));
            dir.setNameFilters(QStringList("*.exe"));
            dir.setFilter(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
            qDebug() << "Looking in: " << dir.filePath("");
            QStringList test = recursiveFindFiles(dir, ignoreList);
            node.put("name", dir.dirName().toLocal8Bit().constData());
            for (auto exe : test)
            {
                node.add("exes.exe", exe.toLocal8Bit().constData());
            }
            count++;
        }
    }
    originTree.add("games.count", count);
}

void ResultsPage::findUplayGames()
{
{'fraction_non_alphanumeric': 0.15303308823529413, 'fraction_numerical': 0.006617647058823529, 'mean_word_length': 2.7278437642759252, 'pattern_counts': {'":': 12, '<': 181, '<?xml version=': 0, '>': 177, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 16}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5854298', 'n_tokens_mistral': 10286, 'n_tokens_neox': 10000, 'n_words': 1795}