Git commit 1e37120823fdfc55c4a8730fa1ad7521876b7601 by Jan Kundr?t. Committed on 09/01/2013 at 10:56. Pushed by jkt into branch 'master'.
GUI: disable automatic preloading of the "other" multipart/alternative message parts This has a nice side effect that the tab widget gets resized when the part-to-be-loaded is bigger than the old part M +24 -9 src/Gui/LoadablePartWidget.cpp M +14 -6 src/Gui/LoadablePartWidget.h M +20 -4 src/Gui/PartWidget.cpp M +8 -4 src/Gui/PartWidgetFactory.cpp M +7 -1 src/Gui/PartWidgetFactory.h http://commits.kde.org/trojita/1e37120823fdfc55c4a8730fa1ad7521876b7601 diff --git a/src/Gui/LoadablePartWidget.cpp b/src/Gui/LoadablePartWidget.cpp index 0d2b605..98e2b0c 100644 --- a/src/Gui/LoadablePartWidget.cpp +++ b/src/Gui/LoadablePartWidget.cpp @@ -29,24 +29,32 @@ namespace Gui { LoadablePartWidget::LoadablePartWidget(QWidget *parent, Imap::Network::MsgPartNetAccessManager *manager, const QModelIndex &part, - QObject *wheelEventFilter, QObject *guiInteractionTarget): + QObject *wheelEventFilter, QObject *guiInteractionTarget, const LoadingTriggerMode mode): QStackedWidget(parent), manager(manager), partIndex(part), realPart(0), wheelEventFilter(wheelEventFilter), - guiInteractionTarget(guiInteractionTarget) + guiInteractionTarget(guiInteractionTarget), loadButton(0), m_loadOnShow(mode == LOAD_ON_SHOW) { Q_ASSERT(partIndex.isValid()); - loadButton = new QPushButton(tr("Load %1 (%2)").arg(partIndex.data(Imap::Mailbox::RolePartMimeType).toString(), - Imap::Mailbox::PrettySize::prettySize(partIndex.data(Imap::Mailbox::RolePartOctets).toUInt())), - this); - connect(loadButton, SIGNAL(clicked()), this, SLOT(loadClicked())); - addWidget(loadButton); + if (mode == LOAD_ON_CLICK) { + loadButton = new QPushButton(tr("Load %1 (%2)").arg(partIndex.data(Imap::Mailbox::RolePartMimeType).toString(), + Imap::Mailbox::PrettySize::prettySize(partIndex.data(Imap::Mailbox::RolePartOctets).toUInt())), + this); + connect(loadButton, SIGNAL(clicked()), this, SLOT(loadClicked())); + addWidget(loadButton); + } } void LoadablePartWidget::loadClicked() { if (!partIndex.isValid()) { - loadButton->setEnabled(false); + if (loadButton) { + loadButton->setEnabled(false); + } return; } + if (loadButton) { + loadButton->deleteLater(); + loadButton = 0; + } realPart = new SimplePartWidget(this, manager, partIndex); realPart->installEventFilter(wheelEventFilter); realPart->connectGuiInteractionEvents(guiInteractionTarget); @@ -59,6 +67,13 @@ QString LoadablePartWidget::quoteMe() const return realPart ? realPart->quoteMe() : QString(); } +void LoadablePartWidget::showEvent(QShowEvent *event) +{ + QStackedWidget::showEvent(event); + if (m_loadOnShow) { + m_loadOnShow = false; + loadClicked(); + } } - +} diff --git a/src/Gui/LoadablePartWidget.h b/src/Gui/LoadablePartWidget.h index a3ee04e..9ba7b13 100644 --- a/src/Gui/LoadablePartWidget.h +++ b/src/Gui/LoadablePartWidget.h @@ -33,21 +33,28 @@ class QPushButton; namespace Gui { -/** @short Widget which implements "click-through" for loading message parts on demand +/** @short Widget which implements delayed loading of message parts + + This class supports two modes of loading, either a "click-through" one for loading message parts + on demand after the user clicks a button, or an "automated" mode where the data are loaded after + this widget becomes visible. - When a policy dictates that certain body parts should not be shown unless - really required, this widget comes to action. It provides a click-wrapped - meaning of showing huge body parts. No data are transfered unless the user - clicks a button. */ class LoadablePartWidget : public QStackedWidget, public AbstractPartWidget { Q_OBJECT public: + /** @short Load when the widget becomes visible, or wait until the user clicks a button? */ + typedef enum { + LOAD_ON_SHOW, /**< @short Load as soon as the widget becomes visible */ + LOAD_ON_CLICK /**< @short Load onlt after the user has clicked a button */ + } LoadingTriggerMode; LoadablePartWidget(QWidget *parent, Imap::Network::MsgPartNetAccessManager *manager, const QModelIndex &part, - QObject *wheelEventFilter, QObject *guiInteractionTarget); + QObject *wheelEventFilter, QObject *guiInteractionTarget, const LoadingTriggerMode mode); QString quoteMe() const; virtual void reloadContents() {} +protected: + virtual void showEvent(QShowEvent *event); private slots: void loadClicked(); private: @@ -57,6 +64,7 @@ private: QObject *wheelEventFilter; QObject *guiInteractionTarget; QPushButton *loadButton; + bool m_loadOnShow; LoadablePartWidget(const LoadablePartWidget &); // don't implement LoadablePartWidget &operator=(const LoadablePartWidget &); // don't implement diff --git a/src/Gui/PartWidget.cpp b/src/Gui/PartWidget.cpp index d2fcdbe..640a962 100644 --- a/src/Gui/PartWidget.cpp +++ b/src/Gui/PartWidget.cpp @@ -51,17 +51,33 @@ MultipartAlternativeWidget::MultipartAlternativeWidget(QWidget *parent, { setContentsMargins(0,0,0,0); int preferredIndex = -1; + // First loop iteration is used to find out what MIME type to show for (int i = 0; i < partIndex.model()->rowCount(partIndex); ++i) { - using namespace Imap::Mailbox; QModelIndex anotherPart = partIndex.child(i, 0); Q_ASSERT(anotherPart.isValid()); - QWidget *item = factory->create(anotherPart, recursionDepth + 1); QString mimeType = anotherPart.data(Imap::Mailbox::RolePartMimeType).toString(); - addTab(item, mimeType); if (preferredIndex == -1 && mimeType == preferredMimeType) preferredIndex = i; } - setCurrentIndex(preferredIndex == -1 ? partIndex.model()->rowCount(partIndex) - 1 : preferredIndex); + if (preferredIndex == -1) { + // If no preference is obvious, let's assume the last item wins + preferredIndex = partIndex.model()->rowCount(partIndex) - 1; + } + // The second loop actually creates the widgets + for (int i = 0; i < partIndex.model()->rowCount(partIndex); ++i) { + QModelIndex anotherPart = partIndex.child(i, 0); + Q_ASSERT(anotherPart.isValid()); + // TODO: This is actually not perfect, the preferred part of a multipart/alternative + // which is nested as a non-preferred part of another multipart/alternative actually gets loaded here. + // I can live with that. + QWidget *item = factory->create(anotherPart, recursionDepth + 1, + i == preferredIndex ? + PartWidgetFactory::LOAD_IMMEDIATELY : + PartWidgetFactory::LOAD_ON_SHOW); + QString mimeType = anotherPart.data(Imap::Mailbox::RolePartMimeType).toString(); + addTab(item, mimeType); + } + setCurrentIndex(preferredIndex); } QString MultipartAlternativeWidget::quoteMe() const diff --git a/src/Gui/PartWidgetFactory.cpp b/src/Gui/PartWidgetFactory.cpp index e5e903d..01fe437 100644 --- a/src/Gui/PartWidgetFactory.cpp +++ b/src/Gui/PartWidgetFactory.cpp @@ -51,7 +51,7 @@ QWidget *PartWidgetFactory::create(const QModelIndex &partIndex) return create(partIndex, 0); } -QWidget *PartWidgetFactory::create(const QModelIndex &partIndex, int recursionDepth) +QWidget *PartWidgetFactory::create(const QModelIndex &partIndex, int recursionDepth, const PartLoadingMode loadingMode) { using namespace Imap::Mailbox; Q_ASSERT(partIndex.isValid()); @@ -145,9 +145,10 @@ QWidget *PartWidgetFactory::create(const QModelIndex &partIndex, int recursionDe Q_ASSERT(model); Q_ASSERT(part); part->fetchFromCache(model); - bool showDirectly = true; + + bool showDirectly = loadingMode == LOAD_IMMEDIATELY; if (!part->fetched()) - showDirectly = model->isNetworkOnline() || part->octets() <= ExpensiveFetchThreshold; + showDirectly &= model->isNetworkOnline() || part->octets() <= ExpensiveFetchThreshold; QWidget *widget = 0; if (showDirectly) { @@ -155,7 +156,10 @@ QWidget *PartWidgetFactory::create(const QModelIndex &partIndex, int recursionDe static_cast<SimplePartWidget*>(widget)->connectGuiInteractionEvents(guiInteractionTarget); } else if (model->isNetworkAvailable()) { - widget = new LoadablePartWidget(0, manager, partIndex, wheelEventFilter, guiInteractionTarget); + widget = new LoadablePartWidget(0, manager, partIndex, wheelEventFilter, guiInteractionTarget, + loadingMode == LOAD_ON_SHOW && part->octets() <= ExpensiveFetchThreshold ? + LoadablePartWidget::LOAD_ON_SHOW : + LoadablePartWidget::LOAD_ON_CLICK); } else { widget = new QLabel(tr("Offline"), 0); } diff --git a/src/Gui/PartWidgetFactory.h b/src/Gui/PartWidgetFactory.h index 0977ce6..85ef633 100644 --- a/src/Gui/PartWidgetFactory.h +++ b/src/Gui/PartWidgetFactory.h @@ -36,9 +36,15 @@ class PartWidgetFactory Q_DECLARE_TR_FUNCTIONS(PartWidgetFactory) enum { ExpensiveFetchThreshold = 50*1024 }; public: + /** @short Are the parts supposed to be visible immediately, or only after their respective widget is shown? */ + typedef enum { + LOAD_IMMEDIATELY, /**< @short Load them immediately */ + LOAD_ON_SHOW /**< @short Load the parts only after they have been shown to the user */ + } PartLoadingMode; + PartWidgetFactory(Imap::Network::MsgPartNetAccessManager *manager, QObject *wheelEventFilter, QObject *guiInteractionTarget); QWidget *create(const QModelIndex &partIndex); - QWidget *create(const QModelIndex &partIndex, int recursionDepth); + QWidget *create(const QModelIndex &partIndex, int recursionDepth, const PartLoadingMode loadingMode = LOAD_IMMEDIATELY); private: Imap::Network::MsgPartNetAccessManager *manager; QObject *wheelEventFilter;
