From: lvaatamoinen Date: Fri, 20 Nov 2009 14:15:53 +0000 (+0000) Subject: - Search plugin parses opensearch.xml files and adds them to combobox X-Git-Url: https://vcs.maemo.org/git/?p=qtrapids;a=commitdiff_plain;h=a988ddfbc3be7773bccd4017a70fcd8ce990d8c7 - Search plugin parses opensearch.xml files and adds them to combobox - 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 --- diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 884ced0..9a6770c 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -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(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(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(); } } } diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index 4094a50..6f104d2 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -79,7 +79,7 @@ class MainWindow : public QMainWindow, public qtrapids::PluginHostInterface { SeedView *seedView_; PreferencesDialog *preferencesDialog_; QSettings settings_; - QDir pluginsDir_; + QList pluginDirs_; QStringList pluginFileNames_; //std::vector< std::auto_ptr const > torrentHandles_; diff --git a/src/plugins/PluginInterface.h b/src/plugins/PluginInterface.h index d5ed6c8..a5ea554 100644 --- a/src/plugins/PluginInterface.h +++ b/src/plugins/PluginInterface.h @@ -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; }; diff --git a/src/plugins/searchplugin/SearchPlugin.cpp b/src/plugins/searchplugin/SearchPlugin.cpp index 4440063..add01e0 100644 --- a/src/plugins/searchplugin/SearchPlugin.cpp +++ b/src/plugins/searchplugin/SearchPlugin.cpp @@ -26,15 +26,22 @@ #include #include #include +#include #include #include #include +#include #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 and 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) diff --git a/src/plugins/searchplugin/SearchPlugin.h b/src/plugins/searchplugin/SearchPlugin.h index 0b6a158..1b16330 100644 --- a/src/plugins/searchplugin/SearchPlugin.h +++ b/src/plugins/searchplugin/SearchPlugin.h @@ -20,7 +20,7 @@ #ifndef SEARCHPLUGIN_H #define SEARCHPLUGIN_H - +#include #include #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 engineTemplates_; // Holds the search URL templates }; } // namespace qtrapids diff --git a/src/plugins/searchplugin/searchplugin.pro b/src/plugins/searchplugin/searchplugin.pro index fea3cbe..06f85a1 100644 --- a/src/plugins/searchplugin/searchplugin.pro +++ b/src/plugins/searchplugin/searchplugin.pro @@ -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