diff --git a/launcher/Application.cpp b/launcher/Application.cpp index ddeb30588..0e5f3cb3b 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -825,6 +825,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) m_settings->registerSetting("TPDownloadGeometry", ""); m_settings->registerSetting("ShaderDownloadGeometry", ""); m_settings->registerSetting("DataPackDownloadGeometry", ""); + m_settings->registerSetting("SelectInstanceGeometry", ""); // data pack window // in future, more pages may be added - so this name is chosen to avoid needing migration diff --git a/launcher/minecraft/MultiWorldList.cpp b/launcher/minecraft/MultiWorldList.cpp index 8f892f495..cb00d7b05 100644 --- a/launcher/minecraft/MultiWorldList.cpp +++ b/launcher/minecraft/MultiWorldList.cpp @@ -48,9 +48,9 @@ #include "MinecraftInstance.h" -MultiWorldList::MultiWorldList(const QList& instances) : QAbstractListModel(), m_instances(instances) +MultiWorldList::MultiWorldList(const QList& instances) : QAbstractListModel(), allInstances(instances) { - for (BaseInstance* inst : m_instances) { + for (BaseInstance* inst : allInstances) { m_dirs.append(dynamic_cast(inst)->worldDir()); } @@ -109,7 +109,7 @@ bool MultiWorldList::update() QList newWorlds; - for (BaseInstance* inst : m_instances) { + for (BaseInstance* inst : allInstances) { QDir dir = dynamic_cast(inst)->worldDir(); dir.refresh(); auto folderContents = dir.entryInfoList(); @@ -154,7 +154,7 @@ QList MultiWorldList::instDirPaths() const { QList dirList; - for (BaseInstance* instance : m_instances) { //use m_dirs??? iy + for (BaseInstance* instance : allInstances) { dirList.append(QFileInfo(instance->instanceRoot()).absoluteFilePath()); } @@ -399,14 +399,15 @@ Qt::DropActions MultiWorldList::supportedDropActions() const return Qt::CopyAction | Qt::MoveAction; } -void MultiWorldList::installWorld(QFileInfo filename) +void MultiWorldList::installWorld(BaseInstance* instance, QFileInfo filename) { qDebug() << "installing:" << filename.absoluteFilePath(); World w(filename); if (!w.isValid()) { return; } - w.install(m_dirs[0].absolutePath()); //add option for which instance to install to iy + w.install(QDir(dynamic_cast(instance)->worldDir()).absolutePath()); + update(); } bool MultiWorldList::dropMimeData(const QMimeData* data, @@ -434,9 +435,7 @@ bool MultiWorldList::dropMimeData(const QMimeData* data, QFileInfo worldInfo(filename); - if (!m_dirs[0].entryInfoList().contains(worldInfo)) { //same as above, add option for which instance to install to iy - installWorld(worldInfo); - } + emit fileDropped(worldInfo); } if (was_watching) startWatching(); diff --git a/launcher/minecraft/MultiWorldList.h b/launcher/minecraft/MultiWorldList.h index a8b8ae85a..ddd936892 100644 --- a/launcher/minecraft/MultiWorldList.h +++ b/launcher/minecraft/MultiWorldList.h @@ -53,7 +53,7 @@ class MultiWorldList : public QAbstractListModel { virtual bool update(); /// Install a world from location - void installWorld(QFileInfo filename); + void installWorld(BaseInstance* instance, QFileInfo filename); /// Deletes the mod at the given index. virtual bool deleteWorld(int index); @@ -90,17 +90,22 @@ class MultiWorldList : public QAbstractListModel { const QList& allWorlds() const { return m_worlds; } + QList getInstances() const { return allInstances; } + private slots: void directoryChanged(QString path); void loadWorldsAsync(); signals: void changed(); + void fileDropped(QFileInfo worldInfo); protected: - QList m_instances; QFileSystemWatcher* m_watcher; bool m_isWatching; QList m_dirs; QList m_worlds; + + private: + QList allInstances; }; diff --git a/launcher/ui/MultiWorldListPage.cpp b/launcher/ui/MultiWorldListPage.cpp index fbf11f777..7c0c41062 100644 --- a/launcher/ui/MultiWorldListPage.cpp +++ b/launcher/ui/MultiWorldListPage.cpp @@ -60,6 +60,7 @@ #include "ui/GuiUtil.h" #include "Application.h" +#include "icons/IconList.h" #include "pages/instance/DataPackPage.h" class MultiWorldListProxyModel : public QSortFilterProxyModel { @@ -113,6 +114,8 @@ MultiWorldListPage::MultiWorldListPage(MultiWorldList* worlds, QWidget* parent) connect(ui->worldTreeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &MultiWorldListPage::worldChanged); connect(ui->worldTreeView, &QAbstractItemView::doubleClicked, this, &MultiWorldListPage::worldDoubleClicked); worldChanged(QModelIndex(), QModelIndex()); + + connect(m_worlds, &MultiWorldList::fileDropped, this, &MultiWorldListPage::fileDropped); } void MultiWorldListPage::openedImpl() @@ -400,7 +403,11 @@ void MultiWorldListPage::on_actionAdd_triggered() if (!list.empty()) { m_worlds->stopWatching(); for (auto filename : list) { - m_worlds->installWorld(QFileInfo(filename)); + auto *instance = selectInstance(tr("Select instance to add world '%1' to.").arg(QFileInfo(filename).fileName())); + + if (instance != nullptr) { + m_worlds->installWorld(instance, QFileInfo(filename)); + } } m_worlds->startWatching(); } @@ -434,16 +441,68 @@ void MultiWorldListPage::on_actionCopy_triggered() return; auto worldVariant = m_worlds->data(index, MultiWorldList::ObjectRole); - auto world = (World*)worldVariant.value(); + auto *world = static_cast(worldVariant.value()); + 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->world.name(), &ok); if (ok && name.length() > 0) { - world->install(m_worlds->dirs()[0].absolutePath(), name); //ask which instance iy + auto *instance = selectInstance(tr("Select instance to copy world to."), world->instance); + + if (instance != nullptr) { + world->world.install((QDir(instance->worldDir())).absolutePath(), name); + m_worlds->update(); + } } } +Q_DECLARE_METATYPE(BaseInstance*); + +MinecraftInstance* MultiWorldListPage::selectInstance(const QString& message, BaseInstance* preselectedInstance) +{ + auto *dialog = new QDialog(this); + dialog->setWindowTitle(tr("Select Instance")); + + dialog->resize(static_cast(std::max(0.5 * window()->width(), 400.0)), + static_cast(std::max(0.75 * window()->height(), 400.0))); + dialog->restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("SelectInstanceGeometry").toByteArray())); + + auto layout = new QVBoxLayout(dialog); + + layout->addWidget(new QLabel(message)); + + auto instanceList = new QListWidget(dialog); + + for (auto instance : m_worlds->getInstances()) { + auto *item = new QListWidgetItem(instanceList); + item->setText(instance->name()); + item->setIcon(APPLICATION->icons()->getIcon(instance->iconKey())); + item->setData(Qt::UserRole, QVariant::fromValue(instance)); + if (instance == preselectedInstance) { + instanceList->setCurrentItem(item); + } + } + + layout->addWidget(instanceList); + + auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject); + connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept); + layout->addWidget(buttonBox); + + dialog->setLayout(layout); + + connect(dialog, &QDialog::finished, this, + [dialog]() { APPLICATION->settings()->set("SelectInstanceGeometry", dialog->saveGeometry().toBase64()); }); + + if (dialog->exec() == QDialog::Accepted) { + return static_cast(instanceList->currentItem()->data(Qt::UserRole).value()); + } + + return nullptr; +} + void MultiWorldListPage::on_actionRename_triggered() { QModelIndex index = getSelectedWorld(); @@ -495,6 +554,17 @@ void MultiWorldListPage::worldDoubleClicked(const QModelIndex& index) join(proxy->mapToSource(index)); } +void MultiWorldListPage::fileDropped(const QFileInfo& worldInfo) +{ + auto *instance = selectInstance(tr("Select instance to add world '%1' to.").arg(worldInfo.fileName())); + + if (instance != nullptr) { + if (!QDir(instance->worldDir()).entryInfoList().contains(worldInfo)) { + m_worlds->installWorld(instance, worldInfo); + } + } +} + void MultiWorldListPage::on_actionJoin_triggered() { QModelIndex index = getSelectedWorld(); diff --git a/launcher/ui/MultiWorldListPage.h b/launcher/ui/MultiWorldListPage.h index 3114172e8..848bd5a41 100644 --- a/launcher/ui/MultiWorldListPage.h +++ b/launcher/ui/MultiWorldListPage.h @@ -79,6 +79,7 @@ class MultiWorldListPage : public QMainWindow, public BasePage { bool worldSafetyNagQuestion(const QString& actionType); void mceditError(); void join(QModelIndex index); + MinecraftInstance* selectInstance(const QString& message, BaseInstance* instance = nullptr); private: Ui::MultiWorldListPage* ui; @@ -105,6 +106,7 @@ class MultiWorldListPage : public QMainWindow, public BasePage { void mceditState(LoggedProcess::State state); void on_actionJoin_triggered(); void worldDoubleClicked(const QModelIndex& index); + void fileDropped(const QFileInfo& worldInfo); void ShowContextMenu(const QPoint& pos); };