📄 q3sqlmanager_p.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the Qt3Support module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "q3sqlmanager_p.h"#ifndef QT_NO_SQL#include "qapplication.h"#include "qcursor.h"#include "qwidget.h"#include "q3sqlcursor.h"#include "qsqlfield.h"#include "q3sqlform.h"#include "qsqldriver.h"#include "qstring.h"#include "qmessagebox.h"#include "qbitarray.h"//#define QT_DEBUG_DATAMANAGERclass Q3SqlCursorManagerPrivate{public: Q3SqlCursorManagerPrivate() : cur(0), autoDelete(false) {} QString ftr; QStringList srt; Q3SqlCursor* cur; bool autoDelete;};static QSqlIndex indexFromStringList(const QStringList& l, const Q3SqlCursor* cursor){ QSqlIndex newSort; for (int i = 0; i < l.count(); ++i) { QString f = l[i]; bool desc = false; if (f.mid(f.length()-3) == QLatin1String("ASC")) f = f.mid(0, f.length()-3); if (f.mid(f.length()-4) == QLatin1String("DESC")) { desc = true; f = f.mid(0, f.length()-4); } int dot = f.lastIndexOf(QLatin1Char('.')); if (dot != -1) f = f.mid(dot+1); const QSqlField field = cursor->field(f.trimmed()); if (field.isValid()) newSort.append(field, desc); else qWarning("QSqlIndex::indexFromStringList: unknown field: '%s'", f.latin1()); } return newSort;}/*! \class Q3SqlCursorManager qsqlmanager_p.h \brief The Q3SqlCursorManager class manages a database cursor. \compat \internal This class provides common cursor management functionality. This includes saving and applying sorts and filters, refreshing (i.e., re-selecting) the cursor and searching for records within the cursor.*//*! \internal Constructs a cursor manager.*/Q3SqlCursorManager::Q3SqlCursorManager(){ d = new Q3SqlCursorManagerPrivate;}/*! \internal Destroys the object and frees any allocated resources.*/Q3SqlCursorManager::~Q3SqlCursorManager(){ if (d->autoDelete) delete d->cur; delete d;}/*! \internal Sets the manager's sort to the index \a sort. To apply the new sort, use refresh(). */void Q3SqlCursorManager::setSort(const QSqlIndex& sort){ setSort(sort.toStringList());}/*! \internal Sets the manager's sort to the stringlist \a sort. To apply the new sort, use refresh(). */void Q3SqlCursorManager::setSort(const QStringList& sort){ d->srt = sort;}/*! \internal Returns the current sort, or an empty stringlist if there is none.*/QStringList Q3SqlCursorManager::sort() const{ return d->srt;}/*! \internal Sets the manager's filter to the string \a filter. To apply the new filter, use refresh().*/void Q3SqlCursorManager::setFilter(const QString& filter){ d->ftr = filter;}/*! \internal Returns the current filter, or an empty string if there is none.*/QString Q3SqlCursorManager::filter() const{ return d->ftr;}/*! \internal Sets auto-delete to \a enable. If true, the default cursor will be deleted when necessary. \sa autoDelete()*/void Q3SqlCursorManager::setAutoDelete(bool enable){ d->autoDelete = enable;}/*! \internal Returns true if auto-deletion is enabled, otherwise false. \sa setAutoDelete()*/bool Q3SqlCursorManager::autoDelete() const{ return d->autoDelete;}/*! \internal Sets the default cursor used by the manager to \a cursor. If \a autoDelete is true (the default is false), the manager takes ownership of the \a cursor pointer, which will be deleted when the manager is destroyed, or when setCursor() is called again. To activate the \a cursor use refresh(). \sa cursor()*/void Q3SqlCursorManager::setCursor(Q3SqlCursor* cursor, bool autoDelete){ if (d->autoDelete) delete d->cur; d->cur = cursor; d->autoDelete = autoDelete;}/*! \internal Returns a pointer to the default cursor used for navigation, or 0 if there is no default cursor. \sa setCursor()*/Q3SqlCursor* Q3SqlCursorManager::cursor() const{ return d->cur;}/*! \internal Refreshes the manager using the default cursor. The manager's filter and sort are applied. Returns true on success, false if an error occurred or there is no current cursor. \sa setFilter() setSort()*/bool Q3SqlCursorManager::refresh(){ Q3SqlCursor* cur = cursor(); if (!cur) return false; QString currentFilter = d->ftr; QStringList currentSort = d->srt; QSqlIndex newSort = indexFromStringList(currentSort, cur); return cur->select(currentFilter, newSort);}/* \internal Returns true if the \a buf field values that correspond to \a idx match the field values in \a cur that correspond to \a idx.*/static bool index_matches(const Q3SqlCursor* cur, const QSqlRecord* buf, const QSqlIndex& idx){ bool indexEquals = false; for (int i = 0; i < idx.count(); ++i) { const QString fn(idx.field(i).name()); if (cur->value(fn) == buf->value(fn)) indexEquals = true; else { indexEquals = false; break; } } return indexEquals;}/* Return less than, equal to or greater than 0 if buf1 is less than, equal to or greater than buf2 according to fields described in idx. (### Currently only uses first field.)*/static int compare_recs(const QSqlRecord* buf1, const QSqlRecord* buf2, const QSqlIndex& idx){ int cmp = 0; int i = 0; const QString fn(idx.field(i).name()); const QSqlField f1 = buf1->field(fn); if (f1.isValid()) { switch (f1.type()) { // ### more types? case QVariant::String: cmp = f1.value().toString().trimmed().compare( buf2->value(fn).toString().trimmed()); break; default: if (f1.value().toDouble() < buf2->value(fn).toDouble()) cmp = -1; else if (f1.value().toDouble() > buf2->value(fn).toDouble()) cmp = 1; } } if (idx.isDescending(i)) cmp = -cmp; return cmp;}#ifdef QT_DEBUG_DATAMANAGERstatic void debug_datamanager_buffer(const QString& msg, QSqlRecord* cursor){ qDebug("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); qDebug("%s", msg.latin1()); for (int j = 0; j < cursor->count(); ++j) { qDebug("%s", (cursor->field(j)->name() + " type:" + QString(cursor->field(j)->value().typeName()) + " value:" + cursor->field(j)->value().toString()) .latin1()); }}#endif/*! \internal Relocates the default cursor to the record matching the cursor'sedit buffer. Only the field names specified by \a idx are used todetermine an exact match of the cursor to the edit buffer. However,other fields in the edit buffer are also used during the search,therefore all fields in the edit buffer should be primed with desiredvalues for the record being sought. This function is typically usedto relocate a cursor to the correct position after an insert orupdate. For example:\code Q3SqlCursor* myCursor = myManager.cursor(); ... QSqlRecord* buf = myCursor->primeUpdate(); buf->setValue("name", "Ola"); buf->setValue("city", "Oslo"); ... myCursor->update(); // update current record myCursor->select(); // refresh the cursor myManager.findBuffer(myCursor->primaryIndex()); // go to the updated record\endcode*///## possibly add sizeHint parameterbool Q3SqlCursorManager::findBuffer(const QSqlIndex& idx, int atHint){#ifdef QT_DEBUG_DATAMANAGER qDebug("Q3SqlCursorManager::findBuffer:");#endif Q3SqlCursor* cur = cursor(); if (!cur) return false; if (!cur->isActive()) return false; if (!idx.count()) { if (cur->at() == QSql::BeforeFirst) cur->next(); return false; } QSqlRecord* buf = cur->editBuffer(); bool indexEquals = false;#ifdef QT_DEBUG_DATAMANAGER qDebug(" Checking hint...");#endif /* check the hint */ if (cur->seek(atHint)) indexEquals = index_matches(cur, buf, idx); if (!indexEquals) {#ifdef QT_DEBUG_DATAMANAGER qDebug(" Checking current page...");#endif /* check current page */ int pageSize = 20; int startIdx = qMax(atHint - pageSize, 0); int endIdx = atHint + pageSize; for (int j = startIdx; j <= endIdx; ++j) { if (cur->seek(j)) { indexEquals = index_matches(cur, buf, idx); if (indexEquals) break; } } } if (!indexEquals && cur->driver()->hasFeature(QSqlDriver::QuerySize) && cur->sort().count()) {#ifdef QT_DEBUG_DATAMANAGER qDebug(" Using binary search...");#endif // binary search based on record buffer and current sort fields int lo = 0; int hi = cur->size(); int mid; if (compare_recs(buf, cur, cur->sort()) >= 0) lo = cur->at(); while (lo != hi) { mid = lo + (hi - lo) / 2; if (!cur->seek(mid)) break; if (index_matches(cur, buf, idx)) { indexEquals = true; break; } int c = compare_recs(buf, cur, cur->sort()); if (c < 0) { hi = mid; } else if (c == 0) { // found it, but there may be duplicates int at = mid; do { mid--; if (!cur->seek(mid)) break; if (index_matches(cur, buf, idx)) { indexEquals = true; break; } } while (compare_recs(buf, cur, cur->sort()) == 0); if (!indexEquals) { mid = at; do { mid++; if (!cur->seek(mid)) break; if (index_matches(cur, buf, idx)) { indexEquals = true; break; } } while (compare_recs(buf, cur, cur->sort()) == 0); } break; } else if (c > 0) { lo = mid + 1; } } } if (!indexEquals) {#ifdef QT_DEBUG_DATAMANAGER qDebug(" Using brute search...");#endif#ifndef QT_NO_CURSOR QApplication::setOverrideCursor(Qt::WaitCursor);#endif /* give up, use brute force */ int startIdx = 0; if (cur->at() != startIdx) { cur->seek(startIdx); } for (;;) { indexEquals = false; indexEquals = index_matches(cur, buf, idx); if (indexEquals) break; if (!cur->next()) break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -