\chapter Creating Database Applications

\index Databases
\index SQL
This chapter shows you how to use Qt's data-aware widgets from within
\QD. It demonstrates \INS, \UPD and \DEL in both \Class {QDataTable}s
(tables) and \Class {QDataBrowser}s (forms). It also shows how to code
Master-Detail relationships and Drilldown. A simple approach to foreign
key handling is presented here; a more sophisticated approach is shown
in the online SQL module documentation.

\index Databases!Drivers
\index QODBC3, Database driver
\index QOCI8, Database driver
\index QPSQL7, Database driver
\index QMYSQL3, Database driver
\index Databases!Drivers!QODBC3
\index Databases!Drivers!QOCI8
\index Databases!Drivers!QPSQL7
\index Databases!Drivers!QMYSQL3
If you wish to run the examples or create your own applications using
these widgets you need access to an SQL database and a Qt database driver
that can connect to the database. At the time of writing the drivers
that Qt supports are QODBC3 (Open Database Connectivity), QOCI8 (Oracle),
QPSQL7 (PostgreSQL 6 and 7) and QMYSQL3 (MySQL).

\index Widgets!Data Aware
\index Data Aware Widgets
\index Databases!Data Aware Widgets
Although you can use the Qt data-aware widgets to browse and edit data
in SQL databases without having to write any SQL, a basic understanding
of SQL is highly recommended. We assume that you have some familiarity with
\c {SELECT}, \INS, \UPD and \DEL statements. We also assume a basic
understanding of the concepts of normalisation and of primary and
foreign keys. A standard text covering SQL databases is \e {An Introduction to Database Systems (7th ed.)} by C. J.
Date, ISBN 0201385902.

\index In-place Editing
\index Databases!In-place Editing
In the following text we describe the creation of a 'book' database
application. The application demonstrates how to use
\Class {QDataTable}s including in-place record editing and how to set
up master-detail relationships between \Class {QDataTable}s. It also
explains how to drill down from a \Class QDataTable to another
widget, for example, to a \Class QDataBrowser or a \Class QDataView
and how to perform record editing in a \Class QDataBrowser. A great
deal of functionality is available from the classes directly in \QD
although subclassing is always available for finer control. If you
want to build the 'book' examples you will need to create the example
schema on your database.  \img book-main.png
\caption The Book Application

\sidebar The Example Schema

Note that the examples in this chapter all use the tables, views and
records which are defined in the
\File qt/tools/designer/examples/book/book.sql file. This file has
been tested with PostgreSQL 6 and PostgreSQL 7. You may need to modify
the SQL in this file to recreate the example database on your own
system.

Schema \c {CREATE TABLE} Statements

\quotefile book/book.sql
\skipto CREATE TABLE author
\printuntil ;

\skipto CREATE TABLE book
\printuntil ;

\skipto CREATE TABLE sequence
\printuntil ;

The 'book' table is simplified for the purposes of the example. It can
only relate a book to a single author (authorid) and lacks an ISBN
field.  The 'sequence' table is used for generating unique index
values for the example tables.  Note that SQL databases often provide
their own method for creating sequences (for example, using the
\c {CREATE SEQUENCE} command) which is very likely to be a more
optimal solution. For the sake of portability the examples will use a
'sequence' table which will work with the vast majority of SQL
databases.

\endsidebar

\section1 Setting Up Database Connections

    \index Databases!Connecting to Database Servers
\index Connecting!Databases to Database Servers
There are two aspects of database connections that we must consider.
    Firstly the connection we wish to use within \QD itself, and
    secondly the connection we wish to use in the applications that we
    create.

    \section2 Setting Up Qt Designer's Connections

	\img database-connections.png
\caption Database Connections Dialog

	Choose \Menu {Project|Database Connections} from the menu
	bar. The \Dialog {Database Connections} dialog will appear. Click
	\Button {New Connection}. For applications that use a single
	database it will probably be most convenient to use the default
	connection name of '(default)'. If you use more than one
	database then each one must be given a unique name. A driver must be
	chosen from the Driver combo box. The database name may be
	available in the Database Name combo box or may have to be typed
	in. The database name, username, password and hostname should be
	provided by your database system administrator. When the
	Connection information has been completed click
	\Button Connect. If the connection is made the connection
	name will appear in the list box on the left hand side of the
	dialog. You can now close the dialog; the connection settings
	will remain in effect until you change or delete them or exit
	from \QD.

	\index Projects!Database Connections
	\QD can remember database connection settings in \Cmd qmake
	project files. Create a new project, e.g. click \Menu
	{File|New}, then click the 'C++ Project' icon to invoke the
	\Dialog{Project Settings} dialog. Click the ellipsis button to
	invoke the \Dialog{Save As} dialog; navigate to the project's
	directory (creating it if necessary). Make sure you're in the
	project's directory, then enter a project name of 'book.pro'.
	Click the \Button Save button to return to the \Dialog{Project
	Settings} dialog, then click \OK. 
	 Next time you start \QD instead of
	opening individual \c {.ui} files open the
	\c {.pro} project file instead and \QD will
	automatically reload the project's connection settings.  To
	activate the connection click \Menu {Project|Database Connections}.
	The connections previously saved with the
	project will be listed in the left hand list box. Click the
	connection you wish to use and then click \Button Connect. This
	connection will be used from now on, e.g. for previewing
	\Class {QDataTable}s. Opening a project file also causes \QD to
	load in the list of forms associated with the project into the
	Form List window. In most of the explanation that follows we
	will assume that you use project files and have clicked
	\Button Connect so that there is always a connection available
	when you work in
	\QD.

    \section2 Setting Up Connections for Applications

	The applications you create must make their own connections to
	the SQL database.
