Project Gutenberg downloads work end-to-end.
authorAkos Polster <akos@pipacs.com>
Sat, 30 Oct 2010 14:16:18 +0000 (16:16 +0200)
committerAkos Polster <akos@pipacs.com>
Sat, 30 Oct 2010 14:16:18 +0000 (16:16 +0200)
platform.cpp
platform.h
search.cpp
search.h
searchresultsdialog.cpp
searchresultsdialog.h

index ea09cfe..1c4172b 100644 (file)
@@ -48,3 +48,8 @@ QString Platform::version()
 {
     return QString(DORIAN_VERSION);
 }
+
+QString Platform::downloadDir()
+{
+    return QDir::home().absoluteFilePath("Books");
+}
index 5f63180..5a25b23 100644 (file)
@@ -11,6 +11,7 @@ public:
     static QString icon(const QString &name);
     static void restart(char *argv[]);
     static QString version();
+    static QString downloadDir();
 };
 
 #endif // PLATFORM_H
index 0d13733..a2ca1ba 100644 (file)
@@ -5,6 +5,7 @@
 #include <QWebPage>
 #include <QWebElementCollection>
 #include <QWebElement>
+#include <QFile>
 
 #include "search.h"
 #include "platform.h"
@@ -59,9 +60,11 @@ QList<Search::Result> Search::results()
     return searchResults;
 }
 
-bool Search::download(const Search::Result &result, const QString &fileName)
+void Search::download(const Search::Result &result, const QString &fileName)
 {
     Trace t("Search::download");
+    downloadResult = result;
+    downloadFileName = fileName;
     qDebug() << "UID" << result.id;
     Q_UNUSED(fileName);
     emit beginDownload(0);
@@ -71,7 +74,6 @@ bool Search::download(const Search::Result &result, const QString &fileName)
     request.setUrl(url);
     downloadReply = downloadManager->get(request);
     connect(downloadReply, SIGNAL(finished()), this, SLOT(downloadFinished()));
-    return true;
 }
 
 void Search::finished()
@@ -133,19 +135,49 @@ void Search::downloadFinished()
         return;
     }
 
+    // Handle download errors
+    if (QNetworkReply::NoError != downloadReply->error()) {
+        qCritical() << "Search::downloadFinished: Network error"
+                << downloadReply->error();
+        downloadReply->deleteLater();
+        downloadReply = 0;
+        emit endDownload(Search::DownloadError, downloadResult, downloadFileName);
+        return;
+    }
+
+    // Handle redirection
     QVariant header = downloadReply->header(QNetworkRequest::LocationHeader);
     if (header.isValid()) {
+        // Handle redirection: Download again with the new URL
         qDebug() << "Redirected to" << header;
-        downloadReply->deleteLater();
         QNetworkRequest request;
         request.setUrl(header.toUrl());
+        downloadReply->deleteLater();
         downloadReply = downloadManager->get(request);
         connect(downloadReply, SIGNAL(finished()), this, SLOT(downloadFinished()));
+        return;
+    }
+
+    // Handle download success
+    QByteArray data = downloadReply->readAll();
+    quint64 size = (quint64)data.size();
+    qDebug() << "Got" << size << "bytes";
+    downloadReply->deleteLater();
+    downloadReply = 0;
+    QFile out(downloadFileName);
+    int status = Search::FileError;
+    if (out.open(QIODevice::WriteOnly)) {
+        if (size == out.write(data, size)) {
+            qDebug() << "Book saved to" << downloadFileName;
+            status = Search::Ok;
+        } else {
+            qCritical() << "Search::downloadFinished: Failed to write" << size
+                    << "bytes to" << downloadFileName;
+        }
+        out.close();
     } else {
-        QByteArray data = downloadReply->readAll();
-        qDebug() << "Got" << data.size() << "bytes";
-        downloadReply->deleteLater();
-        downloadReply = 0;
-        emit endDownload();
+        qCritical() << "Search::downloadFinished: Could not open"
+                << downloadFileName;
     }
+    emit endDownload(status, downloadResult, downloadFileName);
 }
index 6405ea1..4908ac6 100644 (file)
--- a/search.h
+++ b/search.h
@@ -16,6 +16,7 @@ class Search: public QObject
     Q_OBJECT
 
 public:
+    /** Search query. */
     struct Query
     {
         QString title;
@@ -23,6 +24,7 @@ public:
         QStringList languages;
     };
 
