- License texts modified to GPLv2
[qtrapids] / src / plugins / searchplugin / SearchPlugin.cpp
index 8c6aac4..7c28980 100644 (file)
@@ -1,11 +1,9 @@
 /***************************************************************************
- *   Copyright (C) 2009 by Lassi Väätämöinen   *
- *   lassi.vaatamoinen@ixonos.com   *
+ *   Copyright (C) 2010 by Ixonos Plc   *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
+ *   the Free Software Foundation; version 2 of the License.               *
  *                                                                         *
  *   This program is distributed in the hope that it will be useful,       *
  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 #include <QLineEdit>
 #include <QPushButton>
 #include <QUrl>
+#include <QDir>
+#include <QFileInfo>
 #include <QWebView>
-
+#include <QWebPage>
+#include <QNetworkReply>
+#include <QDomDocument>
 
 #include "SearchPlugin.h"
+#include "DownloadManager.h"
 
 namespace qtrapids
 {
-<<<<<<< .mine
-SearchPlugin::SearchPlugin() :
-               comboBox_(NULL), searchLine_(NULL), searchButton_(NULL), host_(NULL)
-{
-       // TODO: Parse engine descriptions.
-       // -Add engines to model
-       // -Show model in comboBox
-
-}
-
-void SearchPlugin::initialize(PluginHostInterface* host)
-{
-       host_ = host;
-
-       if (host_ != NULL) {
-
-               QWidget *pluginWidget = new QWidget;
-               QVBoxLayout *vbox = new QVBoxLayout;
-               QHBoxLayout *hbox = new QHBoxLayout;
-               comboBox_ = new QComboBox;
-               searchLine_ = new QLineEdit;
-               searchButton_ = new QPushButton("Search");
-
-               hbox->addWidget(searchLine_);
-               hbox->addWidget(searchButton_);
-               vbox->addWidget(comboBox_);
-               vbox->addLayout(hbox);
-               pluginWidget->setLayout(vbox);
-
-               connect(searchButton_, SIGNAL(clicked()), this, SLOT(on_searchButton_clicked()));
-               //connect(this, SIGNAL(searchResult(QWidget*)), this, SLOT(on_searchResult(QWidget*)));
-
-               host_->setGui(this, pluginWidget);
+       const QString ENGINES_DIR = "engines";
+       const QString DESCRIPTION_FILENAME = "opensearch.xml";
+       const QString SEARCH_TERMS_STRING = "{searchTerms}";
+       const QString SEARCHPLUGIN_ID = "SearchPlugin";
+       
+       SearchPlugin::SearchPlugin() : 
+               comboBox_(NULL), searchLine_(NULL),
+               searchButton_(NULL), result_(NULL), 
+               dlManager_(NULL), host_(NULL)
+       {
+               // TODO: Add back/forward/refresh -buttons to widget to allow some browsing functionality
        }
-}
-
-QWidget* SearchPlugin::getGui()
-{
-       return NULL;
-}
-
-void SearchPlugin::on_searchButton_clicked()
-{
-       QUrl searchUrl(QString("http://www.google.fi/search?q="
-                              + searchLine_->text()));
-       qDebug() << searchUrl;
-       QWebView *result = new QWebView;
-       result->load(searchUrl);
-
-       on_searchResult((QWidget*)result);
-}
-
-void SearchPlugin::on_searchResult(QWidget* resultWidget)
-{
-       qDebug() << "on_searchResult()";
-       if (host_) {
-               host_->addPluginWidget(this, resultWidget);
+       
+       
+       void SearchPlugin::initialize(PluginHostInterface* host, Info info)
+       {
+               host_ = host;
+               
+               if (host_ != NULL) {
+               
+                       // Build up the plugin widget:
+                       QWidget *pluginWidget = new QWidget;
+                       QVBoxLayout *vbox = new QVBoxLayout;
+                       QHBoxLayout *hbox = new QHBoxLayout;
+                       comboBox_ = new QComboBox;
+                       searchLine_ = new QLineEdit;
+                       searchButton_ = new QPushButton("Search");
+                       
+                       hbox->addWidget(searchLine_);
+                       hbox->addWidget(searchButton_);
+                       vbox->addWidget(comboBox_);
+                       vbox->addLayout(hbox);
+                       pluginWidget->setLayout(vbox);
+       
+                       connect(searchButton_, SIGNAL(clicked()), this, SLOT(on_searchButton_clicked()));
+                       //connect(this, SIGNAL(searchResult(QWidget*)), this, SLOT(on_searchResult(QWidget*)));
+                       qDebug() << info.directory;
+                       QDir dir(info.directory);
+                       if (dir.cd(ENGINES_DIR)) {
+                               ParseSearchEngineDescriptions(dir);
+                       }
+                       
+                       host_->setGui(pluginWidget, qtrapids::PluginHostInterface::BASE_WIDGET, this);
+               }
+       }
+       
+       QWidget* SearchPlugin::getGui()
+       {
+               return NULL;
+       }
+       
+       QString SearchPlugin::identifier()
+       {
+               return SEARCHPLUGIN_ID;
        }
-}
-=======
-    SearchPlugin::SearchPlugin() :
-                   comboBox_(NULL), searchLine_(NULL), searchButton_(NULL), host_(NULL)
-{
-       // TODO: Parse engine descriptions.
-       // -Add engines to model
-       // -Show model in comboBox
-       >>>>>>> .r31
-
-}
-
-void SearchPlugin::initialize(PluginHostInterface* host)
-{
-       host_ = host;
-
-       if (host_ != NULL) {
-
-               QWidget *pluginWidget = new QWidget;
-               QVBoxLayout *vbox = new QVBoxLayout;
-               QHBoxLayout *hbox = new QHBoxLayout;
-               comboBox_ = new QComboBox;
-               searchLine_ = new QLineEdit;
-               searchButton_ = new QPushButton("Search");
-
-               hbox->addWidget(searchLine_);
-               hbox->addWidget(searchButton_);
-               vbox->addWidget(comboBox_);
-               vbox->addLayout(hbox);
-               pluginWidget->setLayout(vbox);
 
-               connect(searchButton_, SIGNAL(clicked()), this, SLOT(on_searchButton_clicked()));
-               //connect(this, SIGNAL(searchResult(QWidget*)), this, SLOT(on_searchResult(QWidget*)));
 
-               host_->setGui(pluginWidget);
+       void SearchPlugin::on_searchButton_clicked()
+       {
+               int i = comboBox_->currentIndex();
+               QString tmp = engineTemplates_.at(i);
+               
+               i = tmp.indexOf(SEARCH_TERMS_STRING);
+               tmp.replace(i, SEARCH_TERMS_STRING.length(), searchLine_->text());
+               
+               QUrl searchUrl(tmp);
+               qDebug() << searchUrl;
+               result_ = new QWebView;
+               
+               // Get underlying QWebPage and change link delegation, so we can meddle with links in on_linkClicked().
+               QWebPage *resultPage = result_->page();
+               resultPage->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks);
+               
+               // Get the network access manager for examining HTTP replies.
+               QNetworkAccessManager *netwAccessManager_ = resultPage->networkAccessManager();
+               
+               connect(resultPage, SIGNAL(linkClicked(const QUrl&)), this, SLOT(on_linkClicked(const QUrl&)));
+               connect(result_, SIGNAL(loadFinished(bool)), this, SLOT(on_loadFinished(bool)));
+               connect(netwAccessManager_, SIGNAL(finished(QNetworkReply*)), this, SLOT(on_networkReplyFinished(QNetworkReply*)));
+               
+               result_->load(searchUrl);
+               
+               on_searchResult((QWidget*)result_);
+       }
+       
+       
+       void SearchPlugin::on_loadFinished(bool ok)
+       {
+#ifdef QTRAPIDS_DEBUG
+               if (ok) {
+                       qDebug() << "on_loadFinished(): success";
+               }
+#endif
+       }
+       
+       
+       void SearchPlugin::on_networkReplyFinished(QNetworkReply* reply)
+       {
+               
+               qDebug() << "on_networkReplyFinished()";
+               QString contentType = reply->header(QNetworkRequest::ContentTypeHeader).toString();
+               QString filename;
+               QByteArray replyData;
+               QUrl url = reply->url();
+               
+               qDebug() << "on_networkReplyFinished():" << url;
+               
+               // If content type is torrent data, read reply data:
+               if (contentType == "application/x-bittorrent") {
+                       
+                       // If HTTP-response has Content-Disposition: -header, then we must use that as filename.
+                       if (reply->hasRawHeader("Content-Disposition")) { // NOTE this code block taken from kwebpage.cpp
+                               const QString value = QLatin1String(reply->rawHeader("Content-Disposition"));
+                               const int pos = value.indexOf(QLatin1String("filename="));
+                               if (pos != -1) {
+                                       QString name = value.mid(pos + 9);
+                                       if (name.startsWith(QLatin1Char('"')) && name.endsWith(QLatin1Char('"')))
+                                               name = name.mid(1, name.size() - 2);
+                                       filename = name;
+                               }
+                       // No content-disposition header, use last part (the filename) of URL as filename:
+                       } else {
+                               QString path = url.path();
+                               QFileInfo fInfo(path);
+                               filename = fInfo.fileName();
+                       }
+                       
+                       // Destroy ongoing download, if any.
+                       if (dlManager_) {
+                               delete dlManager_;
+                               dlManager_ = NULL;
+                       }
+               
+                       /// @todo Is this a bit of a hack now; we get the reply and check Content-Type,
+                       /// The download is then started afterwards, so we get unecessarily one extra
+                       /// HTTP-response here.  
+                       /// @todo Could this whole content-type checking be logically moved to DownloadManager?
+                       // Start downloading Torrent file.
+                       dlManager_ = new DownloadManager(url, "/tmp/" + filename);
+                       connect(dlManager_, SIGNAL(finished(QString)), this, SLOT(on_downloadFinished(QString)));
+                       dlManager_->start();
+                       
+               }
+       }
+       
+       
+       void SearchPlugin::on_searchResult(QWidget* resultWidget)
+       {
+#ifdef QTRAPIDS_DEBUG
+               qDebug() << "on_searchResult()";
+#endif
+               if (host_) {
+                       host_->addPluginWidget(resultWidget, qtrapids::PluginHostInterface::TAB_PAGE);
+               }
        }
-}
 
-QWidget* SearchPlugin::getGui()
-{
-       return NULL;
-}
 
-void SearchPlugin::on_searchButton_clicked()
-{
-       QUrl searchUrl(QString("http://www.google.fi/search?q="
-                              + searchLine_->text()));
-       qDebug() << searchUrl;
-       QWebView *result = new QWebView;
-       result->load(searchUrl);
+       /// @todo It may be that we don't actually need link delegation, because we check response Content-Type header
+       /// on_linkClicked() in that case unnecessary function
+       void SearchPlugin::on_linkClicked(const QUrl& url)
+       {
+               qDebug() << "on_linkClicked():" << url;
+               
+               if (url.isValid()) {
+                       result_->load(url);
+               }
+       }
+       
+       
+       void SearchPlugin::on_downloadFinished(QString filepath)
+       {
+#ifdef QTRAPIDS_DEBUG
+               qDebug() << "TORRENT DOWNLOADED: " << filepath;
+#endif
+               delete dlManager_;
+               dlManager_ = NULL;
+               if (host_) {
+                       host_->eventRequest(QVariant(filepath), qtrapids::PluginHostInterface::OPEN_FILE);
+               }
+       }
 
-       on_searchResult((QWidget*)result);
-}
 
-void SearchPlugin::on_searchResult(QWidget* resultWidget)
-{
-       qDebug() << "on_searchResult()";
-       if (host_) {
-               host_->addPluginWidget(resultWidget);
+       void SearchPlugin::ParseSearchEngineDescriptions(const QDir& dir)
+       {
+               foreach (QString dirName, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
+               
+                       QFile file(dir.path() + "/" + dirName + "/" + DESCRIPTION_FILENAME);
+                       
+                       if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+                               qWarning() << "Unable to open " << DESCRIPTION_FILENAME << " for reading in " << dir.path();
+                               continue;
+                       }
+                       
+                       // Parse the XML file to DOM document.
+                       QDomDocument document;
+                       
+                       // Second parameter: nameSpaceProcessing = false
+                       if (!document.setContent(&file, false)) {
+                               qWarning() << "Unable to parse " << DESCRIPTION_FILENAME << " in " << dirName;
+                       } else {
+                               QDomNodeList urlElements = document.elementsByTagName("Url");
+                               QDomNodeList shortNameElements = document.elementsByTagName("ShortName");
+                               
+                               QDomNode n = urlElements.item(0);
+                               QDomNode m;
+                               QDomNamedNodeMap attribMap;
+                               if (n.hasAttributes()) {
+                                       attribMap = n.attributes();
+                                       m = attribMap.namedItem("template");
+                                       engineTemplates_.push_back(m.nodeValue());
+                               }
+                               
+                               n = shortNameElements.item(0);
+                               if (n.hasChildNodes()) {
+                                       m = n.firstChild();
+                                       comboBox_->addItem(m.nodeValue());
+                               }
+                       }
+               }
+               /// @todo save parsed xml elements <Shortname> and <Url template="<foo>"> to a model which is displayed in combobox.
        }
-}
 
 } // namespace qtrapids