Finish status pills.

This commit is contained in:
Petr Mrázek 2014-05-17 16:23:48 +02:00
parent 927217c7f0
commit 8a8c4193e6
10 changed files with 242 additions and 114 deletions

View File

@ -308,16 +308,23 @@ SET(MULTIMC_SOURCES
gui/dialogs/NotificationDialog.cpp
# GUI - widgets
gui/widgets/Common.h
gui/widgets/Common.cpp
gui/widgets/ModListView.h
gui/widgets/ModListView.cpp
gui/widgets/VersionListView.h
gui/widgets/VersionListView.cpp
gui/widgets/LabeledToolButton.h
gui/widgets/Common.h
gui/widgets/IconLabel.cpp
gui/widgets/IconLabel.h
gui/widgets/LabeledToolButton.cpp
gui/widgets/MCModInfoFrame.h
gui/widgets/LabeledToolButton.h
gui/widgets/LineSeparator.cpp
gui/widgets/LineSeparator.h
gui/widgets/MCModInfoFrame.cpp
gui/widgets/MCModInfoFrame.h
gui/widgets/ModListView.cpp
gui/widgets/ModListView.h
gui/widgets/ServerStatus.cpp
gui/widgets/ServerStatus.h
gui/widgets/VersionListView.cpp
gui/widgets/VersionListView.h
# GUI - instance group view
gui/groupview/Group.cpp

View File

@ -200,7 +200,7 @@ private:
Task *m_versionLoadTask;
QLabel *m_statusLeft;
QLabel *m_statusRight;
class ServerStatus *m_statusRight;
QMenu *accountMenu;
QToolButton *accountMenuButton;

30
gui/widgets/IconLabel.cpp Normal file
View File

@ -0,0 +1,30 @@
#include "IconLabel.h"
#include <QStyle>
#include <QStyleOption>
#include <QLayout>
#include <QPainter>
#include <QRect>
IconLabel::IconLabel(QWidget *parent, QIcon icon, QSize size)
: QWidget(parent), m_icon(icon), m_size(size)
{
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
}
QSize IconLabel::sizeHint() const
{
return m_size;
}
void IconLabel::setIcon(QIcon icon)
{
m_icon = icon;
update();
}
void IconLabel::paintEvent(QPaintEvent *)
{
QPainter p(this);
m_icon.paint(&p, contentsRect());
}

26
gui/widgets/IconLabel.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include <QWidget>
#include <QIcon>
class QStyleOption;
/**
* This is a trivial widget that paints a QIcon of the specified size.
*/
class IconLabel : public QWidget
{
Q_OBJECT
public:
/// Create a line separator. orientation is the orientation of the line.
explicit IconLabel(QWidget *parent, QIcon icon, QSize size);
virtual QSize sizeHint() const;
virtual void paintEvent(QPaintEvent *);
void setIcon(QIcon icon);
private:
QSize m_size;
QIcon m_icon;
};

View File

@ -0,0 +1,37 @@
#include "LineSeparator.h"
#include <QStyle>
#include <QStyleOption>
#include <QLayout>
#include <QPainter>
void LineSeparator::initStyleOption(QStyleOption *option) const
{
option->initFrom(this);
// in a horizontal layout, the line is vertical (and vice versa)
if (m_orientation == Qt::Vertical)
option->state |= QStyle::State_Horizontal;
}
LineSeparator::LineSeparator(QWidget *parent, Qt::Orientation orientation)
: QWidget(parent), m_orientation(orientation)
{
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
}
QSize LineSeparator::sizeHint() const
{
QStyleOption opt;
initStyleOption(&opt);
const int extent =
style()->pixelMetric(QStyle::PM_ToolBarSeparatorExtent, &opt, parentWidget());
return QSize(extent, extent);
}
void LineSeparator::paintEvent(QPaintEvent *)
{
QPainter p(this);
QStyleOption opt;
initStyleOption(&opt);
style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &opt, &p, parentWidget());
}

View File

@ -0,0 +1,18 @@
#pragma once
#include <QWidget>
class QStyleOption;
class LineSeparator : public QWidget
{
Q_OBJECT
public:
/// Create a line separator. orientation is the orientation of the line.
explicit LineSeparator(QWidget *parent, Qt::Orientation orientation = Qt::Vertical);
QSize sizeHint() const;
void paintEvent(QPaintEvent *);
void initStyleOption(QStyleOption *option) const;
private:
Qt::Orientation m_orientation = Qt::Vertical;
};

View File

