You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/kexi/kexidb/drivermanager.cpp

436 lines
13 KiB

/* This file is part of the KDE project
Copyright (C) 2003 Daniel Molkentin <molkentin@kde.org>
Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org>
Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <kexidb/drivermanager.h>
#include <kexidb/drivermanager_p.h>
#include <kexidb/driver.h>
#include <kexidb/driver_p.h>
#include <kexidb/error.h>
#include <klibloader.h>
#include <kparts/componentfactory.h>
#include <ktrader.h>
#include <kdebug.h>
#include <klocale.h>
#include <kservice.h>
#include <assert.h>
#include <tqapplication.h>
//remove debug
#undef KexiDBDbg
#define KexiDBDbg if (0) kdDebug()
using namespace KexiDB;
DriverManagerInternal* DriverManagerInternal::s_self = 0L;
DriverManagerInternal::DriverManagerInternal() /* protected */
: TQObject( 0, "KexiDB::DriverManager" )
, Object()
, m_drivers(17, false)
, m_refCount(0)
, lookupDriversNeeded(true)
{
m_drivers.setAutoDelete(true);
m_serverResultNum=0;
}
DriverManagerInternal::~DriverManagerInternal()
{
KexiDBDbg << "DriverManagerInternal::~DriverManagerInternal()" << endl;
m_drivers.clear();
if ( s_self == this )
s_self = 0;
KexiDBDbg << "DriverManagerInternal::~DriverManagerInternal() ok" << endl;
}
void DriverManagerInternal::slotAppQuits()
{
if (tqApp->mainWidget() && tqApp->mainWidget()->isVisible())
return; //what a hack! - we give up when app is still there
KexiDBDbg << "DriverManagerInternal::slotAppQuits(): let's clear drivers..." << endl;
m_drivers.clear();
}
DriverManagerInternal *DriverManagerInternal::self()
{
if (!s_self)
s_self = new DriverManagerInternal();
return s_self;
}
bool DriverManagerInternal::lookupDrivers()
{
if (!lookupDriversNeeded)
return true;
if (tqApp) {
connect(tqApp,TQT_SIGNAL(aboutToQuit()),this,TQT_SLOT(slotAppQuits()));
}
//TODO: for QT-only version check for KInstance wrapper
// KexiDBWarn << "DriverManagerInternal::lookupDrivers(): cannot work without KInstance (KGlobal::instance()==0)!" << endl;
// setError("Driver Manager cannot work without KInstance (KGlobal::instance()==0)!");
lookupDriversNeeded = false;
clearError();
KTrader::OfferList tlist = KTrader::self()->query("Kexi/DBDriver");
KTrader::OfferList::ConstIterator it(tlist.constBegin());
for(; it != tlist.constEnd(); ++it)
{
KService::Ptr ptr = (*it);
if (!ptr->property("Library").toString().startsWith("kexidb_")) {
KexiDBWarn << "DriverManagerInternal::lookupDrivers():"
" X-KDE-Library == " << ptr->property("Library").toString()
<< ": no \"kexidb_\" prefix -- skipped to avoid potential conflicts!" << endl;
continue;
}
TQString srv_name = ptr->property("X-Kexi-DriverName").toString();
if (srv_name.isEmpty()) {
KexiDBWarn << "DriverManagerInternal::lookupDrivers():"
" X-Kexi-DriverName must be set for KexiDB driver \""
<< ptr->property("Name").toString() << "\" service!\n -- skipped!" << endl;
continue;
}
if (m_services_lcase.tqcontains(srv_name.lower())) {
KexiDBWarn << "DriverManagerInternal::lookupDrivers(): more than one driver named '"
<< srv_name.lower() << "'\n -- skipping this one!" << endl;
continue;
}
TQString srv_ver_str = ptr->property("X-Kexi-KexiDBVersion").toString();
TQStringList lst( TQStringList::split(".", srv_ver_str) );
uint minor_ver, major_ver;
bool ok = (lst.count() == 2);
if (ok)
major_ver = lst[0].toUInt(&ok);
if (ok)
minor_ver = lst[1].toUInt(&ok);
if (!ok) {
KexiDBWarn << "DriverManagerInternal::lookupDrivers(): problem with detecting '"
<< srv_name.lower() << "' driver's version -- skipping it!" << endl;
continue;
}
if (major_ver != KexiDB::version().major || minor_ver != KexiDB::version().minor) {
KexiDBWarn << TQString("DriverManagerInternal::lookupDrivers(): '%1' driver"
" has version '%2' but required KexiDB driver version is '%3.%4'\n"
" -- skipping this driver!").tqarg(srv_name.lower()).tqarg(srv_ver_str)
.tqarg(KexiDB::version().major).tqarg(KexiDB::version().minor) << endl;
possibleProblems += TQString("\"%1\" database driver has version \"%2\" "
"but required driver version is \"%3.%4\"")
.tqarg(srv_name.lower()).tqarg(srv_ver_str)
.tqarg(KexiDB::version().major).tqarg(KexiDB::version().minor);
continue;
}
TQString drvType = ptr->property("X-Kexi-DriverType").toString().lower();
if (drvType=="file") {
//new property: a list of supported mime types
TQStringList mimes( ptr->property("X-Kexi-FileDBDriverMimeList").toStringList() );
//single mime is obsolete, but we're handling it:
{
TQString mime( ptr->property("X-Kexi-FileDBDriverMime").toString().lower() );
if (!mime.isEmpty())
mimes.append( mime );
}
//store association of this driver with all listed mime types
for (TQStringList::ConstIterator mime_it = mimes.constBegin(); mime_it!=mimes.constEnd(); ++mime_it) {
TQString mime( (*mime_it).lower() );
if (!m_services_by_mimetype.tqcontains(mime)) {
m_services_by_mimetype.insert(mime, ptr);
}
else {
KexiDBWarn << "DriverManagerInternal::lookupDrivers(): more than one driver for '"
<< mime << "' mime type!" << endl;
}
}
}
m_services.insert(srv_name, ptr);
m_services_lcase.insert(srv_name.lower(), ptr);
KexiDBDbg << "KexiDB::DriverManager::lookupDrivers(): registered driver: " << ptr->name() << "(" << ptr->library() << ")" << endl;
}
if (tlist.isEmpty())
{
setError(ERR_DRIVERMANAGER, i18n("Could not find any database drivers.") );
return false;
}
return true;
}
KexiDB::Driver::Info DriverManagerInternal::driverInfo(const TQString &name)
{
KexiDB::Driver::Info i = m_driversInfo[name.lower()];
if (!error() && i.name.isEmpty())
setError(ERR_DRIVERMANAGER, i18n("Could not find database driver \"%1\".").tqarg(name) );
return i;
}
Driver* DriverManagerInternal::driver(const TQString& name)
{
if (!lookupDrivers())
return 0;
clearError();
KexiDBDbg << "DriverManager::driver(): loading " << name << endl;
Driver *drv = name.isEmpty() ? 0 : m_drivers.tqfind(name.latin1());
if (drv)
return drv; //cached
if (!m_services_lcase.tqcontains(name.lower())) {
setError(ERR_DRIVERMANAGER, i18n("Could not find database driver \"%1\".").tqarg(name) );
return 0;
}
KService::Ptr ptr= *(m_services_lcase.tqfind(name.lower()));
TQString srv_name = ptr->property("X-Kexi-DriverName").toString();
KexiDBDbg << "KexiDBInterfaceManager::load(): library: "<<ptr->library()<<endl;
drv = KParts::ComponentFactory::createInstanceFromService<KexiDB::Driver>(ptr,
this, srv_name.latin1(), TQStringList(),&m_serverResultNum);
if (!drv) {
setError(ERR_DRIVERMANAGER, i18n("Could not load database driver \"%1\".")
.tqarg(name) );
if (m_componentLoadingErrors.isEmpty()) {//fill errtable on demand
m_componentLoadingErrors[KParts::ComponentFactory::ErrNoServiceFound]="ErrNoServiceFound";
m_componentLoadingErrors[KParts::ComponentFactory::ErrServiceProvidesNoLibrary]="ErrServiceProvidesNoLibrary";
m_componentLoadingErrors[KParts::ComponentFactory::ErrNoLibrary]="ErrNoLibrary";
m_componentLoadingErrors[KParts::ComponentFactory::ErrNoFactory]="ErrNoFactory";
m_componentLoadingErrors[KParts::ComponentFactory::ErrNoComponent]="ErrNoComponent";
}
m_serverResultName=m_componentLoadingErrors[m_serverResultNum];
return 0;
}
KexiDBDbg << "KexiDBInterfaceManager::load(): loading succeed: " << name <<endl;
// KexiDBDbg << "drv="<<(long)drv <<endl;
// drv->setName(srv_name.latin1());
drv->d->service = ptr.data(); //store info
drv->d->fileDBDriverMimeType = ptr->property("X-Kexi-FileDBDriverMime").toString();
drv->d->initInternalProperties();
if (!drv->isValid()) {
setError(drv);
delete drv;
return 0;
}
m_drivers.insert(name.latin1(), drv); //cache it
return drv;
}
void DriverManagerInternal::incRefCount()
{
m_refCount++;
KexiDBDbg << "DriverManagerInternal::incRefCount(): " << m_refCount << endl;
}
void DriverManagerInternal::decRefCount()
{
m_refCount--;
KexiDBDbg << "DriverManagerInternal::decRefCount(): " << m_refCount << endl;
// if (m_refCount<1) {
// KexiDBDbg<<"KexiDB::DriverManagerInternal::decRefCount(): reached m_refCount<1 -->deletelater()"<<endl;
// s_self=0;
// deleteLater();
// }
}
void DriverManagerInternal::aboutDelete( Driver* drv )
{
m_drivers.take(drv->name());
}
// ---------------------------
// --- DriverManager impl. ---
// ---------------------------
DriverManager::DriverManager()
: TQObject( 0, "KexiDB::DriverManager" )
, Object()
, d_int( DriverManagerInternal::self() )
{
d_int->incRefCount();
// if ( !s_self )
// s_self = this;
// lookupDrivers();
}
DriverManager::~DriverManager()
{
KexiDBDbg << "DriverManager::~DriverManager()" << endl;
/* Connection *conn;
for ( conn = m_connections.first(); conn ; conn = m_connections.next() ) {
conn->disconnect();
conn->m_driver = 0; //don't let the connection touch our driver now
m_connections.remove();
delete conn;
}*/
d_int->decRefCount();
if (d_int->m_refCount==0) {
//delete internal drv manager!
delete d_int;
}
// if ( s_self == this )
//s_self = 0;
KexiDBDbg << "DriverManager::~DriverManager() ok" << endl;
}
const KexiDB::Driver::InfoMap DriverManager::driversInfo()
{
if (!d_int->lookupDrivers())
return KexiDB::Driver::InfoMap();
if (!d_int->m_driversInfo.isEmpty())
return d_int->m_driversInfo;
ServicesMap::ConstIterator it;
for ( it=d_int->m_services.constBegin() ; it != d_int->m_services.constEnd(); ++it ) {
Driver::Info info;
KService::Ptr ptr = it.data();
info.name = ptr->property("X-Kexi-DriverName").toString();
info.caption = ptr->property("Name").toString();
info.comment = ptr->property("Comment").toString();
if (info.caption.isEmpty())
info.caption = info.name;
info.fileBased = (ptr->property("X-Kexi-DriverType").toString().lower()=="file");
if (info.fileBased)
info.fileDBMimeType = ptr->property("X-Kexi-FileDBDriverMime").toString().lower();
TQVariant v = ptr->property("X-Kexi-DoNotAllowProjectImportingTo");
info.allowImportingTo = v.isNull() ? true : !v.toBool();
d_int->m_driversInfo.insert(info.name.lower(), info);
}
return d_int->m_driversInfo;
}
const TQStringList DriverManager::driverNames()
{
if (!d_int->lookupDrivers())
return TQStringList();
if (d_int->m_services.isEmpty() && d_int->error())
return TQStringList();
return d_int->m_services.keys();
}
KexiDB::Driver::Info DriverManager::driverInfo(const TQString &name)
{
driversInfo();
KexiDB::Driver::Info i = d_int->driverInfo(name);
if (d_int->error())
setError(d_int);
return i;
}
KService::Ptr DriverManager::serviceInfo(const TQString &name)
{
if (!d_int->lookupDrivers()) {
setError(d_int);
return KService::Ptr();
}
clearError();
if (d_int->m_services_lcase.tqcontains(name.lower())) {
return *d_int->m_services_lcase.tqfind(name.lower());
} else {
setError(ERR_DRIVERMANAGER, i18n("No such driver service: \"%1\".").tqarg(name) );
return KService::Ptr();
}
}
const DriverManager::ServicesMap& DriverManager::services()
{
d_int->lookupDrivers();
return d_int->m_services;
}
TQString DriverManager::lookupByMime(const TQString &mimeType)
{
if (!d_int->lookupDrivers()) {
setError(d_int);
return 0;
}
KService::Ptr ptr = d_int->m_services_by_mimetype[mimeType.lower()];
if (!ptr)
return TQString();
return ptr->property("X-Kexi-DriverName").toString();
}
Driver* DriverManager::driver(const TQString& name)
{
Driver *drv = d_int->driver(name);
if (d_int->error())
setError(d_int);
return drv;
}
TQString DriverManager::serverErrorMsg()
{
return d_int->m_serverErrMsg;
}
int DriverManager::serverResult()
{
return d_int->m_serverResultNum;
}
TQString DriverManager::serverResultName()
{
return d_int->m_serverResultName;
}
void DriverManager::drv_clearServerResult()
{
d_int->m_serverErrMsg=TQString();
d_int->m_serverResultNum=0;
d_int->m_serverResultName=TQString();
}
TQString DriverManager::possibleProblemsInfoMsg() const
{
if (d_int->possibleProblems.isEmpty())
return TQString();
TQString str;
str.reserve(1024);
str = "<ul>";
for (TQStringList::ConstIterator it = d_int->possibleProblems.constBegin();
it!=d_int->possibleProblems.constEnd(); ++it)
{
str += (TQString::tqfromLatin1("<li>") + *it + TQString::tqfromLatin1("</li>"));
}
str += "</ul>";
return str;
}
#include "drivermanager_p.moc"