kexi

utils.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2004-2006 Jaroslaw Staniek <js@iidea.pl>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <kexidb/utils.h>
00021 #include <kexidb/cursor.h>
00022 #include <kexidb/drivermanager.h>
00023 
00024 #include <qmap.h>
00025 #include <qthread.h>
00026 
00027 #include <kdebug.h>
00028 #include <klocale.h>
00029 #include <kstaticdeleter.h>
00030 #include <kmessagebox.h>
00031 
00032 #include "utils_p.h"
00033 
00034 using namespace KexiDB;
00035 
00037 struct TypeCache
00038 {
00039     QMap< uint, TypeGroupList > tlist;
00040     QMap< uint, QStringList > nlist;
00041     QMap< uint, QStringList > slist;
00042     QMap< uint, Field::Type > def_tlist;
00043 };
00044 
00045 static KStaticDeleter<TypeCache> KexiDB_typeCacheDeleter;
00046 TypeCache *KexiDB_typeCache = 0;
00047 
00048 static void initList()
00049 {
00050     KexiDB_typeCacheDeleter.setObject( KexiDB_typeCache, new TypeCache() );
00051 
00052     for (uint t=0; t<=KexiDB::Field::LastType; t++) {
00053         const uint tg = KexiDB::Field::typeGroup( t );
00054         TypeGroupList list;
00055         QStringList name_list, str_list;
00056         if (KexiDB_typeCache->tlist.find( tg )!=KexiDB_typeCache->tlist.end()) {
00057             list = KexiDB_typeCache->tlist[ tg ];
00058             name_list = KexiDB_typeCache->nlist[ tg ];
00059             str_list = KexiDB_typeCache->slist[ tg ];
00060         }
00061         list+= t;
00062         name_list += KexiDB::Field::typeName( t );
00063         str_list += KexiDB::Field::typeString( t );
00064         KexiDB_typeCache->tlist[ tg ] = list;
00065         KexiDB_typeCache->nlist[ tg ] = name_list;
00066         KexiDB_typeCache->slist[ tg ] = str_list;
00067     }
00068 
00069     KexiDB_typeCache->def_tlist[ Field::InvalidGroup ] = Field::InvalidType;
00070     KexiDB_typeCache->def_tlist[ Field::TextGroup ] = Field::Text;
00071     KexiDB_typeCache->def_tlist[ Field::IntegerGroup ] = Field::Integer;
00072     KexiDB_typeCache->def_tlist[ Field::FloatGroup ] = Field::Float;
00073     KexiDB_typeCache->def_tlist[ Field::BooleanGroup ] = Field::Boolean;
00074     KexiDB_typeCache->def_tlist[ Field::DateTimeGroup ] = Field::Date;
00075     KexiDB_typeCache->def_tlist[ Field::BLOBGroup ] = Field::BLOB;
00076 }
00077 
00078 const TypeGroupList KexiDB::typesForGroup(KexiDB::Field::TypeGroup typeGroup)
00079 {
00080     if (!KexiDB_typeCache)
00081         initList();
00082     return KexiDB_typeCache->tlist[ typeGroup ];
00083 }
00084 
00085 QStringList KexiDB::typeNamesForGroup(KexiDB::Field::TypeGroup typeGroup)
00086 {
00087     if (!KexiDB_typeCache)
00088         initList();
00089     return KexiDB_typeCache->nlist[ typeGroup ];
00090 }
00091 
00092 QStringList KexiDB::typeStringsForGroup(KexiDB::Field::TypeGroup typeGroup)
00093 {
00094     if (!KexiDB_typeCache)
00095         initList();
00096     return KexiDB_typeCache->slist[ typeGroup ];
00097 }
00098 
00099 KexiDB::Field::Type KexiDB::defaultTypeForGroup(KexiDB::Field::TypeGroup typeGroup)
00100 {
00101     if (!KexiDB_typeCache)
00102         initList();
00103     return (typeGroup <= Field::LastTypeGroup) ? KexiDB_typeCache->def_tlist[ typeGroup ] : Field::InvalidType;
00104 }
00105 
00106 void KexiDB::getHTMLErrorMesage(Object* obj, QString& msg, QString &details)
00107 {
00108     Connection *conn = 0;
00109     if (!obj || !obj->error()) {
00110         if (dynamic_cast<Cursor*>(obj)) {
00111             conn = dynamic_cast<Cursor*>(obj)->connection();
00112             obj = conn;
00113         }
00114         else {
00115             return;
00116         }
00117     }
00118 //  if (dynamic_cast<Connection*>(obj)) {
00119     //  conn = dynamic_cast<Connection*>(obj);
00120     //}
00121     if (!obj || !obj->error())
00122         return;
00123     //lower level message is added to the details, if there is alread message specified
00124     if (!obj->msgTitle().isEmpty())
00125         msg += "<p>" + obj->msgTitle();
00126     
00127     if (msg.isEmpty())
00128         msg = "<p>" + obj->errorMsg();
00129     else
00130         details += "<p>" + obj->errorMsg();
00131 
00132     if (!obj->serverErrorMsg().isEmpty())
00133         details += "<p><b><nobr>" +i18n("Message from server:") + "</nobr></b><br>" + obj->serverErrorMsg();
00134     if (!obj->recentSQLString().isEmpty())
00135         details += "<p><b><nobr>" +i18n("SQL statement:") + QString("</nobr></b><br><tt>%1</tt>").arg(obj->recentSQLString());
00136     int serverResult;
00137     QString serverResultName;
00138     if (obj->serverResult()!=0) {
00139         serverResult = obj->serverResult();
00140         serverResultName = obj->serverResultName();
00141     }
00142     else {
00143         serverResult = obj->previousServerResult();
00144         serverResultName = obj->previousServerResultName();
00145     }
00146     if (!serverResultName.isEmpty())
00147         details += (QString("<p><b><nobr>")+i18n("Server result name:")+"</nobr></b><br>"+serverResultName);
00148     if (!details.isEmpty() 
00149         && (!obj->serverErrorMsg().isEmpty() || !obj->recentSQLString().isEmpty() || !serverResultName.isEmpty() || serverResult!=0) )
00150     {
00151         details += (QString("<p><b><nobr>")+i18n("Server result number:")+"</nobr></b><br>"+QString::number(serverResult));
00152     }
00153 
00154     if (!details.isEmpty() && !details.startsWith("<qt>")) {
00155         if (details.startsWith("<p>"))
00156             details = QString::fromLatin1("<qt>")+details;
00157         else
00158             details = QString::fromLatin1("<qt><p>")+details;
00159     }
00160 }
00161 
00162 void KexiDB::getHTMLErrorMesage(Object* obj, QString& msg)
00163 {
00164     getHTMLErrorMesage(obj, msg, msg);
00165 }
00166 
00167 void KexiDB::getHTMLErrorMesage(Object* obj, ResultInfo *result)
00168 {
00169     getHTMLErrorMesage(obj, result->msg, result->desc);
00170 }
00171 
00172 int KexiDB::idForObjectName( Connection &conn, const QString& objName, int objType )
00173 {
00174     RowData data;
00175     if (true!=conn.querySingleRecord(QString("select o_id from kexi__objects where lower(o_name)='%1' and o_type=%2")
00176         .arg(objName.lower()).arg(objType), data))
00177         return 0;
00178     bool ok;
00179     int id = data[0].toInt(&ok);
00180     return ok ? id : 0;
00181 }
00182 
00183 //-----------------------------------------
00184 
00185 TableOrQuerySchema::TableOrQuerySchema(Connection *conn, const QCString& name, bool table)
00186  : m_name(name)
00187  , m_table(table ? conn->tableSchema(QString(name)) : 0)
00188  , m_query(table ? 0 : conn->querySchema(QString(name)))
00189 {
00190     if (table && !m_table)
00191         kdWarning() << "TableOrQuery(Connection *conn, const QCString& name, bool table) : "
00192             "no table specified!" << endl;
00193     if (!table && !m_query)
00194         kdWarning() << "TableOrQuery(Connection *conn, const QCString& name, bool table) : "
00195             "no query specified!" << endl;
00196 }
00197 
00198 TableOrQuerySchema::TableOrQuerySchema(FieldList &tableOrQuery)
00199  : m_table(dynamic_cast<TableSchema*>(&tableOrQuery))
00200  , m_query(dynamic_cast<QuerySchema*>(&tableOrQuery))
00201 {
00202     if (!m_table && !m_query)
00203         kdWarning() << "TableOrQuery(FieldList &tableOrQuery) : "
00204             " tableOrQuery is nether table nor query!" << endl;
00205 }
00206 
00207 TableOrQuerySchema::TableOrQuerySchema(Connection *conn, int id)
00208 {
00209     m_table = conn->tableSchema(id);
00210     m_query = m_table ? 0 : conn->querySchema(id);
00211     if (!m_table && !m_query)
00212         kdWarning() << "TableOrQuery(Connection *conn, int id) : no table or query found for id==" 
00213             << id << "!" << endl;
00214 }
00215 
00216 TableOrQuerySchema::TableOrQuerySchema(TableSchema* table)
00217  : m_table(table)
00218  , m_query(0)
00219 {
00220     if (!m_table)
00221         kdWarning() << "TableOrQuery(TableSchema* table) : no table specified!" << endl;
00222 }
00223 
00224 TableOrQuerySchema::TableOrQuerySchema(QuerySchema* query)
00225  : m_table(0)
00226  , m_query(query)
00227 {
00228     if (!m_query)
00229         kdWarning() << "TableOrQuery(QuerySchema* query) : no query specified!" << endl;
00230 }
00231 
00232 const QueryColumnInfo::Vector TableOrQuerySchema::columns(bool unique)
00233 {
00234     if (m_table)
00235         return m_table->query()->fieldsExpanded();
00236     
00237     if (m_query)
00238         return m_query->fieldsExpanded(unique);
00239 
00240     kdWarning() << "TableOrQuery::fields() : no query or table specified!" << endl;
00241     return QueryColumnInfo::Vector();
00242 }
00243 
00244 QCString TableOrQuerySchema::name() const
00245 {
00246     if (m_table)
00247         return m_table->name().latin1();
00248     if (m_query)
00249         return m_query->name().latin1();
00250     return m_name;
00251 }
00252 
00253 QString TableOrQuerySchema::captionOrName() const
00254 {
00255     SchemaData *sdata = m_table ? static_cast<SchemaData *>(m_table) : static_cast<SchemaData *>(m_query);
00256     if (!sdata)
00257         return m_name;
00258     return sdata->caption().isEmpty() ? sdata->name() : sdata->caption();
00259 }
00260 
00261 Field* TableOrQuerySchema::field(const QString& name)
00262 {
00263     if (m_table)
00264         return m_table->field(name);
00265     if (m_query)
00266         return m_query->field(name);
00267 
00268     return 0;
00269 }
00270 
00271 QueryColumnInfo* TableOrQuerySchema::columnInfo(const QString& name)
00272 {
00273     if (m_table)
00274         return m_table->query()->columnInfo(name);
00275     
00276     if (m_query)
00277         return m_query->columnInfo(name);
00278 
00279     return 0;
00280 }
00281 
00282 QString TableOrQuerySchema::debugString()
00283 {
00284     if (m_table)
00285         return m_table->debugString();
00286     else if (m_query)
00287         return m_query->debugString();
00288     return QString::null;
00289 }
00290 
00291 void TableOrQuerySchema::debug()
00292 {
00293     if (m_table)
00294         return m_table->debug();
00295     else if (m_query)
00296         return m_query->debug();
00297 }
00298 
00299 Connection* TableOrQuerySchema::connection() const
00300 {
00301     if (m_table)
00302         return m_table->connection();
00303     else if (m_query)
00304         return m_query->connection();
00305     return 0;
00306 }
00307 
00308 
00309 //------------------------------------------
00310 
00311 class ConnectionTestThread : public QThread {
00312     public:
00313         ConnectionTestThread(ConnectionTestDialog *dlg, const KexiDB::ConnectionData& connData);
00314         virtual void run();
00315     protected:
00316         ConnectionTestDialog* m_dlg;
00317         KexiDB::ConnectionData m_connData;
00318 };
00319 
00320 ConnectionTestThread::ConnectionTestThread(ConnectionTestDialog* dlg, const KexiDB::ConnectionData& connData)
00321  : m_dlg(dlg), m_connData(connData)
00322 {
00323 }
00324 
00325 void ConnectionTestThread::run()
00326 {
00327     KexiDB::DriverManager manager;
00328     KexiDB::Driver* drv = manager.driver(m_connData.driverName);
00329 //  KexiGUIMessageHandler msghdr;
00330     if (!drv || manager.error()) {
00331 //move      msghdr.showErrorMessage(&Kexi::driverManager());
00332         m_dlg->error(&manager);
00333         return;
00334     }
00335     KexiDB::Connection * conn = drv->createConnection(m_connData);
00336     if (!conn || drv->error()) {
00337 //move      msghdr.showErrorMessage(drv);
00338         delete conn;
00339         m_dlg->error(drv);
00340         return;
00341     }
00342     if (!conn->connect() || conn->error()) {
00343 //move      msghdr.showErrorMessage(conn);
00344         m_dlg->error(conn);
00345         delete conn;
00346         return;
00347     }
00348     // SQL database backends like PostgreSQL require executing "USE database" 
00349     // if we really want to know connection to the server succeeded.
00350     QString tmpDbName;
00351     if (!conn->useTemporaryDatabaseIfNeeded( tmpDbName )) {
00352         m_dlg->error(conn);
00353         delete conn;
00354         return;
00355     }
00356     delete conn;
00357     m_dlg->error(0);
00358 }
00359 
00360 ConnectionTestDialog::ConnectionTestDialog(QWidget* parent, 
00361     const KexiDB::ConnectionData& data,
00362     KexiDB::MessageHandler& msgHandler)
00363  : KProgressDialog(parent, "testconn_dlg",
00364     i18n("Test Connection"), i18n("<qt>Testing connection to <b>%1</b> database server...</qt>")
00365     .arg(data.serverInfoString(true)), true /*modal*/)
00366  , m_thread(new ConnectionTestThread(this, data))
00367  , m_connData(data)
00368  , m_msgHandler(&msgHandler)
00369  , m_elapsedTime(0)
00370  , m_errorObj(0)
00371  , m_stopWaiting(false)
00372 {
00373     showCancelButton(true);
00374     progressBar()->setPercentageVisible(false);
00375     progressBar()->setTotalSteps(0);
00376     connect(&m_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
00377     adjustSize();
00378     resize(250, height());
00379 }
00380 
00381 ConnectionTestDialog::~ConnectionTestDialog()
00382 {
00383     m_wait.wakeAll();
00384     m_thread->terminate();
00385     delete m_thread;
00386 }
00387 
00388 int ConnectionTestDialog::exec()
00389 {
00390     m_timer.start(20);
00391     m_thread->start();
00392     const int res = KProgressDialog::exec();
00393     m_thread->wait();
00394     m_timer.stop();
00395     return res;
00396 }
00397 
00398 void ConnectionTestDialog::slotTimeout()
00399 {
00400 //  KexiDBDbg << "ConnectionTestDialog::slotTimeout() " << m_errorObj << endl;
00401     bool notResponding = false;
00402     if (m_elapsedTime >= 1000*5) {//5 seconds
00403         m_stopWaiting = true;
00404         notResponding = true;
00405     }
00406     if (m_stopWaiting) {
00407         m_timer.disconnect(this);
00408         m_timer.stop();
00409         slotCancel();
00410 //      reject();
00411 //      close();
00412         if (m_errorObj) {
00413             m_msgHandler->showErrorMessage(m_errorObj);
00414             m_errorObj = 0;
00415         }
00416         else if (notResponding) {
00417             KMessageBox::sorry(0, 
00418                 i18n("<qt>Test connection to <b>%1</b> database server failed. The server is not responding.</qt>")
00419                     .arg(m_connData.serverInfoString(true)),
00420                 i18n("Test Connection"));
00421         }
00422         else {
00423             KMessageBox::information(0, 
00424                 i18n("<qt>Test connection to <b>%1</b> database server established successfully.</qt>")
00425                     .arg(m_connData.serverInfoString(true)),
00426                 i18n("Test Connection"));
00427         }
00428 //      slotCancel();
00429 //      reject();
00430         m_wait.wakeAll();
00431         return;
00432     }
00433     m_elapsedTime += 20;
00434     progressBar()->setProgress( m_elapsedTime );
00435 }
00436 
00437 void ConnectionTestDialog::error(KexiDB::Object *obj)
00438 {
00439     KexiDBDbg << "ConnectionTestDialog::error()" << endl;
00440     m_stopWaiting = true;
00441     m_errorObj = obj;
00442 /*      reject();
00443         m_msgHandler->showErrorMessage(obj);
00444     if (obj) {
00445     }
00446     else {
00447         accept();
00448     }*/
00449     m_wait.wait();
00450 }
00451 
00452 void ConnectionTestDialog::slotCancel()
00453 {
00454 //  m_wait.wakeAll();
00455     m_thread->terminate();
00456     m_timer.disconnect(this);
00457     m_timer.stop();
00458     KProgressDialog::slotCancel();
00459 }
00460 
00461 void KexiDB::connectionTestDialog(QWidget* parent, const KexiDB::ConnectionData& data, 
00462     KexiDB::MessageHandler& msgHandler)
00463 {
00464     ConnectionTestDialog dlg(parent, data, msgHandler);
00465     dlg.exec();
00466 }
00467 
00468 int KexiDB::rowCount(const KexiDB::TableSchema& tableSchema)
00469 {
00471     if (!tableSchema.connection()) {
00472         KexiDBWarn << "KexiDB::rowsCount(const KexiDB::TableSchema&): no tableSchema.connection() !" << endl;
00473         return -1;
00474     }
00475     int count = -1; //will be changed only on success of querySingleNumber()
00476     tableSchema.connection()->querySingleNumber(
00477         QString::fromLatin1("SELECT COUNT() FROM ") 
00478         + tableSchema.connection()->driver()->escapeIdentifier(tableSchema.name()), 
00479         count
00480     );
00481     return count;
00482 }
00483 
00484 int KexiDB::rowCount(KexiDB::QuerySchema& querySchema)
00485 {
00487     if (!querySchema.connection()) {
00488         KexiDBWarn << "KexiDB::rowsCount(const KexiDB::QuerySchema&): no querySchema.connection() !" << endl;
00489         return -1;
00490     }
00491     int count = -1; //will be changed only on success of querySingleNumber()
00492     querySchema.connection()->querySingleNumber(
00493         QString::fromLatin1("SELECT COUNT() FROM (") 
00494         + querySchema.connection()->selectStatement(querySchema) + ")",
00495         count
00496     );
00497     return count;
00498 }
00499 
00500 int KexiDB::rowCount(KexiDB::TableOrQuerySchema& tableOrQuery)
00501 {
00502     if (tableOrQuery.table())
00503         return rowCount( *tableOrQuery.table() );
00504     if (tableOrQuery.query())
00505         return rowCount( *tableOrQuery.query() );
00506     return -1;
00507 }
00508 
00509 int KexiDB::fieldCount(KexiDB::TableOrQuerySchema& tableOrQuery)
00510 {
00511     if (tableOrQuery.table())
00512         return tableOrQuery.table()->fieldCount();
00513     if (tableOrQuery.query())
00514         return tableOrQuery.query()->fieldsExpanded().count();
00515     return -1;
00516 }
00517 
00518 QMap<QString,QString> KexiDB::toMap( const ConnectionData& data )
00519 {
00520     QMap<QString,QString> m;
00521     m["caption"] = data.caption;
00522     m["description"] = data.description;
00523     m["driverName"] = data.driverName;
00524     m["hostName"] = data.hostName;
00525     m["port"] = QString::number(data.port);
00526     m["useLocalSocketFile"] = QString::number((int)data.useLocalSocketFile);
00527     m["localSocketFileName"] = data.localSocketFileName;
00528     m["password"] = data.password;
00529     m["savePassword"] = QString::number((int)data.savePassword);
00530     m["userName"] = data.userName;
00531     m["fileName"] = data.fileName();
00532     return m;
00533 }
00534 
00535 void KexiDB::fromMap( const QMap<QString,QString>& map, ConnectionData& data )
00536 {
00537     data.caption = map["caption"];
00538     data.description = map["description"];
00539     data.driverName = map["driverName"];
00540     data.hostName = map["hostName"];
00541     data.port = map["port"].toInt();
00542     data.useLocalSocketFile = map["useLocalSocketFile"].toInt()==1;
00543     data.localSocketFileName = map["localSocketFileName"];
00544     data.password = map["password"];
00545     data.savePassword = map["savePassword"].toInt()==1;
00546     data.userName = map["userName"];
00547     data.setFileName(map["fileName"]);
00548 }
00549 
00550 bool KexiDB::splitToTableAndFieldParts(const QString& string, 
00551     QString& tableName, QString& fieldName,
00552     SetFieldNameIfNoTableNameOptions option)
00553 {
00554     const int id = string.find('.');
00555     if (option & SetFieldNameIfNoTableName && id==-1) {
00556         tableName = QString::null;
00557         fieldName = string;
00558         return true;
00559     }
00560     if (id<=0 || id==int(string.length()-1))
00561         return false;
00562     tableName = string.left(id);
00563     fieldName = string.mid(id+1);
00564     return true;
00565 }
00566 
00567 #include "utils_p.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys