mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2026-06-29 01:54:20 +03:00
Merge 2163cb771c into d2fa7cf7f7
This commit is contained in:
commit
afdb2dc5bb
6 changed files with 309 additions and 25 deletions
|
|
@ -321,6 +321,8 @@ set(MINECRAFT_SOURCES
|
|||
minecraft/World.cpp
|
||||
minecraft/WorldList.h
|
||||
minecraft/WorldList.cpp
|
||||
minecraft/WorldTasks.h
|
||||
minecraft/WorldTasks.cpp
|
||||
|
||||
minecraft/mod/MetadataHandler.h
|
||||
minecraft/mod/Mod.h
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
*/
|
||||
|
||||
#include "WorldList.h"
|
||||
#include "WorldTasks.h"
|
||||
|
||||
#include <FileSystem.h>
|
||||
#include <QDebug>
|
||||
|
|
@ -123,18 +124,23 @@ QString WorldList::instDirPath() const
|
|||
return QFileInfo(m_instance->instanceRoot()).absoluteFilePath();
|
||||
}
|
||||
|
||||
bool WorldList::deleteWorld(int index)
|
||||
bool WorldList::removeWorldFromModel(const QFileInfo& sourceFile)
|
||||
{
|
||||
if (index >= m_worlds.size() || index < 0)
|
||||
return false;
|
||||
World& m = m_worlds[index];
|
||||
if (m.destroy()) {
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
m_worlds.removeAt(index);
|
||||
const auto sourcePath = sourceFile.absoluteFilePath();
|
||||
|
||||
for (int row = 0; row < m_worlds.size(); ++row) {
|
||||
if (m_worlds.at(row).container().absoluteFilePath() != sourcePath) {
|
||||
continue;
|
||||
}
|
||||
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
m_worlds.removeAt(row);
|
||||
endRemoveRows();
|
||||
|
||||
emit changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -360,6 +366,46 @@ void WorldList::installWorld(QFileInfo filename)
|
|||
w.install(m_dir.absolutePath());
|
||||
}
|
||||
|
||||
std::unique_ptr<Task> WorldList::createInstallWorldTask(QFileInfo filename)
|
||||
{
|
||||
return std::make_unique<InstallWorldTask>(InstallWorldTask::Args{
|
||||
.worlds = this,
|
||||
.sourceFile = filename,
|
||||
.targetDir = m_dir.absolutePath(),
|
||||
});
|
||||
}
|
||||
|
||||
std::unique_ptr<Task> WorldList::createCopyWorldTask(int index, const QString& name)
|
||||
{
|
||||
if (index >= m_worlds.size() || index < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto& world = m_worlds.at(index);
|
||||
|
||||
return std::make_unique<CopyWorldTask>(CopyWorldTask::Args{
|
||||
.worlds = this,
|
||||
.sourceFile = world.container(),
|
||||
.targetDir = m_dir.absolutePath(),
|
||||
.targetName = name,
|
||||
});
|
||||
}
|
||||
|
||||
std::unique_ptr<Task> WorldList::createDeleteWorldTask(int index)
|
||||
{
|
||||
if (index >= m_worlds.size() || index < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto& world = m_worlds.at(index);
|
||||
|
||||
return std::make_unique<DeleteWorldTask>(DeleteWorldTask::Args{
|
||||
.worlds = this,
|
||||
.sourceFile = world.container(),
|
||||
.displayName = world.name(),
|
||||
});
|
||||
}
|
||||
|
||||
bool WorldList::dropMimeData(const QMimeData* data,
|
||||
Qt::DropAction action,
|
||||
[[maybe_unused]] int row,
|
||||
|
|
|
|||
|
|
@ -20,10 +20,12 @@
|
|||
#include <QList>
|
||||
#include <QMimeData>
|
||||
#include <QString>
|
||||
#include <memory>
|
||||
#include "BaseInstance.h"
|
||||
#include "minecraft/World.h"
|
||||
|
||||
class QFileSystemWatcher;
|
||||
class Task;
|
||||
|
||||
class WorldList : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
|
|
@ -50,8 +52,17 @@ class WorldList : public QAbstractListModel {
|
|||
/// Install a world from location
|
||||
void installWorld(QFileInfo filename);
|
||||
|
||||
/// Deletes the mod at the given index.
|
||||
virtual bool deleteWorld(int index);
|
||||
/// Create a task to install a world from location
|
||||
std::unique_ptr<Task> createInstallWorldTask(QFileInfo filename);
|
||||
|
||||
/// Create a task to copy the world at the given index.
|
||||
std::unique_ptr<Task> createCopyWorldTask(int index, const QString& name);
|
||||
|
||||
/// Create a task to delete the world at the given index.
|
||||
std::unique_ptr<Task> createDeleteWorldTask(int index);
|
||||
|
||||
/// Remove an already deleted world from the model.
|
||||
bool removeWorldFromModel(const QFileInfo& sourceFile);
|
||||
|
||||
/// Removes the world icon, if any
|
||||
virtual bool resetIcon(int index);
|
||||
|
|
|
|||
130
launcher/minecraft/WorldTasks.cpp
Normal file
130
launcher/minecraft/WorldTasks.cpp
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
#include "WorldTasks.h"
|
||||
|
||||
#include "World.h"
|
||||
#include "WorldList.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QMetaObject>
|
||||
#include <QThreadPool>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename Func>
|
||||
void invokeOnMainThread(Func&& func)
|
||||
{
|
||||
auto app = QCoreApplication::instance();
|
||||
if (!app) {
|
||||
return;
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(app, std::forward<Func>(func), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
InstallWorldTask::InstallWorldTask(Args args) : m_args(std::move(args)) {}
|
||||
|
||||
void InstallWorldTask::executeTask()
|
||||
{
|
||||
setStatus(tr("Importing world..."));
|
||||
setDetails(m_args.sourceFile.fileName());
|
||||
setProgress(0, 0);
|
||||
|
||||
QPointer<InstallWorldTask> self(this);
|
||||
auto args = m_args;
|
||||
|
||||
QThreadPool::globalInstance()->start([self, args]() mutable {
|
||||
World world(args.sourceFile);
|
||||
const bool ok = world.isValid() && world.install(args.targetDir);
|
||||
|
||||
invokeOnMainThread([self, worlds = args.worlds, ok]() {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
self->emitFailed(self->tr("Failed to import world."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (worlds) {
|
||||
worlds->update();
|
||||
}
|
||||
|
||||
self->setProgress(1, 1);
|
||||
self->emitSucceeded();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
CopyWorldTask::CopyWorldTask(Args args) : m_args(std::move(args)) {}
|
||||
|
||||
void CopyWorldTask::executeTask()
|
||||
{
|
||||
setStatus(tr("Copying world..."));
|
||||
setDetails(m_args.targetName);
|
||||
setProgress(0, 0);
|
||||
|
||||
QPointer<CopyWorldTask> self(this);
|
||||
auto args = m_args;
|
||||
|
||||
QThreadPool::globalInstance()->start([self, args]() mutable {
|
||||
World world(args.sourceFile);
|
||||
const bool ok = world.isValid() && world.install(args.targetDir, args.targetName);
|
||||
|
||||
invokeOnMainThread([self, worlds = args.worlds, ok]() {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
self->emitFailed(self->tr("Failed to copy world."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (worlds) {
|
||||
worlds->update();
|
||||
}
|
||||
|
||||
self->setProgress(1, 1);
|
||||
self->emitSucceeded();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
DeleteWorldTask::DeleteWorldTask(Args args) : m_args(std::move(args)) {}
|
||||
|
||||
void DeleteWorldTask::executeTask()
|
||||
{
|
||||
setStatus(tr("Deleting world..."));
|
||||
setDetails(m_args.displayName);
|
||||
setProgress(0, 0);
|
||||
|
||||
QPointer<DeleteWorldTask> self(this);
|
||||
auto args = m_args;
|
||||
|
||||
QThreadPool::globalInstance()->start([self, args]() mutable {
|
||||
World world(args.sourceFile);
|
||||
const bool ok = world.destroy();
|
||||
|
||||
invokeOnMainThread([self, worlds = args.worlds, sourceFile = args.sourceFile, ok]() {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
self->emitFailed(self->tr("Failed to delete world."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (worlds) {
|
||||
worlds->removeWorldFromModel(sourceFile);
|
||||
}
|
||||
|
||||
self->setProgress(1, 1);
|
||||
self->emitSucceeded();
|
||||
});
|
||||
});
|
||||
}
|
||||
63
launcher/minecraft/WorldTasks.h
Normal file
63
launcher/minecraft/WorldTasks.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QPointer>
|
||||
#include <QString>
|
||||
|
||||
#include "tasks/Task.h"
|
||||
|
||||
class WorldList;
|
||||
|
||||
class InstallWorldTask : public Task {
|
||||
public:
|
||||
struct Args {
|
||||
QPointer<WorldList> worlds;
|
||||
QFileInfo sourceFile;
|
||||
QString targetDir;
|
||||
};
|
||||
|
||||
explicit InstallWorldTask(Args args);
|
||||
|
||||
protected:
|
||||
void executeTask() override;
|
||||
|
||||
private:
|
||||
Args m_args;
|
||||
};
|
||||
|
||||
class CopyWorldTask : public Task {
|
||||
public:
|
||||
struct Args {
|
||||
QPointer<WorldList> worlds;
|
||||
QFileInfo sourceFile;
|
||||
QString targetDir;
|
||||
QString targetName;
|
||||
};
|
||||
|
||||
explicit CopyWorldTask(Args args);
|
||||
|
||||
protected:
|
||||
void executeTask() override;
|
||||
|
||||
private:
|
||||
Args m_args;
|
||||
};
|
||||
|
||||
class DeleteWorldTask : public Task {
|
||||
public:
|
||||
struct Args {
|
||||
QPointer<WorldList> worlds;
|
||||
QFileInfo sourceFile;
|
||||
QString displayName;
|
||||
};
|
||||
|
||||
explicit DeleteWorldTask(Args args);
|
||||
|
||||
protected:
|
||||
void executeTask() override;
|
||||
|
||||
private:
|
||||
Args m_args;
|
||||
};
|
||||
|
|
@ -38,6 +38,7 @@
|
|||
#include "WorldListPage.h"
|
||||
#include "minecraft/WorldList.h"
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui/dialogs/ProgressDialog.h"
|
||||
#include "ui_WorldListPage.h"
|
||||
|
||||
#include <ui/widgets/PageContainer.h>
|
||||
|
|
@ -187,23 +188,34 @@ bool WorldListPage::eventFilter(QObject* obj, QEvent* ev)
|
|||
void WorldListPage::on_actionRemove_triggered()
|
||||
{
|
||||
auto proxiedIndex = getSelectedWorld();
|
||||
|
||||
if (!proxiedIndex.isValid())
|
||||
if (!proxiedIndex.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& world = m_worlds->allWorlds().at(proxiedIndex.row());
|
||||
|
||||
auto result = CustomMessageBox::selectable(this, tr("Confirm Deletion"),
|
||||
tr("You are about to delete \"%1\".\n"
|
||||
"The world may be gone forever (A LONG TIME).\n\n"
|
||||
"Are you sure?")
|
||||
.arg(m_worlds->allWorlds().at(proxiedIndex.row()).name()),
|
||||
.arg(world.name()),
|
||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
||||
->exec();
|
||||
|
||||
if (result != QMessageBox::Yes) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto task = m_worlds->createDeleteWorldTask(proxiedIndex.row());
|
||||
if (!task) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_worlds->stopWatching();
|
||||
m_worlds->deleteWorld(proxiedIndex.row());
|
||||
|
||||
ProgressDialog dialog(this);
|
||||
dialog.execWithTask(std::move(task));
|
||||
|
||||
m_worlds->startWatching();
|
||||
}
|
||||
|
||||
|
|
@ -393,13 +405,20 @@ void WorldListPage::on_actionAdd_triggered()
|
|||
{
|
||||
auto list = GuiUtil::BrowseForFiles(displayName(), tr("Select a Minecraft world zip"), tr("Minecraft World Zip File") + " (*.zip)",
|
||||
QString(), this->parentWidget());
|
||||
if (!list.empty()) {
|
||||
m_worlds->stopWatching();
|
||||
for (auto filename : list) {
|
||||
m_worlds->installWorld(QFileInfo(filename));
|
||||
}
|
||||
m_worlds->startWatching();
|
||||
if (list.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_worlds->stopWatching();
|
||||
for (auto filename : list) {
|
||||
auto task = m_worlds->createInstallWorldTask(QFileInfo(filename));
|
||||
if (!task) {
|
||||
continue;
|
||||
}
|
||||
ProgressDialog dialog(this);
|
||||
dialog.execWithTask(std::move(task));
|
||||
}
|
||||
m_worlds->startWatching();
|
||||
}
|
||||
|
||||
bool WorldListPage::isWorldSafe(QModelIndex)
|
||||
|
|
@ -426,18 +445,31 @@ void WorldListPage::on_actionCopy_triggered()
|
|||
return;
|
||||
}
|
||||
|
||||
if (!worldSafetyNagQuestion(tr("Copy World")))
|
||||
if (!worldSafetyNagQuestion(tr("Copy World"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto world = m_worlds->allWorlds().at(index.row());
|
||||
|
||||
auto worldVariant = m_worlds->data(index, WorldList::ObjectRole);
|
||||
auto world = (World*)worldVariant.value<void*>();
|
||||
bool ok = false;
|
||||
QString name =
|
||||
QInputDialog::getText(this, tr("World name"), tr("Enter a new name for the copy."), QLineEdit::Normal, world->name(), &ok);
|
||||
QInputDialog::getText(this, tr("World name"), tr("Enter a new name for the copy."), QLineEdit::Normal, world.name(), &ok);
|
||||
|
||||
if (ok && name.length() > 0) {
|
||||
world->install(m_worlds->dir().absolutePath(), name);
|
||||
if (!ok || name.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto task = m_worlds->createCopyWorldTask(index.row(), name);
|
||||
if (!task) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_worlds->stopWatching();
|
||||
|
||||
ProgressDialog dialog(this);
|
||||
dialog.execWithTask(std::move(task));
|
||||
|
||||
m_worlds->startWatching();
|
||||
}
|
||||
|
||||
void WorldListPage::on_actionRename_triggered()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue