- Search plugin parses opensearch.xml files and adds them to combobox
authorlvaatamoinen <lassi.vaatamoinen@ixonos.com>
Fri, 20 Nov 2009 14:15:53 +0000 (14:15 +0000)
committerlvaatamoinen <lassi.vaatamoinen@ixonos.com>
Fri, 20 Nov 2009 14:15:53 +0000 (14:15 +0000)
- Searching works
- TODO: check for MIME x-application/torrent in HTTP responses, because relying on .torrent -extension on link is very hacky

git-svn-id: file:///svnroot/qtrapids/trunk@45 42ac0dd5-4c8c-4c71-bb3e-ecdfe252ffda

src/gui/MainWindow.cpp
src/gui/MainWindow.h
src/plugins/PluginInterface.h
src/plugins/searchplugin/SearchPlugin.cpp
src/plugins/searchplugin/SearchPlugin.h
src/plugins/searchplugin/searchplugin.pro

index 884ced0..9a6770c 100644 (file)
@@ -43,6 +43,8 @@ const QString ABOUT_TEXT
                           "\nDenis Zalevskiy, denis.zalewsky@ixonos.com"
                           "\n\nIxonos Plc, Finland\n"));
 
+const QString PLUGINS_DIR = "plugins";
+
 // Consturctor
 MainWindow::MainWindow():
                QMainWindow(), // Superclass
@@ -51,6 +53,7 @@ MainWindow::MainWindow():
                seedView_(NULL),
                preferencesDialog_(NULL),
                settings_(),
