00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "kexidataawareobjectiface.h"
00028
00029 #include <qscrollview.h>
00030 #include <qlabel.h>
00031 #include <qtooltip.h>
00032
00033 #include <kexi.h>
00034 #include <kexiutils/validator.h>
00035 #include <widget/utils/kexirecordnavigator.h>
00036 #include <widget/utils/kexirecordmarker.h>
00037 #include <kexidb/roweditbuffer.h>
00038 #include <kexidataiteminterface.h>
00039
00040 #include <kmessagebox.h>
00041
00042 using namespace KexiUtils;
00043
00044 KexiDataAwareObjectInterface::KexiDataAwareObjectInterface()
00045 {
00046 m_data = 0;
00047 m_itemIterator = 0;
00048 m_readOnly = -1;
00049 m_insertingEnabled = -1;
00050 m_isSortingEnabled = true;
00051 m_isFilteringEnabled = true;
00052 m_deletionPolicy = AskDelete;
00053 m_inside_acceptEditor = false;
00054 m_acceptsRowEditAfterCellAccepting = false;
00055 m_internal_acceptsRowEditAfterCellAccepting = false;
00056 m_contentsMousePressEvent_dblClick = false;
00057 m_navPanel = 0;
00058 m_initDataContentsOnShow = false;
00059 m_cursorPositionSetExplicityBeforeShow = false;
00060 m_verticalHeader = 0;
00061 m_insertItem = 0;
00062 m_rowEditBuffer = 0;
00063 m_spreadSheetMode = false;
00064 m_dropsAtRowEnabled = false;
00065 m_updateEntireRowWhenMovingToOtherRow = false;
00066 m_dragIndicatorLine = -1;
00067 m_emptyRowInsertingEnabled = false;
00068 m_popup = 0;
00069 m_contextMenuEnabled = true;
00070 m_rowWillBeDeleted = -1;
00071 m_alsoUpdateNextRow = false;
00072 m_verticalHeaderAlreadyAdded = false;
00073 clearVariables();
00074 }
00075
00076 KexiDataAwareObjectInterface::~KexiDataAwareObjectInterface()
00077 {
00078 delete m_insertItem;
00079 delete m_rowEditBuffer;
00080 delete m_itemIterator;
00081
00082 }
00083
00084 void KexiDataAwareObjectInterface::clearVariables()
00085 {
00086 m_editor = 0;
00087 m_rowEditBuffer = 0;
00088 m_rowEditing = false;
00089 m_newRowEditing = false;
00090 m_curRow = -1;
00091 m_curCol = -1;
00092 m_currentItem = 0;
00093 }
00094
00095 void KexiDataAwareObjectInterface::setData( KexiTableViewData *data, bool owner )
00096 {
00097 const bool theSameData = m_data && m_data==data;
00098 if (m_owner && m_data && m_data!=data) {
00099 kexidbg << "KexiDataAwareObjectInterface::setData(): destroying old data (owned)" << endl;
00100 delete m_itemIterator;
00101 delete m_data;
00102 m_data = 0;
00103 m_itemIterator = 0;
00104 }
00105 m_owner = owner;
00106 m_data = data;
00107 if (m_data)
00108 m_itemIterator = m_data->createIterator();
00109
00110 kdDebug(44021) << "KexiDataAwareObjectInterface::setData(): using shared data" << endl;
00111
00112
00113 clearColumnsInternal(false);
00114 if (m_data) {
00115 int i = 0;
00116 for (KexiTableViewColumn::ListIterator it(m_data->columns);
00117 it.current(); ++it, i++)
00118 {
00119 KexiDB::Field *f = it.current()->field();
00120 if (it.current()->visible()) {
00121 int wid = f->width();
00122 if (wid==0)
00123 wid=KEXI_DEFAULT_DATA_COLUMN_WIDTH;
00124
00125 addHeaderColumn(it.current()->captionAliasOrName(), f->description(), wid);
00126 }
00127 }
00128 }
00129 if (m_verticalHeader) {
00130 m_verticalHeader->clear();
00131 if (m_data)
00132 m_verticalHeader->addLabels(m_data->count());
00133 }
00134 if (m_data && m_data->count()==0)
00135 m_navPanel->setCurrentRecordNumber(0+1);
00136
00137 if (m_data && !theSameData) {
00139 setSorting(-1);
00140
00141 connectToReloadDataSlot(m_data, SIGNAL(reloadRequested()));
00142 if (dynamic_cast<QObject*>(this)) {
00143 QObject::connect(m_data, SIGNAL(destroying()), dynamic_cast<QObject*>(this), SLOT(slotDataDestroying()));
00144 QObject::connect(m_data, SIGNAL(rowsDeleted( const QValueList<int> & )),
00145 dynamic_cast<QObject*>(this), SLOT(slotRowsDeleted( const QValueList<int> & )));
00146 QObject::connect(m_data, SIGNAL(aboutToDeleteRow(KexiTableItem&,KexiDB::ResultInfo*,bool)),
00147 dynamic_cast<QObject*>(this), SLOT(slotAboutToDeleteRow(KexiTableItem&,KexiDB::ResultInfo*,bool)));
00148 QObject::connect(m_data, SIGNAL(rowDeleted()), dynamic_cast<QObject*>(this), SLOT(slotRowDeleted()));
00149 QObject::connect(m_data, SIGNAL(rowInserted(KexiTableItem*,bool)),
00150 dynamic_cast<QObject*>(this), SLOT(slotRowInserted(KexiTableItem*,bool)));
00151 QObject::connect(m_data, SIGNAL(rowInserted(KexiTableItem*,uint,bool)),
00152 dynamic_cast<QObject*>(this), SLOT(slotRowInserted(KexiTableItem*,uint,bool)));
00153 QObject::connect(m_data, SIGNAL(rowRepaintRequested(KexiTableItem&)),
00154 dynamic_cast<QObject*>(this), SLOT(slotRowRepaintRequested(KexiTableItem&)));
00155 }
00156 }
00157
00158 if (!m_data) {
00159
00160 cancelRowEdit();
00161
00162 clearVariables();
00163 }
00164 else {
00165 if (!m_insertItem) {
00166 m_insertItem = m_data->createItem();
00167 }
00168 else {
00169 m_insertItem->init(m_data->columns.count());
00170 }
00171 }
00172
00173
00174 m_navPanel->setInsertingEnabled(m_data && isInsertingEnabled());
00175 if (m_verticalHeader)
00176 m_verticalHeader->showInsertRow(m_data && isInsertingEnabled());
00177
00178 initDataContents();
00179
00180 if (m_data)
00181 dataSet( m_data );
00182 }
00183
00184 void KexiDataAwareObjectInterface::initDataContents()
00185 {
00186 m_editor = 0;
00187
00188
00189
00190 m_navPanel->setRecordCount(rows());
00191
00192 if (m_data && !m_cursorPositionSetExplicityBeforeShow) {
00193
00194 m_currentItem = 0;
00195 int curRow = -1, curCol = -1;
00196 if (m_data->columnsCount()>0) {
00197 if (rows()>0) {
00198 m_itemIterator->toFirst();
00199 m_currentItem = **m_itemIterator;
00200 curRow = 0;
00201 curCol = 0;
00202 }
00203 else {
00204 if (isInsertingEnabled()) {
00205 m_currentItem = m_insertItem;
00206 curRow = 0;
00207 curCol = 0;
00208 }
00209 }
00210 }
00211 setCursorPosition(curRow, curCol, true);
00212 }
00213 ensureCellVisible(m_curRow, m_curCol);
00214
00215
00216
00217
00218
00219 updateWidgetContents();
00220
00221 m_cursorPositionSetExplicityBeforeShow = false;
00222
00223 dataRefreshed();
00224 }
00225
00226 void KexiDataAwareObjectInterface::setSortingEnabled(bool set)
00227 {
00228 if (m_isSortingEnabled && !set)
00229 setSorting(-1);
00230 m_isSortingEnabled = set;
00231 reloadActions();
00232 }
00233
00234 void KexiDataAwareObjectInterface::setSorting(int col, bool ascending)
00235 {
00236 if (!m_data || !m_isSortingEnabled)
00237 return;
00238
00239 setLocalSortingOrder(col, ascending ? 1 : -1);
00240 m_data->setSorting(col, ascending);
00241 }
00242
00243 int KexiDataAwareObjectInterface::dataSortedColumn() const
00244 {
00245 if (m_data && m_isSortingEnabled)
00246 return m_data->sortedColumn();
00247 return -1;
00248 }
00249
00250 int KexiDataAwareObjectInterface::dataSortingOrder() const
00251 {
00252 return m_data ? m_data->sortingOrder() : 0;
00253 }
00254
00255 bool KexiDataAwareObjectInterface::sort()
00256 {
00257 if (!m_data || !m_isSortingEnabled)
00258 return false;
00259
00260 if (rows() < 2)
00261 return true;
00262
00263 if (!acceptRowEdit())
00264 return false;
00265
00266 if (m_data->sortedColumn()!=-1)
00267 m_data->sort();
00268
00269
00270 if (!m_currentItem) {
00271 m_itemIterator->toFirst();
00272 m_currentItem = **m_itemIterator;
00273 m_curRow = 0;
00274 if (!m_currentItem)
00275 return true;
00276 }
00277 if (m_currentItem != m_insertItem) {
00278 m_curRow = m_data->findRef(m_currentItem);
00279 }
00280
00281
00282
00283 updateGUIAfterSorting();
00284 if (m_verticalHeader)
00285 m_verticalHeader->setCurrentRow(m_curRow);
00286 return true;
00287 }
00288
00289 void KexiDataAwareObjectInterface::sortAscending()
00290 {
00291 if (currentColumn()<0)
00292 return;
00293 sortColumnInternal( currentColumn(), 1 );
00294 }
00295
00296 void KexiDataAwareObjectInterface::sortDescending()
00297 {
00298 if (currentColumn()<0)
00299 return;
00300 sortColumnInternal( currentColumn(), -1 );
00301 }
00302
00303 void KexiDataAwareObjectInterface::sortColumnInternal(int col, int order)
00304 {
00305
00306 bool asc;
00307 if (order == 0) {
00308 if (col==dataSortedColumn() && dataSortingOrder()==1)
00309 asc = dataSortingOrder()==-1;
00310 else
00311 asc = true;
00312 }
00313 else
00314 asc = (order==1);
00315
00316
00317 int prevSortOrder = currentLocalSortingOrder();
00318 const int prevSortColumn = currentLocalSortingOrder();
00319 setSorting( col, asc );
00320
00321 if (!sort())
00322 setLocalSortingOrder(prevSortColumn, prevSortOrder);
00323
00324
00325
00326
00327 if (col != prevSortColumn)
00328 sortedColumnChanged(col);
00329 }
00330
00331 bool KexiDataAwareObjectInterface::isInsertingEnabled() const
00332 {
00333 if (isReadOnly())
00334 return false;
00335 if (m_insertingEnabled == 1 || m_insertingEnabled == 0)
00336 return (bool)m_insertingEnabled;
00337 if (!hasData())
00338 return true;
00339 return m_data->isInsertingEnabled();
00340 }
00341
00342 void KexiDataAwareObjectInterface::setFilteringEnabled(bool set)
00343 {
00344 m_isFilteringEnabled = set;
00345 }
00346
00347 bool KexiDataAwareObjectInterface::isDeleteEnabled() const
00348 {
00349 return (m_deletionPolicy != NoDelete) && !isReadOnly();
00350 }
00351
00352 void KexiDataAwareObjectInterface::setDeletionPolicy(DeletionPolicy policy)
00353 {
00354 m_deletionPolicy = policy;
00355
00356 }
00357
00358 void KexiDataAwareObjectInterface::setReadOnly(bool set)
00359 {
00360 if (isReadOnly() == set || (m_data && m_data->isReadOnly() && !set))
00361 return;
00362 m_readOnly = (set ? 1 : 0);
00363 if (set)
00364 setInsertingEnabled(false);
00365 updateWidgetContents();
00366 reloadActions();
00367 }
00368
00369 bool KexiDataAwareObjectInterface::isReadOnly() const
00370 {
00371 if (!hasData())
00372 return true;
00373 if (m_readOnly == 1 || m_readOnly == 0)
00374 return (bool)m_readOnly;
00375 if (!hasData())
00376 return true;
00377 return m_data->isReadOnly();
00378 }
00379
00380 void KexiDataAwareObjectInterface::setInsertingEnabled(bool set)
00381 {
00382 if (isInsertingEnabled() == set || (m_data && !m_data->isInsertingEnabled() && set))
00383 return;
00384 m_insertingEnabled = (set ? 1 : 0);
00385 m_navPanel->setInsertingEnabled(set);
00386 if (m_verticalHeader)
00387 m_verticalHeader->showInsertRow(set);
00388 if (set)
00389 setReadOnly(false);
00390
00391 updateWidgetContents();
00392 reloadActions();
00393 }
00394
00395 void KexiDataAwareObjectInterface::setSpreadSheetMode()
00396 {
00397 m_spreadSheetMode = true;
00398 setSortingEnabled( false );
00399 setInsertingEnabled( false );
00400 setAcceptsRowEditAfterCellAccepting( true );
00401 setFilteringEnabled( false );
00402 setEmptyRowInsertingEnabled( true );
00403 m_navPanelEnabled = false;
00404 }
00405
00406 void KexiDataAwareObjectInterface::selectNextRow()
00407 {
00408 selectRow( QMIN( rows() - 1 +(isInsertingEnabled()?1:0), m_curRow + 1 ) );
00409 }
00410
00411 void KexiDataAwareObjectInterface::selectPrevPage()
00412 {
00413 selectRow(
00414 QMAX( 0, m_curRow - rowsPerPage() )
00415 );
00416 }
00417
00418 void KexiDataAwareObjectInterface::selectNextPage()
00419 {
00420 selectRow(
00421 QMIN(
00422 rows() - 1 + (isInsertingEnabled()?1:0),
00423 m_curRow + rowsPerPage()
00424 )
00425 );
00426 }
00427
00428 void KexiDataAwareObjectInterface::selectFirstRow()
00429 {
00430 selectRow(0);
00431 }
00432
00433 void KexiDataAwareObjectInterface::selectLastRow()
00434 {
00435
00436 selectRow(rows() - 1);
00437 }
00438
00439 void KexiDataAwareObjectInterface::selectRow(int row)
00440 {
00441 setCursorPosition(row, -1);
00442 }
00443
00444 void KexiDataAwareObjectInterface::selectPrevRow()
00445 {
00446 selectRow( QMAX( 0, m_curRow - 1 ) );
00447 }
00448
00449 void KexiDataAwareObjectInterface::clearSelection()
00450 {
00451
00452 int oldRow = m_curRow;
00453
00454 m_curRow = -1;
00455 m_curCol = -1;
00456 m_currentItem = 0;
00457 updateRow( oldRow );
00458 m_navPanel->setCurrentRecordNumber(0);
00459
00460 }
00461
00462 void KexiDataAwareObjectInterface::setCursorPosition(int row, int col, bool forceSet)
00463 {
00464 int newrow = row;
00465 int newcol = col;
00466
00467 if(rows() <= 0) {
00468 if (m_verticalHeader)
00469 m_verticalHeader->setCurrentRow(-1);
00470 if (isInsertingEnabled()) {
00471 m_currentItem=m_insertItem;
00472 newrow=0;
00473 if (col>=0)
00474 newcol=col;
00475 else
00476 newcol=0;
00477 }
00478 else {
00479 m_currentItem=0;
00480 m_curRow=-1;
00481 m_curCol=-1;
00482 return;
00483 }
00484 }
00485
00486 if(col>=0)
00487 {
00488 newcol = QMAX(0, col);
00489 newcol = QMIN(columns() - 1, newcol);
00490 }
00491 else {
00492 newcol = m_curCol;
00493 newcol = QMAX(0, newcol);
00494 }
00495 newrow = QMAX(0, row);
00496 newrow = QMIN(rows() - 1 + (isInsertingEnabled()?1:0), newrow);
00497
00498
00499
00500
00501 if ( forceSet || m_curRow != newrow || m_curCol != newcol )
00502 {
00503 kexidbg << "setCursorPosition(): " <<QString("old:%1,%2 new:%3,%4").arg(m_curCol)
00504 .arg(m_curRow).arg(newcol).arg(newrow) << endl;
00505
00506
00507 if (m_editor) {
00508 if (!m_contentsMousePressEvent_dblClick) {
00509 if (!acceptEditor()) {
00510 return;
00511 }
00512
00513 newrow = QMIN( rows() - 1 + (isInsertingEnabled()?1:0), newrow);
00514 }
00515 }
00516 if (m_errorMessagePopup) {
00517 m_errorMessagePopup->close();
00518 }
00519
00520 if (m_curRow != newrow) {
00521 m_navPanel->setCurrentRecordNumber(newrow+1);
00522
00523
00524
00525
00526
00527 }
00528
00529
00530 bool newRowInserted = false;
00531 if (m_rowEditing && m_curRow != newrow) {
00532 newRowInserted = m_newRowEditing;
00533 if (!acceptRowEdit()) {
00534
00535 return;
00536 }
00537
00538 newrow = QMIN( rows() - 1 + (isInsertingEnabled()?1:0), newrow);
00539
00540 m_navPanel->setCurrentRecordNumber(newrow+1);
00541 }
00542
00543
00544 int oldRow = m_curRow;
00545 int oldCol = m_curCol;
00546 m_curRow = newrow;
00547 m_curCol = newcol;
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562 if (oldCol>=0 && oldCol<columns() && m_curCol!=oldCol) {
00563
00564 KexiDataItemInterface *edit = editor( oldCol );
00565 if (edit) {
00566 edit->hideFocus();
00567 }
00568 }
00569
00570
00571 editorShowFocus( m_curRow, m_curCol );
00572
00573 if (m_updateEntireRowWhenMovingToOtherRow)
00574 updateRow( oldRow );
00575 else
00576 updateCell( oldRow, oldCol );
00577
00578
00579
00580
00581
00582
00583
00584
00585 if (m_verticalHeader && oldRow != m_curRow)
00586 m_verticalHeader->setCurrentRow(m_curRow);
00587
00588 if (m_updateEntireRowWhenMovingToOtherRow)
00589 updateRow( m_curRow );
00590 else
00591 updateCell( m_curRow, m_curCol );
00592
00593 if (m_curCol != oldCol || m_curRow != oldRow ) {
00594 if (!m_updateEntireRowWhenMovingToOtherRow)
00595 updateCell( oldRow, m_curCol );
00596 }
00597
00598 if (forceSet || m_curRow != oldRow) {
00599 if (isInsertingEnabled() && m_curRow == rows()) {
00600 kdDebug(44021) << "NOW insert item is current" << endl;
00601 m_currentItem = m_insertItem;
00602 }
00603 else {
00604 kdDebug(44021) << QString("NOW item at %1 (%2) is current")
00605 .arg(m_curRow).arg((ulong)itemAt(m_curRow)) << endl;
00606
00607
00608 if (!newRowInserted && isInsertingEnabled() && m_currentItem == m_insertItem && m_curRow == (rows()-1)) {
00609
00610 m_itemIterator->toLast();
00611 }
00612 else if (!newRowInserted && !forceSet && m_currentItem != m_insertItem && 0==m_curRow)
00613 m_itemIterator->toFirst();
00614 else if (!newRowInserted && !forceSet && m_currentItem != m_insertItem && oldRow>=0 && (oldRow+1)==m_curRow)
00615 ++(*m_itemIterator);
00616 else if (!newRowInserted && !forceSet && m_currentItem != m_insertItem && oldRow>=0 && (oldRow-1)==m_curRow)
00617 --(*m_itemIterator);
00618 else {
00619 m_itemIterator->toFirst();
00620 (*m_itemIterator)+=m_curRow;
00621 }
00622 m_currentItem = **m_itemIterator;
00623
00624 }
00625 }
00626
00627
00628 ensureCellVisible(m_curRow, m_curCol);
00629
00630 itemSelected(m_currentItem);
00631 cellSelected(m_curCol, m_curRow);
00632
00633 selectCellInternal();
00634 }
00635 else {
00636 kexidbg << "setCursorPosition(): NO CHANGE" << endl;
00637 }
00638
00639 if(m_initDataContentsOnShow) {
00640 m_cursorPositionSetExplicityBeforeShow = true;
00641 }
00642 }
00643
00644 bool KexiDataAwareObjectInterface::acceptRowEdit()
00645 {
00646 if (!m_rowEditing || !m_data->rowEditBuffer())
00647 return true;
00648 if (m_inside_acceptEditor) {
00649 m_internal_acceptsRowEditAfterCellAccepting = true;
00650 return true;
00651 }
00652 m_internal_acceptsRowEditAfterCellAccepting = false;
00653
00654 const int columnEditedBeforeAccepting = m_editor ? currentColumn() : -1;
00655 if (!acceptEditor())
00656 return false;
00657 kdDebug() << "EDIT ROW ACCEPTING..." << endl;
00658
00659 bool success = true;
00660
00661
00662 const bool inserting = m_newRowEditing;
00663
00664
00665
00666 if (m_data->rowEditBuffer()->isEmpty() && !m_newRowEditing) {
00667
00668
00669
00670
00671
00672
00673 kdDebug() << "-- NOTHING TO ACCEPT!!!" << endl;
00674
00675 }
00676 else {
00677 if (m_newRowEditing) {
00678
00679
00680 kdDebug() << "-- INSERTING: " << endl;
00681 m_data->rowEditBuffer()->debug();
00682 success = m_data->saveNewRow(*m_currentItem);
00683
00684
00685
00686 }
00687 else {
00688
00689 if (success) {
00690
00691 kdDebug() << "-- UPDATING: " << endl;
00692 m_data->rowEditBuffer()->debug();
00693 success = m_data->saveRowChanges(*m_currentItem);
00694
00695
00696 }
00697 }
00698 }
00699
00700 if (success) {
00701
00702 m_rowEditing = false;
00703 m_newRowEditing = false;
00704
00705 if (m_verticalHeader)
00706 m_verticalHeader->setEditRow(-1);
00707
00708 updateAfterAcceptRowEdit();
00709
00710 kdDebug() << "EDIT ROW ACCEPTED:" << endl;
00711
00712
00713 if (inserting) {
00714
00715
00716 m_navPanel->setRecordCount(rows());
00717 }
00718 else {
00719
00720 }
00721
00722 rowEditTerminated(m_curRow);
00723 }
00724 else {
00725
00726
00727
00728
00729
00730
00731 int faultyColumn = -1;
00732 if (m_data->result()->column >= 0 && m_data->result()->column < columns())
00733 faultyColumn = m_data->result()->column;
00734 else if (columnEditedBeforeAccepting >= 0)
00735 faultyColumn = columnEditedBeforeAccepting;
00736 if (faultyColumn >= 0) {
00737 setCursorPosition(m_curRow, faultyColumn);
00738 }
00739 if (m_data->result()->desc.isEmpty())
00740 KMessageBox::sorry(dynamic_cast<QWidget*>(this), m_data->result()->msg);
00741 else
00742 KMessageBox::detailedSorry(dynamic_cast<QWidget*>(this), m_data->result()->msg, m_data->result()->desc);
00743
00744 if (faultyColumn >= 0) {
00745
00746 startEditCurrentCell();
00747 }
00748 }
00749
00750 return success;
00751 }
00752
00753 void KexiDataAwareObjectInterface::cancelRowEdit()
00754 {
00755 if (!hasData())
00756 return;
00757 if (!m_rowEditing)
00758 return;
00759 cancelEditor();
00760 m_rowEditing = false;
00761
00762 if (m_verticalHeader)
00763 m_verticalHeader->setEditRow(-1);
00764 m_alsoUpdateNextRow = m_newRowEditing;
00765 if (m_newRowEditing) {
00766 m_newRowEditing = false;
00767
00768 m_data->removeLast();
00769
00770 m_currentItem = m_insertItem;
00771
00772 if (m_verticalHeader)
00773 m_verticalHeader->removeLabel(false);
00774
00775
00776
00777 updateWidgetContents();
00778
00779
00780
00781 updateWidgetContentsSize();
00782
00783
00784
00785 }
00786
00787 m_data->clearRowEditBuffer();
00788 updateAfterCancelRowEdit();
00789
00791 kexidbg << "EDIT ROW CANCELLED." << endl;
00792
00793 rowEditTerminated(m_curRow);
00794 }
00795
00796 void KexiDataAwareObjectInterface::updateAfterCancelRowEdit()
00797 {
00798 updateRow(m_curRow);
00799 if (m_alsoUpdateNextRow)
00800 updateRow(m_curRow+1);
00801 m_alsoUpdateNextRow = false;
00802 }
00803
00804 void KexiDataAwareObjectInterface::updateAfterAcceptRowEdit()
00805 {
00806 updateRow(m_curRow);
00807 }
00808
00809 void KexiDataAwareObjectInterface::removeEditor()
00810 {
00811 if (!m_editor)
00812 return;
00813 m_editor->hideWidget();
00814 m_editor = 0;
00815 }
00816
00817 void KexiDataAwareObjectInterface::cancelEditor()
00818 {
00819 if (m_errorMessagePopup) {
00820 m_errorMessagePopup->close();
00821 }
00822 if (!m_editor)
00823 return;
00824 removeEditor();
00825 }
00826
00828 class KexiDataAwareObjectInterfaceToolTip : public QToolTip {
00829 public:
00830 KexiDataAwareObjectInterfaceToolTip( const QString & text, const QPoint & pos, QWidget * widget )
00831 : QToolTip(widget), m_text(text)
00832 {
00833 tip( QRect(pos, QSize(100, 100)), text );
00834 }
00835 virtual void maybeTip(const QPoint & p) {
00836 tip( QRect(p, QSize(100, 100)), m_text);
00837 }
00838 QString m_text;
00839 };
00840
00841 bool KexiDataAwareObjectInterface::acceptEditor()
00842 {
00843 if (!hasData())
00844 return true;
00845 if (!m_editor || m_inside_acceptEditor)
00846 return true;
00847
00848 m_inside_acceptEditor = true;
00849
00850 QVariant newval;
00851 Validator::Result res = Validator::Ok;
00852 QString msg, desc;
00853 bool setNull = false;
00854
00855
00856
00857
00858 const bool autoIncColumnCanBeOmitted = m_newRowEditing && m_editor->field()->isAutoIncrement();
00859
00860
00861 bool valueChanged = m_editor->valueChanged();
00862 bool editCurrentCellAgain = false;
00863
00864 if (valueChanged) {
00865 if (!m_editor->valueIsValid()) {
00866
00867 res = Validator::Error;
00868 editCurrentCellAgain = true;
00869 QWidget *par = dynamic_cast<QScrollView*>(this) ? dynamic_cast<QScrollView*>(this)->viewport() :
00870 dynamic_cast<QWidget*>(this);
00871 QWidget *edit = dynamic_cast<QWidget*>(m_editor);
00872 if (par && edit) {
00876 if (!m_errorMessagePopup) {
00877
00878 m_errorMessagePopup = new QLabel(i18n("Error: %1").arg(m_editor->columnInfo()->field->typeName())+"?",
00879 dynamic_cast<QWidget*>(this), 0,
00880 Qt::WStyle_Customize | Qt::WType_Popup | Qt::WStyle_NoBorder
00881 | Qt::WX11BypassWM | Qt::WDestructiveClose);
00882 QPalette pal( QToolTip::palette() );
00883 QColorGroup cg(pal.active());
00884 cg.setColor(QColorGroup::Foreground, Qt::red);
00885 pal.setActive(cg);
00886 m_errorMessagePopup->setFocusPolicy(QWidget::NoFocus);
00887 m_errorMessagePopup->setPalette(pal);
00888 m_errorMessagePopup->setMargin(2);
00889 m_errorMessagePopup->setAutoMask( FALSE );
00890 m_errorMessagePopup->setFrameStyle( QFrame::Plain | QFrame::Box );
00891 m_errorMessagePopup->setLineWidth( 2 );
00892 m_errorMessagePopup->setAlignment( Qt::AlignAuto | Qt::AlignTop );
00893 m_errorMessagePopup->setIndent(0);
00894 m_errorMessagePopup->polish();
00895 m_errorMessagePopup->adjustSize();
00896 m_errorMessagePopup->move(
00897 par->mapToGlobal(edit->pos()) +
00898 QPoint(
00899 (m_verticalHeader ? m_verticalHeader->width() : 0),
00900 edit->height() + 5) );
00901 m_errorMessagePopup->show();
00902 }
00903 m_editor->setFocus();
00904
00905
00906
00907
00908
00909
00910
00911 }
00912 }
00913 else if (m_editor->valueIsNull()) {
00914
00915 if (m_editor->field()->isNotNull() && !autoIncColumnCanBeOmitted) {
00916 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NULL NOT ALLOWED!" << endl;
00917 res = Validator::Error;
00918
00919 msg = Validator::msgColumnNotEmpty().arg(m_editor->field()->captionOrName())
00920 + "\n\n" + Kexi::msgYouCanImproveData();
00921 desc = i18n("The column's constraint is declared as NOT NULL.");
00922 editCurrentCellAgain = true;
00923
00924
00925
00926 }
00927 else {
00928 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NULL VALUE WILL BE SET" << endl;
00929
00930 setNull = true;
00931 }
00932 }
00933 else if (m_editor->valueIsEmpty()) {
00934
00935 if (m_editor->field()->hasEmptyProperty()) {
00936
00937 if (m_editor->field()->isNotEmpty() && !autoIncColumnCanBeOmitted) {
00938 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): EMPTY NOT ALLOWED!" << endl;
00939 res = Validator::Error;
00940
00941 msg = Validator::msgColumnNotEmpty().arg(m_editor->field()->captionOrName())
00942 + "\n\n" + Kexi::msgYouCanImproveData();
00943 desc = i18n("The column's constraint is declared as NOT EMPTY.");
00944 editCurrentCellAgain = true;
00945
00946
00947
00948 }
00949 else {
00950 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): EMPTY VALUE WILL BE SET" << endl;
00951 }
00952 }
00953 else {
00954
00955 if (m_editor->field()->isNotNull() && !autoIncColumnCanBeOmitted) {
00956 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NEITHER NULL NOR EMPTY VALUE CAN BE SET!" << endl;
00957 res = Validator::Error;
00958
00959 msg = Validator::msgColumnNotEmpty().arg(m_editor->field()->captionOrName())
00960 + "\n\n" + Kexi::msgYouCanImproveData();
00961 desc = i18n("The column's constraint is declared as NOT EMPTY and NOT NULL.");
00962 editCurrentCellAgain = true;
00963
00964
00965
00966 }
00967 else {
00968 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NULL VALUE WILL BE SET BECAUSE EMPTY IS NOT ALLOWED" << endl;
00969
00970 setNull = true;
00971 }
00972 }
00973 }
00974 }
00975
00976 const int realFieldNumber = fieldNumberForColumn(m_curCol);
00977 if (realFieldNumber < 0) {
00978 kdWarning() << "KexiDataAwareObjectInterface::acceptEditor(): fieldNumberForColumn(m_curCol) < 0" << endl;
00979 return false;
00980 }
00981
00982
00983 if (res == Validator::Ok) {
00984 if (!setNull && !valueChanged
00985 || setNull && m_currentItem->at( realFieldNumber ).isNull()) {
00986 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): VALUE NOT CHANGED." << endl;
00987 removeEditor();
00988 m_inside_acceptEditor = false;
00989 if (m_acceptsRowEditAfterCellAccepting || m_internal_acceptsRowEditAfterCellAccepting)
00990 acceptRowEdit();
00991 return true;
00992 }
00993 if (!setNull) {
00994
00995 newval = m_editor->value();
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008 }
01009
01010
01011
01012
01013 Validator *validator = column(m_curCol)->validator();
01014 if (validator) {
01015
01016 res = validator->check(column(m_curCol)->field()->captionOrName(),
01017 newval, msg, desc);
01018 }
01019 }
01020
01021
01022 if (res == Validator::Error) {
01023 if (!msg.isEmpty()) {
01024 if (desc.isEmpty())
01025 KMessageBox::sorry(dynamic_cast<QWidget*>(this), msg);
01026 else
01027 KMessageBox::detailedSorry(dynamic_cast<QWidget*>(this), msg, desc);
01028 }
01029 editCurrentCellAgain = true;
01030
01031 }
01032 else if (res == Validator::Warning) {
01033
01034 KMessageBox::messageBox(dynamic_cast<QWidget*>(this), KMessageBox::Sorry, msg + "\n" + desc);
01035 editCurrentCellAgain = true;
01036 }
01037
01038 if (res == Validator::Ok) {
01039
01040
01041
01042
01043
01044 if (m_data->updateRowEditBufferRef(m_currentItem, m_curCol, column( m_curCol), newval)) {
01045 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): ------ EDIT BUFFER CHANGED TO:" << endl;
01046 m_data->rowEditBuffer()->debug();
01047 } else {
01048 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): ------ CHANGE FAILED in KexiDataAwareObjectInterface::updateRowEditBuffer()" << endl;
01049 res = Validator::Error;
01050
01051
01052
01053
01054 if (m_editor && m_data->result()->column>=0 && m_data->result()->column<columns()) {
01055
01056 setCursorPosition(m_curRow, m_data->result()->column);
01057 }
01058 if (!m_data->result()->msg.isEmpty()) {
01059 if (m_data->result()->desc.isEmpty())
01060 KMessageBox::sorry(dynamic_cast<QWidget*>(this), m_data->result()->msg);
01061 else
01062 KMessageBox::detailedSorry(dynamic_cast<QWidget*>(this), m_data->result()->msg, m_data->result()->desc);
01063 }
01064 }
01065 }
01066
01067 if (res == Validator::Ok) {
01068 removeEditor();
01069 itemChanged(m_currentItem, m_curRow, m_curCol,
01070 m_currentItem->at( realFieldNumber ));
01071 itemChanged(m_currentItem, m_curRow, m_curCol);
01072 }
01073 m_inside_acceptEditor = false;
01074 if (res == Validator::Ok) {
01075 if (m_acceptsRowEditAfterCellAccepting || m_internal_acceptsRowEditAfterCellAccepting)
01076 acceptRowEdit();
01077 return true;
01078 }
01079 if (m_editor) {
01080
01081
01082 if (m_editor->hasFocusableWidget()) {
01083 m_editor->showWidget();
01084 m_editor->setFocus();
01085 }
01086
01087
01088 }
01089 return false;
01090 }
01091
01092 void KexiDataAwareObjectInterface::startEditCurrentCell(const QString &setText)
01093 {
01094 kdDebug() << "** KexiDataAwareObjectInterface::startEditCurrentCell("<<setText<<")"<<endl;
01095
01096
01097 if (isReadOnly() || !columnEditable(m_curCol))
01098 return;
01099 if (m_editor) {
01100 if (m_editor->hasFocusableWidget()) {
01101 m_editor->showWidget();
01102 m_editor->setFocus();
01103 }
01104 }
01105
01106
01107
01108 ensureCellVisible(m_curRow+1, m_curCol);
01109 createEditor(m_curRow, m_curCol, setText, !setText.isEmpty());
01110 }
01111
01112 void KexiDataAwareObjectInterface::deleteAndStartEditCurrentCell()
01113 {
01114 if (isReadOnly() || !columnEditable(m_curCol))
01115 return;
01116 if (m_editor) {
01117 m_editor->clear();
01118 return;
01119 }
01120 if (columnType(m_curCol) == KexiDB::Field::Boolean)
01121 return;
01122
01123
01124
01125 ensureCellVisible(m_curRow+1, m_curCol);
01126 createEditor(m_curRow, m_curCol, QString::null, false);
01127 if (!m_editor)
01128 return;
01129 m_editor->clear();
01130 if (m_editor->acceptEditorAfterDeleteContents())
01131 acceptEditor();
01132 }
01133
01134 void KexiDataAwareObjectInterface::deleteCurrentRow()
01135 {
01136 if (m_newRowEditing) {
01137 cancelRowEdit();
01138 return;
01139 }
01140
01141 if (!acceptRowEdit())
01142 return;
01143
01144 if (!isDeleteEnabled() || !m_currentItem || m_currentItem == m_insertItem)
01145 return;
01146 switch (m_deletionPolicy) {
01147 case NoDelete:
01148 return;
01149 case ImmediateDelete:
01150 break;
01151 case AskDelete:
01152 if (KMessageBox::Cancel == KMessageBox::warningContinueCancel(dynamic_cast<QWidget*>(this),
01153 i18n("Do you want to delete selected row?"), 0,
01154 KGuiItem(i18n("&Delete Row"),"editdelete"),
01155 "dontAskBeforeDeleteRow",
01156 KMessageBox::Notify|KMessageBox::Dangerous))
01157 return;
01158 break;
01159 case SignalDelete:
01160 itemDeleteRequest(m_currentItem, m_curRow, m_curCol);
01161 currentItemDeleteRequest();
01162 return;
01163 default:
01164 return;
01165 }
01166
01167 if (!deleteItem(m_currentItem)) {
01168 }
01169 }
01170
01171 KexiTableItem *KexiDataAwareObjectInterface::insertEmptyRow(int row)
01172 {
01173 if ( !acceptRowEdit() || !isEmptyRowInsertingEnabled()
01174 || (row!=-1 && row >= ((int)rows()+(isInsertingEnabled()?1:0) ) ) )
01175 return 0;
01176
01177 KexiTableItem *newItem = m_data->createItem();
01178 insertItem(newItem, row);
01179 return newItem;
01180 }
01181
01182 void KexiDataAwareObjectInterface::insertItem(KexiTableItem *newItem, int row)
01183 {
01184 const bool changeCurrentRow = row==-1 || row==m_curRow;
01185 if (changeCurrentRow) {
01186
01187 row = (m_curRow >= 0 ? m_curRow : 0);
01188 m_currentItem = newItem;
01189 m_curRow = row;
01190 }
01191 else if (m_curRow >= row) {
01192 m_curRow++;
01193 }
01194
01195 m_data->insertRow(*newItem, row, true );
01196
01197 if (changeCurrentRow) {
01198
01199 m_itemIterator->toFirst();
01200 (*m_itemIterator)+=m_curRow;
01201 }
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223 }
01224
01225 void KexiDataAwareObjectInterface::slotRowInserted(KexiTableItem *item, bool repaint)
01226 {
01227 int row = m_data->findRef(item);
01228 slotRowInserted( item, row, repaint );
01229 }
01230
01231 void KexiDataAwareObjectInterface::slotRowInserted(KexiTableItem * , uint row, bool repaint)
01232 {
01233 if (repaint && (int)row<rows()) {
01234 updateWidgetContentsSize();
01235
01236
01237
01238
01239
01240
01241
01242 updateAllVisibleRowsBelow(row);
01243
01244 if (!m_verticalHeaderAlreadyAdded) {
01245 if (m_verticalHeader)
01246 m_verticalHeader->addLabel();
01247 }
01248 else
01249 m_verticalHeaderAlreadyAdded = false;
01250
01251
01252 m_navPanel->setRecordCount(rows());
01253
01254 if (m_curRow >= (int)row) {
01255
01256 editorShowFocus( m_curRow, m_curCol );
01257 }
01258 }
01259 }
01260
01261 tristate KexiDataAwareObjectInterface::deleteAllRows(bool ask, bool repaint)
01262 {
01263 if (!hasData())
01264 return true;
01265 if (m_data->count()<1)
01266 return true;
01267
01268 if (ask) {
01269 QString tableName = m_data->dbTableName();
01270 if (!tableName.isEmpty()) {
01271 tableName.prepend(" \"");
01272 tableName.append("\"");
01273 }
01274 if (KMessageBox::Cancel == KMessageBox::warningContinueCancel(dynamic_cast<QWidget*>(this),
01275 i18n("Do you want to clear the contents of table %1?").arg(tableName),
01276 0, KGuiItem(i18n("&Clear Contents")) ))
01277 return cancelled;
01278 }
01279
01280 cancelRowEdit();
01281
01282
01283 const bool repaintLater = repaint && m_spreadSheetMode;
01284 const int oldRows = rows();
01285
01286 bool res = m_data->deleteAllRows(repaint && !repaintLater);
01287
01288 if (res) {
01289 if (m_spreadSheetMode) {
01290
01291 for (int i=0; i<oldRows; i++) {
01292 m_data->append(m_data->createItem());
01293 }
01294 }
01295 }
01296 if (repaintLater)
01297 m_data->reload();
01298
01299
01300
01301
01302
01303
01304
01305 return res;
01306 }
01307
01308 void KexiDataAwareObjectInterface::clearColumns(bool repaint)
01309 {
01310 cancelRowEdit();
01311 m_data->clearInternal();
01312
01313 clearColumnsInternal(repaint);
01314
01315 if (repaint)
01316
01317
01318 updateWidgetContents();
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341 }
01342
01343 void KexiDataAwareObjectInterface::reloadData()
01344 {
01345
01346 acceptRowEdit();
01347 if (m_verticalHeader)
01348 m_verticalHeader->clear();
01349
01350 if (m_curCol>=0 && m_curCol<columns()) {
01351
01352 KexiDataItemInterface *edit = editor( m_curCol );
01353 if (edit) {
01354 edit->hideFocus();
01355 }
01356 }
01357
01358 clearVariables();
01359 if (m_verticalHeader)
01360 m_verticalHeader->setCurrentRow(-1);
01361
01362 if (dynamic_cast<QWidget*>(this) && dynamic_cast<QWidget*>(this)->isVisible())
01363 initDataContents();
01364 else
01365 m_initDataContentsOnShow = true;
01366
01367 if (m_verticalHeader)
01368 m_verticalHeader->addLabels(m_data->count());
01369
01370 updateWidgetScrollBars();
01371 }
01372
01373 int KexiDataAwareObjectInterface::columnType(int col)
01374 {
01375 KexiTableViewColumn* c = m_data ? column(col) : 0;
01376 return c ? c->field()->type() : KexiDB::Field::InvalidType;
01377 }
01378
01379 bool KexiDataAwareObjectInterface::columnEditable(int col)
01380 {
01381 KexiTableViewColumn* c = m_data ? column(col) : 0;
01382 return c ? (! c->isReadOnly()) : false;
01383 }
01384
01385 int KexiDataAwareObjectInterface::rows() const
01386 {
01387 if (!hasData())
01388 return 0;
01389 return m_data->count();
01390 }
01391
01392 int KexiDataAwareObjectInterface::dataColumns() const
01393 {
01394 if (!hasData())
01395 return 0;
01396 return m_data->columns.count();
01397 }
01398
01399 QVariant KexiDataAwareObjectInterface::columnDefaultValue(int ) const
01400 {
01401 return QVariant(0);
01402
01403
01404 }
01405
01406 void KexiDataAwareObjectInterface::setAcceptsRowEditAfterCellAccepting(bool set)
01407 {
01408 m_acceptsRowEditAfterCellAccepting = set;
01409 }
01410
01411 void KexiDataAwareObjectInterface::setDropsAtRowEnabled(bool set)
01412 {
01413
01414 if (!set)
01415 m_dragIndicatorLine = -1;
01416 if (m_dropsAtRowEnabled && !set) {
01417 m_dropsAtRowEnabled = false;
01418
01419 updateWidgetContents();
01420 }
01421 else {
01422 m_dropsAtRowEnabled = set;
01423 }
01424 }
01425
01426 void KexiDataAwareObjectInterface::setEmptyRowInsertingEnabled(bool set)
01427 {
01428 m_emptyRowInsertingEnabled = set;
01429 reloadActions();
01430 }
01431
01432 void KexiDataAwareObjectInterface::slotAboutToDeleteRow(KexiTableItem& item,
01433 KexiDB::ResultInfo* , bool repaint)
01434 {
01435 if (repaint) {
01436 m_rowWillBeDeleted = m_data->findRef(&item);
01437 }
01438 }
01439
01440 void KexiDataAwareObjectInterface::slotRowDeleted()
01441 {
01442 if (m_rowWillBeDeleted >= 0) {
01443 if (m_rowWillBeDeleted > 0 && m_rowWillBeDeleted >= (rows()-1) && !m_spreadSheetMode)
01444 m_rowWillBeDeleted = rows()-1;
01445 updateWidgetContentsSize();
01446
01447 if (! (m_spreadSheetMode && m_rowWillBeDeleted>=(rows()-1)))
01448 setCursorPosition(m_rowWillBeDeleted, m_curCol, true);
01449 if (m_verticalHeader)
01450 m_verticalHeader->removeLabel();
01451
01452 updateAllVisibleRowsBelow(m_curRow);
01453
01454
01455 m_navPanel->setRecordCount(rows());
01456
01457 m_rowWillBeDeleted = -1;
01458 }
01459 }
01460
01461 bool KexiDataAwareObjectInterface::beforeDeleteItem(KexiTableItem *)
01462 {
01463
01464 return true;
01465 }
01466
01467 bool KexiDataAwareObjectInterface::deleteItem(KexiTableItem *item)
01468 {
01469 if (!item || !beforeDeleteItem(item))
01470 return false;
01471
01472 QString msg, desc;
01473
01474 const bool lastRowDeleted = m_spreadSheetMode && m_data->last() == item;
01475
01476
01477 if (!m_data->deleteRow(*item, true )) {
01478
01479 if (m_data->result()->desc.isEmpty())
01480 KMessageBox::sorry(dynamic_cast<QWidget*>(this), m_data->result()->msg);
01481 else
01482 KMessageBox::detailedSorry(dynamic_cast<QWidget*>(this), m_data->result()->msg, m_data->result()->desc);
01483 return false;
01484 }
01485 else {
01486
01487
01488 }
01489
01490
01491 if (m_spreadSheetMode) {
01492 m_data->append(m_data->createItem());
01493 if (m_verticalHeader)
01494 m_verticalHeader->addLabels(1);
01495 if (lastRowDeleted)
01496 setCursorPosition(rows()-1, m_curCol, true);
01497 }
01498 return true;
01499 }
01500
01501 KexiTableViewColumn* KexiDataAwareObjectInterface::column(int col)
01502 {
01503 return m_data->column(col);
01504 }
01505
01506 const QVariant* KexiDataAwareObjectInterface::bufferedValueAt(int col)
01507 {
01508 if (m_rowEditing && m_data->rowEditBuffer())
01509 {
01510
01511 KexiTableViewColumn* tvcol = column(col);
01512 if (tvcol->isDBAware) {
01513
01514 const QVariant *cv = m_data->rowEditBuffer()->at( *tvcol->fieldinfo );
01515 if (cv)
01516 return cv;
01517
01518 const int realFieldNumber = fieldNumberForColumn(col);
01519 if (realFieldNumber < 0) {
01520 kdWarning() << "KexiDataAwareObjectInterface::bufferedValueAt(): fieldNumberForColumn(m_curCol) < 0" << endl;
01521 return 0;
01522 }
01523 return &m_currentItem->at( realFieldNumber );
01524 }
01525 const QVariant *cv = m_data->rowEditBuffer()->at( tvcol->field()->name() );
01526 if (cv)
01527 return cv;
01528 }
01529 const int realFieldNumber = fieldNumberForColumn(col);
01530 if (realFieldNumber < 0) {
01531 kdWarning() << "KexiDataAwareObjectInterface::bufferedValueAt(): fieldNumberForColumn(m_curCol) < 0" << endl;
01532 return 0;
01533 }
01534 return &m_currentItem->at( realFieldNumber );
01535 }
01536
01537 void KexiDataAwareObjectInterface::startEditOrToggleValue()
01538 {
01539 if ( !isReadOnly() && columnEditable(m_curCol) ) {
01540 if (columnType(m_curCol) == KexiDB::Field::Boolean) {
01541 boolToggled();
01542 }
01543 else {
01544 startEditCurrentCell();
01545 return;
01546 }
01547 }
01548 }
01549
01550 void KexiDataAwareObjectInterface::boolToggled()
01551 {
01552 startEditCurrentCell();
01553 if (m_editor) {
01554 m_editor->clickedOnContents();
01555 }
01556 acceptEditor();
01557 updateCell(m_curRow, m_curCol);
01558
01559
01560
01561
01562
01563
01564
01565 }
01566
01567 void KexiDataAwareObjectInterface::slotDataDestroying()
01568 {
01569 m_data = 0;
01570 m_itemIterator = 0;
01571 }
01572
01573 void KexiDataAwareObjectInterface::addNewRecordRequested()
01574 {
01575 if (!isInsertingEnabled())
01576 return;
01577 if (m_rowEditing) {
01578 if (!acceptRowEdit())
01579 return;
01580 }
01581
01582 selectRow(rows());
01583 startEditCurrentCell();
01584 if (m_editor)
01585 m_editor->setFocus();
01586 }
01587