summaryrefslogtreecommitdiffstats
path: root/src/qt3support/sql
diff options
context:
space:
mode:
Diffstat (limited to 'src/qt3support/sql')
-rw-r--r--src/qt3support/sql/q3databrowser.cpp1281
-rw-r--r--src/qt3support/sql/q3databrowser.h183
-rw-r--r--src/qt3support/sql/q3datatable.cpp2335
-rw-r--r--src/qt3support/sql/q3datatable.h251
-rw-r--r--src/qt3support/sql/q3dataview.cpp208
-rw-r--r--src/qt3support/sql/q3dataview.h90
-rw-r--r--src/qt3support/sql/q3editorfactory.cpp202
-rw-r--r--src/qt3support/sql/q3editorfactory.h77
-rw-r--r--src/qt3support/sql/q3sqlcursor.cpp1519
-rw-r--r--src/qt3support/sql/q3sqlcursor.h167
-rw-r--r--src/qt3support/sql/q3sqleditorfactory.cpp229
-rw-r--r--src/qt3support/sql/q3sqleditorfactory.h78
-rw-r--r--src/qt3support/sql/q3sqlfieldinfo.h167
-rw-r--r--src/qt3support/sql/q3sqlform.cpp378
-rw-r--r--src/qt3support/sql/q3sqlform.h109
-rw-r--r--src/qt3support/sql/q3sqlmanager_p.cpp961
-rw-r--r--src/qt3support/sql/q3sqlmanager_p.h160
-rw-r--r--src/qt3support/sql/q3sqlpropertymap.cpp276
-rw-r--r--src/qt3support/sql/q3sqlpropertymap.h86
-rw-r--r--src/qt3support/sql/q3sqlrecordinfo.h122
-rw-r--r--src/qt3support/sql/q3sqlselectcursor.cpp263
-rw-r--r--src/qt3support/sql/q3sqlselectcursor.h115
-rw-r--r--src/qt3support/sql/sql.pri25
23 files changed, 9282 insertions, 0 deletions
diff --git a/src/qt3support/sql/q3databrowser.cpp b/src/qt3support/sql/q3databrowser.cpp
new file mode 100644
index 0000000..fd20f66
--- /dev/null
+++ b/src/qt3support/sql/q3databrowser.cpp
@@ -0,0 +1,1281 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3databrowser.h"
+
+#ifndef QT_NO_SQL_VIEW_WIDGETS
+
+#include "q3sqlform.h"
+#include "private/q3sqlmanager_p.h"
+#include "qsqlresult.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q3DataBrowserPrivate
+{
+public:
+ Q3DataBrowserPrivate() : boundaryCheck(true), readOnly(false) {}
+ Q3SqlCursorManager cur;
+ Q3SqlFormManager frm;
+ Q3DataManager dat;
+ bool boundaryCheck;
+ bool readOnly;
+};
+
+/*!
+ \class Q3DataBrowser
+ \brief The Q3DataBrowser class provides data manipulation and
+ navigation for data entry forms.
+
+ \compat
+
+ A high-level API is provided for navigating through data records
+ in a cursor, for inserting, updating and deleting records, and for
+ refreshing data in the display.
+
+ If you want a read-only form to present database data use
+ Q3DataView; if you want a table-based presentation of your data use
+ Q3DataTable.
+
+ A Q3DataBrowser is used to associate a dataset with a form in much
+ the same way as a Q3DataTable associates a dataset with a table.
+ Once the data browser has been constructed it can be associated
+ with a dataset with setSqlCursor(), and with a form with
+ setForm(). Boundary checking, sorting and filtering can be set
+ with setBoundaryChecking(), setSort() and setFilter(),
+ respectively.
+
+ The insertCurrent() function reads the fields from the default
+ form into the default cursor and performs the insert. The
+ updateCurrent() and deleteCurrent() functions perform similarly to
+ update and delete the current record respectively.
+
+ The user can be asked to confirm all edits with setConfirmEdits().
+ For more precise control use setConfirmInsert(),
+ setConfirmUpdate(), setConfirmDelete() and setConfirmCancels().
+ Use setAutoEdit() to control the behavior of the form when the
+ user edits a record and then navigates.
+
+ The record set is navigated using first(), next(), prev(), last()
+ and seek(). The form's display is updated with refresh(). When
+ navigation takes place the firstRecordAvailable(),
+ lastRecordAvailable(), nextRecordAvailable() and
+ prevRecordAvailable() signals are emitted. When the cursor record
+ is changed due to navigation the cursorChanged() signal is
+ emitted.
+
+ If you want finer control of the insert, update and delete
+ processes then you can use the lower level functions to perform
+ these operations as described below.
+
+ The form is populated with data from the database with
+ readFields(). If the user is allowed to edit, (see setReadOnly()),
+ write the form's data back to the cursor's edit buffer with
+ writeFields(). You can clear the values in the form with
+ clearValues(). Editing is performed as follows:
+ \list
+ \i \e insert When the data browser enters insertion mode it emits the
+ primeInsert() signal which you can connect to, for example to
+ pre-populate fields. Call writeFields() to write the user's edits to
+ the cursor's edit buffer then call insert() to insert the record
+ into the database. The beforeInsert() signal is emitted just before
+ the cursor's edit buffer is inserted into the database; connect to
+ this for example, to populate fields such as an auto-generated
+ primary key.
+ \i \e update For updates the primeUpdate() signal is emitted when
+ the data browser enters update mode. After calling writeFields()
+ call update() to update the record and connect to the beforeUpdate()
+ signal to manipulate the user's data before the update takes place.
+ \i \e delete For deletion the primeDelete() signal is emitted when
+ the data browser enters deletion mode. After calling writeFields()
+ call del() to delete the record and connect to the beforeDelete()
+ signal, for example to record an audit of the deleted record.
+ \endlist
+
+*/
+
+/*!
+ \enum Q3DataBrowser::Boundary
+
+ This enum describes where the data browser is positioned.
+
+ \value Unknown the boundary cannot be determined (usually because
+ there is no default cursor, or the default cursor is not active).
+
+ \value None the browser is not positioned on a boundary, but it is
+ positioned on a record somewhere in the middle.
+
+ \value BeforeBeginning the browser is positioned before the
+ first available record.
+
+ \value Beginning the browser is positioned at the first record.
+
+ \value End the browser is positioned at the last
+ record.
+
+ \value AfterEnd the browser is positioned after the last
+ available record.
+*/
+
+/*!
+ Constructs a data browser which is a child of \a parent, with the
+ name \a name and widget flags set to \a fl.
+*/
+
+Q3DataBrowser::Q3DataBrowser(QWidget *parent, const char *name, Qt::WindowFlags fl)
+ : QWidget(parent, name, fl)
+{
+ d = new Q3DataBrowserPrivate();
+ d->dat.setMode(QSql::Update);
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+Q3DataBrowser::~Q3DataBrowser()
+{
+ delete d;
+}
+
+
+/*!
+ Returns an enum indicating the boundary status of the browser.
+
+ This is achieved by moving the default cursor and checking the
+ position, however the current default form values will not be
+ altered. After checking for the boundary, the cursor is moved back
+ to its former position. See \l Q3DataBrowser::Boundary.
+
+ \sa Boundary
+*/
+
+Q3DataBrowser::Boundary Q3DataBrowser::boundary()
+{
+ Q3SqlCursor* cur = d->cur.cursor();
+ if (!cur || !cur->isActive())
+ return Unknown;
+ if (!cur->isValid()) {
+ if (cur->at() == QSql::BeforeFirst)
+ return BeforeBeginning;
+ if (cur->at() == QSql::AfterLast)
+ return AfterEnd;
+ return Unknown;
+ }
+ if (cur->at() == 0)
+ return Beginning;
+ int currentAt = cur->at();
+
+ Boundary b = None;
+ if (!cur->previous())
+ b = Beginning;
+ else
+ cur->seek(currentAt);
+ if (b == None && !cur->next())
+ b = End;
+ cur->seek(currentAt);
+ return b;
+}
+
+
+/*!
+ \property Q3DataBrowser::boundaryChecking
+ \brief whether boundary checking is active
+
+ When boundary checking is active (the default), signals are
+ emitted indicating the current position of the default cursor.
+
+ \sa boundary()
+*/
+
+void Q3DataBrowser::setBoundaryChecking(bool active)
+{
+ d->boundaryCheck = active;
+}
+
+bool Q3DataBrowser::boundaryChecking() const
+{
+ return d->boundaryCheck;
+}
+
+/*!
+ \property Q3DataBrowser::sort
+ \brief the data browser's sort
+
+ The data browser's sort affects the order in which records are
+ viewed in the browser. Call refresh() to apply the new sort.
+
+ When retrieving the sort property, a string list is returned in
+ the form 'fieldname order', e.g. 'id ASC', 'surname DESC'.
+
+ There is no default sort.
+
+ Note that if you want to iterate over the list, you should iterate
+ over a copy, e.g.
+ \snippet doc/src/snippets/code/src_qt3support_sql_q3databrowser.cpp 0
+*/
+
+void Q3DataBrowser::setSort(const QStringList& sort)
+{
+ d->cur.setSort(sort);
+}
+
+/*!
+ \overload
+
+ Sets the data browser's sort to the QSqlIndex \a sort. To apply
+ the new sort, use refresh().
+
+*/
+void Q3DataBrowser::setSort(const QSqlIndex& sort)
+{
+ d->cur.setSort(sort);
+}
+
+QStringList Q3DataBrowser::sort() const
+{
+ return d->cur.sort();
+}
+
+
+/*!
+ \property Q3DataBrowser::filter
+ \brief the data browser's filter
+
+ The filter applies to the data shown in the browser. Call
+ refresh() to apply the new filter. A filter is a string containing
+ a SQL WHERE clause without the WHERE keyword, e.g. "id>1000",
+ "name LIKE 'A%'", etc.
+
+ There is no default filter.
+
+ \sa sort()
+*/
+
+void Q3DataBrowser::setFilter(const QString& filter)
+{
+ d->cur.setFilter(filter);
+}
+
+
+QString Q3DataBrowser::filter() const
+{
+ return d->cur.filter();
+}
+
+
+/*!
+ Sets the default cursor used by the data browser to \a cursor. If
+ \a autoDelete is true (the default is false), the data browser
+ takes ownership of the \a cursor pointer, which will be deleted
+ when the browser is destroyed, or when setSqlCursor() is called
+ again. To activate the \a cursor use refresh(). The cursor's edit
+ buffer is used in the default form to browse and edit records.
+
+ \sa sqlCursor() form() setForm()
+*/
+
+void Q3DataBrowser::setSqlCursor(Q3SqlCursor* cursor, bool autoDelete)
+{
+ if (!cursor)
+ return;
+ d->cur.setCursor(cursor, autoDelete);
+ d->frm.setRecord(cursor->editBuffer());
+ if (cursor->isReadOnly())
+ setReadOnly(true);
+}
+
+
+/*!
+ Returns the default cursor used for navigation, or 0 if there is
+ no default cursor.
+
+ \sa setSqlCursor()
+*/
+
+Q3SqlCursor* Q3DataBrowser::sqlCursor() const
+{
+ return d->cur.cursor();
+}
+
+
+/*!
+ Sets the browser's default form to \a form. The cursor and all
+ navigation and data manipulation functions that the browser
+ provides become available to the \a form.
+*/
+
+void Q3DataBrowser::setForm(Q3SqlForm* form)
+{
+ d->frm.setForm(form);
+}
+
+
+/*!
+ Returns the data browser's default form or 0 if no form has been
+ set.
+*/
+
+Q3SqlForm* Q3DataBrowser::form()
+{
+ return d->frm.form();
+}
+
+/*!
+ \property Q3DataBrowser::readOnly
+ \brief whether the browser is read-only
+
+ The default is false, i.e. data can be edited. If the data browser
+ is read-only, no database edits will be allowed.
+*/
+
+void Q3DataBrowser::setReadOnly(bool active)
+{
+ d->readOnly = active;
+}
+
+bool Q3DataBrowser::isReadOnly() const
+{
+ return d->readOnly;
+}
+
+void Q3DataBrowser::setConfirmEdits(bool confirm)
+{
+ d->dat.setConfirmEdits(confirm);
+}
+
+/*!
+ \property Q3DataBrowser::confirmInsert
+ \brief whether the data browser confirms insertions
+
+ If this property is true, the browser confirms insertions,
+ otherwise insertions happen immediately.
+
+ \sa confirmCancels() confirmEdits() confirmUpdate() confirmDelete() confirmEdit()
+*/
+
+void Q3DataBrowser::setConfirmInsert(bool confirm)
+{
+ d->dat.setConfirmInsert(confirm);
+}
+
+/*!
+ \property Q3DataBrowser::confirmUpdate
+ \brief whether the browser confirms updates
+
+ If this property is true, the browser confirms updates, otherwise
+ updates happen immediately.
+
+ \sa confirmCancels() confirmEdits() confirmInsert() confirmDelete() confirmEdit()
+*/
+
+void Q3DataBrowser::setConfirmUpdate(bool confirm)
+{
+ d->dat.setConfirmUpdate(confirm);
+}
+
+/*!
+ \property Q3DataBrowser::confirmDelete
+ \brief whether the browser confirms deletions
+
+ If this property is true, the browser confirms deletions,
+ otherwise deletions happen immediately.
+
+ \sa confirmCancels() confirmEdits() confirmUpdate() confirmInsert() confirmEdit()
+*/
+
+void Q3DataBrowser::setConfirmDelete(bool confirm)
+{
+ d->dat.setConfirmDelete(confirm);
+}
+
+/*!
+ \property Q3DataBrowser::confirmEdits
+ \brief whether the browser confirms edits
+
+ If this property is true, the browser confirms all edit operations
+ (insertions, updates and deletions), otherwise all edit operations
+ happen immediately. Confirmation is achieved by presenting the
+ user with a message box -- this behavior can be changed by
+ reimplementing the confirmEdit() function,
+
+ \sa confirmEdit() confirmCancels() confirmInsert() confirmUpdate() confirmDelete()
+*/
+
+bool Q3DataBrowser::confirmEdits() const
+{
+ return (d->dat.confirmEdits());
+}
+
+bool Q3DataBrowser::confirmInsert() const
+{
+ return (d->dat.confirmInsert());
+}
+
+bool Q3DataBrowser::confirmUpdate() const
+{
+ return (d->dat.confirmUpdate());
+}
+
+bool Q3DataBrowser::confirmDelete() const
+{
+ return (d->dat.confirmDelete());
+}
+
+/*!
+ \property Q3DataBrowser::confirmCancels
+ \brief whether the browser confirms cancel operations
+
+ If this property is true, all cancels must be confirmed by the
+ user through a message box (this behavior can be changed by
+ overriding the confirmCancel() function), otherwise all cancels
+ occur immediately. The default is false.
+
+ \sa confirmEdits() confirmCancel()
+*/
+
+void Q3DataBrowser::setConfirmCancels(bool confirm)
+{
+ d->dat.setConfirmCancels(confirm);
+}
+
+bool Q3DataBrowser::confirmCancels() const
+{
+ return d->dat.confirmCancels();
+}
+
+/*!
+ \property Q3DataBrowser::autoEdit
+ \brief whether the browser automatically applies edits
+
+ The default value for this property is true. When the user begins
+ an insertion or an update on a form there are two possible
+ outcomes when they navigate to another record:
+
+ \list
+ \i the insert or update is is performed -- this occurs if autoEdit is true
+ \i the insert or update is discarded -- this occurs if autoEdit is false
+ \endlist
+*/
+
+void Q3DataBrowser::setAutoEdit(bool autoEdit)
+{
+ d->dat.setAutoEdit(autoEdit);
+}
+
+bool Q3DataBrowser::autoEdit() const
+{
+ return d->dat.autoEdit();
+}
+
+/*!
+ \fn void Q3DataBrowser::firstRecordAvailable(bool available)
+
+ This signal is emitted whenever the position of the cursor
+ changes. The \a available parameter indicates whether or not the
+ first record in the default cursor is available.
+*/
+
+/*!
+ \fn void Q3DataBrowser::lastRecordAvailable(bool available)
+
+ This signal is emitted whenever the position of the cursor
+ changes. The \a available parameter indicates whether or not the
+ last record in the default cursor is available.
+*/
+
+/*!
+ \fn void Q3DataBrowser::nextRecordAvailable(bool available)
+
+ This signal is emitted whenever the position of the cursor
+ changes. The \a available parameter indicates whether or not the
+ next record in the default cursor is available.
+*/
+
+
+/*!
+ \fn void Q3DataBrowser::prevRecordAvailable(bool available)
+
+ This signal is emitted whenever the position of the cursor
+ changes. The \a available parameter indicates whether or not the
+ previous record in the default cursor is available.
+*/
+
+
+/*!
+ \fn void Q3DataBrowser::currentChanged(const QSqlRecord* record)
+
+ This signal is emitted whenever the current cursor position
+ changes. The \a record parameter points to the contents of the
+ current cursor's record.
+*/
+
+
+/*!
+ \fn void Q3DataBrowser::primeInsert(QSqlRecord* buf)
+
+ This signal is emitted when the data browser enters insertion
+ mode. The \a buf parameter points to the record buffer that is to
+ be inserted. Connect to this signal to, for example, prime the
+ record buffer with default data values, auto-numbered fields etc.
+ (Note that Q3SqlCursor::primeInsert() is \e not called on the
+ default cursor, as this would corrupt values in the form.)
+
+ \sa insert()
+*/
+
+
+/*!
+ \fn void Q3DataBrowser::primeUpdate(QSqlRecord* buf)
+
+ This signal is emitted when the data browser enters update mode.
+ Note that during navigation (first(), last(), next(), prev()),
+ each record that is shown in the default form is primed for
+ update. The \a buf parameter points to the record buffer being
+ updated. (Note that Q3SqlCursor::primeUpdate() is \e not called on
+ the default cursor, as this would corrupt values in the form.)
+ Connect to this signal in order to, for example, keep track of
+ which records have been updated, perhaps for auditing purposes.
+
+ \sa update()
+*/
+
+/*!
+ \fn void Q3DataBrowser::primeDelete(QSqlRecord* buf)
+
+ This signal is emitted when the data browser enters deletion mode.
+ The \a buf parameter points to the record buffer being deleted.
+ (Note that Q3SqlCursor::primeDelete() is \e not called on the
+ default cursor, as this would corrupt values in the form.)
+ Connect to this signal in order to, for example, save a copy of
+ the deleted record for auditing purposes.
+
+ \sa del()
+*/
+
+
+/*!
+ \fn void Q3DataBrowser::cursorChanged(Q3SqlCursor::Mode mode)
+
+ This signal is emitted whenever the cursor record was changed due
+ to navigation. The \a mode parameter is the edit that just took
+ place, e.g. Insert, Update or Delete. See \l Q3SqlCursor::Mode.
+*/
+
+
+/*!
+ Refreshes the data browser's data using the default cursor. The
+ browser's current filter and sort are applied if they have been
+ set.
+
+ \sa setFilter() setSort()
+*/
+
+void Q3DataBrowser::refresh()
+{
+ d->cur.refresh();
+}
+
+
+/*!
+ Performs an insert operation on the data browser's cursor. If
+ there is no default cursor or no default form, nothing happens.
+
+ If auto-editing is on (see setAutoEdit()), the following happens:
+
+ \list
+ \i If the browser is already actively inserting a record,
+ the current form's data is inserted into the database.
+ \i If the browser is not inserting a record, but the current record
+ was changed by the user, the record is updated in the database with
+ the current form's data (i.e. with the changes).
+ \endlist
+
+ If there is an error handling any of the above auto-edit actions,
+ handleError() is called and no insert or update is performed.
+
+ If no error occurred, or auto-editing is not enabled, the data browser
+ begins actively inserting a record into the database by performing the
+ following actions:
+
+ \list
+ \i The default cursor is primed for insert using Q3SqlCursor::primeInsert().
+ \i The primeInsert() signal is emitted.
+ \i The form is updated with the values in the default cursor's.
+ edit buffer so that the user can fill in the values to be inserted.
+ \endlist
+
+*/
+
+void Q3DataBrowser::insert()
+{
+ QSqlRecord* buf = d->frm.record();
+ Q3SqlCursor* cur = d->cur.cursor();
+ if (!buf || !cur)
+ return;
+ bool doIns = true;
+ QSql::Confirm conf = QSql::Yes;
+ switch (d->dat.mode()) {
+ case QSql::Insert:
+ if (autoEdit()) {
+ if (confirmInsert())
+ conf = confirmEdit(QSql::Insert);
+ switch (conf) {
+ case QSql::Yes:
+ insertCurrent();
+ break;
+ case QSql::No:
+ break;
+ case QSql::Cancel:
+ doIns = false;
+ break;
+ }
+ }
+ break;
+ default:
+ if (autoEdit() && currentEdited()) {
+ if (confirmUpdate())
+ conf = confirmEdit(QSql::Update);
+ switch (conf) {
+ case QSql::Yes:
+ updateCurrent();
+ break;
+ case QSql::No:
+ break;
+ case QSql::Cancel:
+ doIns = false;
+ break;
+ }
+ }
+ break;
+ }
+ if (doIns) {
+ d->dat.setMode(QSql::Insert);
+ sqlCursor()->primeInsert();
+ emit primeInsert(d->frm.record());
+ readFields();
+ }
+}
+
+
+/*!
+ Performs an update operation on the data browser's cursor.
+
+ If there is no default cursor or no default form, nothing happens.
+ Otherwise, the following happens:
+
+ If the data browser is actively inserting a record (see insert()),
+ that record is inserted into the database using insertCurrent().
+ Otherwise, the database is updated with the current form's data
+ using updateCurrent(). If there is an error handling either
+ action, handleError() is called.
+*/
+
+void Q3DataBrowser::update()
+{
+ QSqlRecord* buf = d->frm.record();
+ Q3SqlCursor* cur = d->cur.cursor();
+ if (!buf || !cur)
+ return;
+ QSql::Confirm conf = QSql::Yes;
+ switch (d->dat.mode()){
+ case QSql::Insert:
+ if (confirmInsert())
+ conf = confirmEdit(QSql::Insert);
+ switch (conf) {
+ case QSql::Yes:
+ if (insertCurrent())
+ d->dat.setMode(QSql::Update);
+ break;
+ case QSql::No:
+ d->dat.setMode(QSql::Update);
+ cur->editBuffer(true);
+ readFields();
+ break;
+ case QSql::Cancel:
+ break;
+ }
+ break;
+ default:
+ d->dat.setMode(QSql::Update);
+ if (confirmUpdate())
+ conf = confirmEdit(QSql::Update);
+ switch (conf) {
+ case QSql::Yes:
+ updateCurrent();
+ break;
+ case QSql::No:
+ case QSql::Cancel:
+ break;
+ }
+ break;
+ }
+}
+
+
+/*!
+ Performs a delete operation on the data browser's cursor. If there
+ is no default cursor or no default form, nothing happens.
+
+ Otherwise, the following happens:
+
+ The current form's record is deleted from the database, providing
+ that the data browser is not in insert mode. If the data browser
+ is actively inserting a record (see insert()), the insert action
+ is canceled, and the browser navigates to the last valid record
+ that was current. If there is an error, handleError() is called.
+*/
+
+void Q3DataBrowser::del()
+{
+ QSqlRecord* buf = d->frm.record();
+ Q3SqlCursor* cur = d->cur.cursor();
+ if (!buf || !cur)
+ return;
+ QSql::Confirm conf = QSql::Yes;
+ switch (d->dat.mode()){
+ case QSql::Insert:
+ if (confirmCancels())
+ conf = confirmCancel(QSql::Insert);
+ if (conf == QSql::Yes) {
+ cur->editBuffer(true); /* restore from cursor */
+ readFields();
+ d->dat.setMode(QSql::Update);
+ } else
+ d->dat.setMode(QSql::Insert);
+ break;
+ default:
+ if (confirmDelete())
+ conf = confirmEdit(QSql::Delete);
+ switch (conf) {
+ case QSql::Yes:
+ emit primeDelete(buf);
+ deleteCurrent();
+ break;
+ case QSql::No:
+ case QSql::Cancel:
+ break;
+ }
+ d->dat.setMode(QSql::Update);
+ break;
+ }
+}
+
+/*!
+ Moves the default cursor to the record specified by index \a i
+ and refreshes the default form to display that record. If there is
+ no default form or no default cursor, nothing happens. If
+ \a relative is true (the default is false), the cursor is moved
+ relative to its current position. If the data browser successfully
+ navigated to the desired record, the default cursor is primed for
+ update and the primeUpdate() signal is emitted.
+
+ If the browser is already positioned on the desired record nothing
+ happens. Returns false if there is no cursor. Otherwise returns
+ true.
+*/
+
+bool Q3DataBrowser::seek(int i, bool relative)
+{
+ int b = 0;
+ Q3SqlCursor* cur = d->cur.cursor();
+ if (!cur)
+ return false;
+ if (preNav())
+ b = cur->seek(i, relative);
+ postNav(b);
+ return b;
+}
+
+/*!
+ Moves the default cursor to the first record and refreshes the
+ default form to display this record. If there is no default form
+ or no default cursor, nothing happens. If the data browser
+ successfully navigated to the first record, the default cursor is
+ primed for update and the primeUpdate() signal is emitted.
+
+ If the browser is already positioned on the first record nothing
+ happens.
+
+*/
+
+void Q3DataBrowser::first()
+{
+ nav(&Q3SqlCursor::first);
+}
+
+
+/*!
+ Moves the default cursor to the last record and refreshes the
+ default form to display this record. If there is no default form
+ or no default cursor, nothing happens. If the data browser
+ successfully navigated to the last record, the default cursor is
+ primed for update and the primeUpdate() signal is emitted.
+
+ If the browser is already positioned on the last record nothing
+ happens.
+*/
+
+void Q3DataBrowser::last()
+{
+ nav(&Q3SqlCursor::last);
+}
+
+
+/*!
+ Moves the default cursor to the next record and refreshes the
+ default form to display this record. If there is no default form
+ or no default cursor, nothing happens. If the data browser
+ successfully navigated to the next record, the default cursor is
+ primed for update and the primeUpdate() signal is emitted.
+
+ If the browser is positioned on the last record nothing happens.
+*/
+
+void Q3DataBrowser::next()
+{
+ nav(&Q3SqlCursor::next);
+}
+
+
+/*!
+ Moves the default cursor to the previous record and refreshes the
+ default form to display this record. If there is no default form
+ or no default cursor, nothing happens. If the data browser
+ successfully navigated to the previous record, the default cursor
+ is primed for update and the primeUpdate() signal is emitted.
+
+ If the browser is positioned on the first record nothing happens.
+*/
+
+void Q3DataBrowser::prev()
+{
+ nav(&Q3SqlCursor::previous);
+}
+
+/*!
+ Reads the fields from the default cursor's edit buffer and
+ displays them in the form. If there is no default cursor or no
+ default form, nothing happens.
+*/
+
+void Q3DataBrowser::readFields()
+{
+ d->frm.readFields();
+}
+
+
+/*!
+ Writes the form's data to the default cursor's edit buffer. If
+ there is no default cursor or no default form, nothing happens.
+*/
+
+void Q3DataBrowser::writeFields()
+{
+ d->frm.writeFields();
+}
+
+
+/*!
+ Clears all the values in the form.
+
+ All the edit buffer field values are set to their 'zero state',
+ e.g. 0 for numeric fields and "" for string fields. Then the
+ widgets are updated using the property map. For example, a
+ combobox that is property-mapped to integers would scroll to the
+ first item. See the \l Q3SqlPropertyMap constructor for the default
+ mappings of widgets to properties.
+*/
+
+void Q3DataBrowser::clearValues()
+{
+ d->frm.clearValues();
+}
+
+/*!
+ Reads the fields from the default form into the default cursor and
+ performs an insert on the default cursor. If there is no default
+ form or no default cursor, nothing happens. If an error occurred
+ during the insert into the database, handleError() is called and
+ false is returned. If the insert was successful, the cursor is
+ refreshed and relocated to the newly inserted record, the
+ cursorChanged() signal is emitted, and true is returned.
+
+ \sa cursorChanged() sqlCursor() form() handleError()
+*/
+
+bool Q3DataBrowser::insertCurrent()
+{
+ if (isReadOnly())
+ return false;
+ QSqlRecord* buf = d->frm.record();
+ Q3SqlCursor* cur = d->cur.cursor();
+ if (!buf || !cur)
+ return false;
+ writeFields();
+ emit beforeInsert(buf);
+ int ar = cur->insert();
+ if (!ar || !cur->isActive()) {
+ handleError(cur->lastError());
+ refresh();
+ updateBoundary();
+ } else {
+ refresh();
+ d->cur.findBuffer(cur->primaryIndex());
+ updateBoundary();
+ cursorChanged(Q3SqlCursor::Insert);
+ return true;
+ }
+ return false;
+}
+
+
+/*!
+ Reads the fields from the default form into the default cursor and
+ performs an update on the default cursor. If there is no default
+ form or no default cursor, nothing happens. If an error occurred
+ during the update on the database, handleError() is called and
+ false is returned. If the update was successful, the cursor is
+ refreshed and relocated to the updated record, the cursorChanged()
+ signal is emitted, and true is returned.
+
+ \sa cursor() form() handleError()
+*/
+
+bool Q3DataBrowser::updateCurrent()
+{
+ if (isReadOnly())
+ return false;
+ QSqlRecord* buf = d->frm.record();
+ Q3SqlCursor* cur = d->cur.cursor();
+ if (!buf || !cur)
+ return false;
+ writeFields();
+ emit beforeUpdate(buf);
+ int ar = cur->update();
+ if (!ar || !cur->isActive()) {
+ handleError(cur->lastError());
+ refresh();
+ updateBoundary();
+ } else {
+ refresh();
+ d->cur.findBuffer(cur->primaryIndex());
+ updateBoundary();
+ cur->editBuffer(true);
+ cursorChanged(Q3SqlCursor::Update);
+ readFields();
+ return true;
+ }
+ return false;
+}
+
+
+/*!
+ Performs a delete on the default cursor using the values from the
+ default form and updates the default form. If there is no default
+ form or no default cursor, nothing happens. If the deletion was
+ successful, the cursor is repositioned to the nearest record and
+ true is returned. The nearest record is the next record if there
+ is one otherwise the previous record if there is one. If an error
+ occurred during the deletion from the database, handleError() is
+ called and false is returned.
+
+ \sa cursor() form() handleError()
+*/
+
+bool Q3DataBrowser::deleteCurrent()
+{
+ if (isReadOnly())
+ return false;
+ QSqlRecord* buf = d->frm.record();
+ Q3SqlCursor* cur = d->cur.cursor();
+ if (!buf || !cur)
+ return false;
+ writeFields();
+ int n = cur->at();
+ emit beforeDelete(buf);
+ int ar = cur->del();
+ if (ar) {
+ refresh();
+ updateBoundary();
+ cursorChanged(Q3SqlCursor::Delete);
+ if (!cur->seek(n))
+ last();
+ if (cur->isValid()) {
+ cur->editBuffer(true);
+ readFields();
+ } else {
+ clearValues();
+ }
+ return true;
+ } else {
+ if (!cur->isActive()) {
+ handleError(cur->lastError());
+ refresh();
+ updateBoundary();
+ }
+ }
+ return false;
+}
+
+
+/*!
+ Returns true if the form's edit buffer differs from the current
+ cursor buffer; otherwise returns false.
+*/
+
+bool Q3DataBrowser::currentEdited()
+{
+ QSqlRecord* buf = d->frm.record();
+ Q3SqlCursor* cur = d->cur.cursor();
+ if (!buf || !cur)
+ return false;
+ if (!cur->isActive() || !cur->isValid())
+ return false;
+ writeFields();
+ for (int i = 0; i < cur->count(); ++i) {
+ if (cur->value(i) != buf->value(i))
+ return true;
+ }
+ return false;
+}
+
+/*! \internal
+
+ Pre-navigation checking.
+*/
+
+bool Q3DataBrowser::preNav()
+{
+ QSqlRecord* buf = d->frm.record();
+ Q3SqlCursor* cur = d->cur.cursor();
+ if (!buf || !cur)
+ return false;
+
+ if (!isReadOnly() && autoEdit() && currentEdited()) {
+ bool ok = true;
+ QSql::Confirm conf = QSql::Yes;
+ switch (d->dat.mode()){
+ case QSql::Insert:
+ if (confirmInsert())
+ conf = confirmEdit(QSql::Insert);
+ switch (conf) {
+ case QSql::Yes:
+ ok = insertCurrent();
+ d->dat.setMode(QSql::Update);
+ break;
+ case QSql::No:
+ d->dat.setMode(QSql::Update);
+ break;
+ case QSql::Cancel:
+ return false;
+ }
+ break;
+ default:
+ if (confirmUpdate())
+ conf = confirmEdit(QSql::Update);
+ switch (conf) {
+ case QSql::Yes:
+ ok = updateCurrent();
+ break;
+ case QSql::No:
+ break;
+ case QSql::Cancel:
+ return false;
+ }
+ }
+ return ok;
+ }
+ return true;
+}
+
+/*! \internal
+
+ Handles post-navigation according to \a primeUpd.
+*/
+
+void Q3DataBrowser::postNav(bool primeUpd)
+{
+ if (primeUpd) {
+ QSqlRecord* buf = d->frm.record();
+ Q3SqlCursor* cur = d->cur.cursor();
+ if (!buf || !cur)
+ return;
+ currentChanged(cur);
+ cur->primeUpdate();
+ emit primeUpdate(buf);
+ readFields();
+ }
+ updateBoundary();
+}
+
+/*! \internal
+
+ Navigate default cursor according to \a nav. Handles autoEdit.
+
+*/
+void Q3DataBrowser::nav(Nav nav)
+{
+ int b = 0;
+ Q3SqlCursor* cur = d->cur.cursor();
+ if (!cur)
+ return;
+ if (preNav())
+ b = (cur->*nav)();
+ postNav(b);
+}
+
+/*!
+ If boundaryChecking() is true, checks the boundary of the current
+ default cursor and emits signals which indicate the position of
+ the cursor.
+*/
+
+void Q3DataBrowser::updateBoundary()
+{
+ if (d->boundaryCheck) {
+ Boundary bound = boundary();
+ switch (bound) {
+ case Unknown:
+ case None:
+ emit firstRecordAvailable(true);
+ emit prevRecordAvailable(true);
+ emit nextRecordAvailable(true);
+ emit lastRecordAvailable(true);
+ break;
+
+ case BeforeBeginning:
+ emit firstRecordAvailable(false);
+ emit prevRecordAvailable(false);
+ emit nextRecordAvailable(true);
+ emit lastRecordAvailable(true);
+ break;
+
+ case Beginning:
+ emit firstRecordAvailable(false);
+ emit prevRecordAvailable(false);
+ emit nextRecordAvailable(true);
+ emit lastRecordAvailable(true);
+ break;
+
+ case End:
+ emit firstRecordAvailable(true);
+ emit prevRecordAvailable(true);
+ emit nextRecordAvailable(false);
+ emit lastRecordAvailable(false);
+ break;
+
+ case AfterEnd:
+ emit firstRecordAvailable(true);
+ emit prevRecordAvailable(true);
+ emit nextRecordAvailable(false);
+ emit lastRecordAvailable(false);
+ break;
+ }
+ }
+}
+
+/*!
+ Virtual function which handles the error \a error. The default
+ implementation warns the user with a message box.
+*/
+
+void Q3DataBrowser::handleError(const QSqlError& error)
+{
+ d->dat.handleError(this, error);
+}
+
+/*!
+ Protected virtual function which returns a confirmation for an
+ edit of mode \a m. Derived classes can reimplement this function
+ and provide their own confirmation dialog. The default
+ implementation uses a message box which prompts the user to
+ confirm the edit action.
+*/
+
+QSql::Confirm Q3DataBrowser::confirmEdit(QSql::Op m)
+{
+ return d->dat.confirmEdit(this, m);
+}
+
+/*!
+ Protected virtual function which returns a confirmation for
+ canceling an edit mode \a m. Derived classes can reimplement this
+ function and provide their own confirmation dialog. The default
+ implementation uses a message box which prompts the user to
+ confirm the edit action.
+*/
+
+QSql::Confirm Q3DataBrowser::confirmCancel(QSql::Op m)
+{
+ return d->dat.confirmCancel(this, m);
+}
+
+/*!
+ \fn void Q3DataBrowser::beforeInsert(QSqlRecord* buf)
+
+ This signal is emitted just before the cursor's edit buffer is
+ inserted into the database. The \a buf parameter points to the
+ edit buffer being inserted. You might connect to this signal to
+ populate a generated primary key for example.
+*/
+
+/*!
+ \fn void Q3DataBrowser::beforeUpdate(QSqlRecord* buf)
+
+ This signal is emitted just before the cursor's edit buffer is
+ updated in the database. The \a buf parameter points to the edit
+ buffer being updated. You might connect to this signal to capture
+ some auditing information about the update.
+*/
+
+/*!
+ \fn void Q3DataBrowser::beforeDelete(QSqlRecord* buf)
+
+ This signal is emitted just before the cursor's edit buffer is
+ deleted from the database. The \a buf parameter points to the edit
+ buffer being deleted. You might connect to this signal to capture
+ some auditing information about the deletion.
+*/
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qt3support/sql/q3databrowser.h b/src/qt3support/sql/q3databrowser.h
new file mode 100644
index 0000000..5727a63
--- /dev/null
+++ b/src/qt3support/sql/q3databrowser.h
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DATABROWSER_H
+#define Q3DATABROWSER_H
+
+#include <QtGui/qwidget.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtSql/qsql.h>
+#include <QtSql/qsqlindex.h>
+#include <Qt3Support/q3sqlcursor.h>
+#include <QtSql/qsqlerror.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3Support)
+
+#ifndef QT_NO_SQL_VIEW_WIDGETS
+
+class Q3SqlForm;
+class Q3DataBrowserPrivate;
+
+class Q_COMPAT_EXPORT Q3DataBrowser : public QWidget
+{
+ Q_OBJECT
+ Q_PROPERTY(bool boundaryChecking READ boundaryChecking WRITE setBoundaryChecking)
+ Q_PROPERTY(QString filter READ filter WRITE setFilter)
+ Q_PROPERTY(QStringList sort READ sort WRITE setSort)
+ Q_PROPERTY(bool confirmEdits READ confirmEdits WRITE setConfirmEdits)
+ Q_PROPERTY(bool confirmInsert READ confirmInsert WRITE setConfirmInsert)
+ Q_PROPERTY(bool confirmUpdate READ confirmUpdate WRITE setConfirmUpdate)
+ Q_PROPERTY(bool confirmDelete READ confirmDelete WRITE setConfirmDelete)
+ Q_PROPERTY(bool confirmCancels READ confirmCancels WRITE setConfirmCancels)
+ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly)
+ Q_PROPERTY(bool autoEdit READ autoEdit WRITE setAutoEdit)
+
+public:
+ Q3DataBrowser(QWidget* parent=0, const char* name=0, Qt::WindowFlags fl = 0);
+ ~Q3DataBrowser();
+
+ enum Boundary {
+ Unknown,
+ None,
+ BeforeBeginning,
+ Beginning,
+ End,
+ AfterEnd
+ };
+
+ Boundary boundary();
+ void setBoundaryChecking(bool active);
+ bool boundaryChecking() const;
+
+ void setSort(const QSqlIndex& sort);
+ void setSort(const QStringList& sort);
+ QStringList sort() const;
+ void setFilter(const QString& filter);
+ QString filter() const;
+ virtual void setSqlCursor(Q3SqlCursor* cursor, bool autoDelete = false);
+ Q3SqlCursor* sqlCursor() const;
+ virtual void setForm(Q3SqlForm* form);
+ Q3SqlForm* form();
+
+ virtual void setConfirmEdits(bool confirm);
+ virtual void setConfirmInsert(bool confirm);
+ virtual void setConfirmUpdate(bool confirm);
+ virtual void setConfirmDelete(bool confirm);
+ virtual void setConfirmCancels(bool confirm);
+ bool confirmEdits() const;
+ bool confirmInsert() const;
+ bool confirmUpdate() const;
+ bool confirmDelete() const;
+ bool confirmCancels() const;
+
+ virtual void setReadOnly(bool active);
+ bool isReadOnly() const;
+ virtual void setAutoEdit(bool autoEdit);
+ bool autoEdit() const;
+
+ virtual bool seek(int i, bool relative = false);
+
+Q_SIGNALS:
+ void firstRecordAvailable(bool available);
+ void lastRecordAvailable(bool available);
+ void nextRecordAvailable(bool available);
+ void prevRecordAvailable(bool available);
+
+ void currentChanged(const QSqlRecord* record);
+ void primeInsert(QSqlRecord* buf);
+ void primeUpdate(QSqlRecord* buf);
+ void primeDelete(QSqlRecord* buf);
+ void beforeInsert(QSqlRecord* buf);
+ void beforeUpdate(QSqlRecord* buf);
+ void beforeDelete(QSqlRecord* buf);
+ void cursorChanged(Q3SqlCursor::Mode mode);
+
+public Q_SLOTS:
+ virtual void refresh();
+
+ virtual void insert();
+ virtual void update();
+ virtual void del();
+
+ virtual void first();
+ virtual void last();
+ virtual void next();
+ virtual void prev();
+
+ virtual void readFields();
+ virtual void writeFields();
+ virtual void clearValues();
+
+ void updateBoundary();
+
+protected:
+ virtual bool insertCurrent();
+ virtual bool updateCurrent();
+ virtual bool deleteCurrent();
+ virtual bool currentEdited();
+
+ virtual QSql::Confirm confirmEdit(QSql::Op m);
+ virtual QSql::Confirm confirmCancel(QSql::Op m);
+
+ virtual void handleError(const QSqlError& error);
+
+private:
+ typedef bool (Q3SqlCursor::*Nav)();
+ bool preNav();
+ void postNav(bool primeUpd);
+ void nav(Nav nav);
+ Q3DataBrowserPrivate* d;
+
+ Q_DISABLE_COPY(Q3DataBrowser)
+};
+
+#endif // QT_NO_SQL_VIEW_WIDGETS
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3DATABROWSER_H
diff --git a/src/qt3support/sql/q3datatable.cpp b/src/qt3support/sql/q3datatable.cpp
new file mode 100644
index 0000000..559abaf
--- /dev/null
+++ b/src/qt3support/sql/q3datatable.cpp
@@ -0,0 +1,2335 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3datatable.h"
+
+#ifndef QT_NO_SQL_VIEW_WIDGETS
+
+#include "qevent.h"
+#include "qsqldriver.h"
+#include "q3sqleditorfactory.h"
+#include "q3sqlpropertymap.h"
+#include "qapplication.h"
+#include "qlayout.h"
+#include "qpainter.h"
+#include "q3popupmenu.h"
+#include "q3valuelist.h"
+#include "q3sqlmanager_p.h"
+#include "qsqlfield.h"
+#include "qdatetime.h"
+#include "qcursor.h"
+#include "qtimer.h"
+#include "qpointer.h"
+
+QT_BEGIN_NAMESPACE
+
+//#define QT_DEBUG_DATATABLE
+
+class Q3DataTablePrivate
+{
+public:
+ Q3DataTablePrivate()
+ : nullTxtChanged( false ),
+ haveAllRows( false ),
+ continuousEdit( false ),
+ editorFactory( 0 ),
+ propertyMap( 0 ),
+ datefmt( Qt::TextDate ),
+ editRow( -1 ),
+ editCol( -1 ),
+ insertRowLast( -1 ),
+ insertPreRows( -1 ),
+ editBuffer( 0 ),
+ cancelMode( false ),
+ cancelInsert( false ),
+ cancelUpdate( false ),
+ lastAt( -1 )
+ {}
+ ~Q3DataTablePrivate() { if ( propertyMap ) delete propertyMap; }
+
+ QString nullTxt;
+ bool nullTxtChanged;
+ typedef Q3ValueList< uint > ColIndex;
+ ColIndex colIndex;
+ bool haveAllRows;
+ bool continuousEdit;
+ Q3SqlEditorFactory* editorFactory;
+ Q3SqlPropertyMap* propertyMap;
+ QString trueTxt;
+ Qt::DateFormat datefmt;
+ QString falseTxt;
+ int editRow;
+ int editCol;
+ int insertRowLast;
+ QString insertHeaderLabelLast;
+ int insertPreRows;
+ QSqlRecord* editBuffer;
+ bool cancelMode;
+ bool cancelInsert;
+ bool cancelUpdate;
+ int lastAt;
+ QString ftr;
+ QStringList srt;
+ QStringList fld;
+ QStringList fldLabel;
+ Q3ValueList<int> fldWidth;
+ Q3ValueList<QIconSet> fldIcon;
+ Q3ValueList<bool> fldHidden;
+ Q3SqlCursorManager cur;
+ Q3DataManager dat;
+};
+
+#ifdef QT_DEBUG_DATATABLE
+void qt_debug_buffer( const QString& msg, QSqlRecord* cursor )
+{
+ qDebug("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
+ qDebug(msg);
+ for ( uint j = 0; j < cursor->count(); ++j ) {
+ qDebug(cursor->field(j)->name() + " type:" + QString(cursor->field(j)->value().typeName()) + " value:" + cursor->field(j)->value().toString() );
+ }
+}
+#endif
+
+/*!
+ \enum Q3DataTable::Refresh
+
+ This enum describes the refresh options.
+
+ \value RefreshData refresh the data, i.e. read it from the database
+ \value RefreshColumns refresh the list of fields, e.g. the column headings
+ \value RefreshAll refresh both the data and the list of fields
+*/
+
+
+/*!
+ \class Q3DataTable
+ \brief The Q3DataTable class provides a flexible SQL table widget that supports browsing and editing.
+
+ \compat
+
+ Q3DataTable supports various functions for presenting and editing
+ SQL data from a \l Q3SqlCursor in a table.
+
+ If you want a to present your data in a form use QDataBrowser, or
+ for read-only forms, use QDataView instead.
+
+ When displaying data, Q3DataTable only retrieves data for visible
+ rows. If the driver supports the 'query size' property the
+ Q3DataTable will have the correct number of rows and the vertical
+ scroll bar will accurately reflect the number of rows displayed in
+ proportion to the number of rows in the dataset. If the driver
+ does not support the 'query size' property, rows are dynamically
+ fetched from the database on an as-needed basis with the scroll bar
+ becoming more accurate as the user scrolls down through the
+ records. This allows extremely large queries to be displayed as
+ quickly as possible, with minimum memory usage.
+
+ Q3DataTable inherits Q3Table's API and extends it with functions to
+ sort and filter the data and sort columns. See setSqlCursor(),
+ setFilter(), setSort(), setSorting(), sortColumn() and refresh().
+
+ When displaying editable cursors, cell editing will be enabled.
+ (For more information on editable cursors, see \l Q3SqlCursor).
+ Q3DataTable can be used to modify existing data and to add new
+ records. When a user makes changes to a field in the table, the
+ cursor's edit buffer is used. The table will not send changes in
+ the edit buffer to the database until the user moves to a
+ different record in the grid or presses Enter. Cell editing is
+ initiated by pressing F2 (or right clicking and then clicking the
+ appropriate popup menu item) and canceled by pressing Esc. If
+ there is a problem updating or adding data, errors are handled
+ automatically (see handleError() to change this behavior). Note
+ that if autoEdit() is false navigating to another record will
+ cancel the insert or update.
+
+ The user can be asked to confirm all edits with setConfirmEdits().
+ For more precise control use setConfirmInsert(),
+ setConfirmUpdate(), setConfirmDelete() and setConfirmCancels().
+ Use setAutoEdit() to control the behavior of the table when the
+ user edits a record and then navigates. (Note that setAutoDelete()
+ is unrelated; it is used to set whether the Q3SqlCursor is deleted
+ when the table is deleted.)
+
+ Since the data table can perform edits, it must be able to
+ uniquely identify every record so that edits are correctly
+ applied. Because of this the underlying cursor must have a valid
+ primary index to ensure that a unique record is inserted, updated
+ or deleted within the database otherwise the database may be
+ changed to an inconsistent state.
+
+ Q3DataTable creates editors using the default \l Q3SqlEditorFactory.
+ Different editor factories can be used by calling
+ installEditorFactory(). A property map is used to map between the
+ cell's value and the editor. You can use your own property map
+ with installPropertyMap().
+
+ The contents of a cell is available as a QString with text() or as
+ a QVariant with value(). The current record is returned by
+ currentRecord(). Use the find() function to search for a string in
+ the table.
+
+ Editing actions can be applied programmatically. For example, the
+ insertCurrent() function reads the fields from the current record
+ into the cursor and performs the insert. The updateCurrent() and
+ deleteCurrent() functions perform similarly to update and delete
+ the current record respectively.
+
+ Columns in the table can be created automatically based on the
+ cursor (see setSqlCursor()). Columns can be manipulated manually
+ using addColumn(), removeColumn() and setColumn().
+
+ The table automatically copies many of the properties of the
+ cursor to format the display of data within cells (alignment,
+ visibility, etc.). The cursor can be changed with setSqlCursor().
+ The filter (see setFilter()) and sort defined within the table are
+ used instead of the filter and sort set on the cursor. For sorting
+ options see setSort(), sortColumn(), sortAscending() and
+ sortDescending(). Note that sorting operations will not behave as
+ expected if you are using a QSqlSelectCursor because it uses
+ user-defined SQL queries to obtain data.
+
+ The text used to represent NULL, true and false values can be
+ changed with setNullText(), setTrueText() and setFalseText()
+ respectively. You can change the appearance of cells by
+ reimplementing paintField().
+
+ Whenever a new row is selected in the table the currentChanged()
+ signal is emitted. The primeInsert() signal is emitted when an
+ insert is initiated. The primeUpdate() and primeDelete() signals
+ are emitted when update and deletion are initiated respectively.
+ Just before the database is updated a signal is emitted;
+ beforeInsert(), beforeUpdate() or beforeDelete() as appropriate.
+
+*/
+
+/*!
+ Constructs a data table which is a child of \a parent, called
+ name \a name.
+*/
+
+Q3DataTable::Q3DataTable ( QWidget * parent, const char * name )
+ : Q3Table( parent, name )
+{
+ init();
+}
+
+/*!
+ Constructs a data table which is a child of \a parent, called name
+ \a name using the cursor \a cursor.
+
+ If \a autoPopulate is true (the default is false), columns are
+ automatically created based upon the fields in the \a cursor
+ record. Note that \a autoPopulate only governs the creation of
+ columns; to load the cursor's data into the table use refresh().
+
+ If the \a cursor is read-only, the table also becomes read-only.
+ In addition, the table adopts the cursor's driver's definition for
+ representing NULL values as strings.
+*/
+
+Q3DataTable::Q3DataTable ( Q3SqlCursor* cursor, bool autoPopulate, QWidget * parent, const char * name )
+ : Q3Table( parent, name )
+{
+ init();
+ setSqlCursor( cursor, autoPopulate );
+}
+
+/*! \internal
+*/
+
+
+void Q3DataTable::init()
+{
+ d = new Q3DataTablePrivate();
+ setAutoEdit( true );
+ setSelectionMode( SingleRow );
+ setFocusStyle( FollowStyle );
+ d->trueTxt = tr( "True" );
+ d->falseTxt = tr( "False" );
+ d->datefmt = Qt::LocalDate;
+ reset();
+ connect( this, SIGNAL(selectionChanged()),
+ SLOT(updateCurrentSelection()));
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+Q3DataTable::~Q3DataTable()
+{
+ delete d;
+}
+
+
+/*!
+ Adds the next column to be displayed using the field \a fieldName,
+ column label \a label, width \a width and iconset \a iconset.
+
+ If \a label is specified, it is used as the column's header label,
+ otherwise the field's display label is used when setSqlCursor() is
+ called. The \a iconset is used to set the icon used by the column
+ header; by default there is no icon.
+
+ \sa setSqlCursor() refresh()
+*/
+
+void Q3DataTable::addColumn( const QString& fieldName,
+ const QString& label,
+ int width,
+ const QIconSet& iconset )
+{
+ d->fld += fieldName;
+ d->fldLabel += label;
+ d->fldIcon += iconset;
+ d->fldWidth += width;
+ d->fldHidden += false;
+}
+
+/*!
+ Sets the \a col column to display using the field \a fieldName,
+ column label \a label, width \a width and iconset \a iconset.
+
+ If \a label is specified, it is used as the column's header label,
+ otherwise the field's display label is used when setSqlCursor() is
+ called. The \a iconset is used to set the icon used by the column
+ header; by default there is no icon.
+
+ \sa setSqlCursor() refresh()
+*/
+
+void Q3DataTable::setColumn( uint col, const QString& fieldName,
+ const QString& label,
+ int width,
+ const QIconSet& iconset )
+{
+ d->fld[col]= fieldName;
+ d->fldLabel[col] = label;
+ d->fldIcon[col] = iconset;
+ d->fldWidth[col] = width;
+ d->fldHidden[col] = false;
+}
+
+/*!
+ Removes column \a col from the list of columns to be displayed. If
+ \a col does not exist, nothing happens.
+
+ \sa QSqlField
+*/
+
+void Q3DataTable::removeColumn( int col )
+{
+ if ( d->fld.begin() + col != d->fld.end() ) {
+ d->fld.remove( d->fld.at( col ) );
+ d->fldLabel.remove( d->fldLabel.at( col ) );
+ d->fldIcon.remove( d->fldIcon.at( col ) );
+ d->fldWidth.remove( d->fldWidth.at( col ) );
+ d->fldHidden.remove( d->fldHidden.at( col ) );
+ }
+}
+
+/*!
+ Sets the column \a col to the width \a w. Note that unlike Q3Table
+ the Q3DataTable is not immediately redrawn, you must call
+ refresh(Q3DataTable::RefreshColumns)
+ yourself.
+
+ \sa refresh()
+*/
+void Q3DataTable::setColumnWidth( int col, int w )
+{
+ if ( d->fldWidth.at( col ) != d->fldWidth.end() ) {
+ d->fldWidth[col] = w;
+ }
+}
+
+/*!
+ Resizes column \a col so that the column width is wide enough to
+ display the widest item the column contains (including the column
+ label). If the table's Q3SqlCursor is not currently active, the
+ cursor will be refreshed before the column width is calculated. Be
+ aware that this function may be slow on tables that contain large
+ result sets.
+*/
+void Q3DataTable::adjustColumn( int col )
+{
+ Q3SqlCursor * cur = sqlCursor();
+ if ( !cur || cur->count() <= col )
+ return;
+ if ( !cur->isActive() ) {
+ d->cur.refresh();
+ }
+ int oldRow = currentRow();
+ int w = fontMetrics().width( horizontalHeader()->label( col ) + QLatin1Char('W') );
+ cur->seek( QSql::BeforeFirst );
+ while ( cur->next() ) {
+ w = qMax( w, fontMetrics().width( fieldToString( cur->fieldPtr( indexOf( col ) ) ) ) + 10 );
+ }
+ setColumnWidth( col, w );
+ cur->seek( oldRow );
+ refresh( RefreshColumns );
+}
+
+/*! \reimp
+*/
+void Q3DataTable::setColumnStretchable( int col, bool s )
+{
+ if ( numCols() == 0 ) {
+ refresh( RefreshColumns );
+ }
+ if ( numCols() > col ) {
+ Q3Table::setColumnStretchable( col, s );
+ }
+}
+
+QString Q3DataTable::filter() const
+{
+ return d->cur.filter();
+}
+
+/*!
+ \property Q3DataTable::filter
+ \brief the data filter for the data table
+
+ The filter applies to the data shown in the table. To view data
+ with a new filter, use refresh(). A filter string is an SQL WHERE
+ clause without the WHERE keyword.
+
+ There is no default filter.
+
+ \sa sort()
+
+*/
+
+void Q3DataTable::setFilter( const QString& filter )
+{
+ d->cur.setFilter( filter );
+}
+
+
+/*!
+ \property Q3DataTable::sort
+ \brief the data table's sort
+
+ The table's sort affects the order in which data records are
+ displayed in the table. To apply a sort, use refresh().
+
+ When examining the sort property, a string list is returned with
+ each item having the form 'fieldname order' (e.g., 'id ASC',
+ 'surname DESC').
+
+ There is no default sort.
+
+ Note that if you want to iterate over the sort list, you should
+ iterate over a copy, e.g.
+ \snippet doc/src/snippets/code/src_qt3support_sql_q3datatable.cpp 0
+
+ \sa filter() refresh()
+*/
+
+void Q3DataTable::setSort( const QStringList& sort )
+{
+ d->cur.setSort( sort );
+}
+
+/*!
+ \overload
+
+ Sets the sort to be applied to the displayed data to \a sort. If
+ there is no current cursor, nothing happens. A QSqlIndex contains
+ field names and their ordering (ASC or DESC); these are used to
+ compose the ORDER BY clause.
+
+ \sa sort()
+*/
+
+void Q3DataTable::setSort( const QSqlIndex& sort )
+{
+ d->cur.setSort( sort );
+}
+
+QStringList Q3DataTable::sort() const
+{
+ return d->cur.sort();
+}
+
+/*!
+ Returns the cursor used by the data table.
+*/
+
+Q3SqlCursor* Q3DataTable::sqlCursor() const
+{
+ return d->cur.cursor();
+}
+
+void Q3DataTable::setConfirmEdits( bool confirm )
+{
+ d->dat.setConfirmEdits( confirm );
+}
+
+void Q3DataTable::setConfirmInsert( bool confirm )
+{
+ d->dat.setConfirmInsert( confirm );
+}
+
+void Q3DataTable::setConfirmUpdate( bool confirm )
+{
+ d->dat.setConfirmUpdate( confirm );
+}
+
+void Q3DataTable::setConfirmDelete( bool confirm )
+{
+ d->dat.setConfirmDelete( confirm );
+}
+
+/*!
+ \property Q3DataTable::confirmEdits
+ \brief whether the data table confirms edit operations
+
+ If the confirmEdits property is true, the data table confirms all
+ edit operations (inserts, updates and deletes). Finer control of
+ edit confirmation can be achieved using \l confirmCancels, \l
+ confirmInsert, \l confirmUpdate and \l confirmDelete.
+
+ \sa confirmCancels() confirmInsert() confirmUpdate() confirmDelete()
+*/
+
+bool Q3DataTable::confirmEdits() const
+{
+ return ( d->dat.confirmEdits() );
+}
+
+/*!
+ \property Q3DataTable::confirmInsert
+ \brief whether the data table confirms insert operations
+
+ If the confirmInsert property is true, all insertions must be
+ confirmed by the user through a message box (this behavior can be
+ changed by overriding the confirmEdit() function), otherwise all
+ insert operations occur immediately.
+
+ \sa confirmCancels() confirmEdits() confirmUpdate() confirmDelete()
+*/
+
+bool Q3DataTable::confirmInsert() const
+{
+ return ( d->dat.confirmInsert() );
+}
+
+/*!
+ \property Q3DataTable::confirmUpdate
+ \brief whether the data table confirms update operations
+
+ If the confirmUpdate property is true, all updates must be
+ confirmed by the user through a message box (this behavior can be
+ changed by overriding the confirmEdit() function), otherwise all
+ update operations occur immediately.
+
+ \sa confirmCancels() confirmEdits() confirmInsert() confirmDelete()
+*/
+
+bool Q3DataTable::confirmUpdate() const
+{
+ return ( d->dat.confirmUpdate() );
+}
+
+/*!
+ \property Q3DataTable::confirmDelete
+ \brief whether the data table confirms delete operations
+
+ If the confirmDelete property is true, all deletions must be
+ confirmed by the user through a message box (this behavior can be
+ changed by overriding the confirmEdit() function), otherwise all
+ delete operations occur immediately.
+
+ \sa confirmCancels() confirmEdits() confirmUpdate() confirmInsert()
+*/
+
+bool Q3DataTable::confirmDelete() const
+{
+ return ( d->dat.confirmDelete() );
+}
+
+/*!
+ \property Q3DataTable::confirmCancels
+ \brief whether the data table confirms cancel operations
+
+ If the confirmCancel property is true, all cancels must be
+ confirmed by the user through a message box (this behavior can be
+ changed by overriding the confirmCancel() function), otherwise all
+ cancels occur immediately. The default is false.
+
+ \sa confirmEdits() confirmCancel()
+*/
+
+void Q3DataTable::setConfirmCancels( bool confirm )
+{
+ d->dat.setConfirmCancels( confirm );
+}
+
+bool Q3DataTable::confirmCancels() const
+{
+ return d->dat.confirmCancels();
+}
+
+/*!
+ \reimp
+
+ For an editable table, creates an editor suitable for the field in
+ column \a col. The editor is created using the default editor
+ factory, unless a different editor factory was installed with
+ installEditorFactory(). The editor is primed with the value of the
+ field in \a col using a property map. The property map used is the
+ default property map, unless a new property map was installed with
+ installPropertMap(). If \a initFromCell is true then the editor is
+ primed with the value in the Q3DataTable cell.
+*/
+
+QWidget * Q3DataTable::createEditor( int , int col, bool initFromCell ) const
+{
+ if ( d->dat.mode() == QSql::None )
+ return 0;
+
+ Q3SqlEditorFactory * f = (d->editorFactory == 0) ?
+ Q3SqlEditorFactory::defaultFactory() : d->editorFactory;
+
+ Q3SqlPropertyMap * m = (d->propertyMap == 0) ?
+ Q3SqlPropertyMap::defaultMap() : d->propertyMap;
+
+ QWidget * w = 0;
+ if( initFromCell && d->editBuffer ){
+ w = f->createEditor( viewport(), d->editBuffer->fieldPtr( indexOf( col ) ) );
+ if ( w )
+ m->setProperty( w, d->editBuffer->value( indexOf( col ) ) );
+ }
+ return w;
+}
+
+/*! \reimp */
+bool Q3DataTable::eventFilter( QObject *o, QEvent *e )
+{
+ if ( d->cancelMode )
+ return true;
+
+ int r = currentRow();
+ int c = currentColumn();
+
+ if ( d->dat.mode() != QSql::None ) {
+ r = d->editRow;
+ c = d->editCol;
+ }
+
+ d->cancelInsert = false;
+ d->cancelUpdate = false;
+ switch ( e->type() ) {
+ case QEvent::KeyPress: {
+ int conf = QSql::Yes;
+ QKeyEvent *ke = (QKeyEvent*)e;
+ if ( ( ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_BackTab )
+ && ke->state() & Qt::ControlButton )
+ return false;
+
+ if ( ke->key() == Qt::Key_Escape && d->dat.mode() == QSql::Insert ){
+ if ( confirmCancels() && !d->cancelMode ) {
+ d->cancelMode = true;
+ conf = confirmCancel( QSql::Insert );
+ d->cancelMode = false;
+ }
+ if ( conf == QSql::Yes ) {
+ d->cancelInsert = true;
+ } else {
+ QWidget *editorWidget = cellWidget( r, c );
+ if ( editorWidget ) {
+ editorWidget->setActiveWindow();
+ editorWidget->setFocus();
+ }
+ return true;
+ }
+ }
+ if ( ke->key() == Qt::Key_Escape && d->dat.mode() == QSql::Update ) {
+ if ( confirmCancels() && !d->cancelMode ) {
+ d->cancelMode = true;
+ conf = confirmCancel( QSql::Update );
+ d->cancelMode = false;
+ }
+ if ( conf == QSql::Yes ){
+ d->cancelUpdate = true;
+ } else {
+ QWidget *editorWidget = cellWidget( r, c );
+ if ( editorWidget ) {
+ editorWidget->setActiveWindow();
+ editorWidget->setFocus();
+ }
+ return true;
+ }
+ }
+ if ( ke->key() == Qt::Key_Insert && d->dat.mode() == QSql::None ) {
+ beginInsert();
+ return true;
+ }
+ if ( ke->key() == Qt::Key_Delete && d->dat.mode() == QSql::None ) {
+ deleteCurrent();
+ return true;
+ }
+ if ( d->dat.mode() != QSql::None ) {
+ if ( (ke->key() == Qt::Key_Tab) && (c < numCols() - 1) && (!isColumnReadOnly( c+1 ) || d->dat.mode() == QSql::Insert) )
+ d->continuousEdit = true;
+ else if ( (ke->key() == Qt::Key_BackTab) && (c > 0) && (!isColumnReadOnly( c-1 ) || d->dat.mode() == QSql::Insert) )
+ d->continuousEdit = true;
+ else
+ d->continuousEdit = false;
+ }
+ Q3SqlCursor * sql = sqlCursor();
+ if ( sql && sql->driver() &&
+ !sql->driver()->hasFeature( QSqlDriver::QuerySize ) &&
+ ke->key() == Qt::Key_End && d->dat.mode() == QSql::None ) {
+#ifndef QT_NO_CURSOR
+ QApplication::setOverrideCursor( Qt::WaitCursor );
+#endif
+ int i = sql->at();
+ if ( i < 0 ) {
+ i = 0;
+ sql->seek(0);
+ }
+ while ( sql->next() )
+ i++;
+ setNumRows( i+1 );
+ setCurrentCell( i+1, currentColumn() );
+#ifndef QT_NO_CURSOR
+ QApplication::restoreOverrideCursor();
+#endif
+ return true;
+ }
+ break;
+ }
+ case QEvent::FocusOut: {
+ QWidget *editorWidget = cellWidget( r, c );
+ repaintCell( currentRow(), currentColumn() );
+ if ( !d->cancelMode && editorWidget && o == editorWidget &&
+ ( d->dat.mode() == QSql::Insert) && !d->continuousEdit) {
+ setCurrentCell( r, c );
+ d->cancelInsert = true;
+ }
+ d->continuousEdit = false;
+ break;
+ }
+ case QEvent::FocusIn:
+ repaintCell( currentRow(), currentColumn() );
+ break;
+ default:
+ break;
+ }
+ return Q3Table::eventFilter( o, e );
+}
+
+/*! \reimp */
+void Q3DataTable::resizeEvent ( QResizeEvent * e )
+{
+ if ( sqlCursor() &&
+ sqlCursor()->driver() &&
+ !sqlCursor()->driver()->hasFeature( QSqlDriver::QuerySize ) )
+ loadNextPage();
+ Q3Table::resizeEvent( e );
+}
+
+/*! \reimp */
+void Q3DataTable::contentsContextMenuEvent( QContextMenuEvent* e )
+{
+ Q3Table::contentsContextMenuEvent( e );
+ if ( isEditing() && d->dat.mode() != QSql::None )
+ endEdit( d->editRow, d->editCol, autoEdit(), false );
+ if ( !sqlCursor() )
+ return;
+ if ( d->dat.mode() == QSql::None ) {
+ if ( isReadOnly() )
+ return;
+ enum {
+ IdInsert,
+ IdUpdate,
+ IdDelete
+ };
+ QPointer<Q3PopupMenu> popup = new Q3PopupMenu( this, "qt_datatable_menu" );
+ int id[ 3 ];
+ id[ IdInsert ] = popup->insertItem( tr( "Insert" ) );
+ id[ IdUpdate ] = popup->insertItem( tr( "Update" ) );
+ id[ IdDelete ] = popup->insertItem( tr( "Delete" ) );
+ bool enableInsert = sqlCursor()->canInsert();
+ popup->setItemEnabled( id[ IdInsert ], enableInsert );
+ bool enableUpdate = currentRow() > -1 && sqlCursor()->canUpdate() && !isColumnReadOnly( currentColumn() );
+ popup->setItemEnabled( id[ IdUpdate ], enableUpdate );
+ bool enableDelete = currentRow() > -1 && sqlCursor()->canDelete();
+ popup->setItemEnabled( id[ IdDelete ], enableDelete );
+ int r = popup->exec( e->globalPos() );
+ delete (Q3PopupMenu*) popup;
+ if ( r == id[ IdInsert ] )
+ beginInsert();
+ else if ( r == id[ IdUpdate ] ) {
+ if ( beginEdit( currentRow(), currentColumn(), false ) )
+ setEditMode( Editing, currentRow(), currentColumn() );
+ else
+ endUpdate();
+ }
+ else if ( r == id[ IdDelete ] )
+ deleteCurrent();
+ e->accept();
+ }
+}
+
+/*! \reimp */
+void Q3DataTable::contentsMousePressEvent( QMouseEvent* e )
+{
+ Q3Table::contentsMousePressEvent( e );
+}
+
+/*! \reimp */
+QWidget* Q3DataTable::beginEdit ( int row, int col, bool replace )
+{
+ d->editRow = -1;
+ d->editCol = -1;
+ if ( !sqlCursor() )
+ return 0;
+ if ( d->dat.mode() == QSql::Insert && !sqlCursor()->canInsert() )
+ return 0;
+ if ( d->dat.mode() == QSql::Update && !sqlCursor()->canUpdate() )
+ return 0;
+ d->editRow = row;
+ d->editCol = col;
+ if ( d->continuousEdit ) {
+ // see comment in beginInsert()
+ bool fakeReadOnly = isColumnReadOnly( col );
+ setColumnReadOnly( col, false );
+ QWidget* w = Q3Table::beginEdit( row, col, replace );
+ setColumnReadOnly( col, fakeReadOnly );
+ return w;
+ }
+ if ( d->dat.mode() == QSql::None && sqlCursor()->canUpdate() && sqlCursor()->primaryIndex().count() > 0 )
+ return beginUpdate( row, col, replace );
+ return 0;
+}
+
+/*! \reimp */
+void Q3DataTable::endEdit( int row, int col, bool, bool )
+{
+ bool accept = autoEdit() && !d->cancelInsert && !d->cancelUpdate;
+
+ QWidget *editor = cellWidget( row, col );
+ if ( !editor )
+ return;
+ if ( d->cancelMode )
+ return;
+ if ( d->dat.mode() != QSql::None && d->editBuffer ) {
+ Q3SqlPropertyMap * m = (d->propertyMap == 0) ?
+ Q3SqlPropertyMap::defaultMap() : d->propertyMap;
+ d->editBuffer->setValue( indexOf( col ), m->property( editor ) );
+ clearCellWidget( row, col );
+ if ( !d->continuousEdit ) {
+ switch ( d->dat.mode() ) {
+ case QSql::Insert:
+ if ( accept )
+ QTimer::singleShot( 0, this, SLOT(doInsertCurrent()) );
+ else
+ endInsert();
+ break;
+ case QSql::Update:
+ if ( accept )
+ QTimer::singleShot( 0, this, SLOT(doUpdateCurrent()) );
+ else
+ endUpdate();
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
+ setEditMode( NotEditing, -1, -1 );
+ }
+ if ( d->dat.mode() == QSql::None )
+ viewport()->setFocus();
+ updateCell( row, col );
+ emit valueChanged( row, col );
+}
+
+/*! \internal */
+void Q3DataTable::doInsertCurrent()
+{
+ insertCurrent();
+}
+
+/*! \internal */
+void Q3DataTable::doUpdateCurrent()
+{
+ updateCurrent();
+ if ( d->dat.mode() == QSql::None ) {
+ viewport()->setFocus();
+ }
+}
+
+/*! \reimp */
+void Q3DataTable::activateNextCell()
+{
+// if ( d->dat.mode() == QSql::None )
+// Q3Table::activateNextCell();
+}
+
+/*! \internal
+*/
+
+void Q3DataTable::endInsert()
+{
+ if ( d->dat.mode() != QSql::Insert )
+ return;
+ d->dat.setMode( QSql::None );
+ d->editBuffer = 0;
+ verticalHeader()->setLabel( d->editRow, QString::number( d->editRow +1 ) );
+ d->editRow = -1;
+ d->editCol = -1;
+ d->insertRowLast = -1;
+ d->insertHeaderLabelLast.clear();
+ setEditMode( NotEditing, -1, -1 );
+ setNumRows( d->insertPreRows );
+ d->insertPreRows = -1;
+ viewport()->setFocus();
+}
+
+/*! \internal
+ */
+void Q3DataTable::endUpdate()
+{
+ d->dat.setMode( QSql::None );
+ d->editBuffer = 0;
+ updateRow( d->editRow );
+ d->editRow = -1;
+ d->editCol = -1;
+ setEditMode( NotEditing, -1, -1 );
+}
+
+/*!
+ Protected virtual function called when editing is about to begin
+ on a new record. If the table is read-only, or if there's no cursor
+ or the cursor does not allow inserts, nothing happens and false
+ is returned. Otherwise returns true.
+
+ Editing takes place using the cursor's edit buffer(see
+ Q3SqlCursor::editBuffer()).
+
+ When editing begins, a new row is created in the table marked with
+ an asterisk '*' in the row's vertical header column, i.e. at the
+ left of the row.
+*/
+bool Q3DataTable::beginInsert()
+{
+ if ( !sqlCursor() || isReadOnly() || !numCols() )
+ return false;
+ if ( !sqlCursor()->canInsert() )
+ return false;
+ int i = 0;
+ int row = currentRow();
+
+ d->insertPreRows = numRows();
+ if ( row < 0 || numRows() < 1 )
+ row = 0;
+ setNumRows( d->insertPreRows + 1 );
+ setCurrentCell( row, 0 );
+ d->editBuffer = sqlCursor()->primeInsert();
+ emit primeInsert( d->editBuffer );
+ d->dat.setMode( QSql::Insert );
+ int lastRow = row;
+ int lastY = contentsY() + visibleHeight();
+ for ( i = row; i < numRows() ; ++i ) {
+ QRect cg = cellGeometry( i, 0 );
+ if ( (cg.y()+cg.height()) > lastY ) {
+ lastRow = i;
+ break;
+ }
+ }
+ if ( lastRow == row && ( numRows()-1 > row ) )
+ lastRow = numRows() - 1;
+ d->insertRowLast = lastRow;
+ d->insertHeaderLabelLast = verticalHeader()->label( d->insertRowLast );
+ verticalHeader()->setLabel( row, QString(QLatin1Char('*')) );
+ d->editRow = row;
+ // in the db world it's common to allow inserting new records
+ // into a table that has read-only columns - temporarily
+ // switch off read-only mode for such columns
+ bool fakeReadOnly = isColumnReadOnly( 0 );
+ setColumnReadOnly( 0, false );
+ if ( Q3Table::beginEdit( row, 0, false ) )
+ setEditMode( Editing, row, 0 );
+ setColumnReadOnly( 0, fakeReadOnly );
+ return true;
+}
+
+/*!
+ Protected virtual function called when editing is about to begin
+ on an existing row. If the table is read-only, or if there's no
+ cursor, nothing happens.
+
+ Editing takes place using the cursor's edit buffer (see
+ Q3SqlCursor::editBuffer()).
+
+ \a row and \a col refer to the row and column in the Q3DataTable.
+
+ (\a replace is provided for reimplementors and reflects the API of
+ Q3Table::beginEdit().)
+*/
+
+QWidget* Q3DataTable::beginUpdate ( int row, int col, bool replace )
+{
+ if ( !sqlCursor() || isReadOnly() || isColumnReadOnly( col ) )
+ return 0;
+ setCurrentCell( row, col );
+ d->dat.setMode( QSql::Update );
+ if ( sqlCursor()->seek( row ) ) {
+ d->editBuffer = sqlCursor()->primeUpdate();
+ sqlCursor()->seek( currentRow() );
+ emit primeUpdate( d->editBuffer );
+ return Q3Table::beginEdit( row, col, replace );
+ }
+ return 0;
+}
+
+/*!
+ For an editable table, issues an insert on the current cursor
+ using the values in the cursor's edit buffer. If there is no
+ current cursor or there is no current "insert" row, nothing
+ happens. If confirmEdits() or confirmInsert() is true,
+ confirmEdit() is called to confirm the insert. Returns true if the
+ insert succeeded; otherwise returns false.
+
+ The underlying cursor must have a valid primary index to ensure
+ that a unique record is inserted within the database otherwise the
+ database may be changed to an inconsistent state.
+*/
+
+bool Q3DataTable::insertCurrent()
+{
+ if ( d->dat.mode() != QSql::Insert || ! numCols() )
+ return false;
+ if ( !sqlCursor()->canInsert() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("Q3DataTable::insertCurrent: insert not allowed for %s",
+ sqlCursor()->name().latin1() );
+#endif
+ endInsert();
+ return false;
+ }
+ int b = 0;
+ int conf = QSql::Yes;
+ if ( confirmEdits() || confirmInsert() )
+ conf = confirmEdit( QSql::Insert );
+ switch ( conf ) {
+ case QSql::Yes: {
+#ifndef QT_NO_CURSOR
+ QApplication::setOverrideCursor( Qt::waitCursor );
+#endif
+ emit beforeInsert( d->editBuffer );
+ b = sqlCursor()->insert();
+#ifndef QT_NO_CURSOR
+ QApplication::restoreOverrideCursor();
+#endif
+ if ( ( !b && !sqlCursor()->isActive() ) || !sqlCursor()->isActive() ) {
+ handleError( sqlCursor()->lastError() );
+ endInsert(); // cancel the insert if anything goes wrong
+ refresh();
+ } else {
+ endInsert();
+ refresh();
+ QSqlIndex idx = sqlCursor()->primaryIndex();
+ findBuffer( idx, d->lastAt );
+ repaintContents( contentsX(), contentsY(), visibleWidth(), visibleHeight(), false );
+ emit cursorChanged( QSql::Insert );
+ }
+ break;
+ }
+ case QSql::No:
+ endInsert();
+ break;
+ case QSql::Cancel:
+ if ( Q3Table::beginEdit( currentRow(), currentColumn(), false ) )
+ setEditMode( Editing, currentRow(), currentColumn() );
+ break;
+ }
+ return ( b > 0 );
+}
+
+/*! \internal
+
+ Updates the row \a row.
+*/
+
+void Q3DataTable::updateRow( int row )
+{
+ for ( int i = 0; i < numCols(); ++i )
+ updateCell( row, i );
+}
+
+/*!
+ For an editable table, issues an update using the cursor's edit
+ buffer. If there is no current cursor or there is no current
+ selection, nothing happens. If confirmEdits() or confirmUpdate()
+ is true, confirmEdit() is called to confirm the update. Returns
+ true if the update succeeded; otherwise returns false.
+
+ The underlying cursor must have a valid primary index to ensure
+ that a unique record is updated within the database otherwise the
+ database may be changed to an inconsistent state.
+*/
+
+bool Q3DataTable::updateCurrent()
+{
+ if ( d->dat.mode() != QSql::Update )
+ return false;
+ if ( sqlCursor()->primaryIndex().count() == 0 ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("Q3DataTable::updateCurrent: no primary index for %s",
+ sqlCursor()->name().latin1() );
+#endif
+ endUpdate();
+ return false;
+ }
+ if ( !sqlCursor()->canUpdate() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("Q3DataTable::updateCurrent: updates not allowed for %s",
+ sqlCursor()->name().latin1() );
+#endif
+ endUpdate();
+ return false;
+ }
+ int b = 0;
+ int conf = QSql::Yes;
+ if ( confirmEdits() || confirmUpdate() )
+ conf = confirmEdit( QSql::Update );
+ switch ( conf ) {
+ case QSql::Yes: {
+#ifndef QT_NO_CURSOR
+ QApplication::setOverrideCursor( Qt::waitCursor );
+#endif
+ emit beforeUpdate( d->editBuffer );
+ b = sqlCursor()->update();
+#ifndef QT_NO_CURSOR
+ QApplication::restoreOverrideCursor();
+#endif
+ if ( ( !b && !sqlCursor()->isActive() ) || !sqlCursor()->isActive() ) {
+ handleError( sqlCursor()->lastError() );
+ endUpdate();
+ refresh();
+ setCurrentCell( d->editRow, d->editCol );
+ if ( Q3Table::beginEdit( d->editRow, d->editCol, false ) )
+ setEditMode( Editing, d->editRow, d->editCol );
+ } else {
+ emit cursorChanged( QSql::Update );
+ refresh();
+ endUpdate();
+ }
+ break;
+ }
+ case QSql::No:
+ endUpdate();
+ setEditMode( NotEditing, -1, -1 );
+ break;
+ case QSql::Cancel:
+ setCurrentCell( d->editRow, d->editCol );
+ if ( Q3Table::beginEdit( d->editRow, d->editCol, false ) )
+ setEditMode( Editing, d->editRow, d->editCol );
+ break;
+ }
+ return ( b > 0 );
+}
+
+/*!
+ For an editable table, issues a delete on the current cursor's
+ primary index using the values of the currently selected row. If
+ there is no current cursor or there is no current selection,
+ nothing happens. If confirmEdits() or confirmDelete() is true,
+ confirmEdit() is called to confirm the delete. Returns true if the
+ delete succeeded; otherwise false.
+
+ The underlying cursor must have a valid primary index to ensure
+ that a unique record is deleted within the database otherwise the
+ database may be changed to an inconsistent state.
+*/
+
+bool Q3DataTable::deleteCurrent()
+{
+ if ( !sqlCursor() || isReadOnly() )
+ return false;
+ if ( sqlCursor()->primaryIndex().count() == 0 ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("Q3DataTable::deleteCurrent: no primary index %s",
+ sqlCursor()->name().latin1() );
+#endif
+ return false;
+ }
+ if ( !sqlCursor()->canDelete() )
+ return false;
+
+ int b = 0;
+ int conf = QSql::Yes;
+ if ( confirmEdits() || confirmDelete() )
+ conf = confirmEdit( QSql::Delete );
+
+ // Have to have this here - the confirmEdit() might pop up a
+ // dialog that causes a repaint which the cursor to the
+ // record it has to repaint.
+ if ( !sqlCursor()->seek( currentRow() ) )
+ return false;
+ switch ( conf ) {
+ case QSql::Yes:{
+#ifndef QT_NO_CURSOR
+ QApplication::setOverrideCursor( Qt::waitCursor );
+#endif
+ sqlCursor()->primeDelete();
+ emit primeDelete( sqlCursor()->editBuffer() );
+ emit beforeDelete( sqlCursor()->editBuffer() );
+ b = sqlCursor()->del();
+#ifndef QT_NO_CURSOR
+ QApplication::restoreOverrideCursor();
+#endif
+ if ( !b )
+ handleError( sqlCursor()->lastError() );
+ refresh();
+ emit cursorChanged( QSql::Delete );
+ setCurrentCell( currentRow(), currentColumn() );
+ repaintContents( contentsX(), contentsY(), visibleWidth(), visibleHeight(), false );
+ verticalHeader()->repaint(); // get rid of trailing garbage
+ }
+ break;
+ case QSql::No:
+ setEditMode( NotEditing, -1, -1 );
+ break;
+ }
+ return ( b > 0 );
+}
+
+/*!
+ Protected virtual function which returns a confirmation for an
+ edit of mode \a m. Derived classes can reimplement this function
+ to provide their own confirmation dialog. The default
+ implementation uses a message box which prompts the user to
+ confirm the edit action.
+*/
+
+QSql::Confirm Q3DataTable::confirmEdit( QSql::Op m )
+{
+ return d->dat.confirmEdit( this, m );
+}
+
+/*!
+ Protected virtual function which returns a confirmation for
+ canceling an edit mode of \a m. Derived classes can reimplement
+ this function to provide their own cancel dialog. The default
+ implementation uses a message box which prompts the user to
+ confirm the cancel.
+*/
+
+QSql::Confirm Q3DataTable::confirmCancel( QSql::Op m )
+{
+ return d->dat.confirmCancel( this, m );
+}
+
+
+/*!
+ Searches the current cursor for a cell containing the string \a
+ str starting at the current cell and working forwards (or
+ backwards if \a backwards is true). If the string is found, the
+ cell containing the string is set as the current cell. If \a
+ caseSensitive is false the case of \a str will be ignored.
+
+ The search will wrap, i.e. if the first (or if backwards is true,
+ last) cell is reached without finding \a str the search will
+ continue until it reaches the starting cell. If \a str is not
+ found the search will fail and the current cell will remain
+ unchanged.
+*/
+void Q3DataTable::find( const QString & str, bool caseSensitive, bool backwards )
+{
+ if ( !sqlCursor() )
+ return;
+
+ Q3SqlCursor * r = sqlCursor();
+ QString tmp, text;
+ uint row = currentRow(), startRow = row,
+ col = backwards ? currentColumn() - 1 : currentColumn() + 1;
+ bool wrap = true, found = false;
+
+ if( str.isEmpty() || str.isNull() )
+ return;
+
+ if( !caseSensitive )
+ tmp = str.lower();
+ else
+ tmp = str;
+
+#ifndef QT_NO_CURSOR
+ QApplication::setOverrideCursor( Qt::waitCursor );
+#endif
+ while( wrap ){
+ while( !found && r->seek( row ) ){
+ for( int i = col; backwards ? (i >= 0) : (i < (int) numCols());
+ backwards ? i-- : i++ )
+ {
+ text = r->value( indexOf( i ) ).toString();
+ if( !caseSensitive ){
+ text = text.lower();
+ }
+ if( text.contains( tmp ) ){
+ setCurrentCell( row, i );
+ col = i;
+ found = true;
+ }
+ }
+ if( !backwards ){
+ col = 0;
+ row++;
+ } else {
+ col = numCols() - 1;
+ row--;
+ }
+ }
+ if( !backwards ){
+ if( startRow != 0 ){
+ startRow = 0;
+ } else {
+ wrap = false;
+ }
+ r->first();
+ row = 0;
+ } else {
+ if( startRow != (uint) (numRows() - 1) ){
+ startRow = numRows() - 1;
+ } else {
+ wrap = false;
+ }
+ r->last();
+ row = numRows() - 1;
+ }
+ }
+#ifndef QT_NO_CURSOR
+ QApplication::restoreOverrideCursor();
+#endif
+}
+
+
+/*!
+ Resets the table so that it displays no data.
+
+ \sa setSqlCursor()
+*/
+
+void Q3DataTable::reset()
+{
+ clearCellWidget( currentRow(), currentColumn() );
+ switch ( d->dat.mode() ) {
+ case QSql::Insert:
+ endInsert();
+ break;
+ case QSql::Update:
+ endUpdate();
+ break;
+ default:
+ break;
+ }
+ ensureVisible( 0, 0 );
+ verticalScrollBar()->setValue(0);
+ setNumRows(0);
+
+ d->haveAllRows = false;
+ d->continuousEdit = false;
+ d->dat.setMode( QSql::None );
+ d->editRow = -1;
+ d->editCol = -1;
+ d->insertRowLast = -1;
+ d->insertHeaderLabelLast.clear();
+ d->cancelMode = false;
+ d->lastAt = -1;
+ d->fld.clear();
+ d->fldLabel.clear();
+ d->fldWidth.clear();
+ d->fldIcon.clear();
+ d->fldHidden.clear();
+ if ( sorting() )
+ horizontalHeader()->setSortIndicator( -1 );
+}
+
+/*!
+ Returns the index of the field within the current SQL query that
+ is displayed in column \a i.
+*/
+
+int Q3DataTable::indexOf( uint i ) const
+{
+ Q3DataTablePrivate::ColIndex::ConstIterator it = d->colIndex.at( i );
+ if ( it != d->colIndex.end() )
+ return *it;
+ return -1;
+}
+
+/*!
+ Returns true if the table will automatically delete the cursor
+ specified by setSqlCursor(); otherwise returns false.
+*/
+
+bool Q3DataTable::autoDelete() const
+{
+ return d->cur.autoDelete();
+}
+
+/*!
+ Sets the cursor auto-delete flag to \a enable. If \a enable is
+ true, the table will automatically delete the cursor specified by
+ setSqlCursor(). If \a enable is false (the default), the cursor
+ will not be deleted.
+*/
+
+void Q3DataTable::setAutoDelete( bool enable )
+{
+ d->cur.setAutoDelete( enable );
+}
+
+/*!
+ \property Q3DataTable::autoEdit
+ \brief whether the data table automatically applies edits
+
+ The default value for this property is true. When the user begins
+ an insert or update in the table there are two possible outcomes
+ when they navigate to another record:
+
+ \list 1
+ \i the insert or update is is performed -- this occurs if autoEdit is true
+ \i the insert or update is abandoned -- this occurs if autoEdit is false
+ \endlist
+*/
+
+void Q3DataTable::setAutoEdit( bool autoEdit )
+{
+ d->dat.setAutoEdit( autoEdit );
+}
+
+bool Q3DataTable::autoEdit() const
+{
+ return d->dat.autoEdit();
+}
+
+/*!
+ \property Q3DataTable::nullText
+ \brief the text used to represent NULL values
+
+ The nullText property will be used to represent NULL values in the
+ table. The default value is provided by the cursor's driver.
+*/
+
+void Q3DataTable::setNullText( const QString& nullText )
+{
+ d->nullTxt = nullText;
+ d->nullTxtChanged = true;
+}
+
+QString Q3DataTable::nullText() const
+{
+ return d->nullTxt;
+}
+
+/*!
+ \property Q3DataTable::trueText
+ \brief the text used to represent true values
+
+ The trueText property will be used to represent NULL values in the
+ table. The default value is "True".
+*/
+
+void Q3DataTable::setTrueText( const QString& trueText )
+{
+ d->trueTxt = trueText;
+}
+
+QString Q3DataTable::trueText() const
+{
+ return d->trueTxt;
+}
+
+/*!
+ \property Q3DataTable::falseText
+ \brief the text used to represent false values
+
+ The falseText property will be used to represent NULL values in
+ the table. The default value is "False".
+*/
+
+void Q3DataTable::setFalseText( const QString& falseText )
+{
+ d->falseTxt = falseText;
+}
+
+QString Q3DataTable::falseText() const
+{
+ return d->falseTxt;
+}
+
+/*!
+ \property Q3DataTable::dateFormat
+ \brief the format used for displaying date/time values
+
+ The dateFormat property is used for displaying date/time values in
+ the table. The default value is Qt::LocalDate.
+*/
+
+void Q3DataTable::setDateFormat( const Qt::DateFormat f )
+{
+ d->datefmt = f;
+}
+
+Qt::DateFormat Q3DataTable::dateFormat() const
+{
+ return d->datefmt;
+}
+
+/*!
+ \property Q3DataTable::numRows
+
+ \brief the number of rows in the table
+*/
+
+int Q3DataTable::numRows() const
+{
+ return Q3Table::numRows();
+}
+
+/*!
+ \reimp
+
+ The number of rows in the table will be determined by the cursor
+ (see setSqlCursor()), so normally this function should never be
+ called. It is included for completeness.
+*/
+
+void Q3DataTable::setNumRows ( int r )
+{
+ Q3Table::setNumRows( r );
+}
+
+/*!
+ \reimp
+
+ The number of columns in the table will be determined
+ automatically (see addColumn()), so normally this function should
+ never be called. It is included for completeness.
+*/
+
+void Q3DataTable::setNumCols ( int r )
+{
+ Q3Table::setNumCols( r );
+}
+
+/*!
+ \property Q3DataTable::numCols
+
+ \brief the number of columns in the table
+*/
+
+int Q3DataTable::numCols() const
+{
+ return Q3Table::numCols();
+}
+
+/*!
+ Returns the text in cell \a row, \a col, or an empty string if the
+ cell is empty. If the cell's value is NULL then nullText() will be
+ returned. If the cell does not exist then an empty string is
+ returned.
+*/
+
+QString Q3DataTable::text ( int row, int col ) const
+{
+ if ( !sqlCursor() )
+ return QString();
+
+ QString s;
+ if ( sqlCursor()->seek( row ) )
+ s = sqlCursor()->value( indexOf( col ) ).toString();
+ sqlCursor()->seek( currentRow() );
+ return s;
+}
+
+/*!
+ Returns the value in cell \a row, \a col, or an invalid value if
+ the cell does not exist or has no value.
+*/
+
+QVariant Q3DataTable::value ( int row, int col ) const
+{
+ if ( !sqlCursor() )
+ return QVariant();
+
+ QVariant v;
+ if ( sqlCursor()->seek( row ) )
+ v = sqlCursor()->value( indexOf( col ) );
+ sqlCursor()->seek( currentRow() );
+ return v;
+}
+
+/*! \internal
+ Used to update the table when the size of the result set cannot be
+ determined - divide the result set into pages and load the pages as
+ the user moves around in the table.
+*/
+void Q3DataTable::loadNextPage()
+{
+ if ( d->haveAllRows )
+ return;
+ if ( !sqlCursor() )
+ return;
+ int pageSize = 0;
+ int lookAhead = 0;
+ if ( height() ) {
+ pageSize = (int)( height() * 2 / 20 );
+ lookAhead = pageSize / 2;
+ }
+ int startIdx = verticalScrollBar()->value() / 20;
+ int endIdx = startIdx + pageSize + lookAhead;
+ if ( endIdx < numRows() || endIdx < 0 )
+ return;
+
+ // check for empty result set
+ if ( sqlCursor()->at() == QSql::BeforeFirst && !sqlCursor()->next() ) {
+ d->haveAllRows = true;
+ return;
+ }
+
+ while ( endIdx > 0 && !sqlCursor()->seek( endIdx ) )
+ endIdx--;
+ if ( endIdx != ( startIdx + pageSize + lookAhead ) )
+ d->haveAllRows = true;
+ // small hack to prevent Q3Table from moving the view when a row
+ // is selected and the contents is resized
+ SelectionMode m = selectionMode();
+ clearSelection();
+ setSelectionMode( NoSelection );
+ setNumRows( endIdx ? endIdx + 1 : 0 );
+ sqlCursor()->seek( currentRow() );
+ setSelectionMode( m );
+}
+
+/*! \internal */
+void Q3DataTable::sliderPressed()
+{
+ disconnect( verticalScrollBar(), SIGNAL(valueChanged(int)),
+ this, SLOT(loadNextPage()) );
+}
+
+/*! \internal */
+void Q3DataTable::sliderReleased()
+{
+ loadNextPage();
+ connect( verticalScrollBar(), SIGNAL(valueChanged(int)),
+ this, SLOT(loadNextPage()) );
+}
+
+/*!
+ Sorts column \a col in ascending order if \a ascending is true
+ (the default); otherwise sorts in descending order.
+
+ The \a wholeRows parameter is ignored; Q3DataTable always sorts
+ whole rows by the specified column.
+*/
+
+void Q3DataTable::sortColumn ( int col, bool ascending,
+ bool )
+{
+ if ( sorting() ) {
+ if ( isEditing() && d->dat.mode() != QSql::None )
+ endEdit( d->editRow, d->editCol, autoEdit(), false );
+ if ( !sqlCursor() )
+ return;
+ QSqlIndex lastSort = sqlCursor()->sort();
+ QSqlIndex newSort( lastSort.cursorName(), QLatin1String("newSort") );
+ const QSqlField *field = sqlCursor()->fieldPtr( indexOf( col ) );
+ if ( field )
+ newSort.append( *field );
+ newSort.setDescending( 0, !ascending );
+ horizontalHeader()->setSortIndicator( col, ascending );
+ setSort( newSort );
+ refresh();
+ }
+}
+
+/*! \reimp */
+void Q3DataTable::columnClicked ( int col )
+{
+ if ( sorting() ) {
+ if ( !sqlCursor() )
+ return;
+ QSqlIndex lastSort = sqlCursor()->sort();
+ bool asc = true;
+ if ( lastSort.count() && lastSort.fieldPtr( 0 )->name() == sqlCursor()->fieldPtr( indexOf( col ) )->name() )
+ asc = lastSort.isDescending( 0 );
+ sortColumn( col, asc );
+ emit currentChanged( sqlCursor() );
+ }
+}
+
+/*!
+ Repaints the cell at \a row, \a col.
+*/
+void Q3DataTable::repaintCell( int row, int col )
+{
+ QRect cg = cellGeometry( row, col );
+ QRect re( QPoint( cg.x() - 2, cg.y() - 2 ),
+ QSize( cg.width() + 4, cg.height() + 4 ) );
+ repaintContents( re, false );
+}
+
+/*!
+ \reimp
+
+ This function renders the cell at \a row, \a col with the value of
+ the corresponding cursor field on the painter \a p. Depending on
+ the table's current edit mode, paintField() is called for the
+ appropriate cursor field. \a cr describes the cell coordinates in
+ the content coordinate system. If \a selected is true the cell has
+ been selected and would normally be rendered differently than an
+ unselected cell.
+
+ \sa QSql::isNull()
+*/
+
+void Q3DataTable::paintCell( QPainter * p, int row, int col, const QRect & cr,
+ bool selected, const QColorGroup &cg )
+{
+ Q3Table::paintCell( p, row, col, cr, selected, cg ); // empty cell
+
+ if ( !sqlCursor() )
+ return;
+
+ p->setPen( selected ? cg.highlightedText() : cg.text() );
+ if ( d->dat.mode() != QSql::None ) {
+ if ( row == d->editRow && d->editBuffer ) {
+ paintField( p, d->editBuffer->fieldPtr( indexOf( col ) ), cr,
+ selected );
+ } else if ( row > d->editRow && d->dat.mode() == QSql::Insert ) {
+ if ( sqlCursor()->seek( row - 1 ) )
+ paintField( p, sqlCursor()->fieldPtr( indexOf( col ) ), cr,
+ selected );
+ } else {
+ if ( sqlCursor()->seek( row ) )
+ paintField( p, sqlCursor()->fieldPtr( indexOf( col ) ), cr,
+ selected );
+ }
+ } else {
+ if ( sqlCursor()->seek( row ) )
+ paintField( p, sqlCursor()->fieldPtr( indexOf( col ) ), cr, selected );
+
+ }
+}
+
+
+/*!
+ Paints the \a field on the painter \a p. The painter has already
+ been translated to the appropriate cell's origin where the \a
+ field is to be rendered. \a cr describes the cell coordinates in
+ the content coordinate system. The \a selected parameter is
+ ignored.
+
+ If you want to draw custom field content you must reimplement
+ paintField() to do the custom drawing. The default implementation
+ renders the \a field value as text. If the field is NULL,
+ nullText() is displayed in the cell. If the field is Boolean,
+ trueText() or falseText() is displayed as appropriate.
+*/
+
+void Q3DataTable::paintField( QPainter * p, const QSqlField* field,
+ const QRect & cr, bool )
+{
+ if ( !field )
+ return;
+ p->drawText( 2,2, cr.width()-4, cr.height()-4, fieldAlignment( field ), fieldToString( field ) );
+}
+
+/*!
+ Returns the alignment for \a field.
+*/
+
+int Q3DataTable::fieldAlignment( const QSqlField* /*field*/ )
+{
+ return Qt::AlignLeft | Qt::AlignVCenter; //## Reggie: add alignment to Q3Table
+}
+
+
+/*!
+ If the cursor's \a sql driver supports query sizes, the number of
+ rows in the table is set to the size of the query. Otherwise, the
+ table dynamically resizes itself as it is scrolled. If \a sql is
+ not active, it is made active by issuing a select() on the cursor
+ using the \a sql cursor's current filter and current sort.
+*/
+
+void Q3DataTable::setSize( Q3SqlCursor* sql )
+{
+ // ### what are the connect/disconnect calls doing here!? move to refresh()
+ if ( sql->driver() && sql->driver()->hasFeature( QSqlDriver::QuerySize ) ) {
+ setVScrollBarMode( Auto );
+ disconnect( verticalScrollBar(), SIGNAL(sliderPressed()),
+ this, SLOT(sliderPressed()) );
+ disconnect( verticalScrollBar(), SIGNAL(sliderReleased()),
+ this, SLOT(sliderReleased()) );
+ disconnect( verticalScrollBar(), SIGNAL(valueChanged(int)),
+ this, SLOT(loadNextPage()) );
+ if ( numRows() != sql->size() )
+ setNumRows( sql->size() );
+ } else {
+ setVScrollBarMode( AlwaysOn );
+ connect( verticalScrollBar(), SIGNAL(sliderPressed()),
+ this, SLOT(sliderPressed()) );
+ connect( verticalScrollBar(), SIGNAL(sliderReleased()),
+ this, SLOT(sliderReleased()) );
+ connect( verticalScrollBar(), SIGNAL(valueChanged(int)),
+ this, SLOT(loadNextPage()) );
+ setNumRows(0);
+ loadNextPage();
+ }
+}
+
+/*!
+ Sets \a cursor as the data source for the table. To force the
+ display of the data from \a cursor, use refresh(). If \a
+ autoPopulate is true, columns are automatically created based upon
+ the fields in the \a cursor record. If \a autoDelete is true (the
+ default is false), the table will take ownership of the \a cursor
+ and delete it when appropriate. If the \a cursor is read-only, the
+ table becomes read-only. The table adopts the cursor's driver's
+ definition for representing NULL values as strings.
+
+ \sa refresh() setReadOnly() setAutoDelete() QSqlDriver::nullText()
+*/
+
+void Q3DataTable::setSqlCursor( Q3SqlCursor* cursor, bool autoPopulate, bool autoDelete )
+{
+ setUpdatesEnabled( false );
+ d->cur.setCursor( 0 );
+ if ( cursor ) {
+ d->cur.setCursor( cursor, autoDelete );
+ if ( autoPopulate ) {
+ d->fld.clear();
+ d->fldLabel.clear();
+ d->fldWidth.clear();
+ d->fldIcon.clear();
+ d->fldHidden.clear();
+ for ( int i = 0; i < sqlCursor()->count(); ++i ) {
+ addColumn( sqlCursor()->fieldPtr( i )->name(), sqlCursor()->fieldPtr( i )->name() );
+ setColumnReadOnly( i, sqlCursor()->fieldPtr( i )->isReadOnly() );
+ }
+ }
+ setReadOnly( sqlCursor()->isReadOnly() );
+ if ( sqlCursor()->driver() && !d->nullTxtChanged )
+ setNullText(sqlCursor()->driver()->nullText() );
+ setAutoDelete( autoDelete );
+ } else {
+ setNumRows( 0 );
+ setNumCols( 0 );
+ }
+ setUpdatesEnabled( true );
+}
+
+
+/*!
+ Protected virtual function which is called when an error \a e has
+ occurred on the current cursor(). The default implementation
+ displays a warning message to the user with information about the
+ error.
+*/
+void Q3DataTable::handleError( const QSqlError& e )
+{
+ d->dat.handleError( this, e );
+}
+
+/*! \reimp
+ */
+
+void Q3DataTable::keyPressEvent( QKeyEvent* e )
+{
+ switch( e->key() ) {
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_Prior:
+ case Qt::Key_Next:
+ case Qt::Key_Home:
+ case Qt::Key_End:
+ case Qt::Key_F2:
+ case Qt::Key_Enter: case Qt::Key_Return:
+ case Qt::Key_Tab: case Qt::Key_BackTab:
+ Q3Table::keyPressEvent( e );
+ default:
+ return;
+ }
+}
+
+/*! \reimp
+*/
+
+void Q3DataTable::resizeData ( int )
+{
+
+}
+
+/*! \reimp
+*/
+
+Q3TableItem * Q3DataTable::item ( int, int ) const
+{
+ return 0;
+}
+
+/*! \reimp
+*/
+
+void Q3DataTable::setItem ( int , int , Q3TableItem * )
+{
+
+}
+
+/*! \reimp
+*/
+
+void Q3DataTable::clearCell ( int , int )
+{
+
+}
+
+/*! \reimp
+*/
+
+void Q3DataTable::setPixmap ( int , int , const QPixmap & )
+{
+
+}
+
+/*! \reimp */
+void Q3DataTable::takeItem ( Q3TableItem * )
+{
+
+}
+
+/*!
+ Installs a new SQL editor factory \a f. This enables the user to
+ create and instantiate their own editors for use in cell editing.
+ Note that Q3DataTable takes ownership of this pointer, and will
+ delete it when it is no longer needed or when
+ installEditorFactory() is called again.
+
+ \sa Q3SqlEditorFactory
+*/
+
+void Q3DataTable::installEditorFactory( Q3SqlEditorFactory * f )
+{
+ if( f ) {
+ delete d->editorFactory;
+ d->editorFactory = f;
+ }
+}
+
+/*!
+ Installs a new property map \a m. This enables the user to create
+ and instantiate their own property maps for use in cell editing.
+ Note that Q3DataTable takes ownership of this pointer, and will
+ delete it when it is no longer needed or when installPropertMap()
+ is called again.
+
+ \sa Q3SqlPropertyMap
+*/
+
+void Q3DataTable::installPropertyMap( Q3SqlPropertyMap* m )
+{
+ if ( m ) {
+ delete d->propertyMap;
+ d->propertyMap = m;
+ }
+}
+
+/*! \internal
+
+ Sets the current selection to \a row, \a col.
+*/
+
+void Q3DataTable::setCurrentSelection( int row, int )
+{
+ if ( !sqlCursor() )
+ return;
+ if ( row == d->lastAt )
+ return;
+ if ( !sqlCursor()->seek( row ) )
+ return;
+ d->lastAt = row;
+ emit currentChanged( sqlCursor() );
+}
+
+void Q3DataTable::updateCurrentSelection()
+{
+ setCurrentSelection( currentRow(), -1 );
+}
+
+/*!
+ Returns the currently selected record, or 0 if there is no current
+ selection. The table owns the pointer, so do \e not delete it or
+ otherwise modify it or the cursor it points to.
+*/
+
+QSqlRecord* Q3DataTable::currentRecord() const
+{
+ if ( !sqlCursor() || currentRow() < 0 )
+ return 0;
+ if ( !sqlCursor()->seek( currentRow() ) )
+ return 0;
+ return sqlCursor();
+}
+
+/*!
+ Sorts column \a col in ascending order.
+
+ \sa setSorting()
+*/
+
+void Q3DataTable::sortAscending( int col )
+{
+ sortColumn( col, true );
+}
+
+/*!
+ Sorts column \a col in descending order.
+
+ \sa setSorting()
+*/
+
+void Q3DataTable::sortDescending( int col )
+{
+ sortColumn( col, false );
+}
+
+/*!
+ \fn void Q3DataTable::refresh( Refresh mode )
+
+ Refreshes the table. If there is no currently defined cursor (see
+ setSqlCursor()), nothing happens. The \a mode parameter determines
+ which type of refresh will take place.
+
+ \sa Refresh setSqlCursor() addColumn()
+*/
+
+void Q3DataTable::refresh( Q3DataTable::Refresh mode )
+{
+ Q3SqlCursor* cur = sqlCursor();
+ if ( !cur )
+ return;
+ bool refreshData = ( (mode & RefreshData) == RefreshData );
+ bool refreshCol = ( (mode & RefreshColumns) == RefreshColumns );
+ if ( ( (mode & RefreshAll) == RefreshAll ) ) {
+ refreshData = true;
+ refreshCol = true;
+ }
+ if ( !refreshCol && d->fld.count() && numCols() == 0 )
+ refreshCol = true;
+ viewport()->setUpdatesEnabled( false );
+ d->haveAllRows = false;
+ if ( refreshData ) {
+ if ( !d->cur.refresh() && d->cur.cursor() ) {
+ handleError( d->cur.cursor()->lastError() );
+ }
+ d->lastAt = -1;
+ }
+ if ( refreshCol ) {
+ setNumCols( 0 );
+ d->colIndex.clear();
+ if ( d->fld.count() ) {
+ const QSqlField* field = 0;
+ int i;
+ int fpos = -1;
+ for ( i = 0; i < (int)d->fld.count(); ++i ) {
+ if ( cur->fieldPtr( i ) && cur->fieldPtr( i )->name() == d->fld[ i ] )
+ // if there is a field with the desired name on the desired position
+ // then we take that
+ fpos = i;
+ else
+ // otherwise we take the first field that matches the desired name
+ fpos = cur->position( d->fld[ i ] );
+ field = cur->fieldPtr( fpos );
+ if ( field && ( cur->isGenerated( fpos ) ||
+ cur->isCalculated( field->name() ) ) )
+ {
+ setNumCols( numCols() + 1 );
+ d->colIndex.append( fpos );
+ setColumnReadOnly( numCols()-1, field->isReadOnly() || isColumnReadOnly( numCols()-1 ) );
+ horizontalHeader()->setLabel( numCols()-1, d->fldIcon[ i ], d->fldLabel[ i ] );
+ if ( d->fldHidden[ i ] ) {
+ Q3Table::showColumn( i ); // ugly but necessary
+ Q3Table::hideColumn( i );
+ } else {
+ Q3Table::showColumn( i );
+ }
+ if ( d->fldWidth[ i ] > -1 )
+ Q3Table::setColumnWidth( i, d->fldWidth[i] );
+ }
+ }
+ }
+ }
+ viewport()->setUpdatesEnabled( true );
+ viewport()->repaint( false );
+ horizontalHeader()->repaint();
+ verticalHeader()->repaint();
+ setSize( cur );
+ // keep others aware
+ if ( d->lastAt == -1 )
+ setCurrentSelection( -1, -1 );
+ else if ( d->lastAt != currentRow() )
+ setCurrentSelection( currentRow(), currentColumn() );
+ if ( cur->isValid() )
+ emit currentChanged( sqlCursor() );
+}
+
+/*!
+ Refreshes the table. The cursor is refreshed using the current
+ filter, the current sort, and the currently defined columns.
+ Equivalent to calling refresh( Q3DataTable::RefreshData ).
+*/
+
+void Q3DataTable::refresh()
+{
+ refresh( RefreshData );
+}
+
+/*!
+ \internal
+
+ Selects the record in the table using the current cursor edit
+ buffer and the fields specified by the index \a idx. If \a atHint
+ is specified, it will be used as a hint about where to begin
+ searching.
+*/
+
+bool Q3DataTable::findBuffer( const QSqlIndex& idx, int atHint )
+{
+ Q3SqlCursor* cur = sqlCursor();
+ if ( !cur )
+ return false;
+ bool found = d->cur.findBuffer( idx, atHint );
+ if ( found )
+ setCurrentCell( cur->at(), currentColumn() );
+ return found;
+}
+
+/*! \internal
+ Returns the string representation of a database field.
+*/
+QString Q3DataTable::fieldToString( const QSqlField * field )
+{
+ QString text;
+ if ( field->isNull() ) {
+ text = nullText();
+ } else {
+ QVariant val = field->value();
+ switch ( val.type() ) {
+ case QVariant::Bool:
+ text = val.toBool() ? d->trueTxt : d->falseTxt;
+ break;
+ case QVariant::Date:
+ text = val.toDate().toString( d->datefmt );
+ break;
+ case QVariant::Time:
+ text = val.toTime().toString( d->datefmt );
+ break;
+ case QVariant::DateTime:
+ text = val.toDateTime().toString( d->datefmt );
+ break;
+ default:
+ text = val.toString();
+ break;
+ }
+ }
+ return text;
+}
+
+/*!
+ \reimp
+*/
+
+void Q3DataTable::swapColumns( int col1, int col2, bool )
+{
+ QString fld = d->fld[ col1 ];
+ QString fldLabel = d->fldLabel[ col1 ];
+ QIconSet fldIcon = d->fldIcon[ col1 ];
+ int fldWidth = d->fldWidth[ col1 ];
+
+ d->fld[ col1 ] = d->fld[ col2 ];
+ d->fldLabel[ col1 ] = d->fldLabel[ col2 ];
+ d->fldIcon[ col1 ] = d->fldIcon[ col2 ];
+ d->fldWidth[ col1 ] = d->fldWidth[ col2 ];
+
+ d->fld[ col2 ] = fld;
+ d->fldLabel[ col2 ] = fldLabel;
+ d->fldIcon[ col2 ] = fldIcon;
+ d->fldWidth[ col2 ] = fldWidth;
+
+ int colIndex = d->colIndex[ col1 ];
+ d->colIndex[ col1 ] = d->colIndex[ col2 ];
+ d->colIndex[ col2 ] = colIndex;
+}
+
+/*!
+ \reimp
+*/
+
+void Q3DataTable::drawContents( QPainter * p, int cx, int cy, int cw, int ch )
+{
+ Q3Table::drawContents( p, cx, cy, cw, ch );
+ if ( sqlCursor() && currentRow() >= 0 )
+ sqlCursor()->seek( currentRow() );
+}
+
+/*!
+ \reimp
+ */
+void Q3DataTable::drawContents(QPainter *)
+{
+}
+
+/*!
+ \reimp
+*/
+
+void Q3DataTable::hideColumn( int col )
+{
+ d->fldHidden[col] = true;
+ refresh( RefreshColumns );
+}
+
+/*!
+ \reimp
+*/
+
+void Q3DataTable::showColumn( int col )
+{
+ d->fldHidden[col] = false;
+ refresh( RefreshColumns );
+}
+
+/*!
+ \reimp
+*/
+void Q3DataTable::selectRow(int row)
+{
+ setCurrentCell(row, currentColumn());
+}
+
+/*!
+ \fn void Q3DataTable::currentChanged( QSqlRecord* record )
+
+ This signal is emitted whenever a new row is selected in the
+ table. The \a record parameter points to the contents of the newly
+ selected record.
+*/
+
+/*!
+ \fn void Q3DataTable::primeInsert( QSqlRecord* buf )
+
+ This signal is emitted after the cursor is primed for insert by
+ the table, when an insert action is beginning on the table. The \a
+ buf parameter points to the edit buffer being inserted. Connect to
+ this signal in order to, for example, prime the record buffer with
+ default data values.
+*/
+
+/*!
+ \fn void Q3DataTable::primeUpdate( QSqlRecord* buf )
+
+ This signal is emitted after the cursor is primed for update by
+ the table, when an update action is beginning on the table. The \a
+ buf parameter points to the edit buffer being updated. Connect to
+ this signal in order to, for example, provide some visual feedback
+ that the user is in 'edit mode'.
+*/
+
+/*!
+ \fn void Q3DataTable::primeDelete( QSqlRecord* buf )
+
+ This signal is emitted after the cursor is primed for delete by
+ the table, when a delete action is beginning on the table. The \a
+ buf parameter points to the edit buffer being deleted. Connect to
+ this signal in order to, for example, record auditing information
+ on deletions.
+*/
+
+/*!
+ \fn void Q3DataTable::beforeInsert( QSqlRecord* buf )
+
+ This signal is emitted just before the cursor's edit buffer is
+ inserted into the database. The \a buf parameter points to the
+ edit buffer being inserted. Connect to this signal to, for
+ example, populate a key field with a unique sequence number.
+*/
+
+/*!
+ \fn void Q3DataTable::beforeUpdate( QSqlRecord* buf )
+
+ This signal is emitted just before the cursor's edit buffer is
+ updated in the database. The \a buf parameter points to the edit
+ buffer being updated. Connect to this signal when you want to
+ transform the user's data behind-the-scenes.
+*/
+
+/*!
+ \fn void Q3DataTable::beforeDelete( QSqlRecord* buf )
+
+ This signal is emitted just before the currently selected record
+ is deleted from the database. The \a buf parameter points to the
+ edit buffer being deleted. Connect to this signal to, for example,
+ copy some of the fields for later use.
+*/
+
+/*!
+ \fn void Q3DataTable::cursorChanged( QSql::Op mode )
+
+ This signal is emitted whenever the cursor record was changed due
+ to an edit. The \a mode parameter is the type of edit that just
+ took place.
+*/
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/qt3support/sql/q3datatable.h b/src/qt3support/sql/q3datatable.h
new file mode 100644
index 0000000..bbfd01c
--- /dev/null
+++ b/src/qt3support/sql/q3datatable.h
@@ -0,0 +1,251 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DATATABLE_H
+#define Q3DATATABLE_H
+
+#include <QtCore/qstring.h>
+#include <QtCore/qvariant.h>
+#include <Qt3Support/q3table.h>
+#include <QtSql/qsql.h>
+#include <Qt3Support/q3sqlcursor.h>
+#include <QtSql/qsqlindex.h>
+#include <Qt3Support/q3sqleditorfactory.h>
+#include <Qt3Support/qiconset.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3Support)
+
+#ifndef QT_NO_SQL_VIEW_WIDGETS
+
+class QPainter;
+class QSqlField;
+class Q3SqlPropertyMap;
+class Q3DataTablePrivate;
+
+class Q_COMPAT_EXPORT Q3DataTable : public Q3Table
+{
+ Q_OBJECT
+
+ Q_PROPERTY( QString nullText READ nullText WRITE setNullText )
+ Q_PROPERTY( QString trueText READ trueText WRITE setTrueText )
+ Q_PROPERTY( QString falseText READ falseText WRITE setFalseText )
+ Q_PROPERTY( Qt::DateFormat dateFormat READ dateFormat WRITE setDateFormat )
+ Q_PROPERTY( bool confirmEdits READ confirmEdits WRITE setConfirmEdits )
+ Q_PROPERTY( bool confirmInsert READ confirmInsert WRITE setConfirmInsert )
+ Q_PROPERTY( bool confirmUpdate READ confirmUpdate WRITE setConfirmUpdate )
+ Q_PROPERTY( bool confirmDelete READ confirmDelete WRITE setConfirmDelete )
+ Q_PROPERTY( bool confirmCancels READ confirmCancels WRITE setConfirmCancels )
+ Q_PROPERTY( bool autoEdit READ autoEdit WRITE setAutoEdit )
+ Q_PROPERTY( QString filter READ filter WRITE setFilter )
+ Q_PROPERTY( QStringList sort READ sort WRITE setSort )
+ Q_PROPERTY( int numCols READ numCols )
+ Q_PROPERTY( int numRows READ numRows )
+
+public:
+ Q3DataTable ( QWidget* parent=0, const char* name=0 );
+ Q3DataTable ( Q3SqlCursor* cursor, bool autoPopulate = false, QWidget* parent=0, const char* name=0 );
+ ~Q3DataTable();
+
+ virtual void addColumn( const QString& fieldName,
+ const QString& label = QString(),
+ int width = -1,
+ const QIconSet& iconset = QIconSet() );
+ virtual void removeColumn( int col );
+ virtual void setColumn( uint col, const QString& fieldName,
+ const QString& label = QString(),
+ int width = -1,
+ const QIconSet& iconset = QIconSet() );
+
+ QString nullText() const;
+ QString trueText() const;
+ QString falseText() const;
+ Qt::DateFormat dateFormat() const;
+ bool confirmEdits() const;
+ bool confirmInsert() const;
+ bool confirmUpdate() const;
+ bool confirmDelete() const;
+ bool confirmCancels() const;
+ bool autoDelete() const;
+ bool autoEdit() const;
+ QString filter() const;
+ QStringList sort() const;
+
+ virtual void setSqlCursor( Q3SqlCursor* cursor = 0,
+ bool autoPopulate = false, bool autoDelete = false );
+ Q3SqlCursor* sqlCursor() const;
+
+ virtual void setNullText( const QString& nullText );
+ virtual void setTrueText( const QString& trueText );
+ virtual void setFalseText( const QString& falseText );
+ virtual void setDateFormat( const Qt::DateFormat f );
+ virtual void setConfirmEdits( bool confirm );
+ virtual void setConfirmInsert( bool confirm );
+ virtual void setConfirmUpdate( bool confirm );
+ virtual void setConfirmDelete( bool confirm );
+ virtual void setConfirmCancels( bool confirm );
+ virtual void setAutoDelete( bool enable );
+ virtual void setAutoEdit( bool autoEdit );
+ virtual void setFilter( const QString& filter );
+ virtual void setSort( const QStringList& sort );
+ virtual void setSort( const QSqlIndex& sort );
+
+ enum Refresh {
+ RefreshData = 1,
+ RefreshColumns = 2,
+ RefreshAll = 3
+ };
+ void refresh( Refresh mode );
+ void sortColumn ( int col, bool ascending = true,
+ bool wholeRows = false );
+ QString text ( int row, int col ) const;
+ QVariant value ( int row, int col ) const;
+ QSqlRecord* currentRecord() const;
+
+ void installEditorFactory( Q3SqlEditorFactory * f );
+ void installPropertyMap( Q3SqlPropertyMap* m );
+
+ int numCols() const;
+ int numRows() const;
+ void setNumCols( int c );
+ void setNumRows ( int r );
+ bool findBuffer( const QSqlIndex& idx, int atHint = 0 );
+
+ void hideColumn( int col );
+ void showColumn( int col );
+ int indexOf( uint i ) const;
+ void selectRow(int row);
+
+Q_SIGNALS:
+ void currentChanged( QSqlRecord* record );
+ void primeInsert( QSqlRecord* buf );
+ void primeUpdate( QSqlRecord* buf );
+ void primeDelete( QSqlRecord* buf );
+ void beforeInsert( QSqlRecord* buf );
+ void beforeUpdate( QSqlRecord* buf );
+ void beforeDelete( QSqlRecord* buf );
+ void cursorChanged( QSql::Op mode );
+
+public Q_SLOTS:
+ virtual void find( const QString & str, bool caseSensitive,
+ bool backwards );
+ virtual void sortAscending( int col );
+ virtual void sortDescending( int col );
+ virtual void refresh();
+ void setColumnWidth( int col, int w );
+ void adjustColumn( int col );
+ void setColumnStretchable( int col, bool stretch );
+ void swapColumns( int col1, int col2, bool swapHeaders = false );
+
+protected:
+ virtual bool insertCurrent();
+ virtual bool updateCurrent();
+ virtual bool deleteCurrent();
+
+ virtual QSql::Confirm confirmEdit( QSql::Op m );
+ virtual QSql::Confirm confirmCancel( QSql::Op m );
+
+ virtual void handleError( const QSqlError& e );
+
+ virtual bool beginInsert();
+ virtual QWidget* beginUpdate ( int row, int col, bool replace );
+
+ bool eventFilter( QObject *o, QEvent *e );
+ void keyPressEvent( QKeyEvent* );
+ void resizeEvent ( QResizeEvent * );
+ void contentsMousePressEvent( QMouseEvent* e );
+ void contentsContextMenuEvent( QContextMenuEvent* e );
+ void endEdit( int row, int col, bool accept, bool replace );
+ QWidget * createEditor( int row, int col, bool initFromCell ) const;
+ void activateNextCell();
+ void reset();
+ void setSize( Q3SqlCursor* sql );
+ void repaintCell( int row, int col );
+ void paintCell ( QPainter * p, int row, int col, const QRect & cr,
+ bool selected, const QColorGroup &cg );
+ virtual void paintField( QPainter * p, const QSqlField* field, const QRect & cr,
+ bool selected );
+ void drawContents( QPainter * p, int cx, int cy, int cw, int ch );
+ virtual int fieldAlignment( const QSqlField* field );
+ void columnClicked ( int col );
+ void resizeData ( int len );
+
+ Q3TableItem * item ( int row, int col ) const;
+ void setItem ( int row, int col, Q3TableItem * item );
+ void clearCell ( int row, int col ) ;
+ void setPixmap ( int row, int col, const QPixmap & pix );
+ void takeItem ( Q3TableItem * i );
+
+private Q_SLOTS:
+ void loadNextPage();
+ void setCurrentSelection( int row, int col );
+ void updateCurrentSelection();
+ void sliderPressed();
+ void sliderReleased();
+ void doInsertCurrent();
+ void doUpdateCurrent();
+
+private:
+ void drawContents( QPainter *p);
+ QString fieldToString( const QSqlField * field );
+ void init();
+ QWidget* beginEdit ( int row, int col, bool replace );
+ void updateRow( int row );
+ void endInsert();
+ void endUpdate();
+ Q3DataTablePrivate* d;
+
+#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator=
+ Q3DataTable( const Q3DataTable & );
+ Q3DataTable &operator=( const Q3DataTable & );
+#endif
+};
+
+#endif // QT_NO_SQL_VIEW_WIDGETS
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3DATATABLE_H
diff --git a/src/qt3support/sql/q3dataview.cpp b/src/qt3support/sql/q3dataview.cpp
new file mode 100644
index 0000000..fb44996
--- /dev/null
+++ b/src/qt3support/sql/q3dataview.cpp
@@ -0,0 +1,208 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3dataview.h"
+
+#ifndef QT_NO_SQL_VIEW_WIDGETS
+
+#include "private/q3sqlmanager_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q3DataViewPrivate
+{
+public:
+ Q3DataViewPrivate() {}
+ Q3SqlFormManager frm;
+};
+
+
+/*!
+ \class Q3DataView
+ \brief The Q3DataView class provides read-only SQL forms.
+
+ \compat
+
+ This class provides a form which displays SQL field data from a
+ record buffer. Because Q3DataView does not support editing it uses
+ less resources than a Q3DataBrowser. This class is well suited for
+ displaying read-only data from a SQL database.
+
+ If you want a to present your data in an editable form use
+ Q3DataBrowser; if you want a table-based presentation of your data
+ use Q3DataTable.
+
+ The form is associated with the data view with setForm() and the
+ record is associated with setRecord(). You can also pass a
+ QSqlRecord to the refresh() function which will set the record to
+ the given record and read the record's fields into the form.
+*/
+
+/*!
+ Constructs a data view which is a child of \a parent, called \a
+ name, and with widget flags \a fl.
+*/
+
+Q3DataView::Q3DataView(QWidget *parent, const char *name, Qt::WindowFlags fl)
+ : QWidget(parent, name, fl)
+{
+ d = new Q3DataViewPrivate();
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+Q3DataView::~Q3DataView()
+{
+ delete d;
+}
+
+/*!
+ Clears the default form's values. If there is no default form,
+ nothing happens. All the values are set to their 'zero state',
+ e.g. 0 for numeric fields, "" for string fields.
+*/
+
+void Q3DataView::clearValues()
+{
+ d->frm.clearValues();
+}
+
+/*!
+ Sets the form used by the data view to \a form. If a record has
+ already been assigned to the data view, the form will display that
+ record's data.
+
+ \sa form()
+*/
+
+void Q3DataView::setForm(Q3SqlForm* form)
+{
+ d->frm.setForm(form);
+}
+
+
+/*!
+ Returns the default form used by the data view, or 0 if there is
+ none.
+
+ \sa setForm()
+*/
+
+Q3SqlForm* Q3DataView::form()
+{
+ return d->frm.form();
+}
+
+
+/*!
+ Sets the record used by the data view to \a record. If a form has
+ already been assigned to the data view, the form will display the
+ data from \a record in that form.
+
+ \sa record()
+*/
+
+void Q3DataView::setRecord(QSqlRecord* record)
+{
+ d->frm.setRecord(record);
+}
+
+
+/*!
+ Returns the default record used by the data view, or 0 if there is
+ none.
+
+ \sa setRecord()
+*/
+
+QSqlRecord* Q3DataView::record()
+{
+ return d->frm.record();
+}
+
+
+/*!
+ Causes the default form to read its fields from the record buffer.
+ If there is no default form, or no record, nothing happens.
+
+ \sa setForm()
+*/
+
+void Q3DataView::readFields()
+{
+ d->frm.readFields();
+}
+
+/*!
+ Causes the default form to write its fields to the record buffer.
+ If there is no default form, or no record, nothing happens.
+
+ \sa setForm()
+*/
+
+void Q3DataView::writeFields()
+{
+ d->frm.writeFields();
+}
+
+/*!
+ Causes the default form to display the contents of \a buf. If
+ there is no default form, nothing happens.The \a buf also becomes
+ the default record for all subsequent calls to readFields() and
+ writefields(). This slot is equivalant to calling:
+
+ \snippet doc/src/snippets/code/src_qt3support_sql_q3dataview.cpp 0
+
+ \sa setRecord() readFields()
+*/
+
+void Q3DataView::refresh(QSqlRecord* buf)
+{
+ if (buf && buf != record())
+ setRecord(buf);
+ readFields();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SQL_VIEW_WIDGETS
diff --git a/src/qt3support/sql/q3dataview.h b/src/qt3support/sql/q3dataview.h
new file mode 100644
index 0000000..f1b29d1
--- /dev/null
+++ b/src/qt3support/sql/q3dataview.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DATAVIEW_H
+#define Q3DATAVIEW_H
+
+#include <QtGui/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3Support)
+
+#ifndef QT_NO_SQL_VIEW_WIDGETS
+
+class Q3SqlForm;
+class QSqlRecord;
+class Q3DataViewPrivate;
+
+class Q_COMPAT_EXPORT Q3DataView : public QWidget
+{
+ Q_OBJECT
+
+public:
+ Q3DataView(QWidget* parent=0, const char* name=0, Qt::WindowFlags fl = 0);
+ ~Q3DataView();
+
+ virtual void setForm(Q3SqlForm* form);
+ Q3SqlForm* form();
+ virtual void setRecord(QSqlRecord* record);
+ QSqlRecord* record();
+
+public Q_SLOTS:
+ virtual void refresh(QSqlRecord* buf);
+ virtual void readFields();
+ virtual void writeFields();
+ virtual void clearValues();
+
+private:
+ Q_DISABLE_COPY(Q3DataView)
+
+ Q3DataViewPrivate* d;
+};
+
+#endif // QT_NO_SQL_VIEW_WIDGETS
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3DATAVIEW_H
diff --git a/src/qt3support/sql/q3editorfactory.cpp b/src/qt3support/sql/q3editorfactory.cpp
new file mode 100644
index 0000000..e5d97c7
--- /dev/null
+++ b/src/qt3support/sql/q3editorfactory.cpp
@@ -0,0 +1,202 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3cleanuphandler.h"
+#include "qlabel.h"
+#include "qlineedit.h"
+#include "qspinbox.h"
+#include "qcombobox.h"
+
+#include "q3editorfactory.h"
+#include "qdatetimeedit.h"
+
+#ifndef QT_NO_SQL_EDIT_WIDGETS
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class Q3EditorFactory
+ \brief The Q3EditorFactory class is used to create editor widgets
+ for QVariant data types.
+
+ \compat
+
+ Each editor factory provides the createEditor() function which
+ given a QVariant will create and return a QWidget that can edit
+ that QVariant. For example if you have a QVariant::String type, a
+ QLineEdit would be the default editor returned, whereas a
+ QVariant::Int's default editor would be a QSpinBox.
+
+ If you want to create different editors for fields with the same
+ data type, subclass Q3EditorFactory and reimplement the
+ createEditor() function.
+*/
+
+/*!
+ Constructs an editor factory with parent \a parent.
+*/
+
+Q3EditorFactory::Q3EditorFactory (QObject * parent)
+ : QObject(parent)
+{
+
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+Q3EditorFactory::~Q3EditorFactory()
+{
+
+}
+
+static Q3EditorFactory * defaultfactory = 0;
+static Q3CleanupHandler< Q3EditorFactory > q_cleanup_editor_factory;
+
+/*!
+ Returns an instance of a default editor factory.
+*/
+
+Q3EditorFactory * Q3EditorFactory::defaultFactory()
+{
+ if(defaultfactory == 0){
+ defaultfactory = new Q3EditorFactory();
+ q_cleanup_editor_factory.add(&defaultfactory);
+ }
+
+ return defaultfactory;
+}
+
+/*!
+ Replaces the default editor factory with \a factory.
+ \e{Q3EditorFactory takes ownership of factory, and destroys it
+ when it is no longer needed.}
+*/
+
+void Q3EditorFactory::installDefaultFactory(Q3EditorFactory * factory)
+{
+ if(factory == 0 || factory == defaultfactory) return;
+
+ if(defaultfactory != 0){
+ q_cleanup_editor_factory.remove(&defaultfactory);
+ delete defaultfactory;
+ }
+ defaultfactory = factory;
+ q_cleanup_editor_factory.add(&defaultfactory);
+}
+
+/*!
+ Creates and returns the appropriate editor for the QVariant \a v.
+ If the QVariant is invalid, 0 is returned. The \a parent is passed
+ to the appropriate editor's constructor.
+*/
+
+QWidget * Q3EditorFactory::createEditor(QWidget * parent, const QVariant & v)
+{
+ QWidget * w = 0;
+ switch(v.type()){
+ case QVariant::Invalid:
+ w = 0;
+ break;
+ case QVariant::Bool:
+ w = new QComboBox(parent, "qt_editor_bool");
+ ((QComboBox *) w)->insertItem(QLatin1String("False"));
+ ((QComboBox *) w)->insertItem(QLatin1String("True"));
+ break;
+ case QVariant::UInt:
+ w = new QSpinBox(0, 999999, 1, parent, "qt_editor_spinbox");
+ break;
+ case QVariant::Int:
+ w = new QSpinBox(-999999, 999999, 1, parent, "qt_editor_int");
+ break;
+ case QVariant::String:
+ case QVariant::Double:
+ w = new QLineEdit(parent, "qt_editor_double");
+ ((QLineEdit*)w)->setFrame(false);
+ break;
+ case QVariant::Date: {
+ QDateTimeEdit *edit = new QDateTimeEdit(parent);
+ edit->setDisplayFormat(QLatin1String("yyyy/MM/dd"));
+ edit->setObjectName(QLatin1String("qt_editor_date"));
+ w = edit; }
+ break;
+ case QVariant::Time: {
+ QDateTimeEdit *edit = new QDateTimeEdit(parent);
+ edit->setDisplayFormat(QLatin1String("hh:mm"));
+ edit->setObjectName(QLatin1String("qt_editor_time"));
+ w = edit; }
+ break;
+ case QVariant::DateTime:
+ w = new QDateTimeEdit(parent);
+ w->setObjectName(QLatin1String("qt_editor_datetime"));
+ break;
+#ifndef QT_NO_LABEL
+ case QVariant::Pixmap:
+ w = new QLabel(parent, QLatin1String("qt_editor_pixmap"));
+ break;
+#endif
+ case QVariant::Palette:
+ case QVariant::Color:
+ case QVariant::Font:
+ case QVariant::Brush:
+ case QVariant::Bitmap:
+ case QVariant::Cursor:
+ case QVariant::Map:
+ case QVariant::StringList:
+ case QVariant::Rect:
+ case QVariant::Size:
+ case QVariant::IconSet:
+ case QVariant::Point:
+ case QVariant::PointArray:
+ case QVariant::Region:
+ case QVariant::SizePolicy:
+ case QVariant::ByteArray:
+ default:
+ w = new QWidget(parent, "qt_editor_default");
+ break;
+ }
+ return w;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SQL
diff --git a/src/qt3support/sql/q3editorfactory.h b/src/qt3support/sql/q3editorfactory.h
new file mode 100644
index 0000000..476b683
--- /dev/null
+++ b/src/qt3support/sql/q3editorfactory.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3EDITORFACTORY_H
+#define Q3EDITORFACTORY_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3Support)
+
+#ifndef QT_NO_SQL_EDIT_WIDGETS
+
+class Q_COMPAT_EXPORT Q3EditorFactory : public QObject
+{
+public:
+ Q3EditorFactory (QObject * parent = 0);
+ ~Q3EditorFactory();
+
+ virtual QWidget * createEditor(QWidget * parent, const QVariant & v);
+
+ static Q3EditorFactory * defaultFactory();
+ static void installDefaultFactory(Q3EditorFactory * factory);
+
+private:
+ Q_DISABLE_COPY(Q3EditorFactory)
+};
+
+#endif // QT_NO_SQL_EDIT_WIDGETS
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3EDITORFACTORY_H
diff --git a/src/qt3support/sql/q3sqlcursor.cpp b/src/qt3support/sql/q3sqlcursor.cpp
new file mode 100644
index 0000000..5bc23c1
--- /dev/null
+++ b/src/qt3support/sql/q3sqlcursor.cpp
@@ -0,0 +1,1519 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qplatformdefs.h>
+#include "q3sqlcursor.h"
+
+#ifndef QT_NO_SQL
+
+#include "qsqldriver.h"
+#include "qsqlresult.h"
+#include "qdatetime.h"
+#include "qsqldatabase.h"
+#include "qsql.h"
+#include "q3sqlrecordinfo.h"
+#include "q3sqlfieldinfo.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q3SqlCursorPrivate
+{
+public:
+
+ Q3SqlCursorPrivate(const QString& name, QSqlDatabase sdb)
+ : lastAt(QSql::BeforeFirst), nm(name), srt(name), md(0), db(sdb), q(0)
+ {}
+ ~Q3SqlCursorPrivate()
+ {
+ delete q;
+ }
+
+ QSqlQuery* query()
+ {
+ if (!q)
+ q = new QSqlQuery(QString(), db);
+ return q;
+ }
+
+ int lastAt;
+ QString nm; //name
+ QSqlIndex srt; //sort
+ QString ftr; //filter
+ int md; //mode
+ QSqlIndex priIndx; //primary index
+ QSqlRecord editBuffer;
+ // the primary index as it was before the user changed the values in editBuffer
+ QString editIndex;
+ Q3SqlRecordInfo infoBuffer;
+ QSqlDatabase db;
+ QSqlQuery *q;
+};
+
+QString qOrderByClause(const QSqlIndex & i, const QString& prefix = QString())
+{
+ QString str;
+ int k = i.count();
+ if(k == 0)
+ return QString();
+ str = QLatin1String(" order by ") + i.toString(prefix);
+ return str;
+}
+
+QString qWhereClause(const QString& prefix, QSqlField* field, const QSqlDriver* driver)
+{
+ QString f;
+ if (field && driver) {
+ if (!prefix.isEmpty())
+ f += prefix + QLatin1Char('.');
+ f += field->name();
+ if (field->isNull()) {
+ f += QLatin1String(" IS NULL");
+ } else {
+ f += QLatin1String(" = ") + driver->formatValue(field);
+ }
+ }
+ return f;
+}
+
+QString qWhereClause(QSqlRecord* rec, const QString& prefix, const QString& sep,
+ const QSqlDriver* driver)
+{
+ static QString blank(QLatin1Char(' '));
+ QString filter;
+ bool separator = false;
+ for (int j = 0; j < rec->count(); ++j) {
+ QSqlField f = rec->field(j);
+ if (rec->isGenerated(j)) {
+ if (separator)
+ filter += sep + blank;
+ filter += qWhereClause(prefix, &f, driver);
+ filter += blank;
+ separator = true;
+ }
+ }
+ return filter;
+}
+
+/*!
+ \class Q3SqlCursor
+ \brief The Q3SqlCursor class provides browsing and editing of SQL
+ tables and views.
+
+ \compat
+
+ A Q3SqlCursor is a database record (see \l QSqlRecord) that
+ corresponds to a table or view within an SQL database (see \l
+ QSqlDatabase). There are two buffers in a cursor, one used for
+ browsing and one used for editing records. Each buffer contains a
+ list of fields which correspond to the fields in the table or
+ view.
+
+ When positioned on a valid record, the browse buffer contains the
+ values of the current record's fields from the database. The edit
+ buffer is separate, and is used for editing existing records and
+ inserting new records.
+
+ For browsing data, a cursor must first select() data from the
+ database. After a successful select() the cursor is active
+ (isActive() returns true), but is initially not positioned on a
+ valid record (isValid() returns false). To position the cursor on
+ a valid record, use one of the navigation functions, next(),
+ previous(), first(), last(), or seek(). Once positioned on a valid
+ record, data can be retrieved from the browse buffer using
+ value(). If a navigation function is not successful, it returns
+ false, the cursor will no longer be positioned on a valid record
+ and the values returned by value() are undefined.
+
+ For example:
+
+ \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 0
+
+ In the above example, a cursor is created specifying a table or
+ view name in the database. Then, select() is called, which can be
+ optionally parameterised to filter and order the records
+ retrieved. Each record in the cursor is retrieved using next().
+ When next() returns false, there are no more records to process,
+ and the loop terminates.
+
+ For editing records (rows of data), a cursor contains a separate
+ edit buffer which is independent of the fields used when browsing.
+ The functions insert(), update() and del() operate on the edit
+ buffer. This allows the cursor to be repositioned to other
+ records while simultaneously maintaining a separate buffer for
+ edits. You can get a pointer to the edit buffer using
+ editBuffer(). The primeInsert(), primeUpdate() and primeDelete()
+ functions also return a pointer to the edit buffer and prepare it
+ for insert, update and delete respectively. Edit operations only
+ affect a single row at a time. Note that update() and del()
+ require that the table or view contain a primaryIndex() to ensure
+ that edit operations affect a unique record within the database.
+
+ For example:
+
+ \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 1
+
+ To edit an existing database record, first move to the record you
+ wish to update. Call primeUpdate() to get the pointer to the
+ cursor's edit buffer. Then use this pointer to modify the values
+ in the edit buffer. Finally, call update() to save the changes to
+ the database. The values in the edit buffer will be used to
+ locate the appropriate record when updating the database (see
+ primaryIndex()).
+
+ Similarly, when deleting an existing database record, first move
+ to the record you wish to delete. Then, call primeDelete() to get
+ the pointer to the edit buffer. Finally, call del() to delete the
+ record from the database. Again, the values in the edit buffer
+ will be used to locate and delete the appropriate record.
+
+ To insert a new record, call primeInsert() to get the pointer to
+ the edit buffer. Use this pointer to populate the edit buffer
+ with new values and then insert() the record into the database.
+
+ After calling insert(), update() or del(), the cursor is no longer
+ positioned on a valid record and can no longer be navigated
+ (isValid() return false). The reason for this is that any changes
+ made to the database will not be visible until select() is called
+ to refresh the cursor. You can change this behavior by passing
+ false to insert(), update() or del() which will prevent the cursor
+ from becoming invalid. The edits will still not be visible when
+ navigating the cursor until select() is called.
+
+ Q3SqlCursor contains virtual methods which allow editing behavior
+ to be customized by subclasses. This allows custom cursors to be
+ created that encapsulate the editing behavior of a database table
+ for an entire application. For example, a cursor can be customized
+ to always auto-number primary index fields, or provide fields with
+ suitable default values, when inserting new records. Q3SqlCursor
+ generates SQL statements which are sent to the database engine;
+ you can control which fields are included in these statements
+ using setGenerated().
+
+ Note that Q3SqlCursor does not inherit from QObject. This means
+ that you are responsible for destroying instances of this class
+ yourself. However if you create a Q3SqlCursor and use it in a
+ \l Q3DataTable, \l Q3DataBrowser or a \l Q3DataView these classes will
+ usually take ownership of the cursor and destroy it when they
+ don't need it anymore. The documentation for Q3DataTable,
+ Q3DataBrowser and Q3DataView explicitly states which calls take
+ ownership of the cursor.
+*/
+
+/*!
+ \enum Q3SqlCursor::Mode
+
+ This enum type describes how Q3SqlCursor operates on records in the
+ database.
+
+ \value ReadOnly the cursor can only SELECT records from the
+ database.
+
+ \value Insert the cursor can INSERT records into the database.
+
+ \value Update the cursor can UPDATE records in the database.
+
+ \value Delete the cursor can DELETE records from the database.
+
+ \value Writable the cursor can INSERT, UPDATE and DELETE records
+ in the database.
+*/
+
+/*!
+ \fn QVariant Q3SqlCursor::value(const QString &name) const
+
+ \overload
+
+ Returns the value of the field named \a name.
+*/
+
+/*!
+ \fn void Q3SqlCursor::setValue(const QString &name, const QVariant &val)
+
+ \overload
+
+ Sets the value for the field named \a name to \a val.
+*/
+
+/*!
+ Constructs a cursor on database \a db using table or view \a name.
+
+ If \a autopopulate is true (the default), the \a name of the
+ cursor must correspond to an existing table or view name in the
+ database so that field information can be automatically created.
+ If the table or view does not exist, the cursor will not be
+ functional.
+
+ The cursor is created with an initial mode of Q3SqlCursor::Writable
+ (meaning that records can be inserted, updated or deleted using
+ the cursor). If the cursor does not have a unique primary index,
+ update and deletes cannot be performed.
+
+ Note that \a autopopulate refers to populating the cursor with
+ meta-data, e.g. the names of the table's fields, not with
+ retrieving data. The select() function is used to populate the
+ cursor with data.
+
+ \sa setName() setMode()
+*/
+
+Q3SqlCursor::Q3SqlCursor(const QString & name, bool autopopulate, QSqlDatabase db)
+ : QSqlRecord(), QSqlQuery(QString(), db)
+{
+ d = new Q3SqlCursorPrivate(name, db);
+ setMode(Writable);
+ if (!d->nm.isEmpty())
+ setName(d->nm, autopopulate);
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+
+Q3SqlCursor::Q3SqlCursor(const Q3SqlCursor & other)
+ : QSqlRecord(other), QSqlQuery(other)
+{
+ d = new Q3SqlCursorPrivate(other.d->nm, other.d->db);
+ d->lastAt = other.d->lastAt;
+ d->nm = other.d->nm;
+ d->srt = other.d->srt;
+ d->ftr = other.d->ftr;
+ d->priIndx = other.d->priIndx;
+ d->editBuffer = other.d->editBuffer;
+ d->infoBuffer = other.d->infoBuffer;
+ d->q = 0; // do not share queries
+ setMode(other.mode());
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+Q3SqlCursor::~Q3SqlCursor()
+{
+ delete d;
+}
+
+/*!
+ Sets the cursor equal to \a other.
+*/
+
+Q3SqlCursor& Q3SqlCursor::operator=(const Q3SqlCursor& other)
+{
+ QSqlRecord::operator=(other);
+ QSqlQuery::operator=(other);
+ delete d;
+ d = new Q3SqlCursorPrivate(other.d->nm, other.d->db);
+ d->lastAt = other.d->lastAt;
+ d->nm = other.d->nm;
+ d->srt = other.d->srt;
+ d->ftr = other.d->ftr;
+ d->priIndx = other.d->priIndx;
+ d->editBuffer = other.d->editBuffer;
+ d->infoBuffer = other.d->infoBuffer;
+ d->q = 0; // do not share queries
+ setMode(other.mode());
+ return *this;
+}
+
+/*!
+ Sets the current sort to \a sort. Note that no new records are
+ selected. To select new records, use select(). The \a sort will
+ apply to any subsequent select() calls that do not explicitly
+ specify a sort.
+*/
+
+void Q3SqlCursor::setSort(const QSqlIndex& sort)
+{
+ d->srt = sort;
+}
+
+/*!
+ Returns the current sort, or an empty index if there is no current
+ sort.
+*/
+QSqlIndex Q3SqlCursor::sort() const
+{
+ return d->srt;
+}
+
+/*!
+ Sets the current filter to \a filter. Note that no new records are
+ selected. To select new records, use select(). The \a filter will
+ apply to any subsequent select() calls that do not explicitly
+ specify a filter.
+
+ The filter is a SQL \c WHERE clause without the keyword 'WHERE',
+ e.g. \c{name='Dave'} which will be processed by the DBMS.
+*/
+void Q3SqlCursor::setFilter(const QString& filter)
+{
+ d->ftr = filter;
+}
+
+/*!
+ Returns the current filter, or an empty string if there is no
+ current filter.
+*/
+QString Q3SqlCursor::filter() const
+{
+ return d->ftr;
+}
+
+/*!
+ Sets the name of the cursor to \a name. If \a autopopulate is true
+ (the default), the \a name must correspond to a valid table or
+ view name in the database. Also, note that all references to the
+ cursor edit buffer become invalidated when fields are
+ auto-populated. See the Q3SqlCursor constructor documentation for
+ more information.
+*/
+void Q3SqlCursor::setName(const QString& name, bool autopopulate)
+{
+ d->nm = name;
+ if (autopopulate) {
+ if (driver()) {
+ d->infoBuffer = driver()->record(name);
+ *this = d->infoBuffer.toRecord();
+ d->editBuffer = *this;
+ d->priIndx = driver()->primaryIndex(name);
+ }
+ if (isEmpty())
+ qWarning("Q3SqlCursor::setName: unable to build record, does '%s' exist?", name.latin1());
+ }
+}
+
+/*!
+ Returns the name of the cursor.
+*/
+
+QString Q3SqlCursor::name() const
+{
+ return d->nm;
+}
+
+/*! \internal
+*/
+
+QString Q3SqlCursor::toString(const QString& prefix, const QString& sep) const
+{
+ QString pflist;
+ QString pfix = prefix.isEmpty() ? prefix : prefix + QLatin1Char('.');
+ bool comma = false;
+
+ for (int i = 0; i < count(); ++i) {
+ const QString fname = fieldName(i);
+ if (isGenerated(i)) {
+ if(comma)
+ pflist += sep + QLatin1Char(' ');
+ pflist += pfix + driver()->escapeIdentifier(fname, QSqlDriver::FieldName);
+ comma = true;
+ }
+ }
+ return pflist;
+}
+
+/*!
+ \internal
+
+ Assigns the record \a list.
+
+*/
+QSqlRecord & Q3SqlCursor::operator=(const QSqlRecord & list)
+{
+ return QSqlRecord::operator=(list);
+}
+
+/*!
+ Append a copy of field \a fieldInfo to the end of the cursor. Note
+ that all references to the cursor edit buffer become invalidated.
+*/
+
+void Q3SqlCursor::append(const Q3SqlFieldInfo& fieldInfo)
+{
+ d->editBuffer.append(fieldInfo.toField());
+ d->infoBuffer.append(fieldInfo);
+ QSqlRecord::append(fieldInfo.toField());
+}
+
+/*!
+ Removes all fields from the cursor. Note that all references to
+ the cursor edit buffer become invalidated.
+*/
+void Q3SqlCursor::clear()
+{
+ d->editBuffer.clear();
+ d->infoBuffer.clear();
+ QSqlRecord::clear();
+}
+
+
+/*!
+ Insert a copy of \a fieldInfo at position \a pos. If a field
+ already exists at \a pos, it is removed. Note that all references
+ to the cursor edit buffer become invalidated.
+*/
+
+void Q3SqlCursor::insert(int pos, const Q3SqlFieldInfo& fieldInfo)
+{
+ d->editBuffer.replace(pos, fieldInfo.toField());
+ d->infoBuffer[pos] = fieldInfo;
+ QSqlRecord::replace(pos, fieldInfo.toField());
+}
+
+/*!
+ Removes the field at \a pos. If \a pos does not exist, nothing
+ happens. Note that all references to the cursor edit buffer become
+ invalidated.
+*/
+
+void Q3SqlCursor::remove(int pos)
+{
+ d->editBuffer.remove(pos);
+ d->infoBuffer[pos] = Q3SqlFieldInfo();
+ QSqlRecord::remove(pos);
+}
+
+/*!
+ Sets the generated flag for the field \a name to \a generated. If
+ the field does not exist, nothing happens. Only fields that have
+ \a generated set to true are included in the SQL that is
+ generated by insert(), update() or del().
+*/
+
+void Q3SqlCursor::setGenerated(const QString& name, bool generated)
+{
+ int pos = indexOf(name);
+ if (pos == -1)
+ return;
+ QSqlRecord::setGenerated(name, generated);
+ d->editBuffer.setGenerated(name, generated);
+ d->infoBuffer[pos].setGenerated(generated);
+}
+
+/*!
+ \overload
+
+ Sets the generated flag for the field \a i to \a generated.
+*/
+void Q3SqlCursor::setGenerated(int i, bool generated)
+{
+ if (i < 0 || i >= (int)d->infoBuffer.count())
+ return;
+ QSqlRecord::setGenerated(i, generated);
+ d->editBuffer.setGenerated(i, generated);
+ d->infoBuffer[i].setGenerated(generated);
+}
+
+/*!
+ Returns the primary index associated with the cursor as defined in
+ the database, or an empty index if there is no primary index. If
+ \a setFromCursor is true (the default), the index fields are
+ populated with the corresponding values in the cursor's current
+ record.
+*/
+
+QSqlIndex Q3SqlCursor::primaryIndex(bool setFromCursor) const
+{
+ if (setFromCursor) {
+ for (int i = 0; i < d->priIndx.count(); ++i) {
+ const QString fn = d->priIndx.fieldName(i);
+ if (contains(fn))
+ d->priIndx.setValue(i, QSqlRecord::value(fn));
+ }
+ }
+ return d->priIndx;
+}
+
+/*!
+ Sets the primary index associated with the cursor to the index \a
+ idx. Note that this index must contain a field or set of fields
+ which identify a unique record within the underlying database
+ table or view so that update() and del() will execute as expected.
+
+ \sa update() del()
+*/
+
+void Q3SqlCursor::setPrimaryIndex(const QSqlIndex& idx)
+{
+ d->priIndx = idx;
+}
+
+
+/*!
+ Returns an index composed of \a fieldNames, all in ASCending
+ order. Note that all field names must exist in the cursor,
+ otherwise an empty index is returned.
+
+ \sa QSqlIndex
+*/
+
+QSqlIndex Q3SqlCursor::index(const QStringList& fieldNames) const
+{
+ QSqlIndex idx;
+ for (QStringList::ConstIterator it = fieldNames.begin(); it != fieldNames.end(); ++it) {
+ QSqlField f = field((*it));
+ if (!f.isValid()) { /* all fields must exist */
+ idx.clear();
+ break;
+ }
+ idx.append(f);
+ }
+ return idx;
+}
+
+/*!
+ \overload
+
+ Returns an index based on \a fieldName.
+*/
+
+QSqlIndex Q3SqlCursor::index(const QString& fieldName) const
+{
+ QStringList fl(fieldName);
+ return index(fl);
+}
+
+/*!
+ Selects all fields in the cursor from the database matching the
+ filter criteria \a filter. The data is returned in the order
+ specified by the index \a sort. Returns true if the data was
+ successfully selected; otherwise returns false.
+
+ The \a filter is a string containing a SQL \c WHERE clause but
+ without the 'WHERE' keyword. The cursor is initially positioned at
+ an invalid row after this function is called. To move to a valid
+ row, use seek(), first(), last(), previous() or next().
+
+ Example:
+ \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 2
+
+ The filter will apply to any subsequent select() calls that do not
+ explicitly specify another filter. Similarly the sort will apply
+ to any subsequent select() calls that do not explicitly specify
+ another sort.
+
+ \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 3
+
+*/
+
+bool Q3SqlCursor::select(const QString & filter, const QSqlIndex & sort)
+{
+ QString fieldList(toString(d->nm));
+ if (fieldList.isEmpty())
+ return false;
+ QString str(QLatin1String("select ") + fieldList);
+ str += QLatin1String(" from ") + d->nm;
+ if (!filter.isEmpty()) {
+ d->ftr = filter;
+ str += QLatin1String(" where ") + filter;
+ } else
+ d->ftr.clear();
+ if (sort.count() > 0)
+ str += QLatin1String(" order by ") + sort.toString(d->nm);
+ d->srt = sort;
+ return exec(str);
+}
+
+/*!
+ \overload
+
+ Selects all fields in the cursor from the database. The rows are
+ returned in the order specified by the last call to setSort() or
+ the last call to select() that specified a sort, whichever is the
+ most recent. If there is no current sort, the order in which the
+ rows are returned is undefined. The records are filtered according
+ to the filter specified by the last call to setFilter() or the
+ last call to select() that specified a filter, whichever is the
+ most recent. If there is no current filter, all records are
+ returned. The cursor is initially positioned at an invalid row. To
+ move to a valid row, use seek(), first(), last(), previous() or
+ next().
+
+ \sa setSort() setFilter()
+*/
+
+bool Q3SqlCursor::select()
+{
+ return select(filter(), sort());
+}
+
+/*!
+ \overload
+
+ Selects all fields in the cursor from the database. The data is
+ returned in the order specified by the index \a sort. The records
+ are filtered according to the filter specified by the last call to
+ setFilter() or the last call to select() that specified a filter,
+ whichever is the most recent. The cursor is initially positioned
+ at an invalid row. To move to a valid row, use seek(), first(),
+ last(), previous() or next().
+*/
+
+bool Q3SqlCursor::select(const QSqlIndex& sort)
+{
+ return select(filter(), sort);
+}
+
+/*!
+ \overload
+
+ Selects all fields in the cursor matching the filter index \a
+ filter. The data is returned in the order specified by the index
+ \a sort. The \a filter index works by constructing a WHERE clause
+ using the names of the fields from the \a filter and their values
+ from the current cursor record. The cursor is initially positioned
+ at an invalid row. To move to a valid row, use seek(), first(),
+ last(), previous() or next(). This function is useful, for example,
+ for retrieving data based upon a table's primary index:
+
+ \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 4
+
+ In this example the QSqlIndex, pk, is used for two different
+ purposes. When used as the filter (first) argument, the field
+ names it contains are used to construct the WHERE clause, each set
+ to the current cursor value, \c{WHERE id=10}, in this case. When
+ used as the sort (second) argument the field names it contains are
+ used for the ORDER BY clause, \c{ORDER BY id} in this example.
+*/
+
+bool Q3SqlCursor::select(const QSqlIndex & filter, const QSqlIndex & sort)
+{
+ return select(toString(filter, this, d->nm, QString(QLatin1Char('=')), QLatin1String("and")), sort);
+}
+
+/*!
+ Sets the cursor mode to \a mode. This value can be an OR'ed
+ combination of \l Q3SqlCursor::Mode values. The default mode for a
+ cursor is Q3SqlCursor::Writable.
+
+ \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 5
+*/
+
+void Q3SqlCursor::setMode(int mode)
+{
+ d->md = mode;
+}
+
+/*!
+ Returns the current cursor mode.
+
+ \sa setMode()
+*/
+
+int Q3SqlCursor::mode() const
+{
+ return d->md;
+}
+
+/*!
+ Sets field \a name to \a calculated. If the field \a name does not
+ exist, nothing happens. The value of a calculated field is set by
+ the calculateField() virtual function which you must reimplement
+ (or the field value will be an invalid QVariant). Calculated
+ fields do not appear in generated SQL statements sent to the
+ database.
+
+ \sa calculateField()
+*/
+
+void Q3SqlCursor::setCalculated(const QString& name, bool calculated)
+{
+ int pos = indexOf(name);
+ if (pos < 0)
+ return;
+ d->infoBuffer[pos].setCalculated(calculated);
+ if (calculated)
+ setGenerated(pos, false);
+}
+
+/*!
+ Returns true if the field \a name exists and is calculated;
+ otherwise returns false.
+
+ \sa setCalculated()
+*/
+
+bool Q3SqlCursor::isCalculated(const QString& name) const
+{
+ int pos = indexOf(name);
+ if (pos < 0)
+ return false;
+ return d->infoBuffer[pos].isCalculated();
+}
+
+/*!
+ Sets field \a{name}'s trimmed status to \a trim. If the field \a
+ name does not exist, nothing happens.
+
+ When a trimmed field of type string is read from the
+ database any trailing (right-most) spaces are removed.
+
+ \sa isTrimmed() QVariant
+*/
+
+void Q3SqlCursor::setTrimmed(const QString& name, bool trim)
+{
+ int pos = indexOf(name);
+ if (pos < 0)
+ return;
+ d->infoBuffer[pos].setTrim(trim);
+}
+
+/*!
+ Returns true if the field \a name exists and is trimmed; otherwise
+ returns false.
+
+ When a trimmed field of type string or cstring is read from the
+ database any trailing (right-most) spaces are removed.
+
+ \sa setTrimmed()
+*/
+
+bool Q3SqlCursor::isTrimmed(const QString& name) const
+{
+ int pos = indexOf(name);
+ if (pos < 0)
+ return false;
+ return d->infoBuffer[pos].isTrim();
+}
+
+/*!
+ Returns true if the cursor is read-only; otherwise returns false.
+ The default is false. Read-only cursors cannot be edited using
+ insert(), update() or del().
+
+ \sa setMode()
+*/
+
+bool Q3SqlCursor::isReadOnly() const
+{
+ return d->md == 0;
+}
+
+/*!
+ Returns true if the cursor will perform inserts; otherwise returns
+ false.
+
+ \sa setMode()
+*/
+
+bool Q3SqlCursor::canInsert() const
+{
+ return ((d->md & Insert) == Insert) ;
+}
+
+
+/*!
+ Returns true if the cursor will perform updates; otherwise returns
+ false.
+
+ \sa setMode()
+*/
+
+bool Q3SqlCursor::canUpdate() const
+{
+ return ((d->md & Update) == Update) ;
+}
+
+/*!
+ Returns true if the cursor will perform deletes; otherwise returns
+ false.
+
+ \sa setMode()
+*/
+
+bool Q3SqlCursor::canDelete() const
+{
+ return ((d->md & Delete) == Delete) ;
+}
+
+/*!
+ \overload
+
+ Returns a formatted string composed of the \a prefix (e.g. table
+ or view name), ".", the \a field name, the \a fieldSep and the
+ field value. If the \a prefix is empty then the string will begin
+ with the \a field name. This function is useful for generating SQL
+ statements.
+*/
+
+QString Q3SqlCursor::toString(const QString& prefix, QSqlField* field, const QString& fieldSep) const
+{
+ QString f;
+ if (field && driver()) {
+ f = (prefix.length() > 0 ? prefix + QLatin1Char('.') : QString()) + field->name();
+ f += QLatin1Char(' ') + fieldSep + QLatin1Char(' ');
+ if (field->isNull()) {
+ f += QLatin1String("NULL");
+ } else {
+ f += driver()->formatValue(field);
+ }
+ }
+ return f;
+}
+
+/*!
+ Returns a formatted string composed of all the fields in \a rec.
+ Each field is composed of the \a prefix (e.g. table or view name),
+ ".", the field name, the \a fieldSep and the field value. If the
+ \a prefix is empty then each field will begin with the field name.
+ The fields are then joined together separated by \a sep. Fields
+ where isGenerated() returns false are not included. This function
+ is useful for generating SQL statements.
+*/
+
+QString Q3SqlCursor::toString(QSqlRecord* rec, const QString& prefix, const QString& fieldSep,
+ const QString& sep) const
+{
+ static QString blank(QLatin1Char(' '));
+ QString filter;
+ bool separator = false;
+ for (int j = 0; j < count(); ++j) {
+ QSqlField f = rec->field(j);
+ if (rec->isGenerated(j)) {
+ if (separator)
+ filter += sep + blank;
+ filter += toString(prefix, &f, fieldSep);
+ filter += blank;
+ separator = true;
+ }
+ }
+ return filter;
+}
+
+/*!
+ \overload
+
+ Returns a formatted string composed of all the fields in the index
+ \a i. Each field is composed of the \a prefix (e.g. table or view
+ name), ".", the field name, the \a fieldSep and the field value.
+ If the \a prefix is empty then each field will begin with the field
+ name. The field values are taken from \a rec. The fields are then
+ joined together separated by \a sep. Fields where isGenerated()
+ returns false are ignored. This function is useful for generating
+ SQL statements.
+*/
+
+QString Q3SqlCursor::toString(const QSqlIndex& i, QSqlRecord* rec, const QString& prefix,
+ const QString& fieldSep, const QString& sep) const
+{
+ QString filter;
+ bool separator = false;
+ for(int j = 0; j < i.count(); ++j){
+ if (rec->isGenerated(j)) {
+ if(separator) {
+ filter += QLatin1Char(' ') + sep + QLatin1Char(' ') ;
+ }
+ QString fn = i.fieldName(j);
+ QSqlField f = rec->field(fn);
+ filter += toString(prefix, &f, fieldSep);
+ separator = true;
+ }
+ }
+ return filter;
+}
+
+/*!
+ Inserts the current contents of the cursor's edit record buffer
+ into the database, if the cursor allows inserts. Returns the
+ number of rows affected by the insert. For error information, use
+ lastError().
+
+ If \a invalidate is true (the default), the cursor will no longer
+ be positioned on a valid record and can no longer be navigated. A
+ new select() call must be made before navigating to a valid
+ record.
+
+ \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 6
+
+ In the above example, a cursor is created on the 'prices' table
+ and a pointer to the insert buffer is acquired using primeInsert().
+ Each field's value is set to the desired value and then insert()
+ is called to insert the data into the database. Remember: all edit
+ operations (insert(), update() and delete()) operate on the
+ contents of the cursor edit buffer and not on the contents of the
+ cursor itself.
+
+ \sa setMode() lastError()
+*/
+
+int Q3SqlCursor::insert(bool invalidate)
+{
+ if ((d->md & Insert) != Insert || !driver())
+ return false;
+ int k = d->editBuffer.count();
+ if (k == 0)
+ return 0;
+
+ QString fList;
+ QString vList;
+ bool comma = false;
+ // use a prepared query if the driver supports it
+ if (driver()->hasFeature(QSqlDriver::PreparedQueries)) {
+ int cnt = 0;
+ bool oraStyle = driver()->hasFeature(QSqlDriver::NamedPlaceholders);
+ for(int j = 0; j < k; ++j) {
+ QSqlField f = d->editBuffer.field(j);
+ if (d->editBuffer.isGenerated(j)) {
+ if (comma) {
+ fList += QLatin1Char(',');
+ vList += QLatin1Char(',');
+ }
+ fList += driver()->escapeIdentifier(f.name(), QSqlDriver::FieldName);
+ vList += (oraStyle == true) ? QLatin1String(":f") + QString::number(cnt) : QString(QLatin1Char('?'));
+ cnt++;
+ comma = true;
+ }
+ }
+ if (!comma) {
+ return 0;
+ }
+ QString str;
+ str.append(QLatin1String("insert into ")).append(name())
+ .append(QLatin1String(" (")).append(fList)
+ .append(QLatin1String(") values (")).append(vList). append(QLatin1Char(')'));
+
+ return applyPrepared(str, invalidate);
+ } else {
+ for(int j = 0; j < k; ++j) {
+ QSqlField f = d->editBuffer.field(j);
+ if (d->editBuffer.isGenerated(j)) {
+ if (comma) {
+ fList += QLatin1Char(',');
+ vList += QLatin1Char(',');
+ }
+ fList += driver()->escapeIdentifier(f.name(), QSqlDriver::FieldName);
+ vList += driver()->formatValue(&f);
+ comma = true;
+ }
+ }
+
+ if (!comma) {
+ // no valid fields found
+ return 0;
+ }
+ QString str;
+ str.append(QLatin1String("insert into ")).append(name()).append(QLatin1String(" ("))
+ .append(fList).append(QLatin1String(") values (")).append(vList). append (QLatin1String(")"));
+ return apply(str, invalidate);
+ }
+}
+
+/*!
+ Returns the current internal edit buffer. If \a copy is true (the
+ default is false), the current cursor field values are first
+ copied into the edit buffer. The edit buffer is valid as long as
+ the cursor remains valid. The cursor retains ownership of the
+ returned pointer, so it must not be deleted or modified.
+
+ \sa primeInsert(), primeUpdate() primeDelete()
+*/
+
+QSqlRecord* Q3SqlCursor::editBuffer(bool copy)
+{
+ sync();
+ if (copy) {
+ for(int i = 0; i < d->editBuffer.count(); i++) {
+ if (QSqlRecord::isNull(i)) {
+ d->editBuffer.setNull(i);
+ } else {
+ d->editBuffer.setValue(i, value(i));
+ }
+ }
+ }
+ return &d->editBuffer;
+}
+
+/*!
+ This function primes the edit buffer's field values for update and
+ returns the edit buffer. The default implementation copies the
+ field values from the current cursor record into the edit buffer
+ (therefore, this function is equivalent to calling editBuffer(
+ true)). The cursor retains ownership of the returned pointer, so
+ it must not be deleted or modified.
+
+ \sa editBuffer() update()
+*/
+
+QSqlRecord* Q3SqlCursor::primeUpdate()
+{
+ // memorize the primary keys as they were before the user changed the values in editBuffer
+ QSqlRecord* buf = editBuffer(true);
+ QSqlIndex idx = primaryIndex(false);
+ if (!idx.isEmpty())
+ d->editIndex = toString(idx, buf, d->nm, QString(QLatin1Char('=')), QLatin1String("and"));
+ else
+ d->editIndex = qWhereClause(buf, d->nm, QLatin1String("and"), driver());
+ return buf;
+}
+
+/*!
+ This function primes the edit buffer's field values for delete and
+ returns the edit buffer. The default implementation copies the
+ field values from the current cursor record into the edit buffer
+ (therefore, this function is equivalent to calling editBuffer(
+ true)). The cursor retains ownership of the returned pointer, so
+ it must not be deleted or modified.
+
+ \sa editBuffer() del()
+*/
+
+QSqlRecord* Q3SqlCursor::primeDelete()
+{
+ return editBuffer(true);
+}
+
+/*!
+ This function primes the edit buffer's field values for insert and
+ returns the edit buffer. The default implementation clears all
+ field values in the edit buffer. The cursor retains ownership of
+ the returned pointer, so it must not be deleted or modified.
+
+ \sa editBuffer() insert()
+*/
+
+QSqlRecord* Q3SqlCursor::primeInsert()
+{
+ d->editBuffer.clearValues();
+ return &d->editBuffer;
+}
+
+
+/*!
+ Updates the database with the current contents of the edit buffer.
+ Returns the number of records which were updated.
+ For error information, use lastError().
+
+ Only records which meet the filter criteria specified by the
+ cursor's primary index are updated. If the cursor does not contain
+ a primary index, no update is performed and 0 is returned.
+
+ If \a invalidate is true (the default), the current cursor can no
+ longer be navigated. A new select() call must be made before you
+ can move to a valid record. For example:
+
+ \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 7
+
+ In the above example, a cursor is created on the 'prices' table
+ and is positioned on the record to be updated. Then a pointer to
+ the cursor's edit buffer is acquired using primeUpdate(). A new
+ value is calculated and placed into the edit buffer with the
+ setValue() call. Finally, an update() call is made on the cursor
+ which uses the tables's primary index to update the record in the
+ database with the contents of the cursor's edit buffer. Remember:
+ all edit operations (insert(), update() and delete()) operate on
+ the contents of the cursor edit buffer and not on the contents of
+ the cursor itself.
+
+ Note that if the primary index does not uniquely distinguish
+ records the database may be changed into an inconsistent state.
+
+ \sa setMode() lastError()
+*/
+
+int Q3SqlCursor::update(bool invalidate)
+{
+ if (d->editIndex.isEmpty())
+ return 0;
+ return update(d->editIndex, invalidate);
+}
+
+/*!
+ \overload
+
+ Updates the database with the current contents of the cursor edit
+ buffer using the specified \a filter. Returns the number of
+ records which were updated.
+ For error information, use lastError().
+
+ Only records which meet the filter criteria are updated, otherwise
+ all records in the table are updated.
+
+ If \a invalidate is true (the default), the cursor can no longer
+ be navigated. A new select() call must be made before you can move
+ to a valid record.
+
+ \sa primeUpdate() setMode() lastError()
+*/
+
+int Q3SqlCursor::update(const QString & filter, bool invalidate)
+{
+ if ((d->md & Update) != Update) {
+ return false;
+ }
+ int k = count();
+ if (k == 0) {
+ return 0;
+ }
+
+ // use a prepared query if the driver supports it
+ if (driver()->hasFeature(QSqlDriver::PreparedQueries)) {
+ QString fList;
+ bool comma = false;
+ int cnt = 0;
+ bool oraStyle = driver()->hasFeature(QSqlDriver::NamedPlaceholders);
+ for(int j = 0; j < k; ++j) {
+ QSqlField f = d->editBuffer.field(j);
+ if (d->editBuffer.isGenerated(j)) {
+ if (comma) {
+ fList += QLatin1Char(',');
+ }
+ fList += f.name() + QLatin1String(" = ") + (oraStyle == true ? QLatin1String(":f") + QString::number(cnt) : QString(QLatin1Char('?')));
+ cnt++;
+ comma = true;
+ }
+ }
+ if (!comma) {
+ return 0;
+ }
+ QString str(QLatin1String("update ") + name() + QLatin1String(" set ") + fList);
+ if (filter.length()) {
+ str+= QLatin1String(" where ") + filter;
+ }
+ return applyPrepared(str, invalidate);
+ } else {
+ QString str = QLatin1String("update ") + name();
+ str += QLatin1String(" set ") + toString(&d->editBuffer, QString(), QString(QLatin1Char('=')), QString(QLatin1Char(',')));
+ if (filter.length()) {
+ str+= QLatin1String(" where ") + filter;
+ }
+ return apply(str, invalidate);
+ }
+}
+
+/*!
+ Deletes a record from the database using the cursor's primary
+ index and the contents of the cursor edit buffer. Returns the
+ number of records which were deleted.
+ For error information, use lastError().
+
+ Only records which meet the filter criteria specified by the
+ cursor's primary index are deleted. If the cursor does not contain
+ a primary index, no delete is performed and 0 is returned. If \a
+ invalidate is true (the default), the current cursor can no longer
+ be navigated. A new select() call must be made before you can move
+ to a valid record. For example:
+
+ \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 8
+
+ In the above example, a cursor is created on the 'prices' table
+ and positioned to the record to be deleted. First primeDelete() is
+ called to populate the edit buffer with the current cursor values,
+ e.g. with an id of 999, and then del() is called to actually
+ delete the record from the database. Remember: all edit operations
+ (insert(), update() and delete()) operate on the contents of the
+ cursor edit buffer and not on the contents of the cursor itself.
+
+ \sa primeDelete() setMode() lastError()
+*/
+
+int Q3SqlCursor::del(bool invalidate)
+{
+ QSqlIndex idx = primaryIndex(false);
+ if (idx.isEmpty())
+ return del(qWhereClause(&d->editBuffer, d->nm, QLatin1String("and"), driver()), invalidate);
+ return del(toString(primaryIndex(), &d->editBuffer, d->nm, QString(QLatin1Char('=')), QLatin1String("and")), invalidate);
+}
+
+/*!
+ \overload
+
+ Deletes the current cursor record from the database using the
+ filter \a filter. Only records which meet the filter criteria are
+ deleted. Returns the number of records which were deleted. If \a
+ invalidate is true (the default), the current cursor can no longer
+ be navigated. A new select() call must be made before you can move
+ to a valid record. For error information, use lastError().
+
+ The \a filter is an SQL \c WHERE clause, e.g. \c{id=500}.
+
+ \sa setMode() lastError()
+*/
+
+int Q3SqlCursor::del(const QString & filter, bool invalidate)
+{
+ if ((d->md & Delete) != Delete)
+ return 0;
+ int k = count();
+ if(k == 0) return 0;
+ QString str = QLatin1String("delete from ") + name();
+ if (filter.length())
+ str+= QLatin1String(" where ") + filter;
+ return apply(str, invalidate);
+}
+
+/*
+ \internal
+*/
+
+int Q3SqlCursor::apply(const QString& q, bool invalidate)
+{
+ int ar = 0;
+ if (invalidate) {
+ if (exec(q))
+ ar = numRowsAffected();
+ } else if (driver()) {
+ QSqlQuery* sql = d->query();
+ if (sql && sql->exec(q))
+ ar = sql->numRowsAffected();
+ }
+ return ar;
+}
+
+/*
+ \internal
+*/
+
+int Q3SqlCursor::applyPrepared(const QString& q, bool invalidate)
+{
+ int ar = 0;
+ QSqlQuery* sql = 0;
+
+ if (invalidate) {
+ sql = (QSqlQuery*)this;
+ d->lastAt = QSql::BeforeFirst;
+ } else {
+ sql = d->query();
+ }
+ if (!sql)
+ return 0;
+
+ if (invalidate || sql->lastQuery() != q) {
+ if (!sql->prepare(q))
+ return 0;
+ }
+
+ int cnt = 0;
+ int fieldCount = (int)count();
+ for (int j = 0; j < fieldCount; ++j) {
+ const QSqlField f = d->editBuffer.field(j);
+ if (d->editBuffer.isGenerated(j)) {
+ if (f.type() == QVariant::ByteArray)
+ sql->bindValue(cnt, f.value(), QSql::In | QSql::Binary);
+ else
+ sql->bindValue(cnt, f.value());
+ cnt++;
+ }
+ }
+ if (sql->exec()) {
+ ar = sql->numRowsAffected();
+ }
+ return ar;
+}
+
+/*!
+ Executes the SQL query \a sql. Returns true of the cursor is
+ active, otherwise returns false.
+*/
+bool Q3SqlCursor::exec(const QString & sql)
+{
+ d->lastAt = QSql::BeforeFirst;
+ QSqlQuery::exec(sql);
+ return isActive();
+}
+
+/*!
+ Protected virtual function which is called whenever a field needs
+ to be calculated. If calculated fields are being used, derived
+ classes must reimplement this function and return the appropriate
+ value for field \a name. The default implementation returns an
+ invalid QVariant.
+
+ \sa setCalculated()
+*/
+
+QVariant Q3SqlCursor::calculateField(const QString&)
+{
+ return QVariant();
+}
+
+/*! \internal
+ Ensure fieldlist is synced with query.
+
+*/
+
+static QString qTrim(const QString& s)
+{
+ QString result = s;
+ int end = result.length() - 1;
+ while (end >= 0 && result[end].isSpace()) // skip white space from end
+ end--;
+ result.truncate(end + 1);
+ return result;
+}
+
+/*! \internal
+ */
+
+void Q3SqlCursor::sync()
+{
+ if (isActive() && isValid() && d->lastAt != at()) {
+ d->lastAt = at();
+ int i = 0;
+ int j = 0;
+ bool haveCalculatedFields = false;
+ for (; i < count(); ++i) {
+ if (!haveCalculatedFields && d->infoBuffer[i].isCalculated()) {
+ haveCalculatedFields = true;
+ }
+ if (QSqlRecord::isGenerated(i)) {
+ QVariant v = QSqlQuery::value(j);
+ if ((v.type() == QVariant::String) &&
+ d->infoBuffer[i].isTrim()) {
+ v = qTrim(v.toString());
+ }
+ QSqlRecord::setValue(i, v);
+ if (QSqlQuery::isNull(j))
+ QSqlRecord::field(i).clear();
+ j++;
+ }
+ }
+ if (haveCalculatedFields) {
+ for (i = 0; i < count(); ++i) {
+ if (d->infoBuffer[i].isCalculated())
+ QSqlRecord::setValue(i, calculateField(fieldName(i)));
+ }
+ }
+ }
+}
+
+/*!
+ Returns the value of field number \a i.
+*/
+
+QVariant Q3SqlCursor::value(int i) const
+{
+ const_cast<Q3SqlCursor *>(this)->sync();
+ return QSqlRecord::value(i);
+}
+
+/*! \internal
+ cursors should be filled with Q3SqlFieldInfos...
+*/
+void Q3SqlCursor::append(const QSqlField& field)
+{
+ append(Q3SqlFieldInfo(field));
+}
+
+/*!
+ Returns true if the field \a i is NULL or if there is no field at
+ position \a i; otherwise returns false.
+
+ This is the same as calling QSqlRecord::isNull(\a i)
+*/
+bool Q3SqlCursor::isNull(int i) const
+{
+ const_cast<Q3SqlCursor *>(this)->sync();
+ return QSqlRecord::isNull(i);
+}
+/*!
+ \overload
+
+ Returns true if the field called \a name is NULL or if there is no
+ field called \a name; otherwise returns false.
+
+ This is the same as calling QSqlRecord::isNull(\a name)
+*/
+bool Q3SqlCursor::isNull(const QString& name) const
+{
+ const_cast<Q3SqlCursor *>(this)->sync();
+ return QSqlRecord::isNull(name);
+}
+
+/*! \internal */
+void Q3SqlCursor::setValue(int i, const QVariant& val)
+{
+ sync();
+#ifdef QT_DEBUG
+ qDebug("Q3SqlCursor::setValue(): This will not affect actual database values. Use primeInsert(), primeUpdate() or primeDelete().");
+#endif
+ QSqlRecord::setValue(i, val);
+}
+
+/*! \internal */
+bool Q3SqlCursor::seek(int i, bool relative)
+{
+ bool res = QSqlQuery::seek(i, relative);
+ sync();
+ return res;
+}
+
+/*! \internal */
+bool Q3SqlCursor::next()
+{
+ bool res = QSqlQuery::next();
+ sync();
+ return res;
+}
+
+/*!
+ \fn Q3SqlCursor::previous()
+
+ \internal
+*/
+
+/*! \internal */
+bool Q3SqlCursor::prev()
+{
+ bool res = QSqlQuery::previous();
+ sync();
+ return res;
+}
+
+/*! \internal */
+bool Q3SqlCursor::first()
+{
+ bool res = QSqlQuery::first();
+ sync();
+ return res;
+}
+
+/*! \internal */
+bool Q3SqlCursor::last()
+{
+ bool res = QSqlQuery::last();
+ sync();
+ return res;
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qt3support/sql/q3sqlcursor.h b/src/qt3support/sql/q3sqlcursor.h
new file mode 100644
index 0000000..9544fb5
--- /dev/null
+++ b/src/qt3support/sql/q3sqlcursor.h
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3SQLCURSOR_H
+#define Q3SQLCURSOR_H
+
+#include <QtCore/qvariant.h>
+#include <QtSql/qsqldatabase.h>
+#include <QtSql/qsqlrecord.h>
+#include <QtCore/qstringlist.h>
+#include <QtSql/qsqlquery.h>
+#include <QtSql/qsqlindex.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3Support)
+
+#ifndef QT_NO_SQL
+
+class Q3SqlCursorPrivate;
+class Q3SqlFieldInfo;
+
+class Q_COMPAT_EXPORT Q3SqlCursor : public QSqlRecord, public QSqlQuery
+{
+public:
+ Q3SqlCursor(const QString & name = QString(), bool autopopulate = true,
+ QSqlDatabase db = QSqlDatabase());
+ Q3SqlCursor(const Q3SqlCursor & other);
+ Q3SqlCursor& operator=(const Q3SqlCursor& other);
+ virtual ~Q3SqlCursor();
+
+ enum Mode {
+ ReadOnly = 0,
+ Insert = 1,
+ Update = 2,
+ Delete = 4,
+ Writable = 7
+ };
+
+ QVariant value(int i) const;
+ inline QVariant value(const QString &name) const { return value(indexOf(name)); }
+ virtual void setValue(int i, const QVariant &val);
+ inline void setValue(const QString &name, const QVariant &val) { setValue(indexOf(name), val); }
+ virtual QSqlIndex primaryIndex(bool prime = true) const;
+ virtual QSqlIndex index(const QStringList& fieldNames) const;
+ QSqlIndex index(const QString& fieldName) const;
+ virtual void setPrimaryIndex(const QSqlIndex& idx);
+
+ virtual void append(const Q3SqlFieldInfo& fieldInfo);
+ virtual void insert(int pos, const Q3SqlFieldInfo &fieldInfo);
+ virtual void remove(int pos);
+ virtual void clear();
+ virtual void setGenerated(const QString& name, bool generated);
+ virtual void setGenerated(int i, bool generated);
+
+ virtual QSqlRecord* editBuffer(bool copy = false);
+ virtual QSqlRecord* primeInsert();
+ virtual QSqlRecord* primeUpdate();
+ virtual QSqlRecord* primeDelete();
+ virtual int insert(bool invalidate = true);
+ virtual int update(bool invalidate = true);
+ virtual int del(bool invalidate = true);
+
+ virtual void setMode(int flags);
+ int mode() const;
+ virtual void setCalculated(const QString& name, bool calculated);
+ bool isCalculated(const QString& name) const;
+ virtual void setTrimmed(const QString& name, bool trim);
+ bool isTrimmed(const QString& name) const;
+
+ bool isReadOnly() const;
+ bool canInsert() const;
+ bool canUpdate() const;
+ bool canDelete() const;
+
+ bool select();
+ bool select(const QSqlIndex& sort);
+ bool select(const QSqlIndex & filter, const QSqlIndex & sort);
+ virtual bool select(const QString & filter, const QSqlIndex & sort = QSqlIndex());
+
+ virtual void setSort(const QSqlIndex& sort);
+ QSqlIndex sort() const;
+ virtual void setFilter(const QString& filter);
+ QString filter() const;
+ virtual void setName(const QString& name, bool autopopulate = true);
+ QString name() const;
+ QString toString(const QString& prefix = QString(),
+ const QString& sep = QLatin1String(",")) const;
+ bool isNull(int i) const;
+ bool isNull(const QString& name) const;
+ virtual bool seek(int i, bool relative = false);
+ virtual bool next();
+ inline bool previous() { return prev(); }
+ virtual bool prev();
+ virtual bool first();
+ virtual bool last();
+
+protected:
+ virtual bool exec(const QString & sql);
+
+ virtual QVariant calculateField(const QString& name);
+ virtual int update(const QString & filter, bool invalidate = true);
+ virtual int del(const QString & filter, bool invalidate = true);
+
+ virtual QString toString(const QString& prefix, QSqlField* field, const QString& fieldSep) const;
+ virtual QString toString(QSqlRecord* rec, const QString& prefix, const QString& fieldSep,
+ const QString& sep) const;
+ virtual QString toString(const QSqlIndex& i, QSqlRecord* rec, const QString& prefix,
+ const QString& fieldSep, const QString& sep) const;
+
+private:
+ void sync();
+ int apply(const QString& q, bool invalidate);
+ int applyPrepared(const QString& q, bool invalidate);
+ QSqlRecord& operator=(const QSqlRecord & list);
+ void append(const QSqlField& field);
+
+ Q3SqlCursorPrivate* d;
+};
+
+#endif // QT_NO_SQL
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3SQLCURSOR_H
diff --git a/src/qt3support/sql/q3sqleditorfactory.cpp b/src/qt3support/sql/q3sqleditorfactory.cpp
new file mode 100644
index 0000000..5d71ad7
--- /dev/null
+++ b/src/qt3support/sql/q3sqleditorfactory.cpp
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3sqleditorfactory.h"
+
+#ifndef QT_NO_SQL_EDIT_WIDGETS
+
+#include "qsqlfield.h"
+#include "q3cleanuphandler.h"
+#include "qlabel.h"
+#include "qlineedit.h"
+#include "qspinbox.h"
+#include "qcombobox.h"
+#include "qdatetimeedit.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class Q3SqlEditorFactory
+ \brief The Q3SqlEditorFactory class is used to create the editors
+ used by Q3DataTable and Q3SqlForm.
+
+ \compat
+
+ Q3SqlEditorFactory is used by Q3DataTable and Q3SqlForm to
+ automatically create appropriate editors for a given QSqlField.
+ For example if the field is a QVariant::String a QLineEdit would
+ be the default editor, whereas a QVariant::Int's default editor
+ would be a QSpinBox.
+
+ If you want to create different editors for fields with the same
+ data type, subclass Q3SqlEditorFactory and reimplement the
+ createEditor() function.
+
+ \sa Q3DataTable, Q3SqlForm
+*/
+
+
+/*!
+ Constructs a SQL editor factory with parent \a parent.
+*/
+
+Q3SqlEditorFactory::Q3SqlEditorFactory (QObject * parent)
+ : Q3EditorFactory(parent)
+{
+
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+Q3SqlEditorFactory::~Q3SqlEditorFactory()
+{
+
+}
+
+static Q3SqlEditorFactory * defaultfactory = 0;
+static Q3CleanupHandler< Q3SqlEditorFactory > qsql_cleanup_editor_factory;
+
+/*!
+ Returns an instance of a default editor factory.
+*/
+
+Q3SqlEditorFactory * Q3SqlEditorFactory::defaultFactory()
+{
+ if(defaultfactory == 0){
+ defaultfactory = new Q3SqlEditorFactory();
+ qsql_cleanup_editor_factory.add(&defaultfactory);
+ }
+
+ return defaultfactory;
+}
+
+/*!
+ Replaces the default editor factory with \a factory. All
+ Q3DataTable and Q3SqlForm instantiations will use this new factory
+ for creating field editors. \e{Q3SqlEditorFactory takes ownership
+ of \a factory, and destroys it when it is no longer needed.}
+*/
+
+void Q3SqlEditorFactory::installDefaultFactory(Q3SqlEditorFactory * factory)
+{
+ if(factory == 0) return;
+
+ if(defaultfactory != 0){
+ qsql_cleanup_editor_factory.remove(&defaultfactory);
+ delete defaultfactory;
+ }
+ defaultfactory = factory;
+ qsql_cleanup_editor_factory.add(&defaultfactory);
+}
+
+/*!
+ Creates and returns the appropriate editor widget for the QVariant
+ \a variant.
+
+ The widget that is returned has the parent \a parent (which may be
+ zero). If \a variant is invalid, 0 is returned.
+*/
+
+QWidget * Q3SqlEditorFactory::createEditor(QWidget * parent,
+ const QVariant & variant)
+{
+ return Q3EditorFactory::createEditor(parent, variant);
+}
+
+/*!
+ \overload
+
+ Creates and returns the appropriate editor for the QSqlField \a
+ field.
+*/
+
+QWidget * Q3SqlEditorFactory::createEditor(QWidget * parent,
+ const QSqlField * field)
+{
+ if (!field) {
+ return 0;
+ }
+
+ QWidget * w = 0;
+ switch(field->type()){
+ case QVariant::Invalid:
+ w = 0;
+ break;
+ case QVariant::Bool:
+ w = new QComboBox(parent, "qt_editor_bool");
+ ((QComboBox *) w)->insertItem(QLatin1String("False"));
+ ((QComboBox *) w)->insertItem(QLatin1String("True"));
+ break;
+ case QVariant::UInt:
+ w = new QSpinBox(0, 2147483647, 1, parent, "qt_editor_spinbox");
+ break;
+ case QVariant::Int:
+ w = new QSpinBox(-2147483647, 2147483647, 1, parent, "qt_editor_int");
+ break;
+ case QVariant::LongLong:
+ case QVariant::ULongLong:
+ case QVariant::String:
+ case QVariant::Double:
+ w = new QLineEdit(parent, "qt_editor_double");
+ ((QLineEdit*)w)->setFrame(false);
+ break;
+ case QVariant::Date: {
+ QDateTimeEdit *edit = new QDateTimeEdit(parent);
+ edit->setDisplayFormat(QLatin1String("yyyy/MM/dd"));
+ edit->setObjectName(QLatin1String("qt_editor_date"));
+ w = edit; }
+ break;
+ case QVariant::Time: {
+ QDateTimeEdit *edit = new QDateTimeEdit(parent);
+ edit->setDisplayFormat(QLatin1String("hh:mm"));
+ edit->setObjectName(QLatin1String("qt_editor_time"));
+ w = edit; }
+ break;
+ case QVariant::DateTime:
+ w = new QDateTimeEdit(parent);
+ w->setObjectName(QLatin1String("qt_editor_datetime"));
+ break;
+#ifndef QT_NO_LABEL
+ case QVariant::Pixmap:
+ w = new QLabel(parent, "qt_editor_pixmap");
+ break;
+#endif
+ case QVariant::Palette:
+ case QVariant::Color:
+ case QVariant::Font:
+ case QVariant::Brush:
+ case QVariant::Bitmap:
+ case QVariant::Cursor:
+ case QVariant::Map:
+ case QVariant::StringList:
+ case QVariant::Rect:
+ case QVariant::Size:
+ case QVariant::IconSet:
+ case QVariant::Point:
+ case QVariant::PointArray:
+ case QVariant::Region:
+ case QVariant::SizePolicy:
+ case QVariant::ByteArray:
+ default:
+ w = new QWidget(parent, "qt_editor_default");
+ break;
+ }
+ return w;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SQL
diff --git a/src/qt3support/sql/q3sqleditorfactory.h b/src/qt3support/sql/q3sqleditorfactory.h
new file mode 100644
index 0000000..803d0eb
--- /dev/null
+++ b/src/qt3support/sql/q3sqleditorfactory.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3SQLEDITORFACTORY_H
+#define Q3SQLEDITORFACTORY_H
+
+#include <Qt3Support/q3editorfactory.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3Support)
+
+#ifndef QT_NO_SQL_EDIT_WIDGETS
+
+class QSqlField;
+
+class Q_COMPAT_EXPORT Q3SqlEditorFactory : public Q3EditorFactory
+{
+public:
+ Q3SqlEditorFactory (QObject * parent = 0);
+ ~Q3SqlEditorFactory();
+ virtual QWidget * createEditor(QWidget * parent, const QVariant & variant);
+ virtual QWidget * createEditor(QWidget * parent, const QSqlField * field);
+
+ static Q3SqlEditorFactory * defaultFactory();
+ static void installDefaultFactory(Q3SqlEditorFactory * factory);
+
+private:
+ Q_DISABLE_COPY(Q3SqlEditorFactory)
+};
+
+#endif // QT_NO_SQL_EDIT_WIDGETS
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3SQLEDITORFACTORY_H
diff --git a/src/qt3support/sql/q3sqlfieldinfo.h b/src/qt3support/sql/q3sqlfieldinfo.h
new file mode 100644
index 0000000..e2b4db3
--- /dev/null
+++ b/src/qt3support/sql/q3sqlfieldinfo.h
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3SQLFIELDINFO_H
+#define Q3SQLFIELDINFO_H
+
+#ifndef QT_NO_SQL
+
+#include <QtCore/qglobal.h>
+#include <QtSql/qsqlfield.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3Support)
+
+/* Q3SqlFieldInfo Class
+ obsoleted, use QSqlField instead
+*/
+
+class Q_COMPAT_EXPORT Q3SqlFieldInfo
+{
+ // class is obsoleted, won't change anyways,
+ // so no d pointer
+ int req, len, prec, tID;
+ uint gen: 1;
+ uint trim: 1;
+ uint calc: 1;
+ QString nm;
+ QVariant::Type typ;
+ QVariant defValue;
+
+public:
+ Q3SqlFieldInfo(const QString& name = QString(),
+ QVariant::Type typ = QVariant::Invalid,
+ int required = -1,
+ int len = -1,
+ int prec = -1,
+ const QVariant& defValue = QVariant(),
+ int sqlType = 0,
+ bool generated = true,
+ bool trim = false,
+ bool calculated = false) :
+ req(required), len(len), prec(prec), tID(sqlType),
+ gen(generated), trim(trim), calc(calculated),
+ nm(name), typ(typ), defValue(defValue) {}
+
+ virtual ~Q3SqlFieldInfo() {}
+
+ Q3SqlFieldInfo(const QSqlField & other)
+ {
+ nm = other.name();
+ typ = other.type();
+ switch (other.requiredStatus()) {
+ case QSqlField::Unknown: req = -1; break;
+ case QSqlField::Required: req = 1; break;
+ case QSqlField::Optional: req = 0; break;
+ }
+ len = other.length();
+ prec = other.precision();
+ defValue = other.defaultValue();
+ tID = other.typeID();
+ gen = other.isGenerated();
+ calc = false;
+ trim = false;
+ }
+
+ bool operator==(const Q3SqlFieldInfo& f) const
+ {
+ return (nm == f.nm &&
+ typ == f.typ &&
+ req == f.req &&
+ len == f.len &&
+ prec == f.prec &&
+ defValue == f.defValue &&
+ tID == f.tID &&
+ gen == f.gen &&
+ trim == f.trim &&
+ calc == f.calc);
+ }
+
+ QSqlField toField() const
+ { QSqlField f(nm, typ);
+ f.setRequiredStatus(QSqlField::RequiredStatus(req));
+ f.setLength(len);
+ f.setPrecision(prec);
+ f.setDefaultValue(defValue);
+ f.setSqlType(tID);
+ f.setGenerated(gen);
+ return f;
+ }
+ int isRequired() const
+ { return req; }
+ QVariant::Type type() const
+ { return typ; }
+ int length() const
+ { return len; }
+ int precision() const
+ { return prec; }
+ QVariant defaultValue() const
+ { return defValue; }
+ QString name() const
+ { return nm; }
+ int typeID() const
+ { return tID; }
+ bool isGenerated() const
+ { return gen; }
+ bool isTrim() const
+ { return trim; }
+ bool isCalculated() const
+ { return calc; }
+
+ virtual void setTrim(bool trim)
+ { this->trim = trim; }
+ virtual void setGenerated(bool generated)
+ { gen = generated; }
+ virtual void setCalculated(bool calculated)
+ { calc = calculated; }
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_SQL
+
+#endif // Q3SQLFIELDINFO_H
diff --git a/src/qt3support/sql/q3sqlform.cpp b/src/qt3support/sql/q3sqlform.cpp
new file mode 100644
index 0000000..f02e85e
--- /dev/null
+++ b/src/qt3support/sql/q3sqlform.cpp
@@ -0,0 +1,378 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3sqlform.h"
+
+#ifndef QT_NO_SQL_FORM
+
+#include "qsqlfield.h"
+#include "q3sqlpropertymap.h"
+#include "qsqlrecord.h"
+#include "qstringlist.h"
+#include "qwidget.h"
+#include "qhash.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q3SqlFormPrivate
+{
+public:
+ Q3SqlFormPrivate() : propertyMap(0), buf(0), dirty(false) {}
+ ~Q3SqlFormPrivate() { if (propertyMap) delete propertyMap; }
+ QStringList fld;
+ QHash <QString, QWidget*> wgt;
+ QMap <QWidget*, QSqlField *> map;
+ Q3SqlPropertyMap * propertyMap;
+ QSqlRecord* buf;
+ bool dirty;
+};
+
+/*!
+ \class Q3SqlForm
+ \brief The Q3SqlForm class creates and manages data entry forms
+ tied to SQL databases.
+
+ \compat
+
+ Typical use of a Q3SqlForm consists of the following steps:
+ \list
+ \i Create the widgets you want to appear in the form.
+ \i Create a cursor and navigate to the record to be edited.
+ \i Create the Q3SqlForm.
+ \i Set the form's record buffer to the cursor's update buffer.
+ \i Insert each widget and the field it is to edit into the form.
+ \i Use readFields() to update the editor widgets with values from
+ the database's fields.
+ \i Display the form and let the user edit values etc.
+ \i Use writeFields() to update the database's field values with
+ the values in the editor widgets.
+ \endlist
+
+ Note that a Q3SqlForm does not access the database directly, but
+ most often via QSqlFields which are part of a Q3SqlCursor. A
+ Q3SqlCursor::insert(), Q3SqlCursor::update() or Q3SqlCursor::del()
+ call is needed to actually write values to the database.
+
+ Some sample code to initialize a form successfully:
+
+ \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlform.cpp 0
+
+ If you want to use custom editors for displaying and editing data
+ fields, you must install a custom Q3SqlPropertyMap. The form
+ uses this object to get or set the value of a widget.
+
+ \sa installPropertyMap(), Q3SqlPropertyMap
+*/
+
+
+/*!
+ Constructs a Q3SqlForm with parent \a parent.
+*/
+Q3SqlForm::Q3SqlForm(QObject * parent)
+ : QObject(parent)
+{
+ d = new Q3SqlFormPrivate();
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+Q3SqlForm::~Q3SqlForm()
+{
+ delete d;
+}
+
+/*!
+ Installs a custom Q3SqlPropertyMap. This is useful if you plan to
+ create your own custom editor widgets.
+
+ Q3SqlForm takes ownership of \a pmap, so \a pmap is deleted when
+ Q3SqlForm goes out of scope.
+
+ \sa Q3DataTable::installEditorFactory()
+*/
+void Q3SqlForm::installPropertyMap(Q3SqlPropertyMap * pmap)
+{
+ if(d->propertyMap)
+ delete d->propertyMap;
+ d->propertyMap = pmap;
+}
+
+/*!
+ Sets \a buf as the record buffer for the form. To force the
+ display of the data from \a buf, use readFields().
+
+ \sa readFields() writeFields()
+*/
+
+void Q3SqlForm::setRecord(QSqlRecord* buf)
+{
+ d->dirty = true;
+ d->buf = buf;
+}
+
+/*!
+ Inserts a \a widget, and the name of the \a field it is to be
+ mapped to, into the form. To actually associate inserted widgets
+ with an edit buffer, use setRecord().
+
+ \sa setRecord()
+*/
+
+void Q3SqlForm::insert(QWidget * widget, const QString& field)
+{
+ d->dirty = true;
+ d->wgt.insert(field, widget);
+ d->fld += field;
+}
+
+/*!
+ \overload
+
+ Removes \a field from the form.
+*/
+
+void Q3SqlForm::remove(const QString& field)
+{
+ d->dirty = true;
+ int i = d->fld.indexOf(field);
+ if (i >= 0)
+ d->fld.removeAt(i);
+ d->wgt.remove(field);
+}
+
+/*!
+ \overload
+
+ Inserts a \a widget, and the \a field it is to be mapped to, into
+ the form.
+*/
+
+void Q3SqlForm::insert(QWidget * widget, QSqlField * field)
+{
+ d->map[widget] = field;
+}
+
+/*!
+ Removes a \a widget, and hence the field it's mapped to, from the
+ form.
+*/
+
+void Q3SqlForm::remove(QWidget * widget)
+{
+ d->map.remove(widget);
+}
+
+/*!
+ Clears the values in all the widgets, and the fields they are
+ mapped to, in the form, and sets them to NULL.
+*/
+void Q3SqlForm::clearValues()
+{
+ QMap< QWidget *, QSqlField * >::Iterator it;
+ for(it = d->map.begin(); it != d->map.end(); ++it){
+ QSqlField* f = (*it);
+ if (f)
+ f->clear();
+ }
+ readFields();
+}
+
+/*!
+ Removes every widget, and the fields they're mapped to, from the form.
+*/
+void Q3SqlForm::clear()
+{
+ d->dirty = true;
+ d->fld.clear();
+ clearMap();
+}
+
+/*!
+ Returns the number of widgets in the form.
+*/
+int Q3SqlForm::count() const
+{
+ return d->map.size();
+}
+
+/*!
+ Returns the \a{i}-th widget in the form. Useful for traversing
+ the widgets in the form.
+*/
+QWidget * Q3SqlForm::widget(int i) const
+{
+ QMap< QWidget *, QSqlField * >::ConstIterator it;
+ int cnt = 0;
+
+ if(i > d->map.size())
+ return 0;
+ for(it = d->map.constBegin(); it != d->map.constEnd(); ++it){
+ if(cnt++ == i)
+ return it.key();
+ }
+ return 0;
+}
+
+/*!
+ Returns the widget that field \a field is mapped to.
+*/
+QWidget * Q3SqlForm::fieldToWidget(QSqlField * field) const
+{
+ QMap< QWidget *, QSqlField * >::ConstIterator it;
+ for(it = d->map.constBegin(); it != d->map.constEnd(); ++it){
+ if(*it == field)
+ return it.key();
+ }
+ return 0;
+}
+
+/*!
+ Returns the SQL field that widget \a widget is mapped to.
+*/
+QSqlField * Q3SqlForm::widgetToField(QWidget * widget) const
+{
+ return d->map.value(widget, 0);
+}
+
+/*!
+ Updates the widgets in the form with current values from the SQL
+ fields they are mapped to.
+*/
+void Q3SqlForm::readFields()
+{
+ sync();
+ QSqlField * f;
+ QMap< QWidget *, QSqlField * >::Iterator it;
+ Q3SqlPropertyMap * pmap = (d->propertyMap == 0) ?
+ Q3SqlPropertyMap::defaultMap() : d->propertyMap;
+ for(it = d->map.begin() ; it != d->map.end(); ++it){
+ f = widgetToField(it.key());
+ if(!f)
+ continue;
+ pmap->setProperty(it.key(), f->value());
+ }
+}
+
+/*!
+ Updates the SQL fields with values from the widgets they are
+ mapped to. To actually update the database with the contents of
+ the record buffer, use Q3SqlCursor::insert(), Q3SqlCursor::update()
+ or Q3SqlCursor::del() as appropriate.
+*/
+void Q3SqlForm::writeFields()
+{
+ sync();
+ QSqlField * f;
+ QMap< QWidget *, QSqlField * >::Iterator it;
+ Q3SqlPropertyMap * pmap = (d->propertyMap == 0) ?
+ Q3SqlPropertyMap::defaultMap() : d->propertyMap;
+
+ for(it = d->map.begin() ; it != d->map.end(); ++it){
+ f = widgetToField(it.key());
+ if(!f)
+ continue;
+ f->setValue(pmap->property(it.key()));
+ }
+}
+
+/*!
+ Updates the widget \a widget with the value from the SQL field it
+ is mapped to. Nothing happens if no SQL field is mapped to the \a
+ widget.
+*/
+void Q3SqlForm::readField(QWidget * widget)
+{
+ sync();
+ QSqlField * field = 0;
+ Q3SqlPropertyMap * pmap = (d->propertyMap == 0) ?
+ Q3SqlPropertyMap::defaultMap() : d->propertyMap;
+ field = widgetToField(widget);
+ if(field)
+ pmap->setProperty(widget, field->value());
+}
+
+/*!
+ Updates the SQL field with the value from the \a widget it is
+ mapped to. Nothing happens if no SQL field is mapped to the \a
+ widget.
+*/
+void Q3SqlForm::writeField(QWidget * widget)
+{
+ sync();
+ QSqlField * field = 0;
+ Q3SqlPropertyMap * pmap = (d->propertyMap == 0) ?
+ Q3SqlPropertyMap::defaultMap() : d->propertyMap;
+ field = widgetToField(widget);
+ if(field)
+ field->setValue(pmap->property(widget));
+}
+
+/*! \internal
+*/
+
+void Q3SqlForm::sync()
+{
+ if (d->dirty) {
+ clearMap();
+ if (d->buf) {
+ for (int i = 0; i < d->fld.count(); ++i) {
+ const QSqlField *field = d->buf->fieldPtr(d->fld.at(i));
+ insert(d->wgt.value(d->fld.at(i)), const_cast<QSqlField *>(field));
+ }
+ }
+ }
+ d->dirty = false;
+}
+
+/*! \internal
+
+ Clears the internal map of widget/field associations
+*/
+
+void Q3SqlForm::clearMap()
+{
+ d->map.clear();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SQL
diff --git a/src/qt3support/sql/q3sqlform.h b/src/qt3support/sql/q3sqlform.h
new file mode 100644
index 0000000..b6b76b7
--- /dev/null
+++ b/src/qt3support/sql/q3sqlform.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3SQLFORM_H
+#define Q3SQLFORM_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qmap.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3Support)
+
+#ifndef QT_NO_SQL_FORM
+
+class QSqlField;
+class QSqlRecord;
+class Q3SqlEditorFactory;
+class Q3SqlPropertyMap;
+class QWidget;
+class Q3SqlFormPrivate;
+
+class Q_COMPAT_EXPORT Q3SqlForm : public QObject
+{
+ Q_OBJECT
+public:
+ Q3SqlForm(QObject * parent = 0);
+ ~Q3SqlForm();
+
+ virtual void insert(QWidget * widget, const QString& field);
+ virtual void remove(const QString& field);
+ int count() const;
+
+ QWidget * widget(int i) const;
+ QSqlField * widgetToField(QWidget * widget) const;
+ QWidget * fieldToWidget(QSqlField * field) const;
+
+ void installPropertyMap(Q3SqlPropertyMap * map);
+
+ virtual void setRecord(QSqlRecord* buf);
+
+public Q_SLOTS:
+ virtual void readField(QWidget * widget);
+ virtual void writeField(QWidget * widget);
+ virtual void readFields();
+ virtual void writeFields();
+
+ virtual void clear();
+ virtual void clearValues();
+
+protected:
+ virtual void insert(QWidget * widget, QSqlField * field);
+ virtual void remove(QWidget * widget);
+ void clearMap();
+
+private:
+ Q_DISABLE_COPY(Q3SqlForm)
+
+ virtual void sync();
+ Q3SqlFormPrivate* d;
+};
+
+#endif // QT_NO_SQL_FORM
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3SQLFORM_H
diff --git a/src/qt3support/sql/q3sqlmanager_p.cpp b/src/qt3support/sql/q3sqlmanager_p.cpp
new file mode 100644
index 0000000..146be96
--- /dev/null
+++ b/src/qt3support/sql/q3sqlmanager_p.cpp
@@ -0,0 +1,961 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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"
+
+QT_BEGIN_NAMESPACE
+
+//#define QT_DEBUG_DATAMANAGER
+
+class 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
+ \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_DATAMANAGER
+static 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's
+edit buffer. Only the field names specified by \a idx are used to
+determine 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 desired
+values for the record being sought. This function is typically used
+to relocate a cursor to the correct position after an insert or
+update. For example:
+
+\snippet doc/src/snippets/code/src_qt3support_sql_q3sqlmanager_p.cpp 0
+
+*/
+
+//## possibly add sizeHint parameter
+bool 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;
+ }
+#ifndef QT_NO_CURSOR
+ QApplication::restoreOverrideCursor();
+#endif
+ }
+#ifdef QT_DEBUG_DATAMANAGER
+ qDebug(" Done, result:" + QString::number(indexEquals));
+#endif
+ return indexEquals;
+}
+
+#ifndef QT_NO_SQL_FORM
+
+class Q3SqlFormManagerPrivate
+{
+public:
+ Q3SqlFormManagerPrivate() : frm(0), rcd(0) {}
+ Q3SqlForm* frm;
+ QSqlRecord* rcd;
+};
+
+
+/*! \internal
+
+ Creates a form manager.
+
+*/
+
+Q3SqlFormManager::Q3SqlFormManager()
+{
+ d = new Q3SqlFormManagerPrivate();
+}
+
+/*! \internal
+
+ Destroys the object and frees any allocated resources.
+
+*/
+
+Q3SqlFormManager::~Q3SqlFormManager()
+{
+ delete d;
+}
+
+/*! \internal
+
+ Clears the default form values. If there is no default form,
+ nothing happens,
+
+*/
+
+void Q3SqlFormManager::clearValues()
+{
+ if (form())
+ form()->clearValues();
+}
+
+/*! \internal
+
+ Sets the form used by the form manager to \a form. If a record has
+ already been assigned to the form manager, that record is also used by
+ the \a form to display data.
+
+ \sa form()
+
+*/
+
+void Q3SqlFormManager::setForm(Q3SqlForm* form)
+{
+ d->frm = form;
+ if (d->rcd && d->frm)
+ d->frm->setRecord(d->rcd);
+}
+
+
+/*! \internal
+
+ Returns the default form used by the form manager, or 0 if there is
+ none.
+
+ \sa setForm()
+
+*/
+
+Q3SqlForm* Q3SqlFormManager::form()
+{
+ return d->frm;
+}
+
+
+/*! \internal
+
+ Sets the record used by the form manager to \a record. If a form has
+ already been assigned to the form manager, \a record is also used by
+ the default form to display data.
+
+ \sa record()
+
+*/
+
+void Q3SqlFormManager::setRecord(QSqlRecord* record)
+{
+ d->rcd = record;
+ if (d->frm) {
+ d->frm->setRecord(d->rcd);
+ }
+}
+
+
+/*! \internal
+
+ Returns the default record used by the form manager, or 0 if there is
+ none.
+
+ \sa setRecord()
+*/
+
+QSqlRecord* Q3SqlFormManager::record()
+{
+ return d->rcd;
+}
+
+
+/*! \internal
+
+ Causes the default form to read its fields . If there is no
+ default form, nothing happens.
+
+ \sa setForm()
+
+*/
+
+void Q3SqlFormManager::readFields()
+{
+ if (d->frm) {
+ d->frm->readFields();
+ }
+}
+
+/*! \internal
+
+ Causes the default form to write its fields . If there is no
+ default form, nothing happens.
+
+ \sa setForm()
+
+*/
+
+void Q3SqlFormManager::writeFields()
+{
+ if (d->frm) {
+ d->frm->writeFields();
+ }
+}
+
+#endif // QT_NO_SQL_FORM
+
+class Q3DataManagerPrivate
+{
+public:
+ Q3DataManagerPrivate()
+ : mode(QSql::None), autoEd(true), confEdits(3),
+ confCancs(false) {}
+ QSql::Op mode;
+ bool autoEd;
+ QBitArray confEdits;
+ bool confCancs;
+
+};
+
+/*!
+ \class Q3DataManager
+
+ \brief The Q3DataManager class is an internal class for implementing
+ the data-aware widgets.
+
+ \internal
+ \compat
+
+ Q3DataManager is a strictly internal class that acts as a base class
+ for other data-aware widgets.
+
+*/
+
+
+/*! \internal
+
+ Constructs an empty data handler.
+
+*/
+
+Q3DataManager::Q3DataManager()
+{
+ d = new Q3DataManagerPrivate();
+}
+
+
+/*! \internal
+
+ Destroys the object and frees any allocated resources.
+
+*/
+
+Q3DataManager::~Q3DataManager()
+{
+ delete d;
+}
+
+
+/*! \internal
+
+ Virtual function which is called when an error has occurred The
+ default implementation displays a warning message to the user with
+ information about the error.
+
+*/
+void Q3DataManager::handleError(QWidget* parent, const QSqlError& e)
+{
+#ifndef QT_NO_MESSAGEBOX
+ if (e.driverText().isEmpty() && e.databaseText().isEmpty()) {
+ QMessageBox::warning (parent, QLatin1String("Warning"), QLatin1String("An error occurred while accessing the database"));
+ } else {
+ QMessageBox::warning (parent, QLatin1String("Warning"), e.driverText() + QLatin1Char('\n') + e.databaseText(),
+ 0, 0);
+ }
+#endif // QT_NO_MESSAGEBOX
+}
+
+
+/*! \internal
+
+ Sets the internal mode to \a m.
+
+*/
+
+void Q3DataManager::setMode(QSql::Op m)
+{
+ d->mode = m;
+}
+
+
+/*! \internal
+
+ Returns the current mode.
+
+*/
+
+QSql::Op Q3DataManager::mode() const
+{
+ return d->mode;
+}
+
+
+/*! \internal
+
+ Sets the auto-edit mode to \a auto.
+
+*/
+
+void Q3DataManager::setAutoEdit(bool autoEdit)
+{
+ d->autoEd = autoEdit;
+}
+
+
+
+/*! \internal
+
+ Returns true if auto-edit mode is enabled; otherwise returns false.
+
+*/
+
+bool Q3DataManager::autoEdit() const
+{
+ return d->autoEd;
+}
+
+/*! \internal
+
+ If \a confirm is true, all edit operations (inserts, updates and
+ deletes) will be confirmed by the user. If \a confirm is false (the
+ default), all edits are posted to the database immediately.
+
+*/
+void Q3DataManager::setConfirmEdits(bool confirm)
+{
+ d->confEdits = QBitArray(d->confEdits.size(), confirm);
+}
+
+/*! \internal
+
+ If \a confirm is true, all inserts will be confirmed by the user.
+ If \a confirm is false (the default), all edits are posted to the
+ database immediately.
+
+*/
+
+void Q3DataManager::setConfirmInsert(bool confirm)
+{
+ d->confEdits[QSql::Insert] = confirm;
+}
+
+/*! \internal
+
+ If \a confirm is true, all updates will be confirmed by the user.
+ If \a confirm is false (the default), all edits are posted to the
+ database immediately.
+
+*/
+
+void Q3DataManager::setConfirmUpdate(bool confirm)
+{
+ d->confEdits[QSql::Update] = confirm;
+}
+
+/*! \internal
+
+ If \a confirm is true, all deletes will be confirmed by the user.
+ If \a confirm is false (the default), all edits are posted to the
+ database immediately.
+
+*/
+
+void Q3DataManager::setConfirmDelete(bool confirm)
+{
+ d->confEdits[QSql::Delete] = confirm;
+}
+
+/*! \internal
+
+ Returns true if the table confirms all edit operations (inserts,
+ updates and deletes), otherwise returns false.
+*/
+
+bool Q3DataManager::confirmEdits() const
+{
+ return (confirmInsert() && confirmUpdate() && confirmDelete());
+}
+
+/*! \internal
+
+ Returns true if the table confirms inserts, otherwise returns
+ false.
+*/
+
+bool Q3DataManager::confirmInsert() const
+{
+ return d->confEdits[QSql::Insert];
+}
+
+/*! \internal
+
+ Returns true if the table confirms updates, otherwise returns
+ false.
+*/
+
+bool Q3DataManager::confirmUpdate() const
+{
+ return d->confEdits[QSql::Update];
+}
+
+/*! \internal
+
+ Returns true if the table confirms deletes, otherwise returns
+ false.
+*/
+
+bool Q3DataManager::confirmDelete() const
+{
+ return d->confEdits[QSql::Delete];
+}
+
+/*! \internal
+
+ If \a confirm is true, all cancels will be confirmed by the user
+ through a message box. If \a confirm is false (the default), all
+ cancels occur immediately.
+*/
+
+void Q3DataManager::setConfirmCancels(bool confirm)
+{
+ d->confCancs = confirm;
+}
+
+/*! \internal
+
+ Returns true if the table confirms cancels, otherwise returns false.
+*/
+
+bool Q3DataManager::confirmCancels() const
+{
+ return d->confCancs;
+}
+
+/*! \internal
+
+ Virtual function which returns a confirmation for an edit of mode \a
+ m. Derived classes can reimplement this function and provide their
+ own confirmation dialog. The default implementation uses a message
+ box which prompts the user to confirm the edit action. The dialog
+ is centered over \a parent.
+
+*/
+
+QSql::Confirm Q3DataManager::confirmEdit(QWidget* parent, QSql::Op m)
+{
+ int ans = 2;
+ if (m == QSql::Delete) {
+#ifndef QT_NO_MESSAGEBOX
+ ans = QMessageBox::information(parent,
+ qApp->translate("QSql", "Delete"),
+ qApp->translate("QSql", "Delete this record?"),
+ qApp->translate("QSql", "Yes"),
+ qApp->translate("QSql", "No"),
+ QString(), 0, 1);
+#else
+ ans = QSql::No;
+#endif // QT_NO_MESSAGEBOX
+ } else if (m != QSql::None) {
+ QString caption;
+ if (m == QSql::Insert) {
+ caption = qApp->translate("QSql", "Insert");
+ } else { // QSql::Update
+ caption = qApp->translate("QSql", "Update");
+ }
+#ifndef QT_NO_MESSAGEBOX
+ ans = QMessageBox::information(parent, caption,
+ qApp->translate("QSql", "Save edits?"),
+ qApp->translate("QSql", "Yes"),
+ qApp->translate("QSql", "No"),
+ qApp->translate("QSql", "Cancel"),
+ 0, 2);
+#else
+ ans = QSql::No;
+#endif // QT_NO_MESSAGEBOX
+ }
+
+ switch (ans) {
+ case 0:
+ return QSql::Yes;
+ case 1:
+ return QSql::No;
+ default:
+ return QSql::Cancel;
+ }
+}
+
+/*! \internal
+
+ Virtual function which returns a confirmation for canceling an edit
+ mode \a m. Derived classes can reimplement this function and
+ provide their own confirmation dialog. The default implementation
+ uses a message box which prompts the user to confirm the edit
+ action. The dialog is centered over \a parent.
+
+
+*/
+
+QSql::Confirm Q3DataManager::confirmCancel(QWidget* parent, QSql::Op)
+{
+#ifndef QT_NO_MESSAGEBOX
+ switch (QMessageBox::information(parent,
+ qApp->translate("QSql", "Confirm"),
+ qApp->translate("QSql", "Cancel your edits?"),
+ qApp->translate("QSql", "Yes"),
+ qApp->translate("QSql", "No"),
+ QString(), 0, 1)) {
+ case 0:
+ return QSql::Yes;
+ case 1:
+ return QSql::No;
+ default:
+ return QSql::Cancel;
+ }
+#else
+ return QSql::Yes;
+#endif // QT_NO_MESSAGEBOX
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qt3support/sql/q3sqlmanager_p.h b/src/qt3support/sql/q3sqlmanager_p.h
new file mode 100644
index 0000000..b9ea5c7
--- /dev/null
+++ b/src/qt3support/sql/q3sqlmanager_p.h
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3SQLMANAGER_P_H
+#define Q3SQLMANAGER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtCore/qvariant.h"
+#include "QtCore/qglobal.h"
+#include "QtCore/qstring.h"
+#include "QtCore/qstringlist.h"
+#include "QtSql/qsql.h"
+#include "QtSql/qsqlerror.h"
+#include "QtSql/qsqlindex.h"
+#include "Qt3Support/q3sqlcursor.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_SQL
+
+class Q3SqlCursor;
+class Q3SqlForm;
+class Q3SqlCursorManagerPrivate;
+
+class Q_COMPAT_EXPORT Q3SqlCursorManager
+{
+public:
+ Q3SqlCursorManager();
+ virtual ~Q3SqlCursorManager();
+
+ virtual void setSort(const QSqlIndex& sort);
+ virtual void setSort(const QStringList& sort);
+ QStringList sort() const;
+ virtual void setFilter(const QString& filter);
+ QString filter() const;
+ virtual void setCursor(Q3SqlCursor* cursor, bool autoDelete = false);
+ Q3SqlCursor* cursor() const;
+
+ virtual void setAutoDelete(bool enable);
+ bool autoDelete() const;
+
+ virtual bool refresh();
+ virtual bool findBuffer(const QSqlIndex& idx, int atHint = 0);
+
+private:
+ Q3SqlCursorManagerPrivate* d;
+};
+
+#ifndef QT_NO_SQL_FORM
+
+class Q3SqlFormManagerPrivate;
+
+class Q_COMPAT_EXPORT Q3SqlFormManager
+{
+public:
+ Q3SqlFormManager();
+ virtual ~Q3SqlFormManager();
+
+ virtual void setForm(Q3SqlForm* form);
+ Q3SqlForm* form();
+ virtual void setRecord(QSqlRecord* record);
+ QSqlRecord* record();
+
+ virtual void clearValues();
+ virtual void readFields();
+ virtual void writeFields();
+
+private:
+ Q3SqlFormManagerPrivate* d;
+};
+
+#endif
+
+class QWidget;
+class Q3DataManagerPrivate;
+
+class Q_COMPAT_EXPORT Q3DataManager
+{
+public:
+ Q3DataManager();
+ virtual ~Q3DataManager();
+
+ virtual void setMode(QSql::Op m);
+ QSql::Op mode() const;
+ virtual void setAutoEdit(bool autoEdit);
+ bool autoEdit() const;
+
+ virtual void handleError(QWidget* parent, const QSqlError& error);
+ virtual QSql::Confirm confirmEdit(QWidget* parent, QSql::Op m);
+ virtual QSql::Confirm confirmCancel(QWidget* parent, QSql::Op m);
+
+ virtual void setConfirmEdits(bool confirm);
+ virtual void setConfirmInsert(bool confirm);
+ virtual void setConfirmUpdate(bool confirm);
+ virtual void setConfirmDelete(bool confirm);
+ virtual void setConfirmCancels(bool confirm);
+
+ bool confirmEdits() const;
+ bool confirmInsert() const;
+ bool confirmUpdate() const;
+ bool confirmDelete() const;
+ bool confirmCancels() const;
+
+private:
+ Q3DataManagerPrivate* d;
+};
+
+#endif // QT_NO_SQL
+
+QT_END_NAMESPACE
+
+#endif // Q3SQLMANAGER_P_H
diff --git a/src/qt3support/sql/q3sqlpropertymap.cpp b/src/qt3support/sql/q3sqlpropertymap.cpp
new file mode 100644
index 0000000..6e55af0
--- /dev/null
+++ b/src/qt3support/sql/q3sqlpropertymap.cpp
@@ -0,0 +1,276 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3sqlpropertymap.h"
+
+#ifndef QT_NO_SQL_FORM
+
+#include "qwidget.h"
+#include "q3cleanuphandler.h"
+#include "qmetaobject.h"
+#include "qmap.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q3SqlPropertyMapPrivate
+{
+public:
+ Q3SqlPropertyMapPrivate() {}
+ QMap<QByteArray, QByteArray> propertyMap;
+};
+
+/*!
+ \class Q3SqlPropertyMap
+ \brief The Q3SqlPropertyMap class is used to map widgets to SQL fields.
+
+ \compat
+
+ The SQL module uses Qt \link properties.html object
+ properties\endlink to insert and extract values from editor
+ widgets.
+
+ This class is used to map editors to SQL fields. This works by
+ associating SQL editor class names to the properties used to
+ insert and extract values to/from the editor.
+
+ For example, a QLineEdit can be used to edit text strings and
+ other data types in Q3DataTables or Q3SqlForms. Several properties
+ are defined in QLineEdit, but only the \e text property is used to
+ insert and extract text from a QLineEdit. Both Q3DataTable and
+ Q3SqlForm use the global Q3SqlPropertyMap for inserting and
+ extracting values to and from an editor widget. The global
+ property map defines several common widgets and properties that
+ are suitable for many applications. You can add and remove widget
+ properties to suit your specific needs.
+
+ If you want to use custom editors with your Q3DataTable or
+ Q3SqlForm, you must install your own Q3SqlPropertyMap for that table
+ or form. Example:
+
+ \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlpropertymap.cpp 0
+
+ You can also replace the global Q3SqlPropertyMap that is used by
+ default. (Bear in mind that Q3SqlPropertyMap takes ownership of the
+ new default map.)
+
+ \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlpropertymap.cpp 1
+
+ \sa Q3DataTable, Q3SqlForm, Q3SqlEditorFactory
+*/
+
+/*!
+
+Constructs a Q3SqlPropertyMap.
+
+The default property mappings used by Qt widgets are:
+\table
+\header \i Widgets \i Property
+\row \i \l QCheckBox,
+ \l QRadioButton
+ \i checked
+\row \i \l QComboBox,
+ \l Q3ListBox
+ \i currentItem
+\row \i \l Q3DateEdit
+ \i date
+\row \i \l Q3DateTimeEdit
+ \l QDateTimeEdit
+ \i dateTime
+\row \i \l QTextBrowser
+ \i source
+\row \i \l QAbstractButton,
+ \l QDial,
+ \l QLabel,
+ \l QLineEdit,
+ \l Q3MultiLineEdit,
+ \l QPushButton,
+ \l QTextEdit,
+ \i text
+\row \i \l Q3TimeEdit
+ \i time
+\row \i \l QLCDNumber,
+ \l QScrollBar
+ \l QSlider,
+ \l QSpinBox
+ \i value
+\endtable
+*/
+
+Q3SqlPropertyMap::Q3SqlPropertyMap()
+{
+ d = new Q3SqlPropertyMapPrivate();
+ const struct MapData {
+ const char *classname;
+ const char *property;
+ } mapData[] = {
+ { "Q3DateEdit", "date" },
+ { "Q3DateTimeEdit", "dateTime" },
+ { "Q3ListBox", "currentItem" },
+ { "Q3TimeEdit", "time" },
+ { "QAbstractButton", "text" },
+ { "QCheckBox", "checked" },
+ { "QRadioButton", "checked" },
+ { "QComboBox", "currentIndex" },
+ { "QDateTimeEdit", "dateTime" },
+ { "QDial", "value" },
+ { "QLabel", "text" },
+ { "QLCDNumber", "value" },
+ { "QLineEdit", "text" },
+ { "QPushButton", "text" },
+ { "QScrollBar", "value" },
+ { "QSlider", "value" },
+ { "QSpinBox", "value" },
+ { "QTabBar", "currentTab" },
+ { "QTabWidget", "currentPage" },
+ { "QTextBrowser", "source" },
+ { "QTextEdit", "text" },
+ { "QGroupBox", "checked" }
+ };
+
+ const MapData *m = mapData;
+ for (uint i = 0; i < sizeof(mapData)/sizeof(MapData); i++, m++)
+ d->propertyMap.insert(m->classname, m->property);
+}
+
+/*!
+ Destroys the Q3SqlPropertyMap.
+
+ Note that if the Q3SqlPropertyMap is installed with
+ installPropertyMap() the object it was installed into, e.g. the
+ Q3SqlForm, takes ownership and will delete the Q3SqlPropertyMap when
+ necessary.
+*/
+Q3SqlPropertyMap::~Q3SqlPropertyMap()
+{
+ delete d;
+}
+
+/*!
+ Returns the mapped property of \a widget as a QVariant.
+*/
+QVariant Q3SqlPropertyMap::property(QWidget * widget)
+{
+ if(!widget) return QVariant();
+ const QMetaObject* mo = widget->metaObject();
+ while (mo && !d->propertyMap.contains(mo->className()))
+ mo = mo->superClass();
+
+ if (!mo) {
+ qWarning("Q3SqlPropertyMap::property: %s does not exist", widget->metaObject()->className());
+ return QVariant();
+ }
+ return widget->property(d->propertyMap[mo->className()]);
+}
+
+/*!
+ Sets the property of \a widget to \a value.
+*/
+void Q3SqlPropertyMap::setProperty(QWidget * widget, const QVariant & value)
+{
+ if(!widget) return;
+
+ const QMetaObject* mo = widget->metaObject();
+ while (mo && !d->propertyMap.contains(mo->className()))
+ mo = mo->superClass();
+ if (!mo) {
+ qWarning("Q3SqlPropertyMap::setProperty: %s not handled by Q3SqlPropertyMap", widget->metaObject()->className());
+ return;
+ }
+
+ widget->setProperty(d->propertyMap[mo->className()], value);
+}
+
+/*!
+ Insert a new classname/property pair, which is used for custom SQL
+ field editors. There \e must be a Q_PROPERTY() clause in the \a
+ classname class declaration for the \a property.
+*/
+void Q3SqlPropertyMap::insert(const QString & classname,
+ const QString & property)
+{
+ d->propertyMap[classname.latin1()] = property.latin1();
+}
+
+/*!
+ Removes \a classname from the map.
+*/
+void Q3SqlPropertyMap::remove(const QString & classname)
+{
+ d->propertyMap.remove(classname.latin1());
+}
+
+static Q3SqlPropertyMap * defaultmap = 0;
+static Q3CleanupHandler< Q3SqlPropertyMap > qsql_cleanup_property_map;
+
+/*!
+ Returns the application global Q3SqlPropertyMap.
+*/
+Q3SqlPropertyMap * Q3SqlPropertyMap::defaultMap()
+{
+ if(defaultmap == 0){
+ defaultmap = new Q3SqlPropertyMap();
+ qsql_cleanup_property_map.add(&defaultmap);
+ }
+ return defaultmap;
+}
+
+/*!
+ Replaces the global default property map with \a map. All
+ Q3DataTable and Q3SqlForm instantiations will use this new map for
+ inserting and extracting values to and from editors.
+ \e{Q3SqlPropertyMap takes ownership of \a map, and destroys it
+ when it is no longer needed.}
+*/
+void Q3SqlPropertyMap::installDefaultMap(Q3SqlPropertyMap * map)
+{
+ if(map == 0) return;
+
+ if(defaultmap != 0){
+ qsql_cleanup_property_map.remove(&defaultmap);
+ delete defaultmap;
+ }
+ defaultmap = map;
+ qsql_cleanup_property_map.add(&defaultmap);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SQL_FORM
diff --git a/src/qt3support/sql/q3sqlpropertymap.h b/src/qt3support/sql/q3sqlpropertymap.h
new file mode 100644
index 0000000..88660b4
--- /dev/null
+++ b/src/qt3support/sql/q3sqlpropertymap.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3SQLPROPERTYMAP_H
+#define Q3SQLPROPERTYMAP_H
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3Support)
+
+#ifndef QT_NO_SQL_FORM
+
+class QWidget;
+class Q3SqlPropertyMapPrivate;
+
+class Q_COMPAT_EXPORT Q3SqlPropertyMap
+{
+public:
+ Q3SqlPropertyMap();
+ virtual ~Q3SqlPropertyMap();
+
+ QVariant property(QWidget * widget);
+ virtual void setProperty(QWidget * widget, const QVariant & value);
+
+ void insert(const QString & classname, const QString & property);
+ void remove(const QString & classname);
+
+ static Q3SqlPropertyMap * defaultMap();
+ static void installDefaultMap(Q3SqlPropertyMap * map);
+
+private:
+ Q_DISABLE_COPY(Q3SqlPropertyMap)
+
+ Q3SqlPropertyMapPrivate* d;
+};
+
+#endif // QT_NO_SQL_FORM
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3SQLPROPERTYMAP_H
diff --git a/src/qt3support/sql/q3sqlrecordinfo.h b/src/qt3support/sql/q3sqlrecordinfo.h
new file mode 100644
index 0000000..a81988d
--- /dev/null
+++ b/src/qt3support/sql/q3sqlrecordinfo.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3SQLRECORDINFO_H
+#define Q3SQLRECORDINFO_H
+
+#include <QtCore/qglobal.h>
+
+#ifndef QT_NO_SQL
+# include <Qt3Support/q3valuelist.h>
+# include <QtSql/qsqlrecord.h>
+# include <Qt3Support/q3sqlfieldinfo.h>
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3Support)
+
+#ifndef QT_NO_SQL
+
+/* Q3SqlRecordInfo Class
+ This class is obsolete, use QSqlRecord instead.
+*/
+
+typedef Q3ValueList<Q3SqlFieldInfo> Q3SqlFieldInfoList;
+
+class Q_COMPAT_EXPORT Q3SqlRecordInfo: public Q3SqlFieldInfoList
+{
+public:
+ Q3SqlRecordInfo(): Q3SqlFieldInfoList() {}
+ Q3SqlRecordInfo(const Q3SqlFieldInfoList& other): Q3SqlFieldInfoList(other) {}
+ Q3SqlRecordInfo(const QSqlRecord& other)
+ {
+ for (int i = 0; i < other.count(); ++i)
+ push_back(Q3SqlFieldInfo(other.field(i)));
+ }
+
+ size_type contains(const QString& fieldName) const;
+ Q3SqlFieldInfo find(const QString& fieldName) const;
+ QSqlRecord toRecord() const;
+};
+
+inline Q3SqlRecordInfo::size_type Q3SqlRecordInfo::contains(const QString& fieldName) const
+{
+ size_type i = 0;
+ QString fName = fieldName.toUpper();
+
+ for(const_iterator it = begin(); it != end(); ++it) {
+ if ((*it).name().toUpper() == fName) {
+ ++i;
+ }
+ }
+ return i;
+}
+
+inline Q3SqlFieldInfo Q3SqlRecordInfo::find(const QString& fieldName) const
+{
+ QString fName = fieldName.toUpper();
+ for(const_iterator it = begin(); it != end(); ++it) {
+ if ((*it).name().toUpper() == fName) {
+ return *it;
+ }
+ }
+ return Q3SqlFieldInfo();
+}
+
+inline QSqlRecord Q3SqlRecordInfo::toRecord() const
+{
+ QSqlRecord buf;
+ for(const_iterator it = begin(); it != end(); ++it) {
+ buf.append((*it).toField());
+ }
+ return buf;
+}
+
+#endif // QT_NO_SQL
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3SQLRECORDINFO_H
diff --git a/src/qt3support/sql/q3sqlselectcursor.cpp b/src/qt3support/sql/q3sqlselectcursor.cpp
new file mode 100644
index 0000000..7726f02
--- /dev/null
+++ b/src/qt3support/sql/q3sqlselectcursor.cpp
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3sqlselectcursor.h"
+#include "qsqldriver.h"
+#include "q3sqlrecordinfo.h"
+
+#ifndef QT_NO_SQL
+
+QT_BEGIN_NAMESPACE
+
+class Q3SqlSelectCursorPrivate
+{
+public:
+ Q3SqlSelectCursorPrivate() : populated(false) {}
+ QString query;
+ bool populated : 1;
+};
+
+/*!
+ \class Q3SqlSelectCursor
+ \brief The Q3SqlSelectCursor class provides browsing of general SQL SELECT statements.
+
+ \compat
+
+ Q3SqlSelectCursor is a convenience class that makes it possible to
+ display result sets from general SQL \c SELECT statements in
+ data-aware Qt widgets. Q3SqlSelectCursor is read-only and does not
+ support \c INSERT, \c UPDATE or \c DELETE operations.
+
+ Pass the query in at construction time, or use the
+ Q3SqlSelectCursor::exec() function.
+
+ Example:
+ \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlselectcursor.cpp 0
+*/
+
+/*!
+ Constructs a read only cursor on database \a db using the query \a query.
+ */
+Q3SqlSelectCursor::Q3SqlSelectCursor(const QString& query, QSqlDatabase db)
+ : Q3SqlCursor(QString(), false, db)
+{
+ d = new Q3SqlSelectCursorPrivate;
+ d->query = query;
+ Q3SqlCursor::setMode(ReadOnly);
+ if (!query.isEmpty())
+ exec(query);
+}
+
+/*! Constructs a copy of \a other */
+Q3SqlSelectCursor::Q3SqlSelectCursor(const Q3SqlSelectCursor& other)
+ : Q3SqlCursor(other)
+{
+ d = new Q3SqlSelectCursorPrivate;
+ d->query = other.d->query;
+ d->populated = other.d->populated;
+}
+
+/*! Destroys the object and frees any allocated resources */
+Q3SqlSelectCursor::~Q3SqlSelectCursor()
+{
+ delete d;
+}
+
+/*! \internal */
+bool Q3SqlSelectCursor::exec(const QString& query)
+{
+ d->query = query;
+ bool ret = Q3SqlCursor::exec(query);
+ if (ret) {
+ Q3SqlCursor::clear();
+ populateCursor();
+ }
+ return ret;
+}
+
+/*! \fn bool Q3SqlSelectCursor::select()
+ \internal
+*/
+
+/*! \internal */
+bool Q3SqlSelectCursor::select(const QString&, const QSqlIndex&)
+{
+ bool ret = Q3SqlCursor::exec(d->query);
+ if (ret && !d->populated)
+ populateCursor();
+ return ret;
+}
+
+/*! \internal */
+void Q3SqlSelectCursor::populateCursor()
+{
+ Q3SqlRecordInfo inf = Q3SqlRecordInfo(record());
+ for (Q3SqlRecordInfo::const_iterator it = inf.begin(); it != inf.end(); ++it)
+ Q3SqlCursor::append(*it);
+ d->populated = true;
+}
+
+/*! \fn QSqlIndex Q3SqlSelectCursor::primaryIndex(bool) const
+ \internal
+*/
+
+/*! \fn QSqlIndex Q3SqlSelectCursor::index(const QStringList&) const
+ \internal
+*/
+
+/*! \fn QSqlIndex Q3SqlSelectCursor::index(const QString&) const
+ \internal
+*/
+
+/*! \fn QSqlIndex Q3SqlSelectCursor::index(const char*) const
+ \internal
+*/
+
+/*! \fn void Q3SqlSelectCursor::setPrimaryIndex(const QSqlIndex&)
+ \internal
+*/
+
+/*! \fn void Q3SqlSelectCursor::append(const Q3SqlFieldInfo&)
+ \internal
+*/
+
+/*! \fn void Q3SqlSelectCursor::insert(int, const Q3SqlFieldInfo&)
+ \internal
+*/
+
+/*! \fn void Q3SqlSelectCursor::remove(int)
+ \internal
+*/
+
+/*! \fn void Q3SqlSelectCursor::clear()
+ \internal
+*/
+
+/*! \fn void Q3SqlSelectCursor::setGenerated(const QString&, bool)
+ \internal
+*/
+
+/*! \fn void Q3SqlSelectCursor::setGenerated(int, bool)
+ \internal
+*/
+
+/*! \fn QSqlRecord* Q3SqlSelectCursor::editBuffer(bool)
+ \internal
+*/
+
+/*! \fn QSqlRecord* Q3SqlSelectCursor::primeInsert()
+ \internal
+*/
+
+/*! \fn QSqlRecord* Q3SqlSelectCursor::primeUpdate()
+ \internal
+*/
+
+/*! \fn QSqlRecord* Q3SqlSelectCursor::primeDelete()
+ \internal
+*/
+
+/*! \fn int Q3SqlSelectCursor::insert(bool)
+ \internal
+*/
+
+/*! \fn int Q3SqlSelectCursor::update(bool)
+ \internal
+*/
+
+/*! \fn int Q3SqlSelectCursor::del(bool)
+ \internal
+*/
+
+/*! \fn void Q3SqlSelectCursor::setMode(int)
+ \internal
+*/
+
+/*! \fn void Q3SqlSelectCursor::setSort(const QSqlIndex&)
+ \internal
+*/
+
+/*! \fn QSqlIndex Q3SqlSelectCursor::sort() const
+ \internal
+*/
+
+/*! \fn void Q3SqlSelectCursor::setFilter(const QString&)
+ \internal
+*/
+
+/*! \fn QString Q3SqlSelectCursor::filter() const
+ \internal
+*/
+
+/*! \fn void Q3SqlSelectCursor::setName(const QString&, bool)
+ \internal
+*/
+
+/*! \fn QString Q3SqlSelectCursor::name() const
+ \internal
+*/
+
+/*! \fn QString Q3SqlSelectCursor::toString(const QString&, const QString&) const
+ \internal
+*/
+
+/*!
+ \fn int Q3SqlSelectCursor::update(const QString & filter, bool invalidate = true)
+ \overload
+
+ Updates the database with the current contents of the cursor edit
+ buffer using the specified \a filter. Returns the number of
+ records which were updated.
+ For error information, use lastError().
+
+ Only records which meet the filter criteria are updated, otherwise
+ all records in the table are updated.
+
+ If \a invalidate is true (the default), the cursor can no longer
+ be navigated. A new select() call must be made before you can move
+ to a valid record.
+
+ \sa Q3SqlCursor::update() primeUpdate() setMode() lastError()
+*/
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SQL
diff --git a/src/qt3support/sql/q3sqlselectcursor.h b/src/qt3support/sql/q3sqlselectcursor.h
new file mode 100644
index 0000000..26103ba
--- /dev/null
+++ b/src/qt3support/sql/q3sqlselectcursor.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3SQLSELECTCURSOR_H
+#define Q3SQLSELECTCURSOR_H
+
+#include <Qt3Support/q3sqlcursor.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3Support)
+
+#ifndef QT_NO_SQL
+
+class Q3SqlSelectCursorPrivate;
+
+class Q_COMPAT_EXPORT Q3SqlSelectCursor : public Q3SqlCursor
+{
+public:
+ Q3SqlSelectCursor(const QString& query = QString(), QSqlDatabase db = QSqlDatabase());
+ Q3SqlSelectCursor(const Q3SqlSelectCursor& other);
+ ~Q3SqlSelectCursor();
+ bool exec(const QString& query);
+ bool select() { return Q3SqlCursor::select(); }
+
+protected:
+ QSqlIndex primaryIndex(bool = true) const { return QSqlIndex(); }
+ QSqlIndex index(const QStringList&) const { return QSqlIndex(); }
+ QSqlIndex index(const QString&) const { return QSqlIndex(); }
+ QSqlIndex index(const char*) const { return QSqlIndex(); }
+ void setPrimaryIndex(const QSqlIndex&) {}
+ void append(const Q3SqlFieldInfo&) {}
+ void insert(int, const Q3SqlFieldInfo&) {}
+ void remove(int) {}
+ void clear() {}
+ void setGenerated(const QString&, bool) {}
+ void setGenerated(int, bool) {}
+ QSqlRecord* editBuffer(bool = false) { return 0; }
+ QSqlRecord* primeInsert() { return 0; }
+ QSqlRecord* primeUpdate() { return 0; }
+ QSqlRecord* primeDelete() { return 0; }
+ int insert(bool = true) { return 0; }
+ int update(bool = true) { return 0; }
+ int del(bool = true) { return 0; }
+ void setMode(int) {}
+
+ void setSort(const QSqlIndex&) {}
+ QSqlIndex sort() const { return QSqlIndex(); }
+ void setFilter(const QString&) {}
+ QString filter() const { return QString(); }
+ void setName(const QString&, bool = true) {}
+ QString name() const { return QString(); }
+ QString toString(const QString& = QString(), const QString& = QLatin1String(",")) const { return QString(); }
+ bool select(const QString &, const QSqlIndex& = QSqlIndex());
+
+private:
+ void populateCursor();
+
+ Q3SqlSelectCursorPrivate * d;
+
+protected:
+#if !defined(Q_NO_USING_KEYWORD)
+ using Q3SqlCursor::update;
+#else
+ virtual int update(const QString & filter, bool invalidate = true) { return Q3SqlCursor::update(filter, invalidate); }
+#endif
+};
+
+#endif // QT_NO_SQL
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3SQLSELECTCURSOR_H
diff --git a/src/qt3support/sql/sql.pri b/src/qt3support/sql/sql.pri
new file mode 100644
index 0000000..41fd641
--- /dev/null
+++ b/src/qt3support/sql/sql.pri
@@ -0,0 +1,25 @@
+# Qt compat module
+
+HEADERS += sql/q3sqlfieldinfo.h \
+ sql/q3sqlrecordinfo.h \
+ sql/q3datatable.h \
+ sql/q3dataview.h \
+ sql/q3sqlcursor.h \
+ sql/q3sqlselectcursor.h \
+ sql/q3sqlform.h \
+ sql/q3sqlmanager_p.h \
+ sql/q3editorfactory.h \
+ sql/q3sqleditorfactory.h \
+ sql/q3sqlpropertymap.h \
+ sql/q3databrowser.h \
+
+SOURCES += sql/q3datatable.cpp \
+ sql/q3dataview.cpp \
+ sql/q3sqlcursor.cpp \
+ sql/q3sqlselectcursor.cpp \
+ sql/q3sqlform.cpp \
+ sql/q3sqlmanager_p.cpp \
+ sql/q3editorfactory.cpp \
+ sql/q3sqleditorfactory.cpp \
+ sql/q3sqlpropertymap.cpp \
+ sql/q3databrowser.cpp