source: trunk/src/qt3support/sql/q3sqlmanager_p.cpp@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

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