+               pluginDirs_(),
 //     torrentHandles_(),
                btSession_()
 {
@@ -191,38 +194,60 @@ bool MainWindow::eventRequest(QVariant param, PluginRequest req)
 
 void MainWindow::LoadPlugins()
 {
-       /// @todo get plugin directory from settings or go through multiple directories
-       /// Now we only check the application directory
-       pluginsDir_ = QDir(qApp->applicationDirPath());
-       pluginsDir_.cd("plugins");
-       QStringList nameFilters;
-       nameFilters << "*.so";
-
-       foreach (QString fileName, pluginsDir_.entryList(nameFilters, QDir::Files)) {
-               QPluginLoader pluginLoader(pluginsDir_.absoluteFilePath(fileName));
-
-               if (!QLibrary::isLibrary(fileName)) {
-                       qDebug() << fileName << " not a library";
-               }
-
-               if (pluginLoader.load()) {
-                       qDebug() << "Plugin loaded: "  << fileName;
-               } else {
-                       qDebug() << "Plugin load failed: " << pluginLoader.errorString();
-               }
-
-               QObject *baseInstance = pluginLoader.instance();
-               if (!baseInstance) {
-                       qDebug() << "Base instance = NULL.";
-               }
-
-               qtrapids::PluginInterface *plugin = qobject_cast<qtrapids::PluginInterface*>(baseInstance);
-
-               if (!plugin) {
-                       qDebug() << "Cast failed.";
+       // Get plugin directories from 
+       QStringList pluginDirsTmp = settings_.value("plugins/path").toStringList();
+       QStringList nameFilters("*.so");
+       
+       /// @todo enable "application directory" for plugin search in development/debug mode only. In release version
+       /// search plugins directory under $HOME/.qtrapids or system library paths
+       pluginDirsTmp << qApp->applicationDirPath();
+       pluginDirsTmp.removeDuplicates();
+       
+       foreach (QString dir, pluginDirsTmp) {
+               pluginDirs_.append(QDir(dir));
+       }
+       
+       foreach (QDir dir, pluginDirs_) {
+               
+               if (dir.cd(PLUGINS_DIR)) {
+                       
+                       foreach (QString fileName, dir.entryList(nameFilters, QDir::Files)) {
+                               QPluginLoader pluginLoader(dir.absoluteFilePath(fileName));
+
+                               // If plugin not loaded from another directory, then load
+                               if (!pluginFileNames_.contains(fileName) && QLibrary::isLibrary(fileName)) {
+
+                                       if (pluginLoader.load()) {
+                                               qDebug() << "Plugin loaded: "  << fileName;
+                                       } else {
+                                               qWarning() << "Plugin load failed: " << pluginLoader.errorString();
+                                       }
+
+                                       QObject *baseInstance = pluginLoader.instance();
+                                       if (!baseInstance) {
+                                               qDebug() << "Base instance = NULL.";
+                                       }
+
+                                       qtrapids::PluginInterface *plugin = qobject_cast<qtrapids::PluginInterface*>(baseInstance);
+
+                                       if (!plugin) {
+                                               qDebug() << "Cast failed.";
+                                       } else {
+                                               qtrapids::PluginInterface::Info info;
+                                               info.directory = dir.path();
+                                               qDebug() << dir.path();
+                                               plugin->initialize(this, info);
+                                               pluginFileNames_ += fileName;
+                                       }
+                               } else {
+                                       qWarning() << "Plugin " 
+                                               << fileName 
+                                               << " already loaded from another directory, or not a valid library file";
+                               }
+                       }
+                       
                } else {
-                       plugin->initialize(this);
-                       pluginFileNames_ += fileName;
+                       qWarning() << PLUGINS_DIR <<  "directory not accessible or does not exist in "  << dir.path();
                }
        }
 }
index 4094a50..6f104d2 100644 (file)
@@ -79,7 +79,7 @@ class MainWindow : public QMainWindow, public qtrapids::PluginHostInterface {
                SeedView *seedView_;
                PreferencesDialog *preferencesDialog_;
                QSettings settings_;
-               QDir pluginsDir_;
+               QList<QDir> pluginDirs_;
                QStringList pluginFileNames_;
                //std::vector< std::auto_ptr<QTorrentHandle> const > torrentHandles_;
                
index d5ed6c8..a5ea554 100644 (file)
@@ -37,8 +37,11 @@ namespace qtrapids
                * that implement the additional functionality
                * @note Implementing plugin host should inherit QObject.
        */
-       class PluginHostInterface {
+       class PluginHostInterface 
+       {
                public:
+                       
+                       
                        /// @enum PluginWidgetType Allows plugin host to differentiate actions 
                        /// when passed as parameter to addWidget(). E.g. Popup a dialog or append tab etc.
                        /// @todo add new types
@@ -85,10 +88,20 @@ namespace qtrapids
                * The host application uses PluginInterface interface for calling the plugins
                * that extend the Host functionality
        */
-       class PluginInterface : public QObject {
+       class PluginInterface : public QObject 
+       {
                public:
+                       
+                       /// @struct Info Used to supply information from the host application to the plugin 
+                       /// for initialization.
+                       struct Info {
+                               Info() : directory("") {} //Constructor
+                               QString directory; ///< directory from which the plugin is loaded
+                               // ...
+                       };
+                       
                        /// @brief Initializes the plugin instance.
-                       virtual void initialize(PluginHostInterface* host) = 0;
+                       virtual void initialize(PluginHostInterface* host, Info info = Info()) = 0;
                        virtual QWidget* getGui() = 0;
        };
 
index 4440063..add01e0 100644 (file)
 #include <QLineEdit>
 #include <QPushButton>
 #include <QUrl>
+#include <QDir>
 #include <QFileInfo>
 #include <QWebView>
 #include <QWebPage>
+#include <QDomDocument>
 
 #include "SearchPlugin.h"
 #include "DownloadManager.h"
 
 namespace qtrapids
 {
+       const QString ENGINES_DIR = "engines";
+       const QString DESCRIPTION_FILENAME = "opensearch.xml";
+       const QString SEARCH_TERMS_STRING = "{searchTerms}";
+       
+       
        SearchPlugin::SearchPlugin() : 
                comboBox_(NULL), searchLine_(NULL),
                searchButton_(NULL), result_(NULL), 
@@ -47,11 +54,13 @@ namespace qtrapids
        
        }
        
-       void SearchPlugin::initialize(PluginHostInterface* host)
+       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;
@@ -67,6 +76,11 @@ namespace qtrapids
        
                        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);
                }
@@ -76,12 +90,16 @@ namespace qtrapids
        {
                return NULL;
        }
-       
-       
+
+
        void SearchPlugin::on_searchButton_clicked()
        {
-               QUrl searchUrl(QString("http://www.google.fi/search?q="
-                       + searchLine_->text()));
+               
+               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;
                
@@ -125,7 +143,11 @@ namespace qtrapids
                QFileInfo fInfo(path);
                
                // Check path suffix. If it is .torrent, we should download:
-               /// @todo We should also check MIME-type, instead of relying on file suffix.
+               /// @todo We should actually check for MIME-type application/x-bittorrent in HTTP response, 
+               /// instead of relying on file suffix.
+               /// e.g. link 
+               ///http://www.bitenova.org/download.php?id=c84375141231eef49fc6c55e6347ba4f4a623a05&name=Nero_Linux_3.5.1.0__(Debian)_deutsch
+               /// will not work.
                /// @todo Also, after downloading, the torrent bencoding validity should be checked at plugin host..
                if (fInfo.suffix() == "torrent") {
 #ifdef QTRAPIDS_DEBUG
@@ -143,6 +165,7 @@ namespace qtrapids
                        dlManager_ = new DownloadManager(url, "/tmp/" + filename);
                        connect(dlManager_, SIGNAL(finished(QString)), this, SLOT(on_downloadFinished(QString)));
                        dlManager_->start();
+                       
                } else {
                        // If was not .torrent -file, check URL validity and load the page as usual.
                        if (url.isValid()) {
@@ -161,6 +184,61 @@ namespace qtrapids
                host_->eventRequest(QVariant(filepath), qtrapids::PluginHostInterface::OPEN_FILE);
        }
 
+
+       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.
+               }
+               
+                                               /*
+               QDomElement docElem = document.documentElement();
+               QDomNode n = docElem.firstChild();
+               while(!n.isNull()) {
+                       QDomElement e = n.toElement(); // try to convert the node to an element.
+                       if(!e.isNull()) {
+                               qDebug() << qPrintable(e.tagName()); // the node really is an element.
+                       }
+                       n = n.nextSibling();
+               }
+               */
+
 } // namespace qtrapids
 
 Q_EXPORT_PLUGIN2(searchplugin, qtrapids::SearchPlugin)
index 0b6a158..1b16330 100644 (file)
@@ -20,7 +20,7 @@
 #ifndef SEARCHPLUGIN_H
 #define SEARCHPLUGIN_H
 
-
+#include <vector>
 #include <QObject>
 
 #include "PluginInterface.h"
@@ -31,6 +31,7 @@ class QPushButton;
 class QLineEdit;
 class QWebView;
 class DownloadManager;
+class QDir;
 
 namespace qtrapids
 {
@@ -40,28 +41,35 @@ class SearchPlugin : public PluginInterface
        Q_OBJECT
        Q_INTERFACES(qtrapids::PluginInterface)
 
-public:
-       SearchPlugin();
-       virtual void initialize(PluginHostInterface* host);
-       virtual QWidget* getGui();
-
-signals:
-       void searchResult(QWidget* resultwidget);
+       public:
+               SearchPlugin();
+               
+               /// @brief Initializes the SearchPlugin
+               /// @param info info.directory is used to search for searchengine description files. 
+               virtual void initialize(PluginHostInterface* host, Info info);
+               virtual QWidget* getGui();
 
-private slots:
-       void on_searchButton_clicked();
-       void on_searchResult(QWidget* resultWidget);
-       void on_loadFinished(bool ok);
-       void on_linkClicked(const QUrl& url);
-       void on_downloadFinished(QString filepath);
-private:
-       QComboBox *comboBox_;
-       QLineEdit *searchLine_;
-       QPushButton *searchButton_;
-       QWebView *result_; // Do not delete, plugin host takes ownership
-       DownloadManager *dlManager_;
-       PluginHostInterface* host_;
+       signals:
+               void searchResult(QWidget* resultwidget);
 
+       private slots:
+               void on_searchButton_clicked();
+               void on_searchResult(QWidget* resultWidget);
+               void on_loadFinished(bool ok);
+               void on_linkClicked(const QUrl& url);
+               void on_downloadFinished(QString filepath);
+               
+       private:
+               void ParseSearchEngineDescriptions(const QDir& dir);
+                       
+       private:
+               QComboBox *comboBox_; // Holds the search engine names. Combobox index maps to engineTemplates_ index
+               QLineEdit *searchLine_;
+               QPushButton *searchButton_;
+               QWebView *result_; // Do not delete, plugin host takes ownership
+               DownloadManager *dlManager_;
+               PluginHostInterface* host_;
+               std::vector<QString> engineTemplates_; // Holds the search URL templates
 };
 
 } // namespace qtrapids
index fea3cbe..06f85a1 100644 (file)
@@ -1,7 +1,7 @@
 ######################################################################
 # Automatically generated by qmake (2.01a) Tue Nov 17 15:43:08 2009
 ######################################################################
-QT += webkit network
+QT += webkit network xml
 
 TEMPLATE = lib