@ -1,4 +1,6 @@
#include "ServerStatus.h"
#include "LineSeparator.h"
#include "IconLabel.h"
#include "logic/status/StatusChecker.h"
#include "MultiMC.h"
@ -8,118 +10,106 @@
#include <QLabel>
#include <QMap>
#include <QToolButton>
#include <QAction>
ServerStatus::ServerStatus(QWidget *parent, Qt::WindowFlags f)
:QWidget(parent, f)
ServerStatus::ServerStatus(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f)
{
clear();
goodIcon = QPixmap(":/icons/multimc/48x48/status-good.png");
goodIcon.setDevicePixelRatio(2.0);
badIcon = QPixmap(":/icons/multimc/48x48/status-bad.png");
badIcon.setDevicePixelRatio(2.0);
addStatus(tr("No status available"), false);
layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
goodIcon = QIcon::fromTheme("status-good");
badIcon = QIcon::fromTheme("status-bad");
addStatus("minecraft.net", tr("Web"));
addLine();
addStatus("account.mojang.com", tr("Account"));
addLine();
addStatus("skins.minecraft.net", tr("Skins"));
addLine();
addStatus("authserver.mojang.com", tr("Auth"));
addLine();
addStatus("sessionserver.mojang.com", tr("Session"));
m_statusRefresh = new QToolButton(this);
m_statusRefresh->setCheckable(true);
m_statusRefresh->setToolButtonStyle(Qt::ToolButtonIconOnly);
m_statusRefresh->setIcon(QIcon::fromTheme("refresh"));
layout->addWidget(m_statusRefresh);
setLayout(layout);
// Start status checker
{
connect(MMC->statusChecker().get(), &StatusChecker::statusLoaded, this,
&ServerStatus::updateStatusUI);
connect(MMC->statusChecker().get(), &StatusChecker::statusLoadingFailed, this,
&ServerStatus::updateStatusFailedUI);
auto reloader = MMC->statusChecker().get();
connect(reloader, &StatusChecker::statusChanged, this, &ServerStatus::StatusChanged);
connect(reloader, &StatusChecker::statusLoading, this, &ServerStatus::StatusReloading);
connect(m_statusRefresh, &QAbstractButton::clicked, this, &ServerStatus::reloadStatus);
connect(&statusTimer, &QTimer::timeout, this, &ServerStatus::reloadStatus);
statusTimer.setSingleShot(true);
MMC->statusChecker()->startTimer(60000);
reloadStatus();
}
}
ServerStatus::addLine()
ServerStatus::~ServerStatus()
{
auto line = new QFrame(this);
line->setFrameShape(QFrame::VLine);
line->setFrameShadow(QFrame::Sunken);
layout->addWidget(line);
}
ServerStatus::addStatus(QString name, bool online)
{
auto label = new QLabel(this);
label->setText(name);
if(online)
label->setPixmap(goodIcon);
else
label->setPixmap(badIcon);
layout->addWidget(label);
}
ServerStatus::clear()
{
if(layout)
delete layout;
layout = new QHBoxLayout(this);
}
void ServerStatus::StatusChanged(QMap<QString, QString> statusEntries)
{
clear();
int howmany = statusEntries.size();
int index = 0;
auto iter = statusEntries.begin();
while (iter != statusEntries.end())
{
addStatus();
index++;
}
}
static QString convertStatus(const QString &status)
{
QString 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>";
}
void ServerStatus::reloadStatus()
{
m_statusRefresh->setChecked(true);
MMC->statusChecker()->reloadStatus();
// updateStatusUI();
}
static QString makeStatusString(const QMap<QString, QString> statuses)
void ServerStatus::addLine()
{
QString status = "";
status += "Web: " + convertStatus(statuses["minecraft.net"]);
status += " Account: " + convertStatus(statuses["account.mojang.com"]);
status += " Skins: " + convertStatus(statuses["skins.minecraft.net"]);
status += " Auth: " + convertStatus(statuses["authserver.mojang.com"]);
status += " Session: " + convertStatus(statuses["sessionserver.mojang.com"]);
return status;
layout->addWidget(new LineSeparator(this));
}
void ServerStatus::updateStatusUI()
void ServerStatus::addStatus(QString key, QString name)
{
m_statusRefresh->setChecked(false);
MMC->statusChecker()->getStatusEntries();
statusTimer.start(60 * 1000);
{
auto label = new IconLabel(this, badIcon, QSize(16, 16));
label->setToolTip(key);
serverLabels[key] = label;
layout->addWidget(label);
}
{
auto label = new QLabel(this);
label->setText(name);
label->setToolTip(key);
layout->addWidget(label);
}
}
void ServerStatus::updateStatusFailedUI()
void ServerStatus::setStatus(QString key, bool value)
{
m_statusRefresh->setChecked(false);
StatusChanged();
statusTimer.start(60 * 1000);
if (!serverLabels.contains(key))
return;
IconLabel *label = serverLabels[key];
label->setIcon(value ? goodIcon : badIcon);
}
void ServerStatus::StatusChanged(const QMap<QString, QString> statusEntries)
{
auto convertStatus = [&](QString status)->bool
{
if (status == "green")
return true;
else if (status == "yellow")
return false;
else if (status == "red")
return false;
return false;
}
;
auto iter = statusEntries.begin();
while (iter != statusEntries.end())
{
QString key = iter.key();
bool value = convertStatus(iter.value());
setStatus(key, value);
iter++;
}
}
void ServerStatus::StatusReloading(bool is_reloading)
{
m_statusRefresh->setChecked(is_reloading);
}