+    /** Search result. */
     struct Result
     {
         QString id;
@@ -31,6 +33,17 @@ public:
         QStringList authors;
         QString language;
         QImage cover;
+        bool operator ==(const Result &other) const {
+            return (source == other.source) && (id == other.id);
+        }
+    };
+
+    /** Download status. */
+    enum
+    {
+        Ok,
+        DownloadError,
+        FileError,
     };
 
     static Search *instance();
@@ -42,12 +55,13 @@ signals:
     void endSearch();
     void beginDownload(int totalBlocks);
     void downloading(int blocks);
-    void endDownload();
+    void endDownload(int status, const Search::Result &result,
+                     const QString &fileName);
 
 public slots:
     void start(const Query &query);
     QList<Result> results();
-    bool download(const Result &result, const QString &fileName);
+    void download(const Result &result, const QString &fileName);
     void finished();
     void downloadFinished();
 
@@ -58,6 +72,8 @@ private:
     QNetworkReply *reply;
     QNetworkReply *downloadReply;
     QList<Result> searchResults;
+    Search::Result downloadResult;
+    QString downloadFileName;
 };
 
 #endif // SEARCH_H
index 3c38816..09bc217 100644 (file)
@@ -1,3 +1,4 @@
+#include <stdio.h>
 #include <QtGui>
 
 #include "listview.h"
@@ -5,6 +6,8 @@
 #include "searchresultinfodialog.h"
 #include "trace.h"
 #include "progressdialog.h"
+#include "library.h"
+#include "platform.h"
 
 SearchResultsDialog::SearchResultsDialog(const QList<Search::Result> results_,
     QWidget *parent): ListWindow(parent), results(results_)
@@ -30,7 +33,10 @@ SearchResultsDialog::SearchResultsDialog(const QList<Search::Result> results_,
             this, SLOT(onItemActivated(const QModelIndex &)));
     Search *search = Search::instance();
     connect(search, SIGNAL(beginDownload(int)), this, SLOT(onBeginDownload(int)));
-    connect(search, SIGNAL(endDownload()), this, SLOT(onEndDownload()));
+    connect(search,
+            SIGNAL(endDownload(int, const Search::Result &, const QString &)),
+            this,
+            SLOT(onEndDownload(int, const Search::Result &, const QString &)));
 
     progress = new ProgressDialog(tr("Downloading Book"), this);
 }
@@ -58,12 +64,24 @@ void SearchResultsDialog::onDownload()
 
 QString SearchResultsDialog::downloadName() const
 {
-    // FIXME
-    return QString("/tmp/book.epub");
+    Trace t("SearchResultsDialog::downloadName");
+    QString dir = Platform::downloadDir();
+    QDir().mkpath(dir); // Not sure if this works. QDir API is quiet lame.
+    unsigned i = 0;
+    QString fileName;
+    do {
+        char tmp[9];
+        snprintf(tmp, 8, "%8.8x", i++);
+        tmp[8] = '\0';
+        fileName = QDir(dir).absoluteFilePath(QString(tmp) + ".epub");
+    } while (QFile(fileName).exists());
+    qDebug() << fileName;
+    return fileName;
 }
 
 void SearchResultsDialog::onBeginDownload(int size)
 {
+    Q_UNUSED(size);
     Trace t("SearchResultsDialog::onBeginDownload");
     progress->setMinimum(0);
     progress->setMaximum(0);
@@ -71,8 +89,17 @@ void SearchResultsDialog::onBeginDownload(int size)
     progress->show();
 }
 
-void SearchResultsDialog::onEndDownload()
+void SearchResultsDialog::onEndDownload(int status, const Search::Result &result,
+                                        const QString &fileName)
 {
+    Q_UNUSED(result);
     Trace t("SearchResultsDialog::onEndDownload");
     progress->reset();
+    if (Search::Ok == status) {
+        Library::instance()->add(fileName);
+        int row = results.indexOf(result);
+        if (-1 != row) {
+            list->model()->removeRow(row);
+        }
+    }
 }
index 6abc9ad..bf8a389 100644 (file)
@@ -23,7 +23,8 @@ protected slots:
     void onDownload();
     void onItemActivated(const QModelIndex &index);
     void onBeginDownload(int size);
-    void onEndDownload();
+    void onEndDownload(int status, const Search::Result &result,
+                       const QString &fileName);
 
 protected:
     QString downloadName() const;