[196] | 1 | /****************************************************************************
|
---|
| 2 | **
|
---|
| 3 | ** Implementation of sql manager classes
|
---|
| 4 | **
|
---|
| 5 | ** Created : 2000-11-03
|
---|
| 6 | **
|
---|
| 7 | ** Copyright (C) 2005-2007 Trolltech ASA. All rights reserved.
|
---|
| 8 | **
|
---|
| 9 | ** This file is part of the sql module of the Qt GUI Toolkit.
|
---|
| 10 | **
|
---|
| 11 | ** This file may be distributed under the terms of the Q Public License
|
---|
| 12 | ** as defined by Trolltech ASA of Norway and appearing in the file
|
---|
| 13 | ** LICENSE.QPL included in the packaging of this file.
|
---|
| 14 | **
|
---|
| 15 | ** This file may be distributed and/or modified under the terms of the
|
---|
| 16 | ** GNU General Public License version 2 as published by the Free Software
|
---|
| 17 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
| 18 | ** packaging of this file.
|
---|
| 19 | **
|
---|
| 20 | ** Licensees holding valid Qt Enterprise Edition licenses may use this
|
---|
| 21 | ** file in accordance with the Qt Commercial License Agreement provided
|
---|
| 22 | ** with the Software.
|
---|
| 23 | **
|
---|
| 24 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
---|
| 25 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
---|
| 26 | **
|
---|
| 27 | ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
|
---|
| 28 | ** information about Qt Commercial License Agreements.
|
---|
| 29 | ** See http://www.trolltech.com/qpl/ for QPL licensing information.
|
---|
| 30 | ** See http://www.trolltech.com/gpl/ for GPL licensing information.
|
---|
| 31 | **
|
---|
| 32 | ** Contact info@trolltech.com if any conditions of this licensing are
|
---|
| 33 | ** not clear to you.
|
---|
| 34 | **
|
---|
| 35 | **********************************************************************/
|
---|
| 36 |
|
---|
| 37 | #include "qsqlmanager_p.h"
|
---|
| 38 |
|
---|
| 39 | #ifndef QT_NO_SQL
|
---|
| 40 |
|
---|
| 41 | #include "qapplication.h"
|
---|
| 42 | #include "qwidget.h"
|
---|
| 43 | #include "qsqlcursor.h"
|
---|
| 44 | #include "qsqlform.h"
|
---|
| 45 | #include "qsqldriver.h"
|
---|
| 46 | #include "qstring.h"
|
---|
| 47 | #include "qmessagebox.h"
|
---|
| 48 | #include "qbitarray.h"
|
---|
| 49 |
|
---|
| 50 | //#define QT_DEBUG_DATAMANAGER
|
---|
| 51 |
|
---|
| 52 | class QSqlCursorManagerPrivate
|
---|
| 53 | {
|
---|
| 54 | public:
|
---|
| 55 | QSqlCursorManagerPrivate()
|
---|
| 56 | : cur( 0 ), autoDelete( FALSE )
|
---|
| 57 | {}
|
---|
| 58 |
|
---|
| 59 | QString ftr;
|
---|
| 60 | QStringList srt;
|
---|
| 61 | QSqlCursor* cur;
|
---|
| 62 | bool autoDelete;
|
---|
| 63 | };
|
---|
| 64 |
|
---|
| 65 | /*!
|
---|
| 66 | \class QSqlCursorManager qsqlmanager_p.h
|
---|
| 67 | \brief The QSqlCursorManager class manages a database cursor.
|
---|
| 68 |
|
---|
| 69 | \module sql
|
---|
| 70 |
|
---|
| 71 | \internal
|
---|
| 72 |
|
---|
| 73 | This class provides common cursor management functionality. This
|
---|
| 74 | includes saving and applying sorts and filters, refreshing (i.e.,
|
---|
| 75 | re-selecting) the cursor and searching for records within the
|
---|
| 76 | cursor.
|
---|
| 77 |
|
---|
| 78 | */
|
---|
| 79 |
|
---|
| 80 | /*! \internal
|
---|
| 81 |
|
---|
| 82 | Constructs a cursor manager.
|
---|
| 83 |
|
---|
| 84 | */
|
---|
| 85 |
|
---|
| 86 | QSqlCursorManager::QSqlCursorManager()
|
---|
| 87 | {
|
---|
| 88 | d = new QSqlCursorManagerPrivate;
|
---|
| 89 | }
|
---|
| 90 |
|
---|
| 91 |
|
---|
| 92 | /*! \internal
|
---|
| 93 |
|
---|
| 94 | Destroys the object and frees any allocated resources.
|
---|
| 95 |
|
---|
| 96 | */
|
---|
| 97 |
|
---|
| 98 | QSqlCursorManager::~QSqlCursorManager()
|
---|
| 99 | {
|
---|
| 100 | if ( d->autoDelete )
|
---|
| 101 | delete d->cur;
|
---|
| 102 | delete d;
|
---|
| 103 | }
|
---|
| 104 |
|
---|
| 105 | /*! \internal
|
---|
| 106 |
|
---|
| 107 | Sets the manager's sort to the index \a sort. To apply the new
|
---|
| 108 | sort, use refresh().
|
---|
| 109 |
|
---|
| 110 | */
|
---|
| 111 |
|
---|
| 112 | void QSqlCursorManager::setSort( const QSqlIndex& sort )
|
---|
| 113 | {
|
---|
| 114 | setSort( sort.toStringList() );
|
---|
| 115 | }
|
---|
| 116 |
|
---|
| 117 | /*! \internal
|
---|
| 118 |
|
---|
| 119 | Sets the manager's sort to the stringlist \a sort. To apply the
|
---|
| 120 | new sort, use refresh().
|
---|
| 121 |
|
---|
| 122 | */
|
---|
| 123 |
|
---|
| 124 | void QSqlCursorManager::setSort( const QStringList& sort )
|
---|
| 125 | {
|
---|
| 126 | d->srt = sort;
|
---|
| 127 | }
|
---|
| 128 |
|
---|
| 129 | /*! \internal
|
---|
| 130 |
|
---|
| 131 | Returns the current sort, or an empty stringlist if there is none.
|
---|
| 132 |
|
---|
| 133 | */
|
---|
| 134 |
|
---|
| 135 | QStringList QSqlCursorManager::sort() const
|
---|
| 136 | {
|
---|
| 137 | return d->srt;
|
---|
| 138 | }
|
---|
| 139 |
|
---|
| 140 | /*! \internal
|
---|
| 141 |
|
---|
| 142 | Sets the manager's filter to the string \a filter. To apply the
|
---|
| 143 | new filter, use refresh().
|
---|
| 144 |
|
---|
| 145 | */
|
---|
| 146 |
|
---|
| 147 | void QSqlCursorManager::setFilter( const QString& filter )
|
---|
| 148 | {
|
---|
| 149 | d->ftr = filter;
|
---|
| 150 | }
|
---|
| 151 |
|
---|
| 152 | /*! \internal
|
---|
| 153 |
|
---|
| 154 | Returns the current filter, or an empty string if there is none.
|
---|
| 155 |
|
---|
| 156 | */
|
---|
| 157 |
|
---|
| 158 | QString QSqlCursorManager::filter() const
|
---|
| 159 | {
|
---|
| 160 | return d->ftr;
|
---|
| 161 | }
|
---|
| 162 |
|
---|
| 163 | /*! \internal
|
---|
| 164 |
|
---|
| 165 | Sets auto-delete to \a enable. If TRUE, the default cursor will
|
---|
| 166 | be deleted when necessary.
|
---|
| 167 |
|
---|
| 168 | \sa autoDelete()
|
---|
| 169 | */
|
---|
| 170 |
|
---|
| 171 | void QSqlCursorManager::setAutoDelete( bool enable )
|
---|
| 172 | {
|
---|
| 173 | d->autoDelete = enable;
|
---|
| 174 | }
|
---|
| 175 |
|
---|
| 176 |
|
---|
| 177 | /*! \internal
|
---|
| 178 |
|
---|
| 179 | Returns TRUE if auto-deletion is enabled, otherwise FALSE.
|
---|
| 180 |
|
---|
| 181 | \sa setAutoDelete()
|
---|
| 182 |
|
---|
| 183 | */
|
---|
| 184 |
|
---|
| 185 | bool QSqlCursorManager::autoDelete() const
|
---|
| 186 | {
|
---|
| 187 | return d->autoDelete;
|
---|
| 188 | }
|
---|
| 189 |
|
---|
| 190 | /*! \internal
|
---|
| 191 |
|
---|
| 192 | Sets the default cursor used by the manager to \a cursor. If \a
|
---|
| 193 | autoDelete is TRUE (the default is FALSE), the manager takes
|
---|
| 194 | ownership of the \a cursor pointer, which will be deleted when the
|
---|
| 195 | manager is destroyed, or when setCursor() is called again. To
|
---|
| 196 | activate the \a cursor use refresh().
|
---|
| 197 |
|
---|
| 198 | \sa cursor()
|
---|
| 199 |
|
---|
| 200 | */
|
---|
| 201 |
|
---|
| 202 | void QSqlCursorManager::setCursor( QSqlCursor* cursor, bool autoDelete )
|
---|
| 203 | {
|
---|
| 204 | if ( d->autoDelete )
|
---|
| 205 | delete d->cur;
|
---|
| 206 | d->cur = cursor;
|
---|
| 207 | d->autoDelete = autoDelete;
|
---|
| 208 | }
|
---|
| 209 |
|
---|
| 210 | /*! \internal
|
---|
| 211 |
|
---|
| 212 | Returns a pointer to the default cursor used for navigation, or 0
|
---|
| 213 | if there is no default cursor.
|
---|
| 214 |
|
---|
| 215 | \sa setCursor()
|
---|
| 216 |
|
---|
| 217 | */
|
---|
| 218 |
|
---|
| 219 | QSqlCursor* QSqlCursorManager::cursor() const
|
---|
| 220 | {
|
---|
| 221 | return d->cur;
|
---|
| 222 | }
|
---|
| 223 |
|
---|
| 224 |
|
---|
| 225 | /*! \internal
|
---|
| 226 |
|
---|
| 227 | Refreshes the manager using the default cursor. The manager's
|
---|
| 228 | filter and sort are applied. Returns TRUE on success, FALSE if an
|
---|
| 229 | error occurred or there is no current cursor.
|
---|
| 230 |
|
---|
| 231 | \sa setFilter() setSort()
|
---|
| 232 |
|
---|
| 233 | */
|
---|
| 234 |
|
---|
| 235 | bool QSqlCursorManager::refresh()
|
---|
| 236 | {
|
---|
| 237 | QSqlCursor* cur = cursor();
|
---|
| 238 | if ( !cur )
|
---|
| 239 | return FALSE;
|
---|
| 240 | QString currentFilter = d->ftr;
|
---|
| 241 | QStringList currentSort = d->srt;
|
---|
| 242 | QSqlIndex newSort = QSqlIndex::fromStringList( currentSort, cur );
|
---|
| 243 | return cur->select( currentFilter, newSort );
|
---|
| 244 | }
|
---|
| 245 |
|
---|
| 246 | /* \internal
|
---|
| 247 |
|
---|
| 248 | Returns TRUE if the \a buf field values that correspond to \a idx
|
---|
| 249 | match the field values in \a cur that correspond to \a idx.
|
---|
| 250 | */
|
---|
| 251 |
|
---|
| 252 | static bool index_matches( const QSqlCursor* cur, const QSqlRecord* buf,
|
---|
| 253 | const QSqlIndex& idx )
|
---|
| 254 | {
|
---|
| 255 | bool indexEquals = FALSE;
|
---|
| 256 | for ( uint i = 0; i < idx.count(); ++i ) {
|
---|
| 257 | const QString fn( idx.field(i)->name() );
|
---|
| 258 | if ( cur->value( fn ) == buf->value( fn ) )
|
---|
| 259 | indexEquals = TRUE;
|
---|
| 260 | else {
|
---|
| 261 | indexEquals = FALSE;
|
---|
| 262 | break;
|
---|
| 263 | }
|
---|
| 264 | }
|
---|
| 265 | return indexEquals;
|
---|
| 266 | }
|
---|
| 267 |
|
---|
| 268 | /*
|
---|
| 269 | Return less than, equal to or greater than 0 if buf1 is less than,
|
---|
| 270 | equal to or greater than buf2 according to fields described in idx.
|
---|
| 271 | (### Currently only uses first field.)
|
---|
| 272 | */
|
---|
| 273 |
|
---|
| 274 | static int compare_recs( const QSqlRecord* buf1, const QSqlRecord* buf2,
|
---|
| 275 | const QSqlIndex& idx )
|
---|
| 276 | {
|
---|
| 277 | int cmp = 0;
|
---|
| 278 |
|
---|
| 279 | int i = 0;
|
---|
| 280 | const QString fn( idx.field(i)->name() );
|
---|
| 281 | const QSqlField* f1 = buf1->field( fn );
|
---|
| 282 |
|
---|
| 283 | if ( f1 ) {
|
---|
| 284 | switch ( f1->type() ) { // ### more types?
|
---|
| 285 | case QVariant::String:
|
---|
| 286 | case QVariant::CString:
|
---|
| 287 | cmp = f1->value().toString().simplifyWhiteSpace().compare(
|
---|
| 288 | buf2->value(fn).toString().simplifyWhiteSpace() );
|
---|
| 289 | break;
|
---|
| 290 | default:
|
---|
| 291 | if ( f1->value().toDouble() < buf2->value( fn ).toDouble() )
|
---|
| 292 | cmp = -1;
|
---|
| 293 | else if ( f1->value().toDouble() > buf2->value( fn ).toDouble() )
|
---|
| 294 | cmp = 1;
|
---|
| 295 | }
|
---|
| 296 | }
|
---|
| 297 |
|
---|
| 298 | if ( idx.isDescending(i) )
|
---|
| 299 | cmp = -cmp;
|
---|
| 300 | return cmp;
|
---|
| 301 | }
|
---|
| 302 |
|
---|
| 303 | #ifdef QT_DEBUG_DATAMANAGER
|
---|
| 304 | static void debug_datamanager_buffer( const QString& msg, QSqlRecord* cursor )
|
---|
| 305 | {
|
---|
| 306 | qDebug("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
|
---|
| 307 | qDebug( "%s", msg.latin1() );
|
---|
| 308 | for ( uint j = 0; j < cursor->count(); ++j ) {
|
---|
| 309 | qDebug( "%s", (cursor->field(j)->name() + " type:"
|
---|
| 310 | + QString(cursor->field(j)->value().typeName())
|
---|
| 311 | + " value:" + cursor->field(j)->value().toString())
|
---|
| 312 | .latin1() );
|
---|
| 313 | }
|
---|
| 314 | }
|
---|
| 315 | #endif
|
---|
| 316 |
|
---|
| 317 |
|
---|
| 318 | /*! \internal
|
---|
| 319 |
|
---|
| 320 | Relocates the default cursor to the record matching the cursor's
|
---|
| 321 | edit buffer. Only the field names specified by \a idx are used to
|
---|
| 322 | determine an exact match of the cursor to the edit buffer. However,
|
---|
| 323 | other fields in the edit buffer are also used during the search,
|
---|
| 324 | therefore all fields in the edit buffer should be primed with desired
|
---|
| 325 | values for the record being sought. This function is typically used
|
---|
| 326 | to relocate a cursor to the correct position after an insert or
|
---|
| 327 | update. For example:
|
---|
| 328 |
|
---|
| 329 | \code
|
---|
| 330 | QSqlCursor* myCursor = myManager.cursor();
|
---|
| 331 | ...
|
---|
| 332 | QSqlRecord* buf = myCursor->primeUpdate();
|
---|
| 333 | buf->setValue( "name", "Ola" );
|
---|
| 334 | buf->setValue( "city", "Oslo" );
|
---|
| 335 | ...
|
---|
| 336 | myCursor->update(); // update current record
|
---|
| 337 | myCursor->select(); // refresh the cursor
|
---|
| 338 | myManager.findBuffer( myCursor->primaryIndex() ); // go to the updated record
|
---|
| 339 | \endcode
|
---|
| 340 |
|
---|
| 341 | */
|
---|
| 342 |
|
---|
| 343 | //## possibly add sizeHint parameter
|
---|
| 344 | bool QSqlCursorManager::findBuffer( const QSqlIndex& idx, int atHint )
|
---|
| 345 | {
|
---|
| 346 | #ifdef QT_DEBUG_DATAMANAGER
|
---|
| 347 | qDebug("QSqlCursorManager::findBuffer:");
|
---|
| 348 | #endif
|
---|
| 349 | QSqlCursor* cur = cursor();
|
---|
| 350 | if ( !cur )
|
---|
| 351 | return FALSE;
|
---|
| 352 | if ( !cur->isActive() )
|
---|
| 353 | return FALSE;
|
---|
| 354 | if ( !idx.count() ) {
|
---|
| 355 | if ( cur->at() == QSql::BeforeFirst )
|
---|
| 356 | cur->next();
|
---|
| 357 | return FALSE;
|
---|
| 358 | }
|
---|
| 359 | QSqlRecord* buf = cur->editBuffer();
|
---|
| 360 | bool indexEquals = FALSE;
|
---|
| 361 | #ifdef QT_DEBUG_DATAMANAGER
|
---|
| 362 | qDebug(" Checking hint...");
|
---|
| 363 | #endif
|
---|
| 364 | /* check the hint */
|
---|
| 365 | if ( cur->seek( atHint ) )
|
---|
| 366 | indexEquals = index_matches( cur, buf, idx );
|
---|
| 367 |
|
---|
| 368 | if ( !indexEquals ) {
|
---|
| 369 | #ifdef QT_DEBUG_DATAMANAGER
|
---|
| 370 | qDebug(" Checking current page...");
|
---|
| 371 | #endif
|
---|
| 372 | /* check current page */
|
---|
| 373 | int pageSize = 20;
|
---|
| 374 | int startIdx = QMAX( atHint - pageSize, 0 );
|
---|
| 375 | int endIdx = atHint + pageSize;
|
---|
| 376 | for ( int j = startIdx; j <= endIdx; ++j ) {
|
---|
| 377 | if ( cur->seek( j ) ) {
|
---|
| 378 | indexEquals = index_matches( cur, buf, idx );
|
---|
| 379 | if ( indexEquals )
|
---|
| 380 | break;
|
---|
| 381 | }
|
---|
| 382 | }
|
---|
| 383 | }
|
---|
| 384 |
|
---|
| 385 | if ( !indexEquals && cur->driver()->hasFeature( QSqlDriver::QuerySize )
|
---|
| 386 | && cur->sort().count() ) {
|
---|
| 387 | #ifdef QT_DEBUG_DATAMANAGER
|
---|
| 388 | qDebug(" Using binary search...");
|
---|
| 389 | #endif
|
---|
| 390 | // binary search based on record buffer and current sort fields
|
---|
| 391 | int lo = 0;
|
---|
| 392 | int hi = cur->size();
|
---|
| 393 | int mid;
|
---|
| 394 | if ( compare_recs( buf, cur, cur->sort() ) >= 0 )
|
---|
| 395 | lo = cur->at();
|
---|
| 396 | while ( lo != hi ) {
|
---|
| 397 | mid = lo + (hi - lo) / 2;
|
---|
| 398 | if ( !cur->seek( mid ) )
|
---|
| 399 | break;
|
---|
| 400 | if ( index_matches( cur, buf, idx ) ) {
|
---|
| 401 | indexEquals = TRUE;
|
---|
| 402 | break;
|
---|
| 403 | }
|
---|
| 404 | int c = compare_recs( buf, cur, cur->sort() );
|
---|
| 405 | if ( c < 0 ) {
|
---|
| 406 | hi = mid;
|
---|
| 407 | } else if ( c == 0 ) {
|
---|
| 408 | // found it, but there may be duplicates
|
---|
| 409 | int at = mid;
|
---|
| 410 | do {
|
---|
| 411 | mid--;
|
---|
| 412 | if ( !cur->seek( mid ) )
|
---|
| 413 | break;
|
---|
| 414 | if ( index_matches( cur, buf, idx ) ) {
|
---|
| 415 | indexEquals = TRUE;
|
---|
| 416 | break;
|
---|
| 417 | }
|
---|
| 418 | } while ( compare_recs( buf, cur, cur->sort() ) == 0 );
|
---|
| 419 |
|
---|
| 420 | if ( !indexEquals ) {
|
---|
| 421 | mid = at;
|
---|
| 422 | do {
|
---|
| 423 | mid++;
|
---|
| 424 | if ( !cur->seek( mid ) )
|
---|
| 425 | break;
|
---|
| 426 | if ( index_matches( cur, buf, idx ) ) {
|
---|
| 427 | indexEquals = TRUE;
|
---|
| 428 | break;
|
---|
| 429 | }
|
---|
| 430 | } while ( compare_recs( buf, cur, cur->sort() ) == 0 );
|
---|
| 431 | }
|
---|
| 432 | break;
|
---|
| 433 | } else if ( c > 0 ) {
|
---|
| 434 | lo = mid + 1;
|
---|
| 435 | }
|
---|
| 436 | }
|
---|
| 437 | }
|
---|
| 438 |
|
---|
| 439 | if ( !indexEquals ) {
|
---|
| 440 | #ifdef QT_DEBUG_DATAMANAGER
|
---|
| 441 | qDebug(" Using brute search...");
|
---|
| 442 | #endif
|
---|
| 443 | #ifndef QT_NO_CURSOR
|
---|
| 444 | QApplication::setOverrideCursor( Qt::waitCursor );
|
---|
| 445 | #endif
|
---|
| 446 | /* give up, use brute force */
|
---|
| 447 | int startIdx = 0;
|
---|
| 448 | if ( cur->at() != startIdx ) {
|
---|
| 449 | cur->seek( startIdx );
|
---|
| 450 | }
|
---|
| 451 | for ( ;; ) {
|
---|
| 452 | indexEquals = FALSE;
|
---|
| 453 | indexEquals = index_matches( cur, buf, idx );
|
---|
| 454 | if ( indexEquals )
|
---|
| 455 | break;
|
---|
| 456 | if ( !cur->next() )
|
---|
| 457 | break;
|
---|
| 458 | }
|
---|
| 459 | #ifndef QT_NO_CURSOR
|
---|
| 460 | QApplication::restoreOverrideCursor();
|
---|
| 461 | #endif
|
---|
| 462 | }
|
---|
| 463 | #ifdef QT_DEBUG_DATAMANAGER
|
---|
| 464 | qDebug(" Done, result:" + QString::number( indexEquals ) );
|
---|
| 465 | #endif
|
---|
| 466 | return indexEquals;
|
---|
| 467 | }
|
---|
| 468 |
|
---|
| 469 | #ifndef QT_NO_SQL_FORM
|
---|
| 470 |
|
---|
| 471 | class QSqlFormManagerPrivate
|
---|
| 472 | {
|
---|
| 473 | public:
|
---|
| 474 | QSqlFormManagerPrivate() : frm(0), rcd(0) {}
|
---|
| 475 | QSqlForm* frm;
|
---|
| 476 | QSqlRecord* rcd;
|
---|
| 477 | };
|
---|
| 478 |
|
---|
| 479 |
|
---|
| 480 | /*! \internal
|
---|
| 481 |
|
---|
| 482 | Creates a form manager.
|
---|
| 483 |
|
---|
| 484 | */
|
---|
| 485 |
|
---|
| 486 | QSqlFormManager::QSqlFormManager()
|
---|
| 487 | {
|
---|
| 488 | d = new QSqlFormManagerPrivate();
|
---|
| 489 | }
|
---|
| 490 |
|
---|
| 491 | /*! \internal
|
---|
| 492 |
|
---|
| 493 | Destroys the object and frees any allocated resources.
|
---|
| 494 |
|
---|
| 495 | */
|
---|
| 496 |
|
---|
| 497 | QSqlFormManager::~QSqlFormManager()
|
---|
| 498 | {
|
---|
| 499 | delete d;
|
---|
| 500 | }
|
---|
| 501 |
|
---|
| 502 | /*! \internal
|
---|
| 503 |
|
---|
| 504 | Clears the default form values. If there is no default form,
|
---|
| 505 | nothing happens,
|
---|
| 506 |
|
---|
| 507 | */
|
---|
| 508 |
|
---|
| 509 | void QSqlFormManager::clearValues()
|
---|
| 510 | {
|
---|
| 511 | if ( form() )
|
---|
| 512 | form()->clearValues();
|
---|
| 513 | }
|
---|
| 514 |
|
---|
| 515 | /*! \internal
|
---|
| 516 |
|
---|
| 517 | Sets the form used by the form manager to \a form. If a record has
|
---|
| 518 | already been assigned to the form manager, that record is also used by
|
---|
| 519 | the \a form to display data.
|
---|
| 520 |
|
---|
| 521 | \sa form()
|
---|
| 522 |
|
---|
| 523 | */
|
---|
| 524 |
|
---|
| 525 | void QSqlFormManager::setForm( QSqlForm* form )
|
---|
| 526 | {
|
---|
| 527 | d->frm = form;
|
---|
| 528 | if ( d->rcd && d->frm )
|
---|
| 529 | d->frm->setRecord( d->rcd );
|
---|
| 530 | }
|
---|
| 531 |
|
---|
| 532 |
|
---|
| 533 | /*! \internal
|
---|
| 534 |
|
---|
| 535 | Returns the default form used by the form manager, or 0 if there is
|
---|
| 536 | none.
|
---|
| 537 |
|
---|
| 538 | \sa setForm()
|
---|
| 539 |
|
---|
| 540 | */
|
---|
| 541 |
|
---|
| 542 | QSqlForm* QSqlFormManager::form()
|
---|
| 543 | {
|
---|
| 544 | return d->frm;
|
---|
| 545 | }
|
---|
| 546 |
|
---|
| 547 |
|
---|
| 548 | /*! \internal
|
---|
| 549 |
|
---|
| 550 | Sets the record used by the form manager to \a record. If a form has
|
---|
| 551 | already been assigned to the form manager, \a record is also used by
|
---|
| 552 | the default form to display data.
|
---|
| 553 |
|
---|
| 554 | \sa record()
|
---|
| 555 |
|
---|
| 556 | */
|
---|
| 557 |
|
---|
| 558 | void QSqlFormManager::setRecord( QSqlRecord* record )
|
---|
| 559 | {
|
---|
| 560 | d->rcd = record;
|
---|
| 561 | if ( d->frm ) {
|
---|
| 562 | d->frm->setRecord( d->rcd );
|
---|
| 563 | }
|
---|
| 564 | }
|
---|
| 565 |
|
---|
| 566 |
|
---|
| 567 | /*! \internal
|
---|
| 568 |
|
---|
| 569 | Returns the default record used by the form manager, or 0 if there is
|
---|
| 570 | none.
|
---|
| 571 |
|
---|
| 572 | \sa setRecord()
|
---|
| 573 | */
|
---|
| 574 |
|
---|
| 575 | QSqlRecord* QSqlFormManager::record()
|
---|
| 576 | {
|
---|
| 577 | return d->rcd;
|
---|
| 578 | }
|
---|
| 579 |
|
---|
| 580 |
|
---|
| 581 | /*! \internal
|
---|
| 582 |
|
---|
| 583 | Causes the default form to read its fields . If there is no
|
---|
| 584 | default form, nothing happens.
|
---|
| 585 |
|
---|
| 586 | \sa setForm()
|
---|
| 587 |
|
---|
| 588 | */
|
---|
| 589 |
|
---|
| 590 | void QSqlFormManager::readFields()
|
---|
| 591 | {
|
---|
| 592 | if ( d->frm ) {
|
---|
| 593 | d->frm->readFields();
|
---|
| 594 | }
|
---|
| 595 | }
|
---|
| 596 |
|
---|
| 597 | /*! \internal
|
---|
| 598 |
|
---|
| 599 | Causes the default form to write its fields . If there is no
|
---|
| 600 | default form, nothing happens.
|
---|
| 601 |
|
---|
| 602 | \sa setForm()
|
---|
| 603 |
|
---|
| 604 | */
|
---|
| 605 |
|
---|
| 606 | void QSqlFormManager::writeFields()
|
---|
| 607 | {
|
---|
| 608 | if ( d->frm ) {
|
---|
| 609 | d->frm->writeFields();
|
---|
| 610 | }
|
---|
| 611 | }
|
---|
| 612 |
|
---|
| 613 | #endif // QT_NO_SQL_FORM
|
---|
| 614 |
|
---|
| 615 | class QDataManagerPrivate
|
---|
| 616 | {
|
---|
| 617 | public:
|
---|
| 618 | QDataManagerPrivate()
|
---|
| 619 | : mode( QSql::None ), autoEd( TRUE ), confEdits( 3 ),
|
---|
| 620 | confCancs( FALSE ) {}
|
---|
| 621 | QSql::Op mode;
|
---|
| 622 | bool autoEd;
|
---|
| 623 | QBitArray confEdits;
|
---|
| 624 | bool confCancs;
|
---|
| 625 |
|
---|
| 626 | };
|
---|
| 627 |
|
---|
| 628 | /*!
|
---|
| 629 | \class QDataManager qsqlmanager_p.h
|
---|
| 630 | \ingroup database
|
---|
| 631 |
|
---|
| 632 | \brief The QDataManager class is an internal class for implementing
|
---|
| 633 | the data-aware widgets.
|
---|
| 634 |
|
---|
| 635 | \internal
|
---|
| 636 |
|
---|
| 637 | QDataManager is a strictly internal class that acts as a base class
|
---|
| 638 | for other data-aware widgets.
|
---|
| 639 |
|
---|
| 640 | */
|
---|
| 641 |
|
---|
| 642 |
|
---|
| 643 | /*! \internal
|
---|
| 644 |
|
---|
| 645 | Constructs an empty data handler.
|
---|
| 646 |
|
---|
| 647 | */
|
---|
| 648 |
|
---|
| 649 | QDataManager::QDataManager()
|
---|
| 650 | {
|
---|
| 651 | d = new QDataManagerPrivate();
|
---|
| 652 | }
|
---|
| 653 |
|
---|
| 654 |
|
---|
| 655 | /*! \internal
|
---|
| 656 |
|
---|
| 657 | Destroys the object and frees any allocated resources.
|
---|
| 658 |
|
---|
| 659 | */
|
---|
| 660 |
|
---|
| 661 | QDataManager::~QDataManager()
|
---|
| 662 | {
|
---|
| 663 | delete d;
|
---|
| 664 | }
|
---|
| 665 |
|
---|
| 666 |
|
---|
| 667 | /*! \internal
|
---|
| 668 |
|
---|
| 669 | Virtual function which is called when an error has occurred The
|
---|
| 670 | default implementation displays a warning message to the user with
|
---|
| 671 | information about the error.
|
---|
| 672 |
|
---|
| 673 | */
|
---|
| 674 | void QDataManager::handleError( QWidget* parent, const QSqlError& e )
|
---|
| 675 | {
|
---|
| 676 | #ifndef QT_NO_MESSAGEBOX
|
---|
| 677 | if (e.driverText().isEmpty() && e.databaseText().isEmpty()) {
|
---|
| 678 | QMessageBox::warning ( parent, "Warning", "An error occurred while accessing the database");
|
---|
| 679 | } else {
|
---|
| 680 | QMessageBox::warning ( parent, "Warning", e.driverText() + "\n" + e.databaseText(),
|
---|
| 681 | 0, 0 );
|
---|
| 682 | }
|
---|
| 683 | #endif // QT_NO_MESSAGEBOX
|
---|
| 684 | }
|
---|
| 685 |
|
---|
| 686 |
|
---|
| 687 | /*! \internal
|
---|
| 688 |
|
---|
| 689 | Sets the internal mode to \a m.
|
---|
| 690 |
|
---|
| 691 | */
|
---|
| 692 |
|
---|
| 693 | void QDataManager::setMode( QSql::Op m )
|
---|
| 694 | {
|
---|
| 695 | d->mode = m;
|
---|
| 696 | }
|
---|
| 697 |
|
---|
| 698 |
|
---|
| 699 | /*! \internal
|
---|
| 700 |
|
---|
| 701 | Returns the current mode.
|
---|
| 702 |
|
---|
| 703 | */
|
---|
| 704 |
|
---|
| 705 | QSql::Op QDataManager::mode() const
|
---|
| 706 | {
|
---|
| 707 | return d->mode;
|
---|
| 708 | }
|
---|
| 709 |
|
---|
| 710 |
|
---|
| 711 | /*! \internal
|
---|
| 712 |
|
---|
| 713 | Sets the auto-edit mode to \a auto.
|
---|
| 714 |
|
---|
| 715 | */
|
---|
| 716 |
|
---|
| 717 | void QDataManager::setAutoEdit( bool autoEdit )
|
---|
| 718 | {
|
---|
| 719 | d->autoEd = autoEdit;
|
---|
| 720 | }
|
---|
| 721 |
|
---|
| 722 |
|
---|
| 723 |
|
---|
| 724 | /*! \internal
|
---|
| 725 |
|
---|
| 726 | Returns TRUE if auto-edit mode is enabled; otherwise returns FALSE.
|
---|
| 727 |
|
---|
| 728 | */
|
---|
| 729 |
|
---|
| 730 | bool QDataManager::autoEdit() const
|
---|
| 731 | {
|
---|
| 732 | return d->autoEd;
|
---|
| 733 | }
|
---|
| 734 |
|
---|
| 735 | /*! \internal
|
---|
| 736 |
|
---|
| 737 | If \a confirm is TRUE, all edit operations (inserts, updates and
|
---|
| 738 | deletes) will be confirmed by the user. If \a confirm is FALSE (the
|
---|
| 739 | default), all edits are posted to the database immediately.
|
---|
| 740 |
|
---|
| 741 | */
|
---|
| 742 | void QDataManager::setConfirmEdits( bool confirm )
|
---|
| 743 | {
|
---|
| 744 | d->confEdits.fill( confirm );
|
---|
| 745 | }
|
---|
| 746 |
|
---|
| 747 | /*! \internal
|
---|
| 748 |
|
---|
| 749 | If \a confirm is TRUE, all inserts will be confirmed by the user.
|
---|
| 750 | If \a confirm is FALSE (the default), all edits are posted to the
|
---|
| 751 | database immediately.
|
---|
| 752 |
|
---|
| 753 | */
|
---|
| 754 |
|
---|
| 755 | void QDataManager::setConfirmInsert( bool confirm )
|
---|
| 756 | {
|
---|
| 757 | d->confEdits[ QSql::Insert ] = confirm;
|
---|
| 758 | }
|
---|
| 759 |
|
---|
| 760 | /*! \internal
|
---|
| 761 |
|
---|
| 762 | If \a confirm is TRUE, all updates will be confirmed by the user.
|
---|
| 763 | If \a confirm is FALSE (the default), all edits are posted to the
|
---|
| 764 | database immediately.
|
---|
| 765 |
|
---|
| 766 | */
|
---|
| 767 |
|
---|
| 768 | void QDataManager::setConfirmUpdate( bool confirm )
|
---|
| 769 | {
|
---|
| 770 | d->confEdits[ QSql::Update ] = confirm;
|
---|
| 771 | }
|
---|
| 772 |
|
---|
| 773 | /*! \internal
|
---|
| 774 |
|
---|
| 775 | If \a confirm is TRUE, all deletes will be confirmed by the user.
|
---|
| 776 | If \a confirm is FALSE (the default), all edits are posted to the
|
---|
| 777 | database immediately.
|
---|
| 778 |
|
---|
| 779 | */
|
---|
| 780 |
|
---|
| 781 | void QDataManager::setConfirmDelete( bool confirm )
|
---|
| 782 | {
|
---|
| 783 | d->confEdits[ QSql::Delete ] = confirm;
|
---|
| 784 | }
|
---|
| 785 |
|
---|
| 786 | /*! \internal
|
---|
| 787 |
|
---|
| 788 | Returns TRUE if the table confirms all edit operations (inserts,
|
---|
| 789 | updates and deletes), otherwise returns FALSE.
|
---|
| 790 | */
|
---|
| 791 |
|
---|
| 792 | bool QDataManager::confirmEdits() const
|
---|
| 793 | {
|
---|
| 794 | return ( confirmInsert() && confirmUpdate() && confirmDelete() );
|
---|
| 795 | }
|
---|
| 796 |
|
---|
| 797 | /*! \internal
|
---|
| 798 |
|
---|
| 799 | Returns TRUE if the table confirms inserts, otherwise returns
|
---|
| 800 | FALSE.
|
---|
| 801 | */
|
---|
| 802 |
|
---|
| 803 | bool QDataManager::confirmInsert() const
|
---|
| 804 | {
|
---|
| 805 | return d->confEdits[ QSql::Insert ];
|
---|
| 806 | }
|
---|
| 807 |
|
---|
| 808 | /*! \internal
|
---|
| 809 |
|
---|
| 810 | Returns TRUE if the table confirms updates, otherwise returns
|
---|
| 811 | FALSE.
|
---|
| 812 | */
|
---|
| 813 |
|
---|
| 814 | bool QDataManager::confirmUpdate() const
|
---|
| 815 | {
|
---|
| 816 | return d->confEdits[ QSql::Update ];
|
---|
| 817 | }
|
---|
| 818 |
|
---|
| 819 | /*! \internal
|
---|
| 820 |
|
---|
| 821 | Returns TRUE if the table confirms deletes, otherwise returns
|
---|
| 822 | FALSE.
|
---|
| 823 | */
|
---|
| 824 |
|
---|
| 825 | bool QDataManager::confirmDelete() const
|
---|
| 826 | {
|
---|
| 827 | return d->confEdits[ QSql::Delete ];
|
---|
| 828 | }
|
---|
| 829 |
|
---|
| 830 | /*! \internal
|
---|
| 831 |
|
---|
| 832 | If \a confirm is TRUE, all cancels will be confirmed by the user
|
---|
| 833 | through a message box. If \a confirm is FALSE (the default), all
|
---|
| 834 | cancels occur immediately.
|
---|
| 835 | */
|
---|
| 836 |
|
---|
| 837 | void QDataManager::setConfirmCancels( bool confirm )
|
---|
| 838 | {
|
---|
| 839 | d->confCancs = confirm;
|
---|
| 840 | }
|
---|
| 841 |
|
---|
| 842 | /*! \internal
|
---|
| 843 |
|
---|
| 844 | Returns TRUE if the table confirms cancels, otherwise returns FALSE.
|
---|
| 845 | */
|
---|
| 846 |
|
---|
| 847 | bool QDataManager::confirmCancels() const
|
---|
| 848 | {
|
---|
| 849 | return d->confCancs;
|
---|
| 850 | }
|
---|
| 851 |
|
---|
| 852 | /*! \internal
|
---|
| 853 |
|
---|
| 854 | Virtual function which returns a confirmation for an edit of mode \a
|
---|
| 855 | m. Derived classes can reimplement this function and provide their
|
---|
| 856 | own confirmation dialog. The default implementation uses a message
|
---|
| 857 | box which prompts the user to confirm the edit action. The dialog
|
---|
| 858 | is centered over \a parent.
|
---|
| 859 |
|
---|
| 860 | */
|
---|
| 861 |
|
---|
| 862 | QSql::Confirm QDataManager::confirmEdit( QWidget* parent, QSql::Op m )
|
---|
| 863 | {
|
---|
| 864 | int ans = 2;
|
---|
| 865 | if ( m == QSql::Delete ) {
|
---|
| 866 | #ifndef QT_NO_MESSAGEBOX
|
---|
| 867 | ans = QMessageBox::information( parent,
|
---|
| 868 | qApp->translate( "QSql", "Delete" ),
|
---|
| 869 | qApp->translate( "QSql", "Delete this record?" ),
|
---|
| 870 | qApp->translate( "QSql", "Yes" ),
|
---|
| 871 | qApp->translate( "QSql", "No" ),
|
---|
| 872 | QString::null, 0, 1 );
|
---|
| 873 | #else
|
---|
| 874 | ans = QSql::No;
|
---|
| 875 | #endif // QT_NO_MESSAGEBOX
|
---|
| 876 | } else if ( m != QSql::None ) {
|
---|
| 877 | QString caption;
|
---|
| 878 | if ( m == QSql::Insert ) {
|
---|
| 879 | caption = qApp->translate( "QSql", "Insert" );
|
---|
| 880 | } else { // QSql::Update
|
---|
| 881 | caption = qApp->translate( "QSql", "Update" );
|
---|
| 882 | }
|
---|
| 883 | #ifndef QT_NO_MESSAGEBOX
|
---|
| 884 | ans = QMessageBox::information( parent, caption,
|
---|
| 885 | qApp->translate( "QSql", "Save edits?" ),
|
---|
| 886 | qApp->translate( "QSql", "Yes" ),
|
---|
| 887 | qApp->translate( "QSql", "No" ),
|
---|
| 888 | qApp->translate( "QSql", "Cancel" ),
|
---|
| 889 | 0, 2 );
|
---|
| 890 | #else
|
---|
| 891 | ans = QSql::No;
|
---|
| 892 | #endif // QT_NO_MESSAGEBOX
|
---|
| 893 | }
|
---|
| 894 |
|
---|
| 895 | switch ( ans ) {
|
---|
| 896 | case 0:
|
---|
| 897 | return QSql::Yes;
|
---|
| 898 | case 1:
|
---|
| 899 | return QSql::No;
|
---|
| 900 | default:
|
---|
| 901 | return QSql::Cancel;
|
---|
| 902 | }
|
---|
| 903 | }
|
---|
| 904 |
|
---|
| 905 | /*! \internal
|
---|
| 906 |
|
---|
| 907 | Virtual function which returns a confirmation for cancelling an edit
|
---|
| 908 | mode \a m. Derived classes can reimplement this function and
|
---|
| 909 | provide their own confirmation dialog. The default implementation
|
---|
| 910 | uses a message box which prompts the user to confirm the edit
|
---|
| 911 | action. The dialog is centered over \a parent.
|
---|
| 912 |
|
---|
| 913 |
|
---|
| 914 | */
|
---|
| 915 |
|
---|
| 916 | QSql::Confirm QDataManager::confirmCancel( QWidget* parent, QSql::Op )
|
---|
| 917 | {
|
---|
| 918 | #ifndef QT_NO_MESSAGEBOX
|
---|
| 919 | switch ( QMessageBox::information( parent,
|
---|
| 920 | qApp->translate( "QSql", "Confirm" ),
|
---|
| 921 | qApp->translate( "QSql", "Cancel your edits?" ),
|
---|
| 922 | qApp->translate( "QSql", "Yes" ),
|
---|
| 923 | qApp->translate( "QSql", "No" ),
|
---|
| 924 | QString::null, 0, 1 ) ) {
|
---|
| 925 | case 0:
|
---|
| 926 | return QSql::Yes;
|
---|
| 927 | case 1:
|
---|
| 928 | return QSql::No;
|
---|
| 929 | default:
|
---|
| 930 | return QSql::Cancel;
|
---|
| 931 | }
|
---|
| 932 | #else
|
---|
| 933 | return QSql::Yes;
|
---|
| 934 | #endif // QT_NO_MESSAGEBOX
|
---|
| 935 | }
|
---|
| 936 |
|
---|
| 937 | #endif
|
---|