kexi

kexitableviewdata.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at>
3 Copyright (C) 2003 Daniel Molkentin <molkentin@kde.org>
4 Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this program; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20
21 Original Author: Till Busch <till@bux.at>
22 Original Project: buX (www.bux.at)
23*/
24
25#include "kexitableviewdata.h"
26
27#include <kexiutils/validator.h>
28
29#include <kexidb/field.h>
30#include <kexidb/queryschema.h>
31#include <kexidb/roweditbuffer.h>
32#include <kexidb/cursor.h>
33#include <kexidb/utils.h>
34#include <kexi.h>
35
36#include <kdebug.h>
37#include <tdelocale.h>
38
39#include <tqapplication.h>
40
41unsigned short KexiTableViewData::charTable[]=
42{
43 #include "chartable.txt"
44};
45
47: columnInfo(0)
49, m_field(&f)
50{
51 isDBAware = false;
52 m_fieldOwned = owner;
53 m_captionAliasOrName = m_field->captionOrName();
54 init();
55}
56
58 uint cconst,
59 uint options,
60 uint length, uint precision,
61 TQVariant defaultValue,
62 const TQString& caption, const TQString& description, uint width
63)
64: columnInfo(0)
66{
67 m_field = new KexiDB::Field(
68 name, ctype,
69 cconst,
70 options,
71 length, precision,
72 defaultValue,
73 caption, description, width);
74
75 isDBAware = false;
76 m_fieldOwned = true;
77 m_captionAliasOrName = m_field->captionOrName();
78 init();
79}
80
82 const TQString& caption, const TQString& description)
83: columnInfo(0)
85{
86 m_field = new KexiDB::Field(
87 name, ctype,
88 KexiDB::Field::NoConstraints,
89 KexiDB::Field::NoOptions,
90 0, 0,
91 TQVariant(),
92 caption, description);
93
94 isDBAware = false;
95 m_fieldOwned = true;
96 m_captionAliasOrName = m_field->captionOrName();
97 init();
98}
99
100// db-aware
102 const KexiDB::QuerySchema &query, KexiDB::QueryColumnInfo& aColumnInfo,
103 KexiDB::QueryColumnInfo* aVisibleLookupColumnInfo)
104: columnInfo(&aColumnInfo)
105, visibleLookupColumnInfo(aVisibleLookupColumnInfo)
106, m_field(aColumnInfo.field)
107{
108 isDBAware = true;
109 m_fieldOwned = false;
110
111 //setup column's caption:
112 if (!columnInfo->field->caption().isEmpty()) {
113 m_captionAliasOrName = columnInfo->field->caption();
114 }
115 else {
116 //reuse alias if available:
117 m_captionAliasOrName = columnInfo->alias;
118 //last hance: use field name
119 if (m_captionAliasOrName.isEmpty())
120 m_captionAliasOrName = columnInfo->field->name();
121 //todo: compute other auto-name?
122 }
123 init();
124 //setup column's readonly flag: true, if
125 // - it's not from parent table's field, or
126 // - if the query itself is coming from read-only connection, or
127 // - if the query itself is stored (i.e. has connection) and lookup column is defined
128 const bool columnFromMasterTable = query.masterTable()==columnInfo->field->table();
129 m_readOnly = !columnFromMasterTable
130 || (query.connection() && query.connection()->isReadOnly());
131// || (query.connection() && (query.connection()->isReadOnly() || visibleLookupColumnInfo));
133// kdDebug() << "KexiTableViewColumn: query.masterTable()=="
134// << (query.masterTable() ? query.masterTable()->name() : "notable") << ", columnInfo->field->table()=="
135// << (columnInfo->field->table() ? columnInfo->field->table()->name() : "notable") << endl;
136
137// m_visible = query.isFieldVisible(&f);
138}
139
141: columnInfo(0)
143, m_field(0)
144{
145 isDBAware = false;
146 init();
147}
148
149KexiTableViewColumn::~KexiTableViewColumn()
150{
151 if (m_fieldOwned)
152 delete m_field;
153 setValidator( 0 );
154 delete m_relatedData;
155}
156
157void KexiTableViewColumn::init()
158{
159 m_relatedData = 0;
160 m_readOnly = false;
161 m_visible = true;
162 m_data = 0;
163 m_validator = 0;
164 m_relatedDataEditable = false;
165 m_headerTextVisible = true;
166}
167
169{
170 if (m_validator) {//remove old one
171 if (!m_validator->parent()) //destroy if has no parent
172 delete m_validator;
173 }
174 m_validator = v;
175}
176
177void KexiTableViewColumn::setRelatedData(KexiTableViewData *data)
178{
179 if (isDBAware)
180 return;
181 if (m_relatedData)
182 delete m_relatedData;
183 m_relatedData = 0;
184 if (!data)
185 return;
186 //find a primary key
187 KexiTableViewColumn::ListIterator it( data->columns );
188 for (int id = 0;it.current();++it, id++) {
189 if (it.current()->field()->isPrimaryKey()) {
190 //found, remember
191 m_relatedDataPKeyID = id;
192 m_relatedData = data;
193 return;
194 }
195 }
196}
197
199{
200 m_relatedDataEditable = set;
201}
202
204{
205 return m_readOnly || (m_data && m_data->isReadOnly());
206}
207
208bool KexiTableViewColumn::acceptsFirstChar(const TQChar& ch) const
209{
210 // the field we're looking at can be related to "visible lookup column"
211 // if lookup column is present
213 ? visibleLookupColumnInfo->field : m_field;
214 if (visibleField->isNumericType()) {
215 if (ch=='.' || ch==',')
216 return visibleField->isFPNumericType();
217 if (ch=='-')
218 return !visibleField->isUnsigned();
219 if (ch=='+' || ((int)ch>='0' && (int)ch<='9'))
220 return true;
221 return false;
222 }
223
224 switch (visibleField->type()) {
226 return false;
227 case KexiDB::Field::Date:
228 case KexiDB::Field::DateTime:
229 case KexiDB::Field::Time:
230 return (int)ch>='0' && (int)ch<='9';
231 default:;
232 }
233 return true;
234}
235
236
237//------------------------------------------------------
238
240 : TQObject()
241 , KexiTableViewDataBase()
242{
243 init();
244}
245
246// db-aware ctor
248 : TQObject()
249 , KexiTableViewDataBase()
250{
251 init();
252 m_cursor = c;
253 m_containsROWIDInfo = m_cursor->containsROWIDInfo();
254 if (m_cursor && m_cursor->query()) {
255 const KexiDB::QuerySchema::FieldsExpandedOptions fieldsExpandedOptions
258 m_itemSize = m_cursor->query()->fieldsExpanded( fieldsExpandedOptions ).count();
259 }
260 else
261 m_itemSize = columns.count()+(m_containsROWIDInfo?1:0);
262
263 // Allocate KexiTableViewColumn objects for each visible query column
264 const KexiDB::QueryColumnInfo::Vector fields = m_cursor->query()->fieldsExpanded();
265 const uint fieldsCount = fields.count();
266 for (uint i=0;i < fieldsCount;i++) {
267 KexiDB::QueryColumnInfo *ci = fields[i];
268 if (ci->visible) {
269 KexiDB::QueryColumnInfo *visibleLookupColumnInfo = 0;
270 if (ci->indexForVisibleLookupValue() != -1) {
271 //Lookup field is defined
272 visibleLookupColumnInfo = m_cursor->query()->expandedOrInternalField( ci->indexForVisibleLookupValue() );
273 /* not needed
274 if (visibleLookupColumnInfo) {
275 // 2. Create a KexiTableViewData object for each found lookup field
276 }*/
277 }
278 KexiTableViewColumn* col = new KexiTableViewColumn(*m_cursor->query(), *ci, visibleLookupColumnInfo);
279 addColumn( col );
280 }
281 }
282}
283
285 const TQValueList<TQVariant> &keys, const TQValueList<TQVariant> &values,
286 KexiDB::Field::Type keyType, KexiDB::Field::Type valueType)
287 : TQObject()
288 , KexiTableViewDataBase()
289{
290 init(keys, values, keyType, valueType);
291}
292
294 KexiDB::Field::Type keyType, KexiDB::Field::Type valueType)
295{
296 const TQValueList<TQVariant> empty;
297 init(empty, empty, keyType, valueType);
298}
299
300KexiTableViewData::~KexiTableViewData()
301{
302 emit destroying();
303 clearInternal();
304}
305
306void KexiTableViewData::init(
307 const TQValueList<TQVariant> &keys, const TQValueList<TQVariant> &values,
308 KexiDB::Field::Type keyType, KexiDB::Field::Type valueType)
309{
310 init();
311 KexiDB::Field *keyField = new KexiDB::Field("key", keyType);
312 keyField->setPrimaryKey(true);
313 KexiTableViewColumn *keyColumn = new KexiTableViewColumn(*keyField, true);
314 keyColumn->setVisible(false);
315 addColumn(keyColumn);
316
317 KexiDB::Field *valueField = new KexiDB::Field("value", valueType);
318 KexiTableViewColumn *valueColumn = new KexiTableViewColumn(*valueField, true);
319 addColumn(valueColumn);
320
321 uint cnt = TQMIN(keys.count(), values.count());
322 TQValueList<TQVariant>::ConstIterator it_keys = keys.constBegin();
323 TQValueList<TQVariant>::ConstIterator it_values = values.constBegin();
324 for (;cnt>0;++it_keys, ++it_values, cnt--) {
325 KexiTableItem *item = new KexiTableItem(2);
326 (*item)[0] = (*it_keys);
327 (*item)[1] = (*it_values);
328 append( item );
329 }
330}
331
332void KexiTableViewData::init()
333{
334 m_sortedColumn = 0;
336// m_order = 1;
337 m_order = 0;
338 m_type = 1;
339 m_pRowEditBuffer = 0;
340 m_cursor = 0;
341 m_readOnly = false;
342 m_insertingEnabled = true;
343
344 setAutoDelete(true);
345 columns.setAutoDelete(true);
346 m_visibleColumnsCount=0;
347 m_visibleColumnsIDs.resize(100);
348 m_globalColumnsIDs.resize(100);
349
350 m_autoIncrementedColumn = -2;
351 m_containsROWIDInfo = false;
352 m_itemSize = 0;
353}
354
355void KexiTableViewData::deleteLater()
356{
357 m_cursor = 0;
358 TQObject::deleteLater();
359}
360
362{
363// if (!col->isDBAware) {
364// if (!m_simpleColumnsByName)
365// m_simpleColumnsByName = new TQDict<KexiTableViewColumn>(101);
366// m_simpleColumnsByName->insert(col->caption,col);//for faster lookup
367// }
368 columns.append( col );
369 col->m_data = this;
370 if (m_globalColumnsIDs.size() < columns.count()) {//sanity
371 m_globalColumnsIDs.resize( m_globalColumnsIDs.size()*2 );
372 }
373 if (col->visible()) {
374 m_visibleColumnsCount++;
375 if (m_visibleColumnsIDs.size() < m_visibleColumnsCount) {//sanity
376 m_visibleColumnsIDs.resize( m_visibleColumnsIDs.size()*2 );
377 }
378 m_visibleColumnsIDs[ columns.count()-1 ] = m_visibleColumnsCount-1;
379 m_globalColumnsIDs[ m_visibleColumnsCount-1 ] = columns.count()-1;
380 }
381 else {
382 m_visibleColumnsIDs[ columns.count()-1 ] = -1;
383 }
384 m_autoIncrementedColumn = -2; //clear cache;
385 if (!m_cursor || !m_cursor->query())
386 m_itemSize = columns.count()+(m_containsROWIDInfo?1:0);
387}
388
390{
391 if (m_cursor && m_cursor->query() && m_cursor->query()->masterTable())
392 return m_cursor->query()->masterTable()->name();
393 return TQString();
394}
395
396void KexiTableViewData::setSorting(int column, bool ascending)
397{
398 if (column>=0 && column<(int)columns.count()) {
399 m_order = (ascending ? 1 : -1);
400 }
401 else {
402 m_order = 0;
403 m_sortedColumn = -1;
405 return;
406 }
407 // find proper column information for sorting (lookup column points to alternate column with visible data)
408 const KexiTableViewColumn *tvcol = columns.at(column);
409 KexiDB::QueryColumnInfo* visibleLookupColumnInfo = tvcol->visibleLookupColumnInfo;
410 const KexiDB::Field *field = visibleLookupColumnInfo ? visibleLookupColumnInfo->field : tvcol->field();
411 m_sortedColumn = column;
414
415 // setup compare function
416 const int t = field->type();
417 if (field->isTextType())
418 cmpFunc = &KexiTableViewData::cmpStr;
420 cmpFunc = &KexiTableViewData::cmpDouble;
421 else if (t==KexiDB::Field::BigInteger) {
422 if (field->isUnsigned())
423 cmpFunc = &KexiTableViewData::cmpULongLong;
424 else
425 cmpFunc = &KexiTableViewData::cmpLongLong;
426 }
427 else if (t == KexiDB::Field::Integer && field->isUnsigned())
428 cmpFunc = &KexiTableViewData::cmpUInt;
430 cmpFunc = &KexiTableViewData::cmpInt; //other integers
431 else if (t == KexiDB::Field::Date)
432 cmpFunc = &KexiTableViewData::cmpDate;
433 else if (t == KexiDB::Field::Time)
434 cmpFunc = &KexiTableViewData::cmpTime;
435 else if (t == KexiDB::Field::DateTime)
436 cmpFunc = &KexiTableViewData::cmpDateTime;
437 else if (t == KexiDB::Field::BLOB)
440 else
441 cmpFunc = &KexiTableViewData::cmpStr; //anything else
442}
443
444int KexiTableViewData::compareItems(Item item1, Item item2)
445{
446 return ((this->*cmpFunc) (item1, item2));
447}
448
450#define CMP_NULLS(item1, item2) \
451 m_leftTmp = ((KexiTableItem *)item1)->at(m_realSortedColumn); \
452 if (m_leftTmp.isNull()) \
453 return -m_order; \
454 m_rightTmp = ((KexiTableItem *)item2)->at(m_realSortedColumn); \
455 if (m_rightTmp.isNull()) \
456 return m_order
457
458#define CAST_AND_COMPARE(casting, item1, item2) \
459 CMP_NULLS(item1, item2); \
460 if (m_leftTmp.casting() < m_rightTmp.casting()) \
461 return -m_order; \
462 if (m_leftTmp.casting() > m_rightTmp.casting()) \
463 return m_order; \
464 return 0
465
466int KexiTableViewData::cmpInt(Item item1, Item item2)
467{
468 CAST_AND_COMPARE(toInt, item1, item2);
469}
470
471int KexiTableViewData::cmpUInt(Item item1, Item item2)
472{
473 CAST_AND_COMPARE(toUInt, item1, item2);
474}
475
476int KexiTableViewData::cmpLongLong(Item item1, Item item2)
477{
478 CAST_AND_COMPARE(toLongLong, item1, item2);
479}
480
481int KexiTableViewData::cmpULongLong(Item item1, Item item2)
482{
483 CAST_AND_COMPARE(toULongLong, item1, item2);
484}
485
486int KexiTableViewData::cmpDouble(Item item1, Item item2)
487{
488 CAST_AND_COMPARE(toDouble, item1, item2);
489}
490
491int KexiTableViewData::cmpDate(Item item1, Item item2)
492{
493 CAST_AND_COMPARE(toDate, item1, item2);
494}
495
496int KexiTableViewData::cmpDateTime(Item item1, Item item2)
497{
498 CAST_AND_COMPARE(toDateTime, item1, item2);
499}
500
501int KexiTableViewData::cmpTime(Item item1, Item item2)
502{
503 CAST_AND_COMPARE(toDate, item1, item2);
504}
505
506int KexiTableViewData::cmpStr(Item item1, Item item2)
507{
508 CMP_NULLS(item1, item2);
509 const TQString &as = m_leftTmp.toString();
510 const TQString &bs = m_rightTmp.toString();
511
512 const TQChar *a = as.unicode();
513 const TQChar *b = bs.unicode();
514
515 if ( a == b )
516 return 0;
517 if ( a == 0 )
518 return -1;
519 if ( b == 0 )
520 return 1;
521
522 unsigned short au;
523 unsigned short bu;
524
525 int l=TQMIN(as.length(),bs.length());
526
527 au = a->unicode();
528 bu = b->unicode();
529 au = (au <= 0x17e ? charTable[au] : 0xffff);
530 bu = (bu <= 0x17e ? charTable[bu] : 0xffff);
531
532 while (l-- && au == bu)
533 {
534 a++,b++;
535 au = a->unicode();
536 bu = b->unicode();
537 au = (au <= 0x17e ? charTable[au] : 0xffff);
538 bu = (bu <= 0x17e ? charTable[bu] : 0xffff);
539 }
540
541 if ( l==-1 )
542 return m_order*(as.length()-bs.length());
543
544 return m_order*(au-bu);
545}
546
547int KexiTableViewData::cmpBLOB(Item item1, Item item2)
548{
549 CMP_NULLS(item1, item2);
550 return m_leftTmp.toByteArray().size() - m_rightTmp.toByteArray().size();
551}
552
554{
555 if (m_readOnly == set)
556 return;
557 m_readOnly = set;
558 if (m_readOnly)
559 setInsertingEnabled(false);
560}
561
563{
564 if (m_insertingEnabled == set)
565 return;
566 m_insertingEnabled = set;
567 if (m_insertingEnabled)
568 setReadOnly(false);
569}
570
572{
573 //init row edit buffer
574 if (!m_pRowEditBuffer)
575 m_pRowEditBuffer = new KexiDB::RowEditBuffer(isDBAware());
576 else
577 m_pRowEditBuffer->clear();
578}
579
581 int colnum, KexiTableViewColumn* col, TQVariant& newval, bool allowSignals,
582 TQVariant *visibleValueForLookupField)
583{
584 m_result.clear();
585 if (allowSignals)
586 emit aboutToChangeCell(item, colnum, newval, &m_result);
587 if (!m_result.success)
588 return false;
589
590 kdDebug() << "KexiTableViewData::updateRowEditBufferRef() column #"
591 << colnum << " = " << newval.toString() << endl;
592 if (!col) {
593 kdWarning() << "KexiTableViewData::updateRowEditBufferRef(): column #"
594 << colnum << " not found! col==0" << endl;
595 return false;
596 }
597 if (!m_pRowEditBuffer)
598 m_pRowEditBuffer = new KexiDB::RowEditBuffer(isDBAware());
599 if (m_pRowEditBuffer->isDBAware()) {
600 if (!(col->columnInfo)) {
601 kdWarning() << "KexiTableViewData::updateRowEditBufferRef(): column #"
602 << colnum << " not found!" << endl;
603 return false;
604 }
605 m_pRowEditBuffer->insert( *col->columnInfo, newval);
606
607 if (col->visibleLookupColumnInfo && visibleValueForLookupField) {
608 //this is value for lookup table: update visible value as well
609 m_pRowEditBuffer->insert( *col->visibleLookupColumnInfo, *visibleValueForLookupField);
610 }
611 return true;
612 }
613 if (!(col->field())) {
614 kdDebug() << "KexiTableViewData::updateRowEditBufferRef(): column #" << colnum<<" not found!" << endl;
615 return false;
616 }
617 //not db-aware:
618 const TQString colname = col->field()->name();
619 if (colname.isEmpty()) {
620 kdDebug() << "KexiTableViewData::updateRowEditBufferRef(): column #" << colnum<<" not found!" << endl;
621 return false;
622 }
623 m_pRowEditBuffer->insert(colname, newval);
624 return true;
625}
626
627//get a new value (if present in the buffer), or the old one, otherwise
628//(taken here for optimization)
629#define GET_VALUE if (!val) { \
630 val = m_cursor \
631 ? m_pRowEditBuffer->at( *it_f.current()->columnInfo, true /* useDefaultValueIfPossible */ ) \
632 : m_pRowEditBuffer->at( *f ); \
633 if (!val) \
634 val = &(*it_r); /* get old value */ \
635 }
636
638bool KexiTableViewData::saveRow(KexiTableItem& item, bool insert, bool repaint)
639{
640 if (!m_pRowEditBuffer)
641 return true; //nothing to do
642
643 //check constraints:
644 //-check if every NOT NULL and NOT EMPTY field is filled
645 KexiTableViewColumn::ListIterator it_f(columns);
646 KexiDB::RowData::ConstIterator it_r = item.constBegin();
647 int col = 0;
648 const TQVariant *val;
649 for (;it_f.current() && it_r!=item.constEnd();++it_f,++it_r,col++) {
650 KexiDB::Field *f = it_f.current()->field();
651 val = 0;
652 if (f->isNotNull()) {
653 GET_VALUE;
654 //check it
655 if (val->isNull() && !f->isAutoIncrement()) {
656 //NOT NULL violated
657 m_result.msg = i18n("\"%1\" column requires a value to be entered.")
658 .arg(f->captionOrName()) + "\n\n" + Kexi::msgYouCanImproveData();
659 m_result.desc = i18n("The column's constraint is declared as NOT NULL.");
660 m_result.column = col;
661 return false;
662 }
663 }
664 if (f->isNotEmpty()) {
665 GET_VALUE;
666 if (!f->isAutoIncrement() && (val->isNull() || KexiDB::isEmptyValue( f, *val ))) {
667 //NOT EMPTY violated
668 m_result.msg = i18n("\"%1\" column requires a value to be entered.")
669 .arg(f->captionOrName()) + "\n\n" + Kexi::msgYouCanImproveData();
670 m_result.desc = i18n("The column's constraint is declared as NOT EMPTY.");
671 m_result.column = col;
672 return false;
673 }
674 }
675 }
676
677 if (m_cursor) {//db-aware
678 if (insert) {
679 if (!m_cursor->insertRow( static_cast<KexiDB::RowData&>(item), *m_pRowEditBuffer,
680 m_containsROWIDInfo/*also retrieve ROWID*/ ))
681 {
682 m_result.msg = i18n("Row inserting failed.") + "\n\n"
683 + Kexi::msgYouCanImproveData();
685
686/* if (desc)
687 *desc =
688js: TODO: use KexiMainWindowImpl::showErrorMessage(const TQString &title, KexiDB::Object *obj)
689 after it will be moved somewhere to kexidb (this will require moving other
690 showErrorMessage() methods from KexiMainWindowImpl to libkexiutils....)
691 then: just call: *desc = KexiDB::errorMessage(m_cursor);
692*/
693 return false;
694 }
695 }
696 else { // row updating
697// if (m_containsROWIDInfo)
698// ROWID = item[columns.count()].toULongLong();
699 if (!m_cursor->updateRow( static_cast<KexiDB::RowData&>(item), *m_pRowEditBuffer,
700 m_containsROWIDInfo/*use ROWID*/))
701 {
702 m_result.msg = i18n("Row changing failed.") + "\n\n" + Kexi::msgYouCanImproveData();
704 KexiDB::getHTMLErrorMesage(m_cursor, m_result.desc);
705 return false;
706 }
707 }
708 }
709 else {//not db-aware version
710 KexiDB::RowEditBuffer::SimpleMap b = m_pRowEditBuffer->simpleBuffer();
711 for (KexiDB::RowEditBuffer::SimpleMap::ConstIterator it = b.constBegin();it!=b.constEnd();++it) {
712 uint i=0;
713 for (KexiTableViewColumn::ListIterator it2(columns);it2.current();++it2, i++) {
714 if (it2.current()->field()->name()==it.key()) {
715 kdDebug() << it2.current()->field()->name()<< ": "<<item[i].toString()<<" -> "<<it.data().toString()<<endl;
716 item[i] = it.data();
717 }
718 }
719 }
720 }
721
722 m_pRowEditBuffer->clear();
723
724 if (repaint)
725 emit rowRepaintRequested(item);
726 return true;
727}
728
729bool KexiTableViewData::saveRowChanges(KexiTableItem& item, bool repaint)
730{
731 kdDebug() << "KexiTableViewData::saveRowChanges()..." << endl;
732 m_result.clear();
733 emit aboutToUpdateRow(&item, m_pRowEditBuffer, &m_result);
734 if (!m_result.success)
735 return false;
736
737 if (saveRow(item, false /*update*/, repaint)) {
738 emit rowUpdated(&item);
739 return true;
740 }
741 return false;
742}
743
744bool KexiTableViewData::saveNewRow(KexiTableItem& item, bool repaint)
745{
746 kdDebug() << "KexiTableViewData::saveNewRow()..." << endl;
747 m_result.clear();
748 emit aboutToInsertRow(&item, &m_result, repaint);
749 if (!m_result.success)
750 return false;
751
752 if (saveRow(item, true /*insert*/, repaint)) {
753 emit rowInserted(&item, repaint);
754 return true;
755 }
756 return false;
757}
758
759bool KexiTableViewData::deleteRow(KexiTableItem& item, bool repaint)
760{
761 m_result.clear();
762 emit aboutToDeleteRow(item, &m_result, repaint);
763 if (!m_result.success)
764 return false;
765
766 if (m_cursor) {//db-aware
767 m_result.success = false;
768 if (!m_cursor->deleteRow( static_cast<KexiDB::RowData&>(item), m_containsROWIDInfo/*use ROWID*/ )) {
769 m_result.msg = i18n("Row deleting failed.");
770/*js: TODO: use KexiDB::errorMessage() for description (desc) as in KexiTableViewData::saveRow() */
772 m_result.success = false;
773 return false;
774 }
775 }
776
777 if (!removeRef(&item)) {
778 //aah - this shouldn't be!
779 kdWarning() << "KexiTableViewData::deleteRow(): !removeRef() - IMPL. ERROR?" << endl;
780 m_result.success = false;
781 return false;
782 }
783 emit rowDeleted();
784 return true;
785}
786
787void KexiTableViewData::deleteRows( const TQValueList<int> &rowsToDelete, bool repaint )
788{
789 Q_UNUSED( repaint );
790
791 if (rowsToDelete.isEmpty())
792 return;
793 int last_r=0;
794 first();
795 for (TQValueList<int>::ConstIterator r_it = rowsToDelete.constBegin(); r_it!=rowsToDelete.constEnd(); ++r_it) {
796 for (; last_r<(*r_it); last_r++) {
797 next();
798 }
799 remove();
800 last_r++;
801 }
802//DON'T CLEAR BECAUSE KexiTableViewPropertyBuffer will clear BUFFERS!
803//--> emit reloadRequested(); //! \todo more effective?
804 emit rowsDeleted( rowsToDelete );
805}
806
807void KexiTableViewData::insertRow(KexiTableItem& item, uint index, bool repaint)
808{
809 if (!insert( index = TQMIN(index, count()), &item ))
810 return;
811 emit rowInserted(&item, index, repaint);
812}
813
814void KexiTableViewData::clearInternal()
815{
817// tqApp->processEvents( 1 );
818//TODO: this is time consuming: find better data model
819// KexiTableViewDataBase::clear();
820 const uint c = count();
821 for (uint i=0; i<c; i++) {
822 removeLast();
823#ifndef KEXI_NO_PROCESS_EVENTS
824 if (i % 1000 == 0)
825 tqApp->processEvents( 1 );
826#endif
827 }
828}
829
831{
832 clearInternal();
833
834 bool res = true;
835 if (m_cursor) {
836 //db-aware
837 res = m_cursor->deleteAllRows();
838 }
839
840 if (repaint)
841 emit reloadRequested();
842 return res;
843}
844
846{
847 if (m_autoIncrementedColumn==-2) {
848 //find such a column
849 m_autoIncrementedColumn = 0;
850 KexiTableViewColumn::ListIterator it(columns);
851 for (; it.current(); ++it, m_autoIncrementedColumn++) {
852 if (it.current()->field()->isAutoIncrement())
853 break;
854 }
855 if (!it.current())
856 m_autoIncrementedColumn = -1;
857 }
858 return m_autoIncrementedColumn;
859}
860
862{
863 if (!m_cursor)
864 return;
865
866 //const uint fcount = m_cursor->fieldCount() + (m_containsROWIDInfo ? 1 : 0);
867 m_cursor->moveFirst();
868 for (int i=0;!m_cursor->eof();i++) {
869 KexiTableItem *item = new KexiTableItem(0);
870 m_cursor->storeCurrentRow(*item);
871// item->debug();
872 append( item );
873 m_cursor->moveNext();
874#ifndef KEXI_NO_PROCESS_EVENTS
875 if ((i % 1000) == 0)
876 tqApp->processEvents( 1 );
877#endif
878 }
879}
880
882{
883 return m_readOnly || (m_cursor && m_cursor->connection()->isReadOnly());
884}
885
886#include "kexitableviewdata.moc"
virtual bool isReadOnly() const
Provides database cursor functionality.
Definition cursor.h:67
Meta-data for a field.
Definition field.h:73
bool isNotNull() const
Definition field.h:243
Type type() const
Definition field.cpp:134
TQString captionOrName() const
Definition field.h:374
bool isFPNumericType() const
Definition field.h:266
void setPrimaryKey(bool p)
Definition field.cpp:524
bool isAutoIncrement() const
Definition field.h:231
bool isNotEmpty() const
Definition field.h:246
bool isNumericType() const
Definition field.h:252
bool isUnsigned() const
if the type has the unsigned attribute
Definition field.h:384
Helper class that assigns additional information for the column in a query.
Definition queryschema.h:49
bool visible
true if this column is visible to the user (and its data is fetched by the engine)
Definition queryschema.h:87
int indexForVisibleLookupValue() const
Definition queryschema.h:75
KexiDB::QuerySchema provides information about database query.
TableSchema * masterTable() const
Connection * connection() const
@ WithInternalFields
Like Default but internal fields (for lookup) are appended.
bool success
result of the operation, true by default
Definition error.h:127
provides data for single edited database row KexiDB::RowEditBuffer provides data for single edited ro...
void setValidator(KexiUtils::Validator *v)
KexiDB::Field * field() const
bool isDBAware
true if data is stored in DB, not only in memeory
void setVisible(bool v)
Changes column visibility.
KexiTableViewData * m_data
Data that this column is assigned to.
bool visible() const
Column visibility. By default column is visible.
void setRelatedDataEditable(bool set)
KexiDB::QueryColumnInfo * visibleLookupColumnInfo
KexiDB::QueryColumnInfo * columnInfo
KexiTableViewColumn(KexiDB::Field &f, bool owner=false)
void setRelatedData(KexiTableViewData *data)
int m_realSortedColumn
real sorted column number, set by setSorting(), used by cmp*() methods
KexiTableViewColumn::List columns
KexiTableViewData()
not db-aware version
KexiDB::ResultInfo m_result
used to faster lookup columns of simple type (not dbaware)
int cmpBLOB(Item item1, Item item2)
Compare function for BLOB data (TQByteArray). Uses size as the weight.
void insertRow(KexiTableItem &item, uint index, bool repaint=false)
virtual bool deleteAllRows(bool repaint=false)
virtual void setInsertingEnabled(bool set)
bool saveRow(KexiTableItem &item, bool insert, bool repaint)
internal: for saveRowChanges() and saveNewRow()
void rowUpdated(KexiTableItem *)
Current row has been updated.
void aboutToUpdateRow(KexiTableItem *item, KexiDB::RowEditBuffer *buffer, KexiDB::ResultInfo *result)
void rowInserted(KexiTableItem *, bool repaint)
A row has been inserted.
void deleteRows(const TQValueList< int > &rowsToDelete, bool repaint=false)
virtual void setReadOnly(bool set)
void addColumn(KexiTableViewColumn *col)
bool updateRowEditBufferRef(KexiTableItem *item, int colnum, KexiTableViewColumn *col, TQVariant &newval, bool allowSignals=true, TQVariant *visibleValueForLookupField=0)
virtual bool isReadOnly() const
void setSorting(int column, bool ascending=true)
void aboutToDeleteRow(KexiTableItem &item, KexiDB::ResultInfo *result, bool repaint)
void aboutToChangeCell(KexiTableItem *item, int colnum, TQVariant &newValue, KexiDB::ResultInfo *result)
void reloadRequested()
Displayed data needs to be reloaded in all presenters.
void rowsDeleted(const TQValueList< int > &rowsToDelete)
Rows have been deleted.
void aboutToInsertRow(KexiTableItem *item, KexiDB::ResultInfo *result, bool repaint)
void rowDeleted()
Current row has been deleted.
TQString dbTableName() const
A validator extending TQValidator with offline-checking for value's validity.
Definition validator.h:46
bool isEmptyValue(Field *f, const TQVariant &v)
TQValueVector< TQVariant > RowData
structure for storing single record with type information
Definition connection.h:47
KEXI_DB_EXPORT void getHTMLErrorMesage(Object *obj, TQString &msg, TQString &details)