View File

@ -1,7 +1,11 @@
#pragma once
#include <QString>
#include <QWidget>
#include <QMap>
#include <QIcon>
#include <memory>
class IconLabel;
class QToolButton;
class QHBoxLayout;
@ -10,23 +14,21 @@ class ServerStatus: public QWidget
Q_OBJECT
public:
explicit ServerStatus(QWidget *parent = nullptr, Qt::WindowFlags f = 0);
virtual ~ServerStatus() {};
virtual ~ServerStatus();
;
public slots:
void updateStatusUI();
void updateStatusFailedUI();
void reloadStatus();
void StatusChanged();
void StatusChanged(const QMap<QString, QString> statuses);
void StatusReloading(bool is_reloading);
private: /* methods */
clear();
addLine();
addStatus(QString name, bool online);
void addLine();
void addStatus(QString key, QString name);
void setStatus(QString key, bool value);
private: /* data */
QHBoxLayout * layout = nullptr;
QToolButton *m_statusRefresh = nullptr;
QPixmap goodIcon;
QPixmap badIcon;
QTimer statusTimer;
QMap<QString, IconLabel *> serverLabels;
QIcon goodIcon;
QIcon badIcon;
};

View File

@ -27,6 +27,12 @@ StatusChecker::StatusChecker()
}
void StatusChecker::timerEvent(QTimerEvent *e)
{
QObject::timerEvent(e);
reloadStatus();
}
void StatusChecker::reloadStatus()
{
if (isLoadingStatus())
@ -42,13 +48,14 @@ void StatusChecker::reloadStatus()
QObject::connect(job, &NetJob::succeeded, this, &StatusChecker::statusDownloadFinished);
QObject::connect(job, &NetJob::failed, this, &StatusChecker::statusDownloadFailed);
m_statusNetJob.reset(job);
emit statusLoading(true);
job->start();
}
void StatusChecker::statusDownloadFinished()
{
QLOG_DEBUG() << "Finished loading status JSON.";
m_statusEntries.clear();
QByteArray data;
{
ByteArrayDownloadPtr dl = std::dynamic_pointer_cast<ByteArrayDownload>(m_statusNetJob->first());
@ -121,17 +128,27 @@ QString StatusChecker::getLastLoadErrorMsg() const
void StatusChecker::succeed()
{
if(m_prevEntries != m_statusEntries)
{
emit statusChanged(m_statusEntries);
m_prevEntries = m_statusEntries;
}
m_lastLoadError = "";
QLOG_DEBUG() << "Status loading succeeded.";
m_statusNetJob.reset();
emit statusLoaded();
emit statusLoading(false);
}
void StatusChecker::fail(const QString& errorMsg)
{
if(m_prevEntries != m_statusEntries)
{
emit statusChanged(m_statusEntries);
m_prevEntries = m_statusEntries;
}
m_lastLoadError = errorMsg;
QLOG_DEBUG() << "Failed to load status:" << errorMsg;
m_statusNetJob.reset();
emit statusLoadingFailed(errorMsg);
emit statusLoading(false);
}

View File

@ -29,26 +29,27 @@ public:
QString getLastLoadErrorMsg() const;
bool isStatusLoaded() const;
bool isLoadingStatus() const;
QMap<QString, QString> getStatusEntries() const;
void Q_SLOT reloadStatus();
protected:
virtual void timerEvent(QTimerEvent *);
signals:
void statusLoaded();
void statusLoadingFailed(QString errorMsg);
void statusLoading(bool loading);
void statusChanged(QMap<QString, QString> newStatus);
protected slots:
void statusDownloadFinished();
void statusDownloadFailed();
protected:
QMap<QString, QString> m_prevEntries;
QMap<QString, QString> m_statusEntries;
NetJobPtr m_statusNetJob;
bool m_loadedStatus;
QString m_lastLoadError;
void Q_SLOT succeed();