26#include "KDbTableViewData.h"
27#include "KDbConnection.h"
28#include "KDbConnectionOptions.h"
32#include "KDbOrderByColumn.h"
33#include "KDbQuerySchema.h"
34#include "KDbRecordEditBuffer.h"
35#include "KDbTableViewColumn.h"
38#include <QApplication>
40#include <unicode/coll.h>
44static unsigned short charTable[] = {
45#include "chartable.txt"
55 UErrorCode
status = U_ZERO_ERROR;
56 m_collator = icu::Collator::createInstance(
status);
58 kdbWarning() <<
"Could not create instance of collator:" <<
status;
62 m_collator->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON,
status);
64 kdbWarning() <<
"Could not set collator attribute:" <<
status;
69 icu::Collator* getCollator() {
78 icu::Collator *m_collator;
81Q_GLOBAL_STATIC(CollatorInstance, KDb_collator)
88 QVariant m_leftTmp, m_rightTmp;
91 bool (*m_lessThanFunction)(
const QVariant&,
const QVariant&);
93#define CAST_AND_COMPARE(casting) \
94 return left.casting() < right.casting()
96 static bool cmpInt(
const QVariant& left,
const QVariant& right) {
97 CAST_AND_COMPARE(toInt);
100 static bool cmpUInt(
const QVariant& left,
const QVariant& right) {
101 CAST_AND_COMPARE(toUInt);
104 static bool cmpLongLong(
const QVariant& left,
const QVariant& right) {
105 CAST_AND_COMPARE(toLongLong);
108 static bool cmpULongLong(
const QVariant& left,
const QVariant& right) {
109 CAST_AND_COMPARE(toULongLong);
112 static bool cmpDouble(
const QVariant& left,
const QVariant& right) {
113 CAST_AND_COMPARE(toDouble);
116 static bool cmpDate(
const QVariant& left,
const QVariant& right) {
117 CAST_AND_COMPARE(toDate);
120 static bool cmpDateTime(
const QVariant& left,
const QVariant& right) {
121 CAST_AND_COMPARE(toDateTime);
124 static bool cmpTime(
const QVariant& left,
const QVariant& right) {
125 CAST_AND_COMPARE(toDate);
128 static bool cmpString(
const QVariant& left,
const QVariant& right) {
129 const QString &as =
left.toString();
130 const QString &bs =
right.toString();
138 if (a == b || b ==
nullptr) {
144 unsigned short au = a->
unicode();
145 unsigned short bu = b->
unicode();
146 au = (au <= 0x17e ? charTable[au] : 0xffff);
147 bu = (bu <= 0x17e ? charTable[bu] : 0xffff);
161 static bool cmpStringWithCollator(
const QVariant& left,
const QVariant& right) {
162 const QString &as =
left.toString();
163 const QString &bs =
right.toString();
164 return icu::Collator::LESS == KDb_collator->getCollator()->compare(
170 static bool cmpBLOB(
const QVariant& left,
const QVariant& right) {
171 return left.toByteArray().size() <
right.toByteArray().size();
176 : m_order(KDbOrderByColumn::
SortOrder::Ascending)
178 , m_lessThanFunction(nullptr)
182 void setColumnType(
const KDbField& field) {
185 m_lessThanFunction = &cmpString;
187 m_lessThanFunction = &cmpDouble;
189 m_lessThanFunction = &cmpUInt;
191 m_lessThanFunction = &cmpInt;
194 m_lessThanFunction = &cmpULongLong;
196 m_lessThanFunction = &cmpLongLong;
197 }
else if (t == KDbField::Date)
198 m_lessThanFunction = &cmpDate;
199 else if (t == KDbField::Time)
200 m_lessThanFunction = &cmpTime;
201 else if (t == KDbField::DateTime)
202 m_lessThanFunction = &cmpDateTime;
205 m_lessThanFunction = &cmpBLOB;
208 if (!KDb_collator.isDestroyed() && KDb_collator->getCollator()) {
209 m_lessThanFunction = &cmpStringWithCollator;
212 m_lessThanFunction = &cmpString;
221 void setSortColumn(
int column) {
222 m_sortColumn = column;
225#define _IIF(a,b) ((a) ? (b) : !(b))
228 bool operator()(KDbRecordData* record1, KDbRecordData* record2) {
230 if ((m_leftTmp = record1->
at(m_sortColumn)).isNull())
231 return _IIF(m_order == KDbOrderByColumn::SortOrder::Ascending,
232 !record2->
at(m_sortColumn).
isNull());
233 if ((m_rightTmp = record2->
at(m_sortColumn)).isNull())
234 return m_order == KDbOrderByColumn::SortOrder::Descending;
236 return _IIF(m_order == KDbOrderByColumn::SortOrder::Ascending,
237 m_lessThanFunction(m_leftTmp, m_rightTmp));
241#undef CAST_AND_COMPARE
250 , sortOrder(KDbOrderByColumn::
SortOrder::Ascending)
252 , pRecordEditBuffer(nullptr)
254 , insertingEnabled(true)
255 , containsRecordIdInfo(false)
256 , autoIncrementedColumn(-2) {
260 delete pRecordEditBuffer;
267 QList<KDbTableViewColumn*> columns;
270 QList<KDbTableViewColumn*> visibleColumns;
282 LessThanFunctor lessThanFunctor;
286 KDbRecordEditBuffer *pRecordEditBuffer;
290 KDbResultInfo result;
292 QList<int> visibleColumnIDs;
293 QList<int> globalColumnIDs;
297 bool insertingEnabled;
300 bool containsRecordIdInfo;
302 mutable int autoIncrementedColumn;
309 , KDbTableViewDataBase()
312 d->realColumnCount = 0;
319 , KDbTableViewDataBase()
324 if (d->cursor && d->cursor->query()) {
325 const KDbQuerySchema::FieldsExpandedMode fieldsExpandedMode
326 = d->containsRecordIdInfo ? KDbQuerySchema::FieldsExpandedMode::WithInternalFieldsAndRecordId
327 : KDbQuerySchema::FieldsExpandedMode::WithInternalFields;
328 d->realColumnCount = d->cursor->query()->fieldsExpanded(
329 d->cursor->connection(), fieldsExpandedMode).count();
331 d->realColumnCount = d->columns.count() + (d->containsRecordIdInfo ? 1 : 0);
335 const KDbQueryColumnInfo::Vector fields
336 = d->cursor->query()->fieldsExpanded(d->cursor->connection());
337 const int fieldCount = fields.count();
338 for (
int i = 0;i < fieldCount;i++) {
344 visibleLookupColumnInfo = d->cursor->query()->expandedOrInternalField(
347 KDbTableViewColumn* col =
new KDbTableViewColumn(*d->cursor->query(), ci, visibleLookupColumnInfo);
359 KDbTableViewColumn *keyColumn
360 =
new KDbTableViewColumn(keyField, KDbTableViewColumn::FieldIsOwned::Yes);
365 KDbTableViewColumn *valueColumn
366 =
new KDbTableViewColumn(valueField, KDbTableViewColumn::FieldIsOwned::Yes);
372 for (;cnt > 0;++it_keys, ++it_values, cnt--) {
374 (*record)[0] = (*it_keys);
375 (*record)[1] = (*it_values);
385KDbTableViewData::~KDbTableViewData()
389 qDeleteAll(d->columns);
401 d->columns.append(col);
404 d->visibleColumns.append(col);
405 d->visibleColumnIDs.append(d->visibleColumns.count() - 1);
406 d->globalColumnIDs.append(d->columns.count() - 1);
408 d->visibleColumnIDs.append(-1);
410 d->autoIncrementedColumn = -2;
411 if (!d->cursor || !d->cursor->query()) {
412 d->realColumnCount = d->columns.count() + (d->containsRecordIdInfo ? 1 : 0);
419 int indexInGlobal = d->columns.indexOf(
const_cast<KDbTableViewColumn*
>(&
column));
421 int prevIndexInGlobal = indexInGlobal - 1;
422 while (prevIndexInGlobal >= 0 && d->visibleColumnIDs[prevIndexInGlobal] == -1) {
425 int indexInVisible = prevIndexInGlobal + 1;
427 d->visibleColumns.insert(indexInVisible,
const_cast<KDbTableViewColumn*
>(&
column));
428 d->visibleColumnIDs[indexInGlobal] = indexInVisible;
429 d->globalColumnIDs.insert(indexInVisible, indexInGlobal);
430 for (
int i = indexInGlobal + 1; i < d->columns.count(); i++) {
431 if (d->visibleColumnIDs[i] >= 0) {
432 d->visibleColumnIDs[i]++;
437 int indexInVisible = d->visibleColumns.indexOf(
const_cast<KDbTableViewColumn*
>(&
column));
438 d->visibleColumns.removeAt(indexInVisible);
440 d->visibleColumnIDs[indexInGlobal] = -1;
441 d->globalColumnIDs.removeAt(indexInVisible);
447 return d->globalColumnIDs.value(visibleIndex, -1);
452 return d->visibleColumnIDs.value(globalIndex, -1);
455int KDbTableViewData::columnCount()
const
457 return d->columns.
count();
462 return d->visibleColumns.count();
472 return &d->visibleColumns;
477 return d->columns.value(index);
482 return d->visibleColumns.value(index);
487 return d->cursor !=
nullptr;
490KDbCursor* KDbTableViewData::cursor()
const
497 return d->insertingEnabled;
502 return d->pRecordEditBuffer;
512 return d->containsRecordIdInfo;
522 if (d->cursor && d->cursor->query() && d->cursor->query()->masterTable())
523 return d->cursor->query()->masterTable()->name();
529 d->sortOrder = order;
532 d->realSortColumn = -1;
536 const KDbTableViewColumn *tvcol = d->columns.at(
column);
538 const KDbField *field = visibleLookupColumnInfo ? visibleLookupColumnInfo->
field() : tvcol->
field();
544 d->lessThanFunctor.setColumnType(*field);
545 d->lessThanFunctor.setSortOrder(d->sortOrder);
546 d->lessThanFunctor.setSortColumn(
column);
551 return d->sortColumn;
561 if (d->sortColumn < 0 || d->sortColumn >= d->columns.count()) {
564 std::sort(begin(), end(), d->lessThanFunctor);
569 if (d->readOnly == set)
578 if (d->insertingEnabled == set)
580 d->insertingEnabled = set;
581 if (d->insertingEnabled)
588 if (!d->pRecordEditBuffer)
591 d->pRecordEditBuffer->clear();
595 int colnum, KDbTableViewColumn* col,
QVariant* newval,
bool allowSignals,
596 QVariant *visibleValueForLookupField)
598 if (!record || !newval) {
604 if (!d->result.success)
609 kdbWarning() <<
"column #" << colnum <<
"not found! col==0";
612 if (!d->pRecordEditBuffer)
614 if (d->pRecordEditBuffer->isDBAware()) {
616 kdbWarning() <<
"column #" << colnum <<
" not found!";
619 d->pRecordEditBuffer->insert(col->
columnInfo(), *newval);
627 if (!(col->
field())) {
628 kdbWarning() <<
"column #" << colnum <<
"not found!";
634 kdbWarning() <<
"column #" << colnum <<
"not found!";
637 d->pRecordEditBuffer->
insert(colname, *newval);
642 KDbTableViewColumn* col,
643 const QVariant &newval,
bool allowSignals)
650 const QVariant &newval,
bool allowSignals)
652 KDbTableViewColumn* col = d->columns.value(colnum);
665 ? pRecordEditBuffer->
at( (**it_f)->columnInfo(),
667 : pRecordEditBuffer->
at( *f );
668 *val = *pval ? **pval : record->
at(col);
674bool KDbTableViewData::saveRecord(
KDbRecordData *record,
bool insert,
bool repaint)
676 if (!d->pRecordEditBuffer)
683 const QVariant *pval =
nullptr;
685 for (;it_f != d->columns.
constEnd() && colIndex < record->count();++it_f, ++colIndex) {
686 KDbField *f = (*it_f)->field();
688 saveRecordGetValue(&pval, d->cursor, d->pRecordEditBuffer, &it_f, record, f, &val, colIndex);
692 d->result.message =
tr(
"\"%1\" column requires a value to be entered.").
arg(f->
captionOrName())
694 d->result.description =
tr(
"The column's constraint is declared as NOT NULL.");
695 d->result.column = colIndex;
700 saveRecordGetValue(&pval, d->cursor, d->pRecordEditBuffer, &it_f, record, f, &val, colIndex);
703 d->result.message =
tr(
"\"%1\" column requires a value to be entered.").
arg(f->
captionOrName())
705 d->result.description =
tr(
"The column's constraint is declared as NOT EMPTY.");
706 d->result.column = colIndex;
714 if (!d->cursor->insertRecord(record, d->pRecordEditBuffer,
715 d->containsRecordIdInfo ))
717 d->result.message =
tr(
"Record inserting failed.") + QLatin1String(
"\n\n")
730 if (!d->cursor->updateRecord(
static_cast<KDbRecordData*
>(record), d->pRecordEditBuffer,
731 d->containsRecordIdInfo ))
733 d->result.message =
tr(
"Record changing failed.") + QLatin1String(
"\n\n")
741 KDbRecordEditBuffer::SimpleMap b = d->pRecordEditBuffer->simpleBuffer();
744 foreach(KDbTableViewColumn *col, d->columns) {
748 <<
" -> " << it.value().toString();
749 (*record)[i] = it.value();
755 d->pRecordEditBuffer->
clear();
758 emit recordRepaintRequested(record);
762bool KDbTableViewData::saveRecordChanges(
KDbRecordData *record,
bool repaint)
766 if (!d->result.success)
769 if (saveRecord(record,
false , repaint)) {
776bool KDbTableViewData::saveNewRecord(
KDbRecordData *record,
bool repaint)
780 if (!d->result.success)
783 if (saveRecord(record,
true , repaint)) {
794 if (!d->result.success)
798 d->result.success =
false;
799 if (!d->cursor->deleteRecord(
static_cast<KDbRecordData*
>(record), d->containsRecordIdInfo )) {
800 d->result.message =
tr(
"Record deleting failed.");
803 d->result.success =
false;
808 int index = indexOf(record);
811 kdbWarning() <<
"!removeRef() - IMPL. ERROR?";
812 d->result.success =
false;
827 KDbTableViewDataIterator it(begin());
829 for (; last_r < (*r_it); last_r++)
841 insert(index = qMin(index, count()), record);
849 const int c = count();
850#ifndef TABLEVIEW_NO_PROCESS_EVENTS
851 const bool _processEvents = processEvents && !qApp->closingDown();
853 for (
int i = 0; i < c; i++) {
855#ifndef TABLEVIEW_NO_PROCESS_EVENTS
856 if (_processEvents && i % 1000 == 0)
869 res = d->cursor->deleteAllRecords();
879 if (d->autoIncrementedColumn == -2) {
881 d->autoIncrementedColumn = -1;
882 foreach(KDbTableViewColumn *col, d->columns) {
883 d->autoIncrementedColumn++;
888 return d->autoIncrementedColumn;
895 if (!d->cursor->moveFirst() && d->cursor->result().isError())
898#ifndef TABLEVIEW_NO_PROCESS_EVENTS
899 const bool processEvents = !qApp->closingDown();
902 for (
int i = 0;!d->cursor->eof();i++) {
910 if (!d->cursor->moveNext() && d->cursor->result().isError()) {
914#ifndef TABLEVIEW_NO_PROCESS_EVENTS
915 if (processEvents && (i % 1000) == 0)
924 return d->readOnly || (d->cursor && d->cursor->connection()->options()->
isReadOnly());
930 return tr(
"Please correct data in this record or use the \"Cancel record changes\" function.");
935 dbg.
nospace() <<
"TableViewData(";
937 <<
"sortOrder:" << (data.
sortOrder() == KDbOrderByColumn::SortOrder::Ascending
941 <<
"cursor:" << (data.cursor() ?
"yes" :
"no")
942 <<
"columnCount:" << data.columnCount()
943 <<
"count:" << data.count()
949 <<
"result:" << data.
result();
Provides database cursor functionality.
bool containsRecordIdInfo() const
bool isNumericType() const
bool isAutoIncrement() const
void setPrimaryKey(bool p)
QString captionOrName() const
bool isFPNumericType() const
bool isUnsigned() const
if the type has the unsigned attribute
SortOrder
Column sort order.
Helper class that assigns additional information for the column in a query.
int indexForVisibleLookupValue() const
Structure for storing single record with type information.
const QVariant & at(int i) const
provides data for single edited database record
const QVariant * at(KDbQueryColumnInfo *ci, bool useDefaultValueIfPossible=true) const
bool isVisible() const
Column visibility. By default column is visible.
KDbQueryColumnInfo * visibleLookupColumnInfo()
void setVisible(bool v)
Changes column visibility.
KDbQueryColumnInfo * columnInfo()
void setData(KDbTableViewData *data)
used by KDbTableViewData::addColumn()
A list of records to allow configurable sorting and more.
bool deleteRecord(KDbRecordData *record, bool repaint=false)
virtual bool isInsertingEnabled() const
int visibleColumnCount() const
bool updateRecordEditBuffer(KDbRecordData *record, int colnum, KDbTableViewColumn *col, const QVariant &newval, bool allowSignals=true)
QList< KDbTableViewColumn * > * visibleColumns()
const KDbResultInfo & result() const
KDbTableViewColumn * column(int c)
void setSorting(int column, KDbOrderByColumn::SortOrder order=KDbOrderByColumn::SortOrder::Ascending)
QString dbTableName() const
void recordUpdated(KDbRecordData *)
Current record has been updated.
virtual bool isReadOnly() const
static QString messageYouCanImproveData()
bool updateRecordEditBufferRef(KDbRecordData *record, int colnum, KDbTableViewColumn *col, QVariant *newval, bool allowSignals=true, QVariant *visibleValueForLookupField=nullptr)
KDbTableViewData()
Non-db-aware version.
void aboutToInsertRecord(KDbRecordData *record, KDbResultInfo *result, bool repaint)
void addColumn(KDbTableViewColumn *col)
int globalIndexOfVisibleColumn(int visibleIndex) const
void aboutToChangeCell(KDbRecordData *record, int colnum, QVariant *newValue, KDbResultInfo *result)
KDbTableViewColumn * visibleColumn(int index)
KDbOrderByColumn::SortOrder sortOrder() const
void recordInserted(KDbRecordData *, bool repaint)
A record has been inserted.
virtual void clearInternal(bool processEvents=true)
void aboutToUpdateRecord(KDbRecordData *record, KDbRecordEditBuffer *buffer, KDbResultInfo *result)
void aboutToDeleteRecord(KDbRecordData *record, KDbResultInfo *result, bool repaint)
void insertRecord(KDbRecordData *record, int index, bool repaint=false)
void clearRecordEditBuffer()
QList< KDbTableViewColumn * > * columns()
virtual void setReadOnly(bool set)
virtual bool deleteAllRecords(bool repaint=false)
int visibleColumnIndex(int globalIndex) const
void recordsDeleted(const QList< int > &recordsToDelete)
Records have been deleted.
void sort()
Sorts this data using previously set order.
void columnVisibilityChanged(const KDbTableViewColumn &column)
Used by KDbTableViewColumn::setVisible()
void reloadRequested()
Displayed data needs to be reloaded in all presenters.
bool containsRecordIdInfo() const
int autoIncrementedColumn() const
void recordDeleted()
Current record has been deleted.
void deleteRecords(const QList< int > &recordsToDelete, bool repaint=false)
KDbRecordData * createItem() const
Creates a single record data with proper number of columns.
KDbRecordEditBuffer * recordEditBuffer() const
virtual void setInsertingEnabled(bool set)
Q_SCRIPTABLE CaptureState status()
KDB_EXPORT bool isEmptyValue(KDbField::Type type, const QVariant &value)
KDB_EXPORT void getHTMLErrorMesage(const KDbResultable &resultable, QString *msg, QString *details)
Sets HTML-formatted error message with extra details obtained from result object.
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
iterator insert(const_iterator before, parameter_type value)
bool isEmpty() const const
const_iterator constBegin() const const
const_iterator constEnd() const const
QString tr(const char *sourceText, const char *disambiguation, int n)
QString arg(Args &&... args) const const
const QChar * constData() const const
QString & insert(qsizetype position, QChar ch)
bool isEmpty() const const
qsizetype length() const const
qsizetype size() const const
const QChar * unicode() const const
QTextStream & left(QTextStream &stream)
QTextStream & right(QTextStream &stream)
bool isNull() const const
QString toString() const const