src/qt3support/sql/q3datatable.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt3Support module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "q3datatable.h"
       
    43 
       
    44 #ifndef QT_NO_SQL_VIEW_WIDGETS
       
    45 
       
    46 #include "qevent.h"
       
    47 #include "qsqldriver.h"
       
    48 #include "q3sqleditorfactory.h"
       
    49 #include "q3sqlpropertymap.h"
       
    50 #include "qapplication.h"
       
    51 #include "qlayout.h"
       
    52 #include "qpainter.h"
       
    53 #include "q3popupmenu.h"
       
    54 #include "q3valuelist.h"
       
    55 #include "q3sqlmanager_p.h"
       
    56 #include "qsqlfield.h"
       
    57 #include "qdatetime.h"
       
    58 #include "qcursor.h"
       
    59 #include "qtimer.h"
       
    60 #include "qpointer.h"
       
    61 
       
    62 QT_BEGIN_NAMESPACE
       
    63 
       
    64 //#define QT_DEBUG_DATATABLE
       
    65 
       
    66 class Q3DataTablePrivate
       
    67 {
       
    68 public:
       
    69     Q3DataTablePrivate()
       
    70         : nullTxtChanged( false ),
       
    71           haveAllRows( false ),
       
    72           continuousEdit( false ),
       
    73           editorFactory( 0 ),
       
    74           propertyMap( 0 ),
       
    75           datefmt( Qt::TextDate ),
       
    76           editRow( -1 ),
       
    77           editCol( -1 ),
       
    78           insertRowLast( -1 ),
       
    79           insertPreRows( -1 ),
       
    80           editBuffer( 0 ),
       
    81           cancelMode( false ),
       
    82           cancelInsert( false ),
       
    83           cancelUpdate( false ),
       
    84           lastAt( -1 )
       
    85     {}
       
    86     ~Q3DataTablePrivate() { if ( propertyMap ) delete propertyMap; }
       
    87 
       
    88     QString nullTxt;
       
    89     bool nullTxtChanged;
       
    90     typedef Q3ValueList< uint > ColIndex;
       
    91     ColIndex colIndex;
       
    92     bool haveAllRows;
       
    93     bool continuousEdit;
       
    94     Q3SqlEditorFactory* editorFactory;
       
    95     Q3SqlPropertyMap* propertyMap;
       
    96     QString trueTxt;
       
    97     Qt::DateFormat datefmt;
       
    98     QString falseTxt;
       
    99     int editRow;
       
   100     int editCol;
       
   101     int insertRowLast;
       
   102     QString insertHeaderLabelLast;
       
   103     int insertPreRows;
       
   104     QSqlRecord* editBuffer;
       
   105     bool cancelMode;
       
   106     bool cancelInsert;
       
   107     bool cancelUpdate;
       
   108     int lastAt;
       
   109     QString ftr;
       
   110     QStringList srt;
       
   111     QStringList fld;
       
   112     QStringList fldLabel;
       
   113     Q3ValueList<int> fldWidth;
       
   114     Q3ValueList<QIconSet> fldIcon;
       
   115     Q3ValueList<bool> fldHidden;
       
   116     Q3SqlCursorManager cur;
       
   117     Q3DataManager dat;
       
   118 };
       
   119 
       
   120 #ifdef QT_DEBUG_DATATABLE
       
   121 void qt_debug_buffer( const QString& msg, QSqlRecord* cursor )
       
   122 {
       
   123     qDebug("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
       
   124     qDebug(msg);
       
   125     for ( uint j = 0; j < cursor->count(); ++j ) {
       
   126 	qDebug(cursor->field(j)->name() + " type:" + QString(cursor->field(j)->value().typeName()) + " value:" + cursor->field(j)->value().toString() );
       
   127     }
       
   128 }
       
   129 #endif
       
   130 
       
   131 /*!
       
   132     \enum Q3DataTable::Refresh
       
   133 
       
   134     This enum describes the refresh options.
       
   135 
       
   136     \value RefreshData  refresh the data, i.e. read it from the database
       
   137     \value RefreshColumns  refresh the list of fields, e.g. the column headings
       
   138     \value RefreshAll  refresh both the data and the list of fields
       
   139 */
       
   140 
       
   141 
       
   142 /*!
       
   143     \class Q3DataTable
       
   144     \brief The Q3DataTable class provides a flexible SQL table widget that supports browsing and editing.
       
   145 
       
   146     \compat
       
   147 
       
   148     Q3DataTable supports various functions for presenting and editing
       
   149     SQL data from a \l Q3SqlCursor in a table.
       
   150 
       
   151     If you want a to present your data in a form use QDataBrowser, or
       
   152     for read-only forms, use QDataView instead.
       
   153 
       
   154     When displaying data, Q3DataTable only retrieves data for visible
       
   155     rows. If the driver supports the 'query size' property the
       
   156     Q3DataTable will have the correct number of rows and the vertical
       
   157     scroll bar will accurately reflect the number of rows displayed in
       
   158     proportion to the number of rows in the dataset. If the driver
       
   159     does not support the 'query size' property, rows are dynamically
       
   160     fetched from the database on an as-needed basis with the scroll bar
       
   161     becoming more accurate as the user scrolls down through the
       
   162     records. This allows extremely large queries to be displayed as
       
   163     quickly as possible, with minimum memory usage.
       
   164 
       
   165     Q3DataTable inherits Q3Table's API and extends it with functions to
       
   166     sort and filter the data and sort columns. See setSqlCursor(),
       
   167     setFilter(), setSort(), setSorting(), sortColumn() and refresh().
       
   168 
       
   169     When displaying editable cursors, cell editing will be enabled.
       
   170     (For more information on editable cursors, see \l Q3SqlCursor).
       
   171     Q3DataTable can be used to modify existing data and to add new
       
   172     records. When a user makes changes to a field in the table, the
       
   173     cursor's edit buffer is used. The table will not send changes in
       
   174     the edit buffer to the database until the user moves to a
       
   175     different record in the grid or presses Enter. Cell editing is
       
   176     initiated by pressing F2 (or right clicking and then clicking the
       
   177     appropriate popup menu item) and canceled by pressing Esc. If
       
   178     there is a problem updating or adding data, errors are handled
       
   179     automatically (see handleError() to change this behavior). Note
       
   180     that if autoEdit() is false navigating to another record will
       
   181     cancel the insert or update.
       
   182 
       
   183     The user can be asked to confirm all edits with setConfirmEdits().
       
   184     For more precise control use setConfirmInsert(),
       
   185     setConfirmUpdate(), setConfirmDelete() and setConfirmCancels().
       
   186     Use setAutoEdit() to control the behavior of the table when the
       
   187     user edits a record and then navigates. (Note that setAutoDelete()
       
   188     is unrelated; it is used to set whether the Q3SqlCursor is deleted
       
   189     when the table is deleted.)
       
   190 
       
   191     Since the data table can perform edits, it must be able to
       
   192     uniquely identify every record so that edits are correctly
       
   193     applied. Because of this the underlying cursor must have a valid
       
   194     primary index to ensure that a unique record is inserted, updated
       
   195     or deleted within the database otherwise the database may be
       
   196     changed to an inconsistent state.
       
   197 
       
   198     Q3DataTable creates editors using the default \l Q3SqlEditorFactory.
       
   199     Different editor factories can be used by calling
       
   200     installEditorFactory(). A property map is used to map between the
       
   201     cell's value and the editor. You can use your own property map
       
   202     with installPropertyMap().
       
   203 
       
   204     The contents of a cell is available as a QString with text() or as
       
   205     a QVariant with value(). The current record is returned by
       
   206     currentRecord(). Use the find() function to search for a string in
       
   207     the table.
       
   208 
       
   209     Editing actions can be applied programmatically. For example, the
       
   210     insertCurrent() function reads the fields from the current record
       
   211     into the cursor and performs the insert. The updateCurrent() and
       
   212     deleteCurrent() functions perform similarly to update and delete
       
   213     the current record respectively.
       
   214 
       
   215     Columns in the table can be created automatically based on the
       
   216     cursor (see setSqlCursor()). Columns can be manipulated manually
       
   217     using addColumn(), removeColumn() and setColumn().
       
   218 
       
   219     The table automatically copies many of the properties of the
       
   220     cursor to format the display of data within cells (alignment,
       
   221     visibility, etc.). The cursor can be changed with setSqlCursor().
       
   222     The filter (see setFilter()) and sort defined within the table are
       
   223     used instead of the filter and sort set on the cursor. For sorting
       
   224     options see setSort(), sortColumn(), sortAscending() and
       
   225     sortDescending(). Note that sorting operations will not behave as
       
   226     expected if you are using a QSqlSelectCursor because it uses
       
   227     user-defined SQL queries to obtain data.
       
   228 
       
   229     The text used to represent NULL, true and false values can be
       
   230     changed with setNullText(), setTrueText() and setFalseText()
       
   231     respectively. You can change the appearance of cells by
       
   232     reimplementing paintField().
       
   233 
       
   234     Whenever a new row is selected in the table the currentChanged()
       
   235     signal is emitted. The primeInsert() signal is emitted when an
       
   236     insert is initiated. The primeUpdate() and primeDelete() signals
       
   237     are emitted when update and deletion are initiated respectively.
       
   238     Just before the database is updated a signal is emitted;
       
   239     beforeInsert(), beforeUpdate() or beforeDelete() as appropriate.
       
   240 
       
   241 */
       
   242 
       
   243 /*!
       
   244     Constructs a data table which is a child of \a parent, called
       
   245     name \a name.
       
   246 */
       
   247 
       
   248 Q3DataTable::Q3DataTable ( QWidget * parent, const char * name )
       
   249     : Q3Table( parent, name )
       
   250 {
       
   251     init();
       
   252 }
       
   253 
       
   254 /*!
       
   255     Constructs a data table which is a child of \a parent, called name
       
   256     \a name using the cursor \a cursor.
       
   257 
       
   258     If \a autoPopulate is true (the default is false), columns are
       
   259     automatically created based upon the fields in the \a cursor
       
   260     record. Note that \a autoPopulate only governs the creation of
       
   261     columns; to load the cursor's data into the table use refresh().
       
   262 
       
   263     If the \a cursor is read-only, the table also becomes read-only.
       
   264     In addition, the table adopts the cursor's driver's definition for
       
   265     representing NULL values as strings.
       
   266 */
       
   267 
       
   268 Q3DataTable::Q3DataTable ( Q3SqlCursor* cursor, bool autoPopulate, QWidget * parent, const char * name )
       
   269     : Q3Table( parent, name )
       
   270 {
       
   271     init();
       
   272     setSqlCursor( cursor, autoPopulate );
       
   273 }
       
   274 
       
   275 /*! \internal
       
   276 */
       
   277 
       
   278 
       
   279 void Q3DataTable::init()
       
   280 {
       
   281     d = new Q3DataTablePrivate();
       
   282     setAutoEdit( true );
       
   283     setSelectionMode( SingleRow );
       
   284     setFocusStyle( FollowStyle );
       
   285     d->trueTxt = tr( "True" );
       
   286     d->falseTxt = tr( "False" );
       
   287     d->datefmt = Qt::LocalDate;
       
   288     reset();
       
   289     connect( this, SIGNAL(selectionChanged()),
       
   290 	     SLOT(updateCurrentSelection()));
       
   291 }
       
   292 
       
   293 /*!
       
   294     Destroys the object and frees any allocated resources.
       
   295 */
       
   296 
       
   297 Q3DataTable::~Q3DataTable()
       
   298 {
       
   299     delete d;
       
   300 }
       
   301 
       
   302 
       
   303 /*!
       
   304     Adds the next column to be displayed using the field \a fieldName,
       
   305     column label \a label, width \a width and iconset \a iconset.
       
   306 
       
   307     If \a label is specified, it is used as the column's header label,
       
   308     otherwise the field's display label is used when setSqlCursor() is
       
   309     called. The \a iconset is used to set the icon used by the column
       
   310     header; by default there is no icon.
       
   311 
       
   312     \sa setSqlCursor() refresh()
       
   313 */
       
   314 
       
   315 void Q3DataTable::addColumn( const QString& fieldName,
       
   316 			    const QString& label,
       
   317 			    int width,
       
   318 			    const QIconSet& iconset )
       
   319 {
       
   320     d->fld += fieldName;
       
   321     d->fldLabel += label;
       
   322     d->fldIcon += iconset;
       
   323     d->fldWidth += width;
       
   324     d->fldHidden += false;
       
   325 }
       
   326 
       
   327 /*!
       
   328     Sets the \a col column to display using the field \a fieldName,
       
   329     column label \a label, width \a width and iconset \a iconset.
       
   330 
       
   331     If \a label is specified, it is used as the column's header label,
       
   332     otherwise the field's display label is used when setSqlCursor() is
       
   333     called. The \a iconset is used to set the icon used by the column
       
   334     header; by default there is no icon.
       
   335 
       
   336     \sa setSqlCursor() refresh()
       
   337 */
       
   338 
       
   339 void Q3DataTable::setColumn( uint col, const QString& fieldName,
       
   340 			    const QString& label,
       
   341 			    int width,
       
   342 			    const QIconSet& iconset )
       
   343 {
       
   344     d->fld[col]= fieldName;
       
   345     d->fldLabel[col] = label;
       
   346     d->fldIcon[col] = iconset;
       
   347     d->fldWidth[col] = width;
       
   348     d->fldHidden[col] = false;
       
   349 }
       
   350 
       
   351 /*!
       
   352     Removes column \a col from the list of columns to be displayed. If
       
   353     \a col does not exist, nothing happens.
       
   354 
       
   355     \sa QSqlField
       
   356 */
       
   357 
       
   358 void Q3DataTable::removeColumn( int col )
       
   359 {
       
   360     if ( d->fld.begin() + col != d->fld.end() ) {
       
   361 	d->fld.remove( d->fld.at( col ) );
       
   362 	d->fldLabel.remove( d->fldLabel.at( col ) );
       
   363 	d->fldIcon.remove( d->fldIcon.at( col ) );
       
   364 	d->fldWidth.remove( d->fldWidth.at( col ) );
       
   365 	d->fldHidden.remove( d->fldHidden.at( col ) );
       
   366     }
       
   367 }
       
   368 
       
   369 /*!
       
   370     Sets the column \a col to the width \a w. Note that unlike Q3Table
       
   371     the Q3DataTable is not immediately redrawn, you must call
       
   372     refresh(Q3DataTable::RefreshColumns)
       
   373     yourself.
       
   374 
       
   375     \sa refresh()
       
   376 */
       
   377 void Q3DataTable::setColumnWidth( int col, int w )
       
   378 {
       
   379     if ( d->fldWidth.at( col ) != d->fldWidth.end() ) {
       
   380 	d->fldWidth[col] = w;
       
   381     }
       
   382 }
       
   383 
       
   384 /*!
       
   385     Resizes column \a col so that the column width is wide enough to
       
   386     display the widest item the column contains (including the column
       
   387     label). If the table's Q3SqlCursor is not currently active, the
       
   388     cursor will be refreshed before the column width is calculated. Be
       
   389     aware that this function may be slow on tables that contain large
       
   390     result sets.
       
   391 */
       
   392 void Q3DataTable::adjustColumn( int col )
       
   393 {
       
   394     Q3SqlCursor * cur = sqlCursor();
       
   395     if ( !cur || cur->count() <= col )
       
   396 	return;
       
   397     if ( !cur->isActive() ) {
       
   398 	d->cur.refresh();
       
   399     }
       
   400     int oldRow = currentRow();
       
   401     int w = fontMetrics().width( horizontalHeader()->label( col ) + QLatin1Char('W') );
       
   402     cur->seek( QSql::BeforeFirst );
       
   403     while ( cur->next() ) {
       
   404 	w = qMax( w, fontMetrics().width( fieldToString( cur->fieldPtr( indexOf( col ) ) ) ) + 10 );
       
   405     }
       
   406     setColumnWidth( col, w );
       
   407     cur->seek( oldRow );
       
   408     refresh( RefreshColumns );
       
   409 }
       
   410 
       
   411 /*! \reimp
       
   412 */
       
   413 void Q3DataTable::setColumnStretchable( int col, bool s )
       
   414 {
       
   415     if ( numCols() == 0 ) {
       
   416 	refresh( RefreshColumns );
       
   417     }
       
   418     if ( numCols() > col ) {
       
   419 	Q3Table::setColumnStretchable( col, s );
       
   420     }
       
   421 }
       
   422 
       
   423 QString Q3DataTable::filter() const
       
   424 {
       
   425     return d->cur.filter();
       
   426 }
       
   427 
       
   428 /*!
       
   429     \property Q3DataTable::filter
       
   430     \brief the data filter for the data table
       
   431 
       
   432     The filter applies to the data shown in the table. To view data
       
   433     with a new filter, use refresh(). A filter string is an SQL WHERE
       
   434     clause without the WHERE keyword.
       
   435 
       
   436     There is no default filter.
       
   437 
       
   438     \sa sort()
       
   439 
       
   440 */
       
   441 
       
   442 void Q3DataTable::setFilter( const QString& filter )
       
   443 {
       
   444     d->cur.setFilter( filter );
       
   445 }
       
   446 
       
   447 
       
   448 /*!
       
   449     \property Q3DataTable::sort
       
   450     \brief the data table's sort
       
   451 
       
   452     The table's sort affects the order in which data records are
       
   453     displayed in the table. To apply a sort, use refresh().
       
   454 
       
   455     When examining the sort property, a string list is returned with
       
   456     each item having the form 'fieldname order' (e.g., 'id ASC',
       
   457     'surname DESC').
       
   458 
       
   459     There is no default sort.
       
   460 
       
   461     Note that if you want to iterate over the sort list, you should
       
   462     iterate over a copy, e.g.
       
   463     \snippet doc/src/snippets/code/src_qt3support_sql_q3datatable.cpp 0
       
   464 
       
   465     \sa filter() refresh()
       
   466 */
       
   467 
       
   468 void Q3DataTable::setSort( const QStringList& sort )
       
   469 {
       
   470     d->cur.setSort( sort );
       
   471 }
       
   472 
       
   473 /*!
       
   474     \overload
       
   475 
       
   476     Sets the sort to be applied to the displayed data to \a sort. If
       
   477     there is no current cursor, nothing happens. A QSqlIndex contains
       
   478     field names and their ordering (ASC or DESC); these are used to
       
   479     compose the ORDER BY clause.
       
   480 
       
   481     \sa sort()
       
   482 */
       
   483 
       
   484 void Q3DataTable::setSort( const QSqlIndex& sort )
       
   485 {
       
   486     d->cur.setSort( sort );
       
   487 }
       
   488 
       
   489 QStringList Q3DataTable::sort() const
       
   490 {
       
   491     return d->cur.sort();
       
   492 }
       
   493 
       
   494 /*!
       
   495     Returns the cursor used by the data table.
       
   496 */
       
   497 
       
   498 Q3SqlCursor* Q3DataTable::sqlCursor() const
       
   499 {
       
   500     return d->cur.cursor();
       
   501 }
       
   502 
       
   503 void Q3DataTable::setConfirmEdits( bool confirm )
       
   504 {
       
   505     d->dat.setConfirmEdits( confirm );
       
   506 }
       
   507 
       
   508 void Q3DataTable::setConfirmInsert( bool confirm )
       
   509 {
       
   510     d->dat.setConfirmInsert( confirm );
       
   511 }
       
   512 
       
   513 void Q3DataTable::setConfirmUpdate( bool confirm )
       
   514 {
       
   515     d->dat.setConfirmUpdate( confirm );
       
   516 }
       
   517 
       
   518 void Q3DataTable::setConfirmDelete( bool confirm )
       
   519 {
       
   520     d->dat.setConfirmDelete( confirm );
       
   521 }
       
   522 
       
   523 /*!
       
   524     \property Q3DataTable::confirmEdits
       
   525     \brief whether the data table confirms edit operations
       
   526 
       
   527     If the confirmEdits property is true, the data table confirms all
       
   528     edit operations (inserts, updates and deletes). Finer control of
       
   529     edit confirmation can be achieved using \l confirmCancels, \l
       
   530     confirmInsert, \l confirmUpdate and \l confirmDelete.
       
   531 
       
   532     \sa confirmCancels() confirmInsert() confirmUpdate() confirmDelete()
       
   533 */
       
   534 
       
   535 bool Q3DataTable::confirmEdits() const
       
   536 {
       
   537     return ( d->dat.confirmEdits() );
       
   538 }
       
   539 
       
   540 /*!
       
   541     \property Q3DataTable::confirmInsert
       
   542     \brief whether the data table confirms insert operations
       
   543 
       
   544     If the confirmInsert property is true, all insertions must be
       
   545     confirmed by the user through a message box (this behavior can be
       
   546     changed by overriding the confirmEdit() function), otherwise all
       
   547     insert operations occur immediately.
       
   548 
       
   549     \sa confirmCancels() confirmEdits() confirmUpdate() confirmDelete()
       
   550 */
       
   551 
       
   552 bool Q3DataTable::confirmInsert() const
       
   553 {
       
   554     return ( d->dat.confirmInsert() );
       
   555 }
       
   556 
       
   557 /*!
       
   558     \property Q3DataTable::confirmUpdate
       
   559     \brief whether the data table confirms update operations
       
   560 
       
   561     If the confirmUpdate property is true, all updates must be
       
   562     confirmed by the user through a message box (this behavior can be
       
   563     changed by overriding the confirmEdit() function), otherwise all
       
   564     update operations occur immediately.
       
   565 
       
   566     \sa confirmCancels() confirmEdits() confirmInsert() confirmDelete()
       
   567 */
       
   568 
       
   569 bool Q3DataTable::confirmUpdate() const
       
   570 {
       
   571     return ( d->dat.confirmUpdate() );
       
   572 }
       
   573 
       
   574 /*!
       
   575     \property Q3DataTable::confirmDelete
       
   576     \brief whether the data table confirms delete operations
       
   577 
       
   578     If the confirmDelete property is true, all deletions must be
       
   579     confirmed by the user through a message box (this behavior can be
       
   580     changed by overriding the confirmEdit() function), otherwise all
       
   581     delete operations occur immediately.
       
   582 
       
   583     \sa confirmCancels() confirmEdits() confirmUpdate() confirmInsert()
       
   584 */
       
   585 
       
   586 bool Q3DataTable::confirmDelete() const
       
   587 {
       
   588     return ( d->dat.confirmDelete() );
       
   589 }
       
   590 
       
   591 /*!
       
   592     \property Q3DataTable::confirmCancels
       
   593     \brief whether the data table confirms cancel operations
       
   594 
       
   595     If the confirmCancel property is true, all cancels must be
       
   596     confirmed by the user through a message box (this behavior can be
       
   597     changed by overriding the confirmCancel() function), otherwise all
       
   598     cancels occur immediately. The default is false.
       
   599 
       
   600     \sa confirmEdits() confirmCancel()
       
   601 */
       
   602 
       
   603 void Q3DataTable::setConfirmCancels( bool confirm )
       
   604 {
       
   605     d->dat.setConfirmCancels( confirm );
       
   606 }
       
   607 
       
   608 bool Q3DataTable::confirmCancels() const
       
   609 {
       
   610     return d->dat.confirmCancels();
       
   611 }
       
   612 
       
   613 /*!
       
   614     \reimp
       
   615 
       
   616     For an editable table, creates an editor suitable for the field in
       
   617     column \a col. The editor is created using the default editor
       
   618     factory, unless a different editor factory was installed with
       
   619     installEditorFactory(). The editor is primed with the value of the
       
   620     field in \a col using a property map. The property map used is the
       
   621     default property map, unless a new property map was installed with
       
   622     installPropertMap(). If \a initFromCell is true then the editor is
       
   623     primed with the value in the Q3DataTable cell.
       
   624 */
       
   625 
       
   626 QWidget * Q3DataTable::createEditor( int , int col, bool initFromCell ) const
       
   627 {
       
   628     if ( d->dat.mode() == QSql::None )
       
   629 	return 0;
       
   630 
       
   631     Q3SqlEditorFactory * f = (d->editorFactory == 0) ?
       
   632 		     Q3SqlEditorFactory::defaultFactory() : d->editorFactory;
       
   633 
       
   634     Q3SqlPropertyMap * m = (d->propertyMap == 0) ?
       
   635 			  Q3SqlPropertyMap::defaultMap() : d->propertyMap;
       
   636 
       
   637     QWidget * w = 0;
       
   638     if( initFromCell && d->editBuffer ){
       
   639 	w = f->createEditor( viewport(), d->editBuffer->fieldPtr( indexOf( col ) ) );
       
   640 	if ( w )
       
   641 	    m->setProperty( w, d->editBuffer->value( indexOf( col ) ) );
       
   642     }
       
   643     return w;
       
   644 }
       
   645 
       
   646 /*! \reimp */
       
   647 bool Q3DataTable::eventFilter( QObject *o, QEvent *e )
       
   648 {
       
   649     if ( d->cancelMode )
       
   650 	return true;
       
   651 
       
   652     int r = currentRow();
       
   653     int c = currentColumn();
       
   654 
       
   655     if ( d->dat.mode() != QSql::None ) {
       
   656 	r = d->editRow;
       
   657 	c = d->editCol;
       
   658     }
       
   659 
       
   660     d->cancelInsert = false;
       
   661     d->cancelUpdate = false;
       
   662     switch ( e->type() ) {
       
   663     case QEvent::KeyPress: {
       
   664 	int conf = QSql::Yes;
       
   665 	QKeyEvent *ke = (QKeyEvent*)e;
       
   666 	if ( ( ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_BackTab )
       
   667 	    && ke->state() & Qt::ControlButton )
       
   668 	    return false;
       
   669 
       
   670 	if ( ke->key() == Qt::Key_Escape && d->dat.mode() == QSql::Insert ){
       
   671 	    if ( confirmCancels() && !d->cancelMode ) {
       
   672 		d->cancelMode = true;
       
   673 		conf = confirmCancel( QSql::Insert );
       
   674 		d->cancelMode = false;
       
   675 	    }
       
   676 	    if ( conf == QSql::Yes ) {
       
   677 		d->cancelInsert = true;
       
   678 	    } else {
       
   679 		QWidget *editorWidget = cellWidget( r, c );
       
   680 		if ( editorWidget ) {
       
   681 		    editorWidget->setActiveWindow();
       
   682 		    editorWidget->setFocus();
       
   683 		}
       
   684 		return true;
       
   685 	    }
       
   686 	}
       
   687 	if ( ke->key() == Qt::Key_Escape && d->dat.mode() == QSql::Update ) {
       
   688 	    if ( confirmCancels() && !d->cancelMode ) {
       
   689 		d->cancelMode = true;
       
   690 		conf = confirmCancel( QSql::Update );
       
   691 		d->cancelMode = false;
       
   692 	    }
       
   693 	    if ( conf == QSql::Yes ){
       
   694 		d->cancelUpdate = true;
       
   695 	    } else {
       
   696 		QWidget *editorWidget = cellWidget( r, c );
       
   697 		if ( editorWidget ) {
       
   698 		    editorWidget->setActiveWindow();
       
   699 		    editorWidget->setFocus();
       
   700 		}
       
   701 		return true;
       
   702 	    }
       
   703 	}
       
   704 	if ( ke->key() == Qt::Key_Insert && d->dat.mode() == QSql::None ) {
       
   705 	    beginInsert();
       
   706 	    return true;
       
   707 	}
       
   708 	if ( ke->key() == Qt::Key_Delete && d->dat.mode() == QSql::None ) {
       
   709 	    deleteCurrent();
       
   710 	    return true;
       
   711 	}
       
   712 	if ( d->dat.mode() != QSql::None ) {
       
   713 	    if ( (ke->key() == Qt::Key_Tab) && (c < numCols() - 1) && (!isColumnReadOnly( c+1 ) || d->dat.mode() == QSql::Insert) )
       
   714 		d->continuousEdit = true;
       
   715 	    else if ( (ke->key() == Qt::Key_BackTab) && (c > 0) && (!isColumnReadOnly( c-1 ) || d->dat.mode() == QSql::Insert) )
       
   716 		d->continuousEdit = true;
       
   717 	    else
       
   718 		d->continuousEdit = false;
       
   719 	}
       
   720 	Q3SqlCursor * sql = sqlCursor();
       
   721 	if ( sql && sql->driver() &&
       
   722 	     !sql->driver()->hasFeature( QSqlDriver::QuerySize ) &&
       
   723 	     ke->key() == Qt::Key_End && d->dat.mode() == QSql::None ) {
       
   724 #ifndef QT_NO_CURSOR
       
   725 	    QApplication::setOverrideCursor( Qt::WaitCursor );
       
   726 #endif
       
   727 	    int i = sql->at();
       
   728 	    if ( i < 0 ) {
       
   729 		i = 0;
       
   730 		sql->seek(0);
       
   731 	    }
       
   732 	    while ( sql->next() )
       
   733 		i++;
       
   734 	    setNumRows( i+1 );
       
   735 	    setCurrentCell( i+1, currentColumn() );
       
   736 #ifndef QT_NO_CURSOR
       
   737 	    QApplication::restoreOverrideCursor();
       
   738 #endif
       
   739 	    return true;
       
   740 	}
       
   741 	break;
       
   742     }
       
   743     case QEvent::FocusOut: {
       
   744 	QWidget *editorWidget = cellWidget( r, c );
       
   745 	repaintCell( currentRow(), currentColumn() );
       
   746 	if ( !d->cancelMode && editorWidget && o == editorWidget &&
       
   747 	     ( d->dat.mode() == QSql::Insert) && !d->continuousEdit) {
       
   748 	    setCurrentCell( r, c );
       
   749 	    d->cancelInsert = true;
       
   750 	}
       
   751 	d->continuousEdit = false;
       
   752 	break;
       
   753     }
       
   754     case QEvent::FocusIn:
       
   755 	repaintCell( currentRow(), currentColumn() );
       
   756 	break;
       
   757     default:
       
   758 	break;
       
   759     }
       
   760     return Q3Table::eventFilter( o, e );
       
   761 }
       
   762 
       
   763 /*! \reimp */
       
   764 void Q3DataTable::resizeEvent ( QResizeEvent * e )
       
   765 {
       
   766     if ( sqlCursor() &&
       
   767 	 sqlCursor()->driver() &&
       
   768 	 !sqlCursor()->driver()->hasFeature( QSqlDriver::QuerySize ) )
       
   769 	loadNextPage();
       
   770     Q3Table::resizeEvent( e );
       
   771 }
       
   772 
       
   773 /*! \reimp */
       
   774 void Q3DataTable::contentsContextMenuEvent( QContextMenuEvent* e )
       
   775 {
       
   776     Q3Table::contentsContextMenuEvent( e );
       
   777     if ( isEditing() && d->dat.mode() != QSql::None )
       
   778 	endEdit( d->editRow, d->editCol, autoEdit(), false );
       
   779     if ( !sqlCursor() )
       
   780 	return;
       
   781     if ( d->dat.mode() == QSql::None ) {
       
   782 	if ( isReadOnly() )
       
   783 	    return;
       
   784 	enum {
       
   785 	    IdInsert,
       
   786 	    IdUpdate,
       
   787 	    IdDelete
       
   788 	};
       
   789 	QPointer<Q3PopupMenu> popup = new Q3PopupMenu( this, "qt_datatable_menu" );
       
   790 	int id[ 3 ];
       
   791 	id[ IdInsert ] = popup->insertItem( tr( "Insert" ) );
       
   792 	id[ IdUpdate ] = popup->insertItem( tr( "Update" ) );
       
   793 	id[ IdDelete ] = popup->insertItem( tr( "Delete" ) );
       
   794 	bool enableInsert = sqlCursor()->canInsert();
       
   795 	popup->setItemEnabled( id[ IdInsert ], enableInsert );
       
   796 	bool enableUpdate = currentRow() > -1 && sqlCursor()->canUpdate() && !isColumnReadOnly( currentColumn() );
       
   797 	popup->setItemEnabled( id[ IdUpdate ], enableUpdate );
       
   798 	bool enableDelete = currentRow() > -1 && sqlCursor()->canDelete();
       
   799 	popup->setItemEnabled( id[ IdDelete ], enableDelete );
       
   800 	int r = popup->exec( e->globalPos() );
       
   801 	delete (Q3PopupMenu*) popup;
       
   802 	if ( r == id[ IdInsert ] )
       
   803 	    beginInsert();
       
   804 	else if ( r == id[ IdUpdate ] ) {
       
   805 	    if ( beginEdit( currentRow(), currentColumn(), false ) )
       
   806 		setEditMode( Editing, currentRow(), currentColumn() );
       
   807 	    else
       
   808 		endUpdate();
       
   809 	}
       
   810 	else if ( r == id[ IdDelete ] )
       
   811 	    deleteCurrent();
       
   812 	e->accept();
       
   813     }
       
   814 }
       
   815 
       
   816 /*! \reimp */
       
   817 void Q3DataTable::contentsMousePressEvent( QMouseEvent* e )
       
   818 {
       
   819     Q3Table::contentsMousePressEvent( e );
       
   820 }
       
   821 
       
   822 /*! \reimp */
       
   823 QWidget* Q3DataTable::beginEdit ( int row, int col, bool replace )
       
   824 {
       
   825     d->editRow = -1;
       
   826     d->editCol = -1;
       
   827     if ( !sqlCursor() )
       
   828 	return 0;
       
   829     if ( d->dat.mode() == QSql::Insert && !sqlCursor()->canInsert() )
       
   830 	return 0;
       
   831     if ( d->dat.mode() == QSql::Update && !sqlCursor()->canUpdate() )
       
   832 	return 0;
       
   833     d->editRow = row;
       
   834     d->editCol = col;
       
   835     if ( d->continuousEdit ) {
       
   836 	// see comment in beginInsert()
       
   837 	bool fakeReadOnly = isColumnReadOnly( col );
       
   838 	setColumnReadOnly( col, false );
       
   839 	QWidget* w = Q3Table::beginEdit( row, col, replace );
       
   840 	setColumnReadOnly( col, fakeReadOnly );
       
   841 	return w;
       
   842     }
       
   843     if ( d->dat.mode() == QSql::None && sqlCursor()->canUpdate() && sqlCursor()->primaryIndex().count() > 0 )
       
   844 	return beginUpdate( row, col, replace );
       
   845     return 0;
       
   846 }
       
   847 
       
   848 /*! \reimp */
       
   849 void Q3DataTable::endEdit( int row, int col, bool, bool )
       
   850 {
       
   851     bool accept = autoEdit() && !d->cancelInsert && !d->cancelUpdate;
       
   852 
       
   853     QWidget *editor = cellWidget( row, col );
       
   854     if ( !editor )
       
   855 	return;
       
   856     if ( d->cancelMode )
       
   857 	return;
       
   858     if ( d->dat.mode() != QSql::None && d->editBuffer ) {
       
   859 	Q3SqlPropertyMap * m = (d->propertyMap == 0) ?
       
   860 			      Q3SqlPropertyMap::defaultMap() : d->propertyMap;
       
   861 	d->editBuffer->setValue( indexOf( col ), m->property( editor ) );
       
   862 	clearCellWidget( row, col );
       
   863 	if ( !d->continuousEdit ) {
       
   864 	    switch ( d->dat.mode() ) {
       
   865 	    case QSql::Insert:
       
   866 		if ( accept )
       
   867 		    QTimer::singleShot( 0, this, SLOT(doInsertCurrent()) );
       
   868 		else
       
   869 		    endInsert();
       
   870 		break;
       
   871 	    case QSql::Update:
       
   872 		if ( accept )
       
   873 		    QTimer::singleShot( 0, this, SLOT(doUpdateCurrent()) );
       
   874 		else
       
   875 		    endUpdate();
       
   876 		break;
       
   877 	    default:
       
   878 		break;
       
   879 	    }
       
   880 	}
       
   881     } else {
       
   882 	setEditMode( NotEditing, -1, -1 );
       
   883     }
       
   884     if ( d->dat.mode() == QSql::None )
       
   885 	viewport()->setFocus();
       
   886     updateCell( row, col );
       
   887     emit valueChanged( row, col );
       
   888 }
       
   889 
       
   890 /*! \internal */
       
   891 void Q3DataTable::doInsertCurrent()
       
   892 {
       
   893     insertCurrent();
       
   894 }
       
   895 
       
   896 /*! \internal */
       
   897 void Q3DataTable::doUpdateCurrent()
       
   898 {
       
   899     updateCurrent();
       
   900     if ( d->dat.mode() == QSql::None ) {
       
   901 	viewport()->setFocus();
       
   902     }
       
   903 }
       
   904 
       
   905 /*! \reimp */
       
   906 void Q3DataTable::activateNextCell()
       
   907 {
       
   908 //     if ( d->dat.mode() == QSql::None )
       
   909 //	Q3Table::activateNextCell();
       
   910 }
       
   911 
       
   912 /*! \internal
       
   913 */
       
   914 
       
   915 void Q3DataTable::endInsert()
       
   916 {
       
   917     if ( d->dat.mode() != QSql::Insert )
       
   918 	return;
       
   919     d->dat.setMode( QSql::None );
       
   920     d->editBuffer = 0;
       
   921     verticalHeader()->setLabel( d->editRow, QString::number( d->editRow +1 ) );
       
   922     d->editRow = -1;
       
   923     d->editCol = -1;
       
   924     d->insertRowLast = -1;
       
   925     d->insertHeaderLabelLast.clear();
       
   926     setEditMode( NotEditing, -1, -1 );
       
   927     setNumRows( d->insertPreRows );
       
   928     d->insertPreRows = -1;
       
   929     viewport()->setFocus();
       
   930 }
       
   931 
       
   932 /*! \internal
       
   933  */
       
   934 void Q3DataTable::endUpdate()
       
   935 {
       
   936     d->dat.setMode( QSql::None );
       
   937     d->editBuffer = 0;
       
   938     updateRow( d->editRow );
       
   939     d->editRow = -1;
       
   940     d->editCol = -1;
       
   941     setEditMode( NotEditing, -1, -1 );
       
   942 }
       
   943 
       
   944 /*!
       
   945   Protected virtual function called when editing is about to begin
       
   946   on a new record. If the table is read-only, or if there's no cursor
       
   947   or the cursor does not allow inserts, nothing happens and false
       
   948   is returned. Otherwise returns true.
       
   949   
       
   950   Editing takes place using the cursor's edit buffer(see
       
   951   Q3SqlCursor::editBuffer()).
       
   952   
       
   953   When editing begins, a new row is created in the table marked with
       
   954   an asterisk '*' in the row's vertical header column, i.e. at the
       
   955   left of the row.
       
   956 */
       
   957 bool Q3DataTable::beginInsert()
       
   958 {
       
   959     if ( !sqlCursor() || isReadOnly() || !numCols() )
       
   960 	return false;
       
   961     if ( !sqlCursor()->canInsert() )
       
   962 	return false;
       
   963     int i = 0;
       
   964     int row = currentRow();
       
   965 
       
   966     d->insertPreRows = numRows();
       
   967     if ( row < 0 || numRows() < 1 )
       
   968 	row = 0;
       
   969     setNumRows( d->insertPreRows + 1 );
       
   970     setCurrentCell( row, 0 );
       
   971     d->editBuffer = sqlCursor()->primeInsert();
       
   972     emit primeInsert( d->editBuffer );
       
   973     d->dat.setMode( QSql::Insert );
       
   974     int lastRow = row;
       
   975     int lastY = contentsY() + visibleHeight();
       
   976     for ( i = row; i < numRows() ; ++i ) {
       
   977 	QRect cg = cellGeometry( i, 0 );
       
   978 	if ( (cg.y()+cg.height()) > lastY ) {
       
   979 	    lastRow = i;
       
   980 	    break;
       
   981 	}
       
   982     }
       
   983     if ( lastRow == row && ( numRows()-1 > row ) )
       
   984 	lastRow = numRows() - 1;
       
   985     d->insertRowLast = lastRow;
       
   986     d->insertHeaderLabelLast = verticalHeader()->label( d->insertRowLast );
       
   987     verticalHeader()->setLabel( row, QString(QLatin1Char('*')) );
       
   988     d->editRow = row;
       
   989     // in the db world it's common to allow inserting new records
       
   990     // into a table that has read-only columns - temporarily
       
   991     // switch off read-only mode for such columns
       
   992     bool fakeReadOnly = isColumnReadOnly( 0 );
       
   993     setColumnReadOnly( 0, false );
       
   994     if ( Q3Table::beginEdit( row, 0, false ) )
       
   995 	setEditMode( Editing, row, 0 );
       
   996     setColumnReadOnly( 0, fakeReadOnly );
       
   997     return true;
       
   998 }
       
   999 
       
  1000 /*!
       
  1001     Protected virtual function called when editing is about to begin
       
  1002     on an existing row. If the table is read-only, or if there's no
       
  1003     cursor, nothing happens.
       
  1004 
       
  1005     Editing takes place using the cursor's edit buffer (see
       
  1006     Q3SqlCursor::editBuffer()).
       
  1007 
       
  1008     \a row and \a col refer to the row and column in the Q3DataTable.
       
  1009 
       
  1010     (\a replace is provided for reimplementors and reflects the API of
       
  1011     Q3Table::beginEdit().)
       
  1012 */
       
  1013 
       
  1014 QWidget* Q3DataTable::beginUpdate ( int row, int col, bool replace )
       
  1015 {
       
  1016     if ( !sqlCursor() || isReadOnly() || isColumnReadOnly( col ) )
       
  1017 	return 0;
       
  1018     setCurrentCell( row, col );
       
  1019     d->dat.setMode( QSql::Update );
       
  1020     if ( sqlCursor()->seek( row ) ) {
       
  1021 	d->editBuffer = sqlCursor()->primeUpdate();
       
  1022 	sqlCursor()->seek( currentRow() );
       
  1023 	emit primeUpdate( d->editBuffer );
       
  1024 	return Q3Table::beginEdit( row, col, replace );
       
  1025     }
       
  1026     return 0;
       
  1027 }
       
  1028 
       
  1029 /*!
       
  1030     For an editable table, issues an insert on the current cursor
       
  1031     using the values in the cursor's edit buffer. If there is no
       
  1032     current cursor or there is no current "insert" row, nothing
       
  1033     happens. If confirmEdits() or confirmInsert() is true,
       
  1034     confirmEdit() is called to confirm the insert. Returns true if the
       
  1035     insert succeeded; otherwise returns false.
       
  1036 
       
  1037     The underlying cursor must have a valid primary index to ensure
       
  1038     that a unique record is inserted within the database otherwise the
       
  1039     database may be changed to an inconsistent state.
       
  1040 */
       
  1041 
       
  1042 bool Q3DataTable::insertCurrent()
       
  1043 {
       
  1044     if ( d->dat.mode() != QSql::Insert || ! numCols() )
       
  1045 	return false;
       
  1046     if ( !sqlCursor()->canInsert() ) {
       
  1047 #ifdef QT_CHECK_RANGE
       
  1048 	qWarning("Q3DataTable::insertCurrent: insert not allowed for %s",
       
  1049 		 sqlCursor()->name().latin1() );
       
  1050 #endif
       
  1051 	endInsert();
       
  1052 	return false;
       
  1053     }
       
  1054     int b = 0;
       
  1055     int conf = QSql::Yes;
       
  1056     if ( confirmEdits() || confirmInsert() )
       
  1057 	conf = confirmEdit( QSql::Insert );
       
  1058     switch ( conf ) {
       
  1059     case QSql::Yes: {
       
  1060 #ifndef QT_NO_CURSOR
       
  1061 	QApplication::setOverrideCursor( Qt::waitCursor );
       
  1062 #endif
       
  1063 	emit beforeInsert( d->editBuffer );
       
  1064 	b = sqlCursor()->insert();
       
  1065 #ifndef QT_NO_CURSOR
       
  1066 	QApplication::restoreOverrideCursor();
       
  1067 #endif
       
  1068 	if ( ( !b && !sqlCursor()->isActive() ) || !sqlCursor()->isActive() ) {
       
  1069 	    handleError( sqlCursor()->lastError() );
       
  1070 	    endInsert(); // cancel the insert if anything goes wrong
       
  1071 	    refresh();
       
  1072 	} else {
       
  1073 	    endInsert();
       
  1074 	    refresh();
       
  1075 	    QSqlIndex idx = sqlCursor()->primaryIndex();
       
  1076 	    findBuffer( idx, d->lastAt );
       
  1077 	    repaintContents( contentsX(), contentsY(), visibleWidth(), visibleHeight(), false );
       
  1078 	    emit cursorChanged( QSql::Insert );
       
  1079 	}
       
  1080 	break;
       
  1081     }
       
  1082     case QSql::No:
       
  1083 	endInsert();
       
  1084 	break;
       
  1085     case QSql::Cancel:
       
  1086 	if ( Q3Table::beginEdit( currentRow(), currentColumn(), false ) )
       
  1087 	    setEditMode( Editing, currentRow(), currentColumn() );
       
  1088 	break;
       
  1089     }
       
  1090     return ( b > 0 );
       
  1091 }
       
  1092 
       
  1093 /*! \internal
       
  1094 
       
  1095   Updates the row \a row.
       
  1096 */
       
  1097 
       
  1098 void Q3DataTable::updateRow( int row )
       
  1099 {
       
  1100     for ( int i = 0; i < numCols(); ++i )
       
  1101 	updateCell( row, i );
       
  1102 }
       
  1103 
       
  1104 /*!
       
  1105     For an editable table, issues an update using the cursor's edit
       
  1106     buffer. If there is no current cursor or there is no current
       
  1107     selection, nothing happens. If confirmEdits() or confirmUpdate()
       
  1108     is true, confirmEdit() is called to confirm the update. Returns
       
  1109     true if the update succeeded; otherwise returns false.
       
  1110 
       
  1111     The underlying cursor must have a valid primary index to ensure
       
  1112     that a unique record is updated within the database otherwise the
       
  1113     database may be changed to an inconsistent state.
       
  1114 */
       
  1115 
       
  1116 bool Q3DataTable::updateCurrent()
       
  1117 {
       
  1118     if ( d->dat.mode() != QSql::Update )
       
  1119 	return false;
       
  1120     if ( sqlCursor()->primaryIndex().count() == 0 ) {
       
  1121 #ifdef QT_CHECK_RANGE
       
  1122 	qWarning("Q3DataTable::updateCurrent: no primary index for %s",
       
  1123 		 sqlCursor()->name().latin1() );
       
  1124 #endif
       
  1125 	endUpdate();
       
  1126 	return false;
       
  1127     }
       
  1128     if ( !sqlCursor()->canUpdate() ) {
       
  1129 #ifdef QT_CHECK_RANGE
       
  1130 	qWarning("Q3DataTable::updateCurrent: updates not allowed for %s",
       
  1131 		 sqlCursor()->name().latin1() );
       
  1132 #endif
       
  1133 	endUpdate();
       
  1134 	return false;
       
  1135     }
       
  1136     int b = 0;
       
  1137     int conf = QSql::Yes;
       
  1138     if ( confirmEdits() || confirmUpdate() )
       
  1139 	conf = confirmEdit( QSql::Update );
       
  1140     switch ( conf ) {
       
  1141     case QSql::Yes: {
       
  1142 #ifndef QT_NO_CURSOR
       
  1143 	QApplication::setOverrideCursor( Qt::waitCursor );
       
  1144 #endif
       
  1145 	emit beforeUpdate( d->editBuffer );
       
  1146 	b = sqlCursor()->update();
       
  1147 #ifndef QT_NO_CURSOR
       
  1148 	QApplication::restoreOverrideCursor();
       
  1149 #endif
       
  1150 	if ( ( !b && !sqlCursor()->isActive() ) || !sqlCursor()->isActive() ) {
       
  1151 	    handleError( sqlCursor()->lastError() );
       
  1152 	    endUpdate();
       
  1153 	    refresh();
       
  1154 	    setCurrentCell( d->editRow, d->editCol );
       
  1155 	    if ( Q3Table::beginEdit( d->editRow, d->editCol, false ) )
       
  1156 		setEditMode( Editing, d->editRow, d->editCol );
       
  1157 	} else {
       
  1158 	    emit cursorChanged( QSql::Update );
       
  1159 	    refresh();
       
  1160 	    endUpdate();
       
  1161 	}
       
  1162 	break;
       
  1163     }
       
  1164     case QSql::No:
       
  1165 	endUpdate();
       
  1166 	setEditMode( NotEditing, -1, -1 );
       
  1167 	break;
       
  1168     case QSql::Cancel:
       
  1169 	setCurrentCell( d->editRow, d->editCol );
       
  1170 	if ( Q3Table::beginEdit( d->editRow, d->editCol, false ) )
       
  1171 	    setEditMode( Editing, d->editRow, d->editCol );
       
  1172 	break;
       
  1173     }
       
  1174     return ( b > 0 );
       
  1175 }
       
  1176 
       
  1177 /*!
       
  1178     For an editable table, issues a delete on the current cursor's
       
  1179     primary index using the values of the currently selected row. If
       
  1180     there is no current cursor or there is no current selection,
       
  1181     nothing happens. If confirmEdits() or confirmDelete() is true,
       
  1182     confirmEdit() is called to confirm the delete. Returns true if the
       
  1183     delete succeeded; otherwise false.
       
  1184 
       
  1185     The underlying cursor must have a valid primary index to ensure
       
  1186     that a unique record is deleted within the database otherwise the
       
  1187     database may be changed to an inconsistent state.
       
  1188 */
       
  1189 
       
  1190 bool Q3DataTable::deleteCurrent()
       
  1191 {
       
  1192     if ( !sqlCursor() || isReadOnly() )
       
  1193 	return false;
       
  1194     if ( sqlCursor()->primaryIndex().count() == 0 ) {
       
  1195 #ifdef QT_CHECK_RANGE
       
  1196 	qWarning("Q3DataTable::deleteCurrent: no primary index %s",
       
  1197 		 sqlCursor()->name().latin1() );
       
  1198 #endif
       
  1199 	return false;
       
  1200     }
       
  1201     if ( !sqlCursor()->canDelete() )
       
  1202 	return false;
       
  1203 
       
  1204     int b = 0;
       
  1205     int conf = QSql::Yes;
       
  1206     if ( confirmEdits() || confirmDelete() )
       
  1207 	conf = confirmEdit( QSql::Delete );
       
  1208 
       
  1209     // Have to have this here - the confirmEdit() might pop up a
       
  1210     // dialog that causes a repaint which the cursor to the
       
  1211     // record it has to repaint.
       
  1212     if ( !sqlCursor()->seek( currentRow() ) )
       
  1213 	return false;
       
  1214     switch ( conf ) {
       
  1215 	case QSql::Yes:{
       
  1216 #ifndef QT_NO_CURSOR
       
  1217 	    QApplication::setOverrideCursor( Qt::waitCursor );
       
  1218 #endif
       
  1219 	    sqlCursor()->primeDelete();
       
  1220 	    emit primeDelete( sqlCursor()->editBuffer() );
       
  1221 	    emit beforeDelete( sqlCursor()->editBuffer() );
       
  1222 	    b = sqlCursor()->del();
       
  1223 #ifndef QT_NO_CURSOR
       
  1224 	    QApplication::restoreOverrideCursor();
       
  1225 #endif
       
  1226 	    if ( !b )
       
  1227 		handleError( sqlCursor()->lastError() );
       
  1228 	    refresh();
       
  1229 	    emit cursorChanged( QSql::Delete );
       
  1230 	    setCurrentCell( currentRow(), currentColumn() );
       
  1231 	    repaintContents( contentsX(), contentsY(), visibleWidth(), visibleHeight(), false );
       
  1232 	    verticalHeader()->repaint(); // get rid of trailing garbage
       
  1233 	}
       
  1234 	break;
       
  1235     case QSql::No:
       
  1236 	setEditMode( NotEditing, -1, -1 );
       
  1237 	break;
       
  1238     }
       
  1239     return ( b > 0 );
       
  1240 }
       
  1241 
       
  1242 /*!
       
  1243     Protected virtual function which returns a confirmation for an
       
  1244     edit of mode \a m. Derived classes can reimplement this function
       
  1245     to provide their own confirmation dialog. The default
       
  1246     implementation uses a message box which prompts the user to
       
  1247     confirm the edit action.
       
  1248 */
       
  1249 
       
  1250 QSql::Confirm Q3DataTable::confirmEdit( QSql::Op m )
       
  1251 {
       
  1252     return d->dat.confirmEdit( this, m );
       
  1253 }
       
  1254 
       
  1255 /*!
       
  1256     Protected virtual function which returns a confirmation for
       
  1257     canceling an edit mode of \a m. Derived classes can reimplement
       
  1258     this function to provide their own cancel dialog. The default
       
  1259     implementation uses a message box which prompts the user to
       
  1260     confirm the cancel.
       
  1261 */
       
  1262 
       
  1263 QSql::Confirm  Q3DataTable::confirmCancel( QSql::Op m )
       
  1264 {
       
  1265     return d->dat.confirmCancel( this, m );
       
  1266 }
       
  1267 
       
  1268 
       
  1269 /*!
       
  1270     Searches the current cursor for a cell containing the string \a
       
  1271     str starting at the current cell and working forwards (or
       
  1272     backwards if \a backwards is true). If the string is found, the
       
  1273     cell containing the string is set as the current cell. If \a
       
  1274     caseSensitive is false the case of \a str will be ignored.
       
  1275 
       
  1276     The search will wrap, i.e. if the first (or if backwards is true,
       
  1277     last) cell is reached without finding \a str the search will
       
  1278     continue until it reaches the starting cell. If \a str is not
       
  1279     found the search will fail and the current cell will remain
       
  1280     unchanged.
       
  1281 */
       
  1282 void Q3DataTable::find( const QString & str, bool caseSensitive, bool backwards )
       
  1283 {
       
  1284     if ( !sqlCursor() )
       
  1285 	return;
       
  1286 
       
  1287     Q3SqlCursor * r = sqlCursor();
       
  1288     QString tmp, text;
       
  1289     uint  row = currentRow(), startRow = row,
       
  1290 	  col = backwards ? currentColumn() - 1 : currentColumn() + 1;
       
  1291     bool  wrap = true, found = false;
       
  1292 
       
  1293     if( str.isEmpty() || str.isNull() )
       
  1294 	return;
       
  1295 
       
  1296     if( !caseSensitive )
       
  1297 	tmp = str.lower();
       
  1298     else
       
  1299 	tmp = str;
       
  1300 
       
  1301 #ifndef QT_NO_CURSOR
       
  1302     QApplication::setOverrideCursor( Qt::waitCursor );
       
  1303 #endif
       
  1304     while( wrap ){
       
  1305 	while( !found && r->seek( row ) ){
       
  1306 	    for( int i = col; backwards ? (i >= 0) : (i < (int) numCols());
       
  1307 		 backwards ? i-- : i++ )
       
  1308 	    {
       
  1309 		text = r->value( indexOf( i ) ).toString();
       
  1310 		if( !caseSensitive ){
       
  1311 		    text = text.lower();
       
  1312 		}
       
  1313 		if( text.contains( tmp ) ){
       
  1314 		    setCurrentCell( row, i );
       
  1315 		    col = i;
       
  1316 		    found = true;
       
  1317 		}
       
  1318 	    }
       
  1319 	    if( !backwards ){
       
  1320 		col = 0;
       
  1321 		row++;
       
  1322 	    } else {
       
  1323 		col = numCols() - 1;
       
  1324 		row--;
       
  1325 	    }
       
  1326 	}
       
  1327 	if( !backwards ){
       
  1328 	    if( startRow != 0 ){
       
  1329 		startRow = 0;
       
  1330 	    } else {
       
  1331 		wrap = false;
       
  1332 	    }
       
  1333 	    r->first();
       
  1334 	    row = 0;
       
  1335 	} else {
       
  1336 	    if( startRow != (uint) (numRows() - 1) ){
       
  1337 		startRow = numRows() - 1;
       
  1338 	    } else {
       
  1339 		wrap = false;
       
  1340 	    }
       
  1341 	    r->last();
       
  1342 	    row = numRows() - 1;
       
  1343 	}
       
  1344     }
       
  1345 #ifndef QT_NO_CURSOR
       
  1346     QApplication::restoreOverrideCursor();
       
  1347 #endif
       
  1348 }
       
  1349 
       
  1350 
       
  1351 /*!
       
  1352     Resets the table so that it displays no data.
       
  1353 
       
  1354     \sa setSqlCursor()
       
  1355 */
       
  1356 
       
  1357 void Q3DataTable::reset()
       
  1358 {
       
  1359     clearCellWidget( currentRow(), currentColumn() );
       
  1360     switch ( d->dat.mode() ) {
       
  1361     case QSql::Insert:
       
  1362 	endInsert();
       
  1363 	break;
       
  1364     case QSql::Update:
       
  1365 	endUpdate();
       
  1366 	break;
       
  1367     default:
       
  1368 	break;
       
  1369     }
       
  1370     ensureVisible( 0, 0 );
       
  1371     verticalScrollBar()->setValue(0);
       
  1372     setNumRows(0);
       
  1373 
       
  1374     d->haveAllRows = false;
       
  1375     d->continuousEdit = false;
       
  1376     d->dat.setMode( QSql::None );
       
  1377     d->editRow = -1;
       
  1378     d->editCol = -1;
       
  1379     d->insertRowLast = -1;
       
  1380     d->insertHeaderLabelLast.clear();
       
  1381     d->cancelMode = false;
       
  1382     d->lastAt = -1;
       
  1383     d->fld.clear();
       
  1384     d->fldLabel.clear();
       
  1385     d->fldWidth.clear();
       
  1386     d->fldIcon.clear();
       
  1387     d->fldHidden.clear();
       
  1388     if ( sorting() )
       
  1389 	horizontalHeader()->setSortIndicator( -1 );
       
  1390 }
       
  1391 
       
  1392 /*!
       
  1393     Returns the index of the field within the current SQL query that
       
  1394     is displayed in column \a i.
       
  1395 */
       
  1396 
       
  1397 int Q3DataTable::indexOf( uint i ) const
       
  1398 {
       
  1399     Q3DataTablePrivate::ColIndex::ConstIterator it = d->colIndex.at( i );
       
  1400     if ( it != d->colIndex.end() )
       
  1401 	return *it;
       
  1402     return -1;
       
  1403 }
       
  1404 
       
  1405 /*!
       
  1406     Returns true if the table will automatically delete the cursor
       
  1407     specified by setSqlCursor(); otherwise returns false.
       
  1408 */
       
  1409 
       
  1410 bool Q3DataTable::autoDelete() const
       
  1411 {
       
  1412     return d->cur.autoDelete();
       
  1413 }
       
  1414 
       
  1415 /*!
       
  1416     Sets the cursor auto-delete flag to \a enable. If \a enable is
       
  1417     true, the table will automatically delete the cursor specified by
       
  1418     setSqlCursor(). If \a enable is false (the default), the cursor
       
  1419     will not be deleted.
       
  1420 */
       
  1421 
       
  1422 void Q3DataTable::setAutoDelete( bool enable )
       
  1423 {
       
  1424     d->cur.setAutoDelete( enable );
       
  1425 }
       
  1426 
       
  1427 /*!
       
  1428     \property Q3DataTable::autoEdit
       
  1429     \brief whether the data table automatically applies edits
       
  1430 
       
  1431     The default value for this property is true. When the user begins
       
  1432     an insert or update in the table there are two possible outcomes
       
  1433     when they navigate to another record:
       
  1434 
       
  1435     \list 1
       
  1436     \i the insert or update is is performed -- this occurs if autoEdit is true
       
  1437     \i the insert or update is abandoned -- this occurs if autoEdit is false
       
  1438     \endlist
       
  1439 */
       
  1440 
       
  1441 void Q3DataTable::setAutoEdit( bool autoEdit )
       
  1442 {
       
  1443     d->dat.setAutoEdit( autoEdit );
       
  1444 }
       
  1445 
       
  1446 bool Q3DataTable::autoEdit() const
       
  1447 {
       
  1448     return d->dat.autoEdit();
       
  1449 }
       
  1450 
       
  1451 /*!
       
  1452     \property Q3DataTable::nullText
       
  1453     \brief the text used to represent NULL values
       
  1454 
       
  1455     The nullText property will be used to represent NULL values in the
       
  1456     table. The default value is provided by the cursor's driver.
       
  1457 */
       
  1458 
       
  1459 void Q3DataTable::setNullText( const QString& nullText )
       
  1460 {
       
  1461     d->nullTxt = nullText;
       
  1462     d->nullTxtChanged = true;
       
  1463 }
       
  1464 
       
  1465 QString Q3DataTable::nullText() const
       
  1466 {
       
  1467     return d->nullTxt;
       
  1468 }
       
  1469 
       
  1470 /*!
       
  1471     \property Q3DataTable::trueText
       
  1472     \brief the text used to represent true values
       
  1473 
       
  1474     The trueText property will be used to represent NULL values in the
       
  1475     table. The default value is "True".
       
  1476 */
       
  1477 
       
  1478 void Q3DataTable::setTrueText( const QString& trueText )
       
  1479 {
       
  1480     d->trueTxt = trueText;
       
  1481 }
       
  1482 
       
  1483 QString Q3DataTable::trueText() const
       
  1484 {
       
  1485     return d->trueTxt;
       
  1486 }
       
  1487 
       
  1488 /*!
       
  1489     \property Q3DataTable::falseText
       
  1490     \brief the text used to represent false values
       
  1491 
       
  1492     The falseText property will be used to represent NULL values in
       
  1493     the table. The default value is "False".
       
  1494 */
       
  1495 
       
  1496 void Q3DataTable::setFalseText( const QString& falseText )
       
  1497 {
       
  1498     d->falseTxt = falseText;
       
  1499 }
       
  1500 
       
  1501 QString Q3DataTable::falseText() const
       
  1502 {
       
  1503     return d->falseTxt;
       
  1504 }
       
  1505 
       
  1506 /*!
       
  1507     \property Q3DataTable::dateFormat
       
  1508     \brief the format used for displaying date/time values
       
  1509 
       
  1510     The dateFormat property is used for displaying date/time values in
       
  1511     the table. The default value is Qt::LocalDate.
       
  1512 */
       
  1513 
       
  1514 void Q3DataTable::setDateFormat( const Qt::DateFormat f )
       
  1515 {
       
  1516     d->datefmt = f;
       
  1517 }
       
  1518 
       
  1519 Qt::DateFormat Q3DataTable::dateFormat() const
       
  1520 {
       
  1521     return d->datefmt;
       
  1522 }
       
  1523 
       
  1524 /*!
       
  1525     \property Q3DataTable::numRows
       
  1526 
       
  1527     \brief the number of rows in the table
       
  1528 */
       
  1529 
       
  1530 int Q3DataTable::numRows() const
       
  1531 {
       
  1532     return Q3Table::numRows();
       
  1533 }
       
  1534 
       
  1535 /*!
       
  1536     \reimp
       
  1537 
       
  1538     The number of rows in the table will be determined by the cursor
       
  1539     (see setSqlCursor()), so normally this function should never be
       
  1540     called. It is included for completeness.
       
  1541 */
       
  1542 
       
  1543 void Q3DataTable::setNumRows ( int r )
       
  1544 {
       
  1545     Q3Table::setNumRows( r );
       
  1546 }
       
  1547 
       
  1548 /*!
       
  1549     \reimp
       
  1550 
       
  1551     The number of columns in the table will be determined
       
  1552     automatically (see addColumn()), so normally this function should
       
  1553     never be called. It is included for completeness.
       
  1554 */
       
  1555 
       
  1556 void Q3DataTable::setNumCols ( int r )
       
  1557 {
       
  1558     Q3Table::setNumCols( r );
       
  1559 }
       
  1560 
       
  1561 /*!
       
  1562     \property Q3DataTable::numCols
       
  1563 
       
  1564     \brief the number of columns in the table
       
  1565 */
       
  1566 
       
  1567 int Q3DataTable::numCols() const
       
  1568 {
       
  1569     return Q3Table::numCols();
       
  1570 }
       
  1571 
       
  1572 /*!
       
  1573     Returns the text in cell \a row, \a col, or an empty string if the
       
  1574     cell is empty. If the cell's value is NULL then nullText() will be
       
  1575     returned. If the cell does not exist then an empty string is
       
  1576     returned.
       
  1577 */
       
  1578 
       
  1579 QString Q3DataTable::text ( int row, int col ) const
       
  1580 {
       
  1581     if ( !sqlCursor() )
       
  1582 	return QString();
       
  1583 
       
  1584     QString s;
       
  1585     if ( sqlCursor()->seek( row ) )
       
  1586 	s = sqlCursor()->value( indexOf( col ) ).toString();
       
  1587     sqlCursor()->seek( currentRow() );
       
  1588     return s;
       
  1589 }
       
  1590 
       
  1591 /*!
       
  1592     Returns the value in cell \a row, \a col, or an invalid value if
       
  1593     the cell does not exist or has no value.
       
  1594 */
       
  1595 
       
  1596 QVariant Q3DataTable::value ( int row, int col ) const
       
  1597 {
       
  1598     if ( !sqlCursor() )
       
  1599 	return QVariant();
       
  1600 
       
  1601     QVariant v;
       
  1602     if ( sqlCursor()->seek( row ) )
       
  1603 	v = sqlCursor()->value( indexOf( col ) );
       
  1604     sqlCursor()->seek( currentRow() );
       
  1605     return v;
       
  1606 }
       
  1607 
       
  1608 /*!  \internal
       
  1609   Used to update the table when the size of the result set cannot be
       
  1610   determined - divide the result set into pages and load the pages as
       
  1611   the user moves around in the table.
       
  1612 */
       
  1613 void Q3DataTable::loadNextPage()
       
  1614 {
       
  1615     if ( d->haveAllRows )
       
  1616 	return;
       
  1617     if ( !sqlCursor() )
       
  1618 	return;
       
  1619     int pageSize = 0;
       
  1620     int lookAhead = 0;
       
  1621     if ( height() ) {
       
  1622 	pageSize = (int)( height() * 2 / 20 );
       
  1623 	lookAhead = pageSize / 2;
       
  1624     }
       
  1625     int startIdx = verticalScrollBar()->value() / 20;
       
  1626     int endIdx = startIdx + pageSize + lookAhead;
       
  1627     if ( endIdx < numRows() || endIdx < 0 )
       
  1628 	return;
       
  1629 
       
  1630     // check for empty result set
       
  1631     if ( sqlCursor()->at() == QSql::BeforeFirst && !sqlCursor()->next() ) {
       
  1632 	d->haveAllRows = true;
       
  1633 	return;
       
  1634     }
       
  1635 
       
  1636     while ( endIdx > 0 && !sqlCursor()->seek( endIdx ) )
       
  1637 	endIdx--;
       
  1638     if ( endIdx != ( startIdx + pageSize + lookAhead ) )
       
  1639 	d->haveAllRows = true;
       
  1640     // small hack to prevent Q3Table from moving the view when a row
       
  1641     // is selected and the contents is resized
       
  1642     SelectionMode m = selectionMode();
       
  1643     clearSelection();
       
  1644     setSelectionMode( NoSelection );
       
  1645     setNumRows( endIdx ? endIdx + 1 : 0 );
       
  1646     sqlCursor()->seek( currentRow() );
       
  1647     setSelectionMode( m );
       
  1648 }
       
  1649 
       
  1650 /*! \internal */
       
  1651 void Q3DataTable::sliderPressed()
       
  1652 {
       
  1653     disconnect( verticalScrollBar(), SIGNAL(valueChanged(int)),
       
  1654 		this, SLOT(loadNextPage()) );
       
  1655 }
       
  1656 
       
  1657 /*! \internal */
       
  1658 void Q3DataTable::sliderReleased()
       
  1659 {
       
  1660     loadNextPage();
       
  1661     connect( verticalScrollBar(), SIGNAL(valueChanged(int)),
       
  1662 	     this, SLOT(loadNextPage()) );
       
  1663 }
       
  1664 
       
  1665 /*!
       
  1666     Sorts column \a col in ascending order if \a ascending is true
       
  1667     (the default); otherwise sorts in descending order.
       
  1668 
       
  1669     The \a wholeRows parameter is ignored; Q3DataTable always sorts
       
  1670     whole rows by the specified column.
       
  1671 */
       
  1672 
       
  1673 void Q3DataTable::sortColumn ( int col, bool ascending,
       
  1674 			      bool  )
       
  1675 {
       
  1676     if ( sorting() ) {
       
  1677 	if ( isEditing() && d->dat.mode() != QSql::None )
       
  1678 	    endEdit( d->editRow, d->editCol, autoEdit(), false );
       
  1679 	if ( !sqlCursor() )
       
  1680 	    return;
       
  1681 	QSqlIndex lastSort = sqlCursor()->sort();
       
  1682 	QSqlIndex newSort( lastSort.cursorName(), QLatin1String("newSort") );
       
  1683 	const QSqlField *field = sqlCursor()->fieldPtr( indexOf( col ) );
       
  1684 	if ( field )
       
  1685 	    newSort.append( *field );
       
  1686 	newSort.setDescending( 0, !ascending );
       
  1687 	horizontalHeader()->setSortIndicator( col, ascending );
       
  1688 	setSort( newSort );
       
  1689 	refresh();
       
  1690     }
       
  1691 }
       
  1692 
       
  1693 /*! \reimp */
       
  1694 void Q3DataTable::columnClicked ( int col )
       
  1695 {
       
  1696     if ( sorting() ) {
       
  1697 	if ( !sqlCursor() )
       
  1698 	    return;
       
  1699 	QSqlIndex lastSort = sqlCursor()->sort();
       
  1700 	bool asc = true;
       
  1701 	if ( lastSort.count() && lastSort.fieldPtr( 0 )->name() == sqlCursor()->fieldPtr( indexOf( col ) )->name() )
       
  1702 	    asc = lastSort.isDescending( 0 );
       
  1703 	sortColumn( col, asc );
       
  1704 	emit currentChanged( sqlCursor() );
       
  1705     }
       
  1706 }
       
  1707 
       
  1708 /*!
       
  1709     Repaints the cell at \a row, \a col.
       
  1710 */
       
  1711 void Q3DataTable::repaintCell( int row, int col )
       
  1712 {
       
  1713     QRect cg = cellGeometry( row, col );
       
  1714     QRect re( QPoint( cg.x() - 2, cg.y() - 2 ),
       
  1715 	      QSize( cg.width() + 4, cg.height() + 4 ) );
       
  1716     repaintContents( re, false );
       
  1717 }
       
  1718 
       
  1719 /*!
       
  1720     \reimp
       
  1721 
       
  1722     This function renders the cell at \a row, \a col with the value of
       
  1723     the corresponding cursor field on the painter \a p. Depending on
       
  1724     the table's current edit mode, paintField() is called for the
       
  1725     appropriate cursor field. \a cr describes the cell coordinates in
       
  1726     the content coordinate system. If \a selected is true the cell has
       
  1727     been selected and would normally be rendered differently than an
       
  1728     unselected cell.
       
  1729 */
       
  1730 
       
  1731 void Q3DataTable::paintCell( QPainter * p, int row, int col, const QRect & cr,
       
  1732 			  bool selected, const QColorGroup &cg )
       
  1733 {
       
  1734     Q3Table::paintCell( p, row, col, cr, selected, cg );  // empty cell
       
  1735 
       
  1736     if ( !sqlCursor() )
       
  1737 	return;
       
  1738 
       
  1739     p->setPen( selected ? cg.highlightedText() : cg.text() );
       
  1740     if ( d->dat.mode() != QSql::None ) {
       
  1741 	if ( row == d->editRow && d->editBuffer ) {
       
  1742 	    paintField( p, d->editBuffer->fieldPtr( indexOf( col ) ), cr,
       
  1743 			selected );
       
  1744 	} else if ( row > d->editRow && d->dat.mode() == QSql::Insert ) {
       
  1745 	    if ( sqlCursor()->seek( row - 1 ) )
       
  1746 		paintField( p, sqlCursor()->fieldPtr( indexOf( col ) ), cr,
       
  1747 			    selected );
       
  1748 	} else {
       
  1749 	    if ( sqlCursor()->seek( row ) )
       
  1750 		paintField( p, sqlCursor()->fieldPtr( indexOf( col ) ), cr,
       
  1751 			    selected );
       
  1752 	}
       
  1753     } else {
       
  1754 	if ( sqlCursor()->seek( row ) )
       
  1755 		paintField( p, sqlCursor()->fieldPtr( indexOf( col ) ), cr, selected );
       
  1756 
       
  1757     }
       
  1758 }
       
  1759 
       
  1760 
       
  1761 /*!
       
  1762     Paints the \a field on the painter \a p. The painter has already
       
  1763     been translated to the appropriate cell's origin where the \a
       
  1764     field is to be rendered. \a cr describes the cell coordinates in
       
  1765     the content coordinate system. The \a selected parameter is
       
  1766     ignored.
       
  1767 
       
  1768     If you want to draw custom field content you must reimplement
       
  1769     paintField() to do the custom drawing. The default implementation
       
  1770     renders the \a field value as text. If the field is NULL,
       
  1771     nullText() is displayed in the cell. If the field is Boolean,
       
  1772     trueText() or falseText() is displayed as appropriate.
       
  1773 */
       
  1774 
       
  1775 void Q3DataTable::paintField( QPainter * p, const QSqlField* field,
       
  1776 			    const QRect & cr, bool )
       
  1777 {
       
  1778     if ( !field )
       
  1779 	return;
       
  1780     p->drawText( 2,2, cr.width()-4, cr.height()-4, fieldAlignment( field ), fieldToString( field ) );
       
  1781 }
       
  1782 
       
  1783 /*!
       
  1784     Returns the alignment for \a field.
       
  1785 */
       
  1786 
       
  1787 int Q3DataTable::fieldAlignment( const QSqlField* /*field*/ )
       
  1788 {
       
  1789     return Qt::AlignLeft | Qt::AlignVCenter; //## Reggie: add alignment to Q3Table
       
  1790 }
       
  1791 
       
  1792 
       
  1793 /*!
       
  1794     If the cursor's \a sql driver supports query sizes, the number of
       
  1795     rows in the table is set to the size of the query. Otherwise, the
       
  1796     table dynamically resizes itself as it is scrolled. If \a sql is
       
  1797     not active, it is made active by issuing a select() on the cursor
       
  1798     using the \a sql cursor's current filter and current sort.
       
  1799 */
       
  1800 
       
  1801 void Q3DataTable::setSize( Q3SqlCursor* sql )
       
  1802 {
       
  1803     // ### what are the connect/disconnect calls doing here!? move to refresh()
       
  1804     if ( sql->driver() && sql->driver()->hasFeature( QSqlDriver::QuerySize ) ) {
       
  1805 	setVScrollBarMode( Auto );
       
  1806  	disconnect( verticalScrollBar(), SIGNAL(sliderPressed()),
       
  1807 		    this, SLOT(sliderPressed()) );
       
  1808  	disconnect( verticalScrollBar(), SIGNAL(sliderReleased()),
       
  1809 		    this, SLOT(sliderReleased()) );
       
  1810 	disconnect( verticalScrollBar(), SIGNAL(valueChanged(int)),
       
  1811 		    this, SLOT(loadNextPage()) );
       
  1812 	if ( numRows() != sql->size() )
       
  1813 	    setNumRows( sql->size() );
       
  1814     } else {
       
  1815 	setVScrollBarMode( AlwaysOn );
       
  1816  	connect( verticalScrollBar(), SIGNAL(sliderPressed()),
       
  1817  		 this, SLOT(sliderPressed()) );
       
  1818  	connect( verticalScrollBar(), SIGNAL(sliderReleased()),
       
  1819  		 this, SLOT(sliderReleased()) );
       
  1820 	connect( verticalScrollBar(), SIGNAL(valueChanged(int)),
       
  1821 		 this, SLOT(loadNextPage()) );
       
  1822 	setNumRows(0);
       
  1823 	loadNextPage();
       
  1824     }
       
  1825 }
       
  1826 
       
  1827 /*!
       
  1828     Sets \a cursor as the data source for the table. To force the
       
  1829     display of the data from \a cursor, use refresh(). If \a
       
  1830     autoPopulate is true, columns are automatically created based upon
       
  1831     the fields in the \a cursor record. If \a autoDelete is true (the
       
  1832     default is false), the table will take ownership of the \a cursor
       
  1833     and delete it when appropriate. If the \a cursor is read-only, the
       
  1834     table becomes read-only. The table adopts the cursor's driver's
       
  1835     definition for representing NULL values as strings.
       
  1836 
       
  1837     \sa refresh() setReadOnly() setAutoDelete() QSqlDriver::nullText()
       
  1838 */
       
  1839 
       
  1840 void Q3DataTable::setSqlCursor( Q3SqlCursor* cursor, bool autoPopulate, bool autoDelete )
       
  1841 {
       
  1842     setUpdatesEnabled( false );
       
  1843     d->cur.setCursor( 0 );
       
  1844     if ( cursor ) {
       
  1845 	d->cur.setCursor( cursor, autoDelete );
       
  1846 	if ( autoPopulate ) {
       
  1847 	    d->fld.clear();
       
  1848 	    d->fldLabel.clear();
       
  1849 	    d->fldWidth.clear();
       
  1850 	    d->fldIcon.clear();
       
  1851 	    d->fldHidden.clear();
       
  1852 	    for ( int i = 0; i < sqlCursor()->count(); ++i ) {
       
  1853 		addColumn( sqlCursor()->fieldPtr( i )->name(), sqlCursor()->fieldPtr( i )->name() );
       
  1854 		setColumnReadOnly( i, sqlCursor()->fieldPtr( i )->isReadOnly() );
       
  1855 	    }
       
  1856 	}
       
  1857 	setReadOnly( sqlCursor()->isReadOnly() );
       
  1858 	if ( sqlCursor()->driver() && !d->nullTxtChanged )
       
  1859 	    setNullText(sqlCursor()->driver()->nullText() );
       
  1860 	setAutoDelete( autoDelete );
       
  1861     } else {
       
  1862 	setNumRows( 0 );
       
  1863 	setNumCols( 0 );
       
  1864     }
       
  1865     setUpdatesEnabled( true );
       
  1866 }
       
  1867 
       
  1868 
       
  1869 /*!
       
  1870     Protected virtual function which is called when an error \a e has
       
  1871     occurred on the current cursor(). The default implementation
       
  1872     displays a warning message to the user with information about the
       
  1873     error.
       
  1874 */
       
  1875 void Q3DataTable::handleError( const QSqlError& e )
       
  1876 {
       
  1877     d->dat.handleError( this, e );
       
  1878 }
       
  1879 
       
  1880 /*! \reimp
       
  1881   */
       
  1882 
       
  1883 void Q3DataTable::keyPressEvent( QKeyEvent* e )
       
  1884 {
       
  1885     switch( e->key() ) {
       
  1886     case Qt::Key_Left:
       
  1887     case Qt::Key_Right:
       
  1888     case Qt::Key_Up:
       
  1889     case Qt::Key_Down:
       
  1890     case Qt::Key_Prior:
       
  1891     case Qt::Key_Next:
       
  1892     case Qt::Key_Home:
       
  1893     case Qt::Key_End:
       
  1894     case Qt::Key_F2:
       
  1895     case Qt::Key_Enter: case Qt::Key_Return:
       
  1896     case Qt::Key_Tab: case Qt::Key_BackTab:
       
  1897 	Q3Table::keyPressEvent( e );
       
  1898     default:
       
  1899 	return;
       
  1900     }
       
  1901 }
       
  1902 
       
  1903 /*!  \reimp
       
  1904 */
       
  1905 
       
  1906 void Q3DataTable::resizeData ( int )
       
  1907 {
       
  1908 
       
  1909 }
       
  1910 
       
  1911 /*!  \reimp
       
  1912 */
       
  1913 
       
  1914 Q3TableItem * Q3DataTable::item ( int, int ) const
       
  1915 {
       
  1916     return 0;
       
  1917 }
       
  1918 
       
  1919 /*!  \reimp
       
  1920 */
       
  1921 
       
  1922 void Q3DataTable::setItem ( int , int , Q3TableItem * )
       
  1923 {
       
  1924 
       
  1925 }
       
  1926 
       
  1927 /*!  \reimp
       
  1928 */
       
  1929 
       
  1930 void Q3DataTable::clearCell ( int , int )
       
  1931 {
       
  1932 
       
  1933 }
       
  1934 
       
  1935 /*!  \reimp
       
  1936 */
       
  1937 
       
  1938 void Q3DataTable::setPixmap ( int , int , const QPixmap &  )
       
  1939 {
       
  1940 
       
  1941 }
       
  1942 
       
  1943 /*! \reimp */
       
  1944 void Q3DataTable::takeItem ( Q3TableItem * )
       
  1945 {
       
  1946 
       
  1947 }
       
  1948 
       
  1949 /*!
       
  1950     Installs a new SQL editor factory \a f. This enables the user to
       
  1951     create and instantiate their own editors for use in cell editing.
       
  1952     Note that Q3DataTable takes ownership of this pointer, and will
       
  1953     delete it when it is no longer needed or when
       
  1954     installEditorFactory() is called again.
       
  1955 
       
  1956     \sa Q3SqlEditorFactory
       
  1957 */
       
  1958 
       
  1959 void Q3DataTable::installEditorFactory( Q3SqlEditorFactory * f )
       
  1960 {
       
  1961     if( f ) {
       
  1962 	delete d->editorFactory;
       
  1963 	d->editorFactory = f;
       
  1964     }
       
  1965 }
       
  1966 
       
  1967 /*!
       
  1968     Installs a new property map \a m. This enables the user to create
       
  1969     and instantiate their own property maps for use in cell editing.
       
  1970     Note that Q3DataTable takes ownership of this pointer, and will
       
  1971     delete it when it is no longer needed or when installPropertMap()
       
  1972     is called again.
       
  1973 
       
  1974     \sa Q3SqlPropertyMap
       
  1975 */
       
  1976 
       
  1977 void Q3DataTable::installPropertyMap( Q3SqlPropertyMap* m )
       
  1978 {
       
  1979     if ( m ) {
       
  1980 	delete d->propertyMap;
       
  1981 	d->propertyMap = m;
       
  1982     }
       
  1983 }
       
  1984 
       
  1985 /*!  \internal
       
  1986 
       
  1987   Sets the current selection to \a row, \a col.
       
  1988 */
       
  1989 
       
  1990 void Q3DataTable::setCurrentSelection( int row, int )
       
  1991 {
       
  1992     if ( !sqlCursor() )
       
  1993 	return;
       
  1994     if ( row == d->lastAt )
       
  1995 	return;
       
  1996     if ( !sqlCursor()->seek( row ) )
       
  1997 	return;
       
  1998     d->lastAt = row;
       
  1999     emit currentChanged( sqlCursor() );
       
  2000 }
       
  2001 
       
  2002 void Q3DataTable::updateCurrentSelection()
       
  2003 {
       
  2004     setCurrentSelection( currentRow(), -1 );
       
  2005 }
       
  2006 
       
  2007 /*!
       
  2008     Returns the currently selected record, or 0 if there is no current
       
  2009     selection. The table owns the pointer, so do \e not delete it or
       
  2010     otherwise modify it or the cursor it points to.
       
  2011 */
       
  2012 
       
  2013 QSqlRecord* Q3DataTable::currentRecord() const
       
  2014 {
       
  2015     if ( !sqlCursor() || currentRow() < 0 )
       
  2016 	return 0;
       
  2017     if ( !sqlCursor()->seek( currentRow() ) )
       
  2018 	return 0;
       
  2019     return sqlCursor();
       
  2020 }
       
  2021 
       
  2022 /*!
       
  2023     Sorts column \a col in ascending order.
       
  2024 
       
  2025     \sa setSorting()
       
  2026 */
       
  2027 
       
  2028 void Q3DataTable::sortAscending( int col )
       
  2029 {
       
  2030     sortColumn( col, true );
       
  2031 }
       
  2032 
       
  2033 /*!
       
  2034     Sorts column \a col in descending order.
       
  2035 
       
  2036     \sa setSorting()
       
  2037 */
       
  2038 
       
  2039 void Q3DataTable::sortDescending( int col )
       
  2040 {
       
  2041     sortColumn( col, false );
       
  2042 }
       
  2043 
       
  2044 /*!
       
  2045     \fn void Q3DataTable::refresh( Refresh mode )
       
  2046 
       
  2047     Refreshes the table. If there is no currently defined cursor (see
       
  2048     setSqlCursor()), nothing happens. The \a mode parameter determines
       
  2049     which type of refresh will take place.
       
  2050 
       
  2051     \sa Refresh setSqlCursor() addColumn()
       
  2052 */
       
  2053 
       
  2054 void Q3DataTable::refresh( Q3DataTable::Refresh mode )
       
  2055 {
       
  2056     Q3SqlCursor* cur = sqlCursor();
       
  2057     if ( !cur )
       
  2058 	return;
       
  2059     bool refreshData = ( (mode & RefreshData) == RefreshData );
       
  2060     bool refreshCol = ( (mode & RefreshColumns) == RefreshColumns );
       
  2061     if ( ( (mode & RefreshAll) == RefreshAll ) ) {
       
  2062 	refreshData = true;
       
  2063 	refreshCol = true;
       
  2064     }
       
  2065     if ( !refreshCol && d->fld.count() && numCols() == 0 )
       
  2066 	refreshCol = true;
       
  2067     viewport()->setUpdatesEnabled( false );
       
  2068     d->haveAllRows = false;
       
  2069     if ( refreshData ) {
       
  2070 	if ( !d->cur.refresh() && d->cur.cursor() ) {
       
  2071 	    handleError( d->cur.cursor()->lastError() );
       
  2072 	}
       
  2073 	d->lastAt = -1;
       
  2074     }
       
  2075     if ( refreshCol ) {
       
  2076 	setNumCols( 0 );
       
  2077 	d->colIndex.clear();
       
  2078 	if ( d->fld.count() ) {
       
  2079 	    const QSqlField* field = 0;
       
  2080 	    int i;
       
  2081 	    int fpos = -1;
       
  2082 	    for ( i = 0; i < (int)d->fld.count(); ++i ) {
       
  2083 		if ( cur->fieldPtr( i ) && cur->fieldPtr( i )->name() == d->fld[ i ] )
       
  2084 		    // if there is a field with the desired name on the desired position
       
  2085 		    // then we take that
       
  2086 		    fpos = i;
       
  2087 		else
       
  2088 		    // otherwise we take the first field that matches the desired name
       
  2089 		    fpos = cur->position( d->fld[ i ] );
       
  2090 		field = cur->fieldPtr( fpos );
       
  2091 		if ( field && ( cur->isGenerated( fpos ) ||
       
  2092 				cur->isCalculated( field->name() ) ) )
       
  2093 		{
       
  2094 		    setNumCols( numCols() + 1 );
       
  2095 		    d->colIndex.append( fpos );
       
  2096 		    setColumnReadOnly( numCols()-1, field->isReadOnly() || isColumnReadOnly( numCols()-1 ) );
       
  2097 		    horizontalHeader()->setLabel( numCols()-1, d->fldIcon[ i ], d->fldLabel[ i ] );
       
  2098 		    if ( d->fldHidden[ i ] ) {
       
  2099 			Q3Table::showColumn( i ); // ugly but necessary
       
  2100 			Q3Table::hideColumn( i );
       
  2101 		    } else {
       
  2102 			Q3Table::showColumn( i );
       
  2103 		    }
       
  2104 		    if ( d->fldWidth[ i ] > -1 )
       
  2105 			Q3Table::setColumnWidth( i, d->fldWidth[i] );
       
  2106 		}
       
  2107 	    }
       
  2108 	}
       
  2109     }
       
  2110     viewport()->setUpdatesEnabled( true );
       
  2111     viewport()->repaint( false );
       
  2112     horizontalHeader()->repaint();
       
  2113     verticalHeader()->repaint();
       
  2114     setSize( cur );
       
  2115     // keep others aware
       
  2116     if ( d->lastAt == -1 )
       
  2117  	setCurrentSelection( -1, -1 );
       
  2118     else if ( d->lastAt != currentRow() )
       
  2119 	setCurrentSelection( currentRow(), currentColumn() );
       
  2120     if ( cur->isValid() )
       
  2121 	emit currentChanged( sqlCursor() );
       
  2122 }
       
  2123 
       
  2124 /*!
       
  2125     Refreshes the table. The cursor is refreshed using the current
       
  2126     filter, the current sort, and the currently defined columns.
       
  2127     Equivalent to calling refresh( Q3DataTable::RefreshData ).
       
  2128 */
       
  2129 
       
  2130 void Q3DataTable::refresh()
       
  2131 {
       
  2132     refresh( RefreshData );
       
  2133 }
       
  2134 
       
  2135 /*!
       
  2136     \internal
       
  2137 
       
  2138     Selects the record in the table using the current cursor edit
       
  2139     buffer and the fields specified by the index \a idx. If \a atHint
       
  2140     is specified, it will be used as a hint about where to begin
       
  2141     searching.
       
  2142 */
       
  2143 
       
  2144 bool Q3DataTable::findBuffer( const QSqlIndex& idx, int atHint )
       
  2145 {
       
  2146     Q3SqlCursor* cur = sqlCursor();
       
  2147     if ( !cur )
       
  2148 	return false;
       
  2149     bool found = d->cur.findBuffer( idx, atHint );
       
  2150     if ( found )
       
  2151 	setCurrentCell( cur->at(), currentColumn() );
       
  2152     return found;
       
  2153 }
       
  2154 
       
  2155 /*! \internal
       
  2156     Returns the string representation of a database field.
       
  2157 */
       
  2158 QString Q3DataTable::fieldToString( const QSqlField * field )
       
  2159 {
       
  2160     QString text;
       
  2161     if ( field->isNull() ) {
       
  2162 	text = nullText();
       
  2163     } else {
       
  2164 	QVariant val = field->value();
       
  2165 	switch ( val.type() ) {
       
  2166 	    case QVariant::Bool:
       
  2167 		text = val.toBool() ? d->trueTxt : d->falseTxt;
       
  2168 		break;
       
  2169 	    case QVariant::Date:
       
  2170 		text = val.toDate().toString( d->datefmt );
       
  2171 		break;
       
  2172 	    case QVariant::Time:
       
  2173 		text = val.toTime().toString( d->datefmt );
       
  2174 		break;
       
  2175 	    case QVariant::DateTime:
       
  2176 		text = val.toDateTime().toString( d->datefmt );
       
  2177 		break;
       
  2178 	    default:
       
  2179 		text = val.toString();
       
  2180 		break;
       
  2181 	}
       
  2182     }
       
  2183     return text;
       
  2184 }
       
  2185 
       
  2186 /*!
       
  2187     \reimp
       
  2188 */
       
  2189 
       
  2190 void Q3DataTable::swapColumns( int col1, int col2, bool )
       
  2191 {
       
  2192     QString fld = d->fld[ col1 ];
       
  2193     QString fldLabel = d->fldLabel[ col1 ];
       
  2194     QIconSet fldIcon = d->fldIcon[ col1 ];
       
  2195     int fldWidth = d->fldWidth[ col1 ];
       
  2196 
       
  2197     d->fld[ col1 ] = d->fld[ col2 ];
       
  2198     d->fldLabel[ col1 ] = d->fldLabel[ col2 ];
       
  2199     d->fldIcon[ col1 ] = d->fldIcon[ col2 ];
       
  2200     d->fldWidth[ col1 ] = d->fldWidth[ col2 ];
       
  2201 
       
  2202     d->fld[ col2 ] = fld;
       
  2203     d->fldLabel[ col2 ] = fldLabel;
       
  2204     d->fldIcon[ col2 ] = fldIcon;
       
  2205     d->fldWidth[ col2 ] = fldWidth;
       
  2206 
       
  2207     int colIndex = d->colIndex[ col1 ];
       
  2208     d->colIndex[ col1 ] = d->colIndex[ col2 ];
       
  2209     d->colIndex[ col2 ] = colIndex;
       
  2210 }
       
  2211 
       
  2212 /*!
       
  2213     \reimp
       
  2214 */
       
  2215 
       
  2216 void Q3DataTable::drawContents( QPainter * p, int cx, int cy, int cw, int ch )
       
  2217 {
       
  2218     Q3Table::drawContents( p, cx, cy, cw, ch );
       
  2219     if ( sqlCursor() && currentRow() >= 0 )
       
  2220 	sqlCursor()->seek( currentRow() );
       
  2221 }
       
  2222 
       
  2223 /*!
       
  2224     \reimp
       
  2225  */
       
  2226 void Q3DataTable::drawContents(QPainter *)
       
  2227 {
       
  2228 }
       
  2229 
       
  2230 /*!
       
  2231     \reimp
       
  2232 */
       
  2233 
       
  2234 void Q3DataTable::hideColumn( int col )
       
  2235 {
       
  2236     d->fldHidden[col] = true;
       
  2237     refresh( RefreshColumns );
       
  2238 }
       
  2239 
       
  2240 /*!
       
  2241     \reimp
       
  2242 */
       
  2243 
       
  2244 void Q3DataTable::showColumn( int col )
       
  2245 {
       
  2246     d->fldHidden[col] = false;
       
  2247     refresh( RefreshColumns );
       
  2248 }
       
  2249 
       
  2250 /*!
       
  2251   \reimp
       
  2252 */
       
  2253 void  Q3DataTable::selectRow(int row)
       
  2254 {
       
  2255     setCurrentCell(row, currentColumn());
       
  2256 }
       
  2257 
       
  2258 /*!
       
  2259     \fn void Q3DataTable::currentChanged( QSqlRecord* record )
       
  2260 
       
  2261     This signal is emitted whenever a new row is selected in the
       
  2262     table. The \a record parameter points to the contents of the newly
       
  2263     selected record.
       
  2264 */
       
  2265 
       
  2266 /*!
       
  2267     \fn void Q3DataTable::primeInsert( QSqlRecord* buf )
       
  2268 
       
  2269     This signal is emitted after the cursor is primed for insert by
       
  2270     the table, when an insert action is beginning on the table. The \a
       
  2271     buf parameter points to the edit buffer being inserted. Connect to
       
  2272     this signal in order to, for example, prime the record buffer with
       
  2273     default data values.
       
  2274 */
       
  2275 
       
  2276 /*!
       
  2277     \fn void Q3DataTable::primeUpdate( QSqlRecord* buf )
       
  2278 
       
  2279     This signal is emitted after the cursor is primed for update by
       
  2280     the table, when an update action is beginning on the table. The \a
       
  2281     buf parameter points to the edit buffer being updated. Connect to
       
  2282     this signal in order to, for example, provide some visual feedback
       
  2283     that the user is in 'edit mode'.
       
  2284 */
       
  2285 
       
  2286 /*!
       
  2287     \fn void Q3DataTable::primeDelete( QSqlRecord* buf )
       
  2288 
       
  2289     This signal is emitted after the cursor is primed for delete by
       
  2290     the table, when a delete action is beginning on the table. The \a
       
  2291     buf parameter points to the edit buffer being deleted. Connect to
       
  2292     this signal in order to, for example, record auditing information
       
  2293     on deletions.
       
  2294 */
       
  2295 
       
  2296 /*!
       
  2297     \fn void Q3DataTable::beforeInsert( QSqlRecord* buf )
       
  2298 
       
  2299     This signal is emitted just before the cursor's edit buffer is
       
  2300     inserted into the database. The \a buf parameter points to the
       
  2301     edit buffer being inserted. Connect to this signal to, for
       
  2302     example, populate a key field with a unique sequence number.
       
  2303 */
       
  2304 
       
  2305 /*!
       
  2306     \fn void Q3DataTable::beforeUpdate( QSqlRecord* buf )
       
  2307 
       
  2308     This signal is emitted just before the cursor's edit buffer is
       
  2309     updated in the database. The \a buf parameter points to the edit
       
  2310     buffer being updated. Connect to this signal when you want to
       
  2311     transform the user's data behind-the-scenes.
       
  2312 */
       
  2313 
       
  2314 /*!
       
  2315     \fn void Q3DataTable::beforeDelete( QSqlRecord* buf )
       
  2316 
       
  2317     This signal is emitted just before the currently selected record
       
  2318     is deleted from the database. The \a buf parameter points to the
       
  2319     edit buffer being deleted. Connect to this signal to, for example,
       
  2320     copy some of the fields for later use.
       
  2321 */
       
  2322 
       
  2323 /*!
       
  2324     \fn void Q3DataTable::cursorChanged( QSql::Op mode )
       
  2325 
       
  2326     This signal is emitted whenever the cursor record was changed due
       
  2327     to an edit. The \a mode parameter is the type of edit that just
       
  2328     took place.
       
  2329 */
       
  2330 
       
  2331 #endif
       
  2332 
       
  2333 QT_END_NAMESPACE