diff options
Diffstat (limited to 'gui')
-rw-r--r-- | gui/MainWindow.cpp | 204 | ||||
-rw-r--r-- | gui/MainWindow.h | 15 | ||||
-rw-r--r-- | gui/MainWindow.ui | 60 | ||||
-rw-r--r-- | gui/dialogs/AccountListDialog.cpp | 2 | ||||
-rw-r--r-- | gui/dialogs/OneSixModEditDialog.cpp | 8 | ||||
-rw-r--r-- | gui/dialogs/VersionSelectDialog.cpp | 5 | ||||
-rw-r--r-- | gui/dialogs/VersionSelectDialog.h | 1 | ||||
-rw-r--r-- | gui/dialogs/VersionSelectDialog.ui | 9 | ||||
-rw-r--r-- | gui/widgets/Common.cpp | 27 | ||||
-rw-r--r-- | gui/widgets/Common.h | 6 | ||||
-rw-r--r-- | gui/widgets/InstanceDelegate.cpp | 25 | ||||
-rw-r--r-- | gui/widgets/VersionListView.cpp | 150 | ||||
-rw-r--r-- | gui/widgets/VersionListView.h | 43 |
13 files changed, 421 insertions, 134 deletions
diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index ee9c3fad..9977dc75 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -71,7 +71,6 @@ #include "logic/auth/flows/AuthenticateTask.h" #include "logic/auth/flows/RefreshTask.h" -#include "logic/auth/flows/ValidateTask.h" #include "logic/updater/DownloadUpdateTask.h" @@ -132,8 +131,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi newsLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); newsLabel->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); ui->newsToolBar->insertWidget(ui->actionMoreNews, newsLabel); - QObject::connect(newsLabel, &QAbstractButton::clicked, this, &MainWindow::newsButtonClicked); - QObject::connect(MMC->newsChecker().get(), &NewsChecker::newsLoaded, this, &MainWindow::updateNewsLabel); + QObject::connect(newsLabel, &QAbstractButton::clicked, this, + &MainWindow::newsButtonClicked); + QObject::connect(MMC->newsChecker().get(), &NewsChecker::newsLoaded, this, + &MainWindow::updateNewsLabel); updateNewsLabel(); } @@ -173,8 +174,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi view->setModel(proxymodel); view->setContextMenuPolicy(Qt::CustomContextMenu); - connect(view, SIGNAL(customContextMenuRequested(const QPoint&)), - this, SLOT(showInstanceContextMenu(const QPoint&))); + connect(view, SIGNAL(customContextMenuRequested(const QPoint &)), this, + SLOT(showInstanceContextMenu(const QPoint &))); ui->horizontalLayout->addWidget(view); } @@ -213,8 +214,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi // Start status checker { - connect(MMC->statusChecker().get(), &StatusChecker::statusLoaded, this, &MainWindow::updateStatusUI); - connect(MMC->statusChecker().get(), &StatusChecker::statusLoadingFailed, this, &MainWindow::updateStatusFailedUI); + connect(MMC->statusChecker().get(), &StatusChecker::statusLoaded, this, + &MainWindow::updateStatusUI); + connect(MMC->statusChecker().get(), &StatusChecker::statusLoadingFailed, this, + &MainWindow::updateStatusFailedUI); connect(m_statusRefresh, &QAbstractButton::clicked, this, &MainWindow::reloadStatus); connect(&statusTimer, &QTimer::timeout, this, &MainWindow::reloadStatus); @@ -313,8 +316,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi if (MMC->settings()->get("AutoUpdate").toBool()) on_actionCheckUpdate_triggered(); - connect(MMC->notificationChecker().get(), &NotificationChecker::notificationCheckFinished, - this, &MainWindow::notificationsChanged); + connect(MMC->notificationChecker().get(), + &NotificationChecker::notificationCheckFinished, this, + &MainWindow::notificationsChanged); } setSelectedInstanceById(MMC->settings()->get("SelectedInstance").toString()); @@ -330,9 +334,9 @@ MainWindow::~MainWindow() delete drawer; } -void MainWindow::showInstanceContextMenu(const QPoint& pos) +void MainWindow::showInstanceContextMenu(const QPoint &pos) { - if(!view->indexAt(pos).isValid()) + if (!view->indexAt(pos).isValid()) { return; } @@ -522,9 +526,12 @@ static QString convertStatus(const QString &status) { QString ret = "?"; - if(status == "green") ret = "↑"; - else if(status == "yellow") ret = "-"; - else if(status == "red") ret="↓"; + if (status == "green") + ret = "↑"; + else if (status == "yellow") + ret = "-"; + else if (status == "red") + ret = "↓"; return "<span style=\"font-size:11pt; font-weight:600;\">" + ret + "</span>"; } @@ -533,7 +540,7 @@ void MainWindow::reloadStatus() { m_statusRefresh->setChecked(true); MMC->statusChecker()->reloadStatus(); - //updateStatusUI(); + // updateStatusUI(); } static QString makeStatusString(const QMap<QString, QString> statuses) @@ -632,7 +639,8 @@ void MainWindow::notificationsChanged() } QMessageBox box(icon, tr("Notification"), entry.message, QMessageBox::Close, this); - QPushButton *dontShowAgainButton = box.addButton(tr("Don't show again"), QMessageBox::AcceptRole); + QPushButton *dontShowAgainButton = + box.addButton(tr("Don't show again"), QMessageBox::AcceptRole); box.setDefaultButton(QMessageBox::Close); box.exec(); if (box.clickedButton() == dontShowAgainButton) @@ -657,9 +665,9 @@ void MainWindow::downloadUpdates(QString repo, int versionId, bool installOnExit if (updateDlg.exec(&updateTask)) { UpdateFlags baseFlags = None; - #ifdef MultiMC_UPDATER_DRY_RUN - baseFlags |= DryRun; - #endif +#ifdef MultiMC_UPDATER_DRY_RUN + baseFlags |= DryRun; +#endif if (installOnExit) MMC->installUpdates(updateTask.updateFilesDir(), baseFlags | OnExit); else @@ -751,7 +759,7 @@ void MainWindow::on_actionAddInstance_triggered() if (MMC->accounts()->anyAccountIsValid()) { ProgressDialog loadDialog(this); - auto update = newInstance->doUpdate(false); + auto update = newInstance->doUpdate(); connect(update.get(), &Task::failed, [this](QString reason) { QString error = QString("Instance load failed: %1").arg(reason); @@ -837,7 +845,7 @@ void MainWindow::on_actionChangeInstIcon_triggered() void MainWindow::iconUpdated(QString icon) { - if(icon == m_currentInstIcon) + if (icon == m_currentInstIcon) { ui->actionChangeInstIcon->setIcon(MMC->icons()->getBigIcon(m_currentInstIcon)); } @@ -860,7 +868,8 @@ void MainWindow::setSelectedInstanceById(const QString &id) selectionIndex = proxymodel->mapFromSource(index); } } - view->selectionModel()->setCurrentIndex(selectionIndex, QItemSelectionModel::ClearAndSelect); + view->selectionModel()->setCurrentIndex(selectionIndex, + QItemSelectionModel::ClearAndSelect); } void MainWindow::on_actionChangeInstGroup_triggered() @@ -1060,7 +1069,16 @@ void MainWindow::on_actionLaunchInstance_triggered() } } -void MainWindow::doLaunch() +void MainWindow::on_actionLaunchInstanceOffline_triggered() +{ + if (m_selectedInstance) + { + NagUtils::checkJVMArgs(m_selectedInstance->settings().get("JvmArgs").toString(), this); + doLaunch(false); + } +} + +void MainWindow::doLaunch(bool online) { if (!m_selectedInstance) return; @@ -1104,89 +1122,111 @@ void MainWindow::doLaunch() if (!account.get()) return; + // we try empty password first :) + QString password; + // we loop until the user succeeds in logging in or gives up + bool tryagain = true; + // the failure. the default failure. QString failReason = tr("Your account is currently not logged in. Please enter " "your password to log in again."); - // do the login. if the account has an access token, try to refresh it first. - if (account->accountStatus() != NotVerified) + + while (tryagain) { - // We'll need to validate the access token to make sure the account is still logged in. - ProgressDialog progDialog(this); - progDialog.setSkipButton(true, tr("Play Offline")); - auto task = account->login(); - progDialog.exec(task.get()); - - auto status = account->accountStatus(); - if (status != NotVerified) - { - updateInstance(m_selectedInstance, account); - } - else + AuthSessionPtr session(new AuthSession()); + session->wants_online = online; + auto task = account->login(session, password); + if (task) { + // We'll need to validate the access token to make sure the account + // is still logged in. + ProgressDialog progDialog(this); + if (online) + progDialog.setSkipButton(true, tr("Play Offline")); + progDialog.exec(task.get()); if (!task->successful()) { failReason = task->failReason(); } - if (loginWithPassword(account, failReason)) - updateInstance(m_selectedInstance, account); } - // in any case, revert from online to verified. - account->downgrade(); - } - else - { - if (loginWithPassword(account, failReason)) + switch (session->status) { - updateInstance(m_selectedInstance, account); - account->downgrade(); + case AuthSession::Undetermined: + { + QLOG_ERROR() << "Received undetermined session status during login. Bye."; + tryagain = false; + break; } - // in any case, revert from online to verified. - account->downgrade(); - } -} - -bool MainWindow::loginWithPassword(MojangAccountPtr account, const QString &errorMsg) -{ - EditAccountDialog passDialog(errorMsg, this, EditAccountDialog::PasswordField); - if (passDialog.exec() == QDialog::Accepted) - { - // To refresh the token, we just create an authenticate task with the given account and - // the user's password. - ProgressDialog progDialog(this); - auto task = account->login(passDialog.password()); - progDialog.exec(task.get()); - if (task->successful()) - return true; - else + case AuthSession::RequiresPassword: { - // If the authentication task failed, recurse with the task's error message. - return loginWithPassword(account, task->failReason()); + EditAccountDialog passDialog(failReason, this, EditAccountDialog::PasswordField); + if (passDialog.exec() == QDialog::Accepted) + { + password = passDialog.password(); + } + else + { + tryagain = false; + } + break; + } + case AuthSession::PlayableOffline: + { + // we ask the user for a player name + bool ok = false; + QString usedname = session->player_name; + QString name = QInputDialog::getText(this, tr("Player name"), + tr("Choose your offline mode player name."), + QLineEdit::Normal, session->player_name, &ok); + if (!ok) + { + tryagain = false; + break; + } + if (name.length()) + { + usedname = name; + } + session->MakeOffline(usedname); + // offline flavored game from here :3 + } + case AuthSession::PlayableOnline: + { + // update first if the server actually responded + if (session->auth_server_online) + { + updateInstance(m_selectedInstance, session); + } + else + { + launchInstance(m_selectedInstance, session); + } + tryagain = false; + } } } - return false; } -void MainWindow::updateInstance(BaseInstance *instance, MojangAccountPtr account) +void MainWindow::updateInstance(BaseInstance *instance, AuthSessionPtr session) { - bool only_prepare = account->accountStatus() != Online; - auto updateTask = instance->doUpdate(only_prepare); + auto updateTask = instance->doUpdate(); if (!updateTask) { - launchInstance(instance, account); + launchInstance(instance, session); return; } ProgressDialog tDialog(this); - connect(updateTask.get(), &Task::succeeded, [this, instance, account] - { launchInstance(instance, account); }); + connect(updateTask.get(), &Task::succeeded, [this, instance, session] + { launchInstance(instance, session); }); connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString))); tDialog.exec(updateTask.get()); } -void MainWindow::launchInstance(BaseInstance *instance, MojangAccountPtr account) +void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session) { Q_ASSERT_X(instance != NULL, "launchInstance", "instance is NULL"); - Q_ASSERT_X(account.get() != nullptr, "launchInstance", "account is NULL"); + Q_ASSERT_X(session.get() != nullptr, "launchInstance", "session is NULL"); - proc = instance->prepareForLaunch(account); + proc = instance->prepareForLaunch(session); if (!proc) return; @@ -1195,7 +1235,7 @@ void MainWindow::launchInstance(BaseInstance *instance, MojangAccountPtr account console = new ConsoleWindow(proc); connect(console, SIGNAL(isClosing()), this, SLOT(instanceEnded())); - proc->setLogin(account); + proc->setLogin(session); proc->launch(); } @@ -1258,7 +1298,7 @@ void MainWindow::on_actionChangeInstMCVersion_triggered() VersionSelectDialog vselect(m_selectedInstance->versionList().get(), tr("Change Minecraft version"), this); vselect.setFilter(1, "OneSix"); - if(!vselect.exec() || !vselect.selectedVersion()) + if (!vselect.exec() || !vselect.selectedVersion()) return; if (!MMC->accounts()->anyAccountIsValid()) @@ -1276,7 +1316,7 @@ void MainWindow::on_actionChangeInstMCVersion_triggered() auto result = CustomMessageBox::selectable( this, tr("Are you sure?"), tr("This will remove any library/version customization you did previously. " - "This includes things like Forge install and similar."), + "This includes things like Forge install and similar."), QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Abort, QMessageBox::Abort)->exec(); @@ -1285,7 +1325,7 @@ void MainWindow::on_actionChangeInstMCVersion_triggered() } m_selectedInstance->setIntendedVersionId(vselect.selectedVersion()->descriptor()); - auto updateTask = m_selectedInstance->doUpdate(false); + auto updateTask = m_selectedInstance->doUpdate(); if (!updateTask) { return; @@ -1384,7 +1424,7 @@ void MainWindow::instanceEnded() void MainWindow::checkMigrateLegacyAssets() { int legacyAssets = AssetsUtils::findLegacyAssets(); - if(legacyAssets > 0) + if (legacyAssets > 0) { ProgressDialog migrateDlg(this); AssetsMigrateTask migrateTask(legacyAssets, &migrateDlg); diff --git a/gui/MainWindow.h b/gui/MainWindow.h index eb478776..eeba2c26 100644 --- a/gui/MainWindow.h +++ b/gui/MainWindow.h @@ -96,6 +96,8 @@ slots: void on_actionLaunchInstance_triggered(); + void on_actionLaunchInstanceOffline_triggered(); + void on_actionDeleteInstance_triggered(); void on_actionRenameInstance_triggered(); @@ -112,25 +114,18 @@ slots: * Launches the currently selected instance with the default account. * If no default account is selected, prompts the user to pick an account. */ - void doLaunch(); - - /*! - * Opens an input dialog, allowing the user to input their password and refresh its access token. - * This function will execute the proper Yggdrasil task to refresh the access token. - * Returns true if successful. False if the user cancelled. - */ - bool loginWithPassword(MojangAccountPtr account, const QString& errorMsg=""); + void doLaunch(bool online = true); /*! * Launches the given instance with the given account. * This function assumes that the given account has a valid, usable access token. */ - void launchInstance(BaseInstance* instance, MojangAccountPtr account); + void launchInstance(BaseInstance *instance, AuthSessionPtr session); /*! * Prepares the given instance for launch with the given account. */ - void updateInstance(BaseInstance* instance, MojangAccountPtr account); + void updateInstance(BaseInstance *instance, AuthSessionPtr account); void onGameUpdateError(QString error); diff --git a/gui/MainWindow.ui b/gui/MainWindow.ui index 25af6f60..8cf26d18 100644 --- a/gui/MainWindow.ui +++ b/gui/MainWindow.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>688</width> - <height>460</height> + <width>694</width> + <height>563</height> </rect> </property> <property name="windowTitle"> @@ -107,6 +107,7 @@ </attribute> <addaction name="actionChangeInstIcon"/> <addaction name="actionLaunchInstance"/> + <addaction name="actionLaunchInstanceOffline"/> <addaction name="separator"/> <addaction name="actionEditInstNotes"/> <addaction name="actionChangeInstGroup"/> @@ -152,7 +153,9 @@ </widget> <action name="actionAddInstance"> <property name="icon"> - <iconset theme="new"/> + <iconset theme="new"> + <normaloff/> + </iconset> </property> <property name="text"> <string>Add Instance</string> @@ -166,7 +169,9 @@ </action> <action name="actionViewInstanceFolder"> <property name="icon"> - <iconset theme="viewfolder"/> + <iconset theme="viewfolder"> + <normaloff/> + </iconset> </property> <property name="text"> <string>View Instance Folder</string> @@ -180,7 +185,9 @@ </action> <action name="actionRefresh"> <property name="icon"> - <iconset theme="refresh"/> + <iconset theme="refresh"> + <normaloff/> + </iconset> </property> <property name="text"> <string>Refresh</string> @@ -194,7 +201,9 @@ </action> <action name="actionViewCentralModsFolder"> <property name="icon"> - <iconset theme="centralmods"/> + <iconset theme="centralmods"> + <normaloff/> + </iconset> </property> <property name="text"> <string>View Central Mods Folder</string> @@ -208,7 +217,9 @@ </action> <action name="actionCheckUpdate"> <property name="icon"> - <iconset theme="checkupdate"/> + <iconset theme="checkupdate"> + <normaloff/> + </iconset> </property> <property name="text"> <string>Check for Updates</string> @@ -222,7 +233,9 @@ </action> <action name="actionSettings"> <property name="icon"> - <iconset theme="settings"/> + <iconset theme="settings"> + <normaloff/> + </iconset> </property> <property name="text"> <string>Settings</string> @@ -239,7 +252,9 @@ </action> <action name="actionReportBug"> <property name="icon"> - <iconset theme="bug"/> + <iconset theme="bug"> + <normaloff/> + </iconset> </property> <property name="text"> <string>Report a Bug</string> @@ -253,7 +268,9 @@ </action> <action name="actionMoreNews"> <property name="icon"> - <iconset theme="news"/> + <iconset theme="news"> + <normaloff/> + </iconset> </property> <property name="text"> <string>More News</string> @@ -270,7 +287,9 @@ </action> <action name="actionAbout"> <property name="icon"> - <iconset theme="about"/> + <iconset theme="about"> + <normaloff/> + </iconset> </property> <property name="text"> <string>About MultiMC</string> @@ -463,7 +482,9 @@ <bool>true</bool> </property> <property name="icon"> - <iconset theme="cat"/> + <iconset theme="cat"> + <normaloff/> + </iconset> </property> <property name="text"> <string>Meow</string> @@ -474,7 +495,9 @@ </action> <action name="actionCopyInstance"> <property name="icon"> - <iconset theme="copy"/> + <iconset theme="copy"> + <normaloff/> + </iconset> </property> <property name="text"> <string>Copy Instance</string> @@ -494,6 +517,17 @@ <string>Manage your Mojang or Minecraft accounts.</string> </property> </action> + <action name="actionLaunchInstanceOffline"> + <property name="text"> + <string>Play Offline</string> + </property> + <property name="toolTip"> + <string>Launch the selected instance in offline mode.</string> + </property> + <property name="statusTip"> + <string>Launch the selected instance.</string> + </property> + </action> </widget> <layoutdefault spacing="6" margin="11"/> <resources> diff --git a/gui/dialogs/AccountListDialog.cpp b/gui/dialogs/AccountListDialog.cpp index 1712e352..a38035a6 100644 --- a/gui/dialogs/AccountListDialog.cpp +++ b/gui/dialogs/AccountListDialog.cpp @@ -126,7 +126,7 @@ void AccountListDialog::addAccount(const QString& errMsg) MojangAccountPtr account = MojangAccount::createFromUsername(username); ProgressDialog progDialog(this); - auto task = account->login(password); + auto task = account->login(nullptr, password); progDialog.exec(task.get()); if(task->successful()) { diff --git a/gui/dialogs/OneSixModEditDialog.cpp b/gui/dialogs/OneSixModEditDialog.cpp index ebd685e8..1742ff80 100644 --- a/gui/dialogs/OneSixModEditDialog.cpp +++ b/gui/dialogs/OneSixModEditDialog.cpp @@ -161,6 +161,8 @@ void OneSixModEditDialog::on_forgeBtn_clicked() } VersionSelectDialog vselect(MMC->forgelist().get(), tr("Select Forge version"), this); vselect.setFilter(1, m_inst->currentVersionId()); + vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") + + m_inst->currentVersionId()); if (vselect.exec() && vselect.selectedVersion()) { ForgeVersionPtr forgeVersion = @@ -224,9 +226,9 @@ void OneSixModEditDialog::on_liteloaderBtn_clicked() } if (!liteloader.add(m_inst)) { - QMessageBox::critical( - this, tr("LiteLoader"), - tr("For reasons unknown, the LiteLoader installation failed. Check your MultiMC log files for details.")); + QMessageBox::critical(this, tr("LiteLoader"), + tr("For reasons unknown, the LiteLoader installation failed. " + "Check your MultiMC log files for details.")); } else { diff --git a/gui/dialogs/VersionSelectDialog.cpp b/gui/dialogs/VersionSelectDialog.cpp index d6efe3c0..0f379f56 100644 --- a/gui/dialogs/VersionSelectDialog.cpp +++ b/gui/dialogs/VersionSelectDialog.cpp @@ -51,6 +51,11 @@ VersionSelectDialog::VersionSelectDialog(BaseVersionList *vlist, QString title, } } +void VersionSelectDialog::setEmptyString(QString emptyString) +{ + ui->listView->setEmptyString(emptyString); +} + VersionSelectDialog::~VersionSelectDialog() { delete ui; diff --git a/gui/dialogs/VersionSelectDialog.h b/gui/dialogs/VersionSelectDialog.h index e36341db..61fa8ab6 100644 --- a/gui/dialogs/VersionSelectDialog.h +++ b/gui/dialogs/VersionSelectDialog.h @@ -44,6 +44,7 @@ public: BaseVersionPtr selectedVersion() const; void setFilter(int column, QString filter); + void setEmptyString(QString emptyString); void setResizeOn(int column); private diff --git a/gui/dialogs/VersionSelectDialog.ui b/gui/dialogs/VersionSelectDialog.ui index 58264f24..07e9e73e 100644 --- a/gui/dialogs/VersionSelectDialog.ui +++ b/gui/dialogs/VersionSelectDialog.ui @@ -15,7 +15,7 @@ </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QTreeView" name="listView"> + <widget class="VersionListView" name="listView"> <property name="horizontalScrollBarPolicy"> <enum>Qt::ScrollBarAlwaysOff</enum> </property> @@ -65,6 +65,13 @@ </item> </layout> </widget> + <customwidgets> + <customwidget> + <class>VersionListView</class> + <extends>QTreeView</extends> + <header>gui/widgets/VersionListView.h</header> + </customwidget> + </customwidgets> <resources/> <connections> <connection> diff --git a/gui/widgets/Common.cpp b/gui/widgets/Common.cpp new file mode 100644 index 00000000..9b730d6c --- /dev/null +++ b/gui/widgets/Common.cpp @@ -0,0 +1,27 @@ +#include "Common.h" + +// Origin: Qt +QStringList viewItemTextLayout(QTextLayout &textLayout, int lineWidth, qreal &height, + qreal &widthUsed) +{ + QStringList lines; + height = 0; + widthUsed = 0; + textLayout.beginLayout(); + QString str = textLayout.text(); + while (true) + { + QTextLine line = textLayout.createLine(); + if (!line.isValid()) + break; + if (line.textLength() == 0) + break; + line.setLineWidth(lineWidth); + line.setPosition(QPointF(0, height)); + height += line.height(); + lines.append(str.mid(line.textStart(), line.textLength())); + widthUsed = qMax(widthUsed, line.naturalTextWidth()); + } + textLayout.endLayout(); + return lines; +} diff --git a/gui/widgets/Common.h b/gui/widgets/Common.h new file mode 100644 index 00000000..fc46e08f --- /dev/null +++ b/gui/widgets/Common.h @@ -0,0 +1,6 @@ +#pragma once +#include <QStringList> +#include <QTextLayout> + +QStringList viewItemTextLayout(QTextLayout &textLayout, int lineWidth, qreal &height, + qreal &widthUsed);
\ No newline at end of file diff --git a/gui/widgets/InstanceDelegate.cpp b/gui/widgets/InstanceDelegate.cpp index 5020b8b6..33da7130 100644 --- a/gui/widgets/InstanceDelegate.cpp +++ b/gui/widgets/InstanceDelegate.cpp @@ -19,30 +19,7 @@ #include <QTextLayout> #include <QApplication> #include <QtCore/qmath.h> - -// Origin: Qt -static void viewItemTextLayout(QTextLayout &textLayout, int lineWidth, qreal &height, - qreal &widthUsed) -{ - height = 0; - widthUsed = 0; - textLayout.beginLayout(); - QString str = textLayout.text(); - while (true) - { - QTextLine line = textLayout.createLine(); - if (!line.isValid()) - break; - if (line.textLength() == 0) - break; - line.setLineWidth(lineWidth); - line.setPosition(QPointF(0, height)); - height += line.height(); - widthUsed = qMax(widthUsed, line.naturalTextWidth()); - } - textLayout.endLayout(); -} - +#include "Common.h" #define QFIXED_MAX (INT_MAX / 256) ListViewDelegate::ListViewDelegate(QObject *parent) : QStyledItemDelegate(parent) diff --git a/gui/widgets/VersionListView.cpp b/gui/widgets/VersionListView.cpp new file mode 100644 index 00000000..b7f45f27 --- /dev/null +++ b/gui/widgets/VersionListView.cpp @@ -0,0 +1,150 @@ +/* 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 <QHeaderView> +#include <QApplication> +#include <QMouseEvent> +#include <QDrag> +#include <QPainter> +#include "VersionListView.h" +#include "Common.h" + +VersionListView::VersionListView(QWidget *parent) + :QTreeView ( parent ) +{ + m_emptyString = tr("No versions are currently available."); +} + +void VersionListView::rowsInserted(const QModelIndex &parent, int start, int end) +{ + if(!m_itemCount) + viewport()->update(); + m_itemCount += end-start+1; + QTreeView::rowsInserted(parent, start, end); +} + + +void VersionListView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +{ + m_itemCount -= end-start+1; + if(!m_itemCount) + viewport()->update(); + QTreeView::rowsInserted(parent, start, end); +} + +void VersionListView::setModel(QAbstractItemModel *model) +{ + m_itemCount = model->rowCount(); + if(!m_itemCount) + viewport()->update(); + QTreeView::setModel(model); +} + +void VersionListView::reset() +{ + if(model()) + { + m_itemCount = model()->rowCount(); + } + viewport()->update(); + QTreeView::reset(); +} + +void VersionListView::setEmptyString(QString emptyString) +{ + m_emptyString = emptyString; + if(!m_itemCount) + { + viewport()->update(); + } +} + +void VersionListView::paintEvent(QPaintEvent *event) +{ + if(m_itemCount) + { + QTreeView::paintEvent(event); + } + else + { + paintInfoLabel(event); + } +} + +void VersionListView::paintInfoLabel(QPaintEvent *event) +{ + int scrollInterval = 500; + + //calculate the rect for the overlay + QPainter painter(viewport()); + painter.setRenderHint(QPainter::Antialiasing, true); + const QChar letter = 'Q'; + QFont font("sans", 20); + font.setBold(true); + + QRect bounds = viewport()->geometry(); + bounds.moveTop(0); + QTextLayout layout(m_emptyString, font); + qreal height = 0.0; + qreal widthUsed = 0.0; + QStringList lines = viewItemTextLayout(layout, bounds.width() - 20, height, widthUsed); + QRect rect (0,0, widthUsed, height); + rect.setWidth(rect.width()+20); + rect.setHeight(rect.height()+20); + rect.moveCenter(bounds.center()); + //check if we are allowed to draw in our area + if (!event->rect().intersects(rect)) { + return; + } + //draw the letter of the topmost item semitransparent in the middle + QColor background = QApplication::palette().color(QPalette::Foreground); + QColor foreground = QApplication::palette().color(QPalette::Base); + /* + background.setAlpha(128 - scrollFade); + foreground.setAlpha(128 - scrollFade); + */ + painter.setBrush(QBrush(background)); + painter.setPen(foreground); + painter.drawRoundedRect(rect, 5.0, 5.0); + foreground.setAlpha(190); + painter.setPen(foreground); + painter.setFont(font); + painter.drawText(rect, Qt::AlignCenter, lines.join("\n")); + +} + +/* +void ModListView::setModel ( QAbstractItemModel* model ) +{ + QTreeView::setModel ( model ); + auto head = header(); + head->setStretchLastSection(false); + // HACK: this is true for the checkbox column of mod lists + auto string = model->headerData(0,head->orientation()).toString(); + if(!string.size()) + { + head->setSectionResizeMode(0, QHeaderView::ResizeToContents); + head->setSectionResizeMode(1, QHeaderView::Stretch); + for(int i = 2; i < head->count(); i++) + head->setSectionResizeMode(i, QHeaderView::ResizeToContents); + } + else + { + head->setSectionResizeMode(0, QHeaderView::Stretch); + for(int i = 1; i < head->count(); i++) + head->setSectionResizeMode(i, QHeaderView::ResizeToContents); + } +} +*/
\ No newline at end of file diff --git a/gui/widgets/VersionListView.h b/gui/widgets/VersionListView.h new file mode 100644 index 00000000..af9b1f6a --- /dev/null +++ b/gui/widgets/VersionListView.h @@ -0,0 +1,43 @@ +/* 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 <QTreeView> + +class Mod; + +class VersionListView : public QTreeView +{ + Q_OBJECT +public: + explicit VersionListView(QWidget *parent = 0); + virtual void paintEvent(QPaintEvent *event) override; + void setEmptyString(QString emptyString); + virtual void setModel ( QAbstractItemModel* model ); + +public slots: + virtual void reset() override; + +protected slots: + virtual void rowsAboutToBeRemoved(const QModelIndex & parent, int start, int end) override; + virtual void rowsInserted(const QModelIndex &parent, int start, int end) override; + +private: /* methods */ + void paintInfoLabel(QPaintEvent *event); + +private: /* variables */ + int m_itemCount = 0; + QString m_emptyString; +}; |