From cdca53013990ac85967394529476712e6695bbf9 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 18 Nov 2013 12:05:35 -0600 Subject: Implement account list and account list dialog --- gui/dialogs/AccountListDialog.cpp | 90 +++++++++++++++++++++++++++++++++++++++ gui/dialogs/AccountListDialog.h | 60 ++++++++++++++++++++++++++ gui/dialogs/AccountListDialog.ui | 83 ++++++++++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+) create mode 100644 gui/dialogs/AccountListDialog.cpp create mode 100644 gui/dialogs/AccountListDialog.h create mode 100644 gui/dialogs/AccountListDialog.ui (limited to 'gui/dialogs') diff --git a/gui/dialogs/AccountListDialog.cpp b/gui/dialogs/AccountListDialog.cpp new file mode 100644 index 00000000..86d34de8 --- /dev/null +++ b/gui/dialogs/AccountListDialog.cpp @@ -0,0 +1,90 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AccountListDialog.h" +#include "ui_AccountListDialog.h" + +#include + +#include + +#include +#include + +AccountListDialog::AccountListDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::AccountListDialog) +{ + ui->setupUi(this); + + ui->listView->setModel(&m_accounts); +} + +AccountListDialog::~AccountListDialog() +{ + delete ui; +} + + +void AccountListDialog::on_addAccountBtn_clicked() +{ + doLogin("Please log in to add your account."); +} + +void AccountListDialog::on_rmAccountBtn_clicked() +{ + // TODO +} + +void AccountListDialog::on_editAccountBtn_clicked() +{ + // TODO +} + +void AccountListDialog::on_closedBtnBox_rejected() +{ + close(); +} + +void AccountListDialog::doLogin(const QString& errMsg) +{ + // TODO: We can use the login dialog for this for now, but we'll have to make something better for it eventually. + LoginDialog loginDialog(this); + loginDialog.exec(); + + if (loginDialog.result() == QDialog::Accepted) + { + QString username(loginDialog.getUsername()); + QString password(loginDialog.getPassword()); + + MojangAccountPtr account = MojangAccountPtr(new MojangAccount(username)); + + ProgressDialog* progDialog = new ProgressDialog(this); + m_authTask = new AuthenticateTask(account, password, progDialog); + connect(m_authTask, SIGNAL(succeeded()), SLOT(onLoginComplete()), Qt::QueuedConnection); + connect(m_authTask, SIGNAL(failed(QString)), SLOT(doLogin(QString)), Qt::QueuedConnection); + progDialog->exec(m_authTask); + //delete m_authTask; + } +} + +void AccountListDialog::onLoginComplete() +{ + // Add the authenticated account to the accounts list. + MojangAccountPtr account = m_authTask->getMojangAccount(); + m_accounts.addAccount(account); + //ui->listView->update(); +} + diff --git a/gui/dialogs/AccountListDialog.h b/gui/dialogs/AccountListDialog.h new file mode 100644 index 00000000..442834ef --- /dev/null +++ b/gui/dialogs/AccountListDialog.h @@ -0,0 +1,60 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "logic/lists/MojangAccountList.h" + +namespace Ui { +class AccountListDialog; +} + +class AuthenticateTask; + +class AccountListDialog : public QDialog +{ +Q_OBJECT +public: + explicit AccountListDialog(QWidget *parent = 0); + ~AccountListDialog(); + +public +slots: + void on_addAccountBtn_clicked(); + + void on_rmAccountBtn_clicked(); + + void on_editAccountBtn_clicked(); + + // This will be sent when the "close" button is clicked. + void on_closedBtnBox_rejected(); + +protected: + // Temporarily putting this here... + MojangAccountList m_accounts; + + AuthenticateTask* m_authTask; + +protected +slots: + void doLogin(const QString& errMsg=""); + void onLoginComplete(); + +private: + Ui::AccountListDialog *ui; +}; + diff --git a/gui/dialogs/AccountListDialog.ui b/gui/dialogs/AccountListDialog.ui new file mode 100644 index 00000000..034985a9 --- /dev/null +++ b/gui/dialogs/AccountListDialog.ui @@ -0,0 +1,83 @@ + + + AccountListDialog + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + + <html><head/><body><p>Welcome! If you're new here, you can click the &quot;Add&quot; button to add your Mojang or Minecraft account.</p></body></html> + + + true + + + + + + + + + + + + + + &Add + + + + + + + &Edit + + + + + + + &Remove + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + QDialogButtonBox::Close + + + + + + + + -- cgit From a9a0b65358b3799746fa9c8e1aa879e0b59ef526 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 18 Nov 2013 12:58:03 -0600 Subject: Implement loading accounts from list. --- MultiMC.cpp | 6 +++ MultiMC.h | 7 +++ gui/dialogs/AccountListDialog.cpp | 7 ++- gui/dialogs/AccountListDialog.h | 5 ++- logic/auth/MojangAccount.h | 20 +++++++-- logic/lists/MojangAccountList.cpp | 89 +++++++++++++++++++++++++++++++++++++++ logic/lists/MojangAccountList.h | 14 ++++++ 7 files changed, 141 insertions(+), 7 deletions(-) (limited to 'gui/dialogs') diff --git a/MultiMC.cpp b/MultiMC.cpp index 1c70fb54..ae1401a6 100644 --- a/MultiMC.cpp +++ b/MultiMC.cpp @@ -10,6 +10,7 @@ #include "gui/MainWindow.h" #include "gui/dialogs/VersionSelectDialog.h" #include "logic/lists/InstanceList.h" +#include "logic/lists/MojangAccountList.h" #include "logic/lists/IconList.h" #include "logic/lists/LwjglVersionList.h" #include "logic/lists/MinecraftVersionList.h" @@ -146,6 +147,11 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv) connect(InstDirSetting, SIGNAL(settingChanged(const Setting &, QVariant)), m_instances.get(), SLOT(on_InstFolderChanged(const Setting &, QVariant))); + // and accounts + m_accounts.reset(new MojangAccountList(this)); + QLOG_INFO() << "Loading accounts..."; + m_accounts->loadList(); + // init the http meta cache initHttpMetaCache(); diff --git a/MultiMC.h b/MultiMC.h index cd4a5f7d..dba923b1 100644 --- a/MultiMC.h +++ b/MultiMC.h @@ -13,6 +13,7 @@ class LWJGLVersionList; class HttpMetaCache; class SettingsObject; class InstanceList; +class MojangAccountList; class IconList; class QNetworkAccessManager; class ForgeVersionList; @@ -57,6 +58,11 @@ public: return m_instances; } + std::shared_ptr accounts() + { + return m_accounts; + } + std::shared_ptr icons(); Status status() @@ -101,6 +107,7 @@ private: std::shared_ptr m_mmc_translator; std::shared_ptr m_settings; std::shared_ptr m_instances; + std::shared_ptr m_accounts; std::shared_ptr m_icons; std::shared_ptr m_qnam; std::shared_ptr m_metacache; diff --git a/gui/dialogs/AccountListDialog.cpp b/gui/dialogs/AccountListDialog.cpp index 86d34de8..5a73cb18 100644 --- a/gui/dialogs/AccountListDialog.cpp +++ b/gui/dialogs/AccountListDialog.cpp @@ -23,13 +23,16 @@ #include #include +#include + AccountListDialog::AccountListDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AccountListDialog) { ui->setupUi(this); - ui->listView->setModel(&m_accounts); + m_accounts = MMC->accounts(); + ui->listView->setModel(m_accounts.get()); } AccountListDialog::~AccountListDialog() @@ -84,7 +87,7 @@ void AccountListDialog::onLoginComplete() { // Add the authenticated account to the accounts list. MojangAccountPtr account = m_authTask->getMojangAccount(); - m_accounts.addAccount(account); + m_accounts->addAccount(account); //ui->listView->update(); } diff --git a/gui/dialogs/AccountListDialog.h b/gui/dialogs/AccountListDialog.h index 442834ef..57c8b460 100644 --- a/gui/dialogs/AccountListDialog.h +++ b/gui/dialogs/AccountListDialog.h @@ -17,6 +17,8 @@ #include +#include + #include "logic/lists/MojangAccountList.h" namespace Ui { @@ -44,8 +46,7 @@ slots: void on_closedBtnBox_rejected(); protected: - // Temporarily putting this here... - MojangAccountList m_accounts; + std::shared_ptr m_accounts; AuthenticateTask* m_authTask; diff --git a/logic/auth/MojangAccount.h b/logic/auth/MojangAccount.h index a38cb8f7..35261d65 100644 --- a/logic/auth/MojangAccount.h +++ b/logic/auth/MojangAccount.h @@ -18,9 +18,16 @@ #include #include #include +#include #include +class MojangAccount; + +typedef std::shared_ptr MojangAccountPtr; +Q_DECLARE_METATYPE(MojangAccountPtr) + + /** * Class that represents a profile within someone's Mojang account. * @@ -71,6 +78,16 @@ public: */ MojangAccount(const MojangAccount& other, QObject* parent); + /** + * Loads a MojangAccount from the given JSON object. + */ + static MojangAccountPtr loadFromJson(const QJsonObject& json); + + /** + * Saves a MojangAccount to a JSON object and returns it. + */ + QJsonObject saveToJson(); + /** * This MojangAccount's username. May be an email address if the account is migrated. @@ -130,6 +147,3 @@ protected: ProfileList m_profiles; // List of available profiles. }; -typedef std::shared_ptr MojangAccountPtr; -Q_DECLARE_METATYPE(MojangAccountPtr) - diff --git a/logic/lists/MojangAccountList.cpp b/logic/lists/MojangAccountList.cpp index d309d63a..40f0ea26 100644 --- a/logic/lists/MojangAccountList.cpp +++ b/logic/lists/MojangAccountList.cpp @@ -14,8 +14,23 @@ */ #include "logic/lists/MojangAccountList.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "logger/QsLog.h" + #include "logic/auth/MojangAccount.h" +#define DEFAULT_ACCOUNT_LIST_FILE "accounts.json" + +#define ACCOUNT_LIST_FORMAT_VERSION 1 + MojangAccountList::MojangAccountList(QObject *parent) : QAbstractListModel(parent) { } @@ -144,3 +159,77 @@ void MojangAccountList::updateListData(QList versions) m_accounts = versions; endResetModel(); } + +bool MojangAccountList::loadList(const QString& filePath) +{ + QString path = filePath; + if (path.isEmpty()) path = DEFAULT_ACCOUNT_LIST_FILE; + + QFile file(path); + + // Try to open the file and fail if we can't. + // TODO: We should probably report this error to the user. + if (!file.open(QIODevice::ReadOnly)) + { + QLOG_ERROR() << "Failed to read the account list file (" << path << ")."; + return false; + } + + // Read the file and close it. + QByteArray jsonData = file.readAll(); + file.close(); + + QJsonParseError parseError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError); + + // Fail if the JSON is invalid. + if (parseError.error != QJsonParseError::NoError) + { + QLOG_ERROR() << QString("Failed to parse account list file: %1 at offset %2") + .arg(parseError.errorString(), QString::number(parseError.offset)) + .toUtf8(); + return false; + } + + // Make sure the root is an object. + if (!jsonDoc.isObject()) + { + QLOG_ERROR() << "Invalid account list JSON: Root should be an array."; + return false; + } + + QJsonObject root = jsonDoc.object(); + + // Make sure the format version matches. + if (root.value("formatVersion").toVariant().toInt() != ACCOUNT_LIST_FORMAT_VERSION) + { + QString newName = "accountlist-old.json"; + QLOG_WARN() << "Format version mismatch when loading account list. Existing one will be renamed to \"" + << newName << "\"."; + + // Attempt to rename the old version. + file.rename(newName); + return false; + } + + // Now, load the accounts array. + beginResetModel(); + QJsonArray accounts = root.value("accounts").toArray(); + for (QJsonValue accountVal : accounts) + { + QJsonObject accountObj = accountVal.toObject(); + MojangAccountPtr account = MojangAccount::loadFromJson(accountObj); + if (account.get() != nullptr) + { + m_accounts.append(account); + } + else + { + QLOG_WARN() << "Failed to load an account."; + } + } + endResetModel(); + + return true; +} + diff --git a/logic/lists/MojangAccountList.h b/logic/lists/MojangAccountList.h index ce16d70d..37c928de 100644 --- a/logic/lists/MojangAccountList.h +++ b/logic/lists/MojangAccountList.h @@ -80,6 +80,20 @@ public: */ virtual MojangAccountPtr findAccount(const QString &username); + /*! + * \brief Loads the account list from the given file path. + * If the given file is an empty string (default), will load from the default account list file. + * \return True if successful, otherwise false. + */ + virtual bool loadList(const QString& file=""); + + /*! + * \brief Saves the account list to the given file. + * If the given file is an empty string (default), will save from the default account list file. + * \return True if successful, otherwise false. + */ + virtual bool saveList(const QString& file=""); + signals: /*! * Signal emitted to indicate that the account list has changed. -- cgit From 03652b01d2ec8a7c54fb39dd8ed660f0bbc2fa2a Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 20 Nov 2013 12:20:35 -0600 Subject: Add a button to open the account list. Also fix the account list dialog's close button. --- gui/MainWindow.cpp | 7 +++++++ gui/MainWindow.h | 2 ++ gui/MainWindow.ui | 9 +++++++++ gui/dialogs/AccountListDialog.cpp | 2 +- gui/dialogs/AccountListDialog.h | 2 +- 5 files changed, 20 insertions(+), 2 deletions(-) (limited to 'gui/dialogs') diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 62ae195b..3bf248f9 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -57,6 +57,7 @@ #include "gui/dialogs/IconPickerDialog.h" #include "gui/dialogs/EditNotesDialog.h" #include "gui/dialogs/CopyInstanceDialog.h" +#include "gui/dialogs/AccountListDialog.h" #include "gui/ConsoleWindow.h" @@ -427,6 +428,12 @@ void MainWindow::on_actionSettings_triggered() proxymodel->sort(0); } +void MainWindow::on_actionManageAccounts_triggered() +{ + AccountListDialog dialog(this); + dialog.exec(); +} + void MainWindow::on_actionReportBug_triggered() { openWebPage(QUrl("http://multimc.myjetbrains.com/youtrack/dashboard#newissue=yes")); diff --git a/gui/MainWindow.h b/gui/MainWindow.h index 97aa0d9f..b89aab7c 100644 --- a/gui/MainWindow.h +++ b/gui/MainWindow.h @@ -79,6 +79,8 @@ slots: void on_actionSettings_triggered(); + void on_actionManageAccounts_triggered(); + void on_actionReportBug_triggered(); void on_actionNews_triggered(); diff --git a/gui/MainWindow.ui b/gui/MainWindow.ui index 6f70fc98..f76d4d4e 100644 --- a/gui/MainWindow.ui +++ b/gui/MainWindow.ui @@ -70,6 +70,7 @@ + @@ -465,6 +466,14 @@ Add a new instance. + + + Manage Accounts + + + Manage your Mojang or Minecraft accounts. + + diff --git a/gui/dialogs/AccountListDialog.cpp b/gui/dialogs/AccountListDialog.cpp index 5a73cb18..af074514 100644 --- a/gui/dialogs/AccountListDialog.cpp +++ b/gui/dialogs/AccountListDialog.cpp @@ -56,7 +56,7 @@ void AccountListDialog::on_editAccountBtn_clicked() // TODO } -void AccountListDialog::on_closedBtnBox_rejected() +void AccountListDialog::on_closeBtnBox_rejected() { close(); } diff --git a/gui/dialogs/AccountListDialog.h b/gui/dialogs/AccountListDialog.h index 57c8b460..99dee639 100644 --- a/gui/dialogs/AccountListDialog.h +++ b/gui/dialogs/AccountListDialog.h @@ -43,7 +43,7 @@ slots: void on_editAccountBtn_clicked(); // This will be sent when the "close" button is clicked. - void on_closedBtnBox_rejected(); + void on_closeBtnBox_rejected(); protected: std::shared_ptr m_accounts; -- cgit From 23bc195b3c8558cb997789ca8772342612716993 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 22 Nov 2013 10:54:52 -0600 Subject: Implement removing accounts. --- gui/dialogs/AccountListDialog.cpp | 9 ++++++++- logic/lists/MojangAccountList.cpp | 8 ++++++++ logic/lists/MojangAccountList.h | 5 +++++ 3 files changed, 21 insertions(+), 1 deletion(-) (limited to 'gui/dialogs') diff --git a/gui/dialogs/AccountListDialog.cpp b/gui/dialogs/AccountListDialog.cpp index af074514..838bef7f 100644 --- a/gui/dialogs/AccountListDialog.cpp +++ b/gui/dialogs/AccountListDialog.cpp @@ -16,6 +16,8 @@ #include "AccountListDialog.h" #include "ui_AccountListDialog.h" +#include + #include #include @@ -48,7 +50,12 @@ void AccountListDialog::on_addAccountBtn_clicked() void AccountListDialog::on_rmAccountBtn_clicked() { - // TODO + QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes(); + if (selection.size() > 0) + { + QModelIndex selected = selection.first(); + m_accounts->removeAccount(selected); + } } void AccountListDialog::on_editAccountBtn_clicked() diff --git a/logic/lists/MojangAccountList.cpp b/logic/lists/MojangAccountList.cpp index 32317f84..442ef3af 100644 --- a/logic/lists/MojangAccountList.cpp +++ b/logic/lists/MojangAccountList.cpp @@ -73,6 +73,14 @@ void MojangAccountList::removeAccount(const QString& username) onListChanged(); } +void MojangAccountList::removeAccount(QModelIndex index) +{ + beginResetModel(); + m_accounts.removeAt(index.row()); + endResetModel(); + onListChanged(); +} + void MojangAccountList::onListChanged() { diff --git a/logic/lists/MojangAccountList.h b/logic/lists/MojangAccountList.h index 491abf6d..bccc2f9a 100644 --- a/logic/lists/MojangAccountList.h +++ b/logic/lists/MojangAccountList.h @@ -72,6 +72,11 @@ public: */ virtual void removeAccount(const QString& username); + /*! + * Removes the account at the given QModelIndex. + */ + virtual void removeAccount(QModelIndex index); + /*! * \brief Finds an account by its username. * \param The username of the account to find. -- cgit From 75e7932607bdd84d2867765eb6f07dcec95ee193 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 22 Nov 2013 12:47:39 -0600 Subject: Properly implement launching and downloading Also added a system to select an active account to log in with. --- gui/MainWindow.cpp | 147 +++++++++++++++----------------------- gui/MainWindow.h | 12 ++-- gui/dialogs/AccountListDialog.cpp | 12 ++++ gui/dialogs/AccountListDialog.h | 2 + gui/dialogs/AccountListDialog.ui | 12 +++- logic/lists/MojangAccountList.cpp | 37 +++++++++- logic/lists/MojangAccountList.h | 29 +++++++- 7 files changed, 148 insertions(+), 103 deletions(-) (limited to 'gui/dialogs') diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 9824d52f..7ea67764 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -85,11 +85,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi ui->setupUi(this); setWindowTitle(QString("MultiMC %1").arg(MMC->version().toString())); - // Set the selected instance to null - m_selectedInstance = nullptr; - // Set active instance to null. - m_activeInst = nullptr; - // OSX magic. setUnifiedTitleAndToolBarOnMac(true); @@ -563,7 +558,7 @@ void MainWindow::doLogin(const QString &errorMsg) // Find an account to use. std::shared_ptr accounts = MMC->accounts(); - MojangAccountPtr account; + MojangAccountPtr account = accounts->activeAccount(); if (accounts->count() <= 0) { // Tell the user they need to log in at least one account in order to play. @@ -577,107 +572,53 @@ void MainWindow::doLogin(const QString &errorMsg) // Open the account manager. on_actionManageAccounts_triggered(); } - return; } - else + else if (account.get() == nullptr) { - // TODO: Allow user to select different accounts. - // For now, we'll just use the first one in the list until I get arround to implementing that. - account = accounts->at(0); - } - - // We'll need to validate the access token to make sure the account is still logged in. - // TODO: Do that ^ - - launchInstance(m_selectedInstance, account); - - /* - LoginDialog *loginDlg = new LoginDialog(this, errorMsg); - if (!m_selectedInstance->lastLaunch()) - loginDlg->forceOnline(); + // Tell the user they need to log in at least one account in order to play. + auto reply = CustomMessageBox::selectable(this, tr("No Account Selected"), + tr("You don't have an account selected as an active account." + "Would you like to open the account manager to select one now?"), + QMessageBox::Information, QMessageBox::Yes | QMessageBox::No)->exec(); - loginDlg->exec(); - if (loginDlg->result() == QDialog::Accepted) - { - if (loginDlg->isOnline()) - { - m_activeInst = m_selectedInstance; - doLogin(loginDlg->getUsername(), loginDlg->getPassword()); - } - else + if (reply == QMessageBox::Yes) { - QString user = loginDlg->getUsername(); - if (user.length() == 0) - user = QString("Player"); - m_activeLogin = {user, QString("Offline"), user, QString()}; - m_activeInst = m_selectedInstance; - launchInstance(m_activeInst, m_activeLogin); + // Open the account manager. + on_actionManageAccounts_triggered(); } } - */ -} - -void MainWindow::launchInstance(BaseInstance *instance, MojangAccountPtr account) -{ - Q_ASSERT_X(instance != NULL, "launchInstance", "instance is NULL"); - Q_ASSERT_X(account.get() != nullptr, "launchInstance", "account is NULL"); - - proc = instance->prepareForLaunch(account); - if (!proc) - return; - - // Prepare GUI: If it shall stay open disable the required parts - if (MMC->settings()->get("NoHide").toBool()) - { - ui->actionLaunchInstance->setEnabled(false); - } else { - this->hide(); + // We'll need to validate the access token to make sure the account is still logged in. + // TODO: Do that ^ + + prepareLaunch(m_selectedInstance, account); } - - console = new ConsoleWindow(proc); - - connect(proc, SIGNAL(log(QString, MessageLevel::Enum)), console, - SLOT(write(QString, MessageLevel::Enum))); - connect(proc, SIGNAL(ended(BaseInstance *)), this, SLOT(instanceEnded(BaseInstance *))); - - if (instance->settings().get("ShowConsole").toBool()) - { - console->show(); - } - - // I think this will work... - proc->setLogin(account->username(), account->accessToken()); - proc->launch(); } -void MainWindow::onLoginComplete() +void MainWindow::prepareLaunch(BaseInstance* instance, MojangAccountPtr account) { - if (!m_activeInst) - return; - LoginTask *task = (LoginTask *)QObject::sender(); - m_activeLogin = task->getResult(); - - BaseUpdate *updateTask = m_activeInst->doUpdate(); + BaseUpdate *updateTask = instance->doUpdate(); if (!updateTask) { - //launchInstance(m_activeInst, m_activeLogin); + launchInstance(instance, account); } else { ProgressDialog tDialog(this); - connect(updateTask, SIGNAL(succeeded()), SLOT(onGameUpdateComplete())); + connect(updateTask, &BaseUpdate::succeeded, [this, instance, account] { launchInstance(instance, account); }); connect(updateTask, SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString))); tDialog.exec(updateTask); delete updateTask; } - auto job = new NetJob("Player skin: " + m_activeLogin.player_name); + QString playerName = account->currentProfile()->name(); + + auto job = new NetJob("Player skin: " + playerName); - auto meta = MMC->metacache()->resolveEntry("skins", m_activeLogin.player_name + ".png"); + auto meta = MMC->metacache()->resolveEntry("skins", playerName + ".png"); auto action = CacheDownload::make( - QUrl("http://skins.minecraft.net/MinecraftSkins/" + m_activeLogin.player_name + ".png"), + QUrl("http://skins.minecraft.net/MinecraftSkins/" + playerName + ".png"), meta); job->addNetAction(action); meta->stale = true; @@ -702,12 +643,12 @@ void MainWindow::onLoginComplete() QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); QJsonObject root = jsonDoc.object(); QJsonObject mappings = root.value("mappings").toObject(); - QJsonArray usernames = mappings.value(m_activeLogin.username).toArray(); + QJsonArray usernames = mappings.value(account->username()).toArray(); - if (!usernames.contains(m_activeLogin.player_name)) + if (!usernames.contains(playerName)) { - usernames.prepend(m_activeLogin.player_name); - mappings[m_activeLogin.username] = usernames; + usernames.prepend(playerName); + mappings[account->username()] = usernames; root["mappings"] = mappings; jsonDoc.setObject(root); @@ -717,9 +658,39 @@ void MainWindow::onLoginComplete() } } -void MainWindow::onGameUpdateComplete() +void MainWindow::launchInstance(BaseInstance *instance, MojangAccountPtr account) { - //launchInstance(m_activeInst, m_activeLogin); + Q_ASSERT_X(instance != NULL, "launchInstance", "instance is NULL"); + Q_ASSERT_X(account.get() != nullptr, "launchInstance", "account is NULL"); + + proc = instance->prepareForLaunch(account); + if (!proc) + return; + + // Prepare GUI: If it shall stay open disable the required parts + if (MMC->settings()->get("NoHide").toBool()) + { + ui->actionLaunchInstance->setEnabled(false); + } + else + { + this->hide(); + } + + console = new ConsoleWindow(proc); + + connect(proc, SIGNAL(log(QString, MessageLevel::Enum)), console, + SLOT(write(QString, MessageLevel::Enum))); + connect(proc, SIGNAL(ended(BaseInstance *)), this, SLOT(instanceEnded(BaseInstance *))); + + if (instance->settings().get("ShowConsole").toBool()) + { + console->show(); + } + + // I think this will work... + proc->setLogin(account->username(), account->accessToken()); + proc->launch(); } void MainWindow::onGameUpdateError(QString error) diff --git a/gui/MainWindow.h b/gui/MainWindow.h index c0fcc385..f88905bf 100644 --- a/gui/MainWindow.h +++ b/gui/MainWindow.h @@ -113,9 +113,11 @@ slots: */ void launchInstance(BaseInstance* instance, MojangAccountPtr account); - void onLoginComplete(); + /*! + * Prepares the given instance for launch with the given account. + */ + void prepareLaunch(BaseInstance* instance, MojangAccountPtr account); - void onGameUpdateComplete(); void onGameUpdateError(QString error); void taskStart(); @@ -160,12 +162,6 @@ private: BaseInstance *m_selectedInstance; - // A pointer to the instance we are actively doing stuff with. - // This is set when the user launches an instance and is used to refer to that - // instance throughout the launching process. - BaseInstance *m_activeInst; - LoginResponse m_activeLogin; - Task *m_versionLoadTask; QLabel *m_statusLeft; diff --git a/gui/dialogs/AccountListDialog.cpp b/gui/dialogs/AccountListDialog.cpp index 838bef7f..c685c164 100644 --- a/gui/dialogs/AccountListDialog.cpp +++ b/gui/dialogs/AccountListDialog.cpp @@ -34,6 +34,7 @@ AccountListDialog::AccountListDialog(QWidget *parent) : ui->setupUi(this); m_accounts = MMC->accounts(); + // TODO: Make the "Active?" column show checkboxes or radio buttons. ui->listView->setModel(m_accounts.get()); } @@ -63,6 +64,17 @@ void AccountListDialog::on_editAccountBtn_clicked() // TODO } +void AccountListDialog::on_setActiveBtn_clicked() +{ + QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes(); + if (selection.size() > 0) + { + QModelIndex selected = selection.first(); + MojangAccountPtr account = selected.data(MojangAccountList::PointerRole).value(); + m_accounts->setActiveAccount(account->username()); + } +} + void AccountListDialog::on_closeBtnBox_rejected() { close(); diff --git a/gui/dialogs/AccountListDialog.h b/gui/dialogs/AccountListDialog.h index 99dee639..17a50bec 100644 --- a/gui/dialogs/AccountListDialog.h +++ b/gui/dialogs/AccountListDialog.h @@ -42,6 +42,8 @@ slots: void on_editAccountBtn_clicked(); + void on_setActiveBtn_clicked(); + // This will be sent when the "close" button is clicked. void on_closeBtnBox_rejected(); diff --git a/gui/dialogs/AccountListDialog.ui b/gui/dialogs/AccountListDialog.ui index 034985a9..2872b368 100644 --- a/gui/dialogs/AccountListDialog.ui +++ b/gui/dialogs/AccountListDialog.ui @@ -27,7 +27,7 @@ - + @@ -65,6 +65,16 @@ + + + + <html><head/><body><p>Set the currently selected account as the active account. The active account is the account that is used to log in (unless it is overridden in an instance-specific setting).</p></body></html> + + + &Set Active + + + diff --git a/logic/lists/MojangAccountList.cpp b/logic/lists/MojangAccountList.cpp index 442ef3af..1d67c70f 100644 --- a/logic/lists/MojangAccountList.cpp +++ b/logic/lists/MojangAccountList.cpp @@ -33,7 +33,7 @@ MojangAccountList::MojangAccountList(QObject *parent) : QAbstractListModel(paren { } -MojangAccountPtr MojangAccountList::findAccount(const QString &username) +MojangAccountPtr MojangAccountList::findAccount(const QString &username) const { for (int i = 0; i < count(); i++) { @@ -41,7 +41,7 @@ MojangAccountPtr MojangAccountList::findAccount(const QString &username) if (account->username() == username) return account; } - return MojangAccountPtr(); + return nullptr; } @@ -82,6 +82,25 @@ void MojangAccountList::removeAccount(QModelIndex index) } +MojangAccountPtr MojangAccountList::activeAccount() const +{ + if (m_activeAccount.isEmpty()) + return nullptr; + else + return findAccount(m_activeAccount); +} + +void MojangAccountList::setActiveAccount(const QString& username) +{ + beginResetModel(); + for (MojangAccountPtr account : m_accounts) + if (account->username() == username) + m_activeAccount = username; + endResetModel(); + onListChanged(); +} + + void MojangAccountList::onListChanged() { if (m_autosave) @@ -112,6 +131,9 @@ QVariant MojangAccountList::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { + case ActiveColumn: + return account->username() == m_activeAccount; + case NameColumn: return account->username(); @@ -137,6 +159,9 @@ QVariant MojangAccountList::headerData(int section, Qt::Orientation orientation, case Qt::DisplayRole: switch (section) { + case ActiveColumn: + return "Active?"; + case NameColumn: return "Name"; @@ -167,7 +192,7 @@ int MojangAccountList::rowCount(const QModelIndex &parent) const int MojangAccountList::columnCount(const QModelIndex &parent) const { - return 1; + return 2; } void MojangAccountList::updateListData(QList versions) @@ -251,6 +276,9 @@ bool MojangAccountList::loadList(const QString& filePath) } } endResetModel(); + + // Load the active account. + m_activeAccount = root.value("activeAccount").toString(""); return true; } @@ -285,6 +313,9 @@ bool MojangAccountList::saveList(const QString& filePath) // Insert the account list into the root object. root.insert("accounts", accounts); + // Save the active account. + root.insert("activeAccount", m_activeAccount); + // Create a JSON document object to convert our JSON to bytes. QJsonDocument doc(root); diff --git a/logic/lists/MojangAccountList.h b/logic/lists/MojangAccountList.h index bccc2f9a..71f472f7 100644 --- a/logic/lists/MojangAccountList.h +++ b/logic/lists/MojangAccountList.h @@ -44,8 +44,12 @@ public: enum VListColumns { // TODO: Add icon column. - // First column - Name - NameColumn = 0, + + // First column - Active? + ActiveColumn = 0, + + // Second column - Name + NameColumn, }; explicit MojangAccountList(QObject *parent = 0); @@ -83,7 +87,7 @@ public: * \return A const pointer to the account with the given username. NULL if * one doesn't exist. */ - virtual MojangAccountPtr findAccount(const QString &username); + virtual MojangAccountPtr findAccount(const QString &username) const; /*! * Sets the default path to save the list file to. @@ -108,6 +112,19 @@ public: */ virtual bool saveList(const QString& file=""); + /*! + * \brief Gets a pointer to the account that the user has selected as their "active" account. + * Which account is active can be overridden on a per-instance basis, but this will return the one that + * is set as active globally. + * \return The currently active MojangAccount. If there isn't an active account, returns a null pointer. + */ + virtual MojangAccountPtr activeAccount() const; + + /*! + * Sets the given account as the current active account. + */ + virtual void setActiveAccount(const QString& username); + signals: /*! * Signal emitted to indicate that the account list has changed. @@ -124,6 +141,12 @@ protected: QList m_accounts; + /*! + * Username of the account that is currently active. + * Empty string if no account is active. + */ + QString m_activeAccount; + //! Path to the account list file. Empty string if there isn't one. QString m_listFilePath; -- cgit