From 94babbd9ca5eaf22817a41e2df29f2fc8dcad352 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Fri, 20 Aug 2010 17:08:09 +0200
Subject: [PATCH] CodePaster: Do better checking on hosts.

Do an initial connection check on the host
(once per host). Add utility function to
NetworkProtocol, displaying connection check
message box.
Move the 'Paste' handling into the PasteView
dialog, such that the checking happens there
and the dialog stays open if something fails.

Task-number: QTCREATORBUG-2117
---
 src/plugins/cpaster/codepasterprotocol.cpp    | 13 ++++--
 src/plugins/cpaster/codepasterprotocol.h      |  3 +-
 src/plugins/cpaster/cpasterplugin.cpp         | 19 +--------
 src/plugins/cpaster/pastebindotcaprotocol.cpp | 13 +++++-
 src/plugins/cpaster/pastebindotcaprotocol.h   |  4 ++
 .../cpaster/pastebindotcomprotocol.cpp        | 13 +++++-
 src/plugins/cpaster/pastebindotcomprotocol.h  |  4 ++
 src/plugins/cpaster/pasteview.cpp             | 40 ++++++++++++++-----
 src/plugins/cpaster/pasteview.h               |  4 ++
 src/plugins/cpaster/protocol.cpp              | 40 ++++++++++++++++++-
 src/plugins/cpaster/protocol.h                |  7 +++-
 11 files changed, 122 insertions(+), 38 deletions(-)

diff --git a/src/plugins/cpaster/codepasterprotocol.cpp b/src/plugins/cpaster/codepasterprotocol.cpp
index dcf2159bb10..bc8137abfd8 100644
--- a/src/plugins/cpaster/codepasterprotocol.cpp
+++ b/src/plugins/cpaster/codepasterprotocol.cpp
@@ -71,9 +71,10 @@ unsigned CodePasterProtocol::capabilities() const
     return ListCapability|PostCommentCapability|PostDescriptionCapability;
 }
 
-bool CodePasterProtocol::checkConfiguration(QString *errorMessage) const
+bool CodePasterProtocol::checkConfiguration(QString *errorMessage)
 {
-    if (m_page->hostName().isEmpty()) {
+    const QString hostName = m_page->hostName();
+    if (hostName.isEmpty()) {
         if (errorMessage) {
             *errorMessage =
 #ifdef Q_OS_MAC
@@ -84,7 +85,13 @@ bool CodePasterProtocol::checkConfiguration(QString *errorMessage) const
         }
         return false;
     }
-    return true;
+    // Check the host once. Note that it can be modified in the settings page.
+    if (m_hostChecked == hostName)
+        return true;
+    const bool ok = httpStatus(m_page->hostName(), errorMessage);
+    if (ok)
+        m_hostChecked = hostName;
+    return ok;
 }
 
 void CodePasterProtocol::fetch(const QString &id)
diff --git a/src/plugins/cpaster/codepasterprotocol.h b/src/plugins/cpaster/codepasterprotocol.h
index e899248ad07..e47481d03f8 100644
--- a/src/plugins/cpaster/codepasterprotocol.h
+++ b/src/plugins/cpaster/codepasterprotocol.h
@@ -53,7 +53,7 @@ public:
     bool hasSettings() const;
     Core::IOptionsPage *settingsPage() const;
 
-    virtual bool checkConfiguration(QString *errorMessage = 0) const;
+    virtual bool checkConfiguration(QString *errorMessage = 0);
     void fetch(const QString &id);
     void list();
     void paste(const QString &text,
@@ -72,6 +72,7 @@ private:
     QNetworkReply *m_fetchReply;
     QNetworkReply *m_listReply;
     QString m_fetchId;
+    QString m_hostChecked;
 };
 
 } // namespace CodePaster
diff --git a/src/plugins/cpaster/cpasterplugin.cpp b/src/plugins/cpaster/cpasterplugin.cpp
index 0756b1b77dc..cb73abfeebf 100644
--- a/src/plugins/cpaster/cpasterplugin.cpp
+++ b/src/plugins/cpaster/cpasterplugin.cpp
@@ -208,25 +208,10 @@ void CodepasterPlugin::post(QString data, const QString &mimeType)
     QString comment;
     QString protocolName;
 
