- Search plugin parses opensearch.xml files and adds them to combobox
[qtrapids] / src / plugins / searchplugin / SearchPlugin.cpp
1 /***************************************************************************
2  *   Copyright (C) 2009 by Lassi Väätämöinen   *
3  *   lassi.vaatamoinen@ixonos.com   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #include <QDebug>
22 #include <QtCore/qplugin.h>
23 #include <QVBoxLayout>
24 #include <QHBoxLayout>
25 #include <QComboBox>
26 #include <QLineEdit>
27 #include <QPushButton>
28 #include <QUrl>
29 #include <QDir>
30 #include <QFileInfo>
31 #include <QWebView>
32 #include <QWebPage>
33 #include <QDomDocument>
34
35 #include "SearchPlugin.h"
36 #include "DownloadManager.h"
37
38 namespace qtrapids
39 {
40         const QString ENGINES_DIR = "engines";
41         const QString DESCRIPTION_FILENAME = "opensearch.xml";
42         const QString SEARCH_TERMS_STRING = "{searchTerms}";
43         
44         
45         SearchPlugin::SearchPlugin() : 
46                 comboBox_(NULL), searchLine_(NULL),
47                 searchButton_(NULL), result_(NULL), 
48                 dlManager_(NULL), host_(NULL)
49         {
50                 // TODO: Parse search engine XML(?) descriptions.
51                 // -Add search engines to model
52                 // -Show model in comboBox
53                 // Add back/forward/refresh -buttons to widget to allow some browsing
54         
55         }
56         
57         void SearchPlugin::initialize(PluginHostInterface* host, Info info)
58         {
59                 host_ = host;
60                 
61                 if (host_ != NULL) {
62                 
63                         // Build up the plugin widget:
64                         QWidget *pluginWidget = new QWidget;
65                         QVBoxLayout *vbox = new QVBoxLayout;
66                         QHBoxLayout *hbox = new QHBoxLayout;
67                         comboBox_ = new QComboBox;
68                         searchLine_ = new QLineEdit;
69                         searchButton_ = new QPushButton("Search");
70                         
71                         hbox->addWidget(searchLine_);
72                         hbox->addWidget(searchButton_);
73                         vbox->addWidget(comboBox_);
74                         vbox->addLayout(hbox);
75                         pluginWidget->setLayout(vbox);
76         
77                         connect(searchButton_, SIGNAL(clicked()), this, SLOT(on_searchButton_clicked()));
78                         //connect(this, SIGNAL(searchResult(QWidget*)), this, SLOT(on_searchResult(QWidget*)));
79                         qDebug() << info.directory;
80                         QDir dir(info.directory);
81                         if (dir.cd(ENGINES_DIR)) {
82                                 ParseSearchEngineDescriptions(dir);
83                         }
84                         
85                         host_->setGui(pluginWidget, qtrapids::PluginHostInterface::BASE_WIDGET);
86                 }
87         }
88         
89         QWidget* SearchPlugin::getGui()
90         {
91                 return NULL;
92         }
93
94
95         void SearchPlugin::on_searchButton_clicked()
96         {
97                 
98                 int i = comboBox_->currentIndex();
99                 QString tmp = engineTemplates_.at(i);
100                 i = tmp.indexOf(SEARCH_TERMS_STRING);
101                 tmp.replace(i, SEARCH_TERMS_STRING.length(), searchLine_->text());
102                 QUrl searchUrl(tmp);
103                 qDebug() << searchUrl;
104                 result_ = new QWebView;
105                 
106                 // Get underlying QWebPage and change link delegation, so we can meddle with links in on_linkClicked().
107                 QWebPage *resultPage = result_->page();
108                 resultPage->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks);
109                 
110                 connect(resultPage, SIGNAL(linkClicked(const QUrl&)), this, SLOT(on_linkClicked(const QUrl&)));
111                 connect(result_, SIGNAL(loadFinished(bool)), this, SLOT(on_loadFinished(bool)));
112         
113                 result_->load(searchUrl);
114                 
115                 on_searchResult((QWidget*)result_);
116         }
117         
118         
119         void SearchPlugin::on_loadFinished(bool ok)
120         {
121 #ifdef QTRAPIDS_DEBUG
122                 if (ok) {
123                         qDebug() << "on_loadFinished(): success";
124                 }
125 #endif
126         }
127         
128         
129         void SearchPlugin::on_searchResult(QWidget* resultWidget)
130         {
131 #ifdef QTRAPIDS_DEBUG
132                 qDebug() << "on_searchResult()";
133 #endif
134                 if (host_) {
135                         host_->addPluginWidget(resultWidget, qtrapids::PluginHostInterface::TAB_PAGE);
136                 }
137         }
138
139         void SearchPlugin::on_linkClicked(const QUrl& url)
140         {
141                 // Get the path part of URL (the part after the host part) 
142                 QString path = url.path();
143                 QFileInfo fInfo(path);
144                 
145                 // Check path suffix. If it is .torrent, we should download:
146                 /// @todo We should actually check for MIME-type application/x-bittorrent in HTTP response, 
147                 /// instead of relying on file suffix.
148                 /// e.g. link 
149                 ///http://www.bitenova.org/download.php?id=c84375141231eef49fc6c55e6347ba4f4a623a05&name=Nero_Linux_3.5.1.0__(Debian)_deutsch
150                 /// will not work.
151                 /// @todo Also, after downloading, the torrent bencoding validity should be checked at plugin host..
152                 if (fInfo.suffix() == "torrent") {
153 #ifdef QTRAPIDS_DEBUG
154                         qDebug() << "IS TORRENT";
155 #endif
156                         QString filename = fInfo.fileName();
157                         
158                         // Destroy ongoing download, if any.
159                         if (dlManager_) {
160                                 delete dlManager_;
161                                 dlManager_ = NULL;
162                         }
163                         
164                         // Start downloading Torrent file.
165                         dlManager_ = new DownloadManager(url, "/tmp/" + filename);
166                         connect(dlManager_, SIGNAL(finished(QString)), this, SLOT(on_downloadFinished(QString)));
167                         dlManager_->start();
168                         
169                 } else {
170                         // If was not .torrent -file, check URL validity and load the page as usual.
171                         if (url.isValid()) {
172                                 result_->load(url);
173                         }
174                 }
175         }
176         
177         void SearchPlugin::on_downloadFinished(QString filepath)
178         {
179 #ifdef QTRAPIDS_DEBUG
180                 qDebug() << "TORRENT DOWNLOADED: " << filepath;
181 #endif
182                 delete dlManager_;
183                 dlManager_ = NULL;
184                 host_->eventRequest(QVariant(filepath), qtrapids::PluginHostInterface::OPEN_FILE);
185         }
186
187
188         void SearchPlugin::ParseSearchEngineDescriptions(const QDir& dir)
189         {
190                 foreach (QString dirName, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
191                 
192                                 QFile file(dir.path() + "/" + dirName + "/" + DESCRIPTION_FILENAME);
193                                 
194                                 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
195                                         qWarning() << "Unable to open " << DESCRIPTION_FILENAME << " for reading in " << dir.path();
196                                         continue;
197                                 }
198                                 
199                                 // Parse the XML file to DOM document.
200                                 QDomDocument document;
201                                 
202                                 // Second parameter: nameSpaceProcessing = false
203                                 if (!document.setContent(&file, false)) {
204                                         qWarning() << "Unable to parse " << DESCRIPTION_FILENAME << " in " << dirName;
205                                 } else {
206                                         QDomNodeList urlElements = document.elementsByTagName("Url");
207                                         QDomNodeList shortNameElements = document.elementsByTagName("ShortName");
208                                         
209                                         QDomNode n = urlElements.item(0);
210                                         QDomNode m;
211                                         QDomNamedNodeMap attribMap;
212                                         if (n.hasAttributes()) {
213                                                 attribMap = n.attributes();
214                                                 m = attribMap.namedItem("template");
215                                                 engineTemplates_.push_back(m.nodeValue());
216                                         }
217                                         
218                                         n = shortNameElements.item(0);
219                                         if (n.hasChildNodes()) {
220                                                 m = n.firstChild();
221                                                 comboBox_->addItem(m.nodeValue());
222                                         }
223                                 }
224                         }
225                         
226                         
227                         /// @todo save parsed xml elements <Shortname> and <Url template="<foo>"> to a model which is displayed in combobox.
228                 }
229                 
230                                                 /*
231                 QDomElement docElem = document.documentElement();
232                 QDomNode n = docElem.firstChild();
233                 while(!n.isNull()) {
234                         QDomElement e = n.toElement(); // try to convert the node to an element.
235                         if(!e.isNull()) {
236                                 qDebug() << qPrintable(e.tagName()); // the node really is an element.
237                         }
238                         n = n.nextSibling();
239                 }
240                 */
241
242 } // namespace qtrapids
243
244 Q_EXPORT_PLUGIN2(searchplugin, qtrapids::SearchPlugin)