diff --git a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -110,6 +110,7 @@
find_package(KF5WidgetsAddons ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5WindowSystem ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5XmlGui ${KF5_VERSION} CONFIG REQUIRED)
+find_package(KF5Plasma ${KF5_VERSION} CONFIG REQUIRED)
# Find KdepimLibs Package
find_package(KF5Akonadi ${AKONADI_VERSION} CONFIG REQUIRED)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -144,6 +144,7 @@
widgets/statusbarlabeltoggledstate.cpp
widgets/kactionmenutransport.cpp
widgets/kactionmenuaccount.cpp
+ widgets/busyindicator.cpp
)
set(kmailprivate_tag_LIB_SRCS
tag/tagactionmanager.cpp
@@ -324,6 +325,7 @@
KF5::AkonadiSearchPIM
KF5::WebEngineViewer
KF5::SyntaxHighlighting
+ KF5::Plasma
)
target_include_directories(kmailprivate PUBLIC $)
target_include_directories(kmailprivate PUBLIC $)
diff --git a/src/kmreaderwin.h b/src/kmreaderwin.h
--- a/src/kmreaderwin.h
+++ b/src/kmreaderwin.h
@@ -33,6 +33,7 @@
class QAction;
class KToggleAction;
class QMenu;
+class QStackedWidget;
namespace MessageViewer {
class CSSHelper;
}
@@ -43,6 +44,9 @@
class KJob;
+class BusyWidget;
+class OfflineWidget;
+
/**
This class implements a "reader window", that is a window
used for reading or viewing messages.
@@ -243,6 +247,9 @@
QMenu *mViewHtmlOptions;
+ QStackedWidget *mStack;
+ BusyWidget *mBusyWidget;
+ OfflineWidget *mOfflineWidget;
MessageViewer::Viewer *mViewer;
};
diff --git a/src/kmreaderwin.cpp b/src/kmreaderwin.cpp
--- a/src/kmreaderwin.cpp
+++ b/src/kmreaderwin.cpp
@@ -28,6 +28,7 @@
#include "mailcommon/mailkernel.h"
#include "dialog/addemailtoexistingcontactdialog.h"
#include "job/addemailtoexistingcontactjob.h"
+#include "widgets/busyindicator.h"
#include "kmail-version.h"
#include
@@ -73,8 +74,12 @@
#include
#include
#include
+#include
+#include
+#include
#include
+#include
// X headers...
#undef Never
@@ -85,6 +90,109 @@
using namespace KMail;
using namespace MailCommon;
+class BusyWidget : public QWidget {
+ Q_OBJECT
+public:
+ explicit BusyWidget(QWidget *parent = nullptr)
+ : QWidget(parent)
+ {
+ mLabel = new QLabel;
+ mLabel->setAlignment(Qt::AlignCenter);
+
+ mBusy = new BusyIndicator;
+ mBusy->setMinimumWidth(64);
+ mBusy->setMinimumHeight(64);
+
+ auto l = new QGridLayout(this);
+ l->addWidget(mBusy, 1, 0, Qt::AlignCenter);
+ l->addWidget(mLabel, 2, 0, Qt::AlignCenter);
+ l->setRowStretch(0, 2);
+ l->setRowStretch(3, 2);
+ }
+
+ void setText(const QString &text)
+ {
+ mLabel->setText(text);
+ }
+
+protected:
+ void showEvent(QShowEvent *event) override
+ {
+ mBusy->setActive(true);
+ QWidget::showEvent(event);
+ }
+
+ void hideEvent(QHideEvent *event) override
+ {
+ mBusy->setActive(false);
+ QWidget::hideEvent(event);
+ }
+
+private:
+ BusyIndicator *mBusy;
+ QLabel *mLabel;
+};
+
+
+class OfflineWidget : public QWidget {
+ Q_OBJECT
+public:
+ explicit OfflineWidget(QWidget *parent = nullptr)
+ : QWidget(parent)
+ , mOnlineMode(MessageViewer::Viewer::AllResources)
+ {
+ auto l = new QVBoxLayout;
+ setLayout(l);
+ l->addStretch(2);
+
+ auto h = new QHBoxLayout;
+ h->addStretch(2);
+ auto icon = new QLabel;
+ icon->setPixmap(QIcon::fromTheme(QStringLiteral("offline")).pixmap(42));
+ h->addWidget(icon);
+
+ mLabel = new QLabel;
+ mLabel->setAlignment(Qt::AlignCenter);
+ h->addWidget(mLabel);
+ h->addStretch(2);
+
+ l->addLayout(h);
+
+ mOnlineBtn = new QPushButton;
+ connect(mOnlineBtn, &QPushButton::clicked,
+ this, [this]() {
+ Q_EMIT goOnline(mOnlineMode);
+ });
+ l->addWidget(mOnlineBtn, 0, Qt::AlignCenter);
+
+ l->addStretch(2);
+ }
+
+ void setText(const QString &labelText, const QString &buttonText,
+ MessageViewer::Viewer::ResourceOnlineMode onlineMode)
+ {
+ mLabel->setText(labelText);
+ mOnlineBtn->setText(buttonText);
+ mOnlineMode = onlineMode;
+ }
+
+Q_SIGNALS:
+ void goOnline(MessageViewer::Viewer::ResourceOnlineMode onlineMode);
+
+private:
+ QLabel *mLabel;
+ QPushButton *mOnlineBtn;
+ MessageViewer::Viewer::ResourceOnlineMode mOnlineMode;
+};
+
+namespace {
+
+static const int Stack_ViewerIndex = 0;
+static const int Stack_BusyIndex = 1;
+static const int Stack_OfflineIndex = 2;
+
+}
+
KMReaderWin::KMReaderWin(QWidget *aParent, QWidget *mainWindow, KActionCollection *actionCollection)
: QWidget(aParent)
, mMainWindow(mainWindow)
@@ -101,10 +209,13 @@
createActions();
QVBoxLayout *vlay = new QVBoxLayout(this);
vlay->setContentsMargins(0, 4, 0, 0);
+
+ mStack = new QStackedWidget(this);
+ vlay->addWidget(mStack);
+
mViewer = new Viewer(this, mainWindow, mActionCollection);
connect(mViewer, SIGNAL(urlClicked(Akonadi::Item,QUrl)), this, SLOT(slotUrlClicked(Akonadi::Item,QUrl)));
connect(mViewer, &Viewer::requestConfigSync, kmkernel, &KMKernel::slotRequestConfigSync, Qt::QueuedConnection); // happens anyway on shutdown, so we can skip it there with using a queued connection
- connect(mViewer, &Viewer::makeResourceOnline, kmkernel, &KMKernel::makeResourceOnline);
connect(mViewer, &MessageViewer::Viewer::showReader, this, &KMReaderWin::slotShowReader);
connect(mViewer, &MessageViewer::Viewer::showMessage, this, &KMReaderWin::slotShowMessage);
connect(mViewer, &MessageViewer::Viewer::showStatusBarMessage, this, &KMReaderWin::showStatusBarMessage);
@@ -114,7 +225,18 @@
mViewer->addMessageLoadedHandler(new MessageViewer::MarkMessageReadHandler(this));
mViewer->addMessageLoadedHandler(new MailCommon::SendMdnHandler(kmkernel, this));
- vlay->addWidget(mViewer);
+ mStack->addWidget(mViewer);
+
+ mBusyWidget = new BusyWidget(this);
+ mStack->addWidget(mBusyWidget);
+
+ mOfflineWidget = new OfflineWidget(this);
+ connect(mOfflineWidget, &OfflineWidget::goOnline,
+ kmkernel, &KMKernel::makeResourceOnline);
+ mStack->addWidget(mOfflineWidget);
+
+ mStack->setCurrentIndex(Stack_ViewerIndex);
+
readConfig();
}
@@ -313,32 +435,26 @@
void KMReaderWin::displayBusyPage()
{
- displaySplashPage(QStringLiteral("status.html"), {
- { QStringLiteral("title"), i18n("Retrieving Folder Contents") },
- { QStringLiteral("subtext"), i18n("Please wait . . .") }
- });
+ mBusyWidget->setText(i18n("Loading message..."));
+ mStack->setCurrentIndex(Stack_BusyIndex);
+ mViewer->clear(MimeTreeParser::Delayed);
}
void KMReaderWin::displayOfflinePage()
{
- displaySplashPage(QStringLiteral("status.html"), {
- { QStringLiteral("title"), i18n("Offline") },
- {
- QStringLiteral("subtext"), i18n("KMail is currently in offline mode. "
- "Click here to go online . . .
")
- }
- });
+ mOfflineWidget->setText(i18n("KMail is currently in offline mode."),
+ i18n("Go online"), MessageViewer::Viewer::AllResources);
+ mStack->setCurrentIndex(Stack_OfflineIndex);
+ mViewer->clear(MimeTreeParser::Delayed);
}
void KMReaderWin::displayResourceOfflinePage()
{
- displaySplashPage(QStringLiteral("status.html"), {
- { QStringLiteral("title"), i18n("Offline") },
- {
- QStringLiteral("subtext"), i18n("Account is currently in offline mode. "
- "Click here to go online . . .")
- }
- });
+ mOfflineWidget->setText(i18n("Account is currently in offline mode."),
+ i18n("Switch account online"),
+ MessageViewer::Viewer::SelectedResource);
+ mStack->setCurrentIndex(Stack_OfflineIndex);
+ mViewer->clear(MimeTreeParser::Delayed);
}
void KMReaderWin::displayAboutPage()
@@ -661,17 +777,20 @@
void KMReaderWin::clear(bool force)
{
mViewer->clear(force ? MimeTreeParser::Force : MimeTreeParser::Delayed);
+ mStack->setCurrentIndex(Stack_ViewerIndex);
}
void KMReaderWin::setMessage(const Akonadi::Item &item, MimeTreeParser::UpdateMode updateMode)
{
qCDebug(KMAIL_LOG) << Q_FUNC_INFO << parentWidget();
mViewer->setMessageItem(item, updateMode);
+ mStack->setCurrentIndex(Stack_ViewerIndex);
}
void KMReaderWin::setMessage(const KMime::Message::Ptr &message)
{
mViewer->setMessage(message);
+ mStack->setCurrentIndex(Stack_ViewerIndex);
}
QUrl KMReaderWin::urlClicked() const
@@ -890,3 +1009,5 @@
deleteLater();
}
}
+
+#include "kmreaderwin.moc"
diff --git a/src/widgets/busyindicator.h b/src/widgets/busyindicator.h
new file mode 100644
--- /dev/null
+++ b/src/widgets/busyindicator.h
@@ -0,0 +1,35 @@
+#ifndef BUSYINDICATOR_H_
+#define BUSYINDICATOR_H_
+
+#include
+
+namespace Plasma {
+class Svg;
+}
+
+class QTimer;
+
+class BusyIndicator : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit BusyIndicator(QWidget *parent = nullptr);
+ ~BusyIndicator();
+
+ void setActive(bool active);
+ bool active() const;
+
+protected:
+ void paintEvent(QPaintEvent *event) override;
+ void resizeEvent(QResizeEvent *event) override;
+
+ int heightForWidth(int width) const override;
+
+private:
+ Plasma::Svg *mSvg;
+ QTimer *mTimer;
+ int mAngle;
+};
+
+#endif
diff --git a/src/widgets/busyindicator.cpp b/src/widgets/busyindicator.cpp
new file mode 100644
--- /dev/null
+++ b/src/widgets/busyindicator.cpp
@@ -0,0 +1,73 @@
+#include "busyindicator.h"
+
+#include
+#include
+#include
+
+#include
+
+namespace {
+
+static const int FPS = 20;
+static const int StepAngle = 30;
+
+}
+
+BusyIndicator::BusyIndicator(QWidget *parent)
+ : QWidget(parent)
+ , mSvg(new Plasma::Svg(this))
+ , mTimer(new QTimer(this))
+ , mAngle(0)
+{
+ mSvg->setImagePath(QStringLiteral("widgets/busywidget"));
+ mSvg->setUsingRenderingCache(true);
+ mSvg->setContainsMultipleImages(true);
+
+ connect(mTimer, &QTimer::timeout,
+ this, static_cast(&QWidget::repaint));
+ mTimer->setInterval(1000 / FPS);
+}
+
+BusyIndicator::~BusyIndicator()
+{
+ mTimer->stop();
+}
+
+void BusyIndicator::setActive(bool active)
+{
+ if (active && !mTimer->isActive()) {
+ mTimer->start();
+ } else if (!active) {
+ mTimer->stop();
+ }
+}
+
+bool BusyIndicator::active() const
+{
+ return mTimer->isActive();
+}
+
+int BusyIndicator::heightForWidth(int width) const
+{
+ // always square
+ return width;
+}
+
+void BusyIndicator::resizeEvent(QResizeEvent *event)
+{
+ mSvg->resize(event->size());
+ QWidget::resizeEvent(event);
+}
+
+void BusyIndicator::paintEvent(QPaintEvent *event)
+{
+ QWidget::paintEvent(event);
+
+ QPainter painter(this);
+ mAngle = (mAngle + StepAngle) % 360;
+ const int w = width() / 2;
+ const int h = height() / 2;
+ painter.translate(w, h);
+ painter.rotate(mAngle);
+ mSvg->paint(&painter, -w , -h, width(), height());
+}