\index createConnections()
\Func createConnections() function

\code
bool createConnections()
{
    // create the default database connection
    QSqlDatabase *defaultDB = QSqlDatabase::addDatabase( "QPSQL7" );
    if ( ! defaultDB ) {
        qWarning( "Failed to connect to driver" );
        return FALSE;
    }
    defaultDB->setDatabaseName( "book" );
    defaultDB->setUserName( "bookuser" );
    defaultDB->setPassword( "bookpw" );
    defaultDB->setHostName( "bookhost" );
    if ( ! defaultDB->open() ) {
        qWarning( "Failed to open books database: " +
                  defaultDB->lastError().driverText() );
        qWarning( defaultDB->lastError().databaseText() );
        return FALSE;
    }

    return TRUE;
}
\endcode

	\index addDatabase()
	We call \Func addDatabase() passing it the name of the
	driver we wish to use. We then set the connection information by
	calling the \c {set}... functions. Finally we attempt to
	open the connection. If we succeed we return TRUE, otherwise we
	output some error information and return FALSE.
From \File {qt/tools/designer/examples/book/book1/main.cpp}

\quotefile book/book1/main.cpp
\skipto int main
\printuntil }

	\index Databases!Connecting to Multiple Database Servers
	\index createConnections()
	\index main.cpp
	\index addDatabase()
	All the examples presented in this chapter call
	\Func createConnections() after creating the
	\Class QApplication object in their \File main.cpp
	file and make use of the default connection. If you need to
	connect to multiple databases use the two-argument form of
	\Func addDatabase(), passing it both the name of the driver
	and a unique identifier. This is explained further in the
	\link http://doc.trolltech.com/sql.html
	Qt SQL Module documentation \endlink.

	\index QSqlDatabase::database()
	You do not need to keep a reference to database
	connections. If you use a single database connection, this
	becomes the default connection and database functions will use
	this connection automatically. We can always get a pointer to
	any of our connections by calling \Func QSqlDatabase::database().

	If you create a \File main.cpp file using \QD, this file will
	\e not include \Func createConnections(). We do not include
	this function because it needs the username and password for
	the database connection, and you may prefer to handle these
	differently from our simple example function. As a result,
	applications that preview correctly in \QD will not run unless
	you implement your own database connections function.

\section1 Using \Class {QDataTable}

    \Class {QDataTable}s may be placed on any form to provide browsing
    of database tables and views. \Class {QDataTable}s can also be used
    to update or delete records in-place, i.e. inside the cells
    themselves. Inserting records via a \Class QDataTable usually
    requires connecting to the \index primeInsert()
\SignalOrSlot primeInsert() signal, so that we
    can generate primary keys for example, or provide default values.
    If we wish to present records using a form view (perhaps combining
    data from several tables and views) we might use several
    \Class {QDataBrowser}s and \Class {QDataView}s.

    \section2 Quickly Viewing a Database Table

	This example, along with all the other examples in this chapter,
	has the project name 'book' and uses the database created by
	the \index book.sql
\File book.sql script. As we work through the chapter
	we will build the 'book' application step by step. Create or copy the
	\File qt/tools/designer/examples/book/book1/main.cpp file shown
	earlier. The project file for this first example is
	\File qt/tools/designer/examples/book/book1/book.pro. Start a new
	project by clicking  \Menu {File|New}, then click the 'C++
	Project' icon to invoke the \Dialog{Project Settings} dialog.
	Click the ellipsis button to invoke the \Dialog{Save As}
	dialog; navigate to the project's directory (creating it if
	necessary). Make sure you're in the project's directory, then
	enter a project name of 'book.pro'.
	Click the \Button Save button to return to the \Dialog{Project
	Settings} dialog, then click \OK.	
	Now click \Menu {Project|Database Connections}.
	Fill in the
	connection information appropriate to your database then press
	\Button Connect. The connection name should now appear in
	the left hand list box. (If this doesn't happen you'll need to
	contact your database systems administrator for help.) Close the
	dialog.

	We will now create a new form with a \Class QDataTable that's
	connected to one of our database tables.

	Click \Menu File|New. The \Dialog {New File} dialog presents us
	with a number of form templates to choose from. Choose the
	'Dialog' form and click \OK. Now click
	\Menu File|Save. You will be prompted for a filename,
	call it \File book.ui.

	\section3 Setting up a \Class {QDataTable}

	    \index Databases!SQL Table Wizard
