[kde-doc-english] [trojita] src/Gui: GUI: disable automatic preloading of the "other" multipart/alternative message parts

Jan Kundrát jkt at flaska.net
Wed Jan 9 09:58:10 UTC 2013


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;


More information about the kde-doc-english mailing list