diff options
Diffstat (limited to 'gui')
-rw-r--r-- | gui/ConsoleWindow.cpp | 7 | ||||
-rw-r--r-- | gui/MainWindow.cpp | 62 | ||||
-rw-r--r-- | gui/MainWindow.h | 2 | ||||
-rw-r--r-- | gui/MainWindow.ui | 17 | ||||
-rw-r--r-- | gui/dialogs/AccountListDialog.cpp | 71 | ||||
-rw-r--r-- | gui/dialogs/LoginDialog.cpp | 110 | ||||
-rw-r--r-- | gui/dialogs/LoginDialog.h | 58 | ||||
-rw-r--r-- | gui/dialogs/LoginDialog.ui | 77 | ||||
-rw-r--r-- | gui/dialogs/VersionSelectDialog.cpp | 4 |
9 files changed, 353 insertions, 55 deletions
diff --git a/gui/ConsoleWindow.cpp b/gui/ConsoleWindow.cpp index 621f035f..18a617e0 100644 --- a/gui/ConsoleWindow.cpp +++ b/gui/ConsoleWindow.cpp @@ -265,6 +265,13 @@ void ConsoleWindow::onEnded(BaseInstance *instance, int code, QProcess::ExitStat */ if (!isVisible()) show(); + + // Raise Window + if (MMC->settings()->get("RaiseConsole").toBool()) + { + raise(); + activateWindow(); + } } void ConsoleWindow::onLaunchFailed(BaseInstance *instance) diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index ce09c42d..b0e86249 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -35,6 +35,7 @@ #include <QToolButton> #include <QWidgetAction> #include <QProgressDialog> +#include <QShortcut> #include "osutils.h" #include "userutils.h" @@ -116,6 +117,13 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi // OSX magic. // setUnifiedTitleAndToolBarOnMac(true); + // Global shortcuts + { + //FIXME: This is kinda weird. and bad. We need some kind of managed shutdown. + auto q = new QShortcut(QKeySequence::Quit, this); + connect(q, SIGNAL(activated()), qApp, SLOT(quit())); + } + // The instance action toolbar customizations { // disabled until we have an instance selected @@ -353,25 +361,52 @@ void MainWindow::skinJobFinished() void MainWindow::showInstanceContextMenu(const QPoint &pos) { - if (!view->indexAt(pos).isValid()) + QList<QAction *> actions; + + QAction *actionSep = new QAction("", this); + actionSep->setSeparator(true); + + bool onInstance = view->indexAt(pos).isValid(); + if (onInstance) { - return; - } + actions = ui->instanceToolBar->actions(); + + QAction *actionVoid = new QAction(m_selectedInstance->name(), this); + actionVoid->setEnabled(false); + + QAction *actionRename = new QAction(tr("Rename"), this); + actionRename->setToolTip(ui->actionRenameInstance->toolTip()); - QList<QAction *> actions = ui->instanceToolBar->actions(); + QAction *actionCopyInstance = new QAction(tr("Copy instance"), this); + actionCopyInstance->setToolTip(ui->actionCopyInstance->toolTip()); - // HACK: Filthy rename button hack because the instance view is getting rewritten anyway - QAction *actionRename; - actionRename = new QAction(tr("Rename"), this); - actionRename->setToolTip(ui->actionRenameInstance->toolTip()); - connect(actionRename, SIGNAL(triggered(bool)), SLOT(on_actionRenameInstance_triggered())); + connect(actionRename, SIGNAL(triggered(bool)), SLOT(on_actionRenameInstance_triggered())); + connect(actionCopyInstance, SIGNAL(triggered(bool)), SLOT(on_actionCopyInstance_triggered())); - actions.replace(1, actionRename); + actions.replace(1, actionRename); + actions.prepend(actionSep); + actions.prepend(actionVoid); + actions.append(actionCopyInstance); + } + else + { + QAction *actionVoid = new QAction(tr("MultiMC"), this); + actionVoid->setEnabled(false); + + QAction *actionCreateInstance = new QAction(tr("Create instance"), this); + actionCreateInstance->setToolTip(ui->actionAddInstance->toolTip()); + + connect(actionCreateInstance, SIGNAL(triggered(bool)), SLOT(on_actionAddInstance_triggered())); + actions.prepend(actionSep); + actions.prepend(actionVoid); + actions.append(actionCreateInstance); + } QMenu myMenu; myMenu.addActions(actions); - myMenu.setEnabled(m_selectedInstance->canLaunch()); + if(onInstance) + myMenu.setEnabled(m_selectedInstance->canLaunch()); myMenu.exec(view->mapToGlobal(pos)); } @@ -988,6 +1023,11 @@ void MainWindow::on_actionReportBug_triggered() openWebPage(QUrl("https://github.com/MultiMC/MultiMC5/issues")); } +void MainWindow::on_actionPatreon_triggered() +{ + openWebPage(QUrl("http://www.patreon.com/multimc")); +} + void MainWindow::on_actionMoreNews_triggered() { openWebPage(QUrl("http://multimc.org/posts.html")); diff --git a/gui/MainWindow.h b/gui/MainWindow.h index 5ddfef7b..d610a87d 100644 --- a/gui/MainWindow.h +++ b/gui/MainWindow.h @@ -85,6 +85,8 @@ slots: void on_actionReportBug_triggered(); + void on_actionPatreon_triggered(); + void on_actionMoreNews_triggered(); void newsButtonClicked(); diff --git a/gui/MainWindow.ui b/gui/MainWindow.ui index 2bd8ec22..1d7fbec9 100644 --- a/gui/MainWindow.ui +++ b/gui/MainWindow.ui @@ -74,6 +74,7 @@ <addaction name="actionReportBug"/> <addaction name="actionAbout"/> <addaction name="separator"/> + <addaction name="actionPatreon"/> <addaction name="actionCAT"/> </widget> <widget class="QStatusBar" name="statusBar"/> @@ -268,6 +269,22 @@ <string>Open the bug tracker to report a bug with MultiMC.</string> </property> </action> + <action name="actionPatreon"> + <property name="icon"> + <iconset theme="patreon"> + <normaloff/> + </iconset> + </property> + <property name="text"> + <string>Support us on Patreon!</string> + </property> + <property name="toolTip"> + <string>Open the MultiMC Patreon page.</string> + </property> + <property name="statusTip"> + <string>Open the MultiMC Patreon page.</string> + </property> + </action> <action name="actionMoreNews"> <property name="icon"> <iconset theme="news"> diff --git a/gui/dialogs/AccountListDialog.cpp b/gui/dialogs/AccountListDialog.cpp index a38035a6..688cffa8 100644 --- a/gui/dialogs/AccountListDialog.cpp +++ b/gui/dialogs/AccountListDialog.cpp @@ -26,6 +26,7 @@ #include <gui/dialogs/EditAccountDialog.h> #include <gui/dialogs/ProgressDialog.h> #include <gui/dialogs/AccountSelectDialog.h> +#include <gui/dialogs/LoginDialog.h> #include "CustomMessageBox.h" #include <logic/tasks/Task.h> #include <logic/auth/YggdrasilTask.h> @@ -45,10 +46,11 @@ AccountListDialog::AccountListDialog(QWidget *parent) // Expand the account column ui->listView->header()->setSectionResizeMode(1, QHeaderView::Stretch); - QItemSelectionModel* selectionModel = ui->listView->selectionModel(); + QItemSelectionModel *selectionModel = ui->listView->selectionModel(); - connect(selectionModel, &QItemSelectionModel::selectionChanged, - [this] (const QItemSelection& sel, const QItemSelection& dsel) { updateButtonStates(); }); + connect(selectionModel, &QItemSelectionModel::selectionChanged, + [this](const QItemSelection &sel, const QItemSelection &dsel) + { updateButtonStates(); }); connect(m_accounts.get(), SIGNAL(listChanged()), SLOT(listChanged())); connect(m_accounts.get(), SIGNAL(activeAccountChanged()), SLOT(listChanged())); @@ -68,7 +70,8 @@ void AccountListDialog::listChanged() void AccountListDialog::on_addAccountBtn_clicked() { - addAccount(tr("Please enter your Mojang or Minecraft account username and password to add your account.")); + addAccount(tr("Please enter your Mojang or Minecraft account username and password to add " + "your account.")); } void AccountListDialog::on_rmAccountBtn_clicked() @@ -87,7 +90,8 @@ void AccountListDialog::on_setDefaultBtn_clicked() if (selection.size() > 0) { QModelIndex selected = selection.first(); - MojangAccountPtr account = selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>(); + MojangAccountPtr account = + selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>(); m_accounts->setActiveAccount(account->username()); } } @@ -113,48 +117,29 @@ void AccountListDialog::updateButtonStates() ui->noDefaultBtn->setDown(m_accounts->activeAccount().get() == nullptr); } -void AccountListDialog::addAccount(const QString& errMsg) +void AccountListDialog::addAccount(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. - EditAccountDialog loginDialog(errMsg, this, EditAccountDialog::UsernameField | EditAccountDialog::PasswordField); - loginDialog.exec(); + // TODO: The login dialog isn't quite done yet + MojangAccountPtr account = LoginDialog::newAccount(this, errMsg); - if (loginDialog.result() == QDialog::Accepted) + if (account != nullptr) { - QString username(loginDialog.username()); - QString password(loginDialog.password()); - - MojangAccountPtr account = MojangAccount::createFromUsername(username); - ProgressDialog progDialog(this); - auto task = account->login(nullptr, password); - progDialog.exec(task.get()); - if(task->successful()) - { - m_accounts->addAccount(account); - if (m_accounts->count() == 1) - m_accounts->setActiveAccount(account->username()); - - // Grab associated player skins - auto job = new NetJob("Player skins: " + account->username()); - - for(AccountProfile profile : account->profiles()) - { - auto meta = MMC->metacache()->resolveEntry("skins", profile.name + ".png"); - auto action = CacheDownload::make( - QUrl("http://" + URLConstants::SKINS_BASE + profile.name + ".png"), - meta); - job->addNetAction(action); - meta->stale = true; - } - - job->start(); - } - else + m_accounts->addAccount(account); + if (m_accounts->count() == 1) + m_accounts->setActiveAccount(account->username()); + + // Grab associated player skins + auto job = new NetJob("Player skins: " + account->username()); + + for (AccountProfile profile : account->profiles()) { - auto reason = task->failReason(); - auto dlg = CustomMessageBox::selectable(this, tr("Login error."), reason, QMessageBox::Critical); - dlg->exec(); - delete dlg; + auto meta = MMC->metacache()->resolveEntry("skins", profile.name + ".png"); + auto action = CacheDownload::make( + QUrl("http://" + URLConstants::SKINS_BASE + profile.name + ".png"), meta); + job->addNetAction(action); + meta->stale = true; } + + job->start(); } } diff --git a/gui/dialogs/LoginDialog.cpp b/gui/dialogs/LoginDialog.cpp new file mode 100644 index 00000000..5ac94fac --- /dev/null +++ b/gui/dialogs/LoginDialog.cpp @@ -0,0 +1,110 @@ +/* Copyright 2014 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 "LoginDialog.h" +#include "ui_LoginDialog.h" + +#include "logic/auth/YggdrasilTask.h" + +#include <QtWidgets/QPushButton> + +LoginDialog::LoginDialog(QWidget *parent) : QDialog(parent), ui(new Ui::LoginDialog) +{ + ui->setupUi(this); + ui->progressBar->setVisible(false); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + + connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); +} + +LoginDialog::~LoginDialog() +{ + delete ui; +} + +// Stage 1: User interaction +void LoginDialog::accept() +{ + setUserInputsEnabled(false); + ui->progressBar->setVisible(true); + + // Setup the login task and start it + m_account = MojangAccount::createFromUsername(ui->userTextBox->text()); + m_loginTask = m_account->login(nullptr, ui->passTextBox->text()); + connect(m_loginTask.get(), &ProgressProvider::failed, this, &LoginDialog::onTaskFailed); + connect(m_loginTask.get(), &ProgressProvider::succeeded, this, + &LoginDialog::onTaskSucceeded); + connect(m_loginTask.get(), &ProgressProvider::status, this, &LoginDialog::onTaskStatus); + connect(m_loginTask.get(), &ProgressProvider::progress, this, &LoginDialog::onTaskProgress); + m_loginTask->start(); +} + +void LoginDialog::setUserInputsEnabled(bool enable) +{ + ui->userTextBox->setEnabled(enable); + ui->passTextBox->setEnabled(enable); + ui->buttonBox->setEnabled(enable); +} + +// Enable the OK button only when both textboxes contain something. +void LoginDialog::on_userTextBox_textEdited(const QString &newText) +{ + ui->buttonBox->button(QDialogButtonBox::Ok) + ->setEnabled(!newText.isEmpty() && !ui->passTextBox->text().isEmpty()); +} +void LoginDialog::on_passTextBox_textEdited(const QString &newText) +{ + ui->buttonBox->button(QDialogButtonBox::Ok) + ->setEnabled(!newText.isEmpty() && !ui->userTextBox->text().isEmpty()); +} + +void LoginDialog::onTaskFailed(const QString &reason) +{ + // Set message + ui->label->setText("<span style='color:red'>" + reason + "</span>"); + + // Re-enable user-interaction + setUserInputsEnabled(true); + ui->progressBar->setVisible(false); +} + +void LoginDialog::onTaskSucceeded() +{ + QDialog::accept(); +} + +void LoginDialog::onTaskStatus(const QString &status) +{ + ui->label->setText(status); +} + +void LoginDialog::onTaskProgress(qint64 current, qint64 total) +{ + ui->progressBar->setMaximum(total); + ui->progressBar->setValue(current); +} + +// Public interface +MojangAccountPtr LoginDialog::newAccount(QWidget *parent, QString msg) +{ + LoginDialog dlg(parent); + dlg.ui->label->setText(msg); + if (dlg.exec() == QDialog::Accepted) + { + return dlg.m_account; + } + return 0; +} diff --git a/gui/dialogs/LoginDialog.h b/gui/dialogs/LoginDialog.h new file mode 100644 index 00000000..560ed5ec --- /dev/null +++ b/gui/dialogs/LoginDialog.h @@ -0,0 +1,58 @@ +/* Copyright 2014 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 <QtWidgets/QDialog> +#include <QtCore/QEventLoop> + +#include "logic/auth/MojangAccount.h" + +namespace Ui +{ +class LoginDialog; +} + +class LoginDialog : public QDialog +{ + Q_OBJECT + +public: + ~LoginDialog(); + + static MojangAccountPtr newAccount(QWidget *parent, QString message); + +private: + explicit LoginDialog(QWidget *parent = 0); + + void setUserInputsEnabled(bool enable); + +protected +slots: + void accept(); + + void onTaskFailed(const QString &reason); + void onTaskSucceeded(); + void onTaskStatus(const QString &status); + void onTaskProgress(qint64 current, qint64 total); + + void on_userTextBox_textEdited(const QString &newText); + void on_passTextBox_textEdited(const QString &newText); + +private: + Ui::LoginDialog *ui; + MojangAccountPtr m_account; + std::shared_ptr<Task> m_loginTask; +}; diff --git a/gui/dialogs/LoginDialog.ui b/gui/dialogs/LoginDialog.ui new file mode 100644 index 00000000..b24b1c0c --- /dev/null +++ b/gui/dialogs/LoginDialog.ui @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>LoginDialog</class> + <widget class="QDialog" name="LoginDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>162</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string>Add Account</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Message label placeholder.</string> + </property> + <property name="textFormat"> + <enum>Qt::RichText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="userTextBox"> + <property name="placeholderText"> + <string>Email / Username</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="passTextBox"> + <property name="echoMode"> + <enum>QLineEdit::Password</enum> + </property> + <property name="placeholderText"> + <string>Password</string> + </property> + </widget> + </item> + <item> + <widget class="QProgressBar" name="progressBar"> + <property name="value"> + <number>24</number> + </property> + <property name="textVisible"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/gui/dialogs/VersionSelectDialog.cpp b/gui/dialogs/VersionSelectDialog.cpp index 3277fd2f..f4d314b6 100644 --- a/gui/dialogs/VersionSelectDialog.cpp +++ b/gui/dialogs/VersionSelectDialog.cpp @@ -100,7 +100,9 @@ void VersionSelectDialog::on_refreshButton_clicked() void VersionSelectDialog::setFilter(int column, QString filter) { m_proxyModel->setFilterKeyColumn(column); - m_proxyModel->setFilterFixedString(filter); + // m_proxyModel->setFilterFixedString(filter); + m_proxyModel->setFilterRegExp(QRegExp(QString("^%1$").arg(filter.replace(".", "\\.")), + Qt::CaseInsensitive, QRegExp::RegExp)); /* QStringList filteredTypes; if (!ui->filterSnapshotsCheckbox->isChecked()) |