\index Wizards!SQL Table
To place a \Class QDataTable widget on the form either
	    click \Menu Tools|Views|QDataTable or click the
	    \Toolbutton QDataTable toolbar button. Click on the form and
	    the SQL Table Wizard will appear.

	    \list 1
		\i

		    The \e {Database Connection and Table}
		    wizard page is used to set up a connection if one
		    doesn't exist and to choose the table or view for
		    the \Class QDataTable. (See
		    \l {Setting Up Qt Designer's Connections}.)

		    Click the connection you wish to use, listed in the
		    left hand list box, e.g. "(default)". The available
		    tables and views will appear in the right hand Table
		    list box. Click the 'author' table and then click
		    the \Button Next button.

		\i

		    The \e {Displayed Fields} wizard page
		    provides a means of selecting which fields should be
		    displayed in the \Class QDataTable and in what
		    order. By default all fields except the primary key
		    (if there is one) are in the Displayed Fields list
		    box. The left- and right-pointing blue arrow buttons
		    can be used to move fields between the Displayed
		    Fields and the Available Fields list boxes. The blue
		    up and down pointing arrow buttons are used to
		    select the display order of the displayed fields.

		    The default settings are the ones we want so simply
		    click \Button Next.

		\i

		    \index Properties!DataTable
The \e {Table Properties} wizard page provides
		    convenient access to some of the database-related
		    properties of the \Class QDataTable.

		    Make sure the Confirm Deletes checkbox is checked,
		    then click \Button Next.

		\i

		    The \e SQL wizard page is used to set the
		    \Class {QDataTable}'s Filter and Sort properties. The
		    Filter is an SQL \c {WHERE} clause (without
		    the word 'WHERE'). For example, to only list authors
		    whose surnames begin with 'P', we would enter
		    \c {title LIKE 'P%'}. We'll leave
		    the filter empty. The Available Fields list box
		    lists all the fields. The Sort By list box lists the
		    fields that the \Class QDataTable is to sort by and
		    the direction of their sorting (ASCending or
		    DESCending). The left and right blue arrows are used
		    to move fields between the two list boxes. The up
		    and down blue arrows move fields up and down within
		    the Sort By list box. The ASC or DESC setting is
		    changed with the 'sort order' toolbar button.

		    Move the surname and forename fields into the Sort By
		    list box and click \Button Next.

		\i

		    The \e Finish wizard page gives us the
		    opportunity to go back and change any of our
		    settings. We will be able to change them later
		    through the \Class {QDataTable}'s properties so we
		    can finish with the wizard.

		    Click \Button Finish.

	    \endlist

	    The table will appear on the form with each column labelled with
	    a default column name. If you wish to change the settings
	    then most of them are available in the property window. The
	    display names, the fields they are based upon, and the order
	    of appearance of the columns can be changed using the
	    \Dialog {Edit Table} dialog (explained later) by right clicking the
	    \Class QDataTable and left clicking \Button Edit.

	\section3 Laying out the Form

	    Click on the form and click the \Toolbutton {Lay Out Vertically}
	    toolbar button. Now click \Menu {Preview|Preview Form};
	    the form will run and the table will automatically display all
	    the records.

	    To turn the form we've created into an executable application we
	    must add the \index main.cpp
\File main.cpp file to the project file and
	    make the project. We should also do some renaming to make things
	    easier to understand.

	    \list 1
		\i

		    Click on the form and change its name to 'BookForm'
		    and its caption to 'Book'. Click on the
		    \Class QDataTable and change its name to
		    'AuthorDataTable'.

		\i

		    Click \Menu {File|Save All}.

		\i

		    Open the project file, e.g. \index book.pro
\File book.pro, in a
		    plain text editor and add the line:
		    \c {SOURCES += main.cpp}
		    at the end of the file.

		\i

		    Run \Cmd qmake to generate the make file,
		    e.g. \c {qmake -o Makefile book.pro}, then make
		    and run the \Cmd book program.

	    \endlist

	    This example shows how easy it is to use \Class QDataTable
	    to show the contents of a database table or view. You can
	    use the application we've just built to update and delete
	    author records. In the examples that follow we will cover
	    insertions, setting up master-detail relationships,
	    drilldown and foreign key lookups.

	    \sidebar A Note on Foreign Keys

	    \index Foreign Keys
\index Databases!Foreign Keys
In most relational databases tables contain fields which
	    are foreign keys into other tables. In our 'book' database
	    example the authorid in the book table is a foreign key
	    into the author table. When we present a form to the end
	    user we do not usually want the foreign key itself to be
	    visible but rather the text associated with it. Thus, we
	    would want the author's name to appear rather than the
	    author id when we show book information.  In many
	    databases, this can be achieved by using a view.  See your
	    database's documentation for details.

	    \endsidebar

    \section2 Inserting Records in \Class {QDataTable}s

	\index Inserting Records
\index Databases!Inserting Records
Record insertion into a relational database usually requires
	the generation of a primary key value which uniquely
	identifies the record in the table. Also we often want to
	create default values for some fields to minimize the user's
	work. We will create a slot to capture the \Class {QDataTable}s
	\index primeInsert()
\SignalOrSlot primeInsert() signal and populate the
	\Class QSqlRecord insertion buffer with a unique
	primary key.

	\list 1
	    \i

		Click \Menu Edit|Slots to invoke the
		\Dialog {Edit Slots} dialog. Click \Menu {New Slot}, then enter
		the slot name \SignalOrSlot primeInsertAuthor(QSqlRecord*)
		into the Slot Properties' Slot line edit box. Click
		\OK.

	    \i

		Click the \Toolbutton {Connect Signals/Slots}
		toolbar button, then click the AuthorDataTable, drag to
		the form and release the mouse. The \Dialog {Edit Connections}
		dialog will now appear. Click the \index primeInsert()
\SignalOrSlot primeInsert()
		signal and then the \SignalOrSlot primeInsertAuthor() slot to make
		the connection. Now click \OK.

	    \i

		Click the Source tab of the Object Hierarchy window
		(click \Menu {Window|Object Hierarchy} to make
		the window visible if necessary). Click the
		\SignalOrSlot primeInsertAuthor() slot and an editor window will
		appear.

	    \i

		We must change the \SignalOrSlot BookForm::primeInsertAuthor() slot to
		specify the parameter name and perform the necessary
		action:

\quotefile book/book2/book.ui.h
\skipto ::primeInsertAuthor
\printuntil }
\printline }

		A \Class QSqlQuery object is used to increment and
		retrieve a unique 'sequence' number for the author
		table. The signal passed us a pointer to the insertion
		buffer and we then put the value we've retrieved,
		i.e. the next sequence number, into the buffer's id
		field.  (Again, note that SQL databases often support
		a native 'sequence' function.  The method used here is
		inappropriate for production systems, and is for
		example purposes only.  See your database's
		documentation for details on how to generate unique
		keys in code.  In many cases, the database can
		generate them automatically, or the database may
		provide a special syntax for dealing with sequences.)

	\endlist

	\index Deleting!Records!Databases
