kexi

drivermanager.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003 Daniel Molkentin <molkentin@kde.org>
3 Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org>
4 Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this program; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20*/
21
22#include <kexidb/drivermanager.h>
23#include <kexidb/drivermanager_p.h>
24
25#include <kexidb/driver.h>
26#include <kexidb/driver_p.h>
27#include <kexidb/error.h>
28
29#include <klibloader.h>
30#include <tdeparts/componentfactory.h>
31#include <ktrader.h>
32#include <kdebug.h>
33#include <tdelocale.h>
34#include <kservice.h>
35
36#include <assert.h>
37
38#include <tqapplication.h>
39
40//remove debug
41#undef KexiDBDbg
42#define KexiDBDbg if (0) kdDebug()
43
44using namespace KexiDB;
45
46DriverManagerInternal* DriverManagerInternal::s_self = 0L;
47
48
49DriverManagerInternal::DriverManagerInternal() /* protected */
50 : TQObject( 0, "KexiDB::DriverManager" )
51 , Object()
52 , m_drivers(17, false)
53 , m_refCount(0)
54 , lookupDriversNeeded(true)
55{
56 m_drivers.setAutoDelete(true);
57 m_serverResultNum=0;
58
59}
60
61DriverManagerInternal::~DriverManagerInternal()
62{
63 KexiDBDbg << "DriverManagerInternal::~DriverManagerInternal()" << endl;
64 m_drivers.clear();
65 if ( s_self == this )
66 s_self = 0;
67 KexiDBDbg << "DriverManagerInternal::~DriverManagerInternal() ok" << endl;
68}
69
70void DriverManagerInternal::slotAppQuits()
71{
72 if (tqApp->mainWidget() && tqApp->mainWidget()->isVisible())
73 return; //what a hack! - we give up when app is still there
74 KexiDBDbg << "DriverManagerInternal::slotAppQuits(): let's clear drivers..." << endl;
75 m_drivers.clear();
76}
77
78DriverManagerInternal *DriverManagerInternal::self()
79{
80 if (!s_self)
81 s_self = new DriverManagerInternal();
82
83 return s_self;
84}
85
86bool DriverManagerInternal::lookupDrivers()
87{
88 if (!lookupDriversNeeded)
89 return true;
90
91 if (tqApp) {
92 connect(tqApp,TQ_SIGNAL(aboutToQuit()),this,TQ_SLOT(slotAppQuits()));
93 }
94//TODO: for TQt-only version check for TDEInstance wrapper
95// KexiDBWarn << "DriverManagerInternal::lookupDrivers(): cannot work without TDEInstance (TDEGlobal::instance()==0)!" << endl;
96// setError("Driver Manager cannot work without TDEInstance (TDEGlobal::instance()==0)!");
97
98 lookupDriversNeeded = false;
99 clearError();
100 TDETrader::OfferList tlist = TDETrader::self()->query("Kexi/DBDriver");
101 TDETrader::OfferList::ConstIterator it(tlist.constBegin());
102 for(; it != tlist.constEnd(); ++it)
103 {
104 KService::Ptr ptr = (*it);
105 if (!ptr->property("Library").toString().startsWith("kexidb_")) {
106 KexiDBWarn << "DriverManagerInternal::lookupDrivers():"
107 " X-TDE-Library == " << ptr->property("Library").toString()
108 << ": no \"kexidb_\" prefix -- skipped to avoid potential conflicts!" << endl;
109 continue;
110 }
111 TQString srv_name = ptr->property("X-Kexi-DriverName").toString();
112 if (srv_name.isEmpty()) {
113 KexiDBWarn << "DriverManagerInternal::lookupDrivers():"
114 " X-Kexi-DriverName must be set for KexiDB driver \""
115 << ptr->property("Name").toString() << "\" service!\n -- skipped!" << endl;
116 continue;
117 }
118 if (m_services_lcase.contains(srv_name.lower())) {
119 KexiDBWarn << "DriverManagerInternal::lookupDrivers(): more than one driver named '"
120 << srv_name.lower() << "'\n -- skipping this one!" << endl;
121 continue;
122 }
123
124 TQString srv_ver_str = ptr->property("X-Kexi-KexiDBVersion").toString();
125 TQStringList lst( TQStringList::split(".", srv_ver_str) );
126 uint minor_ver, major_ver;
127 bool ok = (lst.count() == 2);
128 if (ok)
129 major_ver = lst[0].toUInt(&ok);
130 if (ok)
131 minor_ver = lst[1].toUInt(&ok);
132 if (!ok) {
133 KexiDBWarn << "DriverManagerInternal::lookupDrivers(): problem with detecting '"
134 << srv_name.lower() << "' driver's version -- skipping it!" << endl;
135 continue;
136 }
137 if (major_ver != KexiDB::version().major || minor_ver != KexiDB::version().minor) {
138 KexiDBWarn << TQString("DriverManagerInternal::lookupDrivers(): '%1' driver"
139 " has version '%2' but required KexiDB driver version is '%3.%4'\n"
140 " -- skipping this driver!").arg(srv_name.lower()).arg(srv_ver_str)
141 .arg(KexiDB::version().major).arg(KexiDB::version().minor) << endl;
142 possibleProblems += TQString("\"%1\" database driver has version \"%2\" "
143 "but required driver version is \"%3.%4\"")
144 .arg(srv_name.lower()).arg(srv_ver_str)
145 .arg(KexiDB::version().major).arg(KexiDB::version().minor);
146 continue;
147 }
148
149 TQString drvType = ptr->property("X-Kexi-DriverType").toString().lower();
150 if (drvType=="file") {
151 //new property: a list of supported mime types
152 TQStringList mimes( ptr->property("X-Kexi-FileDBDriverMimeList").toStringList() );
153 //single mime is obsolete, but we're handling it:
154 {
155 TQString mime( ptr->property("X-Kexi-FileDBDriverMime").toString().lower() );
156 if (!mime.isEmpty())
157 mimes.append( mime );
158 }
159
160 //store association of this driver with all listed mime types
161 for (TQStringList::ConstIterator mime_it = mimes.constBegin(); mime_it!=mimes.constEnd(); ++mime_it) {
162 TQString mime( (*mime_it).lower() );
163 if (!m_services_by_mimetype.contains(mime)) {
164 m_services_by_mimetype.insert(mime, ptr);
165 }
166 else {
167 KexiDBWarn << "DriverManagerInternal::lookupDrivers(): more than one driver for '"
168 << mime << "' mime type!" << endl;
169 }
170 }
171 }
172 m_services.insert(srv_name, ptr);
173 m_services_lcase.insert(srv_name.lower(), ptr);
174 KexiDBDbg << "KexiDB::DriverManager::lookupDrivers(): registered driver: " << ptr->name() << "(" << ptr->library() << ")" << endl;
175 }
176
177 if (tlist.isEmpty())
178 {
179 setError(ERR_DRIVERMANAGER, i18n("Could not find any database drivers.") );
180 return false;
181 }
182 return true;
183}
184
185KexiDB::Driver::Info DriverManagerInternal::driverInfo(const TQString &name)
186{
187 KexiDB::Driver::Info i = m_driversInfo[name.lower()];
188 if (!error() && i.name.isEmpty())
189 setError(ERR_DRIVERMANAGER, i18n("Could not find database driver \"%1\".").arg(name) );
190 return i;
191}
192
193Driver* DriverManagerInternal::driver(const TQString& name)
194{
195 if (!lookupDrivers())
196 return 0;
197
198 clearError();
199 KexiDBDbg << "DriverManager::driver(): loading " << name << endl;
200
201 Driver *drv = name.isEmpty() ? 0 : m_drivers.find(name.latin1());
202 if (drv)
203 return drv; //cached
204
205 if (!m_services_lcase.contains(name.lower())) {
206 setError(ERR_DRIVERMANAGER, i18n("Could not find database driver \"%1\".").arg(name) );
207 return 0;
208 }
209
210 KService::Ptr ptr= *(m_services_lcase.find(name.lower()));
211 TQString srv_name = ptr->property("X-Kexi-DriverName").toString();
212
213 KexiDBDbg << "KexiDBInterfaceManager::load(): library: "<<ptr->library()<<endl;
214 drv = KParts::ComponentFactory::createInstanceFromService<KexiDB::Driver>(ptr,
215 this, srv_name.latin1(), TQStringList(),&m_serverResultNum);
216
217 if (!drv) {
218 setError(ERR_DRIVERMANAGER, i18n("Could not load database driver \"%1\".")
219 .arg(name) );
220 if (m_componentLoadingErrors.isEmpty()) {//fill errtable on demand
221 m_componentLoadingErrors[KParts::ComponentFactory::ErrNoServiceFound]="ErrNoServiceFound";
222 m_componentLoadingErrors[KParts::ComponentFactory::ErrServiceProvidesNoLibrary]="ErrServiceProvidesNoLibrary";
223 m_componentLoadingErrors[KParts::ComponentFactory::ErrNoLibrary]="ErrNoLibrary";
224 m_componentLoadingErrors[KParts::ComponentFactory::ErrNoFactory]="ErrNoFactory";
225 m_componentLoadingErrors[KParts::ComponentFactory::ErrNoComponent]="ErrNoComponent";
226 }
227 m_serverResultName=m_componentLoadingErrors[m_serverResultNum];
228 return 0;
229 }
230 KexiDBDbg << "KexiDBInterfaceManager::load(): loading succeed: " << name <<endl;
231// KexiDBDbg << "drv="<<(long)drv <<endl;
232
233// drv->setName(srv_name.latin1());
234 drv->d->service = ptr.data(); //store info
235 drv->d->fileDBDriverMimeType = ptr->property("X-Kexi-FileDBDriverMime").toString();
236 drv->d->initInternalProperties();
237
238 if (!drv->isValid()) {
239 setError(drv);
240 delete drv;
241 return 0;
242 }
243 m_drivers.insert(name.latin1(), drv); //cache it
244 return drv;
245}
246
247void DriverManagerInternal::incRefCount()
248{
249 m_refCount++;
250 KexiDBDbg << "DriverManagerInternal::incRefCount(): " << m_refCount << endl;
251}
252
253void DriverManagerInternal::decRefCount()
254{
255 m_refCount--;
256 KexiDBDbg << "DriverManagerInternal::decRefCount(): " << m_refCount << endl;
257// if (m_refCount<1) {
258// KexiDBDbg<<"KexiDB::DriverManagerInternal::decRefCount(): reached m_refCount<1 -->deletelater()"<<endl;
259// s_self=0;
260// deleteLater();
261// }
262}
263
264void DriverManagerInternal::aboutDelete( Driver* drv )
265{
266 m_drivers.take(drv->name());
267}
268
269
270
271// ---------------------------
272// --- DriverManager impl. ---
273// ---------------------------
274
275DriverManager::DriverManager()
276 : TQObject( 0, "KexiDB::DriverManager" )
277 , Object()
278 , d_int( DriverManagerInternal::self() )
279{
280 d_int->incRefCount();
281// if ( !s_self )
282// s_self = this;
283// lookupDrivers();
284}
285
286DriverManager::~DriverManager()
287{
288 KexiDBDbg << "DriverManager::~DriverManager()" << endl;
289/* Connection *conn;
290 for ( conn = m_connections.first(); conn ; conn = m_connections.next() ) {
291 conn->disconnect();
292 conn->m_driver = 0; //don't let the connection touch our driver now
293 m_connections.remove();
294 delete conn;
295 }*/
296
297 d_int->decRefCount();
298 if (d_int->m_refCount==0) {
299 //delete internal drv manager!
300 delete d_int;
301 }
302// if ( s_self == this )
303 //s_self = 0;
304 KexiDBDbg << "DriverManager::~DriverManager() ok" << endl;
305}
306
307const KexiDB::Driver::InfoMap DriverManager::driversInfo()
308{
309 if (!d_int->lookupDrivers())
310 return KexiDB::Driver::InfoMap();
311
312 if (!d_int->m_driversInfo.isEmpty())
313 return d_int->m_driversInfo;
314 ServicesMap::ConstIterator it;
315 for ( it=d_int->m_services.constBegin() ; it != d_int->m_services.constEnd(); ++it ) {
316 Driver::Info info;
317 KService::Ptr ptr = it.data();
318 info.name = ptr->property("X-Kexi-DriverName").toString();
319 info.caption = ptr->property("Name").toString();
320 info.comment = ptr->property("Comment").toString();
321 if (info.caption.isEmpty())
322 info.caption = info.name;
323 info.fileBased = (ptr->property("X-Kexi-DriverType").toString().lower()=="file");
324 if (info.fileBased)
325 info.fileDBMimeType = ptr->property("X-Kexi-FileDBDriverMime").toString().lower();
326 TQVariant v = ptr->property("X-Kexi-DoNotAllowProjectImportingTo");
327 info.allowImportingTo = v.isNull() ? true : !v.toBool();
328 d_int->m_driversInfo.insert(info.name.lower(), info);
329 }
330 return d_int->m_driversInfo;
331}
332
333const TQStringList DriverManager::driverNames()
334{
335 if (!d_int->lookupDrivers())
336 return TQStringList();
337
338 if (d_int->m_services.isEmpty() && d_int->error())
339 return TQStringList();
340 return d_int->m_services.keys();
341}
342
344{
345 driversInfo();
346 KexiDB::Driver::Info i = d_int->driverInfo(name);
347 if (d_int->error())
348 setError(d_int);
349 return i;
350}
351
352KService::Ptr DriverManager::serviceInfo(const TQString &name)
353{
354 if (!d_int->lookupDrivers()) {
355 setError(d_int);
356 return KService::Ptr();
357 }
358
359 clearError();
360 if (d_int->m_services_lcase.contains(name.lower())) {
361 return *d_int->m_services_lcase.find(name.lower());
362 } else {
363 setError(ERR_DRIVERMANAGER, i18n("No such driver service: \"%1\".").arg(name) );
364 return KService::Ptr();
365 }
366}
367
368const DriverManager::ServicesMap& DriverManager::services()
369{
370 d_int->lookupDrivers();
371
372 return d_int->m_services;
373}
374
375TQString DriverManager::lookupByMime(const TQString &mimeType)
376{
377 if (!d_int->lookupDrivers()) {
378 setError(d_int);
379 return 0;
380 }
381
382 KService::Ptr ptr = d_int->m_services_by_mimetype[mimeType.lower()];
383 if (!ptr)
384 return TQString();
385 return ptr->property("X-Kexi-DriverName").toString();
386}
387
388Driver* DriverManager::driver(const TQString& name)
389{
390 Driver *drv = d_int->driver(name);
391 if (d_int->error())
392 setError(d_int);
393 return drv;
394}
395
397{
398 return d_int->m_serverErrMsg;
399}
400
402{
403 return d_int->m_serverResultNum;
404}
405
407{
408 return d_int->m_serverResultName;
409}
410
412{
413 d_int->m_serverErrMsg=TQString();
414 d_int->m_serverResultNum=0;
415 d_int->m_serverResultName=TQString();
416}
417
419{
420 if (d_int->possibleProblems.isEmpty())
421 return TQString();
422 TQString str;
423 str.reserve(1024);
424 str = "<ul>";
425 for (TQStringList::ConstIterator it = d_int->possibleProblems.constBegin();
426 it!=d_int->possibleProblems.constEnd(); ++it)
427 {
428 str += (TQString::fromLatin1("<li>") + *it + TQString::fromLatin1("</li>"));
429 }
430 str += "</ul>";
431 return str;
432}
433
434#include "drivermanager_p.moc"
435
virtual void drv_clearServerResult()
const KexiDB::Driver::InfoMap driversInfo()
const TQStringList driverNames()
TQString possibleProblemsInfoMsg() const
Driver * driver(const TQString &name)
KService::Ptr serviceInfo(const TQString &name)
const ServicesMap & services()
KexiDB::Driver::Info driverInfo(const TQString &name)
virtual TQString serverResultName()
TQString lookupByMime(const TQString &mimeType)
virtual TQString serverErrorMsg()
server error is set if there is error at KService level (useful for debugging)
bool fileBased
true is the driver is for file-based database backend
Definition driver.h:78
Generic database abstraction.
Definition driver.h:67
virtual bool isValid()
virtual void clearError()
Definition object.cpp:131
virtual void setError(int code=ERR_OTHER, const TQString &msg=TQString())
Definition object.cpp:53
High-level database connectivity library with database backend drivers.
KEXI_DB_EXPORT DatabaseVersionInfo version()
Definition global.cpp:55