mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2026-06-29 01:54:20 +03:00
Move world import, copy and delete actions to tasks
Signed-off-by: Andrey Kurlin <superkurlin2013@yandex.ru>
This commit is contained in:
parent
f654ce8212
commit
2163cb771c
6 changed files with 309 additions and 25 deletions
|
|
@ -321,6 +321,8 @@ set(MINECRAFT_SOURCES
|
||||||
minecraft/World.cpp
|
minecraft/World.cpp
|
||||||
minecraft/WorldList.h
|
minecraft/WorldList.h
|
||||||
minecraft/WorldList.cpp
|
minecraft/WorldList.cpp
|
||||||
|
minecraft/WorldTasks.h
|
||||||
|
minecraft/WorldTasks.cpp
|
||||||
|
|
||||||
minecraft/mod/MetadataHandler.h
|
minecraft/mod/MetadataHandler.h
|
||||||
minecraft/mod/Mod.h
|
minecraft/mod/Mod.h
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "WorldList.h"
|
#include "WorldList.h"
|
||||||
|
#include "WorldTasks.h"
|
||||||
|
|
||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
@ -123,18 +124,23 @@ QString WorldList::instDirPath() const
|
||||||
return QFileInfo(m_instance->instanceRoot()).absoluteFilePath();
|
return QFileInfo(m_instance->instanceRoot()).absoluteFilePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorldList::deleteWorld(int index)
|
bool WorldList::removeWorldFromModel(const QFileInfo& sourceFile)
|
||||||
{
|
{
|
||||||
if (index >= m_worlds.size() || index < 0)
|
const auto sourcePath = sourceFile.absoluteFilePath();
|
||||||
return false;
|
|
||||||
World& m = m_worlds[index];
|
for (int row = 0; row < m_worlds.size(); ++row) {
|
||||||
if (m.destroy()) {
|
if (m_worlds.at(row).container().absoluteFilePath() != sourcePath) {
|
||||||
beginRemoveRows(QModelIndex(), index, index);
|
continue;
|
||||||
m_worlds.removeAt(index);
|
}
|
||||||
|
|
||||||
|
beginRemoveRows(QModelIndex(), row, row);
|
||||||
|
m_worlds.removeAt(row);
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
|
|
||||||
emit changed();
|
emit changed();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -360,6 +366,46 @@ void WorldList::installWorld(QFileInfo filename)
|
||||||
w.install(m_dir.absolutePath());
|
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,
|
bool WorldList::dropMimeData(const QMimeData* data,
|
||||||
Qt::DropAction action,
|
Qt::DropAction action,
|
||||||
[[maybe_unused]] int row,
|
[[maybe_unused]] int row,
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,12 @@
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <memory>
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
#include "minecraft/World.h"
|
#include "minecraft/World.h"
|
||||||
|
|
||||||
class QFileSystemWatcher;
|
class QFileSystemWatcher;
|
||||||
|
class Task;
|
||||||
|
|
||||||
class WorldList : public QAbstractListModel {
|
class WorldList : public QAbstractListModel {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
@ -50,8 +52,17 @@ class WorldList : public QAbstractListModel {
|
||||||
/// Install a world from location
|
/// Install a world from location
|
||||||
void installWorld(QFileInfo filename);
|
void installWorld(QFileInfo filename);
|
||||||
|
|
||||||
/// Deletes the mod at the given index.
|
/// Create a task to install a world from location
|
||||||
virtual bool deleteWorld(int index);
|
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
|
/// Removes the world icon, if any
|
||||||
virtual bool resetIcon(int index);
|
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 "WorldListPage.h"
|
||||||
#include "minecraft/WorldList.h"
|
#include "minecraft/WorldList.h"
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
|
#include "ui/dialogs/ProgressDialog.h"
|
||||||
#include "ui_WorldListPage.h"
|
#include "ui_WorldListPage.h"
|
||||||
|
|
||||||
#include <ui/widgets/PageContainer.h>
|
#include <ui/widgets/PageContainer.h>
|
||||||
|
|
@ -187,23 +188,34 @@ bool WorldListPage::eventFilter(QObject* obj, QEvent* ev)
|
||||||
void WorldListPage::on_actionRemove_triggered()
|
void WorldListPage::on_actionRemove_triggered()
|
||||||
{
|
{
|
||||||
auto proxiedIndex = getSelectedWorld();
|
auto proxiedIndex = getSelectedWorld();
|
||||||
|
if (!proxiedIndex.isValid()) {
|
||||||
if (!proxiedIndex.isValid())
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& world = m_worlds->allWorlds().at(proxiedIndex.row());
|
||||||
|
|
||||||
auto result = CustomMessageBox::selectable(this, tr("Confirm Deletion"),
|
auto result = CustomMessageBox::selectable(this, tr("Confirm Deletion"),
|
||||||
tr("You are about to delete \"%1\".\n"
|
tr("You are about to delete \"%1\".\n"
|
||||||
"The world may be gone forever (A LONG TIME).\n\n"
|
"The world may be gone forever (A LONG TIME).\n\n"
|
||||||
"Are you sure?")
|
"Are you sure?")
|
||||||
.arg(m_worlds->allWorlds().at(proxiedIndex.row()).name()),
|
.arg(world.name()),
|
||||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
||||||
->exec();
|
->exec();
|
||||||
|
|
||||||
if (result != QMessageBox::Yes) {
|
if (result != QMessageBox::Yes) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto task = m_worlds->createDeleteWorldTask(proxiedIndex.row());
|
||||||
|
if (!task) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_worlds->stopWatching();
|
m_worlds->stopWatching();
|
||||||
m_worlds->deleteWorld(proxiedIndex.row());
|
|
||||||
|
ProgressDialog dialog(this);
|
||||||
|
dialog.execWithTask(std::move(task));
|
||||||
|
|
||||||
m_worlds->startWatching();
|
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)",
|
auto list = GuiUtil::BrowseForFiles(displayName(), tr("Select a Minecraft world zip"), tr("Minecraft World Zip File") + " (*.zip)",
|
||||||
QString(), this->parentWidget());
|
QString(), this->parentWidget());
|
||||||
if (!list.empty()) {
|
if (list.empty()) {
|
||||||
m_worlds->stopWatching();
|
return;
|
||||||
for (auto filename : list) {
|
|
||||||
m_worlds->installWorld(QFileInfo(filename));
|
|
||||||
}
|
|
||||||
m_worlds->startWatching();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
bool WorldListPage::isWorldSafe(QModelIndex)
|
||||||
|
|
@ -426,18 +445,31 @@ void WorldListPage::on_actionCopy_triggered()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!worldSafetyNagQuestion(tr("Copy World")))
|
if (!worldSafetyNagQuestion(tr("Copy World"))) {
|
||||||
return;
|
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;
|
bool ok = false;
|
||||||
QString name =
|
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) {
|
if (!ok || name.isEmpty()) {
|
||||||
world->install(m_worlds->dir().absolutePath(), name);
|
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()
|
void WorldListPage::on_actionRename_triggered()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue