diff --git a/api/logic/CMakeLists.txt b/api/logic/CMakeLists.txt index 3d5687b0..404044d8 100644 --- a/api/logic/CMakeLists.txt +++ b/api/logic/CMakeLists.txt @@ -418,6 +418,20 @@ set(META_SOURCES meta/Index.h ) +set(MODPLATFORM_SOURCES + # Modplatform sources + modplatform/FtbPackDownloader.h + modplatform/FtbPackDownloader.cpp + + modplatform/FtbPackFetchTask.h + modplatform/FtbPackFetchTask.cpp + modplatform/FtbPackInstallTask.h + modplatform/FtbPackInstallTask.cpp + + modplatform/PackHelpers.h + +) + add_unit_test(Index SOURCES meta/Index_test.cpp LIBS MultiMC_logic @@ -446,6 +460,7 @@ set(LOGIC_SOURCES ${TOOLS_SOURCES} ${META_SOURCES} ${ICONS_SOURCES} + ${MODPLATFORM_SOURCES} ) add_library(MultiMC_logic SHARED ${LOGIC_SOURCES}) diff --git a/api/logic/FolderInstanceProvider.cpp b/api/logic/FolderInstanceProvider.cpp index 5ef705d4..a6d3bdc8 100644 --- a/api/logic/FolderInstanceProvider.cpp +++ b/api/logic/FolderInstanceProvider.cpp @@ -428,6 +428,14 @@ Task * FolderInstanceProvider::creationTask(BaseVersionPtr version, const QStrin return new FolderInstanceStaging(this, task, stagingPath, instName, instGroup); } +#include +Task * FolderInstanceProvider::ftbCreationTask(FtbPackDownloader *downloader, const QString& instName, const QString& instGroup, const QString& instIcon) +{ + auto stagingPath = getStagedInstancePath(); + auto task = new FtbPackInstallTask(downloader, m_globalSettings, stagingPath, instName, instIcon, instGroup); + return new FolderInstanceStaging(this, task, stagingPath, instName, instGroup); +} + #include "InstanceCopyTask.h" Task * FolderInstanceProvider::copyTask(const InstancePtr& oldInstance, const QString& instName, const QString& instGroup, const QString& instIcon, bool copySaves) { diff --git a/api/logic/FolderInstanceProvider.h b/api/logic/FolderInstanceProvider.h index a8d1a7bf..5117affc 100644 --- a/api/logic/FolderInstanceProvider.h +++ b/api/logic/FolderInstanceProvider.h @@ -2,6 +2,7 @@ #include "BaseInstanceProvider.h" #include +#include class QFileSystemWatcher; @@ -28,6 +29,9 @@ public: // import zipped instance into this provider Task * zipImportTask(const QUrl sourceUrl, const QString &instName, const QString &instGroup, const QString &instIcon); + //create FtbInstance + Task * ftbCreationTask(FtbPackDownloader *downloader, const QString &instName, const QString &instGroup, const QString &instIcon); + // migrate an instance to the current format Task * legacyUpgradeTask(const InstancePtr& oldInstance); diff --git a/api/logic/modplatform/FtbPackDownloader.cpp b/api/logic/modplatform/FtbPackDownloader.cpp new file mode 100644 index 00000000..a3951bfd --- /dev/null +++ b/api/logic/modplatform/FtbPackDownloader.cpp @@ -0,0 +1,106 @@ +#include "FtbPackDownloader.h" +#include "PackHelpers.h" +#include "FtbPackFetchTask.h" +#include "Env.h" + +FtbPackDownloader::FtbPackDownloader() { + done = false; + fetching = false; +} + +FtbPackDownloader::~FtbPackDownloader(){ + delete netJobContainer.get(); + netJobContainer.reset(nullptr); +} + +bool FtbPackDownloader::isValidPackSelected(){ + FtbModpack dummy; + dummy.name = "__INVALID__"; + + FtbModpack other = fetchedPacks.value(selected.name, dummy); + if(other.name == "__INVALID__") { + return false; + } + + return other.oldVersions.contains(selectedVersion); +} + +QString FtbPackDownloader::getSuggestedInstanceName() { + return selected.name; +} + +FtbModpackList FtbPackDownloader::getModpacks() { + return static_cast(fetchedPacks.values()); +} + +void FtbPackDownloader::fetchModpacks(bool force = false){ + if(fetching || (!force && done)) { + qDebug() << "Skipping modpack refetch because done or already fetching [done =>" << done << "| fetching =>" << fetching << "]"; + return; + } + + fetching = true; + + fetchTask = new FtbPackFetchTask(); + connect(fetchTask, &FtbPackFetchTask::finished, this, &FtbPackDownloader::fetchSuccess); + connect(fetchTask, &FtbPackFetchTask::failed, this, &FtbPackDownloader::fetchFailed); + fetchTask->fetch(); +} + + +void FtbPackDownloader::fetchSuccess(FtbModpackList modpacks) { + for(int i = 0; i < modpacks.size(); i++) { + fetchedPacks.insert(modpacks.at(i).name, modpacks.at(i)); + } + + fetching = false; + done = true; + emit ready(); + fetchTask->deleteLater(); +} + +void FtbPackDownloader::fetchFailed(QString reason) { + qWarning() << "Failed to fetch FtbData" << reason; + fetching = false; + emit packFetchFailed(); + fetchTask->deleteLater(); +} + +void FtbPackDownloader::selectPack(FtbModpack modpack, QString version) { + selected = modpack; + selectedVersion = version; +} + +FtbModpack FtbPackDownloader::getSelectedPack() { + return selected; +} + +void FtbPackDownloader::downloadSelected(MetaEntryPtr cache) { + NetJob *job = new NetJob("Downlad FTB Pack"); + + cache->setStale(true); + QString url = QString("http://ftb.cursecdn.com/FTB2/modpacks/%1/%2/%3").arg(selected.dir, selectedVersion.replace(".", "_"), selected.file); + job->addNetAction(Net::Download::makeCached(url, cache)); + downloadPath = cache->getFullPath(); + + netJobContainer.reset(job); + + connect(job, &NetJob::succeeded, this, &FtbPackDownloader::_downloadSucceeded); + connect(job, &NetJob::failed, this, &FtbPackDownloader::_downloadFailed); + connect(job, &NetJob::progress, this, &FtbPackDownloader::_downloadProgress); + job->start(); +} + +void FtbPackDownloader::_downloadSucceeded() { + netJobContainer.reset(); + emit downloadSucceded(downloadPath); +} + +void FtbPackDownloader::_downloadProgress(qint64 current, qint64 total) { + emit downloadProgress(current, total); +} + +void FtbPackDownloader::_downloadFailed(QString reason) { + netJobContainer.reset(); + emit downloadFailed(reason); +} diff --git a/api/logic/modplatform/FtbPackDownloader.h b/api/logic/modplatform/FtbPackDownloader.h new file mode 100644 index 00000000..45490afc --- /dev/null +++ b/api/logic/modplatform/FtbPackDownloader.h @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include "FtbPackFetchTask.h" +#include "tasks/Task.h" +#include "net/NetJob.h" + +#include "PackHelpers.h" +#include "Env.h" + +#pragma once + +class FtbPackDownloader; +class MULTIMC_LOGIC_EXPORT FtbPackDownloader : public QObject { + + Q_OBJECT + +private: + QMap fetchedPacks; + bool fetching; + bool done; + + FtbModpack selected; + QString selectedVersion; + QString downloadPath; + + FtbPackFetchTask *fetchTask = 0; + NetJobPtr netJobContainer; + + void _downloadSucceeded(); + void _downloadFailed(QString reason); + void _downloadProgress(qint64 current, qint64 total); + +private slots: + void fetchSuccess(FtbModpackList modlist); + void fetchFailed(QString reason); + +public: + FtbPackDownloader(); + ~FtbPackDownloader(); + + bool isValidPackSelected(); + void selectPack(FtbModpack modpack, QString version); + + FtbModpack getSelectedPack(); + + void fetchModpacks(bool force); + void downloadSelected(MetaEntryPtr cache); + + QString getSuggestedInstanceName(); + + FtbModpackList getModpacks(); + +signals: + void ready(); + void packFetchFailed(); + + void downloadSucceded(QString archivePath); + void downloadFailed(QString reason); + void downloadProgress(qint64 current, qint64 total); + +}; diff --git a/api/logic/modplatform/FtbPackFetchTask.cpp b/api/logic/modplatform/FtbPackFetchTask.cpp new file mode 100644 index 00000000..6f578e04 --- /dev/null +++ b/api/logic/modplatform/FtbPackFetchTask.cpp @@ -0,0 +1,75 @@ +#include "FtbPackFetchTask.h" +#include + +FtbPackFetchTask::FtbPackFetchTask() { + +} + +FtbPackFetchTask::~FtbPackFetchTask() { + +} + +void FtbPackFetchTask::fetch() { + NetJob *netJob = new NetJob("FtbModpackFetch"); + + QUrl url = QUrl("https://ftb.cursecdn.com/FTB2/static/modpacks.xml"); + qDebug() << "Downloading version info from " << url.toString(); + + netJob->addNetAction(downloadPtr = Net::Download::makeByteArray(url, &modpacksXmlFileData)); + + QObject::connect(netJob, &NetJob::succeeded, this, &FtbPackFetchTask::fileDownloadFinished); + QObject::connect(netJob, &NetJob::failed, this, &FtbPackFetchTask::fileDownloadFailed); + + jobPtr.reset(netJob); + netJob->start(); +} + +void FtbPackFetchTask::fileDownloadFinished(){ + + jobPtr.reset(); + + QDomDocument doc; + + QString errorMsg = "Unknown error."; + int errorLine = -1; + int errorCol = -1; + + if(!doc.setContent(modpacksXmlFileData, false, &errorMsg, &errorLine, &errorCol)){ + auto fullErrMsg = QString("Failed to fetch modpack data: %s %d:%d!").arg(errorMsg, errorLine, errorCol); + qWarning() << fullErrMsg; + emit failed(fullErrMsg); + modpacksXmlFileData.clear(); + return; + } + + modpacksXmlFileData.clear(); + + FtbModpackList modpackList; + + QDomNodeList nodes = doc.elementsByTagName("modpack"); + for(int i = 0; i < nodes.length(); i++) { + QDomElement element = nodes.at(i).toElement(); + + FtbModpack modpack; + modpack.name = element.attribute("name"); + modpack.currentVersion = element.attribute("version"); + modpack.mcVersion = element.attribute("mcVersion"); + modpack.description = element.attribute("description"); + modpack.mods = element.attribute("mods"); + modpack.image = element.attribute("image"); + modpack.oldVersions = element.attribute("oldVersions").split(";"); + modpack.author = element.attribute("author"); + + modpack.dir = element.attribute("dir"); + modpack.file = element.attribute("url"); + + modpackList.append(modpack); + } + + emit finished(modpackList); +} + +void FtbPackFetchTask::fileDownloadFailed(QString reason){ + qWarning() << "Fetching FtbPacks failed: " << reason; + emit failed(reason); +} diff --git a/api/logic/modplatform/FtbPackFetchTask.h b/api/logic/modplatform/FtbPackFetchTask.h new file mode 100644 index 00000000..df5a96e6 --- /dev/null +++ b/api/logic/modplatform/FtbPackFetchTask.h @@ -0,0 +1,34 @@ +#pragma once + +#include "multimc_logic_export.h" +#include "net/NetJob.h" +#include +#include +#include +#include "PackHelpers.h" + +class MULTIMC_LOGIC_EXPORT FtbPackFetchTask : public QObject { + + Q_OBJECT + +public: + FtbPackFetchTask(); + ~FtbPackFetchTask(); + + void fetch(); + +private: + NetJobPtr jobPtr; + Net::Download::Ptr downloadPtr; + + QByteArray modpacksXmlFileData; + +protected slots: + void fileDownloadFinished(); + void fileDownloadFailed(QString reason); + +signals: + void finished(FtbModpackList list); + void failed(QString reason); + +}; diff --git a/api/logic/modplatform/FtbPackInstallTask.cpp b/api/logic/modplatform/FtbPackInstallTask.cpp new file mode 100644 index 00000000..bedf3942 --- /dev/null +++ b/api/logic/modplatform/FtbPackInstallTask.cpp @@ -0,0 +1,65 @@ +#include "FtbPackInstallTask.h" +#include "Env.h" +#include "MMCZip.h" +#include "QtConcurrent" + +FtbPackInstallTask::FtbPackInstallTask(FtbPackDownloader *downloader, SettingsObjectPtr settings, + const QString &stagingPath, const QString &instName, const QString &instIcon, const QString &instGroup) : + m_globalSettings(settings), m_stagingPath(stagingPath), m_instName(instName), m_instIcon(instIcon), m_instGroup(instGroup) +{ + m_downloader = downloader; +} + +void FtbPackInstallTask::executeTask() { + downloadPack(); +} + +void FtbPackInstallTask::downloadPack(){ + FtbModpack toInstall = m_downloader->getSelectedPack(); + setStatus(tr("Installing new FTB Pack %1").arg(toInstall.name)); + + auto entry = ENV.metacache()->resolveEntry("general", "FTBPack/" + toInstall.name); + m_downloader->downloadSelected(entry); + + connect(m_downloader, &FtbPackDownloader::downloadSucceded, this, &FtbPackInstallTask::onDownloadSucceeded); + connect(m_downloader, &FtbPackDownloader::downloadProgress, this, &FtbPackInstallTask::onDownloadProgress); + connect(m_downloader, &FtbPackDownloader::downloadFailed, this,&FtbPackInstallTask::onDownloadFailed); +} + +void FtbPackInstallTask::onDownloadSucceeded(QString archivePath){ + qDebug() << "Download succeeded!"; + unzip(archivePath); +} + +void FtbPackInstallTask::onDownloadFailed(QString reason) { + emitFailed(reason); +} + +void FtbPackInstallTask::onDownloadProgress(qint64 current, qint64 total){ + progress(current, total); +} + +void FtbPackInstallTask::unzip(QString archivePath) { + setStatus(QString("Extracting modpack from %1").arg(archivePath)); + QDir extractDir(m_stagingPath); + + m_packZip.reset(new QuaZip(archivePath)); + if(!m_packZip->open(QuaZip::mdUnzip)) { + emitFailed(tr("Failed to open modpack file %1!").arg(archivePath)); + return; + } + + m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractSubDir, m_packZip.get(), QString("/"), extractDir.absolutePath()); + connect(&m_extractFutureWatcher, &QFutureWatcher::finished, this, &FtbPackInstallTask::onUnzipFinished); + connect(&m_extractFutureWatcher, &QFutureWatcher::canceled, this, &FtbPackInstallTask::onUnzipCanceled); + m_extractFutureWatcher.setFuture(m_extractFuture); +} + +void FtbPackInstallTask::onUnzipFinished() { + qDebug() << "Unzipped:" << m_stagingPath; + emitSucceeded(); +} + +void FtbPackInstallTask::onUnzipCanceled() { + emitAborted(); +} diff --git a/api/logic/modplatform/FtbPackInstallTask.h b/api/logic/modplatform/FtbPackInstallTask.h new file mode 100644 index 00000000..23ef0811 --- /dev/null +++ b/api/logic/modplatform/FtbPackInstallTask.h @@ -0,0 +1,45 @@ +#pragma once +#include "tasks/Task.h" +#include "modplatform/FtbPackDownloader.h" +#include "BaseInstanceProvider.h" +#include "net/NetJob.h" +#include "quazip.h" +#include "quazipdir.h" + +class MULTIMC_LOGIC_EXPORT FtbPackInstallTask : public Task { + + Q_OBJECT + +public: + explicit FtbPackInstallTask(FtbPackDownloader *downloader, SettingsObjectPtr settings, const QString & stagingPath, const QString &instName, + const QString &instIcon, const QString &instGroup); + +protected: + //! Entry point for tasks. + virtual void executeTask() override; + +private: /* data */ + SettingsObjectPtr m_globalSettings; + QString m_stagingPath; + QString m_instName; + QString m_instIcon; + QString m_instGroup; + NetJobPtr m_netJobPtr; + FtbPackDownloader *m_downloader = nullptr; + + std::unique_ptr m_packZip; + QFuture m_extractFuture; + QFutureWatcher m_extractFutureWatcher; + + void downloadPack(); + void unzip(QString archivePath); + void install(); + +private slots: + void onDownloadSucceeded(QString archivePath); + void onDownloadFailed(QString reason); + void onDownloadProgress(qint64 current, qint64 total); + + void onUnzipFinished(); + void onUnzipCanceled(); +}; diff --git a/api/logic/modplatform/PackHelpers.h b/api/logic/modplatform/PackHelpers.h new file mode 100644 index 00000000..ba0e5cb0 --- /dev/null +++ b/api/logic/modplatform/PackHelpers.h @@ -0,0 +1,21 @@ +#pragma once +#include + +//Header for structs etc... + +struct FtbModpack { + QString name; + QString description; + QString author; + QStringList oldVersions; + QString currentVersion; + QString mcVersion; + QString mods; + QString image; + + //Technical data + QString dir; + QString file; //<- Url in the xml, but doesn't make much sense +}; + +typedef QList FtbModpackList; diff --git a/application/CMakeLists.txt b/application/CMakeLists.txt index 100785f2..da9a42c6 100644 --- a/application/CMakeLists.txt +++ b/application/CMakeLists.txt @@ -153,6 +153,9 @@ SET(MULTIMC_SOURCES dialogs/VersionSelectDialog.h dialogs/SkinUploadDialog.cpp dialogs/SkinUploadDialog.h + dialogs/ChooseFtbPackDialog.cpp + dialogs/ChooseFtbPackDialog.h + # GUI - widgets widgets/Common.cpp @@ -186,7 +189,8 @@ SET(MULTIMC_SOURCES widgets/VersionSelectWidget.h widgets/ProgressWidget.h widgets/ProgressWidget.cpp - + widgets/FtbModpackListItem.h + widgets/FtbModpackListItem.cpp # GUI - instance group view groupview/GroupedProxyModel.cpp @@ -236,6 +240,7 @@ SET(MULTIMC_UIS dialogs/UpdateDialog.ui dialogs/NotificationDialog.ui dialogs/SkinUploadDialog.ui + dialogs/ChooseFtbPackDialog.ui # Widgets/other widgets/CustomCommands.ui diff --git a/application/MainWindow.cpp b/application/MainWindow.cpp index 36b3ba6d..1d36ef8c 100644 --- a/application/MainWindow.cpp +++ b/application/MainWindow.cpp @@ -1272,6 +1272,14 @@ void MainWindow::instanceFromVersion(QString instName, QString instGroup, QStrin // finalizeInstance(newInstance); } +void MainWindow::instanceFromFtbPack(FtbPackDownloader *downloader, QString instName, QString instGroup, QString instIcon) { + std::unique_ptr task(MMC->folderProvider()->ftbCreationTask(downloader, instName, instGroup, instIcon)); + runModalTask(task.get()); + + // FIXME: handle instance selection after creation + // finalizeInstance(newInstance); +} + void MainWindow::on_actionCopyInstance_triggered() { if (!m_selectedInstance) @@ -1347,7 +1355,10 @@ void MainWindow::addInstance(QString url) const QUrl modpackUrl = newInstDlg.modpackUrl(); - if (modpackUrl.isValid()) + if(newInstDlg.isFtbModpackRequested()) { + instanceFromFtbPack(newInstDlg.getFtbPackDownloader(), newInstDlg.instName(), newInstDlg.instGroup(), newInstDlg.iconKey()); + } + else if (modpackUrl.isValid()) { instanceFromZipPack(newInstDlg.instName(), newInstDlg.instGroup(), newInstDlg.iconKey(), modpackUrl); } diff --git a/application/MainWindow.h b/application/MainWindow.h index 6fa076bb..e4c281dc 100644 --- a/application/MainWindow.h +++ b/application/MainWindow.h @@ -25,6 +25,7 @@ #include "minecraft/auth/MojangAccount.h" #include "net/NetJob.h" #include "updater/GoUpdate.h" +#include class LaunchController; class NewsChecker; @@ -185,6 +186,7 @@ private: void runModalTask(Task *task); void instanceFromVersion(QString instName, QString instGroup, QString instIcon, BaseVersionPtr version); void instanceFromZipPack(QString instName, QString instGroup, QString instIcon, QUrl url); + void instanceFromFtbPack(FtbPackDownloader *downloader, QString instName, QString instGroup, QString instIcon); void finalizeInstance(InstancePtr inst); private: diff --git a/application/dialogs/ChooseFtbPackDialog.cpp b/application/dialogs/ChooseFtbPackDialog.cpp new file mode 100644 index 00000000..ae7c72e1 --- /dev/null +++ b/application/dialogs/ChooseFtbPackDialog.cpp @@ -0,0 +1,64 @@ +#include "ChooseFtbPackDialog.h" +#include "widgets/FtbModpackListItem.h" + +ChooseFtbPackDialog::ChooseFtbPackDialog(FtbModpackList modpacks) : ui(new Ui::ChooseFtbPackDialog) { + ui->setupUi(this); + + for(int i = 0; i < modpacks.size(); i++) { + FtbModpackListItem *item = new FtbModpackListItem(ui->packList, modpacks.at(i)); + + item->setText(modpacks.at(i).name); + } + + //TODO: Use a model/view instead of a widget + connect(ui->packList, &QListWidget::itemClicked, this, &ChooseFtbPackDialog::onListItemClicked); + connect(ui->packVersionSelection, &QComboBox::currentTextChanged, this, &ChooseFtbPackDialog::onVersionSelectionItemChanged); + + ui->modpackInfo->setOpenExternalLinks(true); + +} + +ChooseFtbPackDialog::~ChooseFtbPackDialog(){ + delete ui; +} + +void ChooseFtbPackDialog::onListItemClicked(QListWidgetItem *item){ + ui->packVersionSelection->clear(); + FtbModpack selectedPack = static_cast(item)->getModpack(); + + ui->modpackInfo->setHtml("Pack by " + selectedPack.author + "" + "
Minecraft " + selectedPack.mcVersion + "
" + "
" + selectedPack.description + "
  • " + selectedPack.mods.replace(";", "
  • ") + "
"); + + bool currentAdded = false; + + for(int i = 0; i < selectedPack.oldVersions.size(); i++) { + if(selectedPack.currentVersion == selectedPack.oldVersions.at(i)) { + currentAdded = true; + } + ui->packVersionSelection->addItem(selectedPack.oldVersions.at(i)); + } + + if(!currentAdded) { + ui->packVersionSelection->addItem(selectedPack.currentVersion); + } + + selected = selectedPack; + +} + +void ChooseFtbPackDialog::onVersionSelectionItemChanged(QString data) { + if(data.isNull() || data.isEmpty()) { + selectedVersion = ""; + return; + } + + selectedVersion = data; +} + +FtbModpack ChooseFtbPackDialog::getSelectedModpack() { + return selected; +} + +QString ChooseFtbPackDialog::getSelectedVersion() { + return selectedVersion; +} diff --git a/application/dialogs/ChooseFtbPackDialog.h b/application/dialogs/ChooseFtbPackDialog.h new file mode 100644 index 00000000..212aa27b --- /dev/null +++ b/application/dialogs/ChooseFtbPackDialog.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include "ui_ChooseFtbPackDialog.h" +#include + +namespace Ui { + class ChooseFtbPackDialog; +} + +class ChooseFtbPackDialog : public QDialog { + + Q_OBJECT + +private: + Ui::ChooseFtbPackDialog *ui; + FtbModpack selected; + QString selectedVersion; + +private slots: + void onListItemClicked(QListWidgetItem *item); + void onVersionSelectionItemChanged(QString data); + +public: + ChooseFtbPackDialog(FtbModpackList packs); + ~ChooseFtbPackDialog(); + + FtbModpack getSelectedModpack(); + QString getSelectedVersion(); +}; diff --git a/application/dialogs/ChooseFtbPackDialog.ui b/application/dialogs/ChooseFtbPackDialog.ui new file mode 100644 index 00000000..fdf845a9 --- /dev/null +++ b/application/dialogs/ChooseFtbPackDialog.ui @@ -0,0 +1,163 @@ + + + ChooseFtbPackDialog + + + + 0 + 0 + 730 + 437 + + + + + 0 + 0 + + + + false + + + + + 540 + 400 + 176 + 25 + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 10 + 10 + 261 + 381 + + + + true + + + + + 0 + 0 + 259 + 379 + + + + + + 0 + 0 + 261 + 381 + + + + + + + + + 280 + 10 + 441 + 381 + + + + true + + + + + 0 + 0 + 439 + 379 + + + + + + 0 + 0 + 441 + 381 + + + + + + + + + 450 + 400 + 72 + 25 + + + + + + + 340 + 400 + 101 + 21 + + + + Version selected: + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + buttonBox + accepted() + ChooseFtbPackDialog + accept() + + + 666 + 422 + + + 889 + 501 + + + + + buttonBox + rejected() + ChooseFtbPackDialog + reject() + + + 680 + 411 + + + 524 + 458 + + + + + diff --git a/application/dialogs/NewInstanceDialog.cpp b/application/dialogs/NewInstanceDialog.cpp index 5424a119..5faf57ac 100644 --- a/application/dialogs/NewInstanceDialog.cpp +++ b/application/dialogs/NewInstanceDialog.cpp @@ -25,6 +25,7 @@ #include "VersionSelectDialog.h" #include "ProgressDialog.h" #include "IconPickerDialog.h" +#include "ChooseFtbPackDialog.h" #include #include @@ -92,9 +93,12 @@ NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString connect(ui->modpackEdit, &QLineEdit::textChanged, this, &NewInstanceDialog::updateDialogState); connect(ui->modpackBox, &QRadioButton::clicked, this, &NewInstanceDialog::updateDialogState); + connect(ui->versionBox, &QRadioButton::clicked, this, &NewInstanceDialog::updateDialogState); connect(ui->versionTextBox, &QLineEdit::textChanged, this, &NewInstanceDialog::updateDialogState); + connect(ui->ftbBox, &QRadioButton::clicked, this, &NewInstanceDialog::updateDialogState); + auto groups = MMC->instances()->getGroups().toSet(); auto groupList = QStringList(groups.toList()); groupList.sort(Qt::CaseInsensitive); @@ -117,6 +121,14 @@ NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString ui->modpackBox->setChecked(true); ui->modpackEdit->setText(url); } + + ftbPackDownloader = new FtbPackDownloader(); + + connect(ftbPackDownloader, &FtbPackDownloader::ready, this, &NewInstanceDialog::ftbPackDataDownloadSuccessfully); + connect(ftbPackDownloader, &FtbPackDownloader::packFetchFailed, this, &NewInstanceDialog::ftbPackDataDownloadFailed); + + ftbPackDownloader->fetchModpacks(false); + updateDialogState(); } @@ -147,6 +159,17 @@ void NewInstanceDialog::updateDialogState() QFileInfo fi(url.fileName()); suggestedName = fi.completeBaseName(); } + else if (ui->ftbBox->isChecked()) + { + if(ftbPackDownloader->isValidPackSelected()) { + suggestedName = ftbPackDownloader->getSuggestedInstanceName(); + ui->labelFtbPack->setText(selectedPack.name); + } + + } + + ftbModpackRequested = ui->ftbBox->isChecked(); + if(suggestedName.isEmpty()) { ui->instNameTextBox->setPlaceholderText(originalPlaceholderText); @@ -156,9 +179,10 @@ void NewInstanceDialog::updateDialogState() ui->instNameTextBox->setPlaceholderText(suggestedName); } bool allowOK = !instName().isEmpty() && ( - (ui->versionBox->isChecked() && m_selectedVersion) || - (ui->modpackBox->isChecked() && ui->modpackEdit->hasAcceptableInput()) - ); + (ui->versionBox->isChecked() && m_selectedVersion) || + (ui->modpackBox->isChecked() && ui->modpackEdit->hasAcceptableInput()) || + (ui->ftbBox->isChecked() && ftbPackDownloader && ftbPackDownloader->isValidPackSelected() ) + ); ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(allowOK); } @@ -271,3 +295,34 @@ void NewInstanceDialog::on_modpackBtn_clicked() } } } + +bool NewInstanceDialog::isFtbModpackRequested() { + return ftbModpackRequested; +} + +FtbPackDownloader *NewInstanceDialog::getFtbPackDownloader() { + return ftbPackDownloader; +} + +void NewInstanceDialog::on_btnChooseFtbPack_clicked() { + ChooseFtbPackDialog dl(ftbPackDownloader->getModpacks()); + dl.exec(); + if(dl.result() == QDialog::Accepted) { + selectedPack = dl.getSelectedModpack(); + ftbPackDownloader->selectPack(selectedPack, dl.getSelectedVersion()); + } + updateDialogState(); +} + +void NewInstanceDialog::ftbPackDataDownloadSuccessfully() { + ui->packDataDownloadStatus->setText(tr("(Pack data download complete)")); + // ui->labelFtbPack->setText(tr("Disabled for now... not completed!")); + + // Disable for PR + ui->ftbBox->setEnabled(true); +} + +void NewInstanceDialog::ftbPackDataDownloadFailed() { + ui->packDataDownloadStatus->setText(tr("(Pack data download failed)")); +} + diff --git a/application/dialogs/NewInstanceDialog.h b/application/dialogs/NewInstanceDialog.h index 820a8d46..9b0f7f53 100644 --- a/application/dialogs/NewInstanceDialog.h +++ b/application/dialogs/NewInstanceDialog.h @@ -18,6 +18,8 @@ #include #include "BaseVersion.h" +#include "modplatform/FtbPackDownloader.h" +#include "modplatform/PackHelpers.h" namespace Ui { @@ -42,19 +44,31 @@ public: QUrl modpackUrl() const; BaseVersionPtr selectedVersion() const; + bool isFtbModpackRequested(); + FtbPackDownloader* getFtbPackDownloader(); + private slots: void on_btnChangeVersion_clicked(); void on_iconButton_clicked(); void on_modpackBtn_clicked(); + void on_btnChooseFtbPack_clicked(); void on_instNameTextBox_textChanged(const QString &arg1); void versionListUpdated(); + void ftbPackDataDownloadSuccessfully(); + void ftbPackDataDownloadFailed(); + private: Ui::NewInstanceDialog *ui; bool m_versionSetByUser = false; + bool ftbModpackRequested = false; + BaseVersionPtr m_selectedVersion; QString InstIconKey; QString originalPlaceholderText; + + FtbPackDownloader* ftbPackDownloader; + FtbModpack selectedPack; }; diff --git a/application/dialogs/NewInstanceDialog.ui b/application/dialogs/NewInstanceDialog.ui index 6b875ff4..428b9c57 100644 --- a/application/dialogs/NewInstanceDialog.ui +++ b/application/dialogs/NewInstanceDialog.ui @@ -10,7 +10,7 @@ 0 0 281 - 404 + 407 @@ -107,6 +107,33 @@ + + + + false + + + Install FTB Pack + + + + + + + ... + + + + + + + false + + + ... + + + @@ -117,27 +144,13 @@ - - + + false - http:// - - - - - - - true - - - - - - - ... + No Pack choosen @@ -158,6 +171,30 @@ + + + + true + + + + + + + false + + + http:// + + + + + + + (Loading Pack data...) + + + @@ -219,8 +256,8 @@ accept() - 257 - 333 + 266 + 378 157 @@ -235,11 +272,11 @@ reject() - 325 - 333 + 271 + 378 - 286 + 280 274 @@ -251,12 +288,12 @@ setEnabled(bool) - 81 - 229 + 91 + 251 - 236 - 221 + 240 + 278 @@ -267,12 +304,12 @@ setEnabled(bool) - 129 - 225 + 139 + 251 - 328 - 229 + 270 + 278 @@ -287,8 +324,8 @@ 195 - 213 - 191 + 223 + 224 @@ -303,8 +340,40 @@ 198 - 322 - 192 + 270 + 224 + + + + + ftbBox + toggled(bool) + btnChooseFtbPack + setEnabled(bool) + + + 67 + 301 + + + 254 + 327 + + + + + ftbBox + toggled(bool) + labelFtbPack + setEnabled(bool) + + + 81 + 310 + + + 73 + 334 diff --git a/application/widgets/FtbModpackListItem.cpp b/application/widgets/FtbModpackListItem.cpp new file mode 100644 index 00000000..874e0eac --- /dev/null +++ b/application/widgets/FtbModpackListItem.cpp @@ -0,0 +1,8 @@ +#include "FtbModpackListItem.h" + +FtbModpackListItem::FtbModpackListItem(QListWidget *list, FtbModpack modpack) : QListWidgetItem(list), modpack(modpack) { +} + +FtbModpack FtbModpackListItem::getModpack(){ + return modpack; +} diff --git a/application/widgets/FtbModpackListItem.h b/application/widgets/FtbModpackListItem.h new file mode 100644 index 00000000..977cad2d --- /dev/null +++ b/application/widgets/FtbModpackListItem.h @@ -0,0 +1,15 @@ +#pragma once + +#include "QListWidget" +#include + +class FtbModpackListItem : public QListWidgetItem { + +private: + FtbModpack modpack; + +public: + FtbModpackListItem(QListWidget *list, FtbModpack modpack); + FtbModpack getModpack(); + +};