"\nDenis Zalevskiy, denis.zalewsky@ixonos.com"
"\n\nIxonos Plc, Finland\n"));
+const QString PLUGINS_DIR = "plugins";
+
// Consturctor
MainWindow::MainWindow():
QMainWindow(), // Superclass
seedView_(NULL),
preferencesDialog_(NULL),
settings_(),
+ pluginDirs_(),
// torrentHandles_(),
btSession_()
{
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();
}
}
}
SeedView *seedView_;
PreferencesDialog *preferencesDialog_;
QSettings settings_;
- QDir pluginsDir_;
+ QList<QDir> pluginDirs_;
QStringList pluginFileNames_;
//std::vector< std::auto_ptr<QTorrentHandle> const > torrentHandles_;
* 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
* 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;
};
#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),
}
- 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;
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);
}
{
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;
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
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()) {
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)
#ifndef SEARCHPLUGIN_H
#define SEARCHPLUGIN_H
-
+#include <vector>
#include <QObject>
#include "PluginInterface.h"
class QLineEdit;
class QWebView;
class DownloadManager;
+class QDir;
namespace qtrapids
{
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
######################################################################
# Automatically generated by qmake (2.01a) Tue Nov 17 15:43:08 2009
######################################################################
-QT += webkit network
+QT += webkit network xml
TEMPLATE = lib