-    PasteView view(m_protocols, 0);
+    PasteView view(m_protocols, mimeType, 0);
     view.setProtocol(m_settings->protocol);
 
-    if (!view.show(username, description, comment, lst))
-        return; // User canceled post
-
-    username = view.user();
-    description = view.description();
-    comment = view.comment();
-    data = view.content();
-    protocolName = view.protocol();
-    foreach(Protocol *protocol, m_protocols) {
-        if (protocol->name() == protocolName) {
-            const Protocol::ContentType ct = Protocol::contentType(mimeType);
-            if (Protocol::ensureConfiguration(protocol))
-                protocol->paste(data, ct, username, comment, description);
-            break;
-        }
-    }
+    view.show(username, description, comment, lst);
 }
 
 void CodepasterPlugin::fetch()
diff --git a/src/plugins/cpaster/pastebindotcaprotocol.cpp b/src/plugins/cpaster/pastebindotcaprotocol.cpp
index 76bad682df7..00f70c88c8f 100644
--- a/src/plugins/cpaster/pastebindotcaprotocol.cpp
+++ b/src/plugins/cpaster/pastebindotcaprotocol.cpp
@@ -43,7 +43,8 @@ PasteBinDotCaProtocol::PasteBinDotCaProtocol(const NetworkAccessManagerProxyPtr
     NetworkProtocol(nw),
     m_fetchReply(0),
     m_listReply(0),
-    m_pasteReply(0)
+    m_pasteReply(0),
+    m_hostChecked(false)
 {
 }
 
@@ -131,6 +132,16 @@ void PasteBinDotCaProtocol::list()
     connect(m_listReply, SIGNAL(finished()), this, SLOT(listFinished()));
 }
 