\index Databases!Deleting Records
\index Updating Records
\index Databases!Updating Records
If we rebuild the application it will now support \INS as well as
	\UPD and \DEL. We could easily have added additional code to
	insert default values, e.g. today's date into a date field, if
	necessary.

	\index Databases!Browsing
\index Databases!Confirmations
\index Browsing Databases
Browsing is
	supported by clicking records and by using the arrow keys. Once
	a record is active (highlighted) we can edit the it. Press
	the \Key Insert key to \INS a new record;
	press \Key F2 to \UPD the current record;
	press the \Key Del key to \DEL the
	current record. All these operations take place
	immediately. Users can be given the opportunity to confirm
	their edits by setting the \Class {QDataTable}'s confirmEdits
	property to True. If the confirmEdits property is True then user
	confirmation will be required for all insertions, updates and
	deletes. For finer control you can set the confirmInsert,
	confirmUpdate and confirmDelete properties individually.

	\sidebar \Class QDataTable User Interface Interaction

	\index Databases!User Interface Interaction
\index User Interface Interaction, Databases
The default user-interface behaviour for \Class {QDataTable}s is as follows:
	    \list
		\i

		Users can move to records by clicking the scrollbar and
		clicking records with the mouse. They can also use the
		keyboard's navigation keys, e.g. \Key {Left Arrow},
		\Key {Right Arrow}, \Key {Up Arrow}, \Key {Down Arrow},
		\Key {Page Up}, \Key {Page Down}, \Key Home and \Key End.

		\i

		\INS is initiated by right-clicking the record and
		clicking Insert or by pressing the \Key Ins (Insert)
		key. The user moves between fields using \Key Tab and
		\Key Shift+Tab. The \INS will take place if the user
		presses \Key Enter or \Key {Tab}s
		off the last field. If autoEdit is TRUE the
		insert will take place if the user navigates to another
		record. \INS is cancelled by pressing \Key Esc (Escape). If
		autoEdit is FALSE navigating to another record also
		cancels the \INS. Setting confirmInsert to TRUE will
		require the user to confirm each \INS.

		\i

		\UPD is initiated by right-clicking the record and clicking
		Update or by pressing \Key F2. The update will take place if
		the user presses Enter or Tabs off the last
		field. If autoEdit is TRUE the update will take place if
		the user navigates to another record. \UPD is cancelled
		by pressing \Key Esc. If autoEdit is FALSE
		navigating to another record also cancels the \UPD.
		Setting confirmUpdate to TRUE will require the user to
		confirm each \UPD.

		\i

		\DEL is achieved by right-clicking the record and
		clicking Delete or by pressing the \Key Del (Delete) key.
		Setting confirmDelete to TRUE will require the user to
		confirm each \DEL.

	    \endlist

	    You can change this default behaviour programmatically if
	    required.

	\endsidebar

    \section2 Relating Two Tables Together (Master-Detail)

	\index Databases!Master-Detail Relationships
\index Master-Detail Relationships
Databases often have pairs of tables that are related. For
	example, an invoice table might list the numbers, dates and
	customers for invoices, but not the actual invoice items, which
	an invoice item table might store. In the 'book' application we
	wish to have a \Class QDataTable that we can use to browse
	through the authors table and a second \Class QDataTable to
	show the books they've written.

	Open the book project if it isn't already open \QD. We will
	modify this project to show two \Class {QDataTable}s that
	relate the author table to the book table.

	\list 1
	    \i

		Click the author \Class QDataTable and then click the
		\Toolbutton {Break Layout} toolbutton.

	    \i

		Resize the \Class QDataTable so that it only
		occupies the top half of the form.

	    \i

		Now click on the \Class QDataTable toolbutton and click
		on the bottom half of the form. The SQL Table Wizard
		will appear. (This Wizard is explained in \l {Quickly
		Viewing a Database Table}.)
		\list 1
		    \i

			Click the connection you're using and click
			the book table. Click the \Button Next
			button.

		    \i

			Since we do not want them visible, make sure
			the authorid and id fields are moved to the
			Available Fields list box by using the arrow
			buttons. Move the title field to the top of
			the Displayed Fields, and move the price field
			above the notes field.  Click the
			\Button Next button.

		    \i

			On the Table Properties page click the Read Only
			checkbox then click the \Button Next
			button.

		    \i

			On the SQL page we will leave the Filter
			(\c {WHERE} clause) empty. Move the
			title field to the Sort By list box and click
			\Button Next. Now click \Button Finish.

		    \i

			Change this \Class {QDataTable}'s name to "BookDataTable".

		\endlist

	    \i

		\Key Shift+Click the top \Class QDataTable so that both
		\Class {QDataTable}s are selected and then click the
		\Toolbutton {Lay Out Vertically (in Splitter)} toolbar
		button.

	    \i

		Click on the form and click the
		\Toolbutton {Lay Out Vertically} toolbar button.

	\endlist

	Run the form by clicking \Menu {Preview|Preview Form}.
	All the authors are displayed in the top \Class QDataTable
	and all the books are displayed in the bottom
	\Class QDataTable. However we only want the books of the
	currently selected author showing in the bottom
	\Class QDataTable. We will deal with this by filtering the
	records in the book table according to the author selected in
	the author table.

	\sidebar Using the Table Editor

	\index Value Editors!SQL Table Editor
