#include <qfileinfo.h>
#include <qfile.h>
#include <qdir.h>
#include <qlibrary.h>
#include <dlfcn.h>
#include <string.h>
#include <errno.h>
#include "MadApp.h"
#include "MadMainWindow.h"
#include "MadPlugin.h"
//#include "MadChildFrame.h"
#include "MadConf.h"
#include <qmessagebox.h>
MadApp *app = 0;
MadApp::MadApp(int & argc, char ** argv) : QApplication(argc, argv), mw(main_window), conf(_conf), ml(media_library)
{
//setStyle("cde");
app = this;
_conf = new MadConf("test.db");
if(!_conf)
mad_throw(MadException, "Failed to load config");
main_window = new MadMainWindow();
setMainWidget(main_window);
main_window->show();
LoadPlugins();
}
MadDBConnection *MadApp::getDB(const char *name)
{
if(dbmap.contains(name)) {
return dbmap[name]->getDB();
}
return 0;
}
bool MadApp::registerDBHandler(const char *name, MadDBHandler *hndl)
{
if(!dbmap.contains(name)) {
dbmap[name] = hndl;
return true;
}
return false;
}
bool MadApp::unregisterDBHandler(const char *name)
{
if(dbmap.contains(name)) {
dbmap.erase(name);
return true;
}
return false;
}
/*
Some ideas:
===========
o instead of a QPtrList for the plugin list, use a hash and grap the name for the key.
o seperate LoadPlugins into LoadPlugin and LoadPlugins
o add InstallPlugin UninstallPlugin, UnloadPlugin, RehashPlugin/CyclePlugin (deinit/init cycle)
*/
void MadApp::rescanPlugins()
{
}
bool MadApp::LoadPlugin(QFileInfo fi)
{
MadPlugin *plug = 0;
QString name;
if(fi.extension() != QString("so") && fi.extension() != QString("dll")) {
printf("Skipping file: %s\n", fi.filePath().ascii());
return true;
}
if(plugins.contains(fi.baseName())) {
delete plug;
return true;
}
printf( "Loading Plugin: %s\n", fi.filePath().ascii() );
try {
plug = new MadPlugin(fi.filePath().latin1());
name = plug->GetName();
} catch (const char *thing) {
QMessageBox::warning(app->mw, "Error", QString().sprintf("%s: %s", thing, fi.baseName().ascii()));
printf("Plug: %s\n", thing);
printf("err: %s\n", strerror(errno));
return false;
}
plugins[name] = plug;
return true;
}
bool MadApp::installPlugin(const char *path)
{
MadConfKey pkey;
MadConfKey mkey;
MadConfKey modkey;
MadConfKey pathkey, loadkey;
MadConfKeyValue pathval, loadval;
MadPluginInstance *inst = 0;
if(!conf->key(pkey, "plugins")) {
printf("!plugins\n");
return false;
}
if(!pkey.child(mkey, "modules"))
return false;
QFileInfo fi(path);
if(mkey.child(modkey, fi.baseName())) {
MadConfKey pathkey;
if(modkey.child(pathkey, "path")) {
MadConfKeyValue val;
pathkey.value(val);
if(fi.absFilePath() == val.getText())
goto fail;
}
}
if(!mkey.newChild(modkey, fi.baseName()))
goto fail;
if(!modkey.newChild(pathkey, "path"))
goto fail;
if(!pathkey.addValue(pathval, fi.absFilePath()))
goto fail;
if(!modkey.newChild(loadkey, "load"))
goto fail;
if(!loadkey.addValue(loadval, "1"))
goto fail;
if(!LoadPlugin(fi))
goto fail;
inst = plugins[fi.baseName()]->GetInstance();
if(!inst)
goto fail;
inst->init();
instances.append(inst);
return true;
fail:
// message here?
return false;
}
bool MadApp::uninstallPlugin(const char *name)
{
MadConfKey pkey, mkey, modkey;
if(!conf->key(pkey, "plugins"))
return false;
if(!pkey.child(mkey, "modules"))
return false;
if(!mkey.child(modkey, name))
return false;
if(!modkey.erase())
return false;
return true;
}
bool MadApp::disablePlugin(const char *name)
{
if(!plugins.contains(name))
return false;
MadPlugin *plug = plugins[name];
MadPluginInstance *inst = 0;
for ( inst = instances.first(); inst; inst = instances.next() )
if(inst->plug == plug) {
instances.remove();
delete inst;
}
delete plug;
plugins.erase(name);
printf("removed: %s\n", name);
return true;
}
bool MadApp::enablePlugin(const char *name)
{
MadConfKey pkey;
if(!conf->key(pkey, "plugins")) {
printf("!plugins\n");
return false;
}
MadConfKey mkey;
if(!pkey.child(mkey, "modules"))
return false;
printf("modules\n");
MadConfKey modkey;
if(!mkey.child(modkey, name))
return false;
printf("modkey: %s\n", name);
MadConfKey path;
if(!modkey.child(path, "path"))
return false;
printf("path\n");
MadConfKey load;
if(!modkey.child(load, "load"))
return false;
printf("load\n");
MadConfKeyValue lval;
if(!load.value(lval))
return false;
printf("lval\n");
if(!lval.set(true))
return false;
printf("lval.set\n");
MadConfKeyValue pval;
path.value(pval);
QFileInfo fi(pval.getText());
printf("pval\n");
if(!LoadPlugin(fi))
return false;
MadPluginInstance *inst = plugins[name]->GetInstance();
if(!inst)
return false;
inst->init();
instances.append(inst);
printf("added: %s\n", name);
inst->start();
return true;
}
int MadApp::pluginId(const char *name)
{
MadConfKey pkey;
if(!conf->key(pkey, "plugins")) {
printf("!plugins\n");
return -1;
}
MadConfKey mkey;
if(!pkey.child(mkey, "modules"))
return -1;
MadConfKey modkey;
if(!mkey.child(modkey, name))
return -1;
return modkey.getId();
}
bool MadApp::LoadPlugins()
{
MadConfKeyValue dval;
MadPluginRMap rmap;
char *dir = NULL;
MadConfKey pkey;
if(!conf->key(pkey, "plugins")) {
printf("!plugins\n");
return false;
}
MadConfKey mkey;
if(!pkey.child(mkey, "modules"))
return false;
mkey.beginChild();
MadConfKey modkey;
while(mkey.step(modkey)) {
MadConfKeyValue pval, lval;
MadConfKey path;
if(!modkey.child(path, "path"))
continue;
MadConfKey load;
if(!modkey.child(load, "load"))
continue;
if(!load.value(lval))
continue;
if(!lval.getBool())
continue;
path.value(pval);
QFileInfo fi(pval.getText());
LoadPlugin(fi);
}
MadPluginMap::Iterator it;
for ( it = plugins.begin(); it != plugins.end(); ++it ) {
MadPlugin *plug = it.data();
QStringList deps;
if(!plug->Dependencies(deps)) {
// rmap["__none__"] += plug->GetName();
continue;
}
if(deps.count() < 1) {
rmap["__none__"] += plug->GetName();
continue;
}
for(QStringList::Iterator slit = deps.begin(); slit != deps.end(); ++slit) {
rmap[*slit] += plug->GetName();
}
}
// init plugins with no deps.
for(QStringList::Iterator slit = rmap["__none__"].begin(); slit != rmap["__none__"].end(); ++slit) {
MadPluginInstance *inst = plugins[*slit]->GetInstance();
if(!inst)
continue;
inst->init();
instances.append(inst);
}
rmap.erase("__none__");
for (MadPluginRMap::Iterator rit = rmap.begin(); rit != rmap.end(); ++rit ) {
for(QStringList::Iterator slit = rit.data().begin(); slit != rit.data().end(); ++rit) {
MadPluginInstance *inst = plugins[*slit]->GetInstance();
if(!inst)
continue;
if(!inst->init()) {
delete plugins[*slit];
plugins.remove(*slit);
}
instances.append(inst);
}
}
for (MadPluginInstanceList::Iterator iit = instances.begin(); iit != instances.end(); ++iit ) {
(*iit)->start();
}
return true;
}
int main(int argc, char **argv)
{
try {
MadApp app(argc, argv);
return app.exec();
} catch (MadException &me) {
printf("%s:%s:%i:%s: %s\n", me.who(), me.file(), me.line(), me.func(), me.what());
} catch (std::exception &ex) {
printf("error: %s\n", ex.what());
} catch (const char *msg) {
printf("err: '%s'\n", msg);
}
}
#if 0
//try {
//QLibrary *plug = new QLibrary("/home/moose/.projects/mad/plugins/test.so");
void *plug = dlopen("/home/moose/.projects/mad/plugins/conf.so", RTLD_NOW);
if(plug == 0) {
printf("failed to load plugin: %s\n", dlerror());
return false;
}
//VersionFunc _VersionFunc = (VersionFunc) plug->resolve("MPA_Version");
VersionFunc _VersionFunc = (VersionFunc) dlsym(plug, "MPA_Version");
printf("vf: %p\n", _VersionFunc);
if(_VersionFunc == 0) {
printf("Module missing Version method.\n");
return false;
}
//InstanceFunc _InstanceFunc = (InstanceFunc) plug->resolve("MPA_Instance");
InstanceFunc _InstanceFunc = (InstanceFunc) dlsym(plug, "MPA_Instance");
printf("if: %p\n", _InstanceFunc);
if(_InstanceFunc == 0) {
printf("Module missing Instance method.\n");
return false;
}
if( _VersionFunc() != MPA_VERSION) {
printf("Incorrect module version.\n");
return false;
}
MadPluginInstance *Instance = (MadPluginInstance *)_InstanceFunc((MadApp *)qApp);
if(!Instance)
printf("Failed to get module instance.\n");
//} catch (const char *thing) {
// printf("Plug: %s\n", thing);
//}
#endif