From 8a0027c73a755849bf5b58c1509c71a543ddb982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sat, 22 Aug 2020 01:34:55 +0200 Subject: NOISSUE Add world icons and world icon reset button --- api/logic/minecraft/World.cpp | 17 ++++++++++ api/logic/minecraft/World.h | 7 +++++ api/logic/minecraft/WorldList.cpp | 17 ++++++++++ api/logic/minecraft/WorldList.h | 6 +++- application/pages/instance/WorldListPage.cpp | 47 +++++++++++++++++++++++++++- application/pages/instance/WorldListPage.h | 1 + application/pages/instance/WorldListPage.ui | 15 +++++++++ 7 files changed, 108 insertions(+), 2 deletions(-) diff --git a/api/logic/minecraft/World.cpp b/api/logic/minecraft/World.cpp index 17dbf4ae..06a6080a 100644 --- a/api/logic/minecraft/World.cpp +++ b/api/logic/minecraft/World.cpp @@ -138,14 +138,31 @@ void World::repath(const QFileInfo &file) m_folderName = file.fileName(); if(file.isFile() && file.suffix() == "zip") { + m_iconFile = QString(); readFromZip(file); } else if(file.isDir()) { + QFileInfo assumedIconPath(file.absoluteFilePath() + "/icon.png"); + if(assumedIconPath.exists()) { + m_iconFile = assumedIconPath.absoluteFilePath(); + } readFromFS(file); } } +bool World::resetIcon() +{ + if(m_iconFile.isNull()) { + return false; + } + if(QFile(m_iconFile).remove()) { + m_iconFile = QString(); + return true; + } + return false; +} + void World::readFromFS(const QFileInfo &file) { auto bytes = getLevelDatDataFromFS(file); diff --git a/api/logic/minecraft/World.h b/api/logic/minecraft/World.h index 818701fa..d04c1040 100644 --- a/api/logic/minecraft/World.h +++ b/api/logic/minecraft/World.h @@ -40,6 +40,10 @@ public: { return m_actualName; } + QString iconFile() const + { + return m_iconFile; + } QDateTime lastPlayed() const { return m_lastPlayed; @@ -70,6 +74,8 @@ public: bool replace(World &with); // change the world's filesystem path (used by world lists for *MAGIC* purposes) void repath(const QFileInfo &file); + // remove the icon file, if any + bool resetIcon(); bool rename(const QString &to); bool install(const QString &to, const QString &name= QString()); @@ -88,6 +94,7 @@ protected: QString m_containerOffsetPath; QString m_folderName; QString m_actualName; + QString m_iconFile; QDateTime levelDatTime; QDateTime m_lastPlayed; int64_t m_randomSeed = 0; diff --git a/api/logic/minecraft/WorldList.cpp b/api/logic/minecraft/WorldList.cpp index b7a24434..94b59da4 100644 --- a/api/logic/minecraft/WorldList.cpp +++ b/api/logic/minecraft/WorldList.cpp @@ -136,6 +136,19 @@ bool WorldList::deleteWorlds(int first, int last) return true; } +bool WorldList::resetIcon(int row) +{ + if (row >= worlds.size() || row < 0) + return false; + World &m = worlds[row]; + if(m.resetIcon()) { + emit dataChanged(index(row), index(row), {WorldList::IconFileRole}); + return true; + } + return false; +} + + int WorldList::columnCount(const QModelIndex &parent) const { return 3; @@ -195,6 +208,10 @@ QVariant WorldList::data(const QModelIndex &index, int role) const { return world.lastPlayed(); } + case IconFileRole: + { + return world.iconFile(); + } default: return QVariant(); } diff --git a/api/logic/minecraft/WorldList.h b/api/logic/minecraft/WorldList.h index 37ad330a..db44daf9 100644 --- a/api/logic/minecraft/WorldList.h +++ b/api/logic/minecraft/WorldList.h @@ -44,7 +44,8 @@ public: SeedRole, NameRole, GameModeRole, - LastPlayedRole + LastPlayedRole, + IconFileRole }; WorldList(const QString &dir); @@ -81,6 +82,9 @@ public: /// Deletes the mod at the given index. virtual bool deleteWorld(int index); + /// Removes the world icon, if any + virtual bool resetIcon(int index); + /// Deletes all the selected mods virtual bool deleteWorlds(int first, int last); diff --git a/application/pages/instance/WorldListPage.cpp b/application/pages/instance/WorldListPage.cpp index 8358a0f1..75741d22 100644 --- a/application/pages/instance/WorldListPage.cpp +++ b/application/pages/instance/WorldListPage.cpp @@ -31,6 +31,33 @@ #include #include +class WorldListProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + WorldListProxyModel(QObject *parent) : QSortFilterProxyModel(parent) {} + + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const + { + QModelIndex sourceIndex = mapToSource(index); + + if (index.column() == 0 && role == Qt::DecorationRole) + { + WorldList *worlds = qobject_cast(sourceModel()); + auto iconFile = worlds->data(sourceIndex, WorldList::IconFileRole).toString(); + if(iconFile.isNull()) { + // NOTE: Minecraft uses the same placeholder for servers AND worlds + return MMC->getThemedIcon("unknown_server"); + } + return QIcon(iconFile); + } + + return sourceIndex.data(role); + } +}; + + WorldListPage::WorldListPage(BaseInstance *inst, std::shared_ptr worlds, QWidget *parent) : QMainWindow(parent), m_inst(inst), ui(new Ui::WorldListPage), m_worlds(worlds) { @@ -38,13 +65,14 @@ WorldListPage::WorldListPage(BaseInstance *inst, std::shared_ptr worl ui->toolBar->insertSpacer(ui->actionRefresh); - QSortFilterProxyModel * proxy = new QSortFilterProxyModel(this); + WorldListProxyModel * proxy = new WorldListProxyModel(this); proxy->setSortCaseSensitivity(Qt::CaseInsensitive); proxy->setSourceModel(m_worlds.get()); ui->worldTreeView->setSortingEnabled(true); ui->worldTreeView->setModel(proxy); ui->worldTreeView->installEventFilter(this); ui->worldTreeView->setContextMenuPolicy(Qt::CustomContextMenu); + ui->worldTreeView->setIconSize(QSize(64,64)); connect(ui->worldTreeView, &QTreeView::customContextMenuRequested, this, &WorldListPage::ShowContextMenu); auto head = ui->worldTreeView->header(); @@ -142,6 +170,19 @@ void WorldListPage::on_actionView_Folder_triggered() DesktopServices::openDirectory(m_worlds->dir().absolutePath(), true); } +void WorldListPage::on_actionReset_Icon_triggered() +{ + auto proxiedIndex = getSelectedWorld(); + + if(!proxiedIndex.isValid()) + return; + + if(m_worlds->resetIcon(proxiedIndex.row())) { + ui->actionReset_Icon->setEnabled(false); + } +} + + QModelIndex WorldListPage::getSelectedWorld() { auto index = ui->worldTreeView->selectionModel()->currentIndex(); @@ -255,6 +296,8 @@ void WorldListPage::worldChanged(const QModelIndex ¤t, const QModelIndex & ui->actionRemove->setEnabled(enable); ui->actionCopy->setEnabled(enable); ui->actionRename->setEnabled(enable); + bool hasIcon = !index.data(WorldList::IconFileRole).isNull(); + ui->actionReset_Icon->setEnabled(enable && hasIcon); } void WorldListPage::on_actionAdd_triggered() @@ -342,3 +385,5 @@ void WorldListPage::on_actionRefresh_triggered() { m_worlds->update(); } + +#include "WorldListPage.moc" diff --git a/application/pages/instance/WorldListPage.h b/application/pages/instance/WorldListPage.h index c39420da..8ff14819 100644 --- a/application/pages/instance/WorldListPage.h +++ b/application/pages/instance/WorldListPage.h @@ -90,6 +90,7 @@ private slots: void on_actionRename_triggered(); void on_actionRefresh_triggered(); void on_actionView_Folder_triggered(); + void on_actionReset_Icon_triggered(); void worldChanged(const QModelIndex ¤t, const QModelIndex &previous); void mceditState(LoggedProcess::State state); diff --git a/application/pages/instance/WorldListPage.ui b/application/pages/instance/WorldListPage.ui index ddb3dfa9..8d00f8f4 100644 --- a/application/pages/instance/WorldListPage.ui +++ b/application/pages/instance/WorldListPage.ui @@ -41,6 +41,12 @@ true + + false + + + false + true @@ -79,6 +85,7 @@ + @@ -124,6 +131,14 @@ View Folder + + + Reset Icon + + + Remove world icon to make the game re-generate it on next load. + + -- cgit v1.2.3