[tor-commits] [vidalia/alpha] Plugin framework: initial commit
chiiph at torproject.org
chiiph at torproject.org
Sat Jul 2 21:53:46 UTC 2011
commit 92f39c6d275d07b9a49fc1a412c6482551190831
Author: Tomas Touceda <chiiph at torproject.org>
Date: Wed Jun 1 17:02:07 2011 -0300
Plugin framework: initial commit
It introduces the basic structure of the plugin management, not the actual
API. There's some refactoring to do, but the basic layout is working.
---
CMakeLists.txt | 2 +-
src/vidalia/CMakeLists.txt | 13 ++
src/vidalia/MainWindow.cpp | 24 +++-
src/vidalia/MainWindow.h | 7 +
src/vidalia/config/VidaliaSettings.cpp | 13 ++
src/vidalia/config/VidaliaSettings.h | 5 +
src/vidalia/plugin/PluginEngine.cpp | 64 ++++++++
src/vidalia/plugin/PluginEngine.h | 28 ++++
src/vidalia/plugin/PluginWrapper.cpp | 157 ++++++++++++++++++++
src/vidalia/plugin/PluginWrapper.h | 46 ++++++
.../plugin/prototypes/VidaliaTabPrototype.cpp | 10 ++
.../plugin/prototypes/VidaliaTabPrototype.h | 21 +++
12 files changed, 388 insertions(+), 2 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dfd8f3b..0c07d0d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -37,10 +37,10 @@ include(FindQt4)
find_package(Qt4 REQUIRED)
set(QT_USE_QTNETWORK true)
set(QT_USE_QTXML true)
+set(QT_USE_QTSCRIPT true)
if (USE_MARBLE)
set(QT_USE_QTSVG true)
set(QT_USE_QTWEBKIT true)
- set(QT_USE_QTSCRIPT true)
set(QT_USE_QTDBUS true)
endif(USE_MARBLE)
include(${QT_USE_FILE})
diff --git a/src/vidalia/CMakeLists.txt b/src/vidalia/CMakeLists.txt
index 5811320..4cbe458 100644
--- a/src/vidalia/CMakeLists.txt
+++ b/src/vidalia/CMakeLists.txt
@@ -20,6 +20,8 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/help/browser
${CMAKE_CURRENT_SOURCE_DIR}/log
${CMAKE_CURRENT_SOURCE_DIR}/network
+ ${CMAKE_CURRENT_SOURCE_DIR}/plugin
+ ${CMAKE_CURRENT_SOURCE_DIR}/plugin/prototypes
${MARBLE_INCLUDE_DIR}
)
@@ -80,6 +82,17 @@ qt4_wrap_cpp(vidalia_SRCS
bwgraph/BandwidthGraph.h
bwgraph/GraphFrame.h
)
+## Plugin framework sources
+set(vidalia_SRCS ${vidalia_SRCS}
+ plugin/PluginEngine.cpp
+ plugin/PluginWrapper.cpp
+ plugin/prototypes/VidaliaTabPrototype.cpp
+)
+qt4_wrap_cpp(vidalia_SRCS
+ plugin/PluginEngine.h
+ plugin/PluginWrapper.h
+ plugin/prototypes/VidaliaTabPrototype.h
+)
## Configuration dialog sources
set(vidalia_SRCS ${vidalia_SRCS}
diff --git a/src/vidalia/MainWindow.cpp b/src/vidalia/MainWindow.cpp
index 70e8044..931df1c 100644
--- a/src/vidalia/MainWindow.cpp
+++ b/src/vidalia/MainWindow.cpp
@@ -37,6 +37,8 @@
#include "stringutil.h"
#include "procutil.h"
+#include "PluginWrapper.h"
+
#include <QtGui>
#define IMG_BWGRAPH ":/images/16x16/utilities-system-monitor.png"
@@ -100,6 +102,8 @@ MainWindow::MainWindow()
/* Create a new TorControl object, used to communicate with Tor */
_torControl = Vidalia::torControl();
+ _engine = new PluginEngine();
+
createGUI();
createConnections();
@@ -176,7 +180,11 @@ MainWindow::createMenuBar()
viewMenu->addSeparator();
viewMenu->addAction(_actionConfigure);
-// QMenu *pluginsMenu = menu->addMenu(tr("Plugins"));
+ QMenu *pluginsMenu = menu->addMenu(tr("Plugins"));
+ foreach(QAction *action, _engine->getAllActions()) {
+ pluginsMenu->addAction(action);
+ connect(action, SIGNAL(triggered()), this, SLOT(showPluginTab()));
+ }
QMenu *helpMenu = menu->addMenu(tr("Help"));
helpMenu->addAction(_actionVidaliaHelp);
@@ -1539,6 +1547,12 @@ MainWindow::addTab(VidaliaTab *tab)
* instanse passed */
if(_tabMap.contains(tab->getTitle())) {
ui.tabWidget->setCurrentIndex(_tabMap.indexOf(tab->getTitle()));
+
+ /** If we are trying to open the exact same tab twice
+ * don't do anything */
+ if(tab == ui.tabWidget->widget(_tabMap.indexOf(tab->getTitle())))
+ return;
+
/** Exception for tabs that need to be always created */
if (tab != _messageLog &&
tab != &_statusTab &&
@@ -1579,6 +1593,14 @@ MainWindow::delTab(int index)
}
void
+MainWindow::showPluginTab()
+{
+ QAction *act = qobject_cast<QAction *>(sender());
+ PluginWrapper *wrapper = qobject_cast<PluginWrapper *>(act->parent());
+ addTab(wrapper->buildGUI());
+}
+
+void
MainWindow::showStatusTab()
{
addTab(&_statusTab);
diff --git a/src/vidalia/MainWindow.h b/src/vidalia/MainWindow.h
index 7d386d5..e5366b8 100644
--- a/src/vidalia/MainWindow.h
+++ b/src/vidalia/MainWindow.h
@@ -36,6 +36,8 @@
#include "TorControl.h"
+#include "PluginEngine.h"
+
#include <QMainWindow>
#include <QTimer>
#include <QSystemTrayIcon>
@@ -142,6 +144,9 @@ private slots:
/** Deletes the tab at index if it exists and it isn't the Status tab */
void delTab(int index = -1);
+ /** Handles adding a new tab corresponding to a plugin */
+ void showPluginTab();
+
/** Called when the web browser or IM client have stopped */
void onSubprocessFinished(int exitCode, QProcess::ExitStatus exitStatus);
/** Called periodically to check if the browser is running. If it is not,
@@ -304,6 +309,8 @@ private:
NetViewer _netViewer; /**< Network map that draws circuits */
QStringList _tabMap; /**< Map to handle opened tabs */
BandwidthGraph *_graph; /**< Graph that draws bandwidth usage */
+
+ PluginEngine *_engine;
};
#endif
diff --git a/src/vidalia/config/VidaliaSettings.cpp b/src/vidalia/config/VidaliaSettings.cpp
index 0812b03..aa4d18b 100644
--- a/src/vidalia/config/VidaliaSettings.cpp
+++ b/src/vidalia/config/VidaliaSettings.cpp
@@ -39,6 +39,7 @@
#define SETTING_LAST_UPDATE_CHECK "LastUpdateCheck"
#define SETTING_USE_LOCAL_GEOIP_DATABASE "UseLocalGeoIpDatabase"
#define SETTING_LOCAL_GEOIP_DATABASE "LocalGeoIpDatabase"
+#define SETTING_PLUGIN_PATH "PluginPath"
#if defined(Q_OS_WIN32)
#define STARTUP_REG_KEY "Software\\Microsoft\\Windows\\CurrentVersion\\Run"
@@ -82,6 +83,7 @@ VidaliaSettings::VidaliaSettings()
setDefault(SETTING_LAST_UPDATE_CHECK, QDateTime());
setDefault(SETTING_USE_LOCAL_GEOIP_DATABASE, false);
setDefault(SETTING_LOCAL_GEOIP_DATABASE, "");
+ setDefault(SETTING_PLUGIN_PATH, vApp->dataDirectory());
}
/** Gets the currently preferred language code for Vidalia. */
@@ -321,3 +323,14 @@ VidaliaSettings::setLocalGeoIpDatabase(const QString &databaseFile)
setValue(SETTING_LOCAL_GEOIP_DATABASE, databaseFile);
}
+QString
+VidaliaSettings::pluginPath() const
+{
+ return QDir::convertSeparators(value(SETTING_PLUGIN_PATH).toString());
+}
+
+void
+VidaliaSettings::setPluginPath(const QString &path)
+{
+ setValue(SETTING_PLUGIN_PATH, path);
+}
diff --git a/src/vidalia/config/VidaliaSettings.h b/src/vidalia/config/VidaliaSettings.h
index 2667b12..029657f 100644
--- a/src/vidalia/config/VidaliaSettings.h
+++ b/src/vidalia/config/VidaliaSettings.h
@@ -125,6 +125,11 @@ public:
QString localGeoIpDatabase() const;
/** Sets the file to use as a local GeoIP database. */
void setLocalGeoIpDatabase(const QString &databaseFile);
+
+ /** Returns the path where the plugins live */
+ QString pluginPath() const;
+ /** Sets the path where the plugins live */
+ void setPluginPath(const QString &path);
};
#endif
diff --git a/src/vidalia/plugin/PluginEngine.cpp b/src/vidalia/plugin/PluginEngine.cpp
new file mode 100644
index 0000000..fe85883
--- /dev/null
+++ b/src/vidalia/plugin/PluginEngine.cpp
@@ -0,0 +1,64 @@
+#include "PluginEngine.h"
+#include "VidaliaSettings.h"
+#include "PluginWrapper.h"
+
+PluginEngine::PluginEngine(QObject *parent)
+ : QScriptEngine(parent)
+{
+ // load prototypes
+ VidaliaTabPrototype vtabproto;
+ QScriptValue vtabscript = newQObject(&vtabproto, QScriptEngine::ScriptOwnership);
+ setDefaultPrototype(qMetaTypeId<VidaliaTab *>(), vtabscript);
+
+ // load constructors
+ QScriptValue vtabctor = newFunction(VidaliaTabPrototype::constructor, vtabscript);
+ globalObject().setProperty("VidaliaTab", vtabctor);
+
+ loadAllPlugins();
+}
+
+PluginEngine::~PluginEngine() {}
+
+void
+PluginEngine::loadAllPlugins()
+{
+ qWarning() << "loadAllPlugins()";
+
+ VidaliaSettings settings;
+ QDir path = QDir(settings.pluginPath());
+
+ qWarning() << "PluginPath" << path.absolutePath();
+
+ foreach(QString pdir, path.entryList(QDir::NoDotAndDotDot|QDir::AllDirs)) {
+ qWarning() << "pdir" << pdir;
+ QFileInfo finfo(QString("%1%2%3").arg(path.absolutePath()).arg(QDir::separator()).arg(pdir));
+
+ if(finfo.isDir()) {
+ tryLoadPlugin(finfo.filePath());
+ }
+ }
+}
+
+void
+PluginEngine::tryLoadPlugin(QDir path)
+{
+ qWarning() << "tryLoadPlugin()" << path.absolutePath();
+
+ QStringList files = path.entryList();
+
+ if(!files.contains("info.xml"))
+ return;
+
+ PluginWrapper *wrapper = new PluginWrapper(QString("%1%2info.xml").arg(path.absolutePath()).arg(QDir::separator()), this);
+ wrappers << wrapper;
+}
+
+QList<QAction *>
+PluginEngine::getAllActions()
+{
+ QList<QAction *> actions;
+ foreach(PluginWrapper *wrapper, wrappers)
+ actions << wrapper->menuAction();
+
+ return actions;
+}
diff --git a/src/vidalia/plugin/PluginEngine.h b/src/vidalia/plugin/PluginEngine.h
new file mode 100644
index 0000000..09bff23
--- /dev/null
+++ b/src/vidalia/plugin/PluginEngine.h
@@ -0,0 +1,28 @@
+#ifndef PLUGINENGINE_H
+#define PLUGINENGINE_H
+
+#include <QtGui>
+#include <QtScript>
+
+#include "VidaliaTabPrototype.h"
+
+class PluginWrapper;
+
+class PluginEngine : public QScriptEngine {
+ Q_OBJECT
+
+ public:
+ PluginEngine(QObject *parent = 0);
+ ~PluginEngine();
+
+ QList<QAction *> getAllActions();
+
+ protected:
+ void loadAllPlugins();
+ void tryLoadPlugin(QDir path);
+
+ QList<PluginWrapper *> wrappers;
+};
+
+#endif
+
diff --git a/src/vidalia/plugin/PluginWrapper.cpp b/src/vidalia/plugin/PluginWrapper.cpp
new file mode 100644
index 0000000..b06b863
--- /dev/null
+++ b/src/vidalia/plugin/PluginWrapper.cpp
@@ -0,0 +1,157 @@
+#include "PluginWrapper.h"
+#include "PluginEngine.h"
+
+#include <QtXml>
+
+PluginWrapper::PluginWrapper(const QString &info_path, PluginEngine *engine, QObject *parent)
+ : QObject(parent), _engine(engine)
+{
+ _action = 0;
+ _gui = false;
+ _persistent = false;
+ processInfo(info_path);
+
+ foreach(QString path, _files) {
+ qWarning() << path;
+ QFile file(path);
+ if(file.open(QIODevice::ReadOnly)) {
+ _engine->evaluate(file.readAll());
+ qWarning() << "evaluated";
+ } else
+ qWarning() << "Error opening file";
+ }
+}
+
+PluginWrapper::~PluginWrapper() {}
+
+void
+PluginWrapper::processInfo(const QString &path)
+{
+ qWarning() << "processInfo()";
+
+ QDomDocument info("Plugin Info");
+ QFile file(path);
+ if(!file.open(QIODevice::ReadOnly)) {
+ qWarning() << "Problem opening xml file";
+ return;
+ }
+
+ if(!info.setContent(&file)) {
+ qWarning() << "Problem setting contents";
+ file.close();
+ return;
+ }
+
+ QDomElement root = info.documentElement();
+
+ if(root.tagName() != "VidaliaPlugin") {
+ return;
+ }
+
+ QDomNode n = root.firstChild();
+ while(!n.isNull()) {
+ QDomElement e = n.toElement();
+ if(!e.isNull()) {
+ if(e.tagName() == "name")
+ _name = e.text();
+ else if(e.tagName() == "author")
+ _author = e.text();
+ else if(e.tagName() == "date")
+ _date = e.text();
+ else if(e.tagName() == "type") {
+ _persistent = (e.attribute("persistent", "false") == "true");
+ _gui = (e.attribute("gui", "false") == "true");
+ } else if(e.tagName() == "files") {
+ QDomNode froot = e.firstChild();
+ while(!froot.isNull()) {
+ QDomElement fe = froot.toElement();
+ if(fe.tagName() == "file")
+ _files << QString("%1%2%3").arg(QFileInfo(path).path()).arg(QDir::separator()).arg(fe.text());
+ froot = froot.nextSibling();
+ }
+ } else if(e.tagName() == "namespace") {
+ _nspace = e.text();
+ }
+ }
+ n = n.nextSibling();
+ }
+
+ file.close();
+}
+
+void
+PluginWrapper::start()
+{
+ _engine->evaluate(QString("%1.start()").arg(nspace()));
+}
+
+void
+PluginWrapper::stop()
+{
+ _engine->evaluate(QString("%1.stop()").arg(nspace()));
+}
+
+VidaliaTab *
+PluginWrapper::buildGUI()
+{
+ if(!hasGUI())
+ return NULL;
+ VidaliaTab *tab = qscriptvalue_cast<VidaliaTab *>(_engine->evaluate(QString("%1.buildGUI()").arg(nspace())));
+ if(_engine->hasUncaughtException()) {
+ qWarning() << "Exception:";
+ qWarning() << _engine->uncaughtExceptionLineNumber();
+ }
+ qWarning() << "Casted tab:" << tab << nspace();
+ return tab;
+}
+
+bool
+PluginWrapper::hasGUI()
+{
+ return _gui;
+}
+
+bool
+PluginWrapper::isPersistent()
+{
+ return _persistent;
+}
+
+QString
+PluginWrapper::name() const
+{
+ return _name;
+}
+
+QString
+PluginWrapper::date() const
+{
+ return _date;
+}
+
+QString
+PluginWrapper::author() const
+{
+ return _author;
+}
+
+QString
+PluginWrapper::nspace() const
+{
+ return _nspace;
+}
+
+QStringList
+PluginWrapper::files() const
+{
+ return _files;
+}
+
+QAction *
+PluginWrapper::menuAction()
+{
+ if(hasGUI()) {
+ _action = new QAction(_name, this);
+ }
+ return _action;
+}
diff --git a/src/vidalia/plugin/PluginWrapper.h b/src/vidalia/plugin/PluginWrapper.h
new file mode 100644
index 0000000..1c7ad8f
--- /dev/null
+++ b/src/vidalia/plugin/PluginWrapper.h
@@ -0,0 +1,46 @@
+#ifndef PLUGINWRAPPER_H
+#define PLUGINWRAPPER_H
+
+#include <QtCore>
+
+#include "VidaliaTab.h"
+
+class PluginEngine;
+
+class PluginWrapper : public QObject {
+ Q_OBJECT
+
+ public:
+ PluginWrapper(const QString &info_path, PluginEngine *engine, QObject *parent = 0);
+ ~PluginWrapper();
+
+ bool hasGUI();
+ bool isPersistent();
+
+ QString name() const;
+ QString date() const;
+ QString author() const;
+ QString nspace() const;
+ QStringList files() const;
+
+ QAction *menuAction();
+
+ public slots:
+ void start();
+ void stop();
+ VidaliaTab *buildGUI();
+
+ protected:
+ void processInfo(const QString &path);
+
+ PluginEngine *_engine;
+ QString _name, _date, _author;
+ bool _persistent, _gui;
+ QStringList _files;
+ QString _nspace;
+
+ QAction *_action;
+};
+
+#endif
+
diff --git a/src/vidalia/plugin/prototypes/VidaliaTabPrototype.cpp b/src/vidalia/plugin/prototypes/VidaliaTabPrototype.cpp
new file mode 100644
index 0000000..58170ef
--- /dev/null
+++ b/src/vidalia/plugin/prototypes/VidaliaTabPrototype.cpp
@@ -0,0 +1,10 @@
+#include "VidaliaTabPrototype.h"
+
+VidaliaTabPrototype::VidaliaTabPrototype(QObject *parent)
+ : QObject(parent)
+{}
+
+QScriptValue VidaliaTabPrototype::constructor(QScriptContext *context, QScriptEngine *engine)
+{
+ return engine->newQObject(new VidaliaTab(QString("titulooo"), QString("nombreee")), QScriptEngine::ScriptOwnership);
+}
diff --git a/src/vidalia/plugin/prototypes/VidaliaTabPrototype.h b/src/vidalia/plugin/prototypes/VidaliaTabPrototype.h
new file mode 100644
index 0000000..dbd89cd
--- /dev/null
+++ b/src/vidalia/plugin/prototypes/VidaliaTabPrototype.h
@@ -0,0 +1,21 @@
+#ifndef VIDALIATABPROT_H
+#define VIDALIATABPROT_H
+
+#include <QtGui>
+#include <QtScript>
+
+#include "VidaliaTab.h"
+
+class VidaliaTabPrototype : public QObject, public QScriptable
+{
+ Q_OBJECT
+
+ public:
+ VidaliaTabPrototype(QObject *parent = 0);
+ static QScriptValue constructor(QScriptContext *context, QScriptEngine *engine);
+};
+
+Q_DECLARE_METATYPE(VidaliaTab *);
+
+#endif
+
More information about the tor-commits
mailing list