\img edit-dbtable-dialog.png
\caption Edit Table Dialog

	\Class {QDataTable}s are created and set up using the SQL Table
	Wizard. Like any other \QD widget their properties may be
	changed in the Properties window. Some of the column and row
	based properties can also be be changed using the \Dialog {Edit Table}
	dialog. This dialog is invoked by right clicking the
	\Class QDataTable and left clicking the \Menu Edit menu item.
	The right hand half of the \Dialog {Edit Table} dialog is where we choose
	the fields we wish to display, their order and their labels. The
	procedure for creating columns is as follows:

	\list 1
	    \i

		Click the \Button {New Column} button.

	    \i

		Drop down the Field combobox to list the available
		fields.

	    \i

		Click the field you wish to include at this point.

	    \i

		\e Optionally edit the Label if the default
		isn't appropriate.

	    \i

	    \e Optionally click the Pixmap ellipsis (\Button {...})
	    button to choose a pixmap to be displayed to the left of
	    the column's label. (The ellipsis button appears when you
	    click in the Value part of the Properties list by a
	    \Property pixmap or \Property iconSet property.)

	\endlist

	Repeat the steps listed above for each column you wish to add.
	Once all the fields have been added you can change their
	ordering by using the blue up and down arrow buttons. At any
	point you can press \Button Apply to see how the table
	will look. Finally click the \OK button to save the
	properties you have set. You can always return to the table
	editor to change these settings later.

	\endsidebar

	\section3 Filtering One \Class QDataTable by Another

	    \index Databases!Relating Tables
To filter the book table's records we need to capture the author
	    \Class {QDataTable}'s \index currentChanged()
\Func currentChanged() signal and change the
	    BookDataTable's filter accordingly.

	    \list 1
		\i

		    Click \Menu Edit|Slots. In the \Dialog {Edit Slots}
		    dialog click \Menu {New Slot} and enter a slot
		    name of \SignalOrSlot newCurrentAuthor(QSqlRecord*).
		    Click \OK.

		\i

		    Click \Menu {Connect Signals/Slots}, then click
		    the AuthorDataTable \Class QDataTable and drag to
		    the form; release the mouse on the form. The
		    \Dialog {Edit Connections} dialog will appear. Click the
		    \index currentChanged()
\SignalOrSlot currentChanged() signal and the
		    \SignalOrSlot newCurrentAuthor slot. Click \OK.

		\i

		    Click the Source tab of the Object Hierarchy window
		    (click \Menu {Window|Object Hierarchy} to make
		    the window visible if necessary). Click the
		    \SignalOrSlot newCurrentAuthor() slot and an editor window will
		    appear.

		\i

		    We must change the \SignalOrSlot BookForm::newCurrentAuthor() slot to
		    specify the parameter name and perform the necessary
		    action:

\quotefile book/book3/book.ui.h
\skipto ::newCurrentAuthor
\printuntil }

		All that's required now is to change the BookDataTable's
		filter and refresh the \Class QDataTable to show the
		results of the filter.

	    \endlist

	\section3 Preparing the Interface for Drilldown

	    \index Databases!Drilldown
\index Drilldown
We can now browse and edit authors and see their books in the
	    BookDataTable.  In the next section we explore
	    \Class QDataBrowser, which will allow us to drill down to
	    a dialog through which we can edit books. For now we will
	    add some buttons to the main BookForm which we will use to
	    invoke the book editing dialog.

	    \list 1
		\i

		    Click the form, then click the
		    \Toolbutton {Break Layout} toolbar button. Resize the form
		    to make room for some buttons at the bottom.

		\i

		    Add two buttons to the bottom of the form. Change
		    their names and labels to the following:

		    \list
			\i

EditPushButton -- \&Edit Books

			\i

QuitPushButton -- \&Quit

		    \endlist
		    Hold down the Shift key and Click both buttons (i.e.
		    \Key Shift+Click the buttons) and click the
		    \Toolbutton {Lay Out Horizontally} toolbar button.
		    Click the form and click the
		    \Toolbutton {Lay Out Vertically} toolbar
		    button.

		\i

		    We will provide the Quit button with functionality
		    now and work on the rest shortly.
		    Click \Menu {Connect Signals/Slots}, then click
		    the Quit button and drag to the form; release the
		    mouse on the form. The \Dialog {Edit Connections} dialog will
		    appear. Click the \index clicked()
\Func clicked() signal
		    and the \index accept()
\SignalOrSlot accept() slot. Click \OK.

	    \endlist

\section1 Using \Class QDataBrowser and \Class {QDataView}

\img book-dialog.png
\caption The Book Application's Edit Books Dialog

    \section2 Drilling Down to a Form using \Class {QDataBrowser}

	\section3 Setting up a \Class {QDataBrowser}

	\index Databases!Drilldown