+bool PasteBinDotCaProtocol::checkConfiguration(QString *errorMessage)
+{
+    if (m_hostChecked) // Check the host once.
+        return true;
+    const bool ok = httpStatus(QLatin1String(urlC), errorMessage);
+    if (ok)
+        m_hostChecked = true;
+    return ok;
+}
+
 /* Quick & dirty: Parse the <div>-elements with the "Recent Posts" listing
  * out of the page.
 \code
diff --git a/src/plugins/cpaster/pastebindotcaprotocol.h b/src/plugins/cpaster/pastebindotcaprotocol.h
index 38e1e12abe2..9e08b544d15 100644
--- a/src/plugins/cpaster/pastebindotcaprotocol.h
+++ b/src/plugins/cpaster/pastebindotcaprotocol.h
@@ -56,11 +56,15 @@ public slots:
     void listFinished();
     void pasteFinished();
 
+protected:
+    virtual bool checkConfiguration(QString *errorMessage);
+
 private:
     QNetworkReply *m_fetchReply;
     QNetworkReply *m_listReply;
     QNetworkReply *m_pasteReply;
     QString m_fetchId;
+    bool m_hostChecked;
 };
 
 } // namespace CodePaster
diff --git a/src/plugins/cpaster/pastebindotcomprotocol.cpp b/src/plugins/cpaster/pastebindotcomprotocol.cpp
index 2e7876b9eb0..3c2349fbdfd 100644
--- a/src/plugins/cpaster/pastebindotcomprotocol.cpp
+++ b/src/plugins/cpaster/pastebindotcomprotocol.cpp
@@ -55,7 +55,8 @@ PasteBinDotComProtocol::PasteBinDotComProtocol(const NetworkAccessManagerProxyPt
     m_pasteReply(0),
     m_listReply(0),
     m_fetchId(-1),
-    m_postId(-1)
+    m_postId(-1),
+    m_hostChecked(false)
 {
 }
 
@@ -69,6 +70,16 @@ unsigned PasteBinDotComProtocol::capabilities() const
     return ListCapability;
 }
 
+bool PasteBinDotComProtocol::checkConfiguration(QString *errorMessage)
+{
+    if (m_hostChecked)  // Check the host once.
+        return true;
+    const bool ok = httpStatus(hostName(false), errorMessage);
+    if (ok)
+        m_hostChecked = true;
+    return ok;
+}
+
 QString PasteBinDotComProtocol::hostName(bool withSubDomain) const
 {
 
diff --git a/src/plugins/cpaster/pastebindotcomprotocol.h b/src/plugins/cpaster/pastebindotcomprotocol.h
index e137bc14b2a..b42b5b16d0f 100644
--- a/src/plugins/cpaster/pastebindotcomprotocol.h
+++ b/src/plugins/cpaster/pastebindotcomprotocol.h
@@ -61,6 +61,9 @@ public slots:
     void pasteFinished();
     void listFinished();
 
+protected:
+    virtual bool checkConfiguration(QString *errorMessage = 0);
+
 private:
     QString hostName(bool withSubDomain) const;
 
@@ -71,6 +74,7 @@ private:
 
     QString m_fetchId;
     int m_postId;
+    bool m_hostChecked;
 };
 } // namespace CodePaster
 #endif // PASTEBINDOTCOMPROTOCOL_H
diff --git a/src/plugins/cpaster/pasteview.cpp b/src/plugins/cpaster/pasteview.cpp
index 35ed030f1c4..67c49046694 100644
--- a/src/plugins/cpaster/pasteview.cpp
+++ b/src/plugins/cpaster/pasteview.cpp
@@ -46,9 +46,12 @@ static const char widthKeyC[] = "PasteViewWidth";
 namespace CodePaster {
 // -------------------------------------------------------------------------------------------------
 PasteView::PasteView(const QList<Protocol *> protocols,
-                     QWidget *parent)
-    : QDialog(parent), m_protocols(protocols),
-    m_commentPlaceHolder(tr("<Comment>"))
+                     const QString &mt,
+                     QWidget *parent) :
+    QDialog(parent),
+    m_protocols(protocols),
+    m_commentPlaceHolder(tr("<Comment>")),
+    m_mimeType(mt)
 {
     m_ui.setupUi(this);
 
@@ -140,7 +143,7 @@ int PasteView::show(const QString &user, const QString &description, const QStri
     m_ui.uiDescription->selectAll();
 
     // (Re)store dialog size
-    QSettings *settings = Core::ICore::instance()->settings();
+    const QSettings *settings = Core::ICore::instance()->settings();
     const QString rootKey = QLatin1String(groupC) + QLatin1Char('/');
     const int h = settings->value(rootKey + QLatin1String(heightKeyC), height()).toInt();
     const int defaultWidth = m_ui.uiPatchView->columnIndicator() + 50;
@@ -149,16 +152,31 @@ int PasteView::show(const QString &user, const QString &description, const QStri
     resize(w, h);
 
     const int ret = QDialog::exec();
-
-    if (ret == QDialog::Accepted) {
-        settings->beginGroup(QLatin1String(groupC));
-        settings->setValue(QLatin1String(heightKeyC), height());
-        settings->setValue(QLatin1String(widthKeyC), width());
-        settings->endGroup();
-    }
     return ret;
 }
 
+void PasteView::accept()
+{
+    const int index = m_ui.protocolBox->currentIndex();
+    if (index == -1)
+        return;
+
+    Protocol *protocol = m_protocols.at(index);
+
+    if (!Protocol::ensureConfiguration(protocol, this))
+        return;
+
+    const Protocol::ContentType ct = Protocol::contentType(m_mimeType);
+    protocol->paste(content(), ct, user(), comment(), description());
+    // Store settings and close
+    QSettings *settings = Core::ICore::instance()->settings();
+    settings->beginGroup(QLatin1String(groupC));
+    settings->setValue(QLatin1String(heightKeyC), height());
+    settings->setValue(QLatin1String(widthKeyC), width());
+    settings->endGroup();
+    QDialog::accept();
+}
+
 void PasteView::setProtocol(const QString &protocol)
 {
      const int index = m_ui.protocolBox->findText(protocol);
diff --git a/src/plugins/cpaster/pasteview.h b/src/plugins/cpaster/pasteview.h
index 9ccd10051d7..be3659b62fa 100644
--- a/src/plugins/cpaster/pasteview.h
+++ b/src/plugins/cpaster/pasteview.h
@@ -42,6 +42,7 @@ class PasteView : public QDialog
     Q_OBJECT
 public:
     explicit PasteView(const QList<Protocol *> protocols,
+                       const QString &mimeType,
                        QWidget *parent);
     ~PasteView();
 
@@ -56,6 +57,8 @@ public:
     QByteArray content() const;
     QString protocol() const;
 
+    virtual void accept();
+
 private slots:
     void contentChanged();
     void protocolChanged(int);
@@ -63,6 +66,7 @@ private slots:
 private:
     const QList<Protocol *> m_protocols;
     const QString m_commentPlaceHolder;
+    const QString m_mimeType;
 
     Ui::ViewDialog m_ui;
     FileDataList m_parts;
diff --git a/src/plugins/cpaster/protocol.cpp b/src/plugins/cpaster/protocol.cpp
index 68aca2f58c7..00ea7bca153 100644
--- a/src/plugins/cpaster/protocol.cpp
+++ b/src/plugins/cpaster/protocol.cpp
@@ -35,9 +35,13 @@
 
 #include <QtNetwork/QNetworkAccessManager>
 #include <QtNetwork/QNetworkRequest>
+#include <QtNetwork/QNetworkReply>
 
 #include <QtCore/QUrl>
+#include <QtCore/QDebug>
+
 #include <QtGui/QMessageBox>
+#include <QtGui/QApplication>
 #include <QtGui/QMainWindow>
 #include <QtGui/QPushButton>
 
@@ -57,7 +61,7 @@ bool Protocol::hasSettings() const
     return false;
 }
 
-bool Protocol::checkConfiguration(QString *) const
+bool Protocol::checkConfiguration(QString *)
 {
     return true;
 }
@@ -115,7 +119,7 @@ QString Protocol::textFromHtml(QString data)
     return data;
 }
 
-bool Protocol::ensureConfiguration(const Protocol *p, QWidget *parent)
+bool Protocol::ensureConfiguration(Protocol *p, QWidget *parent)
 {
     QString errorMessage;
     bool ok = false;
@@ -196,4 +200,36 @@ NetworkProtocol::~NetworkProtocol()
 {
 }
 
+bool NetworkProtocol::httpStatus(QString url, QString *errorMessage)
+{
+    // Connect to host and display a message box, using its event loop.
+    errorMessage->clear();
+    const QString httpPrefix = QLatin1String("http://");
+    if (!url.startsWith(httpPrefix)) {
+        url.prepend(httpPrefix);
+        url.append(QLatin1Char('/'));
+    }
+    QNetworkReply *reply = httpGet(url);
+    QMessageBox box(QMessageBox::Information,
+                    tr("Checking connection"),
+                    tr("Connecting to %1...").arg(url),
+                    QMessageBox::Cancel,
+                    Core::ICore::instance()->mainWindow());
+    connect(reply, SIGNAL(finished()), &box, SLOT(close()));
+    QApplication::setOverrideCursor(Qt::WaitCursor);
+    box.exec();
+    QApplication::restoreOverrideCursor();
+    // User canceled, discard and be happy.
+    if (!reply->isFinished()) {
+        connect(reply, SIGNAL(finished()), reply, SLOT(deleteLater()));
+        return false;
+    }
+    // Passed
+    if (reply->error() == QNetworkReply::NoError)
+        return true;
+    // Error.
+    *errorMessage = reply->errorString();
+    return false;
+}
+
 } //namespace CodePaster
diff --git a/src/plugins/cpaster/protocol.h b/src/plugins/cpaster/protocol.h
index 43ecc6a823c..40066270ae7 100644
--- a/src/plugins/cpaster/protocol.h
+++ b/src/plugins/cpaster/protocol.h
@@ -67,7 +67,7 @@ public:
     virtual bool hasSettings() const;
     virtual Core::IOptionsPage *settingsPage() const;
 
-    virtual bool checkConfiguration(QString *errorMessage = 0) const;
+    virtual bool checkConfiguration(QString *errorMessage = 0);
     virtual void fetch(const QString &id) = 0;
     virtual void list();
     virtual void paste(const QString &text,
@@ -86,7 +86,7 @@ public:
                                        QWidget *parent = 0,
                                        bool showConfig = true);
     // Ensure configuration is correct
-    static bool ensureConfiguration(const Protocol *p,
+    static bool ensureConfiguration(Protocol *p,
                                     QWidget *parent = 0);
 
 signals:
@@ -143,6 +143,9 @@ protected:
     inline QNetworkAccessManager *networkAccessManager()
     { return m_networkAccessManager->networkAccessManager(); }
 
+    // Check connectivity of host, displaying a message box.
+    bool httpStatus(QString url, QString *errorMessage);
+
 private:
     const NetworkAccessManagerProxyPtr m_networkAccessManager;
 };
-- 
GitLab