Kexi API Documentation (2.0 alpha)

kexidataawareobjectiface.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2005-2006 Jaroslaw Staniek <js@iidea.pl>
00003 
00004    Based on KexiTableView code.
00005    Copyright (C) 2002 Till Busch <till@bux.at>
00006    Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
00007    Copyright (C) 2003 Daniel Molkentin <molkentin@kde.org>
00008    Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org>
00009 
00010    This program is free software; you can redistribute it and/or
00011    modify it under the terms of the GNU Library General Public
00012    License as published by the Free Software Foundation; either
00013    version 2 of the License, or (at your option) any later version.
00014 
00015    This program is distributed in the hope that it will be useful,
00016    but WITHOUT ANY WARRANTY; without even the implied warranty of
00017    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018    Library General Public License for more details.
00019 
00020    You should have received a copy of the GNU Library General Public License
00021    along with this program; see the file COPYING.  If not, write to
00022    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00023  * Boston, MA 02110-1301, USA.
00024 */
00025 
00026 #include "kexidataawareobjectiface.h"
00027 
00028 #include <qscrollview.h>
00029 #include <qlabel.h>
00030 #include <qtooltip.h>
00031 
00032 #include <kmessagebox.h>
00033 
00034 #include <kexi.h>
00035 #include <kexiutils/validator.h>
00036 #include <widget/utils/kexirecordnavigator.h>
00037 #include <widget/utils/kexirecordmarker.h>
00038 #include <kexidb/roweditbuffer.h>
00039 #include <kexidataiteminterface.h>
00040 
00041 #include "kexitableviewheader.h"
00042 
00043 using namespace KexiUtils;
00044 
00045 KexiDataAwareObjectInterface::KexiDataAwareObjectInterface()
00046 {
00047     m_data = 0;
00048     m_itemIterator = 0;
00049     m_readOnly = -1; //don't know
00050     m_insertingEnabled = -1; //don't know
00051     m_isSortingEnabled = true;
00052     m_isFilteringEnabled = true;
00053     m_deletionPolicy = AskDelete;
00054     m_inside_acceptEditor = false;
00055     m_acceptsRowEditAfterCellAccepting = false;
00056     m_internal_acceptsRowEditAfterCellAccepting = false;
00057     m_contentsMousePressEvent_dblClick = false;
00058     m_navPanel = 0;
00059     m_initDataContentsOnShow = false;
00060     m_cursorPositionSetExplicityBeforeShow = false;
00061     m_verticalHeader = 0;
00062     m_horizontalHeader = 0;
00063     m_insertItem = 0;
00064 //  m_rowEditBuffer = 0;
00065     m_spreadSheetMode = false;
00066     m_dropsAtRowEnabled = false;
00067     m_updateEntireRowWhenMovingToOtherRow = false;
00068     m_dragIndicatorLine = -1;
00069     m_emptyRowInsertingEnabled = false;
00070     m_popupMenu = 0;
00071     m_contextMenuEnabled = true;
00072     m_rowWillBeDeleted = -1;
00073     m_alsoUpdateNextRow = false;
00074     m_verticalHeaderAlreadyAdded = false;
00075     m_vScrollBarValueChanged_enabled = true;
00076     m_scrollbarToolTipsEnabled = true;
00077     m_scrollBarTipTimerCnt = 0;
00078     m_scrollBarTip = 0;
00079 
00080     // setup scrollbar tooltip and related members
00081     m_scrollBarTip = new QLabel("",0, "vScrollBarToolTip",
00082         Qt::WStyle_Customize |Qt::WStyle_NoBorder|Qt::WX11BypassWM|Qt::WStyle_StaysOnTop|Qt::WStyle_Tool);
00083     m_scrollBarTip->setPalette(QToolTip::palette());
00084     m_scrollBarTip->setMargin(2);
00085     m_scrollBarTip->setIndent(0);
00086     m_scrollBarTip->setAlignment(Qt::AlignCenter);
00087     m_scrollBarTip->setFrameStyle( QFrame::Plain | QFrame::Box );
00088     m_scrollBarTip->setLineWidth(1);
00089 
00090     clearVariables();
00091 }
00092 
00093 KexiDataAwareObjectInterface::~KexiDataAwareObjectInterface()
00094 {
00095     delete m_insertItem;
00096 //  delete m_rowEditBuffer;
00097     delete m_itemIterator;
00098     delete m_scrollBarTip;
00099     //we cannot delete m_data here... subclasses should do this
00100 }
00101 
00102 void KexiDataAwareObjectInterface::clearVariables()
00103 {
00104     m_editor = 0;
00105 //  m_rowEditBuffer = 0;
00106     m_rowEditing = false;
00107     m_newRowEditing = false;
00108     m_curRow = -1;
00109     m_curCol = -1;
00110     m_currentItem = 0;
00111 }
00112 
00113 void KexiDataAwareObjectInterface::setData( KexiTableViewData *data, bool owner )
00114 {
00115     const bool theSameData = m_data && m_data==data;
00116     if (m_owner && m_data && m_data!=data/*don't destroy if it's the same*/) {
00117         kexidbg << "KexiDataAwareObjectInterface::setData(): destroying old data (owned)" << endl;
00118         delete m_itemIterator;
00119         delete m_data; //destroy old data
00120         m_data = 0;
00121         m_itemIterator = 0;
00122     }
00123     m_owner = owner;
00124     m_data = data;
00125     if (m_data)
00126         m_itemIterator = m_data->createIterator();
00127 
00128     kdDebug(44021) << "KexiDataAwareObjectInterface::setData(): using shared data" << endl;
00129         //add columns
00130 //OK?
00131     clearColumnsInternal(false);
00132     if (m_data) {
00133         int i = 0;
00134         for (KexiTableViewColumn::ListIterator it(m_data->columns);
00135             it.current(); ++it, i++) 
00136         {
00137             KexiDB::Field *f = it.current()->field();
00138             if (it.current()->visible()) {
00139                 int wid = f->width();
00140                 if (wid==0)
00141                     wid=KEXI_DEFAULT_DATA_COLUMN_WIDTH;//default col width in pixels
00143                 addHeaderColumn(it.current()->isHeaderTextVisible()
00144                     ? it.current()->captionAliasOrName() : QString::null,
00145                     f->description(), it.current()->icon(), wid);
00146             }
00147         }
00148     }
00149     if (m_verticalHeader) {
00150         m_verticalHeader->clear();
00151         if (m_data)
00152             m_verticalHeader->addLabels(m_data->count());
00153     }
00154     if (m_data && m_data->count()==0)
00155         m_navPanel->setCurrentRecordNumber(0+1);
00156     
00157     if (m_data && !theSameData) {
00159         setSorting(-1);
00160 //      connect(m_data, SIGNAL(refreshRequested()), this, SLOT(slotRefreshRequested()));
00161         connectToReloadDataSlot(m_data, SIGNAL(reloadRequested()));
00162         QObject* thisObject = dynamic_cast<QObject*>(this);
00163         if (thisObject) {
00164             QObject::connect(m_data, SIGNAL(destroying()), thisObject, SLOT(slotDataDestroying()));
00165             QObject::connect(m_data, SIGNAL(rowsDeleted( const QValueList<int> & )), 
00166                 thisObject, SLOT(slotRowsDeleted( const QValueList<int> & )));
00167             QObject::connect(m_data, SIGNAL(aboutToDeleteRow(KexiTableItem&,KexiDB::ResultInfo*,bool)),
00168                 thisObject, SLOT(slotAboutToDeleteRow(KexiTableItem&,KexiDB::ResultInfo*,bool)));
00169             QObject::connect(m_data, SIGNAL(rowDeleted()), thisObject, SLOT(slotRowDeleted()));
00170             QObject::connect(m_data, SIGNAL(rowInserted(KexiTableItem*,bool)), 
00171                 thisObject, SLOT(slotRowInserted(KexiTableItem*,bool)));
00172             QObject::connect(m_data, SIGNAL(rowInserted(KexiTableItem*,uint,bool)), 
00173                 thisObject, SLOT(slotRowInserted(KexiTableItem*,uint,bool))); //not db-aware
00174             QObject::connect(m_data, SIGNAL(rowRepaintRequested(KexiTableItem&)), 
00175                 thisObject, SLOT(slotRowRepaintRequested(KexiTableItem&)));
00176             // setup scrollbar's tooltip
00177             QObject::connect(verticalScrollBar(),SIGNAL(sliderReleased()),
00178                 thisObject,SLOT(vScrollBarSliderReleased()));
00179             QObject::connect(verticalScrollBar(),SIGNAL(valueChanged(int)),
00180                 thisObject,SLOT(vScrollBarValueChanged(int)));
00181             QObject::connect(&m_scrollBarTipTimer,SIGNAL(timeout()),
00182                 thisObject,SLOT(scrollBarTipTimeout()));
00183         }
00184     }
00185 
00186     if (!m_data) {
00187 //      clearData();
00188         cancelRowEdit();
00189         //m_data->clearInternal();
00190         clearVariables();
00191     }
00192     else {
00193         if (!m_insertItem) {//first setData() call - add 'insert' item
00194             m_insertItem = m_data->createItem(); //new KexiTableItem(m_data->columns.count());
00195         }
00196         else {//just reinit
00197             m_insertItem->init(m_data->columns.count());
00198         }
00199     }
00200 
00201     //update gui mode
00202     m_navPanel->setInsertingEnabled(m_data && isInsertingEnabled());
00203     if (m_verticalHeader)
00204         m_verticalHeader->showInsertRow(m_data && isInsertingEnabled());
00205 
00206     initDataContents();
00207 
00208     if (m_data)
00209         /*emit*/ dataSet( m_data );
00210 }
00211 
00212 void KexiDataAwareObjectInterface::initDataContents()
00213 {
00214     m_editor = 0;
00215 //  QSize s(tableSize());
00216 //  resizeContents(s.width(),s.height());
00217 
00218     m_navPanel->setRecordCount(rows());
00219 
00220     if (m_data && !m_cursorPositionSetExplicityBeforeShow) {
00221         //set current row:
00222         m_currentItem = 0;
00223         int curRow = -1, curCol = -1;
00224         if (m_data->columnsCount()>0) {
00225             if (rows()>0) {
00226                 m_itemIterator->toFirst();
00227                 m_currentItem = **m_itemIterator; //m_data->first();
00228                 curRow = 0;
00229                 curCol = 0;
00230             }
00231             else {//no data
00232                 if (isInsertingEnabled()) {
00233                     m_currentItem = m_insertItem;
00234                     curRow = 0;
00235                     curCol = 0;
00236                 }
00237             }
00238         }
00239         setCursorPosition(curRow, curCol, true/*force*/);
00240     }
00241     ensureCellVisible(m_curRow, m_curCol);
00242 //  updateRowCountInfo();
00243 //  setNavRowCount(rows());
00244 
00245 //OK?
00246 // updateContents();
00247     updateWidgetContents();
00248 
00249     m_cursorPositionSetExplicityBeforeShow = false;
00250 
00251     /*emit*/ dataRefreshed();
00252 }
00253 
00254 void KexiDataAwareObjectInterface::setSortingEnabled(bool set)
00255 {
00256     if (m_isSortingEnabled && !set)
00257         setSorting(-1);
00258     m_isSortingEnabled = set;
00259     /*emit*/ reloadActions();
00260 }
00261 
00262 void KexiDataAwareObjectInterface::setSorting(int col, bool ascending)
00263 {
00264     if (!m_data || !m_isSortingEnabled)
00265         return;
00266 //  d->pTopHeader->setSortIndicator(col, ascending ? Ascending : Descending);
00267     setLocalSortingOrder(col, ascending ? 1 : -1);
00268     m_data->setSorting(col, ascending);
00269 }
00270 
00271 int KexiDataAwareObjectInterface::dataSortedColumn() const
00272 {
00273     if (m_data && m_isSortingEnabled)
00274         return m_data->sortedColumn();
00275     return -1;
00276 }
00277 
00278 int KexiDataAwareObjectInterface::dataSortingOrder() const
00279 {
00280     return m_data ? m_data->sortingOrder() : 0;
00281 }
00282 
00283 bool KexiDataAwareObjectInterface::sort()
00284 {
00285     if (!m_data || !m_isSortingEnabled)
00286         return false;
00287 
00288     if (rows() < 2)
00289         return true;
00290 
00291     if (!acceptRowEdit())
00292         return false;
00293 
00294     const int oldRow = m_curRow;
00295     if (m_data->sortedColumn()!=-1)
00296         m_data->sort();
00297 
00298     //locate current record
00299     if (!m_currentItem) {
00300         m_itemIterator->toFirst();
00301         m_currentItem = **m_itemIterator; //m_data->first();
00302         m_curRow = 0;
00303         if (!m_currentItem)
00304             return true;
00305     }
00306     if (m_currentItem != m_insertItem) {
00307         m_curRow = m_data->findRef(m_currentItem);
00308         int jump = m_curRow - oldRow;
00309         if (jump<0)
00310             (*m_itemIterator) -= -jump;
00311         else
00312             (*m_itemIterator) += jump;
00313     }
00314 
00315     updateGUIAfterSorting();
00316     editorShowFocus( m_curRow, m_curCol );
00317     if (m_verticalHeader)
00318         m_verticalHeader->setCurrentRow(m_curRow);
00319     if (m_horizontalHeader)
00320         m_horizontalHeader->setSelectedSection(m_curCol);
00321     if (m_navPanel)
00322         m_navPanel->setCurrentRecordNumber(m_curRow+1);
00323     return true;
00324 }
00325 
00326 void KexiDataAwareObjectInterface::sortAscending()
00327 {
00328     if (currentColumn()<0)
00329         return;
00330     sortColumnInternal( currentColumn(), 1 );
00331 }
00332 
00333 void KexiDataAwareObjectInterface::sortDescending()
00334 {
00335     if (currentColumn()<0)
00336         return;
00337     sortColumnInternal( currentColumn(), -1 );
00338 }
00339 
00340 void KexiDataAwareObjectInterface::sortColumnInternal(int col, int order)
00341 {
00342     //-select sorting 
00343     bool asc;
00344     if (order == 0) {// invert
00345         if (col==dataSortedColumn() && dataSortingOrder()==1)
00346             asc = dataSortingOrder()==-1; //inverse sorting for this column -> descending order
00347         else
00348             asc = true;
00349     }
00350     else
00351         asc = (order==1);
00352     
00353     int prevSortOrder = currentLocalSortingOrder();
00354     const int prevSortColumn = currentLocalSortingOrder();
00355     setSorting( col, asc );
00356     //-perform sorting 
00357     if (!sort())
00358         setLocalSortingOrder(prevSortColumn, prevSortOrder); //this will also remove indicator
00359                                                              //if prevSortColumn==-1
00360     if (col != prevSortColumn)
00361         /*emit*/ sortedColumnChanged(col);
00362 }
00363 
00364 bool KexiDataAwareObjectInterface::isInsertingEnabled() const
00365 {
00366     if (isReadOnly())
00367         return false;
00368     if (m_insertingEnabled == 1 || m_insertingEnabled == 0)
00369         return (bool)m_insertingEnabled;
00370     if (!hasData())
00371         return true;
00372     return m_data->isInsertingEnabled();
00373 }
00374 
00375 void KexiDataAwareObjectInterface::setFilteringEnabled(bool set)
00376 {
00377     m_isFilteringEnabled = set;
00378 }
00379 
00380 bool KexiDataAwareObjectInterface::isDeleteEnabled() const
00381 {
00382     return (m_deletionPolicy != NoDelete) && !isReadOnly();
00383 }
00384 
00385 void KexiDataAwareObjectInterface::setDeletionPolicy(DeletionPolicy policy)
00386 {
00387     m_deletionPolicy = policy;
00388 //  updateContextMenu();
00389 }
00390 
00391 void KexiDataAwareObjectInterface::setReadOnly(bool set)
00392 {
00393     if (isReadOnly() == set || (m_data && m_data->isReadOnly() && !set))
00394         return; //not allowed!
00395     m_readOnly = (set ? 1 : 0);
00396     if (set)
00397         setInsertingEnabled(false);
00398     updateWidgetContents();
00399     /*emit*/ reloadActions();
00400 }
00401 
00402 bool KexiDataAwareObjectInterface::isReadOnly() const
00403 {
00404     if (!hasData())
00405         return true;
00406     if (m_readOnly == 1 || m_readOnly == 0)
00407         return (bool)m_readOnly;
00408     if (!hasData())
00409         return true;
00410     return m_data->isReadOnly();
00411 }
00412 
00413 void KexiDataAwareObjectInterface::setInsertingEnabled(bool set)
00414 {
00415     if (isInsertingEnabled() == set || (m_data && !m_data->isInsertingEnabled() && set))
00416         return; //not allowed!
00417     m_insertingEnabled = (set ? 1 : 0);
00418     m_navPanel->setInsertingEnabled(set);
00419     if (m_verticalHeader)
00420         m_verticalHeader->showInsertRow(set);
00421     if (set)
00422         setReadOnly(false);
00423 //  update();
00424     updateWidgetContents();
00425     /*emit*/ reloadActions();
00426 }
00427 
00428 void KexiDataAwareObjectInterface::setSpreadSheetMode()
00429 {
00430     m_spreadSheetMode = true;
00431     setSortingEnabled( false );
00432     setInsertingEnabled( false );
00433     setAcceptsRowEditAfterCellAccepting( true );
00434     setFilteringEnabled( false );
00435     setEmptyRowInsertingEnabled( true );
00436     m_navPanelEnabled = false;
00437 }
00438 
00439 void KexiDataAwareObjectInterface::selectNextRow()
00440 {
00441     selectRow( QMIN( rows() - 1 +(isInsertingEnabled()?1:0), m_curRow + 1 ) );
00442 }
00443 
00444 void KexiDataAwareObjectInterface::selectPrevPage()
00445 {
00446     selectRow( 
00447         QMAX( 0, m_curRow - rowsPerPage() )
00448     );
00449 }
00450 
00451 void KexiDataAwareObjectInterface::selectNextPage()
00452 {
00453     selectRow( 
00454         QMIN( 
00455             rows() - 1 + (isInsertingEnabled()?1:0),
00456             m_curRow + rowsPerPage()
00457         )
00458     );
00459 }
00460 
00461 void KexiDataAwareObjectInterface::selectFirstRow()
00462 {
00463     selectRow(0);
00464 }
00465 
00466 void KexiDataAwareObjectInterface::selectLastRow()
00467 {
00468 //  selectRow(rows() - 1 + (isInsertingEnabled()?1:0));
00469     selectRow(rows() - 1);
00470 }
00471 
00472 void KexiDataAwareObjectInterface::selectRow(int row)
00473 {
00474     m_vScrollBarValueChanged_enabled = false; //disable tooltip
00475     setCursorPosition(row, -1);
00476     m_vScrollBarValueChanged_enabled = true;
00477 }
00478 
00479 void KexiDataAwareObjectInterface::selectPrevRow()
00480 {
00481     selectRow( QMAX( 0, m_curRow - 1 ) );
00482 }
00483 
00484 void KexiDataAwareObjectInterface::clearSelection()
00485 {
00486 //  selectRow( -1 );
00487     int oldRow = m_curRow;
00488 //  int oldCol = m_curCol;
00489     m_curRow = -1;
00490     m_curCol = -1;
00491     m_currentItem = 0;
00492     updateRow( oldRow );
00493     m_navPanel->setCurrentRecordNumber(0);
00494 //  setNavRowNumber(-1);
00495 }
00496 
00497 void KexiDataAwareObjectInterface::setCursorPosition(int row, int col/*=-1*/, bool forceSet)
00498 {
00499     int newrow = row;
00500     int newcol = col;
00501 
00502     if(rows() <= 0) {
00503         if (m_verticalHeader)
00504             m_verticalHeader->setCurrentRow(-1);
00505         if (m_horizontalHeader)
00506             m_horizontalHeader->setSelectedSection(-1);
00507         if (isInsertingEnabled()) {
00508             m_currentItem=m_insertItem;
00509             newrow=0;
00510             if (col>=0)
00511                 newcol=col;
00512             else
00513                 newcol=0;
00514         }
00515         else {
00516             m_currentItem=0;
00517             m_curRow=-1;
00518             m_curCol=-1;
00519             return;
00520         }
00521     }
00522 
00523     if(col>=0)
00524     {
00525         newcol = QMAX(0, col);
00526         newcol = QMIN(columns() - 1, newcol);
00527     }
00528     else {
00529         newcol = m_curCol; //no changes
00530         newcol = QMAX(0, newcol); //may not be < 0 !
00531     }
00532     newrow = QMAX(0, row);
00533     newrow = QMIN(rows() - 1 + (isInsertingEnabled()?1:0), newrow);
00534 
00535 //  d->pCurrentItem = itemAt(d->curRow);
00536 //  kdDebug(44021) << "setCursorPosition(): d->curRow=" << d->curRow << " oldRow=" << oldRow << " d->curCol=" << d->curCol << " oldCol=" << oldCol << endl;
00537 
00538     if ( forceSet || m_curRow != newrow || m_curCol != newcol )
00539     {
00540         kexidbg << "setCursorPosition(): " <<QString("old:%1,%2 new:%3,%4").arg(m_curCol)
00541             .arg(m_curRow).arg(newcol).arg(newrow) << endl;
00542         
00543         // cursor moved: get rid of editor
00544         if (m_editor) {
00545             if (!m_contentsMousePressEvent_dblClick) {
00546                 if (!acceptEditor()) {
00547                     return;
00548                 }
00549                 //update row num. again
00550                 newrow = QMIN( rows() - 1 + (isInsertingEnabled()?1:0), newrow);
00551             }
00552         }
00553         if (m_errorMessagePopup) {
00554             m_errorMessagePopup->close();
00555         }
00556 
00557         if (m_curRow != newrow) {//update current row info
00558             m_navPanel->setCurrentRecordNumber(newrow+1);
00559 //          setNavRowNumber(newrow);
00560 //          d->navBtnPrev->setEnabled(newrow>0);
00561 //          d->navBtnFirst->setEnabled(newrow>0);
00562 //          d->navBtnNext->setEnabled(newrow<(rows()-1+(isInsertingEnabled()?1:0)));
00563 //          d->navBtnLast->setEnabled(newrow!=(rows()-1));
00564         }
00565 
00566         // cursor moved to other row: end of row editing
00567         bool newRowInserted = false;
00568         if (m_rowEditing && m_curRow != newrow) {
00569             newRowInserted = m_newRowEditing;
00570             if (!acceptRowEdit()) {
00571                 //accepting failed: cancel setting the cursor
00572                 return;
00573             }
00574             //update row number, because number of rows changed
00575             newrow = QMIN( rows() - 1 + (isInsertingEnabled()?1:0), newrow);
00576 
00577             m_navPanel->setCurrentRecordNumber(newrow+1); //refresh
00578         }
00579 
00580         //change position
00581         int oldRow = m_curRow;
00582         int oldCol = m_curCol;
00583         m_curRow = newrow;
00584         m_curCol = newcol;
00585 
00586 //      int cw = columnWidth( d->curCol );
00587 //      int rh = rowHeight();
00588 //      ensureVisible( columnPos( d->curCol ) + cw / 2, rowPos( d->curRow ) + rh / 2, cw / 2, rh / 2 );
00589 //      center(columnPos(d->curCol) + cw / 2, rowPos(d->curRow) + rh / 2, cw / 2, rh / 2);
00590 //  kdDebug(44021) << " contentsY() = "<< contentsY() << endl;
00591 
00592 //js        if (oldRow > d->curRow)
00593 //js            ensureVisible(columnPos(d->curCol), rowPos(d->curRow) + rh, columnWidth(d->curCol), rh);
00594 //js        else// if (oldRow <= d->curRow)
00595 //js        ensureVisible(columnPos(d->curCol), rowPos(d->curRow), columnWidth(d->curCol), rh);
00596 
00597 
00598         //show editor-dependent focus, if we're changing the current column
00599         if (oldCol>=0 && oldCol<columns() && m_curCol!=oldCol) {
00600             //find the editor for this column
00601             KexiDataItemInterface *edit = editor( oldCol );
00602             if (edit) {
00603                 edit->hideFocus();
00604             }
00605         }
00606 
00607         //show editor-dependent focus, if needed
00608         editorShowFocus( m_curRow, m_curCol );
00609 
00610         if (m_updateEntireRowWhenMovingToOtherRow)
00611             updateRow( oldRow );
00612         else
00613             updateCell( oldRow, oldCol );
00614 
00615 //      //quite clever: ensure the cell is visible:
00616 //      ensureCellVisible(m_curRow, m_curCol);
00617 
00618 //      QPoint pcenter = QRect( columnPos(d->curCol), rowPos(d->curRow), columnWidth(d->curCol), rh).center();
00619 //      ensureVisible(pcenter.x(), pcenter.y(), columnWidth(d->curCol)/2, rh/2);
00620 
00621 //      ensureVisible(columnPos(d->curCol), rowPos(d->curRow) - contentsY(), columnWidth(d->curCol), rh);
00622         if (m_verticalHeader && oldRow != m_curRow)
00623             m_verticalHeader->setCurrentRow(m_curRow);
00624 
00625         if (m_updateEntireRowWhenMovingToOtherRow)
00626             updateRow( m_curRow );
00627         else
00628             updateCell( m_curRow, m_curCol );
00629 
00630         if (m_curCol != oldCol || m_curRow != oldRow ) {//ensure this is also refreshed
00631             if (!m_updateEntireRowWhenMovingToOtherRow) //only if entire row has not been updated
00632                 updateCell( oldRow, m_curCol );
00633         }
00634         //update row
00635         if (forceSet || m_curRow != oldRow) {
00636             if (isInsertingEnabled() && m_curRow == rows()) {
00637                 kdDebug(44021) << "NOW insert item is current" << endl;
00638                 m_currentItem = m_insertItem;
00639             }
00640             else {
00641                 kdDebug(44021) << QString("NOW item at %1 (%2) is current")
00642                     .arg(m_curRow).arg((ulong)itemAt(m_curRow)) << endl;
00643     //NOT EFFECTIVE!!!!!!!!!!!
00644                 //set item iterator
00645                 if (!newRowInserted && isInsertingEnabled() && m_currentItem == m_insertItem && m_curRow == (rows()-1)) {
00646                     //moving from 'insert item' to last item
00647                     m_itemIterator->toLast();
00648                 }
00649                 else if (!newRowInserted && !forceSet && m_currentItem != m_insertItem && 0==m_curRow)
00650                     m_itemIterator->toFirst();
00651                 else if (!newRowInserted && !forceSet && m_currentItem != m_insertItem && oldRow>=0 && (oldRow+1)==m_curRow) //just move next
00652                     ++(*m_itemIterator);
00653                 else if (!newRowInserted && !forceSet && m_currentItem != m_insertItem && oldRow>=0 && (oldRow-1)==m_curRow) //just move back
00654                     --(*m_itemIterator);
00655                 else { //move at:
00656                     m_itemIterator->toFirst();
00657                     (*m_itemIterator)+=m_curRow;
00658                 }
00659                 if (!**m_itemIterator) { //sanity
00660                     m_itemIterator->toFirst();
00661                     (*m_itemIterator)+=m_curRow;
00662                 }
00663                 m_currentItem = **m_itemIterator;
00664                     //itemAt(m_curRow);
00665             }
00666         }
00667 
00668         //quite clever: ensure the cell is visible:
00669         ensureCellVisible(m_curRow, m_curCol);
00670 
00671         if (m_horizontalHeader && oldCol != m_curCol)
00672             m_horizontalHeader->setSelectedSection(m_curCol);
00673 
00674         /*emit*/ itemSelected(m_currentItem);
00675         /*emit*/ cellSelected(m_curCol, m_curRow);
00676         /* only needed for forms */
00677         selectCellInternal();
00678     }
00679     else {
00680             kexidbg << "setCursorPosition(): NO CHANGE" << endl;
00681     }
00682 
00683     if(m_initDataContentsOnShow) {
00684         m_cursorPositionSetExplicityBeforeShow = true;
00685     }
00686 }
00687 
00688 bool KexiDataAwareObjectInterface::acceptRowEdit()
00689 {
00690     if (!m_rowEditing || /*sanity*/!m_data->rowEditBuffer())
00691         return true;
00692     if (m_inside_acceptEditor) {
00693         m_internal_acceptsRowEditAfterCellAccepting = true;
00694         return true;
00695     }
00696     m_internal_acceptsRowEditAfterCellAccepting = false;
00697 
00698     const int columnEditedBeforeAccepting = m_editor ? currentColumn() : -1;
00699     if (!acceptEditor())
00700         return false;
00701     kdDebug() << "EDIT ROW ACCEPTING..." << endl;
00702 
00703     bool success = true;
00704 //  bool allow = true;
00705 //  int faultyColumn = -1; // will be !=-1 if cursor has to be moved to that column
00706     const bool inserting = m_newRowEditing;
00707 //  QString msg, desc;
00708 //  bool inserting = d->pInsertItem && d->pInsertItem==d->pCurrentItem;
00709 
00710     if (m_data->rowEditBuffer()->isEmpty() && !m_newRowEditing) {
00711 /*      if (d->newRowEditing) {
00712             cancelRowEdit();
00713             kdDebug() << "-- NOTHING TO INSERT!!!" << endl;
00714             return true;
00715         }
00716         else {*/
00717             kdDebug() << "-- NOTHING TO ACCEPT!!!" << endl;
00718 //      }
00719     }
00720     else {//not empty edit buffer or new row to insert:
00721         if (m_newRowEditing) {
00722 //          emit aboutToInsertRow(d->pCurrentItem, m_data->rowEditBuffer(), success, &faultyColumn);
00723 //          if (success) {
00724             kdDebug() << "-- INSERTING: " << endl;
00725             m_data->rowEditBuffer()->debug();
00726             success = m_data->saveNewRow(*m_currentItem);
00727 //              if (!success) {
00728 //              }
00729 //          }
00730         }
00731         else {
00732 //          emit aboutToUpdateRow(d->pCurrentItem, m_data->rowEditBuffer(), success, &faultyColumn);
00733             if (success) {
00734                 //accept changes for this row:
00735                 kdDebug() << "-- UPDATING: " << endl;
00736                 m_data->rowEditBuffer()->debug();
00737                 kdDebug() << "-- BEFORE: " << endl;
00738                 m_currentItem->debug();
00739                 success = m_data->saveRowChanges(*m_currentItem);//, &msg, &desc, &faultyColumn);
00740                 kdDebug() << "-- AFTER: " << endl;
00741                 m_currentItem->debug();
00742 
00743 //              if (!success) {
00744 //              }
00745             }
00746         }
00747     }
00748 
00749     if (success) {
00750         //editing is finished:
00751         if (m_newRowEditing) {
00752             //update current-item-iterator
00753             m_itemIterator->toLast();
00754             m_currentItem = **m_itemIterator;
00755         }
00756         m_rowEditing = false;
00757         m_newRowEditing = false;
00758         //indicate on the vheader that we are not editing
00759         if (m_verticalHeader)
00760             m_verticalHeader->setEditRow(-1);
00761 
00762         updateAfterAcceptRowEdit();
00763 
00764         kdDebug() << "EDIT ROW ACCEPTED:" << endl;
00765 //      /*debug*/itemAt(m_curRow);
00766 
00767         if (inserting) {
00768 //          emit rowInserted(d->pCurrentItem);
00769             //update navigator's data
00770             m_navPanel->setRecordCount(rows());
00771         }
00772         else {
00773 //          emit rowUpdated(d->pCurrentItem);
00774         }
00775 
00776         /*emit*/ rowEditTerminated(m_curRow);
00777     }
00778     else {
00779 //      if (!allow) {
00780 //          kdDebug() << "INSERT/EDIT ROW - DISALLOWED by signal!" << endl;
00781 //      }
00782 //      else {
00783 //          kdDebug() << "EDIT ROW - ERROR!" << endl;
00784 //      }
00785         int faultyColumn = -1;
00786         if (m_data->result()->column >= 0 && m_data->result()->column < columns())
00787             faultyColumn = m_data->result()->column;
00788         else if (columnEditedBeforeAccepting >= 0)
00789             faultyColumn = columnEditedBeforeAccepting;
00790         if (faultyColumn >= 0) {
00791             setCursorPosition(m_curRow, faultyColumn);
00792         }
00793 
00794         const int button = showErrorMessageForResult( m_data->result() );
00795         if (KMessageBox::No == button) {
00796             //discard changes
00797             cancelRowEdit();
00798         }
00799         else {
00800             if (faultyColumn >= 0) {
00801                 //edit this cell
00802                 startEditCurrentCell();
00803             }
00804         }
00805     }
00806 
00807     return success;
00808 }
00809 
00810 bool KexiDataAwareObjectInterface::cancelRowEdit()
00811 {
00812     if (!hasData())
00813         return false;
00814     if (!m_rowEditing)
00815         return false;
00816     cancelEditor();
00817     m_rowEditing = false;
00818     //indicate on the vheader that we are not editing
00819     if (m_verticalHeader)
00820         m_verticalHeader->setEditRow(-1);
00821     m_alsoUpdateNextRow = m_newRowEditing;
00822     if (m_newRowEditing) {
00823         m_newRowEditing = false;
00824         //remove current edited row (it is @ the end of list)
00825         m_data->removeLast();
00826         //current item is now empty, last row
00827         m_currentItem = m_insertItem;
00828         //update visibility
00829         if (m_verticalHeader)
00830             m_verticalHeader->removeLabel(false); //-1 label
00831 //      updateContents(columnPos(0), rowPos(rows()), 
00832 //          viewport()->width(), d->rowHeight*3 + (m_navPanel ? m_navPanel->height() : 0)*3 );
00833 //      updateContents(); //js: above did not work well so we do that dirty
00834         updateWidgetContents();
00835 //TODO: still doesn't repaint properly!!
00836 //      QSize s(tableSize());
00837 //      resizeContents(s.width(), s.height());
00838         updateWidgetContentsSize();
00839 //      m_verticalHeader->update();
00840         //--no cancel action is needed for datasource, 
00841         //  because the row was not yet stored.
00842     }
00843 
00844     m_data->clearRowEditBuffer();
00845     updateAfterCancelRowEdit();
00846     
00848     kexidbg << "EDIT ROW CANCELLED." << endl;
00849 
00850     /*emit*/ rowEditTerminated(m_curRow);
00851     return true;
00852 }
00853 
00854 void KexiDataAwareObjectInterface::updateAfterCancelRowEdit()
00855 {
00856     updateRow(m_curRow);
00857     if (m_alsoUpdateNextRow)
00858         updateRow(m_curRow+1);
00859     m_alsoUpdateNextRow = false;
00860 }
00861 
00862 void KexiDataAwareObjectInterface::updateAfterAcceptRowEdit()
00863 {
00864     updateRow(m_curRow);
00865 }
00866 
00867 void KexiDataAwareObjectInterface::removeEditor()
00868 {
00869     if (!m_editor)
00870         return;
00871     m_editor->hideWidget();
00872     m_editor = 0;
00873 }
00874 
00875 bool KexiDataAwareObjectInterface::cancelEditor()
00876 {
00877     if (m_errorMessagePopup) {
00878         m_errorMessagePopup->close();
00879     }
00880     if (!m_editor)
00881         return false;
00882     removeEditor();
00883     return true;
00884 }
00885 
00887 class KexiDataAwareObjectInterfaceToolTip : public QToolTip {
00888     public:
00889     KexiDataAwareObjectInterfaceToolTip( const QString & text, const QPoint & pos, QWidget * widget )
00890         : QToolTip(widget), m_text(text)
00891     {
00892         tip( QRect(pos, QSize(100, 100)), text );
00893     }
00894     virtual void maybeTip(const QPoint & p) {
00895         tip( QRect(p, QSize(100, 100)), m_text);
00896     }
00897     QString m_text;
00898 };
00899 
00900 bool KexiDataAwareObjectInterface::acceptEditor()
00901 {
00902     if (!hasData())
00903         return true;
00904     if (!m_editor || m_inside_acceptEditor)
00905         return true;
00906 
00907     m_inside_acceptEditor = true;//avoid recursion
00908 
00909     QVariant newval;
00910     Validator::Result res = Validator::Ok;
00911     QString msg, desc;
00912     bool setNull = false;
00913 //  bool allow = true;
00914 //  static const QString msg_NOT_NULL = i18n("\"%1\" column requires a value to be entered.");
00915 
00916     //autoincremented field can be omitted (left as null or empty) if we're inserting a new row
00917     const bool autoIncColumnCanBeOmitted = m_newRowEditing && m_editor->field()->isAutoIncrement();
00918 //  const bool autoIncColumnCanBeOmitted = m_newRowEditing && m_editor->columnInfo()->field->isAutoIncrement();
00919 
00920     bool valueChanged = m_editor->valueChanged();
00921     bool editCurrentCellAgain = false;
00922 
00923     if (valueChanged) {
00924         if (!m_editor->valueIsValid()) {
00925             //used e.g. for date or time values - the value can be null but not necessary invalid
00926             res = Validator::Error;
00927             editCurrentCellAgain = true;
00928             QWidget *par = dynamic_cast<QScrollView*>(this) ? dynamic_cast<QScrollView*>(this)->viewport() :
00929                     dynamic_cast<QWidget*>(this);
00930             QWidget *edit = dynamic_cast<QWidget*>(m_editor);
00931             if (par && edit) {
00934                 if (!m_errorMessagePopup) {
00935 //                  m_errorMessagePopup->close();
00936                     m_errorMessagePopup = new KexiArrowTip(
00937                         i18n("Error: %1").arg(m_editor->columnInfo()->field->typeName())+"?", 
00938                         dynamic_cast<QWidget*>(this));
00939                     m_errorMessagePopup->move( 
00940                         par->mapToGlobal(edit->pos()) + QPoint(6, edit->height() + 0) );
00941                     m_errorMessagePopup->show();
00942                 }
00943                 m_editor->setFocus();
00944             }
00945         }
00946         else if (m_editor->valueIsNull()) {//null value entered
00947 //          if (m_editor->columnInfo()->field->isNotNull() && !autoIncColumnCanBeOmitted) {
00948             if (m_editor->field()->isNotNull() && !autoIncColumnCanBeOmitted) {
00949                 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NULL NOT ALLOWED!" << endl;
00950                 res = Validator::Error;
00951 //              msg = Validator::msgColumnNotEmpty().arg(m_editor->columnInfo()->field->captionOrName())
00952                 msg = Validator::msgColumnNotEmpty().arg(m_editor->field()->captionOrName())
00953                     + "\n\n" + Kexi::msgYouCanImproveData();
00954                 desc = i18n("The column's constraint is declared as NOT NULL.");
00955                 editCurrentCellAgain = true;
00956     //          allow = false;
00957     //          removeEditor();
00958     //          return true;
00959             }
00960             else {
00961                 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NULL VALUE WILL BE SET" << endl;
00962                 //ok, just leave newval as NULL
00963                 setNull = true;
00964             }
00965         }
00966         else if (m_editor->valueIsEmpty()) {//empty value entered
00967 //          if (m_editor->columnInfo()->field->hasEmptyProperty()) {
00968             if (m_editor->field()->hasEmptyProperty()) {
00969 //              if (m_editor->columnInfo()->field->isNotEmpty() && !autoIncColumnCanBeOmitted) {
00970                 if (m_editor->field()->isNotEmpty() && !autoIncColumnCanBeOmitted) {
00971                     kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): EMPTY NOT ALLOWED!" << endl;
00972                     res = Validator::Error;
00973 //                  msg = Validator::msgColumnNotEmpty().arg(m_editor->columnInfo()->field->captionOrName())
00974                     msg = Validator::msgColumnNotEmpty().arg(m_editor->field()->captionOrName())
00975                         + "\n\n" + Kexi::msgYouCanImproveData();
00976                     desc = i18n("The column's constraint is declared as NOT EMPTY.");
00977                     editCurrentCellAgain = true;
00978     //              allow = false;
00979     //              removeEditor();
00980     //              return true;
00981                 }
00982                 else {
00983                     kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): EMPTY VALUE WILL BE SET" << endl;
00984                 }
00985             }
00986             else {
00987 //              if (m_editor->columnInfo()->field->isNotNull() && !autoIncColumnCanBeOmitted) {
00988                 if (m_editor->field()->isNotNull() && !autoIncColumnCanBeOmitted) {
00989                     kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NEITHER NULL NOR EMPTY VALUE CAN BE SET!" << endl;
00990                     res = Validator::Error;
00991 //                  msg = Validator::msgColumnNotEmpty().arg(m_editor->columnInfo()->field->captionOrName())
00992                     msg = Validator::msgColumnNotEmpty().arg(m_editor->field()->captionOrName())
00993                         + "\n\n" + Kexi::msgYouCanImproveData();
00994                     desc = i18n("The column's constraint is declared as NOT EMPTY and NOT NULL.");
00995                     editCurrentCellAgain = true;
00996 //              allow = false;
00997     //              removeEditor();
00998     //              return true;
00999                 }
01000                 else {
01001                     kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NULL VALUE WILL BE SET BECAUSE EMPTY IS NOT ALLOWED" << endl;
01002                     //ok, just leave newval as NULL
01003                     setNull = true;
01004                 }
01005             }
01006         }
01007     }//changed
01008 
01009     const int realFieldNumber = fieldNumberForColumn(m_curCol);
01010     if (realFieldNumber < 0) {
01011         kdWarning() << "KexiDataAwareObjectInterface::acceptEditor(): fieldNumberForColumn(m_curCol) < 0" << endl;
01012         m_inside_acceptEditor = false;
01013         return false;
01014     }
01015 
01016     KexiTableViewColumn *currentTVColumn = column(m_curCol);
01017 
01018     //try to get the value entered:
01019     if (res == Validator::Ok) {
01020         if ((!setNull && !valueChanged)
01021             || (m_editor->field()->type()!=KexiDB::Field::Boolean && setNull && m_currentItem->at( realFieldNumber ).isNull())) {
01022             kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): VALUE NOT CHANGED." << endl;
01023             removeEditor();
01024             if (m_acceptsRowEditAfterCellAccepting || m_internal_acceptsRowEditAfterCellAccepting)
01025                 acceptRowEdit();
01026             m_inside_acceptEditor = false;
01027             return true;
01028         }
01029         if (!setNull) {//get the new value 
01030 //          bool ok;
01031             newval = m_editor->value();
01033 /*
01034             if (!ok) {
01035                 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): INVALID VALUE - NOT CHANGED." << endl;
01036                 res = KexiValidator::Error;
01037 //js: TODO get detailed info on why m_editor->value() failed
01038                 msg = i18n("Entered value is invalid.")
01039                     + "\n\n" + KexiValidator::msgYouCanImproveData();
01040                 editCurrentCellAgain = true;
01041 //              removeEditor();
01042 //              return true;
01043             }*/
01044         }
01045 
01046         //Check other validation rules:
01047         //1. check using validator
01048 //      KexiValidator *validator = m_data->column(m_curCol)->validator();
01049         Validator *validator = currentTVColumn->validator();
01050         if (validator) {
01051 //          res = validator->check(m_data->column(m_curCol)->field()->captionOrName(), 
01052             res = validator->check(currentTVColumn->field()->captionOrName(), 
01053                 newval, msg, desc);
01054         }
01055     }
01056 
01057     //show the validation result if not OK:
01058     if (res == Validator::Error) {
01059         if (!msg.isEmpty()) {
01060             if (desc.isEmpty())
01061                 KMessageBox::sorry(dynamic_cast<QWidget*>(this), msg);
01062             else
01063                 KMessageBox::detailedSorry(dynamic_cast<QWidget*>(this), msg, desc);
01064         }
01065         editCurrentCellAgain = true;
01066 //      allow = false;
01067     }
01068     else if (res == Validator::Warning) {
01069         //js: todo: message!!!
01070         KMessageBox::messageBox(dynamic_cast<QWidget*>(this), KMessageBox::Sorry, msg + "\n" + desc);
01071         editCurrentCellAgain = true;
01072     }
01073 
01074     if (res == Validator::Ok) {
01075         //2. check using signal
01076         //bool allow = true;
01077 //      emit aboutToChangeCell(d->pCurrentItem, newval, allow);
01078 //      if (allow) {
01079         //send changes to the backend
01080         QVariant visibleValue;
01081         if (!newval.isNull()/* visible value should be null if value is null */ 
01082             && currentTVColumn->visibleLookupColumnInfo)
01083         {
01084             visibleValue = m_editor->visibleValue(); //visible value for lookup field 
01085         }
01086         //should be also added to the buffer
01087         if (m_data->updateRowEditBufferRef(m_currentItem, m_curCol, currentTVColumn, 
01088             newval, /*allowSignals*/true, currentTVColumn->visibleLookupColumnInfo ? &visibleValue : 0))
01089         {
01090             kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): ------ EDIT BUFFER CHANGED TO:" << endl;
01091             m_data->rowEditBuffer()->debug();
01092         } else {
01093             kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): ------ CHANGE FAILED in KexiDataAwareObjectInterface::updateRowEditBuffer()" << endl;
01094             res = Validator::Error;
01095 
01096             //now: there might be called cancelEditor() in updateRowEditBuffer() handler,
01097             //if this is true, d->pEditor is NULL.
01098 
01099             if (m_editor && m_data->result()->column>=0 && m_data->result()->column<columns()) {
01100                 //move to faulty column (if m_editor is not cleared)
01101                 setCursorPosition(m_curRow, m_data->result()->column);
01102             }
01103             if (!m_data->result()->msg.isEmpty()) {
01104                 const int button = showErrorMessageForResult( m_data->result() );
01105                 if (KMessageBox::No == button) {
01106                     //discard changes
01107                     cancelEditor();
01108                     if (m_acceptsRowEditAfterCellAccepting)
01109                         cancelRowEdit();
01110                     m_inside_acceptEditor = false;
01111                     return false;
01112                 }
01113             }
01114         }
01115     }
01116 
01117     if (res == Validator::Ok) {
01118         removeEditor();
01119         /*emit*/ itemChanged(m_currentItem, m_curRow, m_curCol, 
01120             m_currentItem->at( realFieldNumber ));
01121         /*emit*/ itemChanged(m_currentItem, m_curRow, m_curCol);
01122     }
01123     m_inside_acceptEditor = false;
01124     if (res == Validator::Ok) {
01125         if (m_acceptsRowEditAfterCellAccepting || m_internal_acceptsRowEditAfterCellAccepting)
01126             acceptRowEdit();
01127         return true;
01128     }
01129     if (m_editor) {
01130         //allow to edit the cell again, (if m_pEditor is not cleared)
01131 
01132         if (m_editor->hasFocusableWidget()) {
01133             m_editor->showWidget();
01134             m_editor->setFocus();
01135         }
01136 //      startEditCurrentCell(newval.type()==QVariant::String ? newval.toString() : QString::null);
01137 //      m_editor->setFocus();
01138     }
01139     return false;
01140 }
01141 
01142 void KexiDataAwareObjectInterface::startEditCurrentCell(const QString &setText)
01143 {
01144     kdDebug() << "** KexiDataAwareObjectInterface::startEditCurrentCell("<<setText<<")"<<endl;
01145 //  if (columnType(d->curCol) == KexiDB::Field::Boolean)
01146 //      return;
01147     if (isReadOnly() || !columnEditable(m_curCol))
01148         return;
01149     if (m_editor) {
01150         if (m_editor->hasFocusableWidget()) {
01151             m_editor->showWidget();
01152             m_editor->setFocus();
01153         }
01154     }
01155 //  ensureVisible(columnPos(m_curCol), rowPos(m_curRow)+rowHeight(), 
01156 //      columnWidth(m_curCol), rowHeight());
01157 //OK?   
01158     //ensureCellVisible(m_curRow+1, m_curCol);
01159     if (!m_editor)
01160         createEditor(m_curRow, m_curCol, setText, !setText.isEmpty());
01161 }
01162 
01163 void KexiDataAwareObjectInterface::deleteAndStartEditCurrentCell()
01164 {
01165     if (isReadOnly() || !columnEditable(m_curCol))
01166         return;
01167     if (m_editor) {//if we've editor - just clear it
01168         m_editor->clear();
01169         return;
01170     }
01171 //js    if (columnType(m_curCol) == KexiDB::Field::Boolean)
01172 //js        return;
01173 //  ensureVisible(columnPos(m_curCol), rowPos(m_curRow) + rowHeight(), 
01174 //      columnWidth(m_curCol), rowHeight());
01175 //OK?
01176     ensureCellVisible(m_curRow+1, m_curCol);
01177     createEditor(m_curRow, m_curCol, QString::null, false/*removeOld*/);
01178     if (!m_editor)
01179         return;
01180     m_editor->clear();
01181     if (m_editor->acceptEditorAfterDeleteContents())
01182         acceptEditor();
01183     if (!m_editor || !m_editor->hasFocusableWidget())
01184         updateCell(m_curRow, m_curCol);
01185 }
01186 
01187 void KexiDataAwareObjectInterface::deleteCurrentRow()
01188 {
01189     if (m_newRowEditing) {//we're editing fresh new row: just cancel this!
01190         cancelRowEdit();
01191         return;
01192     }
01193 
01194     if (!acceptRowEdit())
01195         return;
01196 
01197     if (!isDeleteEnabled() || !m_currentItem || m_currentItem == m_insertItem)
01198         return;
01199     switch (m_deletionPolicy) {
01200     case NoDelete:
01201         return;
01202     case ImmediateDelete:
01203         break;
01204     case AskDelete:
01205         if (KMessageBox::Cancel == KMessageBox::warningContinueCancel(dynamic_cast<QWidget*>(this), 
01206             i18n("Do you want to delete selected row?"), 0, 
01207             KGuiItem(i18n("&Delete Row"),"editdelete"),
01208             "dontAskBeforeDeleteRow"/*config entry*/,
01209             KMessageBox::Notify|KMessageBox::Dangerous))
01210             return;
01211         break;
01212     case SignalDelete:
01213         /*emit*/ itemDeleteRequest(m_currentItem, m_curRow, m_curCol);
01214         /*emit*/ currentItemDeleteRequest();
01215         return;
01216     default:
01217         return;
01218     }
01219 
01220     if (!deleteItem(m_currentItem)) {//nothing
01221     }
01222 }
01223 
01224 KexiTableItem *KexiDataAwareObjectInterface::insertEmptyRow(int row)
01225 {
01226     if ( !acceptRowEdit() || !isEmptyRowInsertingEnabled() 
01227         || (row!=-1 && row >= ((int)rows()+(isInsertingEnabled()?1:0) ) ) )
01228         return 0;
01229 
01230     KexiTableItem *newItem = m_data->createItem(); //new KexiTableItem(m_data->columns.count());
01231     insertItem(newItem, row);
01232     return newItem;
01233 }
01234 
01235 void KexiDataAwareObjectInterface::insertItem(KexiTableItem *newItem, int row)
01236 {
01237     const bool changeCurrentRow = row==-1 || row==m_curRow;
01238     if (changeCurrentRow) {
01239         //change current row
01240         row = (m_curRow >= 0 ? m_curRow : 0);
01241         m_currentItem = newItem;
01242         m_curRow = row;
01243     }
01244     else if (m_curRow >= row) {
01245         m_curRow++;
01246     }
01247 
01248     m_data->insertRow(*newItem, row, true /*repaint*/);
01249 
01250     if (changeCurrentRow) {
01251         //update iter...
01252         m_itemIterator->toFirst();
01253         (*m_itemIterator)+=m_curRow;
01254     }
01255 /*
01256     QSize s(tableSize());
01257     resizeContents(s.width(),s.height());
01258 
01259     //redraw only this row and below:
01260     int leftcol = d->pTopHeader->sectionAt( d->pTopHeader->offset() );
01261 //  updateContents( columnPos( leftcol ), rowPos(d->curRow), 
01262 //      clipper()->width(), clipper()->height() - (rowPos(d->curRow) - contentsY()) );
01263