\index Drilldown
\index Databases!Data Browser Wizard
\index Wizards!Data Browser
We will now create a new form to allow users to edit book
	records. Click the \Toolbutton New toolbar button, click the
	Dialog template from the \Dialog {New File} dialog and click \OK. Change
	the name of the form to EditBookForm and its caption to 'Edit
	Books'. Click the \Toolbutton Save toolbar button and call the
	file \File editbook.ui. Now that we have the form we can add a
	\Class QDataBrowser to show the book records.

	\list 1
	    \i

		Click the \Toolbutton {Data Browser} toolbar button, then
		click the form. The Data Browser Wizard will appear.

	    \i

		The \e {Database Connection and Table} wizard
		page is used to set up a connection if one doesn't exist
		and to choose the table or view for the
		\Class QDataBrowser. (See \l {Setting
		Up Qt Designer's Connections}.)

		Click the connection you wish to use, listed in the
		Connection list box, e.g. "(default)". The available
		tables and views will appear in the Table list
		box. Click the book table and then click the
		\Button Next button.

	    \i

		The \e {Displayed Fields} wizard page provides a
		means of selecting which fields should be displayed in
		the \Class QDataBrowser and in what order. By default
		all fields except the primary key (if there is one) are
		in the right hand Displayed Fields list box. The left
		and right blue arrow buttons can be used to move fields
		between the Displayed Fields and the Available Fields
		list boxes. The blue up and down arrow buttons are used
		to select the display order of the displayed fields.

		We don't want to see the authorid foreign key field on
		the form, so move it to the Available Fields list
		box. Also, move the title field to the top of the
		Displayed Fields list. Click the \Button Next
		button.

	    \i

		The \e {Navigation and Editing} wizard page allows
		us to choose which navigation and editing buttons should
		appear on the form.

		We will accept the defaults and simply click the
		\Button Next button.

	    \i

		The \e SQL wizard page is used to set the
		\Class {QDataBrowser}'s Filter and Sort properties. The
		Filter is an SQL \c {WHERE} clause (without the
		word 'WHERE'). For example, to only list books that
		cost less than 50 (of some currency, e.g. dollars), we
		would enter \c {price < 50}. We will leave the
		filter empty. The Available Fields list box lists all
		the fields. The Sort By list box lists the fields that
		the \Class QDataBrowser is to sort by and the
		direction of their sorting (ASCending or
		DESCending). The left and right blue arrows are used
		to move fields between the two list boxes. The up and
		down blue arrows move fields up and down within the
		Sort By list box. The ASC or DESC setting is changed
		with the sort order button.

		Move the title field into the Sort By list box and click
		\Button Next.

	    \i

		The \e Layout wizard page is used to specify the
		initial layout of the form.

		Change the Number of Columns to 1, then click
		\Button Next. Now click \Button Finish.

	    \i

		The \Class QDataBrowser will now appear on the form.
		Resize the form to make it shorter. Click
		the \Class QDataBrowser then click the \Button {Break
		Layout} toolbar button. Click the buttons then click
		the \Toolbutton {Break Layout} toolbar button. Add
		another button called 'PushButtonClose' with the text
		'\&Close' and place it to the right of the Delete button.

	    \i

		\Key Shift+Click the Insert, Update, Delete and Close
		buttons, then click the \Button {Lay Out
		Horizontally} toolbar button. Click the
		\Class QDataBrowser, then click the \Button {Lay Out
		in a Grid} toolbar button. Finally click the form and
		click the \Toolbutton {Lay Out Vertically} toolbar
		button. Now click the \Class QDataBrowser and rename it
		'BookDataBrowser'.

	    \i

		\QD will generate the necessary code to make the
		browser operational (including generating the
		appropriate cursor, sort and filter code).

		For finer control over the form, we will be creating
		our own database cursor.  Therefore, set the
		BookDataBrowser's frameworkCode property to FALSE in
		the Properties window to prevent \QD from generating
		redundant code for the cursor.

	\endlist

	\sidebar \Class QDataBrowser User Interface Interaction

	The user-interface behaviour for \Class {QDataBrowser}s
	is created by connecting slots and signals. The slots provided are:
	    \list
		\i

		\index insert()
\Func insert(), \index update()
\Func update() and \index del()
\Func del() for editing;

		\i

		\index first()
\Func first(), \index next()
\Func next(), \index prev()
\Func prev(), and \index last()
\Func last() for
		navigation;

		\i

		\index refresh()
\Func refresh() to refresh the cursor from the database;

		\i

		\index readFields()
\Func readFields() to read data from the cursor's edit
		buffer and \index writeFields()
\Func writeFields() to write the form's data to
		the cursor's edit buffer;

		\i

		\index clearValues()
\Func clearValues() to clear the form's values.

	    \endlist

	If you use \QD's
	\Class QDataBrowser wizard you will be given the option of
	creating a default set of buttons for navigation and editing.
	The behaviour of these buttons is set up using the slots
	described above to provide the following functionality:
	    \list
		\i

		\INS is initiated by pressing the \Key Ins (Insert) button. The
		user moves between fields using \Key Tab and \Key Shift+Tab. If
		the user presses the Update button the \INS will take
		place and the user will be taken to the record they have
		just inserted. If the user presses the Insert button
		(i.e. a second time) the \INS will take place and a new
		insertion will be initiated. If autoEdit is TRUE the
		\INS will take place if the user navigates to another
		record. \INS is cancelled by pressing the
		\Key Esc
		key or by pressing the \Key Del (Delete) button. If autoEdit is
		FALSE then navigating to another record also cancels the
		\INS. Setting confirmInsert to TRUE will require the
		user to confirm each \INS.

		\i

		\UPD is automatically initiated whenever the user
		navigates to a record. An update will take place if the
		user presses the Update button. If autoEdit is TRUE the
		update will take place if the user navigates to another
		record. \UPD is cancelled by pressing the
		\Key Esc
		key or by pressing the \Key Del button. If autoEdit is
		FALSE then navigating to another record also cancels the
		\UPD. Setting confirmUpdate to TRUE will require the
		user to confirm each \UPD.

		\i

		\DEL is achieved by pressing the \Key Del button.
		Setting confirmDelete to TRUE will require the user to
		confirm each \DEL.

	    \endlist

	\endsidebar

	\section3 Performing the Drilldown

	\index Databases!Drilldown
\index Drilldown
We now have a working form for editing book records. We need to
	start the form when the user clicks our 'Edit Books' button, and to
	navigate to the record they have selected in the BookDataTable.
	We also need to provide a means of editing the foreign keys,
	e.g. authorid.

	\list 1
	    \i

		We need to make a new slot to connect the Edit Books'
		button's \index clicked()
\SignalOrSlot clicked() signal to. Click on the Book
		form to make it \QD's active form. Invoke the
		\Dialog {Edit Slots}
		dialog and create a new slot called \SignalOrSlot editClicked(). Now
		click the \Toolbutton {Connect Signals/Slots} toolbar button.
		Click the Edit Books button and drag to the form; release
		the mouse on the form. In the \Dialog {Edit Connections} dialog
		connect the \index clicked()
\SignalOrSlot clicked() signal to the
		\SignalOrSlot editClicked() slot. Click \OK to leave the
		dialog.

	    \index Object Hierarchy

	    \i  In the Object Hierarchy window click Source and then click
		the \Func editClicked function. We need to change it to
		the following:

\quotefile book/book6/book.ui.h
\skipto ::editClicked
\printuntil }

		We create our dialog as before. We also create a
		cursor over the book table and set the dialog's
		\Class QDataBrowser, BookDataBrowser, to use this new
		cursor. We set the \Class {QDataBrowser}'s filter and
		sort to those that applied to the main form's book
		\Class QDataTable. We refresh the
		\Class QDataBrowser and seek to the same record the
		user was viewing on the main form. Then we exec the
		dialog and delete it when the user has finished with
		it. Finally we update the BookDataTable in the main
		form to reflect any changes that were made in the
		dialog.

	    \i

		Because our code refers to a class declared in
		\File editbook.h and to a \Class QDataBrowser
		we need to add two additional include files. Click on
		the BookForm, then click on the Source tab of the
		Object Hierarchy window. Right click the 'Includes (In
		Declaration)' item and click New. Type in
		\File "editbook.h". Now add a second include,
		this time, \File \<qdatabrowser.h\>.

	\endlist

	Now when we navigate through the author and book records in the
	BookForm we can click the Edit Books button to launch our Edit Books
	dialog. Although the dialog supports \UPD, \DEL and navigation over
	the book table, we cannot edit the foreign keys nor perform
	inserts. We will deal with insertion in the same way as we did
	with the \Class QDataTable, then we will handle the foreign
	key relationship to author.

	\section3 Inserting into a \Class {QDataBrowser}

	We will create a slot to receive the Edit Books form's
	\index primeInsert()
