00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #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;
00050 m_insertingEnabled = -1;
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
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 m_recentSearchDirection = KexiSearchAndReplaceViewInterface::Options::DefaultSearchDirection;
00080
00081
00082 m_scrollBarTip = new QLabel("",0, "vScrollBarToolTip",
00083 Qt::WStyle_Customize |Qt::WStyle_NoBorder|Qt::WX11BypassWM|Qt::WStyle_StaysOnTop|Qt::WStyle_Tool);
00084 m_scrollBarTip->setPalette(QToolTip::palette());
00085 m_scrollBarTip->setMargin(2);
00086 m_scrollBarTip->setIndent(0);
00087 m_scrollBarTip->setAlignment(Qt::AlignCenter);
00088 m_scrollBarTip->setFrameStyle( QFrame::Plain | QFrame::Box );
00089 m_scrollBarTip->setLineWidth(1);
00090
00091 clearVariables();
00092 }
00093
00094 KexiDataAwareObjectInterface::~KexiDataAwareObjectInterface()
00095 {
00096 delete m_insertItem;
00097
00098 delete m_itemIterator;
00099 delete m_scrollBarTip;
00100
00101 }
00102
00103 void KexiDataAwareObjectInterface::clearVariables()
00104 {
00105 m_editor = 0;
00106
00107 m_rowEditing = false;
00108 m_newRowEditing = false;
00109 m_curRow = -1;
00110 m_curCol = -1;
00111 m_currentItem = 0;
00112 }
00113
00114 void KexiDataAwareObjectInterface::setData( KexiTableViewData *data, bool owner )
00115 {
00116 const bool theSameData = m_data && m_data==data;
00117 if (m_owner && m_data && m_data!=data) {
00118 kexidbg << "KexiDataAwareObjectInterface::setData(): destroying old data (owned)" << endl;
00119 delete m_itemIterator;
00120 delete m_data;
00121 m_data = 0;
00122 m_itemIterator = 0;
00123 }
00124 m_owner = owner;
00125 m_data = data;
00126 if (m_data)
00127 m_itemIterator = m_data->createIterator();
00128
00129 kdDebug(44021) << "KexiDataAwareObjectInterface::setData(): using shared data" << endl;
00130
00131
00132 clearColumnsInternal(false);
00133 if (m_data) {
00134 int i = 0;
00135 for (KexiTableViewColumn::ListIterator it(m_data->columns);
00136 it.current(); ++it, i++)
00137 {
00138 KexiDB::Field *f = it.current()->field();
00139 if (it.current()->visible()) {
00140 int wid = f->width();
00141 if (wid==0)
00142 wid=KEXI_DEFAULT_DATA_COLUMN_WIDTH;
00144 addHeaderColumn(it.current()->isHeaderTextVisible()
00145 ? it.current()->captionAliasOrName() : QString::null,
00146 f->description(), it.current()->icon(), wid);
00147 }
00148 }
00149 }
00150 if (m_verticalHeader) {
00151 m_verticalHeader->clear();
00152 if (m_data)
00153 m_verticalHeader->addLabels(m_data->count());
00154 }
00155 if (m_data && m_data->count()==0)
00156 m_navPanel->setCurrentRecordNumber(0+1);
00157
00158 if (m_data && !theSameData) {
00160 setSorting(-1);
00161
00162 connectToReloadDataSlot(m_data, SIGNAL(reloadRequested()));
00163 QObject* thisObject = dynamic_cast<QObject*>(this);
00164 if (thisObject) {
00165 QObject::connect(m_data, SIGNAL(destroying()), thisObject, SLOT(slotDataDestroying()));
00166 QObject::connect(m_data, SIGNAL(rowsDeleted( const QValueList<int> & )),
00167 thisObject, SLOT(slotRowsDeleted( const QValueList<int> & )));
00168 QObject::connect(m_data, SIGNAL(aboutToDeleteRow(KexiTableItem&,KexiDB::ResultInfo*,bool)),
00169 thisObject, SLOT(slotAboutToDeleteRow(KexiTableItem&,KexiDB::ResultInfo*,bool)));
00170 QObject::connect(m_data, SIGNAL(rowDeleted()), thisObject, SLOT(slotRowDeleted()));
00171 QObject::connect(m_data, SIGNAL(rowInserted(KexiTableItem*,bool)),
00172 thisObject, SLOT(slotRowInserted(KexiTableItem*,bool)));
00173 QObject::connect(m_data, SIGNAL(rowInserted(KexiTableItem*,uint,bool)),
00174 thisObject, SLOT(slotRowInserted(KexiTableItem*,uint,bool)));
00175 QObject::connect(m_data, SIGNAL(rowRepaintRequested(KexiTableItem&)),
00176 thisObject, SLOT(slotRowRepaintRequested(KexiTableItem&)));
00177
00178 QObject::connect(verticalScrollBar(),SIGNAL(sliderReleased()),
00179 thisObject,SLOT(vScrollBarSliderReleased()));
00180 QObject::connect(verticalScrollBar(),SIGNAL(valueChanged(int)),
00181 thisObject,SLOT(vScrollBarValueChanged(int)));
00182 QObject::connect(&m_scrollBarTipTimer,SIGNAL(timeout()),
00183 thisObject,SLOT(scrollBarTipTimeout()));
00184 }
00185 }
00186
00187 if (!m_data) {
00188
00189 cancelRowEdit();
00190
00191 clearVariables();
00192 }
00193 else {
00194 if (!m_insertItem) {
00195 m_insertItem = m_data->createItem();
00196 }
00197 else {
00198 m_insertItem->init(m_data->columns.count());
00199 }
00200 }
00201
00202
00203 m_navPanel->setInsertingEnabled(m_data && isInsertingEnabled());
00204 if (m_verticalHeader)
00205 m_verticalHeader->showInsertRow(m_data && isInsertingEnabled());
00206
00207 initDataContents();
00208 updateIndicesForVisibleValues();
00209
00210 if (m_data)
00211 dataSet( m_data );
00212 }
00213
00214 void KexiDataAwareObjectInterface::initDataContents()
00215 {
00216 m_editor = 0;
00217
00218
00219
00220 m_navPanel->setRecordCount(rows());
00221
00222 if (m_data && !m_cursorPositionSetExplicityBeforeShow) {
00223
00224 m_currentItem = 0;
00225 int curRow = -1, curCol = -1;
00226 if (m_data->columnsCount()>0) {
00227 if (rows()>0) {
00228 m_itemIterator->toFirst();
00229 m_currentItem = **m_itemIterator;
00230 curRow = 0;
00231 curCol = 0;
00232 }
00233 else {
00234 if (isInsertingEnabled()) {
00235 m_currentItem = m_insertItem;
00236 curRow = 0;
00237 curCol = 0;
00238 }
00239 }
00240 }
00241 setCursorPosition(curRow, curCol, true);
00242 }
00243 ensureCellVisible(m_curRow, m_curCol);
00244
00245
00246
00247
00248
00249 updateWidgetContents();
00250
00251 m_cursorPositionSetExplicityBeforeShow = false;
00252
00253 dataRefreshed();
00254 }
00255
00256 void KexiDataAwareObjectInterface::setSortingEnabled(bool set)
00257 {
00258 if (m_isSortingEnabled && !set)
00259 setSorting(-1);
00260 m_isSortingEnabled = set;
00261 reloadActions();
00262 }
00263
00264 void KexiDataAwareObjectInterface::setSorting(int col, bool ascending)
00265 {
00266 if (!m_data || !m_isSortingEnabled)
00267 return;
00268
00269 setLocalSortingOrder(col, ascending ? 1 : -1);
00270 m_data->setSorting(col, ascending);
00271 }
00272
00273 int KexiDataAwareObjectInterface::dataSortedColumn() const
00274 {
00275 if (m_data && m_isSortingEnabled)
00276 return m_data->sortedColumn();
00277 return -1;
00278 }
00279
00280 int KexiDataAwareObjectInterface::dataSortingOrder() const
00281 {
00282 return m_data ? m_data->sortingOrder() : 0;
00283 }
00284
00285 bool KexiDataAwareObjectInterface::sort()
00286 {
00287 if (!m_data || !m_isSortingEnabled)
00288 return false;
00289
00290 if (rows() < 2)
00291 return true;
00292
00293 if (!acceptRowEdit())
00294 return false;
00295
00296 const int oldRow = m_curRow;
00297 if (m_data->sortedColumn()!=-1)
00298 m_data->sort();
00299
00300
00301 if (!m_currentItem) {
00302 m_itemIterator->toFirst();
00303 m_currentItem = **m_itemIterator;
00304 m_curRow = 0;
00305 if (!m_currentItem)
00306 return true;
00307 }
00308 if (m_currentItem != m_insertItem) {
00309 m_curRow = m_data->findRef(m_currentItem);
00310 int jump = m_curRow - oldRow;
00311 if (jump<0)
00312 (*m_itemIterator) -= -jump;
00313 else
00314 (*m_itemIterator) += jump;
00315 }
00316
00317 updateGUIAfterSorting();
00318 editorShowFocus( m_curRow, m_curCol );
00319 if (m_verticalHeader)
00320 m_verticalHeader->setCurrentRow(m_curRow);
00321 if (m_horizontalHeader)
00322 m_horizontalHeader->setSelectedSection(m_curCol);
00323 if (m_navPanel)
00324 m_navPanel->setCurrentRecordNumber(m_curRow+1);
00325 return true;
00326 }
00327
00328 void KexiDataAwareObjectInterface::sortAscending()
00329 {
00330 if (currentColumn()<0)
00331 return;
00332 sortColumnInternal( currentColumn(), 1 );
00333 }
00334
00335 void KexiDataAwareObjectInterface::sortDescending()
00336 {
00337 if (currentColumn()<0)
00338 return;
00339 sortColumnInternal( currentColumn(), -1 );
00340 }
00341
00342 void KexiDataAwareObjectInterface::sortColumnInternal(int col, int order)
00343 {
00344
00345 bool asc;
00346 if (order == 0) {
00347 if (col==dataSortedColumn() && dataSortingOrder()==1)
00348 asc = dataSortingOrder()==-1;
00349 else
00350 asc = true;
00351 }
00352 else
00353 asc = (order==1);
00354
00355 int prevSortOrder = currentLocalSortingOrder();
00356 const int prevSortColumn = currentLocalSortingOrder();
00357 setSorting( col, asc );
00358
00359 if (!sort())
00360 setLocalSortingOrder(prevSortColumn, prevSortOrder);
00361
00362 if (col != prevSortColumn)
00363 sortedColumnChanged(col);
00364 }
00365
00366 bool KexiDataAwareObjectInterface::isInsertingEnabled() const
00367 {
00368 if (isReadOnly())
00369 return false;
00370 if (m_insertingEnabled == 1 || m_insertingEnabled == 0)
00371 return (bool)m_insertingEnabled;
00372 if (!hasData())
00373 return true;
00374 return m_data->isInsertingEnabled();
00375 }
00376
00377 void KexiDataAwareObjectInterface::setFilteringEnabled(bool set)
00378 {
00379 m_isFilteringEnabled = set;
00380 }
00381
00382 bool KexiDataAwareObjectInterface::isDeleteEnabled() const
00383 {
00384 return (m_deletionPolicy != NoDelete) && !isReadOnly();
00385 }
00386
00387 void KexiDataAwareObjectInterface::setDeletionPolicy(DeletionPolicy policy)
00388 {
00389 m_deletionPolicy = policy;
00390
00391 }
00392
00393 void KexiDataAwareObjectInterface::setReadOnly(bool set)
00394 {
00395 if (isReadOnly() == set || (m_data && m_data->isReadOnly() && !set))
00396 return;
00397 m_readOnly = (set ? 1 : 0);
00398 if (set)
00399 setInsertingEnabled(false);
00400 updateWidgetContents();
00401 reloadActions();
00402 }
00403
00404 bool KexiDataAwareObjectInterface::isReadOnly() const
00405 {
00406 if (!hasData())
00407 return true;
00408 if (m_readOnly == 1 || m_readOnly == 0)
00409 return (bool)m_readOnly;
00410 if (!hasData())
00411 return true;
00412 return m_data->isReadOnly();
00413 }
00414
00415 void KexiDataAwareObjectInterface::setInsertingEnabled(bool set)
00416 {
00417 if (isInsertingEnabled() == set || (m_data && !m_data->isInsertingEnabled() && set))
00418 return;
00419 m_insertingEnabled = (set ? 1 : 0);
00420 m_navPanel->setInsertingEnabled(set);
00421 if (m_verticalHeader)
00422 m_verticalHeader->showInsertRow(set);
00423 if (set)
00424 setReadOnly(false);
00425
00426 updateWidgetContents();
00427 reloadActions();
00428 }
00429
00430 void KexiDataAwareObjectInterface::setSpreadSheetMode()
00431 {
00432 m_spreadSheetMode = true;
00433 setSortingEnabled( false );
00434 setInsertingEnabled( false );
00435 setAcceptsRowEditAfterCellAccepting( true );
00436 setFilteringEnabled( false );
00437 setEmptyRowInsertingEnabled( true );
00438 m_navPanelEnabled = false;
00439 }
00440
00441 void KexiDataAwareObjectInterface::selectNextRow()
00442 {
00443 selectRow( QMIN( rows() - 1 +(isInsertingEnabled()?1:0), m_curRow + 1 ) );
00444 }
00445
00446 void KexiDataAwareObjectInterface::selectPrevPage()
00447 {
00448 selectRow(
00449 QMAX( 0, m_curRow - rowsPerPage() )
00450 );
00451 }
00452
00453 void KexiDataAwareObjectInterface::selectNextPage()
00454 {
00455 selectRow(
00456 QMIN(
00457 rows() - 1 + (isInsertingEnabled()?1:0),
00458 m_curRow + rowsPerPage()
00459 )
00460 );
00461 }
00462
00463 void KexiDataAwareObjectInterface::selectFirstRow()
00464 {
00465 selectRow(0);
00466 }
00467
00468 void KexiDataAwareObjectInterface::selectLastRow()
00469 {
00470
00471 selectRow(rows() - 1);
00472 }
00473
00474 void KexiDataAwareObjectInterface::selectRow(int row)
00475 {
00476 m_vScrollBarValueChanged_enabled = false;
00477 setCursorPosition(row, -1);
00478 m_vScrollBarValueChanged_enabled = true;
00479 }
00480
00481 void KexiDataAwareObjectInterface::selectPrevRow()
00482 {
00483 selectRow( QMAX( 0, m_curRow - 1 ) );
00484 }
00485
00486 void KexiDataAwareObjectInterface::clearSelection()
00487 {
00488
00489 int oldRow = m_curRow;
00490
00491 m_curRow = -1;
00492 m_curCol = -1;
00493 m_currentItem = 0;
00494 updateRow( oldRow );
00495 m_navPanel->setCurrentRecordNumber(0);
00496
00497 }
00498
00499 void KexiDataAwareObjectInterface::setCursorPosition(int row, int col, bool forceSet)
00500 {
00501 int newrow = row;
00502 int newcol = col;
00503
00504 if(rows() <= 0) {
00505 if (m_verticalHeader)
00506 m_verticalHeader->setCurrentRow(-1);
00507 if (m_horizontalHeader)
00508 m_horizontalHeader->setSelectedSection(-1);
00509 if (isInsertingEnabled()) {
00510 m_currentItem=m_insertItem;
00511 newrow=0;
00512 if (col>=0)
00513 newcol=col;
00514 else
00515 newcol=0;
00516 }
00517 else {
00518 m_currentItem=0;
00519 m_curRow=-1;
00520 m_curCol=-1;
00521 return;
00522 }
00523 }
00524
00525 if(col>=0)
00526 {
00527 newcol = QMAX(0, col);
00528 newcol = QMIN(columns() - 1, newcol);
00529 }
00530 else {
00531 newcol = m_curCol;
00532 newcol = QMAX(0, newcol);
00533 }
00534 newrow = QMAX(0, row);
00535 newrow = QMIN(rows() - 1 + (isInsertingEnabled()?1:0), newrow);
00536
00537
00538
00539
00540 if ( forceSet || m_curRow != newrow || m_curCol != newcol )
00541 {
00542 kexidbg << "setCursorPosition(): " <<QString("old:%1,%2 new:%3,%4").arg(m_curCol)
00543 .arg(m_curRow).arg(newcol).arg(newrow) << endl;
00544
00545
00546 if (m_editor) {
00547 if (!m_contentsMousePressEvent_dblClick) {
00548 if (!acceptEditor()) {
00549 return;
00550 }
00551
00552 newrow = QMIN( rows() - 1 + (isInsertingEnabled()?1:0), newrow);
00553 }
00554 }
00555 if (m_errorMessagePopup) {
00556 m_errorMessagePopup->close();
00557 }
00558
00559 if (m_curRow != newrow || forceSet) {
00560 m_navPanel->setCurrentRecordNumber(newrow+1);
00561
00562
00563
00564
00565
00566 }
00567
00568
00569 bool newRowInserted = false;
00570 if (m_rowEditing && m_curRow != newrow) {
00571 newRowInserted = m_newRowEditing;
00572 if (!acceptRowEdit()) {
00573
00574 return;
00575 }
00576
00577 newrow = QMIN( rows() - 1 + (isInsertingEnabled()?1:0), newrow);
00578
00579 m_navPanel->setCurrentRecordNumber(newrow+1);
00580 }
00581
00582
00583 int oldRow = m_curRow;
00584 int oldCol = m_curCol;
00585 m_curRow = newrow;
00586 m_curCol = newcol;
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601 if (oldCol>=0 && oldCol<columns() && m_curCol!=oldCol) {
00602
00603 KexiDataItemInterface *edit = editor( oldCol );
00604 if (edit) {
00605 edit->hideFocus();
00606 }
00607 }
00608
00609
00610
00611 m_positionOfRecentlyFoundValue.exists = false;
00612
00613
00614 editorShowFocus( m_curRow, m_curCol );
00615
00616 if (m_updateEntireRowWhenMovingToOtherRow)
00617 updateRow( oldRow );
00618 else
00619 updateCell( oldRow, oldCol );
00620
00621
00622
00623
00624
00625
00626
00627
00628 if (m_verticalHeader && (oldRow != m_curRow || forceSet))
00629 m_verticalHeader->setCurrentRow(m_curRow);
00630
00631 if (m_updateEntireRowWhenMovingToOtherRow)
00632 updateRow( m_curRow );
00633 else
00634 updateCell( m_curRow, m_curCol );
00635
00636 if (m_curCol != oldCol || m_curRow != oldRow || forceSet) {
00637 if (!m_updateEntireRowWhenMovingToOtherRow)
00638 updateCell( oldRow, m_curCol );
00639 }
00640
00641 if (forceSet || m_curRow != oldRow) {
00642 if (isInsertingEnabled() && m_curRow == rows()) {
00643 kdDebug(44021) << "NOW insert item is current" << endl;
00644 m_currentItem = m_insertItem;
00645 }
00646 else {
00647 kdDebug(44021) << QString("NOW item at %1 (%2) is current")
00648 .arg(m_curRow).arg((ulong)itemAt(m_curRow)) << endl;
00649
00650
00651 if (!newRowInserted && isInsertingEnabled() && m_currentItem == m_insertItem && m_curRow == (rows()-1)) {
00652
00653 m_itemIterator->toLast();
00654 }
00655 else if (!newRowInserted && !forceSet && m_currentItem != m_insertItem && 0==m_curRow)
00656 m_itemIterator->toFirst();
00657 else if (!newRowInserted && !forceSet && m_currentItem != m_insertItem && oldRow>=0 && (oldRow+1)==m_curRow)
00658 ++(*m_itemIterator);
00659 else if (!newRowInserted && !forceSet && m_currentItem != m_insertItem && oldRow>=0 && (oldRow-1)==m_curRow)
00660 --(*m_itemIterator);
00661 else {
00662 m_itemIterator->toFirst();
00663 (*m_itemIterator)+=m_curRow;
00664 }
00665 if (!**m_itemIterator) {
00666 m_itemIterator->toFirst();
00667 (*m_itemIterator)+=m_curRow;
00668 }
00669 m_currentItem = **m_itemIterator;
00670
00671 }
00672 }
00673
00674
00675 ensureCellVisible(m_curRow, m_curCol);
00676
00677 if (m_horizontalHeader && (oldCol != m_curCol || forceSet))
00678 m_horizontalHeader->setSelectedSection(m_curCol);
00679
00680 itemSelected(m_currentItem);
00681 cellSelected(m_curCol, m_curRow);
00682
00683 selectCellInternal();
00684 }
00685 else {
00686 kexidbg << "setCursorPosition(): NO CHANGE" << endl;
00687 }
00688
00689 if(m_initDataContentsOnShow) {
00690 m_cursorPositionSetExplicityBeforeShow = true;
00691 }
00692 }
00693
00694 bool KexiDataAwareObjectInterface::acceptRowEdit()
00695 {
00696 if (!m_rowEditing || !m_data->rowEditBuffer())
00697 return true;
00698 if (m_inside_acceptEditor) {
00699 m_internal_acceptsRowEditAfterCellAccepting = true;
00700 return true;
00701 }
00702 m_internal_acceptsRowEditAfterCellAccepting = false;
00703
00704 const int columnEditedBeforeAccepting = m_editor ? currentColumn() : -1;
00705 if (!acceptEditor())
00706 return false;
00707 kdDebug() << "EDIT ROW ACCEPTING..." << endl;
00708
00709 bool success = true;
00710
00711
00712 const bool inserting = m_newRowEditing;
00713
00714
00715
00716 if (m_data->rowEditBuffer()->isEmpty() && !m_newRowEditing) {
00717
00718
00719
00720
00721
00722
00723 kdDebug() << "-- NOTHING TO ACCEPT!!!" << endl;
00724
00725 }
00726 else {
00727 if (m_newRowEditing) {
00728
00729
00730 kdDebug() << "-- INSERTING: " << endl;
00731 m_data->rowEditBuffer()->debug();
00732 success = m_data->saveNewRow(*m_currentItem);
00733
00734
00735
00736 }
00737 else {
00738
00739 if (success) {
00740
00741 kdDebug() << "-- UPDATING: " << endl;
00742 m_data->rowEditBuffer()->debug();
00743 kdDebug() << "-- BEFORE: " << endl;
00744 m_currentItem->debug();
00745 success = m_data->saveRowChanges(*m_currentItem);
00746 kdDebug() << "-- AFTER: " << endl;
00747 m_currentItem->debug();
00748
00749
00750
00751 }
00752 }
00753 }
00754
00755 if (success) {
00756
00757 if (m_newRowEditing) {
00758
00759 m_itemIterator->toLast();
00760 m_currentItem = **m_itemIterator;
00761 }
00762 m_rowEditing = false;
00763 m_newRowEditing = false;
00764
00765 if (m_verticalHeader)
00766 m_verticalHeader->setEditRow(-1);
00767
00768 updateAfterAcceptRowEdit();
00769
00770 kdDebug() << "EDIT ROW ACCEPTED:" << endl;
00771
00772
00773 if (inserting) {
00774
00775
00776 m_navPanel->setRecordCount(rows());
00777 }
00778 else {
00779
00780 }
00781
00782 rowEditTerminated(m_curRow);
00783 }
00784 else {
00785
00786
00787
00788
00789
00790
00791 int faultyColumn = -1;
00792 if (m_data->result()->column >= 0 && m_data->result()->column < columns())
00793 faultyColumn = m_data->result()->column;
00794 else if (columnEditedBeforeAccepting >= 0)
00795 faultyColumn = columnEditedBeforeAccepting;
00796 if (faultyColumn >= 0) {
00797 setCursorPosition(m_curRow, faultyColumn);
00798 }
00799
00800 const int button = showErrorMessageForResult( m_data->result() );
00801 if (KMessageBox::No == button) {
00802
00803 cancelRowEdit();
00804 }
00805 else {
00806 if (faultyColumn >= 0) {
00807
00808 startEditCurrentCell();
00809 }
00810 }
00811 }
00812
00813 return success;
00814 }
00815
00816 bool KexiDataAwareObjectInterface::cancelRowEdit()
00817 {
00818 if (!hasData())
00819 return false;
00820 if (!m_rowEditing)
00821 return false;
00822 cancelEditor();
00823 m_rowEditing = false;
00824
00825 if (m_verticalHeader)
00826 m_verticalHeader->setEditRow(-1);
00827 m_alsoUpdateNextRow = m_newRowEditing;
00828 if (m_newRowEditing) {
00829 m_newRowEditing = false;
00830
00831 m_data->removeLast();
00832
00833 m_currentItem = m_insertItem;
00834
00835 if (m_verticalHeader)
00836 m_verticalHeader->removeLabel(false);
00837
00838
00839
00840 updateWidgetContents();
00841
00842
00843
00844 updateWidgetContentsSize();
00845
00846
00847
00848 }
00849
00850 m_data->clearRowEditBuffer();
00851 updateAfterCancelRowEdit();
00852
00854 kexidbg << "EDIT ROW CANCELLED." << endl;
00855
00856 rowEditTerminated(m_curRow);
00857 return true;
00858 }
00859
00860 void KexiDataAwareObjectInterface::updateAfterCancelRowEdit()
00861 {
00862 updateRow(m_curRow);
00863 if (m_alsoUpdateNextRow)
00864 updateRow(m_curRow+1);
00865 m_alsoUpdateNextRow = false;
00866 }
00867
00868 void KexiDataAwareObjectInterface::updateAfterAcceptRowEdit()
00869 {
00870 updateRow(m_curRow);
00871 }
00872
00873 void KexiDataAwareObjectInterface::removeEditor()
00874 {
00875 if (!m_editor)
00876 return;
00877 m_editor->hideWidget();
00878 m_editor = 0;
00879 }
00880
00881 bool KexiDataAwareObjectInterface::cancelEditor()
00882 {
00883 if (m_errorMessagePopup) {
00884 m_errorMessagePopup->close();
00885 }
00886 if (!m_editor)
00887 return false;
00888 removeEditor();
00889 return true;
00890 }
00891
00893 class KexiDataAwareObjectInterfaceToolTip : public QToolTip {
00894 public:
00895 KexiDataAwareObjectInterfaceToolTip( const QString & text, const QPoint & pos, QWidget * widget )
00896 : QToolTip(widget), m_text(text)
00897 {
00898 tip( QRect(pos, QSize(100, 100)), text );
00899 }
00900 virtual void maybeTip(const QPoint & p) {
00901 tip( QRect(p, QSize(100, 100)), m_text);
00902 }
00903 QString m_text;
00904 };
00905
00906 bool KexiDataAwareObjectInterface::acceptEditor()
00907 {
00908 if (!hasData())
00909 return true;
00910 if (!m_editor || m_inside_acceptEditor)
00911 return true;
00912
00913 m_inside_acceptEditor = true;
00914
00915 QVariant newval;
00916 Validator::Result res = Validator::Ok;
00917 QString msg, desc;
00918 bool setNull = false;
00919
00920
00921
00922
00923 const bool autoIncColumnCanBeOmitted = m_newRowEditing && m_editor->field()->isAutoIncrement();
00924
00925
00926 bool valueChanged = m_editor->valueChanged();
00927 bool editCurrentCellAgain = false;
00928
00929 if (valueChanged) {
00930 if (!m_editor->valueIsValid()) {
00931
00932 res = Validator::Error;
00933 editCurrentCellAgain = true;
00934 QWidget *par = dynamic_cast<QScrollView*>(this) ? dynamic_cast<QScrollView*>(this)->viewport() :
00935 dynamic_cast<QWidget*>(this);
00936 QWidget *edit = dynamic_cast<QWidget*>(m_editor);
00937 if (par && edit) {
00940 if (!m_errorMessagePopup) {
00941
00942 m_errorMessagePopup = new KexiArrowTip(
00943 i18n("Error: %1").arg(m_editor->columnInfo()->field->typeName())+"?",
00944 dynamic_cast<QWidget*>(this));
00945 m_errorMessagePopup->move(
00946 par->mapToGlobal(edit->pos()) + QPoint(6, edit->height() + 0) );
00947 m_errorMessagePopup->show();
00948 }
00949 m_editor->setFocus();
00950 }
00951 }
00952 else if (m_editor->valueIsNull()) {
00953
00954 if (m_editor->field()->isNotNull() && !autoIncColumnCanBeOmitted) {
00955 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NULL NOT ALLOWED!" << endl;
00956 res = Validator::Error;
00957
00958 msg = Validator::msgColumnNotEmpty().arg(m_editor->field()->captionOrName())
00959 + "\n\n" + Kexi::msgYouCanImproveData();
00960 desc = i18n("The column's constraint is declared as NOT NULL.");
00961 editCurrentCellAgain = true;
00962
00963
00964
00965 }
00966 else {
00967 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NULL VALUE WILL BE SET" << endl;
00968
00969 setNull = true;
00970 }
00971 }
00972 else if (m_editor->valueIsEmpty()) {
00973
00974 if (m_editor->field()->hasEmptyProperty()) {
00975
00976 if (m_editor->field()->isNotEmpty() && !autoIncColumnCanBeOmitted) {
00977 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): EMPTY NOT ALLOWED!" << endl;
00978 res = Validator::Error;
00979
00980 msg = Validator::msgColumnNotEmpty().arg(m_editor->field()->captionOrName())
00981 + "\n\n" + Kexi::msgYouCanImproveData();
00982 desc = i18n("The column's constraint is declared as NOT EMPTY.");
00983 editCurrentCellAgain = true;
00984
00985
00986
00987 }
00988 else {
00989 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): EMPTY VALUE WILL BE SET" << endl;
00990 }
00991 }
00992 else {
00993
00994 if (m_editor->field()->isNotNull() && !autoIncColumnCanBeOmitted) {
00995 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NEITHER NULL NOR EMPTY VALUE CAN BE SET!" << endl;
00996 res = Validator::Error;
00997
00998 msg = Validator::msgColumnNotEmpty().arg(m_editor->field()->captionOrName())
00999 + "\n\n" + Kexi::msgYouCanImproveData();
01000 desc = i18n("The column's constraint is declared as NOT EMPTY and NOT NULL.");
01001 editCurrentCellAgain = true;
01002
01003
01004
01005 }
01006 else {
01007 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NULL VALUE WILL BE SET BECAUSE EMPTY IS NOT ALLOWED" << endl;
01008
01009 setNull = true;
01010 }
01011 }
01012 }
01013 }
01014
01015 const int realFieldNumber = fieldNumberForColumn(m_curCol);
01016 if (realFieldNumber < 0) {
01017 kdWarning() << "KexiDataAwareObjectInterface::acceptEditor(): fieldNumberForColumn(m_curCol) < 0" << endl;
01018 m_inside_acceptEditor = false;
01019 return false;
01020 }
01021
01022 KexiTableViewColumn *currentTVColumn = column(m_curCol);
01023
01024
01025 if (res == Validator::Ok) {
01026 if ((!setNull && !valueChanged)
01027 || (m_editor->field()->type()!=KexiDB::Field::Boolean && setNull && m_currentItem->at( realFieldNumber ).isNull())) {
01028 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): VALUE NOT CHANGED." << endl;
01029 removeEditor();
01030 if (m_acceptsRowEditAfterCellAccepting || m_internal_acceptsRowEditAfterCellAccepting)
01031 acceptRowEdit();
01032 m_inside_acceptEditor = false;
01033 return true;
01034 }
01035 if (!setNull) {
01036
01037 newval = m_editor->value();
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050 }
01051
01052
01053
01054
01055 Validator *validator = currentTVColumn->validator();
01056 if (validator) {
01057
01058 res = validator->check(currentTVColumn->field()->captionOrName(),
01059 newval, msg, desc);
01060 }
01061 }
01062
01063
01064 if (res == Validator::Error) {
01065 if (!msg.isEmpty()) {
01066 if (desc.isEmpty())
01067 KMessageBox::sorry(dynamic_cast<QWidget*>(this), msg);
01068 else
01069 KMessageBox::detailedSorry(dynamic_cast<QWidget*>(this), msg, desc);
01070 }
01071 editCurrentCellAgain = true;
01072
01073 }
01074 else if (res == Validator::Warning) {
01075
01076 KMessageBox::messageBox(dynamic_cast<QWidget*>(this), KMessageBox::Sorry, msg + "\n" + desc);
01077 editCurrentCellAgain = true;
01078 }
01079
01080 if (res == Validator::Ok) {
01081
01082
01083
01084
01085
01086 QVariant visibleValue;
01087 if (!newval.isNull()
01088 && currentTVColumn->visibleLookupColumnInfo)
01089 {
01090 visibleValue = m_editor->visibleValue();
01091 }
01092
01093 if (m_data->updateRowEditBufferRef(m_currentItem, m_curCol, currentTVColumn,
01094 newval, true, currentTVColumn->visibleLookupColumnInfo ? &visibleValue : 0))
01095 {
01096 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): ------ EDIT BUFFER CHANGED TO:" << endl;
01097 m_data->rowEditBuffer()->debug();
01098 } else {
01099 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): ------ CHANGE FAILED in KexiDataAwareObjectInterface::updateRowEditBuffer()" << endl;
01100 res = Validator::Error;
01101
01102
01103
01104
01105 if (m_editor && m_data->result()->column>=0 && m_data->result()->column<columns()) {
01106
01107 setCursorPosition(m_curRow, m_data->result()->column);
01108 }
01109 if (!m_data->result()->msg.isEmpty()) {
01110 const int button = showErrorMessageForResult( m_data->result() );
01111 if (KMessageBox::No == button) {
01112
01113 cancelEditor();
01114 if (m_acceptsRowEditAfterCellAccepting)
01115 cancelRowEdit();
01116 m_inside_acceptEditor = false;
01117 return false;
01118 }
01119 }
01120 }
01121 }
01122
01123 if (res == Validator::Ok) {
01124 removeEditor();
01125 itemChanged(m_currentItem, m_curRow, m_curCol,
01126 m_currentItem->at( realFieldNumber ));
01127 itemChanged(m_currentItem, m_curRow, m_curCol);
01128 }
01129 m_inside_acceptEditor = false;
01130 if (res == Validator::Ok) {
01131 if (m_acceptsRowEditAfterCellAccepting || m_internal_acceptsRowEditAfterCellAccepting)
01132 acceptRowEdit();
01133 return true;
01134 }
01135 if (m_editor) {
01136
01137
01138 if (m_editor->hasFocusableWidget()) {
01139 m_editor->showWidget();
01140 m_editor->setFocus();
01141 }
01142
01143
01144 }
01145 return false;
01146 }
01147
01148 void KexiDataAwareObjectInterface::startEditCurrentCell(const QString &setText)
01149 {
01150 kdDebug() << "** KexiDataAwareObjectInterface::startEditCurrentCell("<<setText<<")"<<endl;
01151
01152
01153 if (isReadOnly() || !columnEditable(m_curCol))
01154 return;
01155 if (m_editor) {
01156 if (m_editor->hasFocusableWidget()) {
01157 m_editor->showWidget();
01158 m_editor->setFocus();
01159 }
01160 }
01161
01162
01163
01164
01165 if (!m_editor)
01166 createEditor(m_curRow, m_curCol, setText, !setText.isEmpty());
01167 }
01168
01169 void KexiDataAwareObjectInterface::deleteAndStartEditCurrentCell()
01170 {
01171 if (isReadOnly() || !columnEditable(m_curCol))
01172 return;
01173 if (m_editor) {
01174 m_editor->clear();
01175 return;
01176 }
01177
01178
01179
01180
01181
01182 ensureCellVisible(m_curRow+1, m_curCol);
01183 createEditor(m_curRow, m_curCol, QString::null, false);
01184 if (!m_editor)
01185 return;
01186 m_editor->clear();
01187 if (m_editor->acceptEditorAfterDeleteContents())
01188 acceptEditor();
01189 if (!m_editor || !m_editor->hasFocusableWidget())
01190 updateCell(m_curRow, m_curCol);
01191 }
01192
01193 void KexiDataAwareObjectInterface::deleteCurrentRow()
01194 {
01195 if (m_newRowEditing) {
01196 cancelRowEdit();
01197 return;
01198 }
01199
01200 if (!acceptRowEdit())
01201 return;
01202
01203 if (!isDeleteEnabled() || !m_currentItem || m_currentItem == m_insertItem)
01204 return;
01205 switch (m_deletionPolicy) {
01206 case NoDelete:
01207 return;
01208 case ImmediateDelete:
01209 break;
01210 case AskDelete:
01211 if (KMessageBox::Cancel == KMessageBox::warningContinueCancel(dynamic_cast<QWidget*>(this),
01212 i18n("Do you want to delete selected row?"), 0,
01213 KGuiItem(i18n("&Delete Row"),"editdelete"),
01214 "dontAskBeforeDeleteRow",
01215 KMessageBox::Notify|KMessageBox::Dangerous))
01216 return;
01217 break;
01218 case SignalDelete:
01219 itemDeleteRequest(m_currentItem, m_curRow, m_curCol);
01220 currentItemDeleteRequest();
01221 return;
01222 default:
01223 return;
01224 }
01225
01226 if (!deleteItem(m_currentItem)) {
01227 }
01228 }
01229
01230 KexiTableItem *KexiDataAwareObjectInterface::insertEmptyRow(int row)
01231 {
01232 if ( !acceptRowEdit() || !isEmptyRowInsertingEnabled()
01233 || (row!=-1 && row >= ((int)rows()+(isInsertingEnabled()?1:0) ) ) )
01234 return 0;
01235
01236 KexiTableItem *newItem = m_data->createItem();
01237 insertItem(newItem, row);
01238 return newItem;
01239 }
01240
01241 void KexiDataAwareObjectInterface::insertItem(KexiTableItem *newItem, int row)
01242 {
01243 const bool changeCurrentRow = row==-1 || row==m_curRow;
01244 if (changeCurrentRow) {
01245
01246 row = (m_curRow >= 0 ? m_curRow : 0);
01247 m_currentItem = newItem;
01248 m_curRow = row;
01249 }
01250 else if (m_curRow >= row) {
01251 m_curRow++;
01252 }
01253
01254 m_data->insertRow(*newItem, row, true );
01255
01256 if (changeCurrentRow) {
01257
01258 m_itemIterator->toFirst();
01259 (*m_itemIterator)+=m_curRow;
01260 }
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282 }
01283
01284 void KexiDataAwareObjectInterface::slotRowInserted(KexiTableItem *item, bool repaint)
01285 {
01286 int row = m_data->findRef(item);
01287 slotRowInserted( item, row, repaint );
01288 }
01289
01290 void KexiDataAwareObjectInterface::slotRowInserted(KexiTableItem * , uint row, bool repaint)
01291 {
01292 if (repaint && (int)row<rows()) {
01293 updateWidgetContentsSize();
01294
01295
01296
01297
01298
01299
01300
01301 updateAllVisibleRowsBelow(row);
01302
01303 if (!m_verticalHeaderAlreadyAdded) {
01304 if (m_verticalHeader)
01305 m_verticalHeader->addLabel();
01306 }
01307 else
01308 m_verticalHeaderAlreadyAdded = false;
01309
01310
01311 m_navPanel->setRecordCount(rows());
01312
01313 if (m_curRow >= (int)row) {
01314
01315 editorShowFocus( m_curRow, m_curCol );
01316 }
01317 }
01318 }
01319
01320 tristate KexiDataAwareObjectInterface::deleteAllRows(bool ask, bool repaint)
01321 {
01322 if (!hasData())
01323 return true;
01324 if (m_data->count()<1)
01325 return true;
01326
01327 if (ask) {
01328 QString tableName = m_data->dbTableName();
01329 if (!tableName.isEmpty()) {
01330 tableName.prepend(" \"");
01331 tableName.append("\"");
01332 }
01333 if (KMessageBox::Cancel == KMessageBox::warningContinueCancel(dynamic_cast<QWidget*>(this),
01334 i18n("Do you want to clear the contents of table %1?").arg(tableName),
01335 0, KGuiItem(i18n("&Clear Contents")) ))
01336 return cancelled;
01337 }
01338
01339 cancelRowEdit();
01340
01341
01342 const bool repaintLater = repaint && m_spreadSheetMode;
01343 const int oldRows = rows();
01344
01345 bool res = m_data->deleteAllRows(repaint && !repaintLater);
01346
01347 if (res) {
01348 if (m_spreadSheetMode) {
01349
01350 for (int i=0; i<oldRows; i++) {
01351 m_data->append(m_data->createItem());
01352 }
01353 }
01354 }
01355 if (repaintLater)
01356 m_data->reload();
01357
01358
01359
01360
01361
01362
01363
01364 return res;
01365 }
01366
01367 void KexiDataAwareObjectInterface::clearColumns(bool repaint)
01368 {
01369 cancelRowEdit();
01370 m_data->clearInternal();
01371
01372 clearColumnsInternal(repaint);
01373 updateIndicesForVisibleValues();
01374
01375 if (repaint)
01376
01377
01378 updateWidgetContents();
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401 }
01402
01403 void KexiDataAwareObjectInterface::reloadData()
01404 {
01405
01406 acceptRowEdit();
01407 if (m_verticalHeader)
01408 m_verticalHeader->clear();
01409
01410 if (m_curCol>=0 && m_curCol<columns()) {
01411
01412 KexiDataItemInterface *edit = editor( m_curCol );
01413 if (edit) {
01414 edit->hideFocus();
01415 }
01416 }
01417
01418 clearVariables();
01419 if (m_verticalHeader)
01420 m_verticalHeader->setCurrentRow(-1);
01421
01422 if (dynamic_cast<QWidget*>(this) && dynamic_cast<QWidget*>(this)->isVisible())
01423 initDataContents();
01424 else
01425 m_initDataContentsOnShow = true;
01426
01427 if (m_verticalHeader)
01428 m_verticalHeader->addLabels(m_data->count());
01429
01430 updateWidgetScrollBars();
01431 }
01432
01433 int KexiDataAwareObjectInterface::columnType(int col)
01434 {
01435 KexiTableViewColumn* c = m_data ? column(col) : 0;
01436 return c ? c->field()->type() : KexiDB::Field::InvalidType;
01437 }
01438
01439 bool KexiDataAwareObjectInterface::columnEditable(int col)
01440 {
01441 KexiTableViewColumn* c = m_data ? column(col) : 0;
01442 return c ? (! c->isReadOnly()) : false;
01443 }
01444
01445 int KexiDataAwareObjectInterface::rows() const
01446 {
01447 if (!hasData())
01448 return 0;
01449 return m_data->count();
01450 }
01451
01452 int KexiDataAwareObjectInterface::dataColumns() const
01453 {
01454 if (!hasData())
01455 return 0;
01456 return m_data->columns.count();
01457 }
01458
01459 QVariant KexiDataAwareObjectInterface::columnDefaultValue(int ) const
01460 {
01461 return QVariant(0);
01462
01463
01464 }
01465
01466 void KexiDataAwareObjectInterface::setAcceptsRowEditAfterCellAccepting(bool set)
01467 {
01468 m_acceptsRowEditAfterCellAccepting = set;
01469 }
01470
01471 void KexiDataAwareObjectInterface::setDropsAtRowEnabled(bool set)
01472 {
01473
01474 if (!set)
01475 m_dragIndicatorLine = -1;
01476 if (m_dropsAtRowEnabled && !set) {
01477 m_dropsAtRowEnabled = false;
01478
01479 updateWidgetContents();
01480 }
01481 else {
01482 m_dropsAtRowEnabled = set;
01483 }
01484 }
01485
01486 void KexiDataAwareObjectInterface::setEmptyRowInsertingEnabled(bool set)
01487 {
01488 m_emptyRowInsertingEnabled = set;
01489 reloadActions();
01490 }
01491
01492 void KexiDataAwareObjectInterface::slotAboutToDeleteRow(KexiTableItem& item,
01493 KexiDB::ResultInfo* , bool repaint)
01494 {
01495 if (repaint) {
01496 m_rowWillBeDeleted = m_data->findRef(&item);
01497 }
01498 }
01499
01500 void KexiDataAwareObjectInterface::slotRowDeleted()
01501 {
01502 if (m_rowWillBeDeleted >= 0) {
01503 if (m_rowWillBeDeleted > 0 && m_rowWillBeDeleted >= (rows()-1) && !m_spreadSheetMode)
01504 m_rowWillBeDeleted = rows()-1;
01505 updateWidgetContentsSize();
01506
01507 if (! (m_spreadSheetMode && m_rowWillBeDeleted>=(rows()-1)))
01508 setCursorPosition(m_rowWillBeDeleted, m_curCol, true);
01509 if (m_verticalHeader)
01510 m_verticalHeader->removeLabel();
01511
01512 updateAllVisibleRowsBelow(m_curRow);
01513
01514
01515 m_navPanel->setRecordCount(rows());
01516
01517 m_rowWillBeDeleted = -1;
01518 }
01519 }
01520
01521 bool KexiDataAwareObjectInterface::beforeDeleteItem(KexiTableItem *)
01522 {
01523
01524 return true;
01525 }
01526
01527 bool KexiDataAwareObjectInterface::deleteItem(KexiTableItem *item)
01528 {
01529 if (!item || !beforeDeleteItem(item))
01530 return false;
01531
01532 QString msg, desc;
01533
01534 const bool lastRowDeleted = m_spreadSheetMode && m_data->last() == item;
01535
01536
01537 if (!m_data->deleteRow(*item, true )) {
01538
01539 showErrorMessageForResult( m_data->result() );
01540
01541
01542
01543 return false;
01544 }
01545 else {
01546
01547
01548 }
01549
01550
01551 if (m_spreadSheetMode) {
01552 m_data->append(m_data->createItem());
01553 if (m_verticalHeader)
01554 m_verticalHeader->addLabels(1);
01555 if (lastRowDeleted)
01556 setCursorPosition(rows()-1, m_curCol, true);
01557 newItemAppendedForAfterDeletingInSpreadSheetMode();
01558 }
01559 return true;
01560 }
01561
01562 KexiTableViewColumn* KexiDataAwareObjectInterface::column(int col)
01563 {
01564 return m_data->column(col);
01565 }
01566
01567 bool KexiDataAwareObjectInterface::hasDefaultValueAt(const KexiTableViewColumn& tvcol)
01568 {
01569 if (m_rowEditing && m_data->rowEditBuffer() && m_data->rowEditBuffer()->isDBAware()) {
01570 return m_data->rowEditBuffer()->hasDefaultValueAt( *tvcol.columnInfo );
01571 }
01572 return false;
01573 }
01574
01575 const QVariant* KexiDataAwareObjectInterface::bufferedValueAt(int col, bool useDefaultValueIfPossible)
01576 {
01577 if (m_rowEditing && m_data->rowEditBuffer())
01578 {
01579 KexiTableViewColumn* tvcol = column(col);
01580 if (tvcol->isDBAware) {
01581
01582 const int realFieldNumber = fieldNumberForColumn(col);
01583 if (realFieldNumber < 0) {
01584 kdWarning() << "KexiDataAwareObjectInterface::bufferedValueAt(): "
01585 "fieldNumberForColumn(m_curCol) < 0" << endl;
01586 return 0;
01587 }
01588 QVariant *storedValue = &m_currentItem->at( realFieldNumber );
01589
01590
01591 const QVariant *cv = m_data->rowEditBuffer()->at( *tvcol->columnInfo,
01592 storedValue->isNull() && useDefaultValueIfPossible);
01593 if (cv)
01594 return cv;
01595 return storedValue;
01596 }
01597
01598 const QVariant *cv = m_data->rowEditBuffer()->at( tvcol->field()->name() );
01599 if (cv)
01600 return cv;
01601 }
01602
01603 const int realFieldNumber = fieldNumberForColumn(col);
01604 if (realFieldNumber < 0) {
01605 kdWarning() << "KexiDataAwareObjectInterface::bufferedValueAt(): "
01606 "fieldNumberForColumn(m_curCol) < 0" << endl;
01607 return 0;
01608 }
01609 return &m_currentItem->at( realFieldNumber );
01610 }
01611
01612 void KexiDataAwareObjectInterface::startEditOrToggleValue()
01613 {
01614 if ( !isReadOnly() && columnEditable(m_curCol) ) {
01615 if (columnType(m_curCol) == KexiDB::Field::Boolean) {
01616 boolToggled();
01617 }
01618 else {
01619 startEditCurrentCell();
01620 return;
01621 }
01622 }
01623 }
01624
01625 void KexiDataAwareObjectInterface::boolToggled()
01626 {
01627 startEditCurrentCell();
01628 if (m_editor) {
01629 m_editor->clickedOnContents();
01630 }
01631 acceptEditor();
01632 updateCell(m_curRow, m_curCol);
01633
01634
01635
01636
01637
01638
01639
01640 }
01641
01642 void KexiDataAwareObjectInterface::slotDataDestroying()
01643 {
01644 m_data = 0;
01645 m_itemIterator = 0;
01646 }
01647
01648 void KexiDataAwareObjectInterface::addNewRecordRequested()
01649 {
01650 if (!isInsertingEnabled())
01651 return;
01652 if (m_rowEditing) {
01653 if (!acceptRowEdit())
01654 return;
01655 }
01656
01657 selectRow(rows());
01658 startEditCurrentCell();
01659 if (m_editor)
01660 m_editor->setFocus();
01661 }
01662
01663 bool KexiDataAwareObjectInterface::handleKeyPress(QKeyEvent *e, int &curRow, int &curCol,
01664 bool fullRowSelection, bool *moveToFirstField, bool *moveToLastField)
01665 {
01666 if (moveToFirstField)
01667 *moveToFirstField = false;
01668 if (moveToLastField)
01669 *moveToLastField = false;
01670
01671 const bool nobtn = e->state()==Qt::NoButton;
01672 const int k = e->key();
01673
01674
01675 if ((k == Qt::Key_Up && nobtn) || (k == Qt::Key_PageUp && e->state()==Qt::ControlButton)) {
01676 selectPrevRow();
01677 e->accept();
01678 }
01679 else if ((k == Qt::Key_Down && nobtn) || (k == Qt::Key_PageDown && e->state()==Qt::ControlButton)) {
01680 selectNextRow();
01681 e->accept();
01682 }
01683 else if (k == Qt::Key_PageUp && nobtn) {
01684 selectPrevPage();
01685 e->accept();
01686 }
01687 else if (k == Qt::Key_PageDown && nobtn) {
01688 selectNextPage();
01689 e->accept();
01690 }
01691 else if (k == Qt::Key_Home) {
01692 if (fullRowSelection) {
01693
01694 curRow = 0;
01695 }
01696 else {
01697 if (nobtn) {
01698 curCol = 0;
01699 }
01700 else if (e->state()==Qt::ControlButton) {
01701 curRow = 0;
01702 curCol = 0;
01703 }
01704 else
01705 return false;
01706 }
01707 if (moveToFirstField)
01708 *moveToFirstField = true;
01709
01710 e->ignore();
01711 }
01712 else if (k == Qt::Key_End) {
01713 if (fullRowSelection) {
01714
01715 curRow = m_data->count()-1+(isInsertingEnabled()?1:0);
01716 }
01717 else {
01718 if (nobtn) {
01719 curCol = columns()-1;
01720 }
01721 else if (e->state()==Qt::ControlButton) {
01722 curRow = m_data->count()-1 ;
01723 curCol = columns()-1;
01724 }
01725 else
01726 return false;
01727 }
01728 if (moveToLastField)
01729 *moveToLastField = true;
01730
01731 e->ignore();
01732 }
01733 else if (isInsertingEnabled() && (e->state()==Qt::ControlButton && k == Qt::Key_Equal
01734 || e->state()==(Qt::ControlButton|Qt::ShiftButton) && k == Qt::Key_Equal)) {
01735 curRow = m_data->count();
01736 curCol = 0;
01737 if (moveToFirstField)
01738 *moveToFirstField = true;
01739
01740 e->ignore();
01741 }
01742 else
01743 return false;
01744
01745 return true;
01746 }
01747
01748 void KexiDataAwareObjectInterface::vScrollBarValueChanged(int v)
01749 {
01750 Q_UNUSED(v);
01751 if (!m_vScrollBarValueChanged_enabled)
01752 return;
01753
01754 if (m_scrollbarToolTipsEnabled) {
01755 const QRect r( verticalScrollBar()->sliderRect() );
01756 const int row = lastVisibleRow()+1;
01757 if (row<=0) {
01758 m_scrollBarTipTimer.stop();
01759 m_scrollBarTip->hide();
01760 return;
01761 }
01762 m_scrollBarTip->setText( i18n("Row: ") + QString::number(row) );
01763 m_scrollBarTip->adjustSize();
01764 QWidget* thisWidget = dynamic_cast<QWidget*>(this);
01765 m_scrollBarTip->move(
01766 thisWidget->mapToGlobal( r.topLeft() + verticalScrollBar()->pos() )
01767 + QPoint( - m_scrollBarTip->width()-5,
01768 r.height()/2 - m_scrollBarTip->height()/2) );
01769 if (verticalScrollBar()->draggingSlider()) {
01770 kdDebug(44021) << " draggingSlider() " << endl;
01771 m_scrollBarTipTimer.stop();
01772 m_scrollBarTip->show();
01773 m_scrollBarTip->raise();
01774 }
01775 else {
01776 m_scrollBarTipTimerCnt++;
01777 if (m_scrollBarTipTimerCnt>4) {
01778 m_scrollBarTipTimerCnt=0;
01779 m_scrollBarTip->show();
01780 m_scrollBarTip->raise();
01781 m_scrollBarTipTimer.start(500, true);
01782 }
01783 }
01784 }
01785
01786
01787
01788
01789
01790 }
01791
01792 bool KexiDataAwareObjectInterface::scrollbarToolTipsEnabled() const
01793 {
01794 return m_scrollbarToolTipsEnabled;
01795 }
01796
01797 void KexiDataAwareObjectInterface::setScrollbarToolTipsEnabled(bool set)
01798 {
01799 m_scrollbarToolTipsEnabled = set;
01800 }
01801
01802 void KexiDataAwareObjectInterface::vScrollBarSliderReleased()
01803 {
01804 kdDebug(44021) << "vScrollBarSliderReleased()" << endl;
01805 m_scrollBarTip->hide();
01806 }
01807
01808 void KexiDataAwareObjectInterface::scrollBarTipTimeout()
01809 {
01810 if (m_scrollBarTip->isVisible()) {
01811
01812 if (m_scrollBarTipTimerCnt>0) {
01813 m_scrollBarTipTimerCnt=0;
01814 m_scrollBarTipTimer.start(500, true);
01815 return;
01816 }
01817 m_scrollBarTip->hide();
01818 }
01819 m_scrollBarTipTimerCnt=0;
01820 }
01821
01822 void KexiDataAwareObjectInterface::focusOutEvent(QFocusEvent* e)
01823 {
01824 Q_UNUSED(e);
01825 m_scrollBarTipTimer.stop();
01826 m_scrollBarTip->hide();
01827
01828 updateCell(m_curRow, m_curCol);
01829 }
01830
01831 int KexiDataAwareObjectInterface::showErrorMessageForResult(KexiDB::ResultInfo* resultInfo)
01832 {
01833 QWidget *thisWidget = dynamic_cast<QWidget*>(this);
01834 if (resultInfo->allowToDiscardChanges) {
01835 return KMessageBox::questionYesNo(thisWidget, resultInfo->msg
01836 + (resultInfo->desc.isEmpty() ? QString::null : ("\n"+resultInfo->desc)),
01837 QString::null,
01838 KGuiItem(i18n("Correct Changes", "Correct"), QString::null, i18n("Correct changes")),
01839 KGuiItem(i18n("Discard Changes")) );
01840 }
01841
01842 if (resultInfo->desc.isEmpty())
01843 KMessageBox::sorry(thisWidget, resultInfo->msg);
01844 else
01845 KMessageBox::detailedSorry(thisWidget, resultInfo->msg, resultInfo->desc);
01846
01847 return KMessageBox::Ok;
01848 }
01849
01850 void KexiDataAwareObjectInterface::updateIndicesForVisibleValues()
01851 {
01852 m_indicesForVisibleValues.resize( m_data ? m_data->columnsCount() : 0 );
01853 if (!m_data)
01854 return;
01855 for (uint i=0; i < m_data->columnsCount(); i++) {
01856 KexiTableViewColumn* tvCol = m_data->column(i);
01857 if (tvCol->columnInfo && tvCol->columnInfo->indexForVisibleLookupValue()!=-1)
01858
01859 m_indicesForVisibleValues[ i ] = tvCol->columnInfo->indexForVisibleLookupValue();
01860 else
01861 m_indicesForVisibleValues[ i ] = i;
01862 }
01863 }
01864
01876 static inline bool findInString(const QString& stringValue, int stringLength, const QString& where,
01877 int& firstCharacter, bool matchAnyPartOfField, bool matchWholeField,
01878 bool caseSensitive, bool wholeWordsOnly, bool forward)
01879 {
01880 if (where.isEmpty()) {
01881 firstCharacter = -1;
01882 return false;
01883 }
01884
01885 if (matchAnyPartOfField) {
01886 if (forward) {
01887 int pos = firstCharacter == -1 ? 0 : firstCharacter;
01888 if (wholeWordsOnly) {
01889 const int whereLength = where.length();
01890 while (true) {
01891 pos = where.find( stringValue, pos, caseSensitive );
01892 if (pos == -1)
01893 break;
01894 if ((pos > 0 && where.at(pos-1).isLetterOrNumber())
01895 ||((pos+stringLength-1) < (whereLength-1) && where.at(pos+stringLength-1+1).isLetterOrNumber()))
01896 {
01897 pos++;
01898 }
01899 else
01900 break;
01901 }
01902 firstCharacter = pos;
01903 }
01904 else {
01905 firstCharacter = where.find( stringValue, pos, caseSensitive );
01906 }
01907 return firstCharacter != -1;
01908 }
01909 else {
01910 if (firstCharacter == INT_MAX) {
01911 firstCharacter = -1;
01912 return false;
01913 }
01914 int pos = firstCharacter;
01915 if (wholeWordsOnly) {
01916 const int whereLength = where.length();
01917 while (true) {
01918 pos = where.findRev( stringValue, pos, caseSensitive );
01919 if (pos == -1)
01920 break;
01921 if ((pos > 0 && where.at(pos-1).isLetterOrNumber())
01922 ||((pos+stringLength-1) < (whereLength-1) && where.at(pos+stringLength-1+1).isLetterOrNumber()))
01923 {
01924
01925 pos--;
01926 if (pos < 0)
01927 break;
01928 }
01929 else
01930 break;
01931 }
01932 firstCharacter = pos;
01933 }
01934 else {
01935 firstCharacter = where.findRev( stringValue, pos, caseSensitive );
01936 }
01937 return firstCharacter != -1;
01938 }
01939 }
01940 else if (matchWholeField) {
01941 if (firstCharacter != -1 && firstCharacter != 0) {
01942 firstCharacter = -1;
01943 }
01944 else if ( (caseSensitive ? where : where.lower()) == stringValue) {
01945 firstCharacter = 0;
01946 return true;
01947 }
01948 }
01949 else {
01950 if (firstCharacter != -1 && firstCharacter != 0) {
01951 firstCharacter = -1;
01952 }
01953 else if (where.startsWith(stringValue, caseSensitive)) {
01954 if (wholeWordsOnly) {
01955
01956 return !where.at( stringValue.length() ).isLetterOrNumber();
01957 }
01958 firstCharacter = 0;
01959 return true;
01960 }
01961 }
01962 return false;
01963 }
01964
01965 tristate KexiDataAwareObjectInterface::find(const QVariant& valueToFind,
01966 const KexiSearchAndReplaceViewInterface::Options& options, bool next)
01967 {
01968 if (!hasData())
01969 return cancelled;
01970 const QVariant prevSearchedValue( m_recentlySearchedValue );
01971 m_recentlySearchedValue = valueToFind;
01972 const KexiSearchAndReplaceViewInterface::Options::SearchDirection prevSearchDirection = m_recentSearchDirection;
01973 m_recentSearchDirection = options.searchDirection;
01974 if (valueToFind.isNull() || valueToFind.toString().isEmpty())
01975 return cancelled;
01976
01977 const bool forward = (options.searchDirection == KexiSearchAndReplaceViewInterface::Options::SearchUp)
01978 ? !next : next;
01979
01980 if ((!prevSearchedValue.isNull() && prevSearchedValue!=valueToFind)
01981 || (prevSearchDirection!=options.searchDirection && options.searchDirection==KexiSearchAndReplaceViewInterface::Options::SearchAllRows))
01982 {
01983
01984 m_positionOfRecentlyFoundValue.exists = false;
01985 }
01986
01987 const bool startFrom1stRowAndCol = !m_positionOfRecentlyFoundValue.exists && next
01988 && options.searchDirection == KexiSearchAndReplaceViewInterface::Options::SearchAllRows;
01989 const bool startFromLastRowAndCol =
01990 (!m_positionOfRecentlyFoundValue.exists && !next && options.searchDirection == KexiSearchAndReplaceViewInterface::Options::SearchAllRows)
01991 ||(m_curRow >= rows() && !forward);
01992
01993 if (!startFrom1stRowAndCol && !startFromLastRowAndCol && m_curRow >= rows()) {
01994
01995 return false;
01996 }
01997 KexiTableViewData::Iterator it( (startFrom1stRowAndCol || startFromLastRowAndCol)
01998 ? m_data->iterator() : *m_itemIterator );
01999 if (startFromLastRowAndCol)
02000 it.toLast();
02001 int firstCharacter;
02002 if (m_positionOfRecentlyFoundValue.exists) {
02003 if (forward)
02004 firstCharacter = m_positionOfRecentlyFoundValue.lastCharacter + 1;
02005 else {
02006 firstCharacter = (m_positionOfRecentlyFoundValue.firstCharacter > 0) ?
02007 (m_positionOfRecentlyFoundValue.firstCharacter - 1) : INT_MAX ;
02008 }
02009 }
02010 else {
02011 firstCharacter = -1;
02012 }
02013
02014 const int columnsCount = m_data->columnsCount();
02015 int row, col;
02016 if (startFrom1stRowAndCol) {
02017 row = 0;
02018 col = 0;
02019 }
02020 else if (startFromLastRowAndCol) {
02021 row = rows()-1;
02022 col = columnsCount-1;
02023 }
02024 else {
02025 row = m_curRow;
02026 col = m_curCol;
02027 }
02028
02029
02030 const bool matchAnyPartOfField
02031 = options.textMatching == KexiSearchAndReplaceViewInterface::Options::MatchAnyPartOfField;
02032 const bool matchWholeField
02033 = options.textMatching == KexiSearchAndReplaceViewInterface::Options::MatchWholeField;
02034 const bool caseSensitive = options.caseSensitive;
02035 const bool wholeWordsOnly = options.wholeWordsOnly;
02036
02037 int columnNumber = (options.columnNumber == KexiSearchAndReplaceViewInterface::Options::CurrentColumn)
02038 ? m_curCol : options.columnNumber;
02039 if (columnNumber>=0)
02040 col = columnNumber;
02041 const bool lookInAllColumns = columnNumber == KexiSearchAndReplaceViewInterface::Options::AllColumns;
02042 int firstColumn;
02043 int lastColumn;
02044 if (lookInAllColumns) {
02045 firstColumn = forward ? 0 : columnsCount-1;
02046 lastColumn = forward ? columnsCount-1 : 0;
02047 }
02048 else {
02049 firstColumn = columnNumber;
02050 lastColumn = columnNumber;
02051 }
02052 const QString stringValue( caseSensitive ? valueToFind.toString() : valueToFind.toString().lower() );
02053 const int stringLength = stringValue.length();
02054
02055
02056 const int prevRow = m_curRow;
02057 KexiTableItem *item;
02058 while ( (item = it.current()) ) {
02059 for (; forward ? col <= lastColumn : col >= lastColumn;
02060 col = forward ? (col+1) : (col-1))
02061 {
02062 const QVariant cell( item->at( m_indicesForVisibleValues[ col ] ) );
02063 if (findInString(stringValue, stringLength, cell.toString(), firstCharacter,
02064 matchAnyPartOfField, matchWholeField, caseSensitive, wholeWordsOnly, forward))
02065 {
02066
02067
02068
02069
02070 setCursorPosition(row, col, true);
02071 if (prevRow != m_curRow)
02072 updateRow(prevRow);
02073
02074 m_positionOfRecentlyFoundValue.exists = true;
02075 m_positionOfRecentlyFoundValue.firstCharacter = firstCharacter;
02077 m_positionOfRecentlyFoundValue.lastCharacter = firstCharacter + stringLength - 1;
02078 return true;
02079 }
02080 }
02081 if (forward) {
02082 ++it;
02083 ++row;
02084 }
02085 else {
02086 --it;
02087 --row;
02088 }
02089 col = firstColumn;
02090 }
02091 return false;
02092 }
02093
02094 tristate KexiDataAwareObjectInterface::findNextAndReplace(
02095 const QVariant& valueToFind, const QVariant& replacement,
02096 const KexiSearchAndReplaceViewInterface::Options& options, bool replaceAll)
02097 {
02098 Q_UNUSED(replacement);
02099 Q_UNUSED(options);
02100 Q_UNUSED(replaceAll);
02101
02102 if (isReadOnly())
02103 return cancelled;
02104 if (valueToFind.isNull() || valueToFind.toString().isEmpty())
02105 return cancelled;
02107 return false;
02108 }