src/qt3support/sql/q3sqlmanager_p.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the Qt3Support module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #include "q3sqlmanager_p.h"
00025 
00026 #ifndef QT_NO_SQL
00027 
00028 #include "qapplication.h"
00029 #include "qcursor.h"
00030 #include "qwidget.h"
00031 #include "q3sqlcursor.h"
00032 #include "qsqlfield.h"
00033 #include "q3sqlform.h"
00034 #include "qsqldriver.h"
00035 #include "qstring.h"
00036 #include "qmessagebox.h"
00037 #include "qbitarray.h"
00038 
00039 //#define QT_DEBUG_DATAMANAGER
00040 
00041 class Q3SqlCursorManagerPrivate
00042 {
00043 public:
00044     Q3SqlCursorManagerPrivate()
00045         : cur(0), autoDelete(false)
00046     {}
00047 
00048     QString ftr;
00049     QStringList srt;
00050     Q3SqlCursor* cur;
00051     bool autoDelete;
00052 };
00053 
00054 static QSqlIndex indexFromStringList(const QStringList& l, const Q3SqlCursor* cursor)
00055 {
00056     QSqlIndex newSort;
00057     for (int i = 0; i < l.count(); ++i) {
00058         QString f = l[i];
00059         bool desc = false;
00060         if (f.mid(f.length()-3) == "ASC")
00061             f = f.mid(0, f.length()-3);
00062         if (f.mid(f.length()-4) == "DESC") {
00063             desc = true;
00064             f = f.mid(0, f.length()-4);
00065         }
00066         int dot = f.lastIndexOf(QChar('.'));
00067         if (dot != -1)
00068             f = f.mid(dot+1);
00069         const QSqlField field = cursor->field(f.trimmed());
00070         if (field.isValid())
00071             newSort.append(field, desc);
00072         else
00073             qWarning("QSqlIndex::indexFromStringList: unknown field: '%s'", f.latin1());
00074     }
00075     return newSort;
00076 }
00077 
00078 
00099 Q3SqlCursorManager::Q3SqlCursorManager()
00100 {
00101     d = new Q3SqlCursorManagerPrivate;
00102 }
00103 
00104 
00111 Q3SqlCursorManager::~Q3SqlCursorManager()
00112 {
00113     if (d->autoDelete)
00114         delete d->cur;
00115     delete d;
00116 }
00117 
00125 void Q3SqlCursorManager::setSort(const QSqlIndex& sort)
00126 {
00127     setSort(sort.toStringList());
00128 }
00129 
00137 void Q3SqlCursorManager::setSort(const QStringList& sort)
00138 {
00139     d->srt = sort;
00140 }
00141 
00148 QStringList  Q3SqlCursorManager::sort() const
00149 {
00150     return d->srt;
00151 }
00152 
00160 void Q3SqlCursorManager::setFilter(const QString& filter)
00161 {
00162     d->ftr = filter;
00163 }
00164 
00171 QString Q3SqlCursorManager::filter() const
00172 {
00173     return d->ftr;
00174 }
00175 
00184 void Q3SqlCursorManager::setAutoDelete(bool enable)
00185 {
00186     d->autoDelete = enable;
00187 }
00188 
00189 
00198 bool Q3SqlCursorManager::autoDelete() const
00199 {
00200     return d->autoDelete;
00201 }
00202 
00215 void Q3SqlCursorManager::setCursor(Q3SqlCursor* cursor, bool autoDelete)
00216 {
00217     if (d->autoDelete)
00218         delete d->cur;
00219     d->cur = cursor;
00220     d->autoDelete = autoDelete;
00221 }
00222 
00232 Q3SqlCursor* Q3SqlCursorManager::cursor() const
00233 {
00234     return d->cur;
00235 }
00236 
00237 
00248 bool Q3SqlCursorManager::refresh()
00249 {
00250     Q3SqlCursor* cur = cursor();
00251     if (!cur)
00252         return false;
00253     QString currentFilter = d->ftr;
00254     QStringList currentSort = d->srt;
00255     QSqlIndex newSort = indexFromStringList(currentSort, cur);
00256     return cur->select(currentFilter, newSort);
00257 }
00258 
00259 /* \internal
00260 
00261    Returns true if the \a buf field values that correspond to \a idx
00262    match the field values in \a cur that correspond to \a idx.
00263 */
00264 
00265 static bool index_matches(const Q3SqlCursor* cur, const QSqlRecord* buf,
00266                            const QSqlIndex& idx)
00267 {
00268     bool indexEquals = false;
00269     for (int i = 0; i < idx.count(); ++i) {
00270         const QString fn(idx.field(i).name());
00271         if (cur->value(fn) == buf->value(fn))
00272             indexEquals = true;
00273         else {
00274             indexEquals = false;
00275             break;
00276         }
00277     }
00278     return indexEquals;
00279 }
00280 
00281 /*
00282   Return less than, equal to or greater than 0 if buf1 is less than,
00283   equal to or greater than buf2 according to fields described in idx.
00284   (### Currently only uses first field.)
00285 */
00286 
00287 static int compare_recs(const QSqlRecord* buf1, const QSqlRecord* buf2,
00288                          const QSqlIndex& idx)
00289 {
00290     int cmp = 0;
00291 
00292     int i = 0;
00293     const QString fn(idx.field(i).name());
00294     const QSqlField f1 = buf1->field(fn);
00295 
00296     if (f1.isValid()) {
00297         switch (f1.type()) { // ### more types?
00298         case QVariant::String:
00299             cmp = f1.value().toString().trimmed().compare(
00300                           buf2->value(fn).toString().trimmed());
00301             break;
00302         default:
00303             if (f1.value().toDouble() < buf2->value(fn).toDouble())
00304                 cmp = -1;
00305             else if (f1.value().toDouble() > buf2->value(fn).toDouble())
00306                 cmp = 1;
00307         }
00308     }
00309 
00310     if (idx.isDescending(i))
00311         cmp = -cmp;
00312     return cmp;
00313 }
00314 
00315 #ifdef QT_DEBUG_DATAMANAGER
00316 static void debug_datamanager_buffer(const QString& msg, QSqlRecord* cursor)
00317 {
00318     qDebug("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
00319     qDebug("%s", msg.latin1());
00320     for (int j = 0; j < cursor->count(); ++j) {
00321         qDebug("%s", (cursor->field(j)->name() + " type:"
00322                        + QString(cursor->field(j)->value().typeName())
00323                        + " value:" + cursor->field(j)->value().toString())
00324                        .latin1());
00325     }
00326 }
00327 #endif
00328 
00329 
00355 //## possibly add sizeHint parameter
00356 bool Q3SqlCursorManager::findBuffer(const QSqlIndex& idx, int atHint)
00357 {
00358 #ifdef QT_DEBUG_DATAMANAGER
00359     qDebug("Q3SqlCursorManager::findBuffer:");
00360 #endif
00361     Q3SqlCursor* cur = cursor();
00362     if (!cur)
00363         return false;
00364     if (!cur->isActive())
00365         return false;
00366     if (!idx.count()) {
00367         if (cur->at() == QSql::BeforeFirst)
00368             cur->next();
00369         return false;
00370     }
00371     QSqlRecord* buf = cur->editBuffer();
00372     bool indexEquals = false;
00373 #ifdef QT_DEBUG_DATAMANAGER
00374     qDebug(" Checking hint...");
00375 #endif
00376     /* check the hint */
00377     if (cur->seek(atHint))
00378         indexEquals = index_matches(cur, buf, idx);
00379 
00380     if (!indexEquals) {
00381 #ifdef QT_DEBUG_DATAMANAGER
00382         qDebug(" Checking current page...");
00383 #endif
00384         /* check current page */
00385         int pageSize = 20;
00386         int startIdx = qMax(atHint - pageSize, 0);
00387         int endIdx = atHint + pageSize;
00388         for (int j = startIdx; j <= endIdx; ++j) {
00389             if (cur->seek(j)) {
00390                 indexEquals = index_matches(cur, buf, idx);
00391                 if (indexEquals)
00392                     break;
00393             }
00394         }
00395     }
00396 
00397     if (!indexEquals && cur->driver()->hasFeature(QSqlDriver::QuerySize)
00398          && cur->sort().count()) {
00399 #ifdef QT_DEBUG_DATAMANAGER
00400         qDebug(" Using binary search...");
00401 #endif
00402         // binary search based on record buffer and current sort fields
00403         int lo = 0;
00404         int hi = cur->size();
00405         int mid;
00406         if (compare_recs(buf, cur, cur->sort()) >= 0)
00407             lo = cur->at();
00408         while (lo != hi) {
00409             mid = lo + (hi - lo) / 2;
00410             if (!cur->seek(mid))
00411                 break;
00412             if (index_matches(cur, buf, idx)) {
00413                 indexEquals = true;
00414                 break;
00415             }
00416             int c = compare_recs(buf, cur, cur->sort());
00417             if (c < 0) {
00418                 hi = mid;
00419             } else if (c == 0) {
00420                 // found it, but there may be duplicates
00421                 int at = mid;
00422                 do {
00423                     mid--;
00424                     if (!cur->seek(mid))
00425                         break;
00426                     if (index_matches(cur, buf, idx)) {
00427                         indexEquals = true;
00428                         break;
00429                     }
00430                 } while (compare_recs(buf, cur, cur->sort()) == 0);
00431 
00432                 if (!indexEquals) {
00433                     mid = at;
00434                     do {
00435                         mid++;
00436                         if (!cur->seek(mid))
00437                             break;
00438                         if (index_matches(cur, buf, idx)) {
00439                             indexEquals = true;
00440                             break;
00441                         }
00442                     } while (compare_recs(buf, cur, cur->sort()) == 0);
00443                 }
00444                 break;
00445             } else if (c > 0) {
00446                 lo = mid + 1;
00447             }
00448         }
00449     }
00450 
00451     if (!indexEquals) {
00452 #ifdef QT_DEBUG_DATAMANAGER
00453         qDebug(" Using brute search...");
00454 #endif
00455 #ifndef QT_NO_CURSOR
00456         QApplication::setOverrideCursor(Qt::WaitCursor);
00457 #endif
00458         /* give up, use brute force */
00459         int startIdx = 0;
00460         if (cur->at() != startIdx) {
00461             cur->seek(startIdx);
00462         }
00463         for (;;) {
00464             indexEquals = false;
00465             indexEquals = index_matches(cur, buf, idx);
00466             if (indexEquals)
00467                 break;
00468             if (!cur->next())
00469                 break;
00470         }
00471 #ifndef QT_NO_CURSOR
00472         QApplication::restoreOverrideCursor();
00473 #endif
00474     }
00475 #ifdef QT_DEBUG_DATAMANAGER
00476         qDebug(" Done, result:" + QString::number(indexEquals));
00477 #endif
00478     return indexEquals;
00479 }
00480 
00481 #ifndef QT_NO_SQL_FORM
00482 
00483 class Q3SqlFormManagerPrivate
00484 {
00485 public:
00486     Q3SqlFormManagerPrivate() : frm(0), rcd(0) {}
00487     Q3SqlForm* frm;
00488     QSqlRecord* rcd;
00489 };
00490 
00491 
00498 Q3SqlFormManager::Q3SqlFormManager()
00499 {
00500     d = new Q3SqlFormManagerPrivate();
00501 }
00502 
00509 Q3SqlFormManager::~Q3SqlFormManager()
00510 {
00511     delete d;
00512 }
00513 
00521 void Q3SqlFormManager::clearValues()
00522 {
00523     if (form())
00524         form()->clearValues();
00525 }
00526 
00537 void Q3SqlFormManager::setForm(Q3SqlForm* form)
00538 {
00539     d->frm = form;
00540     if (d->rcd && d->frm)
00541         d->frm->setRecord(d->rcd);
00542 }
00543 
00544 
00554 Q3SqlForm* Q3SqlFormManager::form()
00555 {
00556     return d->frm;
00557 }
00558 
00559 
00570 void Q3SqlFormManager::setRecord(QSqlRecord* record)
00571 {
00572     d->rcd = record;
00573     if (d->frm) {
00574         d->frm->setRecord(d->rcd);
00575     }
00576 }
00577 
00578 
00587 QSqlRecord* Q3SqlFormManager::record()
00588 {
00589     return d->rcd;
00590 }
00591 
00592 
00602 void Q3SqlFormManager::readFields()
00603 {
00604     if (d->frm) {
00605         d->frm->readFields();
00606     }
00607 }
00608 
00618 void Q3SqlFormManager::writeFields()
00619 {
00620     if (d->frm) {
00621         d->frm->writeFields();
00622     }
00623 }
00624 
00625 #endif // QT_NO_SQL_FORM
00626 
00627 class Q3DataManagerPrivate
00628 {
00629 public:
00630     Q3DataManagerPrivate()
00631         : mode(QSql::None), autoEd(true), confEdits(3),
00632           confCancs(false) {}
00633     QSql::Op mode;
00634     bool autoEd;
00635     QBitArray confEdits;
00636     bool confCancs;
00637 
00638 };
00639 
00661 Q3DataManager::Q3DataManager()
00662 {
00663     d = new Q3DataManagerPrivate();
00664 }
00665 
00666 
00673 Q3DataManager::~Q3DataManager()
00674 {
00675     delete d;
00676 }
00677 
00678 
00686 void Q3DataManager::handleError(QWidget* parent, const QSqlError& e)
00687 {
00688 #ifndef QT_NO_MESSAGEBOX
00689     if (e.driverText().isEmpty() && e.databaseText().isEmpty()) {
00690         QMessageBox::warning (parent, "Warning", "An error occurred while accessing the database");
00691     } else {
00692         QMessageBox::warning (parent, "Warning", e.driverText() + "\n" + e.databaseText(),
00693                            0, 0);
00694     }
00695 #endif // QT_NO_MESSAGEBOX
00696 }
00697 
00698 
00705 void Q3DataManager::setMode(QSql::Op m)
00706 {
00707     d->mode = m;
00708 }
00709 
00710 
00717 QSql::Op Q3DataManager::mode() const
00718 {
00719     return d->mode;
00720 }
00721 
00722 
00729 void Q3DataManager::setAutoEdit(bool autoEdit)
00730 {
00731     d->autoEd = autoEdit;
00732 }
00733 
00734 
00735 
00742 bool Q3DataManager::autoEdit() const
00743 {
00744     return d->autoEd;
00745 }
00746 
00754 void Q3DataManager::setConfirmEdits(bool confirm)
00755 {
00756     d->confEdits = QBitArray(d->confEdits.size(), confirm);
00757 }
00758 
00767 void Q3DataManager::setConfirmInsert(bool confirm)
00768 {
00769     d->confEdits[QSql::Insert] = confirm;
00770 }
00771 
00780 void Q3DataManager::setConfirmUpdate(bool confirm)
00781 {
00782     d->confEdits[QSql::Update] = confirm;
00783 }
00784 
00793 void Q3DataManager::setConfirmDelete(bool confirm)
00794 {
00795     d->confEdits[QSql::Delete] = confirm;
00796 }
00797 
00804 bool Q3DataManager::confirmEdits() const
00805 {
00806     return (confirmInsert() && confirmUpdate() && confirmDelete());
00807 }
00808 
00815 bool Q3DataManager::confirmInsert() const
00816 {
00817     return d->confEdits[QSql::Insert];
00818 }
00819 
00826 bool Q3DataManager::confirmUpdate() const
00827 {
00828     return d->confEdits[QSql::Update];
00829 }
00830 
00837 bool Q3DataManager::confirmDelete() const
00838 {
00839     return d->confEdits[QSql::Delete];
00840 }
00841 
00849 void Q3DataManager::setConfirmCancels(bool confirm)
00850 {
00851     d->confCancs = confirm;
00852 }
00853 
00859 bool Q3DataManager::confirmCancels() const
00860 {
00861     return d->confCancs;
00862 }
00863 
00874 QSql::Confirm Q3DataManager::confirmEdit(QWidget* parent, QSql::Op m)
00875 {
00876     int ans = 2;
00877     if (m == QSql::Delete) {
00878 #ifndef QT_NO_MESSAGEBOX
00879         ans = QMessageBox::information(parent,
00880                                         qApp->translate("QSql", "Delete"),
00881                                         qApp->translate("QSql", "Delete this record?"),
00882                                         qApp->translate("QSql", "Yes"),
00883                                         qApp->translate("QSql", "No"),
00884                                         QString(), 0, 1);
00885 #else
00886         ans = QSql::No;
00887 #endif // QT_NO_MESSAGEBOX
00888     } else if (m != QSql::None) {
00889         QString caption;
00890         if (m == QSql::Insert) {
00891             caption = qApp->translate("QSql", "Insert");
00892         } else { // QSql::Update
00893             caption = qApp->translate("QSql", "Update");
00894         }
00895 #ifndef QT_NO_MESSAGEBOX
00896         ans = QMessageBox::information(parent, caption,
00897                                         qApp->translate("QSql", "Save edits?"),
00898                                         qApp->translate("QSql", "Yes"),
00899                                         qApp->translate("QSql", "No"),
00900                                         qApp->translate("QSql", "Cancel"),
00901                                         0, 2);
00902 #else
00903         ans = QSql::No;
00904 #endif // QT_NO_MESSAGEBOX
00905     }
00906 
00907     switch (ans) {
00908     case 0:
00909         return QSql::Yes;
00910     case 1:
00911         return QSql::No;
00912     default:
00913         return QSql::Cancel;
00914     }
00915 }
00916 
00928 QSql::Confirm Q3DataManager::confirmCancel(QWidget* parent, QSql::Op)
00929 {
00930 #ifndef QT_NO_MESSAGEBOX
00931     switch (QMessageBox::information(parent,
00932                                        qApp->translate("QSql", "Confirm"),
00933                                        qApp->translate("QSql", "Cancel your edits?"),
00934                                        qApp->translate("QSql", "Yes"),
00935                                        qApp->translate("QSql", "No"),
00936                                        QString(), 0, 1)) {
00937     case 0:
00938         return QSql::Yes;
00939     case 1:
00940         return QSql::No;
00941     default:
00942         return QSql::Cancel;
00943     }
00944 #else
00945     return QSql::Yes;
00946 #endif // QT_NO_MESSAGEBOX
00947 }
00948 
00949 #endif

Generated on Thu Mar 15 11:58:31 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1