\SignalOrSlot primeInsert() signal so that we can insert a unique
	primary key.

	\list 1
	    \i

		Click on the Edit Books form, then
		create a new Slot called \SignalOrSlot primeInsertBook(QSqlRecord*).

		Click \Menu Edit|Slots, then click the
		\Button {New Slot} button and type the new slot name
		in the Slot Properties Slot edit box. Click \OK.

	    \i

		Connect the BookDataBrowser's \index primeInsert()
\SignalOrSlot primeInsert()
		signal to the \SignalOrSlot primeInsertBook() slot.

		Click the
		\Toolbutton {Connect Signals/Slots} toolbar button, then
		click the BookDataBrowser and drag to the form; release
		the mouse on the form. Now click the
		\index primeInsert()
\SignalOrSlot primeInsert() signal and the
		primeInsertBook slot. Click \OK.

	    \i

		In the
		Object Hierarchy window click Source and then click the
		\SignalOrSlot primeInsertBook slot. We need to change
		it to the following:

\quotefile book/book6/editbook.ui.h
\skipto ::primeInsertBook
\printuntil }
\printline }

	    \i
		\index clicked()
		\index accept()
		We will also tidy up the user interface slightly. Click
		the Update button and set its default property to True.
		Connect the Close button's  \SignalOrSlot clicked() signal
		to the EditBookForm's \SignalOrSlot accept() slot.

	\endlist

	\section3 Handling Foreign Keys in a \Class QDataBrowser

	\index Foreign Keys
\index Databases!Foreign Keys
Qt's SQL module provides two approaches to dealing with foreign
	keys. The most powerful and flexible is to subclass widgets and
	use property maps to relate the widgets to the database. This
	approach is described in the \link http://doc.trolltech.com/sql.html#Custom_Editor_Widgets Qt SQL Module documentation \endlink, particularly the StatusPicker
	example. A simpler approach that can be taken wholly within \QD
	is presented here.

	We will add a new field to the EditBookForm so that authors can
	be edited along with the title and price. Once we've handled the
	visual design we'll write the code to make it all work.

	\list 1
	\i

	First we'll add the new widgets. Click the BookDataBrowser and
	click the \Toolbutton {Break Layout} toolbar button. Resize the form
	to make it larger and drag each set of buttons down to make some
	room below the title and price QLineEdits. Click the
	\Toolbutton {Text Label} toolbar button and click on the form beneath
	the Price label. Click the \Widget {Text Label} and change its text to
	'Author'. Click the \Toolbutton ComboBox toolbar button and click
	on the form beneath the price QLineEdit. In the Property Window
	change the \Widget {ComboBox}'s \Property name to ComboBoxAuthor and
	change its \Property sizePolicy \Property hSizeType to Expanding.

	\i

	Now we'll lay out the dialog. \Key Shift+Click the Author label and
	the \Widget ComboBox then click the \Toolbutton {Lay Out Horizontally}
	toolbar button. Now click the BookDataBrowser and click the
	\Toolbutton {Lay Out in a Grid} toolbar button.

	\endlist

	We need to write some code so that the \Widget ComboBox will be
	populated with author names and scroll to the current book's
	author. We also need to ensure that we put the author's id into
	the book table's authorid field when a book record is inserted
	or updated. We'll ensure the code is executed at the right time
	by putting it in slots and connecting signals to our slots.

	\list 1
	\i

	Create two new slots called
	\Func beforeUpdateBook(QSqlRecord *buffer) and
	\Func primeUpdateBook(QSqlRecord *buffer). (Click
	\Menu Edit|Slots, then in the \Dialog {Edit Slots} dialog click New Slot
	and enter the first new slot. Click New Slot again and enter the
	second slot then click \OK.)

	\i

	When the user navigates through the dialog, each time they move
	to a new record, a \index primeUpdate()
