summaryrefslogtreecommitdiffstats
path: root/src/qt3support/sql/q3databrowser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qt3support/sql/q3databrowser.cpp')
-rw-r--r--src/qt3support/sql/q3databrowser.cpp1281
1 files changed, 1281 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