aboutsummaryrefslogtreecommitdiff
path: root/launcher
diff options
context:
space:
mode:
Diffstat (limited to 'launcher')
-rw-r--r--launcher/Application.cpp6
-rw-r--r--launcher/CMakeLists.txt3
-rw-r--r--launcher/minecraft/mod/ResourcePack.cpp7
-rw-r--r--launcher/minecraft/mod/ResourcePack.h2
-rw-r--r--launcher/minecraft/mod/TexturePack.cpp5
-rw-r--r--launcher/minecraft/mod/TexturePack.h2
-rw-r--r--launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp27
-rw-r--r--launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h12
-rw-r--r--launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp27
-rw-r--r--launcher/minecraft/mod/tasks/LocalTexturePackParseTask.h12
-rw-r--r--launcher/ui/MainWindow.cpp49
-rw-r--r--launcher/ui/dialogs/ImportResourcePackDialog.cpp66
-rw-r--r--launcher/ui/dialogs/ImportResourcePackDialog.h27
-rw-r--r--launcher/ui/dialogs/ImportResourcePackDialog.ui74
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>