/**************************************************************************** | |
** | |
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). | |
** All rights reserved. | |
** Contact: Nokia Corporation (qt-info@nokia.com) | |
** | |
** This file is part of the Qt3Support module of the Qt Toolkit. | |
** | |
** $QT_BEGIN_LICENSE:LGPL$ | |
** GNU Lesser General Public License Usage | |
** 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.1, 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. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $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 |