kexi

kexidataawareobjectiface.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2005 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    Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl>
00010 
00011    This program is free software; you can redistribute it and/or
00012    modify it under the terms of the GNU Library General Public
00013    License as published by the Free Software Foundation; either
00014    version 2 of the License, or (at your option) any later version.
00015 
00016    This program is distributed in the hope that it will be useful,
00017    but WITHOUT ANY WARRANTY; without even the implied warranty of
00018    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019    Library General Public License for more details.
00020 
00021    You should have received a copy of the GNU Library General Public License
00022    along with this program; see the file COPYING.  If not, write to
00023    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00024  * Boston, MA 02110-1301, USA.
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; //don't know
00049     m_insertingEnabled = -1; //don't know
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     //we cannot delete m_data here... subclasses should do this
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/*don't destroy if it's the same*/) {
00099         kexidbg << "KexiDataAwareObjectInterface::setData(): destroying old data (owned)" << endl;
00100         delete m_itemIterator;
00101         delete m_data; //destroy old 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         //add columns
00112 //OK?
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;//default col width in pixels
00124 //js: TODO - add col width configuration and storage
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 //      connect(m_data, SIGNAL(refreshRequested()), this, SLOT(slotRefreshRequested()));
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))); //not db-aware
00153             QObject::connect(m_data, SIGNAL(rowRepaintRequested(KexiTableItem&)), 
00154                 dynamic_cast<QObject*>(this), SLOT(slotRowRepaintRequested(KexiTableItem&)));
00155         }
00156     }
00157 
00158     if (!m_data) {
00159 //      clearData();
00160         cancelRowEdit();
00161         //m_data->clearInternal();
00162         clearVariables();
00163     }
00164     else {
00165         if (!m_insertItem) {//first setData() call - add 'insert' item
00166             m_insertItem = m_data->createItem(); //new KexiTableItem(m_data->columns.count());
00167         }
00168         else {//just reinit
00169             m_insertItem->init(m_data->columns.count());
00170         }
00171     }
00172 
00173     //update gui mode
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         /*emit*/ dataSet( m_data );
00182 }
00183 
00184 void KexiDataAwareObjectInterface::initDataContents()
00185 {
00186     m_editor = 0;
00187 //  QSize s(tableSize());
00188 //  resizeContents(s.width(),s.height());
00189 
00190     m_navPanel->setRecordCount(rows());
00191 
00192     if (m_data && !m_cursorPositionSetExplicityBeforeShow) {
00193         //set current row:
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; //m_data->first();
00200                 curRow = 0;
00201                 curCol = 0;
00202             }
00203             else {//no data
00204                 if (isInsertingEnabled()) {
00205                     m_currentItem = m_insertItem;
00206                     curRow = 0;
00207                     curCol = 0;
00208                 }
00209             }
00210         }
00211         setCursorPosition(curRow, curCol);
00212     }
00213     ensureCellVisible(m_curRow, m_curCol);
00214 //  updateRowCountInfo();
00215 //  setNavRowCount(rows());
00216 
00217 //OK?
00218 // updateContents();
00219     updateWidgetContents();
00220 
00221     m_cursorPositionSetExplicityBeforeShow = false;
00222 
00223     /*emit*/ dataRefreshed();
00224 }
00225 
00226 void KexiDataAwareObjectInterface::setSortingEnabled(bool set)
00227 {
00228     if (m_isSortingEnabled && !set)
00229         setSorting(-1);
00230     m_isSortingEnabled = set;
00231     /*emit*/ reloadActions();
00232 }
00233 
00234 void KexiDataAwareObjectInterface::setSorting(int col, bool ascending)
00235 {
00236     if (!m_data || !m_isSortingEnabled)
00237         return;
00238 //  d->pTopHeader->setSortIndicator(col, ascending ? Ascending : Descending);
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     //locate current record
00270     if (!m_currentItem) {
00271         m_itemIterator->toFirst();
00272         m_currentItem = **m_itemIterator; //m_data->first();
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 //  d->pCurrentItem = m_data->at(d->curRow);
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     //-select sorting 
00306     bool asc;
00307     if (order == 0) {// invert
00308         if (col==dataSortedColumn() && dataSortingOrder()==1)
00309             asc = dataSortingOrder()==-1; //inverse sorting for this column -> descending order
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     //-perform sorting 
00321     if (!sort())
00322         setLocalSortingOrder(prevSortColumn, prevSortOrder); //this will also remove indicator
00323                                                              //if prevSortColumn==-1
00324 //      d->pTopHeader->setSortIndicator(prevSortColumn, 
00325 //          (prevSortOrder==1) ? Qt::Ascending : Qt::Descending); 
00326     
00327     if (col != prevSortColumn)
00328         /*emit*/ 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 //  updateContextMenu();
00356 }
00357 
00358 void KexiDataAwareObjectInterface::setReadOnly(bool set)
00359 {
00360     if (isReadOnly() == set || (m_data && m_data->isReadOnly() && !set))
00361         return; //not allowed!
00362     m_readOnly = (set ? 1 : 0);
00363     if (set)
00364         setInsertingEnabled(false);
00365     updateWidgetContents();
00366     /*emit*/ 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; //not allowed!
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 //  update();
00391     updateWidgetContents();
00392     /*emit*/ 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 //  selectRow(rows() - 1 + (isInsertingEnabled()?1:0));
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 //  selectRow( -1 );
00452     int oldRow = m_curRow;
00453 //  int oldCol = m_curCol;
00454     m_curRow = -1;
00455     m_curCol = -1;
00456     m_currentItem = 0;
00457     updateRow( oldRow );
00458     m_navPanel->setCurrentRecordNumber(0);
00459 //  setNavRowNumber(-1);
00460 }
00461 
00462 void KexiDataAwareObjectInterface::setCursorPosition(int row, int col/*=-1*/, 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; //no changes
00493         newcol = QMAX(0, newcol); //may not be < 0 !
00494     }
00495     newrow = QMAX(0, row);
00496     newrow = QMIN(rows() - 1 + (isInsertingEnabled()?1:0), newrow);
00497 
00498 //  d->pCurrentItem = itemAt(d->curRow);
00499 //  kdDebug(44021) << "setCursorPosition(): d->curRow=" << d->curRow << " oldRow=" << oldRow << " d->curCol=" << d->curCol << " oldCol=" << oldCol << endl;
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         // cursor moved: get rid of editor
00507         if (m_editor) {
00508             if (!m_contentsMousePressEvent_dblClick) {
00509                 if (!acceptEditor()) {
00510                     return;
00511                 }
00512                 //update row num. again
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) {//update current row info
00521             m_navPanel->setCurrentRecordNumber(newrow+1);
00522 //          setNavRowNumber(newrow);
00523 //          d->navBtnPrev->setEnabled(newrow>0);
00524 //          d->navBtnFirst->setEnabled(newrow>0);
00525 //          d->navBtnNext->setEnabled(newrow<(rows()-1+(isInsertingEnabled()?1:0)));
00526 //          d->navBtnLast->setEnabled(newrow!=(rows()-1));
00527         }
00528 
00529         // cursor moved to other row: end of row editing
00530         bool newRowInserted = false;
00531         if (m_rowEditing && m_curRow != newrow) {
00532             newRowInserted = m_newRowEditing;
00533             if (!acceptRowEdit()) {
00534                 //accepting failed: cancel setting the cursor
00535                 return;
00536             }
00537             //update row number, because number of rows changed
00538             newrow = QMIN( rows() - 1 + (isInsertingEnabled()?1:0), newrow);
00539 
00540             m_navPanel->setCurrentRecordNumber(newrow+1); //refresh
00541         }
00542 
00543         //change position
00544         int oldRow = m_curRow;
00545         int oldCol = m_curCol;
00546         m_curRow = newrow;
00547         m_curCol = newcol;
00548 
00549 //      int cw = columnWidth( d->curCol );
00550 //      int rh = rowHeight();
00551 //      ensureVisible( columnPos( d->curCol ) + cw / 2, rowPos( d->curRow ) + rh / 2, cw / 2, rh / 2 );
00552 //      center(columnPos(d->curCol) + cw / 2, rowPos(d->curRow) + rh / 2, cw / 2, rh / 2);
00553 //  kdDebug(44021) << " contentsY() = "<< contentsY() << endl;
00554 
00555 //js        if (oldRow > d->curRow)
00556 //js            ensureVisible(columnPos(d->curCol), rowPos(d->curRow) + rh, columnWidth(d->curCol), rh);
00557 //js        else// if (oldRow <= d->curRow)
00558 //js        ensureVisible(columnPos(d->curCol), rowPos(d->curRow), columnWidth(d->curCol), rh);
00559 
00560 
00561         //show editor-dependent focus, if we're changing the current column
00562         if (oldCol>=0 && oldCol<columns() && m_curCol!=oldCol) {
00563             //find the editor for this column
00564             KexiDataItemInterface *edit = editor( oldCol );
00565             if (edit) {
00566                 edit->hideFocus();
00567             }
00568         }
00569 
00570         //show editor-dependent focus, if needed
00571         editorShowFocus( m_curRow, m_curCol );
00572 
00573         if (m_updateEntireRowWhenMovingToOtherRow)
00574             updateRow( oldRow );
00575         else
00576             updateCell( oldRow, oldCol );
00577 
00578 //      //quite clever: ensure the cell is visible:
00579 //      ensureCellVisible(m_curRow, m_curCol);
00580 
00581 //      QPoint pcenter = QRect( columnPos(d->curCol), rowPos(d->curRow), columnWidth(d->curCol), rh).center();
00582 //      ensureVisible(pcenter.x(), pcenter.y(), columnWidth(d->curCol)/2, rh/2);
00583 
00584 //      ensureVisible(columnPos(d->curCol), rowPos(d->curRow) - contentsY(), columnWidth(d->curCol), rh);
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 ) {//ensure this is also refreshed
00594             if (!m_updateEntireRowWhenMovingToOtherRow) //only if entire row has not been updated
00595                 updateCell( oldRow, m_curCol );
00596         }
00597         //update row
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     //NOT EFFECTIVE!!!!!!!!!!!
00607                 //set item iterator
00608                 if (!newRowInserted && isInsertingEnabled() && m_currentItem == m_insertItem && m_curRow == (rows()-1)) {
00609                     //moving from 'insert item' to last item
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) //just move next
00615                     ++(*m_itemIterator);
00616                 else if (!newRowInserted && !forceSet && m_currentItem != m_insertItem && oldRow>=0 && (oldRow-1)==m_curRow) //just move back
00617                     --(*m_itemIterator);
00618                 else { //move at:
00619                     m_itemIterator->toFirst();
00620                     (*m_itemIterator)+=m_curRow;
00621                 }
00622                 m_currentItem = **m_itemIterator;
00623                     //itemAt(m_curRow);
00624             }
00625         }
00626 
00627         //quite clever: ensure the cell is visible:
00628         ensureCellVisible(m_curRow, m_curCol);
00629 
00630         /*emit*/ itemSelected(m_currentItem);
00631         /*emit*/ cellSelected(m_curCol, m_curRow);
00632         /* only needed for forms */
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)
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 //  bool allow = true;
00661 //  int faultyColumn = -1; // will be !=-1 if cursor has to be moved to that column
00662     const bool inserting = m_newRowEditing;
00663 //  QString msg, desc;
00664 //  bool inserting = d->pInsertItem && d->pInsertItem==d->pCurrentItem;
00665 
00666     if (m_data->rowEditBuffer()->isEmpty() && !m_newRowEditing) {
00667 /*      if (d->newRowEditing) {
00668             cancelRowEdit();
00669             kdDebug() << "-- NOTHING TO INSERT!!!" << endl;
00670             return true;
00671         }
00672         else {*/
00673             kdDebug() << "-- NOTHING TO ACCEPT!!!" << endl;
00674 //      }
00675     }
00676     else {//not empty edit buffer or new row to insert:
00677         if (m_newRowEditing) {
00678 //          emit aboutToInsertRow(d->pCurrentItem, m_data->rowEditBuffer(), success, &faultyColumn);
00679 //          if (success) {
00680             kdDebug() << "-- INSERTING: " << endl;
00681             m_data->rowEditBuffer()->debug();
00682             success = m_data->saveNewRow(*m_currentItem);
00683 //              if (!success) {
00684 //              }
00685 //          }
00686         }
00687         else {
00688 //          emit aboutToUpdateRow(d->pCurrentItem, m_data->rowEditBuffer(), success, &faultyColumn);
00689             if (success) {
00690                 //accept changes for this row:
00691                 kdDebug() << "-- UPDATING: " << endl;
00692                 m_data->rowEditBuffer()->debug();
00693                 success = m_data->saveRowChanges(*m_currentItem);//, &msg, &desc, &faultyColumn);
00694 //              if (!success) {
00695 //              }
00696             }
00697         }
00698     }
00699 
00700     if (success) {
00701         //editing is finished:
00702         m_rowEditing = false;
00703         m_newRowEditing = false;
00704         //indicate on the vheader that we are not editing
00705         if (m_verticalHeader)
00706             m_verticalHeader->setEditRow(-1);
00707 
00708         updateAfterAcceptRowEdit();
00709 
00710         kdDebug() << "EDIT ROW ACCEPTED:" << endl;
00711 //      /*debug*/itemAt(m_curRow);
00712 
00713         if (inserting) {
00714 //          emit rowInserted(d->pCurrentItem);
00715             //update navigator's data
00716             m_navPanel->setRecordCount(rows());
00717         }
00718         else {
00719 //          emit rowUpdated(d->pCurrentItem);
00720         }
00721 
00722         /*emit*/ rowEditTerminated(m_curRow);
00723     }
00724     else {
00725 //      if (!allow) {
00726 //          kdDebug() << "INSERT/EDIT ROW - DISALLOWED by signal!" << endl;
00727 //      }
00728 //      else {
00729 //          kdDebug() << "EDIT ROW - ERROR!" << endl;
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             //edit this cell
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     //indicate on the vheader that we are not editing
00762     if (m_verticalHeader)
00763         m_verticalHeader->setEditRow(-1);
00764     m_alsoUpdateNextRow = m_newRowEditing;
00765     if (m_newRowEditing) {
00766         m_newRowEditing = false;
00767         //remove current edited row (it is @ the end of list)
00768         m_data->removeLast();
00769         //current item is now empty, last row
00770         m_currentItem = m_insertItem;
00771         //update visibility
00772         if (m_verticalHeader)
00773             m_verticalHeader->removeLabel(false); //-1 label
00774 //      updateContents(columnPos(0), rowPos(rows()), 
00775 //          viewport()->width(), d->rowHeight*3 + (m_navPanel ? m_navPanel->height() : 0)*3 );
00776 //      updateContents(); //js: above didnt work well so we do that dirty
00777         updateWidgetContents();
00778 //TODO: still doesn't repaint properly!!
00779 //      QSize s(tableSize());
00780 //      resizeContents(s.width(), s.height());
00781         updateWidgetContentsSize();
00782 //      m_verticalHeader->update();
00783         //--no cancel action is needed for datasource, 
00784         //  because the row was not yet stored.
00785     }
00786 
00787     m_data->clearRowEditBuffer();
00788     updateAfterCancelRowEdit();
00789     
00791     kexidbg << "EDIT ROW CANCELLED." << endl;
00792 
00793     /*emit*/ 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;//avoid recursion
00849 
00850     QVariant newval;
00851     Validator::Result res = Validator::Ok;
00852     QString msg, desc;
00853     bool setNull = false;
00854 //  bool allow = true;
00855 //  static const QString msg_NOT_NULL = i18n("\"%1\" column requires a value to be entered.");
00856 
00857     //autoincremented field can be omitted (left as null or empty) if we're inserting a new row
00858     const bool autoIncColumnCanBeOmitted = m_newRowEditing && m_editor->field()->isAutoIncrement();
00859 //  const bool autoIncColumnCanBeOmitted = m_newRowEditing && m_editor->columnInfo()->field->isAutoIncrement();
00860 
00861     bool valueChanged = m_editor->valueChanged();
00862     bool editCurrentCellAgain = false;
00863 
00864     if (valueChanged) {
00865         if (!m_editor->valueIsValid()) {
00866             //used e.g. for date or time values - the value can be null but not necessary invalid
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 //                  m_errorMessagePopup->close();
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 QWhatsThis::display( m_editor->columnInfo()->field->typeName() + " ?", 
00906                     par->mapToGlobal(edit->pos()) 
00907                     + QPoint(
00908                         (m_verticalHeader ? m_verticalHeader->width() : 0) + 10,
00909                         edit->height() + 5),    par );
00910                         */
00911             }
00912         }
00913         else if (m_editor->valueIsNull()) {//null value entered
00914 //          if (m_editor->columnInfo()->field->isNotNull() && !autoIncColumnCanBeOmitted) {
00915             if (m_editor->field()->isNotNull() && !autoIncColumnCanBeOmitted) {
00916                 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NULL NOT ALLOWED!" << endl;
00917                 res = Validator::Error;
00918 //              msg = Validator::msgColumnNotEmpty().arg(m_editor->columnInfo()->field->captionOrName())
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     //          allow = false;
00924     //          removeEditor();
00925     //          return true;
00926             }
00927             else {
00928                 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NULL VALUE WILL BE SET" << endl;
00929                 //ok, just leave newval as NULL
00930                 setNull = true;
00931             }
00932         }
00933         else if (m_editor->valueIsEmpty()) {//empty value entered
00934 //          if (m_editor->columnInfo()->field->hasEmptyProperty()) {
00935             if (m_editor->field()->hasEmptyProperty()) {
00936 //              if (m_editor->columnInfo()->field->isNotEmpty() && !autoIncColumnCanBeOmitted) {
00937                 if (m_editor->field()->isNotEmpty() && !autoIncColumnCanBeOmitted) {
00938                     kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): EMPTY NOT ALLOWED!" << endl;
00939                     res = Validator::Error;
00940 //                  msg = Validator::msgColumnNotEmpty().arg(m_editor->columnInfo()->field->captionOrName())
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     //              allow = false;
00946     //              removeEditor();
00947     //              return true;
00948                 }
00949                 else {
00950                     kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): EMPTY VALUE WILL BE SET" << endl;
00951                 }
00952             }
00953             else {
00954 //              if (m_editor->columnInfo()->field->isNotNull() && !autoIncColumnCanBeOmitted) {
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 //                  msg = Validator::msgColumnNotEmpty().arg(m_editor->columnInfo()->field->captionOrName())
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 //              allow = false;
00964     //              removeEditor();
00965     //              return true;
00966                 }
00967                 else {
00968                     kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NULL VALUE WILL BE SET BECAUSE EMPTY IS NOT ALLOWED" << endl;
00969                     //ok, just leave newval as NULL
00970                     setNull = true;
00971                 }
00972             }
00973         }
00974     }//changed
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     //try to get the value entered:
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) {//get the new value 
00994 //          bool ok;
00995             newval = m_editor->value();
00997 /*
00998             if (!ok) {
00999                 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): INVALID VALUE - NOT CHANGED." << endl;
01000                 res = KexiValidator::Error;
01001 //js: TODO get detailed info on why m_editor->value() failed
01002                 msg = i18n("Entered value is invalid.")
01003                     + "\n\n" + KexiValidator::msgYouCanImproveData();
01004                 editCurrentCellAgain = true;
01005 //              removeEditor();
01006 //              return true;
01007             }*/
01008         }
01009 
01010         //Check other validation rules:
01011         //1. check using validator
01012 //      KexiValidator *validator = m_data->column(m_curCol)->validator();
01013         Validator *validator = column(m_curCol)->validator();
01014         if (validator) {
01015 //          res = validator->check(m_data->column(m_curCol)->field()->captionOrName(), 
01016             res = validator->check(column(m_curCol)->field()->captionOrName(), 
01017                 newval, msg, desc);
01018         }
01019     }
01020 
01021     //show the validation result if not OK:
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 //      allow = false;
01031     }
01032     else if (res == Validator::Warning) {
01033         //js: todo: message!!!
01034         KMessageBox::messageBox(dynamic_cast<QWidget*>(this), KMessageBox::Sorry, msg + "\n" + desc);
01035         editCurrentCellAgain = true;
01036     }
01037 
01038     if (res == Validator::Ok) {
01039         //2. check using signal
01040         //bool allow = true;
01041 //      emit aboutToChangeCell(d->pCurrentItem, newval, allow);
01042 //      if (allow) {
01043         //send changes to the backend
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             //now: there might be called cancelEditor() in updateRowEditBuffer() handler,
01052             //if this is true, d->pEditor is NULL.
01053 
01054             if (m_editor && m_data->result()->column>=0 && m_data->result()->column<columns()) {
01055                 //move to faulty column (if m_editor is not cleared)
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         /*emit*/ itemChanged(m_currentItem, m_curRow, m_curCol, 
01070             m_currentItem->at( realFieldNumber ));
01071         /*emit*/ 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         //allow to edit the cell again, (if m_pEditor is not cleared)
01081 
01082         if (m_editor->hasFocusableWidget()) {
01083             m_editor->showWidget();
01084             m_editor->setFocus();
01085         }
01086 //      startEditCurrentCell(newval.type()==QVariant::String ? newval.toString() : QString::null);
01087 //      m_editor->setFocus();
01088     }
01089     return false;
01090 }
01091 
01092 void KexiDataAwareObjectInterface::startEditCurrentCell(const QString &setText)
01093 {
01094     kdDebug() << "** KexiDataAwareObjectInterface::startEditCurrentCell("<<setText<<")"<<endl;
01095 //  if (columnType(d->curCol) == KexiDB::Field::Boolean)
01096 //      return;
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 //  ensureVisible(columnPos(m_curCol), rowPos(m_curRow)+rowHeight(), 
01106 //      columnWidth(m_curCol), rowHeight());
01107 //OK?
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) {//if we've editor - just clear it
01117         m_editor->clear();
01118         return;
01119     }
01120     if (columnType(m_curCol) == KexiDB::Field::Boolean)
01121         return;
01122 //  ensureVisible(columnPos(m_curCol), rowPos(m_curRow) + rowHeight(), 
01123 //      columnWidth(m_curCol), rowHeight());
01124 //OK?
01125     ensureCellVisible(m_curRow+1, m_curCol);
01126     createEditor(m_curRow, m_curCol, QString::null, false/*removeOld*/);
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) {//we're editing fresh new row: just cancel this!
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"/*config entry*/,
01156             KMessageBox::Notify|KMessageBox::Dangerous))
01157             return;
01158         break;
01159     case SignalDelete:
01160         /*emit*/ itemDeleteRequest(m_currentItem, m_curRow, m_curCol);
01161         /*emit*/ currentItemDeleteRequest();
01162         return;
01163     default:
01164         return;
01165     }
01166 
01167     if (!deleteItem(m_currentItem)) {//nothing
01168     }
01169 }
01170 
01171 KexiTableItem *KexiDataAwareObjectInterface::insertEmptyRow(int row)
01172 {
01173     if ( !acceptRowEdit() || !isEmptyRowInsertingEnabled() 
01174         || (row!=-1 && row >= (rows()+isInsertingEnabled()?1:0) ) )
01175         return 0;
01176 
01177     KexiTableItem *newItem = m_data->createItem(); //new KexiTableItem(m_data->columns.count());
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         //change current row
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 /*repaint*/);
01196 
01197     if (changeCurrentRow) {
01198         //update iter...
01199         m_itemIterator->toFirst();
01200         (*m_itemIterator)+=m_curRow;
01201     }
01202 /*
01203     QSize s(tableSize());
01204     resizeContents(s.width(),s.height());
01205 
01206     //redraw only this row and below:
01207     int leftcol = d->pTopHeader->sectionAt( d->pTopHeader->offset() );
01208 //  updateContents( columnPos( leftcol ), rowPos(d->curRow), 
01209 //      clipper()->width(), clipper()->height() - (rowPos(d->curRow) - contentsY()) );
01210     updateContents( columnPos( leftcol ), rowPos(row), 
01211         clipper()->width(), clipper()->height() - (rowPos(row) - contentsY()) );
01212 
01213     m_verticalHeader->addLabel();
01214 
01215     //update navigator's data
01216     setNavRowCount(rows());
01217 
01218     if (d->curRow >= row) {
01219         //update
01220         editorShowFocus( d->curRow, d->curCol );
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 * /*item*/, uint row, bool repaint)
01232 {
01233     if (repaint && (int)row<rows()) {
01234         updateWidgetContentsSize();
01235 
01236 /* updateAllVisibleRowsBelow() used instead
01237         //redraw only this row and below:
01238         int leftcol = d->pTopHeader->sectionAt( d->pTopHeader->offset() );
01239         updateContents( columnPos( leftcol ), rowPos(row), 
01240             clipper()->width(), clipper()->height() - (rowPos(row) - contentsY()) );
01241 */
01242         updateAllVisibleRowsBelow(row);
01243 
01244         if (!m_verticalHeaderAlreadyAdded) {
01245             if (m_verticalHeader)
01246                 m_verticalHeader->addLabel();
01247         }
01248         else //it was added because this inserting was interactive
01249             m_verticalHeaderAlreadyAdded = false;
01250 
01251         //update navigator's data
01252         m_navPanel->setRecordCount(rows());
01253 
01254         if (m_curRow >= (int)row) {
01255             //update
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 //  acceptRowEdit();
01282 //  m_verticalHeader->clear();
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 //          const uint columns = m_data->columns.count();
01291             for (int i=0; i<oldRows; i++) {
01292                 m_data->append(m_data->createItem());//new KexiTableItem(columns));
01293             }
01294         }
01295     }
01296     if (repaintLater)
01297         m_data->reload();
01298 
01299 //  d->clearVariables();
01300 //  m_verticalHeader->setCurrentRow(-1);
01301 
01302 //  d->pUpdateTimer->start(1,true);
01303 //  if (repaint)
01304 //      viewport()->repaint();
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 //      viewport()->repaint();
01317 //OK?
01318         updateWidgetContents();
01319 
01320 /*  for(int i=0; i < rows(); i++)
01321     {
01322         m_verticalHeader->removeLabel();
01323     }
01324 
01325     editorCancel();
01326     m_contents->clear();
01327 
01328     d->clearVariables();
01329     d->numCols = 0;
01330 
01331     while(d->pTopHeader->count()>0)
01332         d->pTopHeader->removeLabel(0);
01333 
01334     m_verticalHeader->setCurrentRow(-1);
01335 
01336     viewport()->repaint();
01337 
01338 //  d->pColumnTypes.resize(0);
01339 //  d->pColumnModes.resize(0);
01340 //  d->pColumnDefaults.clear();*/
01341 }
01342 
01343 void KexiDataAwareObjectInterface::reloadData()
01344 {
01345 //  cancelRowEdit();
01346     acceptRowEdit();
01347     if (m_verticalHeader)
01348         m_verticalHeader->clear();
01349 
01350     if (m_curCol>=0 && m_curCol<columns()) {
01351         //find the editor for this column
01352         KexiDataItemInterface *edit = editor( m_curCol );
01353         if (edit) {
01354             edit->hideFocus();
01355         }
01356     }
01357 //  setCursorPosition(-1, -1, true);
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 /*col*/) const
01400 {
01401     return QVariant(0);
01402 //TODO(js)  
01403 //  return m_data->columns[col].defaultValue;
01404 }
01405 
01406 void KexiDataAwareObjectInterface::setAcceptsRowEditAfterCellAccepting(bool set)
01407 {
01408     m_acceptsRowEditAfterCellAccepting = set;
01409 }
01410 
01411 void KexiDataAwareObjectInterface::setDropsAtRowEnabled(bool set)
01412 {
01413 //  const bool old = d->dropsAtRowEnabled;
01414     if (!set)
01415         m_dragIndicatorLine = -1;
01416     if (m_dropsAtRowEnabled && !set) {
01417         m_dropsAtRowEnabled = false;
01418 //      update();
01419         updateWidgetContents();
01420     }
01421     else {
01422         m_dropsAtRowEnabled = set;
01423     }
01424 }
01425 
01426 void KexiDataAwareObjectInterface::setEmptyRowInsertingEnabled(bool set)
01427 {
01428     m_emptyRowInsertingEnabled = set;
01429     /*emit*/ reloadActions();
01430 }
01431 
01432 void KexiDataAwareObjectInterface::slotAboutToDeleteRow(KexiTableItem& item, 
01433     KexiDB::ResultInfo* /*result*/, 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())
01444             m_rowWillBeDeleted--; //move up
01445         updateWidgetContentsSize();
01446 
01447         setCursorPosition(m_rowWillBeDeleted, m_curCol, true/*forceSet*/);
01448         if (m_verticalHeader)
01449             m_verticalHeader->removeLabel();
01450 
01451         updateAllVisibleRowsBelow(m_curRow); //needed for KexiTableView
01452 
01453         //update navigator's data
01454         m_navPanel->setRecordCount(rows());
01455 
01456         m_rowWillBeDeleted = -1;
01457     }
01458 }
01459 
01460 bool KexiDataAwareObjectInterface::beforeDeleteItem(KexiTableItem *)
01461 {
01462     //always return
01463     return true;
01464 }
01465 
01466 bool KexiDataAwareObjectInterface::deleteItem(KexiTableItem *item)/*, bool moveCursor)*/
01467 {
01468     if (!item || !beforeDeleteItem(item))
01469         return false;
01470 
01471     QString msg, desc;
01472 //  bool current = (item == d->pCurrentItem);
01473     if (!m_data->deleteRow(*item, true /*repaint*/)) {
01474         //error
01475         if (m_data->result()->desc.isEmpty())
01476             KMessageBox::sorry(dynamic_cast<QWidget*>(this), m_data->result()->msg);
01477         else
01478             KMessageBox::detailedSorry(dynamic_cast<QWidget*>(this), m_data->result()->msg, m_data->result()->desc);
01479         return false;
01480     }
01481     else {
01482 //setCursorPosition() wil lset this!        if (current)
01483             //d->pCurrentItem = m_data->current();
01484     }
01485 
01486 //  repaintAfterDelete();
01487     if (m_spreadSheetMode) { //append empty row for spreadsheet mode
01488             m_data->append(m_data->createItem());//new KexiTableItem(m_data->columns.count()));
01489             if (m_verticalHeader)
01490                 m_verticalHeader->addLabels(1);
01491     }
01492     return true;
01493 }
01494 
01495 KexiTableViewColumn* KexiDataAwareObjectInterface::column(int col)
01496 {
01497     return m_data->column(col);
01498 }
01499 
01500 const QVariant* KexiDataAwareObjectInterface::bufferedValueAt(int col)
01501 {
01502     if (m_rowEditing && m_data->rowEditBuffer())
01503     {
01504 //      KexiTableViewColumn* tvcol = m_data->column(col);
01505         KexiTableViewColumn* tvcol = column(col);
01506         if (tvcol->isDBAware) {
01507 //          QVariant *cv = m_data->rowEditBuffer()->at( *static_cast<KexiDBTableViewColumn*>(tvcol)->field );
01508             const QVariant *cv = m_data->rowEditBuffer()->at( *tvcol->fieldinfo );
01509             if (cv)
01510                 return cv;
01511 
01512             const int realFieldNumber = fieldNumberForColumn(col);
01513             if (realFieldNumber < 0) {
01514                 kdWarning() << "KexiDataAwareObjectInterface::bufferedValueAt(): fieldNumberForColumn(m_curCol) < 0" << endl;
01515                 return 0;
01516             }
01517             return &m_currentItem->at( realFieldNumber );
01518         }
01519         const QVariant *cv = m_data->rowEditBuffer()->at( tvcol->field()->name() );
01520         if (cv)
01521             return cv;
01522     }
01523     const int realFieldNumber = fieldNumberForColumn(col);
01524     if (realFieldNumber < 0) {
01525         kdWarning() << "KexiDataAwareObjectInterface::bufferedValueAt(): fieldNumberForColumn(m_curCol) < 0" << endl;
01526         return 0;
01527     }
01528     return &m_currentItem->at( realFieldNumber );
01529 }
01530 
01531 void KexiDataAwareObjectInterface::startEditOrToggleValue()
01532 {
01533     if ( !isReadOnly() && columnEditable(m_curCol) ) {
01534         if (columnType(m_curCol) == KexiDB::Field::Boolean) {
01535             boolToggled();
01536         }
01537         else {
01538             startEditCurrentCell();
01539             return;
01540         }
01541     }
01542 }
01543 
01544 void KexiDataAwareObjectInterface::boolToggled()
01545 {
01546     startEditCurrentCell();
01547     if (m_editor) {
01548         m_editor->clickedOnContents();
01549     }
01550     acceptEditor();
01551     updateCell(m_curRow, m_curCol);
01552 
01553 /*  int s = m_currentItem->at(m_curCol).toInt();
01554     QVariant oldValue=m_currentItem->at(m_curCol);
01555     (*m_currentItem)[m_curCol] = QVariant(s ? 0 : 1);
01556     updateCell(m_curRow, m_curCol);
01557 //  emit itemChanged(m_currentItem, m_curRow, m_curCol, oldValue);
01558 //  emit itemChanged(m_currentItem, m_curRow, m_curCol);*/
01559 }
01560 
01561 void KexiDataAwareObjectInterface::slotDataDestroying()
01562 {
01563     m_data = 0;
01564     m_itemIterator = 0;
01565 }
01566 
01567 void KexiDataAwareObjectInterface::addNewRecordRequested()
01568 {
01569     if (!isInsertingEnabled())
01570         return;
01571     if (m_rowEditing) {
01572         if (!acceptRowEdit())
01573             return;
01574     }
01575 //  setFocus();
01576     selectRow(rows());
01577     startEditCurrentCell();
01578     if (m_editor)
01579         m_editor->setFocus();
01580 }
01581 
KDE Home | KDE Accessibility Home | Description of Access Keys