kexi

kexidataawareobjectiface.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2005-2007 Jaroslaw Staniek <js@iidea.pl>
3
4 Based on KexiTableView code.
5 Copyright (C) 2002 Till Busch <till@bux.at>
6 Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
7 Copyright (C) 2003 Daniel Molkentin <molkentin@kde.org>
8 Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org>
9
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Library General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Library General Public License for more details.
19
20 You should have received a copy of the GNU Library General Public License
21 along with this program; see the file COPYING. If not, write to
22 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24*/
25
26#include "kexidataawareobjectiface.h"
27
28#include <tqscrollview.h>
29#include <tqlabel.h>
30#include <tqtooltip.h>
31
32#include <tdemessagebox.h>
33
34#include <kexi.h>
35#include <kexiutils/validator.h>
36#include <widget/utils/kexirecordnavigator.h>
37#include <widget/utils/kexirecordmarker.h>
38#include <kexidb/roweditbuffer.h>
39#include <kexidataiteminterface.h>
40
41#include "kexitableviewheader.h"
42
43using namespace KexiUtils;
44
45KexiDataAwareObjectInterface::KexiDataAwareObjectInterface()
46{
47 m_data = 0;
49 m_readOnly = -1; //don't know
50 m_insertingEnabled = -1; //don't know
51 m_isSortingEnabled = true;
53 m_deletionPolicy = AskDelete;
56 m_internal_acceptsRowEditAfterCellAccepting = false;
58 m_navPanel = 0;
63 m_insertItem = 0;
64// m_rowEditBuffer = 0;
65 m_spreadSheetMode = false;
66 m_dropsAtRowEnabled = false;
70 m_popupMenu = 0;
71 m_contextMenuEnabled = true;
73 m_alsoUpdateNextRow = false;
79 m_recentSearchDirection = KexiSearchAndReplaceViewInterface::Options::DefaultSearchDirection;
80
81 // setup scrollbar tooltip and related members
82 m_scrollBarTip = new TQLabel("",0, "vScrollBarToolTip",
83 TQt::WStyle_Customize |TQt::WStyle_NoBorder|TQt::WX11BypassWM|TQt::WStyle_StaysOnTop|TQt::WStyle_Tool);
84 m_scrollBarTip->setPalette(TQToolTip::palette());
85 m_scrollBarTip->setMargin(2);
86 m_scrollBarTip->setIndent(0);
87 m_scrollBarTip->setAlignment(TQt::AlignCenter);
88 m_scrollBarTip->setFrameStyle( TQFrame::Plain | TQFrame::Box );
89 m_scrollBarTip->setLineWidth(1);
90
92}
93
94KexiDataAwareObjectInterface::~KexiDataAwareObjectInterface()
95{
96 delete m_insertItem;
97// delete m_rowEditBuffer;
98 delete m_itemIterator;
99 delete m_scrollBarTip;
100 //we cannot delete m_data here... subclasses should do this
101}
102
104{
105 m_editor = 0;
106// m_rowEditBuffer = 0;
107 m_rowEditing = false;
108 m_newRowEditing = false;
109 m_curRow = -1;
110 m_curCol = -1;
111 m_currentItem = 0;
112}
113
115{
116 const bool theSameData = m_data && m_data==data;
117 if (m_owner && m_data && m_data!=data/*don't destroy if it's the same*/) {
118 kexidbg << "KexiDataAwareObjectInterface::setData(): destroying old data (owned)" << endl;
119 delete m_itemIterator;
120 delete m_data; //destroy old data
121 m_data = 0;
122 m_itemIterator = 0;
123 }
124 m_owner = owner;
125 m_data = data;
126 if (m_data)
127 m_itemIterator = m_data->createIterator();
128
129 kdDebug(44021) << "KexiDataAwareObjectInterface::setData(): using shared data" << endl;
130 //add columns
131//OK?
133 if (m_data) {
134 int i = 0;
135 for (KexiTableViewColumn::ListIterator it(m_data->columns);
136 it.current(); ++it, i++)
137 {
138 KexiDB::Field *f = it.current()->field();
139 if (it.current()->visible()) {
140 int wid = f->width();
141 if (wid==0)
142 wid=KEXI_DEFAULT_DATA_COLUMN_WIDTH;//default col width in pixels
144 addHeaderColumn(it.current()->isHeaderTextVisible()
145 ? it.current()->captionAliasOrName() : TQString(),
146 f->description(), it.current()->icon(), wid);
147 }
148 }
149 }
150 if (m_verticalHeader) {
151 m_verticalHeader->clear();
152 if (m_data)
153 m_verticalHeader->addLabels(m_data->count());
154 }
155 if (m_data && m_data->count()==0)
156 m_navPanel->setCurrentRecordNumber(0+1);
157
158 if (m_data && !theSameData) {
160 setSorting(-1);
161// connect(m_data, TQ_SIGNAL(refreshRequested()), this, TQ_SLOT(slotRefreshRequested()));
162 connectToReloadDataSlot(m_data, TQ_SIGNAL(reloadRequested()));
163 TQObject* thisObject = dynamic_cast<TQObject*>(this);
164 if (thisObject) {
165 TQObject::connect(m_data, TQ_SIGNAL(destroying()), thisObject, TQ_SLOT(slotDataDestroying()));
166 TQObject::connect(m_data, TQ_SIGNAL(rowsDeleted( const TQValueList<int> & )),
167 thisObject, TQ_SLOT(slotRowsDeleted( const TQValueList<int> & )));
168 TQObject::connect(m_data, TQ_SIGNAL(aboutToDeleteRow(KexiTableItem&,KexiDB::ResultInfo*,bool)),
169 thisObject, TQ_SLOT(slotAboutToDeleteRow(KexiTableItem&,KexiDB::ResultInfo*,bool)));
170 TQObject::connect(m_data, TQ_SIGNAL(rowDeleted()), thisObject, TQ_SLOT(slotRowDeleted()));
171 TQObject::connect(m_data, TQ_SIGNAL(rowInserted(KexiTableItem*,bool)),
172 thisObject, TQ_SLOT(slotRowInserted(KexiTableItem*,bool)));
173 TQObject::connect(m_data, TQ_SIGNAL(rowInserted(KexiTableItem*,uint,bool)),
174 thisObject, TQ_SLOT(slotRowInserted(KexiTableItem*,uint,bool))); //not db-aware
175 TQObject::connect(m_data, TQ_SIGNAL(rowRepaintRequested(KexiTableItem&)),
176 thisObject, TQ_SLOT(slotRowRepaintRequested(KexiTableItem&)));
177 // setup scrollbar's tooltip
178 TQObject::connect(verticalScrollBar(),TQ_SIGNAL(sliderReleased()),
179 thisObject,TQ_SLOT(vScrollBarSliderReleased()));
180 TQObject::connect(verticalScrollBar(),TQ_SIGNAL(valueChanged(int)),
181 thisObject,TQ_SLOT(vScrollBarValueChanged(int)));
182 TQObject::connect(&m_scrollBarTipTimer,TQ_SIGNAL(timeout()),
183 thisObject,TQ_SLOT(scrollBarTipTimeout()));
184 }
185 }
186
187 if (!m_data) {
188// clearData();
190 //m_data->clearInternal();
192 }
193 else {
194 if (!m_insertItem) {//first setData() call - add 'insert' item
195 m_insertItem = m_data->createItem(); //new KexiTableItem(m_data->columns.count());
196 }
197 else {//just reinit
198 m_insertItem->init(m_data->columns.count());
199 }
200 }
201
202 //update gui mode
203 m_navPanel->setInsertingEnabled(m_data && isInsertingEnabled());
205 m_verticalHeader->showInsertRow(m_data && isInsertingEnabled());
206
209
210 if (m_data)
211 /*emit*/ dataSet( m_data );
212}
213
215{
216 m_editor = 0;
217// TQSize s(tableSize());
218// resizeContents(s.width(),s.height());
219
220 m_navPanel->setRecordCount(rows());
221
223 //set current row:
224 m_currentItem = 0;
225 int curRow = -1, curCol = -1;
226 if (m_data->columnsCount()>0) {
227 if (rows()>0) {
228 m_itemIterator->toFirst();
230 curRow = 0;
231 curCol = 0;
232 }
233 else {//no data
234 if (isInsertingEnabled()) {
236 curRow = 0;
237 curCol = 0;
238 }
239 }
240 }
241 setCursorPosition(curRow, curCol, true/*force*/);
242 }
243 ensureCellVisible(m_curRow, m_curCol);
244// updateRowCountInfo();
245// setNavRowCount(rows());
246
247//OK?
248// updateContents();
250
252
253 /*emit*/ dataRefreshed();
254}
255
257{
258 if (m_isSortingEnabled && !set)
259 setSorting(-1);
260 m_isSortingEnabled = set;
261 /*emit*/ reloadActions();
262}
263
264void KexiDataAwareObjectInterface::setSorting(int col, bool ascending)
265{
266 if (!m_data || !m_isSortingEnabled)
267 return;
268// d->pTopHeader->setSortIndicator(col, ascending ? Ascending : Descending);
269 setLocalSortingOrder(col, ascending ? 1 : -1);
270 m_data->setSorting(col, ascending);
271}
272
274{
276 return m_data->sortedColumn();
277 return -1;
278}
279
281{
282 return m_data ? m_data->sortingOrder() : 0;
283}
284
286{
287 if (!m_data || !m_isSortingEnabled)
288 return false;
289
290 if (rows() < 2)
291 return true;
292
293 if (!acceptRowEdit())
294 return false;
295
296 const int oldRow = m_curRow;
297 if (m_data->sortedColumn()!=-1)
298 m_data->sort();
299
300 //locate current record
301 if (!m_currentItem) {
302 m_itemIterator->toFirst();
303 m_currentItem = **m_itemIterator; //m_data->first();
304 m_curRow = 0;
305 if (!m_currentItem)
306 return true;
307 }
309 m_curRow = m_data->findRef(m_currentItem);
310 int jump = m_curRow - oldRow;
311 if (jump<0)
312 (*m_itemIterator) -= -jump;
313 else
314 (*m_itemIterator) += jump;
315 }
316
317 updateGUIAfterSorting();
318 editorShowFocus( m_curRow, m_curCol );
320 m_verticalHeader->setCurrentRow(m_curRow);
322 m_horizontalHeader->setSelectedSection(m_curCol);
323 if (m_navPanel)
324 m_navPanel->setCurrentRecordNumber(m_curRow+1);
325 return true;
326}
327
329{
330 if (currentColumn()<0)
331 return;
332 sortColumnInternal( currentColumn(), 1 );
333}
334
336{
337 if (currentColumn()<0)
338 return;
339 sortColumnInternal( currentColumn(), -1 );
340}
341
342void KexiDataAwareObjectInterface::sortColumnInternal(int col, int order)
343{
344 //-select sorting
345 bool asc;
346 if (order == 0) {// invert
347 if (col==dataSortedColumn() && dataSortingOrder()==1)
348 asc = dataSortingOrder()==-1; //inverse sorting for this column -> descending order
349 else
350 asc = true;
351 }
352 else
353 asc = (order==1);
354
355 int prevSortOrder = currentLocalSortingOrder();
356 const int prevSortColumn = currentLocalSortingOrder();
357 setSorting( col, asc );
358 //-perform sorting
359 if (!sort())
360 setLocalSortingOrder(prevSortColumn, prevSortOrder); //this will also remove indicator
361 //if prevSortColumn==-1
362 if (col != prevSortColumn)
363 /*emit*/ sortedColumnChanged(col);
364}
365
367{
368 if (isReadOnly())
369 return false;
370 if (m_insertingEnabled == 1 || m_insertingEnabled == 0)
371 return (bool)m_insertingEnabled;
372 if (!hasData())
373 return true;
374 return m_data->isInsertingEnabled();
375}
376
381
383{
384 return (m_deletionPolicy != NoDelete) && !isReadOnly();
385}
386
387void KexiDataAwareObjectInterface::setDeletionPolicy(DeletionPolicy policy)
388{
389 m_deletionPolicy = policy;
390// updateContextMenu();
391}
392
394{
395 if (isReadOnly() == set || (m_data && m_data->isReadOnly() && !set))
396 return; //not allowed!
397 m_readOnly = (set ? 1 : 0);
398 if (set)
399 setInsertingEnabled(false);
401 /*emit*/ reloadActions();
402}
403
405{
406 if (!hasData())
407 return true;
408 if (m_readOnly == 1 || m_readOnly == 0)
409 return (bool)m_readOnly;
410 if (!hasData())
411 return true;
412 return m_data->isReadOnly();
413}
414
416{
417 if (isInsertingEnabled() == set || (m_data && !m_data->isInsertingEnabled() && set))
418 return; //not allowed!
419 m_insertingEnabled = (set ? 1 : 0);
420 m_navPanel->setInsertingEnabled(set);
422 m_verticalHeader->showInsertRow(set);
423 if (set)
424 setReadOnly(false);
425// update();
427 /*emit*/ reloadActions();
428}
429
431{
432 m_spreadSheetMode = true;
433 setSortingEnabled( false );
434 setInsertingEnabled( false );
436 setFilteringEnabled( false );
438 m_navPanelEnabled = false;
439}
440
441void KexiDataAwareObjectInterface::selectNextRow()
442{
443 selectRow( TQMIN( rows() - 1 +(isInsertingEnabled()?1:0), m_curRow + 1 ) );
444}
445
447{
448 selectRow(
449 TQMAX( 0, m_curRow - rowsPerPage() )
450 );
451}
452
454{
455 selectRow(
456 TQMIN(
457 rows() - 1 + (isInsertingEnabled()?1:0),
459 )
460 );
461}
462
463void KexiDataAwareObjectInterface::selectFirstRow()
464{
465 selectRow(0);
466}
467
468void KexiDataAwareObjectInterface::selectLastRow()
469{
470// selectRow(rows() - 1 + (isInsertingEnabled()?1:0));
471 selectRow(rows() - 1);
472}
473
474void KexiDataAwareObjectInterface::selectRow(int row)
475{
476 m_vScrollBarValueChanged_enabled = false; //disable tooltip
477 setCursorPosition(row, -1);
479}
480
481void KexiDataAwareObjectInterface::selectPrevRow()
482{
483 selectRow( TQMAX( 0, m_curRow - 1 ) );
484}
485
487{
488// selectRow( -1 );
489 int oldRow = m_curRow;
490// int oldCol = m_curCol;
491 m_curRow = -1;
492 m_curCol = -1;
493 m_currentItem = 0;
494 updateRow( oldRow );
495 m_navPanel->setCurrentRecordNumber(0);
496// setNavRowNumber(-1);
497}
498
499void KexiDataAwareObjectInterface::setCursorPosition(int row, int col/*=-1*/, bool forceSet)
500{
501 int newrow = row;
502 int newcol = col;
503
504 if(rows() <= 0) {
506 m_verticalHeader->setCurrentRow(-1);
508 m_horizontalHeader->setSelectedSection(-1);
509 if (isInsertingEnabled()) {
511 newrow=0;
512 if (col>=0)
513 newcol=col;
514 else
515 newcol=0;
516 }
517 else {
519 m_curRow=-1;
520 m_curCol=-1;
521 return;
522 }
523 }
524
525 if(col>=0)
526 {
527 newcol = TQMAX(0, col);
528 newcol = TQMIN(columns() - 1, newcol);
529 }
530 else {
531 newcol = m_curCol; //no changes
532 newcol = TQMAX(0, newcol); //may not be < 0 !
533 }
534 newrow = TQMAX(0, row);
535 newrow = TQMIN(rows() - 1 + (isInsertingEnabled()?1:0), newrow);
536
537// d->pCurrentItem = itemAt(d->curRow);
538// kdDebug(44021) << "setCursorPosition(): d->curRow=" << d->curRow << " oldRow=" << oldRow << " d->curCol=" << d->curCol << " oldCol=" << oldCol << endl;
539
540 if ( forceSet || m_curRow != newrow || m_curCol != newcol )
541 {
542 kexidbg << "setCursorPosition(): " <<TQString("old:%1,%2 new:%3,%4").arg(m_curCol)
543 .arg(m_curRow).arg(newcol).arg(newrow) << endl;
544
545 // cursor moved: get rid of editor
546 if (m_editor) {
548 if (!acceptEditor()) {
549 return;
550 }
551 //update row num. again
552 newrow = TQMIN( rows() - 1 + (isInsertingEnabled()?1:0), newrow);
553 }
554 }
556 m_errorMessagePopup->close();
557 }
558
559 if (m_curRow != newrow || forceSet) {//update current row info
560 m_navPanel->setCurrentRecordNumber(newrow+1);
561// setNavRowNumber(newrow);
562// d->navBtnPrev->setEnabled(newrow>0);
563// d->navBtnFirst->setEnabled(newrow>0);
564// d->navBtnNext->setEnabled(newrow<(rows()-1+(isInsertingEnabled()?1:0)));
565// d->navBtnLast->setEnabled(newrow!=(rows()-1));
566 }
567
568 // cursor moved to other row: end of row editing
569 bool newRowInserted = false;
570 if (m_rowEditing && m_curRow != newrow) {
571 newRowInserted = m_newRowEditing;
572 if (!acceptRowEdit()) {
573 //accepting failed: cancel setting the cursor
574 return;
575 }
576 //update row number, because number of rows changed
577 newrow = TQMIN( rows() - 1 + (isInsertingEnabled()?1:0), newrow);
578
579 m_navPanel->setCurrentRecordNumber(newrow+1); //refresh
580 }
581
582 //change position
583 int oldRow = m_curRow;
584 int oldCol = m_curCol;
585 m_curRow = newrow;
586 m_curCol = newcol;
587
588// int cw = columnWidth( d->curCol );
589// int rh = rowHeight();
590// ensureVisible( columnPos( d->curCol ) + cw / 2, rowPos( d->curRow ) + rh / 2, cw / 2, rh / 2 );
591// center(columnPos(d->curCol) + cw / 2, rowPos(d->curRow) + rh / 2, cw / 2, rh / 2);
592// kdDebug(44021) << " contentsY() = "<< contentsY() << endl;
593
594//js if (oldRow > d->curRow)
595//js ensureVisible(columnPos(d->curCol), rowPos(d->curRow) + rh, columnWidth(d->curCol), rh);
596//js else// if (oldRow <= d->curRow)
597//js ensureVisible(columnPos(d->curCol), rowPos(d->curRow), columnWidth(d->curCol), rh);
598
599
600 //show editor-dependent focus, if we're changing the current column
601 if (oldCol>=0 && oldCol<columns() && m_curCol!=oldCol) {
602 //find the editor for this column
603 KexiDataItemInterface *edit = editor( oldCol );
604 if (edit) {
605 edit->hideFocus();
606 }
607 }
608
609 // position changed, so subsequent searching should be started from scratch
610 // (e.g. from the current cell or the top-left cell)
611 m_positionOfRecentlyFoundValue.exists = false;
612
613 //show editor-dependent focus, if needed
614 editorShowFocus( m_curRow, m_curCol );
615
617 updateRow( oldRow );
618 else
619 updateCell( oldRow, oldCol );
620
621// //quite clever: ensure the cell is visible:
622// ensureCellVisible(m_curRow, m_curCol);
623
624// TQPoint pcenter = TQRect( columnPos(d->curCol), rowPos(d->curRow), columnWidth(d->curCol), rh).center();
625// ensureVisible(pcenter.x(), pcenter.y(), columnWidth(d->curCol)/2, rh/2);
626
627// ensureVisible(columnPos(d->curCol), rowPos(d->curRow) - contentsY(), columnWidth(d->curCol), rh);
628 if (m_verticalHeader && (oldRow != m_curRow || forceSet))
629 m_verticalHeader->setCurrentRow(m_curRow);
630
633 else
634 updateCell( m_curRow, m_curCol );
635
636 if (m_curCol != oldCol || m_curRow != oldRow || forceSet) {//ensure this is also refreshed
637 if (!m_updateEntireRowWhenMovingToOtherRow) //only if entire row has not been updated
638 updateCell( oldRow, m_curCol );
639 }
640 //update row
641 if (forceSet || m_curRow != oldRow) {
642 if (isInsertingEnabled() && m_curRow == rows()) {
643 kdDebug(44021) << "NOW insert item is current" << endl;
645 }
646 else {
647 kdDebug(44021) << TQString("NOW item at %1 (%2) is current")
648 .arg(m_curRow).arg((ulong)itemAt(m_curRow)) << endl;
649 //NOT EFFECTIVE!!!!!!!!!!!
650 //set item iterator
651 if (!newRowInserted && isInsertingEnabled() && m_currentItem == m_insertItem && m_curRow == (rows()-1)) {
652 //moving from 'insert item' to last item
653 m_itemIterator->toLast();
654 }
655 else if (!newRowInserted && !forceSet && m_currentItem != m_insertItem && 0==m_curRow)
656 m_itemIterator->toFirst();
657 else if (!newRowInserted && !forceSet && m_currentItem != m_insertItem && oldRow>=0 && (oldRow+1)==m_curRow) //just move next
658 ++(*m_itemIterator);
659 else if (!newRowInserted && !forceSet && m_currentItem != m_insertItem && oldRow>=0 && (oldRow-1)==m_curRow) //just move back
660 --(*m_itemIterator);
661 else { //move at:
662 m_itemIterator->toFirst();
663 (*m_itemIterator)+=m_curRow;
664 }
665 if (!**m_itemIterator) { //sanity
666 m_itemIterator->toFirst();
667 (*m_itemIterator)+=m_curRow;
668 }
670 //itemAt(m_curRow);
671 }
672 }
673
674 //quite clever: ensure the cell is visible:
675 ensureCellVisible(m_curRow, m_curCol);
676
677 if (m_horizontalHeader && (oldCol != m_curCol || forceSet))
678 m_horizontalHeader->setSelectedSection(m_curCol);
679
680 /*emit*/ itemSelected(m_currentItem);
681 /*emit*/ cellSelected(m_curCol, m_curRow);
682 /* only needed for forms */
684 }
685 else {
686 kexidbg << "setCursorPosition(): NO CHANGE" << endl;
687 }
688
691 }
692}
693
695{
696 if (!m_rowEditing || /*sanity*/!m_data->rowEditBuffer())
697 return true;
699 m_internal_acceptsRowEditAfterCellAccepting = true;
700 return true;
701 }
702 m_internal_acceptsRowEditAfterCellAccepting = false;
703
704 const int columnEditedBeforeAccepting = m_editor ? currentColumn() : -1;
705 if (!acceptEditor())
706 return false;
707 kdDebug() << "EDIT ROW ACCEPTING..." << endl;
708
709 bool success = true;
710// bool allow = true;
711// int faultyColumn = -1; // will be !=-1 if cursor has to be moved to that column
712 const bool inserting = m_newRowEditing;
713// TQString msg, desc;
714// bool inserting = d->pInsertItem && d->pInsertItem==d->pCurrentItem;
715
716 if (m_data->rowEditBuffer()->isEmpty() && !m_newRowEditing) {
717/* if (d->newRowEditing) {
718 cancelRowEdit();
719 kdDebug() << "-- NOTHING TO INSERT!!!" << endl;
720 return true;
721 }
722 else {*/
723 kdDebug() << "-- NOTHING TO ACCEPT!!!" << endl;
724// }
725 }
726 else {//not empty edit buffer or new row to insert:
727 if (m_newRowEditing) {
728// emit aboutToInsertRow(d->pCurrentItem, m_data->rowEditBuffer(), success, &faultyColumn);
729// if (success) {
730 kdDebug() << "-- INSERTING: " << endl;
731 m_data->rowEditBuffer()->debug();
732 success = m_data->saveNewRow(*m_currentItem);
733// if (!success) {
734// }
735// }
736 }
737 else {
738// emit aboutToUpdateRow(d->pCurrentItem, m_data->rowEditBuffer(), success, &faultyColumn);
739 if (success) {
740 //accept changes for this row:
741 kdDebug() << "-- UPDATING: " << endl;
742 m_data->rowEditBuffer()->debug();
743 kdDebug() << "-- BEFORE: " << endl;
744 m_currentItem->debug();
745 success = m_data->saveRowChanges(*m_currentItem);//, &msg, &desc, &faultyColumn);
746 kdDebug() << "-- AFTER: " << endl;
747 m_currentItem->debug();
748
749// if (!success) {
750// }
751 }
752 }
753 }
754
755 if (success) {
756 //editing is finished:
757 if (m_newRowEditing) {
758 //update current-item-iterator
759 m_itemIterator->toLast();
761 }
762 m_rowEditing = false;
763 m_newRowEditing = false;
764 //indicate on the vheader that we are not editing
766 m_verticalHeader->setEditRow(-1);
767
768 updateAfterAcceptRowEdit();
769
770 kdDebug() << "EDIT ROW ACCEPTED:" << endl;
771// /*debug*/itemAt(m_curRow);
772
773 if (inserting) {
774// emit rowInserted(d->pCurrentItem);
775 //update navigator's data
776 m_navPanel->setRecordCount(rows());
777 }
778 else {
779// emit rowUpdated(d->pCurrentItem);
780 }
781
782 /*emit*/ rowEditTerminated(m_curRow);
783 }
784 else {
785// if (!allow) {
786// kdDebug() << "INSERT/EDIT ROW - DISALLOWED by signal!" << endl;
787// }
788// else {
789// kdDebug() << "EDIT ROW - ERROR!" << endl;
790// }
791 int faultyColumn = -1;
792 if (m_data->result()->column >= 0 && m_data->result()->column < columns())
793 faultyColumn = m_data->result()->column;
794 else if (columnEditedBeforeAccepting >= 0)
795 faultyColumn = columnEditedBeforeAccepting;
796 if (faultyColumn >= 0) {
797 setCursorPosition(m_curRow, faultyColumn);
798 }
799
800 const int button = showErrorMessageForResult( m_data->result() );
801 if (KMessageBox::No == button) {
802 //discard changes
804 }
805 else {
806 if (faultyColumn >= 0) {
807 //edit this cell
809 }
810 }
811 }
812
813 return success;
814}
815
817{
818 if (!hasData())
819 return false;
820 if (!m_rowEditing)
821 return false;
822 cancelEditor();
823 m_rowEditing = false;
824 //indicate on the vheader that we are not editing
826 m_verticalHeader->setEditRow(-1);
828 if (m_newRowEditing) {
829 m_newRowEditing = false;
830 //remove current edited row (it is @ the end of list)
831 m_data->removeLast();
832 //current item is now empty, last row
834 //update visibility
836 m_verticalHeader->removeLabel(false); //-1 label
837// updateContents(columnPos(0), rowPos(rows()),
838// viewport()->width(), d->rowHeight*3 + (m_navPanel ? m_navPanel->height() : 0)*3 );
839// updateContents(); //js: above did not work well so we do that dirty
841//TODO: still doesn't repaint properly!!
842// TQSize s(tableSize());
843// resizeContents(s.width(), s.height());
845// m_verticalHeader->update();
846 //--no cancel action is needed for datasource,
847 // because the row was not yet stored.
848 }
849
850 m_data->clearRowEditBuffer();
851 updateAfterCancelRowEdit();
852
854 kexidbg << "EDIT ROW CANCELLED." << endl;
855
856 /*emit*/ rowEditTerminated(m_curRow);
857 return true;
858}
859
860void KexiDataAwareObjectInterface::updateAfterCancelRowEdit()
861{
865 m_alsoUpdateNextRow = false;
866}
867
868void KexiDataAwareObjectInterface::updateAfterAcceptRowEdit()
869{
871}
872
873void KexiDataAwareObjectInterface::removeEditor()
874{
875 if (!m_editor)
876 return;
877 m_editor->hideWidget();
878 m_editor = 0;
879}
880
882{
884 m_errorMessagePopup->close();
885 }
886 if (!m_editor)
887 return false;
888 removeEditor();
889 return true;
890}
891
893class KexiDataAwareObjectInterfaceToolTip : public TQToolTip {
894 public:
895 KexiDataAwareObjectInterfaceToolTip( const TQString & text, const TQPoint & pos, TQWidget * widget )
896 : TQToolTip(widget), m_text(text)
897 {
898 tip( TQRect(pos, TQSize(100, 100)), text );
899 }
900 virtual void maybeTip(const TQPoint & p) {
901 tip( TQRect(p, TQSize(100, 100)), m_text);
902 }
903 TQString m_text;
904};
905
907{
908 if (!hasData())
909 return true;
910 if (!m_editor || m_inside_acceptEditor)
911 return true;
912
913 m_inside_acceptEditor = true;//avoid recursion
914
915 TQVariant newval;
916 Validator::Result res = Validator::Ok;
917 TQString msg, desc;
918 bool setNull = false;
919// bool allow = true;
920// static const TQString msg_NOT_NULL = i18n("\"%1\" column requires a value to be entered.");
921
922 //autoincremented field can be omitted (left as null or empty) if we're inserting a new row
923 const bool autoIncColumnCanBeOmitted = m_newRowEditing && m_editor->field()->isAutoIncrement();
924// const bool autoIncColumnCanBeOmitted = m_newRowEditing && m_editor->columnInfo()->field->isAutoIncrement();
925
926 bool valueChanged = m_editor->valueChanged();
927 bool editCurrentCellAgain = false;
928
929 if (valueChanged) {
930 if (!m_editor->valueIsValid()) {
931 //used e.g. for date or time values - the value can be null but not necessary invalid
932 res = Validator::Error;
933 editCurrentCellAgain = true;
934 TQWidget *par = dynamic_cast<TQScrollView*>(this) ? dynamic_cast<TQScrollView*>(this)->viewport() :
935 dynamic_cast<TQWidget*>(this);
936 TQWidget *edit = dynamic_cast<TQWidget*>(m_editor);
937 if (par && edit) {
940 if (!m_errorMessagePopup) {
941// m_errorMessagePopup->close();
943 i18n("Error: %1").arg(m_editor->columnInfo()->field->typeName())+"?",
944 dynamic_cast<TQWidget*>(this));
945 m_errorMessagePopup->move(
946 par->mapToGlobal(edit->pos()) + TQPoint(6, edit->height() + 0) );
947 m_errorMessagePopup->show();
948 }
949 m_editor->setFocus();
950 }
951 }
952 else if (m_editor->valueIsNull()) {//null value entered
953// if (m_editor->columnInfo()->field->isNotNull() && !autoIncColumnCanBeOmitted) {
954 if (m_editor->field()->isNotNull() && !autoIncColumnCanBeOmitted) {
955 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NULL NOT ALLOWED!" << endl;
956 res = Validator::Error;
957// msg = Validator::msgColumnNotEmpty().arg(m_editor->columnInfo()->field->captionOrName())
958 msg = Validator::msgColumnNotEmpty().arg(m_editor->field()->captionOrName())
959 + "\n\n" + Kexi::msgYouCanImproveData();
960 desc = i18n("The column's constraint is declared as NOT NULL.");
961 editCurrentCellAgain = true;
962 // allow = false;
963 // removeEditor();
964 // return true;
965 }
966 else {
967 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NULL VALUE WILL BE SET" << endl;
968 //ok, just leave newval as NULL
969 setNull = true;
970 }
971 }
972 else if (m_editor->valueIsEmpty()) {//empty value entered
973// if (m_editor->columnInfo()->field->hasEmptyProperty()) {
974 if (m_editor->field()->hasEmptyProperty()) {
975// if (m_editor->columnInfo()->field->isNotEmpty() && !autoIncColumnCanBeOmitted) {
976 if (m_editor->field()->isNotEmpty() && !autoIncColumnCanBeOmitted) {
977 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): EMPTY NOT ALLOWED!" << endl;
978 res = Validator::Error;
979// msg = Validator::msgColumnNotEmpty().arg(m_editor->columnInfo()->field->captionOrName())
980 msg = Validator::msgColumnNotEmpty().arg(m_editor->field()->captionOrName())
981 + "\n\n" + Kexi::msgYouCanImproveData();
982 desc = i18n("The column's constraint is declared as NOT EMPTY.");
983 editCurrentCellAgain = true;
984 // allow = false;
985 // removeEditor();
986 // return true;
987 }
988 else {
989 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): EMPTY VALUE WILL BE SET" << endl;
990 }
991 }
992 else {
993// if (m_editor->columnInfo()->field->isNotNull() && !autoIncColumnCanBeOmitted) {
994 if (m_editor->field()->isNotNull() && !autoIncColumnCanBeOmitted) {
995 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NEITHER NULL NOR EMPTY VALUE CAN BE SET!" << endl;
996 res = Validator::Error;
997// msg = Validator::msgColumnNotEmpty().arg(m_editor->columnInfo()->field->captionOrName())
998 msg = Validator::msgColumnNotEmpty().arg(m_editor->field()->captionOrName())
999 + "\n\n" + Kexi::msgYouCanImproveData();
1000 desc = i18n("The column's constraint is declared as NOT EMPTY and NOT NULL.");
1001 editCurrentCellAgain = true;
1002// allow = false;
1003 // removeEditor();
1004 // return true;
1005 }
1006 else {
1007 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): NULL VALUE WILL BE SET BECAUSE EMPTY IS NOT ALLOWED" << endl;
1008 //ok, just leave newval as NULL
1009 setNull = true;
1010 }
1011 }
1012 }
1013 }//changed
1014
1015 const int realFieldNumber = fieldNumberForColumn(m_curCol);
1016 if (realFieldNumber < 0) {
1017 kdWarning() << "KexiDataAwareObjectInterface::acceptEditor(): fieldNumberForColumn(m_curCol) < 0" << endl;
1018 m_inside_acceptEditor = false;
1019 return false;
1020 }
1021
1022 KexiTableViewColumn *currentTVColumn = column(m_curCol);
1023
1024 //try to get the value entered:
1025 if (res == Validator::Ok) {
1026 if ((!setNull && !valueChanged)
1027 || (m_editor->field()->type()!=KexiDB::Field::Boolean && setNull && m_currentItem->at( realFieldNumber ).isNull())) {
1028 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): VALUE NOT CHANGED." << endl;
1029 removeEditor();
1030 if (m_acceptsRowEditAfterCellAccepting || m_internal_acceptsRowEditAfterCellAccepting)
1031 acceptRowEdit();
1032 m_inside_acceptEditor = false;
1033 return true;
1034 }
1035 if (!setNull) {//get the new value
1036// bool ok;
1037 newval = m_editor->value();
1039/*
1040 if (!ok) {
1041 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): INVALID VALUE - NOT CHANGED." << endl;
1042 res = KexiValidator::Error;
1043//js: TODO get detailed info on why m_editor->value() failed
1044 msg = i18n("Entered value is invalid.")
1045 + "\n\n" + KexiValidator::msgYouCanImproveData();
1046 editCurrentCellAgain = true;
1047// removeEditor();
1048// return true;
1049 }*/
1050 }
1051
1052 //Check other validation rules:
1053 //1. check using validator
1054// KexiValidator *validator = m_data->column(m_curCol)->validator();
1055 Validator *validator = currentTVColumn->validator();
1056 if (validator) {
1057// res = validator->check(m_data->column(m_curCol)->field()->captionOrName(),
1058 res = validator->check(currentTVColumn->field()->captionOrName(),
1059 newval, msg, desc);
1060 }
1061 }
1062
1063 //show the validation result if not OK:
1064 if (res == Validator::Error) {
1065 if (!msg.isEmpty()) {
1066 if (desc.isEmpty())
1067 KMessageBox::sorry(dynamic_cast<TQWidget*>(this), msg);
1068 else
1069 KMessageBox::detailedSorry(dynamic_cast<TQWidget*>(this), msg, desc);
1070 }
1071 editCurrentCellAgain = true;
1072// allow = false;
1073 }
1074 else if (res == Validator::Warning) {
1075 //js: todo: message!!!
1076 KMessageBox::messageBox(dynamic_cast<TQWidget*>(this), KMessageBox::Sorry, msg + "\n" + desc);
1077 editCurrentCellAgain = true;
1078 }
1079
1080 if (res == Validator::Ok) {
1081 //2. check using signal
1082 //bool allow = true;
1083// emit aboutToChangeCell(d->pCurrentItem, newval, allow);
1084// if (allow) {
1085 //send changes to the backend
1086 TQVariant visibleValue;
1087 if (!newval.isNull()/* visible value should be null if value is null */
1088 && currentTVColumn->visibleLookupColumnInfo)
1089 {
1090 visibleValue = m_editor->visibleValue(); //visible value for lookup field
1091 }
1092 //should be also added to the buffer
1093 if (m_data->updateRowEditBufferRef(m_currentItem, m_curCol, currentTVColumn,
1094 newval, /*allowSignals*/true, currentTVColumn->visibleLookupColumnInfo ? &visibleValue : 0))
1095 {
1096 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): ------ EDIT BUFFER CHANGED TO:" << endl;
1097 m_data->rowEditBuffer()->debug();
1098 } else {
1099 kdDebug() << "KexiDataAwareObjectInterface::acceptEditor(): ------ CHANGE FAILED in KexiDataAwareObjectInterface::updateRowEditBuffer()" << endl;
1100 res = Validator::Error;
1101
1102 //now: there might be called cancelEditor() in updateRowEditBuffer() handler,
1103 //if this is true, d->pEditor is NULL.
1104
1105 if (m_editor && m_data->result()->column>=0 && m_data->result()->column<columns()) {
1106 //move to faulty column (if m_editor is not cleared)
1107 setCursorPosition(m_curRow, m_data->result()->column);
1108 }
1109 if (!m_data->result()->msg.isEmpty()) {
1110 const int button = showErrorMessageForResult( m_data->result() );
1111 if (KMessageBox::No == button) {
1112 //discard changes
1113 cancelEditor();
1115 cancelRowEdit();
1116 m_inside_acceptEditor = false;
1117 return false;
1118 }
1119 }
1120 }
1121 }
1122
1123 if (res == Validator::Ok) {
1124 removeEditor();
1125 /*emit*/ itemChanged(m_currentItem, m_curRow, m_curCol,
1126 m_currentItem->at( realFieldNumber ));
1127 /*emit*/ itemChanged(m_currentItem, m_curRow, m_curCol);
1128 }
1129 m_inside_acceptEditor = false;
1130 if (res == Validator::Ok) {
1131 if (m_acceptsRowEditAfterCellAccepting || m_internal_acceptsRowEditAfterCellAccepting)
1132 acceptRowEdit();
1133 return true;
1134 }
1135 if (m_editor) {
1136 //allow to edit the cell again, (if m_pEditor is not cleared)
1137
1138 if (m_editor->hasFocusableWidget()) {
1139 m_editor->showWidget();
1140 m_editor->setFocus();
1141 }
1142// startEditCurrentCell(newval.type()==TQVariant::String ? newval.toString() : TQString());
1143// m_editor->setFocus();
1144 }
1145 return false;
1146}
1147
1149{
1150 kdDebug() << "** KexiDataAwareObjectInterface::startEditCurrentCell("<<setText<<")"<<endl;
1151// if (columnType(d->curCol) == KexiDB::Field::Boolean)
1152// return;
1153 if (isReadOnly() || !columnEditable(m_curCol))
1154 return;
1155 if (m_editor) {
1156 if (m_editor->hasFocusableWidget()) {
1157 m_editor->showWidget();
1158 m_editor->setFocus();
1159 }
1160 }
1161// ensureVisible(columnPos(m_curCol), rowPos(m_curRow)+rowHeight(),
1162// columnWidth(m_curCol), rowHeight());
1163//OK?
1164 //ensureCellVisible(m_curRow+1, m_curCol);
1165 if (!m_editor)
1166 createEditor(m_curRow, m_curCol, setText, !setText.isEmpty());
1167}
1168
1170{
1171 if (isReadOnly() || !columnEditable(m_curCol))
1172 return;
1173 if (m_editor) {//if we've editor - just clear it
1174 m_editor->clear();
1175 return;
1176 }
1177//js if (columnType(m_curCol) == KexiDB::Field::Boolean)
1178//js return;
1179// ensureVisible(columnPos(m_curCol), rowPos(m_curRow) + rowHeight(),
1180// columnWidth(m_curCol), rowHeight());
1181//OK?
1182 ensureCellVisible(m_curRow+1, m_curCol);
1183 createEditor(m_curRow, m_curCol, TQString(), false/*removeOld*/);
1184 if (!m_editor)
1185 return;
1186 m_editor->clear();
1187 if (m_editor->acceptEditorAfterDeleteContents())
1188 acceptEditor();
1189 if (!m_editor || !m_editor->hasFocusableWidget())
1190 updateCell(m_curRow, m_curCol);
1191}
1192
1194{
1195 if (m_newRowEditing) {//we're editing fresh new row: just cancel this!
1196 cancelRowEdit();
1197 return;
1198 }
1199
1200 if (!acceptRowEdit())
1201 return;
1202
1204 return;
1205 switch (m_deletionPolicy) {
1206 case NoDelete:
1207 return;
1208 case ImmediateDelete:
1209 break;
1210 case AskDelete:
1211 if (KMessageBox::Cancel == KMessageBox::warningContinueCancel(dynamic_cast<TQWidget*>(this),
1212 i18n("Do you want to delete selected row?"), 0,
1213 KGuiItem(i18n("&Delete Row"),"edit-delete"),
1214 "dontAskBeforeDeleteRow"/*config entry*/,
1215 KMessageBox::Notify|KMessageBox::Dangerous))
1216 return;
1217 break;
1218 case SignalDelete:
1219 /*emit*/ itemDeleteRequest(m_currentItem, m_curRow, m_curCol);
1220 /*emit*/ currentItemDeleteRequest();
1221 return;
1222 default:
1223 return;
1224 }
1225
1226 if (!deleteItem(m_currentItem)) {//nothing
1227 }
1228}
1229
1231{
1233 || (row!=-1 && row >= ((int)rows()+(isInsertingEnabled()?1:0) ) ) )
1234 return 0;
1235
1236 KexiTableItem *newItem = m_data->createItem(); //new KexiTableItem(m_data->columns.count());
1237 insertItem(newItem, row);
1238 return newItem;
1239}
1240
1241void KexiDataAwareObjectInterface::insertItem(KexiTableItem *newItem, int row)
1242{
1243 const bool changeCurrentRow = row==-1 || row==m_curRow;
1244 if (changeCurrentRow) {
1245 //change current row
1246 row = (m_curRow >= 0 ? m_curRow : 0);
1247 m_currentItem = newItem;
1248 m_curRow = row;
1249 }
1250 else if (m_curRow >= row) {
1251 m_curRow++;
1252 }
1253
1254 m_data->insertRow(*newItem, row, true /*repaint*/);
1255
1256 if (changeCurrentRow) {
1257 //update iter...
1258 m_itemIterator->toFirst();
1259 (*m_itemIterator)+=m_curRow;
1260 }
1261/*
1262 TQSize s(tableSize());
1263 resizeContents(s.width(),s.height());
1264
1265 //redraw only this row and below:
1266 int leftcol = d->pTopHeader->sectionAt( d->pTopHeader->offset() );
1267// updateContents( columnPos( leftcol ), rowPos(d->curRow),
1268// clipper()->width(), clipper()->height() - (rowPos(d->curRow) - contentsY()) );
1269 updateContents( columnPos( leftcol ), rowPos(row),
1270 clipper()->width(), clipper()->height() - (rowPos(row) - contentsY()) );
1271
1272 m_verticalHeader->addLabel();
1273
1274 //update navigator's data
1275 setNavRowCount(rows());
1276
1277 if (d->curRow >= row) {
1278 //update
1279 editorShowFocus( d->curRow, d->curCol );
1280 }
1281 */
1282}
1283
1284void KexiDataAwareObjectInterface::slotRowInserted(KexiTableItem *item, bool repaint)
1285{
1286 int row = m_data->findRef(item);
1287 slotRowInserted( item, row, repaint );
1288}
1289
1290void KexiDataAwareObjectInterface::slotRowInserted(KexiTableItem * /*item*/, uint row, bool repaint)
1291{
1292 if (repaint && (int)row<rows()) {
1294
1295/* updateAllVisibleRowsBelow() used instead
1296 //redraw only this row and below:
1297 int leftcol = d->pTopHeader->sectionAt( d->pTopHeader->offset() );
1298 updateContents( columnPos( leftcol ), rowPos(row),
1299 clipper()->width(), clipper()->height() - (rowPos(row) - contentsY()) );
1300*/
1302
1304 if (m_verticalHeader)
1305 m_verticalHeader->addLabel();
1306 }
1307 else //it was added because this inserting was interactive
1309
1310 //update navigator's data
1311 m_navPanel->setRecordCount(rows());
1312
1313 if (m_curRow >= (int)row) {
1314 //update
1315 editorShowFocus( m_curRow, m_curCol );
1316 }
1317 }
1318}
1319
1321{
1322 if (!hasData())
1323 return true;
1324 if (m_data->count()<1)
1325 return true;
1326
1327 if (ask) {
1328 TQString tableName = m_data->dbTableName();
1329 if (!tableName.isEmpty()) {
1330 tableName.prepend(" \"");
1331 tableName.append("\"");
1332 }
1333 if (KMessageBox::Cancel == KMessageBox::warningContinueCancel(dynamic_cast<TQWidget*>(this),
1334 i18n("Do you want to clear the contents of table %1?").arg(tableName),
1335 0, KGuiItem(i18n("&Clear Contents")) ))
1336 return cancelled;
1337 }
1338
1339 cancelRowEdit();
1340// acceptRowEdit();
1341// m_verticalHeader->clear();
1342 const bool repaintLater = repaint && m_spreadSheetMode;
1343 const int oldRows = rows();
1344
1345 bool res = m_data->deleteAllRows(repaint && !repaintLater);
1346
1347 if (res) {
1348 if (m_spreadSheetMode) {
1349// const uint columns = m_data->columns.count();
1350 for (int i=0; i<oldRows; i++) {
1351 m_data->append(m_data->createItem());//new KexiTableItem(columns));
1352 }
1353 }
1354 }
1355 if (repaintLater)
1356 m_data->reload();
1357
1358// d->clearVariables();
1359// m_verticalHeader->setCurrentRow(-1);
1360
1361// d->pUpdateTimer->start(1,true);
1362// if (repaint)
1363// viewport()->repaint();
1364 return res;
1365}
1366
1368{
1369 cancelRowEdit();
1370 m_data->clearInternal();
1371
1372 clearColumnsInternal(repaint);
1374
1375 if (repaint)
1376// viewport()->repaint();
1377//OK?
1379
1380/* for(int i=0; i < rows(); i++)
1381 {
1382 m_verticalHeader->removeLabel();
1383 }
1384
1385 editorCancel();
1386 m_contents->clear();
1387
1388 d->clearVariables();
1389 d->numCols = 0;
1390
1391 while(d->pTopHeader->count()>0)
1392 d->pTopHeader->removeLabel(0);
1393
1394 m_verticalHeader->setCurrentRow(-1);
1395
1396 viewport()->repaint();
1397
1398// d->pColumnTypes.resize(0);
1399// d->pColumnModes.resize(0);
1400// d->pColumnDefaults.clear();*/
1401}
1402
1404{
1405// cancelRowEdit();
1406 acceptRowEdit();
1407 if (m_verticalHeader)
1408 m_verticalHeader->clear();
1409
1410 if (m_curCol>=0 && m_curCol<columns()) {
1411 //find the editor for this column
1412 KexiDataItemInterface *edit = editor( m_curCol );
1413 if (edit) {
1414 edit->hideFocus();
1415 }
1416 }
1417// setCursorPosition(-1, -1, true);
1419 if (m_verticalHeader)
1420 m_verticalHeader->setCurrentRow(-1);
1421
1422 if (dynamic_cast<TQWidget*>(this) && dynamic_cast<TQWidget*>(this)->isVisible())
1424 else
1426
1427 if (m_verticalHeader)
1428 m_verticalHeader->addLabels(m_data->count());
1429
1431}
1432
1434{
1435 KexiTableViewColumn* c = m_data ? column(col) : 0;
1436 return c ? c->field()->type() : KexiDB::Field::InvalidType;
1437}
1438
1440{
1441 KexiTableViewColumn* c = m_data ? column(col) : 0;
1442 return c ? (! c->isReadOnly()) : false;
1443}
1444
1446{
1447 if (!hasData())
1448 return 0;
1449 return m_data->count();
1450}
1451
1453{
1454 if (!hasData())
1455 return 0;
1456 return m_data->columns.count();
1457}
1458
1460{
1461 return TQVariant(0);
1462//TODO(js)
1463// return m_data->columns[col].defaultValue;
1464}
1465
1470
1472{
1473// const bool old = d->dropsAtRowEnabled;
1474 if (!set)
1476 if (m_dropsAtRowEnabled && !set) {
1477 m_dropsAtRowEnabled = false;
1478// update();
1480 }
1481 else {
1482 m_dropsAtRowEnabled = set;
1483 }
1484}
1485
1491
1493 KexiDB::ResultInfo* /*result*/, bool repaint)
1494{
1495 if (repaint) {
1496 m_rowWillBeDeleted = m_data->findRef(&item);
1497 }
1498}
1499
1501{
1502 if (m_rowWillBeDeleted >= 0) {
1504 m_rowWillBeDeleted = rows()-1; //move up if it's the last row
1506
1507 if (! (m_spreadSheetMode && m_rowWillBeDeleted>=(rows()-1)))
1508 setCursorPosition(m_rowWillBeDeleted, m_curCol, true/*forceSet*/);
1509 if (m_verticalHeader)
1510 m_verticalHeader->removeLabel();
1511
1512 updateAllVisibleRowsBelow(m_curRow); //needed for KexiTableView
1513
1514 //update navigator's data
1515 m_navPanel->setRecordCount(rows());
1516
1517 m_rowWillBeDeleted = -1;
1518 }
1519}
1520
1522{
1523 //always return
1524 return true;
1525}
1526
1527bool KexiDataAwareObjectInterface::deleteItem(KexiTableItem *item)/*, bool moveCursor)*/
1528{
1529 if (!item || !beforeDeleteItem(item))
1530 return false;
1531
1532 TQString msg, desc;
1533// bool current = (item == d->pCurrentItem);
1534 const bool lastRowDeleted = m_spreadSheetMode && m_data->last() == item; //we need to know this so we
1535 //can return to the last row
1536 //after reinserting it
1537 if (!m_data->deleteRow(*item, true /*repaint*/)) {
1538 /*const int button =*/
1539 showErrorMessageForResult( m_data->result() );
1540// if (KMessageBox::No == button) {
1541 //discard changes
1542 // }
1543 return false;
1544 }
1545 else {
1546//setCursorPosition() wil lset this! if (current)
1547 //d->pCurrentItem = m_data->current();
1548 }
1549
1550// repaintAfterDelete();
1551 if (m_spreadSheetMode) { //append empty row for spreadsheet mode
1552 m_data->append(m_data->createItem());//new KexiTableItem(m_data->columns.count()));
1553 if (m_verticalHeader)
1554 m_verticalHeader->addLabels(1);
1555 if (lastRowDeleted) //back to the last row
1556 setCursorPosition(rows()-1, m_curCol, true/*forceSet*/);
1558 }
1559 return true;
1560}
1561
1563{
1564 return m_data->column(col);
1565}
1566
1567bool KexiDataAwareObjectInterface::hasDefaultValueAt(const KexiTableViewColumn& tvcol)
1568{
1569 if (m_rowEditing && m_data->rowEditBuffer() && m_data->rowEditBuffer()->isDBAware()) {
1570 return m_data->rowEditBuffer()->hasDefaultValueAt( *tvcol.columnInfo );
1571 }
1572 return false;
1573}
1574
1575const TQVariant* KexiDataAwareObjectInterface::bufferedValueAt(int col, bool useDefaultValueIfPossible)
1576{
1577 if (m_rowEditing && m_data->rowEditBuffer())
1578 {
1579 KexiTableViewColumn* tvcol = column(col);
1580 if (tvcol->isDBAware) {
1581 //get the stored value
1582 const int realFieldNumber = fieldNumberForColumn(col);
1583 if (realFieldNumber < 0) {
1584 kdWarning() << "KexiDataAwareObjectInterface::bufferedValueAt(): "
1585 "fieldNumberForColumn(m_curCol) < 0" << endl;
1586 return 0;
1587 }
1588 TQVariant *storedValue = &m_currentItem->at( realFieldNumber );
1589
1590 //db-aware data: now, try to find a buffered value (or default one)
1591 const TQVariant *cv = m_data->rowEditBuffer()->at( *tvcol->columnInfo,
1592 storedValue->isNull() && useDefaultValueIfPossible);
1593 if (cv)
1594 return cv;
1595 return storedValue;
1596 }
1597 //not db-aware data:
1598 const TQVariant *cv = m_data->rowEditBuffer()->at( tvcol->field()->name() );
1599 if (cv)
1600 return cv;
1601 }
1602 //not db-aware data:
1603 const int realFieldNumber = fieldNumberForColumn(col);
1604 if (realFieldNumber < 0) {
1605 kdWarning() << "KexiDataAwareObjectInterface::bufferedValueAt(): "
1606 "fieldNumberForColumn(m_curCol) < 0" << endl;
1607 return 0;
1608 }
1609 return &m_currentItem->at( realFieldNumber );
1610}
1611
1613{
1614 if ( !isReadOnly() && columnEditable(m_curCol) ) {
1615 if (columnType(m_curCol) == KexiDB::Field::Boolean) {
1616 boolToggled();
1617 }
1618 else {
1620 return;
1621 }
1622 }
1623}
1624
1626{
1628 if (m_editor) {
1629 m_editor->clickedOnContents();
1630 }
1631 acceptEditor();
1632 updateCell(m_curRow, m_curCol);
1633
1634/* int s = m_currentItem->at(m_curCol).toInt();
1635 TQVariant oldValue=m_currentItem->at(m_curCol);
1636 (*m_currentItem)[m_curCol] = TQVariant(s ? 0 : 1);
1637 updateCell(m_curRow, m_curCol);
1638// emit itemChanged(m_currentItem, m_curRow, m_curCol, oldValue);
1639// emit itemChanged(m_currentItem, m_curRow, m_curCol);*/
1640}
1641
1642void KexiDataAwareObjectInterface::slotDataDestroying()
1643{
1644 m_data = 0;
1645 m_itemIterator = 0;
1646}
1647
1648void KexiDataAwareObjectInterface::addNewRecordRequested()
1649{
1650 if (!isInsertingEnabled())
1651 return;
1652 if (m_rowEditing) {
1653 if (!acceptRowEdit())
1654 return;
1655 }
1656// setFocus();
1657 selectRow(rows());
1659 if (m_editor)
1660 m_editor->setFocus();
1661}
1662
1663bool KexiDataAwareObjectInterface::handleKeyPress(TQKeyEvent *e, int &curRow, int &curCol,
1664 bool fullRowSelection, bool *moveToFirstField, bool *moveToLastField)
1665{
1666 if (moveToFirstField)
1667 *moveToFirstField = false;
1668 if (moveToLastField)
1669 *moveToLastField = false;
1670
1671 const bool nobtn = e->state()==TQt::NoButton;
1672 const int k = e->key();
1673 //kdDebug() << "-----------" << e->state() << " " << k << endl;
1674
1675 if ((k == TQt::Key_Up && nobtn) || (k == TQt::Key_PageUp && e->state()==TQt::ControlButton)) {
1676 selectPrevRow();
1677 e->accept();
1678 }
1679 else if ((k == TQt::Key_Down && nobtn) || (k == TQt::Key_PageDown && e->state()==TQt::ControlButton)) {
1680 selectNextRow();
1681 e->accept();
1682 }
1683 else if (k == TQt::Key_PageUp && nobtn) {
1685 e->accept();
1686 }
1687 else if (k == TQt::Key_PageDown && nobtn) {
1689 e->accept();
1690 }
1691 else if (k == TQt::Key_Home) {
1692 if (fullRowSelection) {
1693 //we're in row-selection mode: home key always moves to 1st row
1694 curRow = 0;//to 1st row
1695 }
1696 else {//cell selection mode: different actions depending on ctrl and shift keys state
1697 if (nobtn) {
1698 curCol = 0;//to 1st col
1699 }
1700 else if (e->state()==TQt::ControlButton) {
1701 curRow = 0;//to 1st row and col
1702 curCol = 0;
1703 }
1704 else
1705 return false;
1706 }
1707 if (moveToFirstField)
1708 *moveToFirstField = true;
1709 //do not accept yet
1710 e->ignore();
1711 }
1712 else if (k == TQt::Key_End) {
1713 if (fullRowSelection) {
1714 //we're in row-selection mode: home key always moves to last row
1715 curRow = m_data->count()-1+(isInsertingEnabled()?1:0);//to last row
1716 }
1717 else {//cell selection mode: different actions depending on ctrl and shift keys state
1718 if (nobtn) {
1719 curCol = columns()-1;//to last col
1720 }
1721 else if (e->state()==TQt::ControlButton) {
1722 curRow = m_data->count()-1 /*+(isInsertingEnabled()?1:0)*/; //to last row and col
1723 curCol = columns()-1;//to last col
1724 }
1725 else
1726 return false;
1727 }
1728 if (moveToLastField)
1729 *moveToLastField = true;
1730 //do not accept yet
1731 e->ignore();
1732 }
1733 else if (isInsertingEnabled() && (e->state()==TQt::ControlButton && k == TQt::Key_Equal
1734 || e->state()==(TQt::ControlButton|TQt::ShiftButton) && k == TQt::Key_Equal)) {
1735 curRow = m_data->count(); //to the new row
1736 curCol = 0;//to first col
1737 if (moveToFirstField)
1738 *moveToFirstField = true;
1739 //do not accept yet
1740 e->ignore();
1741 }
1742 else
1743 return false;
1744
1745 return true;
1746}
1747
1749{
1750 Q_UNUSED(v);
1752 return;
1753
1755 const TQRect r( verticalScrollBar()->sliderRect() );
1756 const int row = lastVisibleRow()+1;
1757 if (row<=0) {
1758 m_scrollBarTipTimer.stop();
1759 m_scrollBarTip->hide();
1760 return;
1761 }
1762 m_scrollBarTip->setText( i18n("Row: ") + TQString::number(row) );
1763 m_scrollBarTip->adjustSize();
1764 TQWidget* thisWidget = dynamic_cast<TQWidget*>(this);
1765 m_scrollBarTip->move(
1766 thisWidget->mapToGlobal( r.topLeft() + verticalScrollBar()->pos() )
1767 + TQPoint( - m_scrollBarTip->width()-5,
1768 r.height()/2 - m_scrollBarTip->height()/2) );
1769 if (verticalScrollBar()->draggingSlider()) {
1770 kdDebug(44021) << " draggingSlider() " << endl;
1771 m_scrollBarTipTimer.stop();
1772 m_scrollBarTip->show();
1773 m_scrollBarTip->raise();
1774 }
1775 else {
1777 if (m_scrollBarTipTimerCnt>4) {
1779 m_scrollBarTip->show();
1780 m_scrollBarTip->raise();
1781 m_scrollBarTipTimer.start(500, true);
1782 }
1783 }
1784 }
1785 //update bottom view region
1786/* if (m_navPanel && (contentsHeight() - contentsY() - clipper()->height()) <= TQMAX(d->rowHeight,m_navPanel->height())) {
1787 slotUpdate();
1788 triggerUpdate();
1789 }*/
1790}
1791
1796
1801
1803{
1804 kdDebug(44021) << "vScrollBarSliderReleased()" << endl;
1805 m_scrollBarTip->hide();
1806}
1807
1809{
1810 if (m_scrollBarTip->isVisible()) {
1811// kdDebug(44021) << "TIMEOUT! - hide" << endl;
1812 if (m_scrollBarTipTimerCnt>0) {
1814 m_scrollBarTipTimer.start(500, true);
1815 return;
1816 }
1817 m_scrollBarTip->hide();
1818 }
1820}
1821
1823{
1824 Q_UNUSED(e);
1825 m_scrollBarTipTimer.stop();
1826 m_scrollBarTip->hide();
1827
1828 updateCell(m_curRow, m_curCol);
1829}
1830
1832{
1833 TQWidget *thisWidget = dynamic_cast<TQWidget*>(this);
1834 if (resultInfo->allowToDiscardChanges) {
1835 return KMessageBox::questionYesNo(thisWidget, resultInfo->msg
1836 + (resultInfo->desc.isEmpty() ? TQString() : ("\n"+resultInfo->desc)),
1837 TQString(),
1838 KGuiItem(i18n("Correct Changes", "Correct"), TQString(), i18n("Correct changes")),
1839 KGuiItem(i18n("Discard Changes")) );
1840 }
1841
1842 if (resultInfo->desc.isEmpty())
1843 KMessageBox::sorry(thisWidget, resultInfo->msg);
1844 else
1845 KMessageBox::detailedSorry(thisWidget, resultInfo->msg, resultInfo->desc);
1846
1847 return KMessageBox::Ok;
1848}
1849
1851{
1852 m_indicesForVisibleValues.resize( m_data ? m_data->columnsCount() : 0 );
1853 if (!m_data)
1854 return;
1855 for (uint i=0; i < m_data->columnsCount(); i++) {
1856 KexiTableViewColumn* tvCol = m_data->column(i);
1857 if (tvCol->columnInfo && tvCol->columnInfo->indexForVisibleLookupValue()!=-1)
1858 // retrieve visible value from lookup field
1860 else
1862 }
1863}
1864
1876static inline bool findInString(const TQString& stringValue, int stringLength, const TQString& where,
1877 int& firstCharacter, bool matchAnyPartOfField, bool matchWholeField,
1878 bool caseSensitive, bool wholeWordsOnly, bool forward)
1879{
1880 if (where.isEmpty()) {
1881 firstCharacter = -1;
1882 return false;
1883 }
1884
1885 if (matchAnyPartOfField) {
1886 if (forward) {
1887 int pos = firstCharacter == -1 ? 0 : firstCharacter;
1888 if (wholeWordsOnly) {
1889 const int whereLength = where.length();
1890 while (true) {
1891 pos = where.find( stringValue, pos, caseSensitive );
1892 if (pos == -1)
1893 break;
1894 if ((pos > 0 && where.at(pos-1).isLetterOrNumber())
1895 ||((pos+stringLength-1) < (whereLength-1) && where.at(pos+stringLength-1+1).isLetterOrNumber()))
1896 {
1897 pos++; // invalid match because before or after the string there is non-white space
1898 }
1899 else
1900 break;
1901 }//while
1902 firstCharacter = pos;
1903 }
1904 else {// !wholeWordsOnly
1905 firstCharacter = where.find( stringValue, pos, caseSensitive );
1906 }
1907 return firstCharacter != -1;
1908 }
1909 else { // !matchAnyPartOfField
1910 if (firstCharacter == INT_MAX) {
1911 firstCharacter = -1; //next time we'll be looking at different cell
1912 return false;
1913 }
1914 int pos = firstCharacter;
1915 if (wholeWordsOnly) {
1916 const int whereLength = where.length();
1917 while (true) {
1918 pos = where.findRev( stringValue, pos, caseSensitive );
1919 if (pos == -1)
1920 break;
1921 if ((pos > 0 && where.at(pos-1).isLetterOrNumber())
1922 ||((pos+stringLength-1) < (whereLength-1) && where.at(pos+stringLength-1+1).isLetterOrNumber()))
1923 {
1924 // invalid match because before or after the string there is non-white space
1925 pos--;
1926 if (pos < 0) // it can make pos < 0
1927 break;
1928 }
1929 else
1930 break;
1931 }//while
1932 firstCharacter = pos;
1933 }
1934 else {// !wholeWordsOnly
1935 firstCharacter = where.findRev( stringValue, pos, caseSensitive );
1936 }
1937 return firstCharacter != -1;
1938 }
1939 }
1940 else if (matchWholeField) {
1941 if (firstCharacter != -1 && firstCharacter != 0) { //we're not at 0-th char
1942 firstCharacter = -1;
1943 }
1944 else if ( (caseSensitive ? where : where.lower()) == stringValue) {
1945 firstCharacter = 0;
1946 return true;
1947 }
1948 }
1949 else {// matchStartOfField
1950 if (firstCharacter != -1 && firstCharacter != 0) { //we're not at 0-th char
1951 firstCharacter = -1;
1952 }
1953 else if (where.startsWith(stringValue, caseSensitive)) {
1954 if (wholeWordsOnly) {
1955 // If where.length() < stringValue.length(), true will be returned too - fine.
1956 return !where.at( stringValue.length() ).isLetterOrNumber();
1957 }
1958 firstCharacter = 0;
1959 return true;
1960 }
1961 }
1962 return false;
1963}
1964
1965tristate KexiDataAwareObjectInterface::find(const TQVariant& valueToFind,
1966 const KexiSearchAndReplaceViewInterface::Options& options, bool next)
1967{
1968 if (!hasData())
1969 return cancelled;
1970 const TQVariant prevSearchedValue( m_recentlySearchedValue );
1971 m_recentlySearchedValue = valueToFind;
1973 m_recentSearchDirection = options.searchDirection;
1974 if (valueToFind.isNull() || valueToFind.toString().isEmpty())
1975 return cancelled;
1976
1977 const bool forward = (options.searchDirection == KexiSearchAndReplaceViewInterface::Options::SearchUp)
1978 ? !next : next; //direction can be reversed
1979
1980 if ((!prevSearchedValue.isNull() && prevSearchedValue!=valueToFind)
1981 || (prevSearchDirection!=options.searchDirection && options.searchDirection==KexiSearchAndReplaceViewInterface::Options::SearchAllRows))
1982 {
1983 // restart searching when value has been changed or new direction is SearchAllRows
1984 m_positionOfRecentlyFoundValue.exists = false;
1985 }
1986
1987 const bool startFrom1stRowAndCol = !m_positionOfRecentlyFoundValue.exists && next
1989 const bool startFromLastRowAndCol =
1991 ||(m_curRow >= rows() && !forward); //we're at "insert" row, and searching backwards: move to the last cell
1992
1993 if (!startFrom1stRowAndCol && !startFromLastRowAndCol && m_curRow >= rows()) {
1994 //we're at "insert" row, and searching forward: no chances to find something
1995 return false;
1996 }
1997 KexiTableViewData::Iterator it( (startFrom1stRowAndCol || startFromLastRowAndCol)
1998 ? m_data->iterator() : *m_itemIterator /*start from the current cell*/ );
1999 if (startFromLastRowAndCol)
2000 it.toLast();
2001 int firstCharacter;
2002 if (m_positionOfRecentlyFoundValue.exists) {// start after the next/prev char position
2003 if (forward)
2004 firstCharacter = m_positionOfRecentlyFoundValue.lastCharacter + 1;
2005 else {
2006 firstCharacter = (m_positionOfRecentlyFoundValue.firstCharacter > 0) ?
2007 (m_positionOfRecentlyFoundValue.firstCharacter - 1) : INT_MAX /* this means 'before first'*/;
2008 }
2009 }
2010 else {
2011 firstCharacter = -1; //forward ? -1 : INT_MAX;
2012 }
2013
2014 const int columnsCount = m_data->columnsCount();
2015 int row, col;
2016 if (startFrom1stRowAndCol) {
2017 row = 0;
2018 col = 0;
2019 }
2020 else if (startFromLastRowAndCol) {
2021 row = rows()-1;
2022 col = columnsCount-1;
2023 }
2024 else {
2025 row = m_curRow;
2026 col = m_curCol;
2027 }
2028
2029 //sache some flags for efficiency
2030 const bool matchAnyPartOfField
2032 const bool matchWholeField
2034 const bool caseSensitive = options.caseSensitive;
2035 const bool wholeWordsOnly = options.wholeWordsOnly;
2036//unused const bool promptOnReplace = options.promptOnReplace;
2037 int columnNumber = (options.columnNumber == KexiSearchAndReplaceViewInterface::Options::CurrentColumn)
2038 ? m_curCol : options.columnNumber;
2039 if (columnNumber>=0)
2040 col = columnNumber;
2041 const bool lookInAllColumns = columnNumber == KexiSearchAndReplaceViewInterface::Options::AllColumns;
2042 int firstColumn; // real number of the first column, can be smaller than lastColumn if forward==true
2043 int lastColumn; // real number of the last column
2044 if (lookInAllColumns) {
2045 firstColumn = forward ? 0 : columnsCount-1;
2046 lastColumn = forward ? columnsCount-1 : 0;
2047 }
2048 else {
2049 firstColumn = columnNumber;
2050 lastColumn = columnNumber;
2051 }
2052 const TQString stringValue( caseSensitive ? valueToFind.toString() : valueToFind.toString().lower() );
2053 const int stringLength = stringValue.length();
2054
2055 // search
2056 const int prevRow = m_curRow;
2057 KexiTableItem *item;
2058 while ( (item = it.current()) ) {
2059 for (; forward ? col <= lastColumn : col >= lastColumn;
2060 col = forward ? (col+1) : (col-1))
2061 {
2062 const TQVariant cell( item->at( m_indicesForVisibleValues[ col ] ) );
2063 if (findInString(stringValue, stringLength, cell.toString(), firstCharacter,
2064 matchAnyPartOfField, matchWholeField, caseSensitive, wholeWordsOnly, forward))
2065 {
2066 //*m_itemIterator = it;
2067 //m_currentItem = *it;
2068 //m_curRow = row;
2069 //m_curCol = col;
2070 setCursorPosition(row, col, true/*forceSet*/);
2071 if (prevRow != m_curRow)
2072 updateRow(prevRow);
2073 // remember the exact position for the found value
2074 m_positionOfRecentlyFoundValue.exists = true;
2075 m_positionOfRecentlyFoundValue.firstCharacter = firstCharacter;
2077 m_positionOfRecentlyFoundValue.lastCharacter = firstCharacter + stringLength - 1;
2078 return true;
2079 }
2080 }//for
2081 if (forward) {
2082 ++it;
2083 ++row;
2084 }
2085 else {
2086 --it;
2087 --row;
2088 }
2089 col = firstColumn;
2090 }//while
2091 return false;
2092}
2093
2095 const TQVariant& valueToFind, const TQVariant& replacement,
2096 const KexiSearchAndReplaceViewInterface::Options& options, bool replaceAll)
2097{
2098 Q_UNUSED(replacement);
2099 Q_UNUSED(options);
2100 Q_UNUSED(replaceAll);
2101
2102 if (isReadOnly())
2103 return cancelled;
2104 if (valueToFind.isNull() || valueToFind.toString().isEmpty())
2105 return cancelled;
2107 return false;
2108}
A tooltip-like widget with additional arrow.
Meta-data for a field.
Definition field.h:73
Type type() const
Definition field.cpp:134
@ InvalidType
Definition field.h:84
TQString captionOrName() const
Definition field.h:374
TQString description() const
Definition field.h:377
uint width() const
Definition field.h:381
int indexForVisibleLookupValue() const
Definition queryschema.h:75
TQString desc
error message and detailed description, both empty by default
Definition error.h:131
bool allowToDiscardChanges
Definition error.h:128
bool hasDefaultValueAt(QueryColumnInfo &ci) const
virtual void slotRowInserted(KexiTableItem *item, bool repaint)
Handles KexiTableViewData::rowInserted() signal to repaint when needed.
virtual void updateWidgetContents()=0
bool m_alsoUpdateNextRow
Used by updateAfterCancelRowEdit().
KexiTableViewData * data() const
virtual void setSorting(int col, bool ascending=true)
virtual void setCursorPosition(int row, int col=-1, bool forceSet=false)
virtual tristate find(const TQVariant &valueToFind, const KexiSearchAndReplaceViewInterface::Options &options, bool next)
void insertItem(KexiTableItem *newItem, int row=-1)
KexiTableItem * m_insertItem
item data for inserting
TQLabel * m_scrollBarTip
scrollbar tooltip
virtual void rowEditTerminated(int row)=0
virtual tristate findNextAndReplace(const TQVariant &valueToFind, const TQVariant &replacement, const KexiSearchAndReplaceViewInterface::Options &options, bool replaceAll)
virtual TQScrollBar * verticalScrollBar() const =0
uint m_scrollBarTipTimerCnt
helper for timeout counting (scrollbar tooltip)
virtual void ensureCellVisible(int row, int col)=0
virtual void selectNextPage()
page down action
bool m_rowEditing
when (current or new) row is edited - changed field values are temporary stored here
virtual void clearColumnsInternal(bool repaint)=0
virtual bool handleKeyPress(TQKeyEvent *e, int &curRow, int &curCol, bool fullRowSelection, bool *moveToFirstField=0, bool *moveToLastField=0)
void setData(KexiTableViewData *data, bool owner=true)
virtual void setAcceptsRowEditAfterCellAccepting(bool set)
virtual void updateRow(int row)=0
virtual KexiTableViewColumn * column(int col)
TQGuardedPtr< KexiArrowTip > m_errorMessagePopup
TQTimer m_scrollBarTipTimer
scrollbar tooltip's timer
bool hasData() const
for sanity checks (return true if m_data is present; else: outputs warning)
virtual int lastVisibleRow() const =0
KexiSearchAndReplaceViewInterface::Options::SearchDirection m_recentSearchDirection
KexiTableViewData * m_data
data structure displayed for this object
virtual void slotRowRepaintRequested(KexiTableItem &item)
Handles KexiTableViewData::rowRepaintRequested() signal.
virtual void createEditor(int row, int col, const TQString &addText=TQString(), bool removeOld=false)=0
Creates editors and shows it, what usually means the beginning of a cell editing.
tristate deleteAllRows(bool ask=false, bool repaint=true)
virtual void cellSelected(int col, int row)=0
virtual void updateWidgetContentsSize()=0
virtual void updateAllVisibleRowsBelow(int row)
virtual void slotRowDeleted()
Handles KexiTableViewData::rowDeleted() signal to repaint when needed.
virtual void updateCell(int row, int col)=0
virtual void dataRefreshed()=0
virtual void updateWidgetScrollBars()=0
KexiDataItemInterface * editor() const
virtual void itemChanged(KexiTableItem *, int row, int col)=0
signals
virtual void focusOutEvent(TQFocusEvent *e)
Call this from the subclass. *‍/.
TQValueVector< uint > m_indicesForVisibleValues
Setup by updateIndicesForVisibleValues() and used by find().
TQVariant columnDefaultValue(int col) const
virtual void itemSelected(KexiTableItem *)=0
virtual bool beforeDeleteItem(KexiTableItem *item)
virtual int rowsPerPage() const =0
KexiRecordNavigator * m_navPanel
main navigation widget
virtual void reloadActions()=0
virtual KexiTableItem * insertEmptyRow(int row=-1)
virtual void sortedColumnChanged(int col)=0
KexiTableViewData::Iterator * m_itemIterator
data item's iterator
virtual void startEditCurrentCell(const TQString &setText=TQString())
int showErrorMessageForResult(KexiDB::ResultInfo *resultInfo)
virtual void editorShowFocus(int row, int col)=0
KexiTableItem * m_currentItem
current data item
virtual void newItemAppendedForAfterDeletingInSpreadSheetMode()=0
Emitted for spreadsheet mode when an item was deleted and a new item has been appended.
bool m_owner
true if m_data member is owned by this object
virtual void selectPrevPage()
page up action
virtual void slotAboutToDeleteRow(KexiTableItem &item, KexiDB::ResultInfo *result, bool repaint)
Handles KexiTableViewData::aboutToDeleteRow() signal. Prepares info for slotRowDeleted().
virtual void clearColumns(bool repaint=true)
An interface for declaring widgets to be data-aware.
Specifies options for find and replace operations.
@ MatchAnyPartOfField
Matched text can be any part of field (the default).
@ MatchWholeField
Matched text must be the whole field.
@ SearchAllRows
Search from the first to the last row.
@ SearchUp
Search up (previous) from the current position.
KexiDB::Field * field() const
bool isDBAware
true if data is stored in DB, not only in memeory
KexiUtils::Validator * validator() const
KexiDB::QueryColumnInfo * visibleLookupColumnInfo
KexiDB::QueryColumnInfo * columnInfo
A validator extending TQValidator with offline-checking for value's validity.
Definition validator.h:46
static const TQString msgColumnNotEmpty()
A generic error/warning message.
Definition validator.h:77
Result check(const TQString &valueName, const TQVariant &v, TQString &message, TQString &details)
Definition validator.cpp:34
3-state logical type with three values: true, false and cancelled and convenient operators.
Definition tristate.h:100
General Utils.
Definition identifier.h:27