diff options
Diffstat (limited to 'launcher')
-rw-r--r-- | launcher/Application.cpp | 6 | ||||
-rw-r--r-- | launcher/CMakeLists.txt | 3 | ||||
-rw-r--r-- | launcher/minecraft/mod/ResourcePack.cpp | 7 | ||||
-rw-r--r-- | launcher/minecraft/mod/ResourcePack.h | 2 | ||||
-rw-r--r-- | launcher/minecraft/mod/TexturePack.cpp | 5 | ||||
-rw-r--r-- | launcher/minecraft/mod/TexturePack.h | 2 | ||||
-rw-r--r-- | launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp | 27 | ||||
-rw-r--r-- | launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h | 12 | ||||
-rw-r--r-- | launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp | 27 | ||||
-rw-r--r-- | launcher/minecraft/mod/tasks/LocalTexturePackParseTask.h | 12 | ||||
-rw-r--r-- | launcher/ui/MainWindow.cpp | 49 | ||||
-rw-r--r-- | launcher/ui/dialogs/ImportResourcePackDialog.cpp | 66 | ||||
-rw-r--r-- | launcher/ui/dialogs/ImportResourcePackDialog.h | 27 | ||||
-rw-r--r-- | launcher/ui/dialogs/ImportResourcePackDialog.ui | 74 |
14 files changed, 286 insertions, 33 deletions
diff --git a/launcher/Application.cpp b/launcher/Application.cpp index ea8d2326..4ba9eb9b 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -915,13 +915,13 @@ bool Application::createSetupWizard() return false; } -bool Application::event(QEvent* event) { +bool Application::event(QEvent* event) +{ #ifdef Q_OS_MACOS if (event->type() == QEvent::ApplicationStateChange) { auto ev = static_cast<QApplicationStateChangeEvent*>(event); - if (m_prevAppState == Qt::ApplicationActive - && ev->applicationState() == Qt::ApplicationActive) { + if (m_prevAppState == Qt::ApplicationActive && ev->applicationState() == Qt::ApplicationActive) { emit clickedOnDock(); } m_prevAppState = ev->applicationState(); diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index e8afa6b8..3eb765dc 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -796,6 +796,8 @@ SET(LAUNCHER_SOURCES ui/dialogs/ExportInstanceDialog.h ui/dialogs/IconPickerDialog.cpp ui/dialogs/IconPickerDialog.h + ui/dialogs/ImportResourcePackDialog.cpp + ui/dialogs/ImportResourcePackDialog.h ui/dialogs/LoginDialog.cpp ui/dialogs/LoginDialog.h ui/dialogs/MSALoginDialog.cpp @@ -944,6 +946,7 @@ qt_wrap_ui(LAUNCHER_UI ui/dialogs/SkinUploadDialog.ui ui/dialogs/ExportInstanceDialog.ui ui/dialogs/IconPickerDialog.ui + ui/dialogs/ImportResourcePackDialog.ui ui/dialogs/MSALoginDialog.ui ui/dialogs/OfflineLoginDialog.ui ui/dialogs/AboutDialog.ui diff --git a/launcher/minecraft/mod/ResourcePack.cpp b/launcher/minecraft/mod/ResourcePack.cpp index 3fc10a2f..4a9ad21b 100644 --- a/launcher/minecraft/mod/ResourcePack.cpp +++ b/launcher/minecraft/mod/ResourcePack.cpp @@ -15,7 +15,7 @@ static const QMap<int, std::pair<Version, Version>> s_pack_format_versions = { { 3, { Version("1.11"), Version("1.12.2") } }, { 4, { Version("1.13"), Version("1.14.4") } }, { 5, { Version("1.15"), Version("1.16.1") } }, { 6, { Version("1.16.2"), Version("1.16.5") } }, { 7, { Version("1.17"), Version("1.17.1") } }, { 8, { Version("1.18"), Version("1.18.2") } }, - { 9, { Version("1.19"), Version("1.19.2") } }, + { 9, { Version("1.19"), Version("1.19.2") } }, { 11, { Version("1.19.3"), Version("1.19.3") } }, }; void ResourcePack::setPackFormat(int new_format_id) @@ -114,3 +114,8 @@ bool ResourcePack::applyFilter(QRegularExpression filter) const return Resource::applyFilter(filter); } + +bool ResourcePack::valid() const +{ + return m_pack_format != 0; +} diff --git a/launcher/minecraft/mod/ResourcePack.h b/launcher/minecraft/mod/ResourcePack.h index 03121908..7cb414d8 100644 --- a/launcher/minecraft/mod/ResourcePack.h +++ b/launcher/minecraft/mod/ResourcePack.h @@ -42,6 +42,8 @@ class ResourcePack : public Resource { /** Thread-safe. */ void setImage(QImage new_image); + bool valid() const override; + [[nodiscard]] auto compare(Resource const& other, SortType type) const -> std::pair<int, bool> override; [[nodiscard]] bool applyFilter(QRegularExpression filter) const override; diff --git a/launcher/minecraft/mod/TexturePack.cpp b/launcher/minecraft/mod/TexturePack.cpp index 796eb69d..99d55584 100644 --- a/launcher/minecraft/mod/TexturePack.cpp +++ b/launcher/minecraft/mod/TexturePack.cpp @@ -62,3 +62,8 @@ QPixmap TexturePack::image(QSize size) TexturePackUtils::process(*this); return image(size); } + +bool TexturePack::valid() const +{ + return m_description != nullptr; +} diff --git a/launcher/minecraft/mod/TexturePack.h b/launcher/minecraft/mod/TexturePack.h index 6aa5e18e..81bd5c69 100644 --- a/launcher/minecraft/mod/TexturePack.h +++ b/launcher/minecraft/mod/TexturePack.h @@ -48,6 +48,8 @@ class TexturePack : public Resource { /** Thread-safe. */ void setImage(QImage new_image); + bool valid() const override; + protected: mutable QMutex m_data_lock; diff --git a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp index 4f87bc13..6fd4b024 100644 --- a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp @@ -28,14 +28,14 @@ namespace ResourcePackUtils { -bool process(ResourcePack& pack) +bool process(ResourcePack& pack, ProcessingLevel level) { switch (pack.type()) { case ResourceType::FOLDER: - ResourcePackUtils::processFolder(pack); + ResourcePackUtils::processFolder(pack, level); return true; case ResourceType::ZIPFILE: - ResourcePackUtils::processZIP(pack); + ResourcePackUtils::processZIP(pack, level); return true; default: qWarning() << "Invalid type for resource pack parse task!"; @@ -43,7 +43,7 @@ bool process(ResourcePack& pack) } } -void processFolder(ResourcePack& pack) +void processFolder(ResourcePack& pack, ProcessingLevel level) { Q_ASSERT(pack.type() == ResourceType::FOLDER); @@ -60,6 +60,9 @@ void processFolder(ResourcePack& pack) mcmeta_file.close(); } + if (level == ProcessingLevel::BasicInfoOnly) + return; + QFileInfo image_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.png")); if (image_file_info.isFile()) { QFile mcmeta_file(image_file_info.filePath()); @@ -74,7 +77,7 @@ void processFolder(ResourcePack& pack) } } -void processZIP(ResourcePack& pack) +void processZIP(ResourcePack& pack, ProcessingLevel level) { Q_ASSERT(pack.type() == ResourceType::ZIPFILE); @@ -98,6 +101,11 @@ void processZIP(ResourcePack& pack) file.close(); } + if (level == ProcessingLevel::BasicInfoOnly) { + zip.close(); + return; + } + if (zip.setCurrentFile("pack.png")) { if (!file.open(QIODevice::ReadOnly)) { qCritical() << "Failed to open file in zip."; @@ -138,6 +146,13 @@ void processPackPNG(ResourcePack& pack, QByteArray&& raw_data) qWarning() << "Failed to parse pack.png."; } } + +bool validate(QFileInfo file) +{ + ResourcePack rp{ file }; + return ResourcePackUtils::process(rp, ProcessingLevel::BasicInfoOnly) && rp.valid(); +} + } // namespace ResourcePackUtils LocalResourcePackParseTask::LocalResourcePackParseTask(int token, ResourcePack& rp) @@ -152,8 +167,6 @@ bool LocalResourcePackParseTask::abort() void LocalResourcePackParseTask::executeTask() { - Q_ASSERT(m_resource_pack.valid()); - if (!ResourcePackUtils::process(m_resource_pack)) return; diff --git a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h index d3c25464..69dbd6ad 100644 --- a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h +++ b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h @@ -26,13 +26,19 @@ #include "tasks/Task.h" namespace ResourcePackUtils { -bool process(ResourcePack& pack); -void processZIP(ResourcePack& pack); -void processFolder(ResourcePack& pack); +enum class ProcessingLevel { Full, BasicInfoOnly }; + +bool process(ResourcePack& pack, ProcessingLevel level = ProcessingLevel::Full); + +void processZIP(ResourcePack& pack, ProcessingLevel level = ProcessingLevel::Full); +void processFolder(ResourcePack& pack, ProcessingLevel level = ProcessingLevel::Full); void processMCMeta(ResourcePack& pack, QByteArray&& raw_data); void processPackPNG(ResourcePack& pack, QByteArray&& raw_data); + +/** Checks whether a file is valid as a resource pack or not. */ +bool validate(QFileInfo file); } // namespace ResourcePackUtils class LocalResourcePackParseTask : public Task { diff --git a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp index bf1e308f..adb19aca 100644 --- a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp @@ -28,14 +28,14 @@ namespace TexturePackUtils { -bool process(TexturePack& pack) +bool process(TexturePack& pack, ProcessingLevel level) { switch (pack.type()) { case ResourceType::FOLDER: - TexturePackUtils::processFolder(pack); + TexturePackUtils::processFolder(pack, level); return true; case ResourceType::ZIPFILE: - TexturePackUtils::processZIP(pack); + TexturePackUtils::processZIP(pack, level); return true; default: qWarning() << "Invalid type for resource pack parse task!"; @@ -43,7 +43,7 @@ bool process(TexturePack& pack) } } -void processFolder(TexturePack& pack) +void processFolder(TexturePack& pack, ProcessingLevel level) { Q_ASSERT(pack.type() == ResourceType::FOLDER); @@ -60,6 +60,9 @@ void processFolder(TexturePack& pack) mcmeta_file.close(); } + if (level == ProcessingLevel::BasicInfoOnly) + return; + QFileInfo image_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.png")); if (image_file_info.isFile()) { QFile mcmeta_file(image_file_info.filePath()); @@ -74,7 +77,7 @@ void processFolder(TexturePack& pack) } } -void processZIP(TexturePack& pack) +void processZIP(TexturePack& pack, ProcessingLevel level) { Q_ASSERT(pack.type() == ResourceType::ZIPFILE); @@ -98,6 +101,11 @@ void processZIP(TexturePack& pack) file.close(); } + if (level == ProcessingLevel::BasicInfoOnly) { + zip.close(); + return; + } + if (zip.setCurrentFile("pack.png")) { if (!file.open(QIODevice::ReadOnly)) { qCritical() << "Failed to open file in zip."; @@ -129,6 +137,13 @@ void processPackPNG(TexturePack& pack, QByteArray&& raw_data) qWarning() << "Failed to parse pack.png."; } } + +bool validate(QFileInfo file) +{ + TexturePack rp{ file }; + return TexturePackUtils::process(rp, ProcessingLevel::BasicInfoOnly) && rp.valid(); +} + } // namespace TexturePackUtils LocalTexturePackParseTask::LocalTexturePackParseTask(int token, TexturePack& rp) @@ -143,8 +158,6 @@ bool LocalTexturePackParseTask::abort() void LocalTexturePackParseTask::executeTask() { - Q_ASSERT(m_texture_pack.valid()); - if (!TexturePackUtils::process(m_texture_pack)) return; diff --git a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.h b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.h index cb0e404a..9f7aab75 100644 --- a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.h +++ b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.h @@ -27,13 +27,19 @@ #include "tasks/Task.h" namespace TexturePackUtils { -bool process(TexturePack& pack); -void processZIP(TexturePack& pack); -void processFolder(TexturePack& pack); +enum class ProcessingLevel { Full, BasicInfoOnly }; + +bool process(TexturePack& pack, ProcessingLevel level = ProcessingLevel::Full); + +void processZIP(TexturePack& pack, ProcessingLevel level = ProcessingLevel::Full); +void processFolder(TexturePack& pack, ProcessingLevel level = ProcessingLevel::Full); void processPackTXT(TexturePack& pack, QByteArray&& raw_data); void processPackPNG(TexturePack& pack, QByteArray&& raw_data); + +/** Checks whether a file is valid as a texture pack or not. */ +bool validate(QFileInfo file); } // namespace TexturePackUtils class LocalTexturePackParseTask : public Task { diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 34c2ad22..b626bbae 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -72,6 +72,7 @@ #include <BaseInstance.h> #include <InstanceList.h> +#include <minecraft/MinecraftInstance.h> #include <MMCZip.h> #include <icons/IconList.h> #include <java/JavaUtils.h> @@ -107,8 +108,14 @@ #include "ui/dialogs/UpdateDialog.h" #include "ui/dialogs/EditAccountDialog.h" #include "ui/dialogs/ExportInstanceDialog.h" +#include "ui/dialogs/ImportResourcePackDialog.h" #include "ui/themes/ITheme.h" +#include <minecraft/mod/ResourcePackFolderModel.h> +#include <minecraft/mod/tasks/LocalResourcePackParseTask.h> +#include <minecraft/mod/TexturePackFolderModel.h> +#include <minecraft/mod/tasks/LocalTexturePackParseTask.h> + #include "UpdateController.h" #include "KonamiCode.h" @@ -1808,17 +1815,41 @@ void MainWindow::on_actionAddInstance_triggered() void MainWindow::droppedURLs(QList<QUrl> urls) { - for(auto & url:urls) - { - if(url.isLocalFile()) - { - addInstance(url.toLocalFile()); - } - else - { + // NOTE: This loop only processes one dropped file! + for (auto& url : urls) { + // The isLocalFile() check below doesn't work as intended without an explicit scheme. + if (url.scheme().isEmpty()) + url.setScheme("file"); + + if (!url.isLocalFile()) { // probably instance/modpack addInstance(url.toString()); + break; + } + + auto localFileName = url.toLocalFile(); + QFileInfo localFileInfo(localFileName); + + bool isResourcePack = ResourcePackUtils::validate(localFileInfo); + bool isTexturePack = TexturePackUtils::validate(localFileInfo); + + if (!isResourcePack && !isTexturePack) { // probably instance/modpack + addInstance(localFileName); + break; } - // Only process one dropped file... + + ImportResourcePackDialog dlg(this); + + if (dlg.exec() != QDialog::Accepted) + break; + + qDebug() << "Adding resource/texture pack" << localFileName << "to" << dlg.selectedInstanceKey; + + auto inst = APPLICATION->instances()->getInstanceById(dlg.selectedInstanceKey); + auto minecraftInst = std::dynamic_pointer_cast<MinecraftInstance>(inst); + if (isResourcePack) + minecraftInst->resourcePackList()->installResource(localFileName); + else if (isTexturePack) + minecraftInst->texturePackList()->installResource(localFileName); break; } } diff --git a/launcher/ui/dialogs/ImportResourcePackDialog.cpp b/launcher/ui/dialogs/ImportResourcePackDialog.cpp new file mode 100644 index 00000000..e807e926 --- /dev/null +++ b/launcher/ui/dialogs/ImportResourcePackDialog.cpp @@ -0,0 +1,66 @@ +#include "ImportResourcePackDialog.h" +#include "ui_ImportResourcePackDialog.h" + +#include <QFileDialog> +#include <QPushButton> + +#include "Application.h" +#include "InstanceList.h" + +#include <InstanceList.h> +#include "ui/instanceview/InstanceProxyModel.h" +#include "ui/instanceview/InstanceDelegate.h" + +ImportResourcePackDialog::ImportResourcePackDialog(QWidget* parent) : QDialog(parent), ui(new Ui::ImportResourcePackDialog) +{ + ui->setupUi(this); + setWindowModality(Qt::WindowModal); + + auto contentsWidget = ui->instanceView; + contentsWidget->setViewMode(QListView::ListMode); + contentsWidget->setFlow(QListView::LeftToRight); + contentsWidget->setIconSize(QSize(48, 48)); + contentsWidget->setMovement(QListView::Static); + contentsWidget->setResizeMode(QListView::Adjust); + contentsWidget->setSelectionMode(QAbstractItemView::SingleSelection); + contentsWidget->setSpacing(5); + contentsWidget->setWordWrap(true); + contentsWidget->setWrapping(true); + // NOTE: We can't have uniform sizes because the text may wrap if it's too long. If we set this, it will cut off the wrapped text. + contentsWidget->setUniformItemSizes(false); + contentsWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + contentsWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + contentsWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + contentsWidget->setItemDelegate(new ListViewDelegate()); + + proxyModel = new InstanceProxyModel(this); + proxyModel->setSourceModel(APPLICATION->instances().get()); + proxyModel->sort(0); + contentsWidget->setModel(proxyModel); + + connect(contentsWidget, SIGNAL(doubleClicked(QModelIndex)), SLOT(activated(QModelIndex))); + connect(contentsWidget->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + SLOT(selectionChanged(QItemSelection, QItemSelection))); +} + +void ImportResourcePackDialog::activated(QModelIndex index) +{ + selectedInstanceKey = index.data(InstanceList::InstanceIDRole).toString(); + accept(); +} + +void ImportResourcePackDialog::selectionChanged(QItemSelection selected, QItemSelection deselected) +{ + if (selected.empty()) + return; + + QString key = selected.first().indexes().first().data(InstanceList::InstanceIDRole).toString(); + if (!key.isEmpty()) { + selectedInstanceKey = key; + } +} + +ImportResourcePackDialog::~ImportResourcePackDialog() +{ + delete ui; +} diff --git a/launcher/ui/dialogs/ImportResourcePackDialog.h b/launcher/ui/dialogs/ImportResourcePackDialog.h new file mode 100644 index 00000000..8356f204 --- /dev/null +++ b/launcher/ui/dialogs/ImportResourcePackDialog.h @@ -0,0 +1,27 @@ +#pragma once + +#include <QDialog> +#include <QItemSelection> + +#include "ui/instanceview/InstanceProxyModel.h" + +namespace Ui { +class ImportResourcePackDialog; +} + +class ImportResourcePackDialog : public QDialog { + Q_OBJECT + + public: + explicit ImportResourcePackDialog(QWidget* parent = 0); + ~ImportResourcePackDialog(); + InstanceProxyModel* proxyModel; + QString selectedInstanceKey; + + private: + Ui::ImportResourcePackDialog* ui; + + private slots: + void selectionChanged(QItemSelection, QItemSelection); + void activated(QModelIndex); +}; diff --git a/launcher/ui/dialogs/ImportResourcePackDialog.ui b/launcher/ui/dialogs/ImportResourcePackDialog.ui new file mode 100644 index 00000000..20cb9177 --- /dev/null +++ b/launcher/ui/dialogs/ImportResourcePackDialog.ui @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ImportResourcePackDialog</class> + <widget class="QDialog" name="ImportResourcePackDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>676</width> + <height>555</height> + </rect> + </property> + <property name="windowTitle"> + <string>Choose instance to import</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Choose the instance you would like to import this resource pack to.</string> + </property> + </widget> + </item> + <item> + <widget class="QListView" name="instanceView"/> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>ImportResourcePackDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>ImportResourcePackDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> |