\SignalOrSlot primeUpdate() signal is emitted. We connect
	to this so that we can update the \Widget {ComboBox}'s display. Just
	before a record is updated or inserted into the database a
	\index beforeUpdate()
\SignalOrSlot beforeUpdate() or \index beforeInsert()
\SignalOrSlot beforeInsert() signal is emitted. We
	connect our \SignalOrSlot beforeUpdateBook() slot to both these signals so
	that we can ensure that the book's authorid field is correctly
	populated.

	Click the BookDataBrowser and drag the mouse to the form;
	release the mouse and the \Dialog {Edit Connections} dialog will appear.
	Connect the \index beforeUpdate()
\SignalOrSlot beforeUpdate() signal to our
	\SignalOrSlot beforeUpdateBook() slot. Connect the \index beforeInsert()
\SignalOrSlot beforeInsert() signal
	to our \SignalOrSlot beforeUpdateBook() slot. Finally connect the
	\index primeUpdate()
\SignalOrSlot primeUpdate() signal to our \SignalOrSlot primeUpdateBook() slot.

	\i

	All that remains is to write the underlying code. All the
	code snippets are taken from
	\File qt/tools/designer/examples/book/book7/editbook.ui.
	    \list 1
	    \i

	    We start with the \index init()
\Func init() function; this is called after
	    the dialog is constructed and we will use it to populate the
	    \Widget ComboBox with author names.

\quotefile book/book7/editbook.ui.h
\skipto ::init
\printuntil }

	    Here we execute a query to get a list of author names and
	    insert each one into the \Widget ComboBox.

	    \i

	    We next write the code which will be executed just before a
	    record is updated (or inserted) in the database.

\quotefile book/book7/editbook.ui.h
\skipto ::beforeUpdateBook
\printuntil }

	    We look up the id of the \Widget {ComboBox}'s current author
	    and place it in the update (or insert) buffer's authorid
	    field.

	    \i

	    As the user navigates through the records we ensure
	    that the \Widget ComboBox reflects the current author.

\skipto ::primeUpdateBook
\printuntil }
\printline }
\printline }

	    Firstly we look up the book's author and secondly we iterate
	    through the \Widget {ComboBox}'s items until we find the author and
	    set the \Widget {ComboBox}'s current item to the matching author.

	    \endlist

	\endlist

    If the author name has changed or been deleted the query will
    fail and no author id will be inserted into the buffer causing the \INS
    to fail.  An alternative is to record
    the author id's as we populate the \Widget ComboBox and store them in a
    \Class QMap which we can then look up as required. This approach
    requires changes to the \index init()
\Func init(), \SignalOrSlot beforeUpdateBook() and
    \SignalOrSlot primeInsertBook() functions and the addition of a new function,
    \Func mapAuthor().
    The relevant code from
    \File qt/tools/designer/examples/book/book8/editbook.ui is shown below.

	    \list 1
	    \i

	    First we need to create a class variable to map author names
	    to author id's. Click in the Source tab of the Object
	    Hierarchy, then right click the Class Variables item and
	    click \Menu New. Type in
	    'QMap\<QString,int\> authorMap;'.

	    \i

	    We now record the author id's in the \index init()
\Func init() function.

\quotefile book/book8/editbook.ui.h
\skipto ::init
\printuntil }
\printline }

	    After inserting each author's name into the \Widget ComboBox we
	    populate a \Class QMap with the author's name and id.

	    \i

	    Instead of looking up the author's id in the database we
	    look it up in the \Class QMap.

\quotefile book/book8/editbook.ui.h
\skipto ::beforeUpdateBook
\printuntil }

	    \i

	    We use a single function for storing author id's and
	    returning them so that we can use a static data structure.

\quotefile book/book8/editbook.ui.h
\skipto ::mapAuthor
\printuntil }

	    If the populate flag is TRUE, we store the author's name and
	    id in the \Class QMap, otherwise we look up the given
	    author name and set id appropriately.

	    \endlist

\index Databases!Foreign Keys
\index Foreign Keys
Another approach which is especially useful if the same foreign key
lookups are required in different parts of the application is to
subclass a cursor and use this for our lookups. This is described in the
\link http://doc.trolltech.com/sql.html Qt SQL Module documentation \endlink, particulary the section on subclassing
\Class QSqlCursor.

The 'book' example demonstrates the basic techniques needed for SQL
programming with Qt. Additional information on the Qt SQL classes,
especially the \Class QSqlQuery and \Class QSqlCursor classes is
provided in the \link http://doc.trolltech.com/sql.html Qt SQL Module documentation \endlink.
