Diffstat (limited to 'noncore/apps/tableviewer/db/common.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/apps/tableviewer/db/common.cpp | 1470 |
1 files changed, 1470 insertions, 0 deletions
diff --git a/noncore/apps/tableviewer/db/common.cpp b/noncore/apps/tableviewer/db/common.cpp new file mode 100644 index 0000000..4c70e54 --- a/dev/null +++ b/noncore/apps/tableviewer/db/common.cpp @@ -0,0 +1,1470 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#include <stdlib.h> +#include <qstring.h> +#include <qheader.h> +#include <qvector.h> +#include <qdatetime.h> +#include <timestring.h> +#include "common.h" +#include "datacache.h" +#include <assert.h> + +static const int del_flag = 0x1; +static const int new_flag = 0x2; + +/* Helper function */ + +int parseNextNumber(QString *q) { + QChar c; + uint i; + int result = 0; + + bool found_digits = FALSE; + for(i = 0; i < q->length(); i++) { + c = q->at(i); + if (c.isDigit()) { + if (found_digits) + result *= 10; + found_digits = TRUE; + result += c.digitValue(); + } else { + if (found_digits) + break; + /* just skip this char */ + } + } + /* now truncate q */ + if (found_digits) + q->remove(0, i); + return result; +} + +/*! + \class QStringVector + \brief A Vector of QStrings that can be sorted and searched + + Implmented in order to allow reverse lookup on the string name + +*/ + +/*! + This function implements the compare function in order to allow the + searching and sorting of the QStringVector to occur + + \returns an int which is either + <UL> + <LI> < 0 if the first string is smaller than the second,</LI> + <LI> > 0 if the first string is bigger then the second,</LI> + <LI> == 0 if the first string is equal to the second.</LI> + </UL> +*/ +int QStringVector::compareItems(Item a, Item b) +{ + QString *qa = (QString *)a; + QString *qb = (QString *)b; + + return QString::compare(*qa, *qb); +} + +/*! + \class TVVariant + A way of abstracting void * and keeping information on + the keytypes and behaviours in one place +*/ + +TVVariantPrivate::TVVariantPrivate() +{ + typ = TVVariant::Invalid; +} + +TVVariantPrivate::TVVariantPrivate( TVVariantPrivate *d) +{ + switch(d->typ) + { + case TVVariant::Invalid: + break; + case TVVariant::String: + value.ptr = new QString(*((QString *)d->value.ptr)); + break; + case TVVariant::Date: + value.ptr = new QDate(*((QDate *)d->value.ptr)); + break; + case TVVariant::Time: + value.ptr = new QTime(*((QTime *)d->value.ptr)); + break; + case TVVariant::Int: + value.i = d->value.i; + break; + default: + ASSERT( 0 ); + } + + typ = d->typ; +} + +TVVariantPrivate::~TVVariantPrivate() +{ + clear(); +} + +void TVVariantPrivate::clear() +{ + switch( typ ) + { + case TVVariant::String: + delete (QString *)value.ptr; + break; + case TVVariant::Date: + delete (QDate *)value.ptr; + break; + case TVVariant::Time: + delete (QTime *)value.ptr; + break; + case TVVariant::Invalid: + case TVVariant::Int: + break; + } + + typ = TVVariant::Invalid; +} + +/*! + \class TVVariant + blah +*/ + +TVVariant::TVVariant() +{ + d = new TVVariantPrivate; +} + +TVVariant::~TVVariant() +{ + if (d->deref()) + delete d; +} + +TVVariant::TVVariant(const TVVariant& p) +{ + d = new TVVariantPrivate; + *this = p; +} + +TVVariant::TVVariant(QDataStream& s) +{ + d = new TVVariantPrivate; + s >> *this; +} + +TVVariant::TVVariant(const QString &val) +{ + d = new TVVariantPrivate; + d->typ = String; + d->value.ptr = new QString(val); +} + +TVVariant::TVVariant(const QDate &val) +{ + d = new TVVariantPrivate; + d->typ = Date; + d->value.ptr = new QDate(val); +} + +TVVariant::TVVariant(const QTime &val) +{ + d = new TVVariantPrivate; + d->typ = Time; + d->value.ptr = new QTime(val); +} + +TVVariant::TVVariant( int val ) +{ + d = new TVVariantPrivate; + d->typ = Int; + d->value.i = val; +} + +TVVariant& TVVariant::operator=(const TVVariant& variant ) +{ + TVVariant& other = (TVVariant&) variant; + + other.d->ref(); + if ( d->deref() ) + delete d; + + d = other.d; + + return *this; +} + +void TVVariant::detach() +{ + if (d->count == 1) + return; + + d->deref(); + d = new TVVariantPrivate(d); +} + +const QString TVVariant::typeName() const +{ + return typeToName(d->typ); +} + +void TVVariant::clear() +{ + if (d->count > 1) + { + d->deref(); + d = new TVVariantPrivate; + return; + } + + d->clear(); +} + +const QString TVVariant::typeToName(KeyType typ) +{ + switch(typ) { + case String: + return QString("String"); + case Date: + return QString("Date"); + case Time: + return QString("Time"); + case Int: + return QString("Int"); + case Invalid: + default: + return QString("Invalid"); + } + return QString("Invalid"); +} + +TVVariant::KeyType TVVariant::nameToType(const QString &name) +{ + if(!qstrcmp("String", name)) + return String; + if(!qstrcmp("Date", name)) + return Date; + if(!qstrcmp("Time", name)) + return Time; + if(!qstrcmp("Int", name)) + return Int; + + return Invalid; +} + +void TVVariant::load(QDataStream &s ) +{ + KeyType t; + s >> t; + + d->typ = t; + switch(t) { + case Invalid: + d->typ = t; + break; + case String: + { + QString *x = new QString; + s >> *x; + d->value.ptr = x; + } + break; + case Time: + { + QTime *x = new QTime; + s >> *x; + d->value.ptr = x; + } + break; + case Date: + { + QDate *x = new QDate; + s >> *x; + d->value.ptr = x; + } + break; + case Int: + { + int x; + s >> x; + d->value.i = x; + } + break; + default: + qFatal("Unrecognized data type"); + } +} + +void TVVariant::save( QDataStream &s ) const +{ + s << type(); + + switch( d->typ ) { + case String: + s << *((QString *)d->value.ptr); + break; + case Date: + s << *((QDate *)d->value.ptr); + break; + case Time: + s << *((QTime *)d->value.ptr); + break; + case Int: + s << d->value.i; + break; + case Invalid: + break; + } +} + +QDataStream& operator>>(QDataStream& s, TVVariant& p) +{ + p.load( s ); + return s; +} + +QDataStream& operator<<(QDataStream &s, const TVVariant& p) +{ + p.save( s ); + return s; +} + +QDataStream& operator>> (QDataStream &s, TVVariant::KeyType& p) +{ + Q_UINT8 u = 0; + s >> u; + p = (TVVariant::KeyType) u; + + return s; +} + +QDataStream& operator<< (QDataStream& s, const TVVariant::KeyType& p) +{ + s << (Q_UINT8)p; + return s; +} + +const QString TVVariant::toString() const +{ + switch(d->typ) { + case String: + return *((QString*)d->value.ptr); + case Date: + return ((QDate*)d->value.ptr)->toString(); + case Time: + return ((QTime*)d->value.ptr)->toString(); + case Int: + return QString::number(d->value.i); + case Invalid: + default: + return QString::null; + } + return QString::null; +} + +// TODO DO, this properly, */ +int TVVariant::toInt() const +{ + if(d->typ == Int) + return d->value.i; + + if(d->typ == String) { + QString tmpq(*(QString *)d->value.ptr); + return parseNextNumber(&tmpq); + } + + return 0; +} + +const QDate TVVariant::toDate() const +{ + if(d->typ == Date) + return *((QDate *)d->value.ptr); + + if(d->typ == String) { + QString q = toString(); + + /* date format is day mon d yyyy */ + /* ignore the first three letters, read the next + three for month.. etc */ + + int day = parseNextNumber(&q); + int month = parseNextNumber(&q); + int year = parseNextNumber(&q); + if (!QDate::isValid(year, month, day)) + return QDate(); + return QDate(year, month, day); + } + + + return QDate(); +} + +const QTime TVVariant::toTime() const +{ + if(d->typ == Time) + return *((QTime *)d->value.ptr); + + if(d->typ == String) { + QString q = toString(); + int hour = parseNextNumber(&q); + int minute = parseNextNumber(&q); + int second = parseNextNumber(&q); + int msecond = parseNextNumber(&q); + if (!QTime::isValid(hour, minute, second, msecond)) + return QTime(); + return QTime(hour, minute, second, msecond); + } + + return QTime(); +} + +#define TV_VARIANT_AS( f ) Q##f& TVVariant::as##f() { \ + if ( d->typ != f ) \ + *this = TVVariant( to##f() ); \ + else \ + detach(); \ + return *((Q##f*)d->value.ptr); } + +TV_VARIANT_AS(String) +TV_VARIANT_AS(Date) +TV_VARIANT_AS(Time) + +#undef TV_VARIANT_AS + +int& TVVariant::asInt() +{ + detach(); + if (d->typ != Int) { + d->value.i = toInt(); + d->typ = Int; + } + return d->value.i; +} + +/*! + valid cast is + anything to String + same to same +*/ +bool TVVariant::canCast(KeyType t) const +{ + if(d->typ == t) + return TRUE; + + if(t == String) + return TRUE; + + if(t == Int) { + if (d->typ == Date) + return TRUE; + if (d->typ == Time) + return TRUE; + if (d->typ == String) + return TRUE; + } + + return FALSE; +} + +bool TVVariant::operator==( const TVVariant &v ) const +{ + switch(d->typ) { + case String: + return v.toString() == toString(); + case Date: + return v.toDate() == toDate(); + case Time: + return v.toTime() == toTime(); + case Int: + return v.toInt() == toInt(); + case Invalid: + break; + } + + return FALSE; +} + +bool TVVariant::operator!=( const TVVariant &v ) const +{ + return !( v == *this); +} + +bool TVVariant::operator<( const TVVariant &v ) const +{ + switch(d->typ) { + case String: + return toString().lower() < v.toString().lower(); + case Date: + return toDate() < v.toDate(); + case Time: + return toTime() < v.toTime(); + case Int: + return toInt() < v.toInt(); + case Invalid: + default: + break; + } + return FALSE; +} + +bool TVVariant::operator>( const TVVariant &v ) const +{ + switch(d->typ) { + case String: + return toString().lower() > v.toString().lower(); + case Date: + return toDate() > v.toDate(); + case Time: + return toTime() > v.toTime(); + case Int: + return toInt() > v.toInt(); + case Invalid: + default: + break; + } + return FALSE; +} + +/*! True if n is closer to this than o */ +bool TVVariant::closer(TVVariant n, TVVariant o) +{ + /* Nothing is close to an invalid, so nothing can be closer */ + if(d->typ == Invalid) + return FALSE; + + /* can't be closer if of different type */ + if(n.type() != type()) + return FALSE; + + /* if new shares type, and old doesn't, then new is closer */ + if(o.type() != type()) + return TRUE; + + switch(type()){ + case String: { + /* case for strings is close is a substring.. closer is + * earlier alphabetically */ + QString qs1 = n.toString().lower(); + QString qs2 = o.toString().lower(); + QString qsv = toString().lower(); + + if (!qs1.startsWith(qsv)) + return FALSE; + + /* contains sub-str, if later than is not closer */ + if(QString::compare(qs1, qs2) > 0) + return FALSE; + return TRUE; + } + case Int: { + /* case for int is smallest absolute difference */ + int i1 = n.toInt(); + int i2 = o.toInt(); + int iv = toInt(); + + int diff1 = (i1 - iv); + if (diff1 < 0) + diff1 = -diff1; + int diff2 = (i2 - iv); + if (diff2 < 0) + diff2 = -diff2; + + if (diff1 < diff2) + return TRUE; + return FALSE; + } + case Date: { + QDate i1 = n.toDate(); + QDate i2 = o.toDate(); + QDate iv = toDate(); + + /* definition of closer is the least difference in days */ + int diff1 = i1.daysTo(iv); + if (diff1 < 0) + diff1 = -diff1; + int diff2 = i2.daysTo(iv); + if (diff2 < 0) + diff2 = -diff2; + + if (diff1 < diff2) + return TRUE; + return FALSE; + } + case Time: { + QTime i1 = n.toTime(); + QTime i2 = o.toTime(); + QTime iv = toTime(); + + /* definition of closer is the least difference in days */ + int diff1 = i1.msecsTo(iv); + if (diff1 < 0) + diff1 = -diff1; + int diff2 = i2.msecsTo(iv); + if (diff2 < 0) + diff2 = -diff2; + if (diff1 < diff2) + return TRUE; + return FALSE; + } + default: + /* don't know how to do 'closer' on this type, hence never closer + * or even close */ + break; + } + return FALSE; +} + +/*! True if n is close to this */ +bool TVVariant::close(TVVariant n) +{ + /* Nothing is close to an invalid, so nothing can be closer */ + if(type() == Invalid) + return FALSE; + + /* can't be close if of different type */ + if(n.type() != type()) + return FALSE; + + switch(type()){ + case String: { + /* case for strings is close is a substring.. closer is + * earlier alphabetically */ + QString qs1 = n.toString().lower(); + QString qsv = toString().lower(); + + if (!qs1.startsWith(qsv)) + return FALSE; + return TRUE; + } + case Int: + case Date: + case Time: + return TRUE; + default: + /* don't know how to do 'closer' on this type, hence never closer + * or even close */ + break; + } + return FALSE; +} + +/*! + \class Key + \brief document me! + + document me! +*/ + +Key::Key() : kname(), kexample(), kflags(0) { } + +Key::Key(QString name, TVVariant example, int flags = 0) : + kname(name), kexample(example), kflags(flags) { } + +Key::Key(const Key &other) +{ + kname = other.kname; + kexample = other.kexample; + kflags = other.kflags; +} + +Key& Key::operator=(const Key& key) +{ + kname = key.kname; + kexample = key.kexample; + kflags = key.kflags; + return *this; +} + +QString Key::name() const +{ + return QString(kname); +} + +TVVariant Key::example() const +{ + return TVVariant(kexample); +} + +TVVariant::KeyType Key::type() const +{ + return kexample.type(); +} + +void Key::setName(const QString &name) +{ + kname = QString(name); +} + +void Key::setExample(const TVVariant &e) +{ + kexample = TVVariant(e); +} + +int Key::flags() const +{ + return kflags; +} + +void Key::setFlags(int fl) +{ + kflags = fl; +} + +bool Key::delFlag() const +{ + if(kflags & del_flag) + return TRUE; + return FALSE; +} + +bool Key::newFlag() const +{ + if(kflags & new_flag) + return TRUE; + return FALSE; +} + +void Key::setDelFlag(bool v) +{ + if(delFlag() != v) + kflags = kflags ^ del_flag; +} + +void Key::setNewFlag(bool v) +{ + if(newFlag() != v) + kflags = kflags ^ new_flag; +} + +/*! + \class KeyList + \brief A represntation of keys used for a table. + + The KeyList class is used to store the representation of keys used in table + headings by DBStore. It stores the names and types of the keys +*/ + +/*! + Constructs a KeyList +*/ +KeyList::KeyList() : QIntDict<Key>(20) +{ + setAutoDelete(TRUE); +} + +/* Should be deep copy, but isn't */ +KeyList::KeyList(const KeyList &k) : QIntDict<Key>(k) +{ + KeyListIterator it(k); + while(it.current()) { + replace(it.currentKey(), new Key(*it.current())); + ++it; + } + + setAutoDelete(TRUE); +} + +/*! + Destroys a KeyList +*/ +KeyList::~KeyList() { +} + +/* Do a comparision base on Keys */ +bool KeyList::operator!=(const KeyList &other) +{ + KeyListIterator it(*this); + + if (other.getNumFields() != getNumFields()) + return TRUE; + + while(it.current()) { + //it.currentKey(), it.current(); + if (other.getKeyName(it.currentKey()) != getKeyName(it.currentKey())) + return TRUE; + if (other.getKeyType(it.currentKey()) != getKeyType(it.currentKey())) + return TRUE; + ++it; + } + return FALSE; +} + +/*! + Returns the number of keys stored in the KeyList +*/ +int KeyList::getNumFields() const +{ + return count(); +} + +/*! + Adds a new key to the KeyList + + \param name the name of the new key + \param type the type of the new key +*/ +int KeyList::addKey(QString name, TVVariant example) +{ + int i = count(); + while(find(i) && (i > -1)) + i--; + replace(i, new Key(name, example, 0)); + return i; +} + +int KeyList::addKey(QString name, TVVariant::KeyType type) +{ + /* generate a valid type for the example? */ + TVVariant e = TVVariant("0"); + switch(type) { + case TVVariant::String: + return addKey(name, TVVariant("<undefined>").asString()); + break; + case TVVariant::Date: + return addKey(name, TVVariant(QDate::currentDate()).asDate()); + break; + case TVVariant::Time: + return addKey(name, TVVariant(QTime(0,0,0)).toTime()); + break; + case TVVariant::Int: + return addKey(name, TVVariant(0).toInt()); + break; + default: + qWarning(QObject::tr("KeyList::addKey() Cannot make default " + "value for type %1, Key not added.").arg(type)); + break; + } + return -1; +} + +void KeyList::setKeyFlags(int i, int flag) +{ + if(find(i)) + find(i)->setFlags(flag); +} + +int KeyList::getKeyFlags(int i) const +{ + if(find(i)) + return find(i)->flags(); + return 0; +} + +bool KeyList::checkNewFlag(int i) const +{ + if (find(i)) + return find(i)->newFlag(); + return false; +} + +void KeyList::setNewFlag(int i, bool f) +{ + if(!find(i)) + return; + find(i)->setNewFlag(f); +} + +bool KeyList::checkDeleteFlag(int i) const +{ + if (find(i)) + return find(i)->delFlag(); + return false; +} + +void KeyList::setDeleteFlag(int i, bool f) +{ + if(!find(i)) + return; + find(i)->setDelFlag(f); +} + +/*! + Returns the name of the key at index i +*/ +QString KeyList::getKeyName(int i) const +{ + if (find (i)) + return find(i)->name(); + return QString(); +} + +void KeyList::setKeyName(int i, const QString &n) +{ + if(find(i)) + find(i)->setName(n); +} + +/*! + Returns the type of the key at index i +*/ +TVVariant::KeyType KeyList::getKeyType(int i) const +{ + if(find(i)) + return find(i)->type(); + return TVVariant::Invalid; +} + +void KeyList::setKeyType(int i, TVVariant::KeyType t) +{ + if(!find(i)) + return; + switch(t) { + case TVVariant::String: + find(i)->setExample(TVVariant(QString("default"))); + return; + case TVVariant::Int: + find(i)->setExample(TVVariant(int(0))); + return; + case TVVariant::Date: + find(i)->setExample(TVVariant(QDate::currentDate())); + return; + case TVVariant::Time: + find(i)->setExample(TVVariant(QTime(0,0,0,0))); + return; + default: + break; + } + return; +} + +TVVariant KeyList::getKeyExample(int i) const +{ + if(find(i)) + return find(i)->example(); + return TVVariant(); +} + +void KeyList::setKeyExample(int i, TVVariant example) +{ + if(find(i)) + find(i)->setExample(example); +} + +/*! + Returns the index of the key with name q +*/ +int KeyList::getKeyIndex(QString q) const +{ + KeyListIterator it(*this); + + while(it.current()) { + if(it.current()->name() == q) + return it.currentKey(); + ++it; + } + return -1; +} + +bool KeyList::validIndex(int i) const +{ + if(!find(i)) + return FALSE; + if(find(i)->delFlag()) + return FALSE; + return TRUE; +} + +QDataStream &operator<<( QDataStream &s, const KeyList &k) +{ + s << k.getNumFields(); + + KeyListIterator it(k); + + while(it.current()) { + s << (Q_UINT16)it.currentKey(); + s << it.current()->name(); + s << it.current()->example(); + s << (Q_UINT16)it.current()->flags(); + ++it; + } + return s; +} + +QDataStream &operator>>( QDataStream &s, KeyList &k) +{ + int i; + int size; + int index = 0; + int flags = 0; + TVVariant type = TVVariant(); + QString name; + + s >> size; + + for (i=0; i < size; i++) { + s >> (Q_UINT16 &)index; + s >> name; + s >> type; + s >> (Q_UINT16 &)flags; + k.replace(index, new Key(name, type, flags)); + } + return s; +} + +/*! + \class DataElem + \brief A class representing a single row or element of a table in a DBStore + + This class holds the data of a row in a table. +*/ + + +/*! + Constructs a DataElem. This function needs a container because the + size, types of keys and primary key are all defined by the containing + database +*/ +DataElem::DataElem(DBStore *c) : values(20) +{ + int size; + contained = c; + size = c->getNumFields(); + values.setAutoDelete(TRUE); +} + +/*! + Destroys a DataElem and frees memory used by the DataElem +*/ +DataElem::~DataElem() { +} + + + +QDataStream &operator<<( QDataStream &s, const DataElem &d) +{ + int size = d.getNumFields(); + + s << size; /* redundent data but makes streaming easier */ + KeyList k = d.getKeys(); + + KeyListIterator it(k); + + while(it.current()) { + s << (Q_UINT16)it.currentKey(); + s << d.getField(it.currentKey()); + ++it; + } + return s; +} + +QDataStream &operator>>( QDataStream &s, DataElem &d) +{ + int i; + int size; + TVVariant t; + int index = 0; + + s >> size; /* redundent data but makes streaming easier */ + if (size != d.getNumFields()) { + qWarning("DataSize mis-match"); + return s; /* sanity check failed.. don't load */ + } + + for(i = 0; i < size; i++) { + s >> (Q_UINT16)index; + s >> t; + d.setField(index, t); + } + return s; +} + +/*! Returns the number of possible (not valid) fields in the data element */ +int DataElem::getNumFields() const +{ + return contained->getNumFields(); +} + +KeyList DataElem::getKeys() const +{ + return *(contained->getKeys()); +} + +/*! + This function determines whether field index i of the element has been + set yet. + + \return A boolean value that is TRUE if the specfied field of this + element has been set and FALSE if the field has not yet been set +*/ +bool DataElem::hasValidValue(int i) const +{ + if(!values.find(i)) + return FALSE; + if(!contained->getKeys()->validIndex(i)) + return FALSE; + return values.find(i)->isValid(); +} + +/*! + This function determines whether field name qs of the element has been + set yet. + + \return A boolean value that is TRUE if the specfied field of this + element has been set and FALSE if the field has not yet been set +*/ +bool DataElem::hasValidValue(QString qs) const +{ + int i = contained->getKeyIndex(qs); + return hasValidValue(i); +} + +/*! returns the type of the field specified by index i */ +TVVariant::KeyType DataElem::getFieldType(int i) const +{ + return contained->getKeyType(i); +} + +/*! returns the type of the field specified by name qs */ +TVVariant::KeyType DataElem::getFieldType(QString qs) const +{ + int i = contained->getKeyIndex(qs); + return contained->getKeyType(i); +} + +/*! + returns a pointer to the data stored in field index i for this + data element, (value may not be valid) +*/ +TVVariant DataElem::getField(int i) const +{ + if(hasValidValue(i)) + return TVVariant(*values.find(i)); + return TVVariant(); +} + +/*! + returns a pointer to the data stored in field name qs for this + data element, (value may not be valid) +*/ +TVVariant DataElem::getField(QString qs) const +{ + int i = contained->getKeyIndex(qs); + return getField(i); +} + +/*! + Sets the value of the elements field index i to the value represented in + the QString q. + + \param i index of the field to set + \param q a string that can be parsed to get the value to be set +*/ +void DataElem::setField(int i, QString q) +{ + /* from the type of the field, parse q and store */ + TVVariant::KeyType kt = contained->getKeyType(i); + + TVVariant t = TVVariant(q); + + switch(kt) { + case TVVariant::Int: { + t.asInt(); + setField(i, t); + return; + } + case TVVariant::String: { + t.asString(); + setField(i, t); + return; + } + case TVVariant::Date: { + t.asDate(); + setField(i, t); + return; + } + case TVVariant::Time: { + t.asTime(); + setField(i, t); + return; + } + default: + qWarning( + QObject::tr("DataElem::setField(%1, %2) No valid type found").arg(i).arg(q) + ); + } +} + +/*! + Sets the value of the elements field index i to the value at the pointer + value. + + \param i index of the field to set + \param value a pointer to the (already allocated) value to set +*/ +void DataElem::setField(int i, TVVariant value) +{ + if (value.isValid()) { + values.remove(i); + values.replace(i, new TVVariant(value)); + } +} + +/*! + Sets the value of the elements field name qs to the value represented in + the QString q. + + \param qs name of the field to set + \param q a string that can be parsed to get the value to be set +*/ +void DataElem::setField(QString qs, QString q) +{ + /* from the type of the field, parse q and store */ + int i = contained->getKeyIndex(qs); + setField(i, qs); +} + +/*! + Sets the value of the elements field name qs to the value at the pointer + value. + + \param qs name of the field to set + \param value a pointer to the (already allocated) value to set +*/ +void DataElem::setField(QString qs, TVVariant value) +{ + int i = contained->getKeyIndex(qs); + setField(i, value); +} + +void DataElem::unsetField(int i) { + values.remove(i); +} + +void DataElem::unsetField(QString qs) +{ + int i = contained->getKeyIndex(qs); + unsetField(i); +} + +/*! + Converts the data element to a Rich Text QString +*/ +QString DataElem::toQString() const +{ + /* lets make an attempt at this function */ + int i; + QString scratch = ""; + + QIntDictIterator<TVVariant> it(values); + + while (it.current()) { + i = it.currentKey(); + if(hasValidValue(i)) { + scratch += "<B>" + contained->getKeyName(i) + ":</B> "; + scratch += getField(i).toString(); + scratch += "<br>"; + } + ++it; + } + return scratch; +} + +/*! formats individual fields to strings so can be displayed */ +QString DataElem::toQString(int i) const +{ + if(hasValidValue(i)) { + return getField(i).toString(); + } + return ""; +} +/*! formats individual fields to strings so can be sorted by QListView */ +QString DataElem::toSortableQString(int i) const +{ + QString scratch = ""; + if(hasValidValue(i)) { + switch (contained->getKeyType(i)) { + case TVVariant::String: { + scratch += getField(i).toString(); + break; + } + case TVVariant::Int: { + scratch.sprintf("%08d", getField(i).toInt()); + break; + } + case TVVariant::Date: { + static QDate epochD(1800, 1, 1); + scratch.sprintf("%08d", + epochD.daysTo(getField(i).toDate())); + break; + } + case TVVariant::Time: { + static QTime epochT(0, 0, 0); + scratch.sprintf("%08d", + epochT.msecsTo(getField(i).toTime())); + break; + } + default: + scratch += "Unknown type"; + break; + } + } + return scratch; +} + +/* compare functions */ + +bool DataElem::lessThan(int i, TVVariant v) const +{ + if (!hasValidValue(i)) return FALSE; + + if (getField(i).type() != v.type()) + return FALSE; + + return (getField(i) < v); +} + +bool DataElem::moreThan(int i, TVVariant v) const +{ + if (!hasValidValue(i)) return FALSE; + + if (getField(i).type() != v.type()) + return FALSE; + + return (getField(i) > v); +} + +bool DataElem::equalTo(int i, TVVariant v) const +{ + if (!hasValidValue(i)) return FALSE; + + if (getField(i).type() != v.type()) + return FALSE; + + return (getField(i) == v); +} + +bool DataElem::contains(int i, TVVariant v) const +{ + if (!hasValidValue(i)) return FALSE; + + if (getField(i).type() != v.type()) + return FALSE; + + switch(getField(i).type()) { + case TVVariant::String: { + QString qs1 = getField(i).toString().lower(); + QString qs2 = v.toString().lower(); + if (qs1.contains(qs2) > 0) return TRUE; + break; + } + /* meaningless for ints */ + /* meaningless for time */ + /* meaningless for dates */ + case TVVariant::Int: + case TVVariant::Time: + case TVVariant::Date: + break; + default: + qWarning("Tried to compare unknown data type"); + } + return FALSE; +} + +bool DataElem::startsWith(int i, TVVariant v) const +{ + if (!hasValidValue(i)) return FALSE; + + if (getField(i).type() != v.type()) + return FALSE; + + switch(getField(i).type()) { + case TVVariant::String: { + QString qs1 = getField(i).toString().lower(); + QString qs2 = v.toString().lower(); + return qs1.startsWith(qs2); + } + /* meaningless for ints */ + /* meaningless for time */ + /* meaningless for dates */ + case TVVariant::Int: + case TVVariant::Time: + case TVVariant::Date: + return FALSE; + default: + qWarning("Tried to compare unknown data type"); + } + return FALSE; +} + +bool DataElem::endsWith(int i, TVVariant v) const +{ + if (!hasValidValue(i)) return FALSE; + + if (getField(i).type() != v.type()) + return FALSE; + + switch(getField(i).type()) { + case TVVariant::String: { + QString qs1 = getField(i).toString().lower(); + QString qs2 = v.toString().lower(); + return qs1.startsWith(qs2); + } + /* meaningless for ints */ + /* meaningless for time */ + /* meaningless for dates */ + case TVVariant::Int: + case TVVariant::Time: + case TVVariant::Date: + return FALSE; + default: + qWarning("Tried to compare unknown data type"); + } + return FALSE; +} + +/*! + Determins which of the first to parameters are closer to the third, target + parameter. + + \return + <UL> + <LI>TRUE if the first element is a closer match to the target than the + second element</LI> + <LI>FALSE if the first element is not a closer match to the target than + the second element</LI> + </UL> +*/ +bool DataElem::closer(DataElem*d1, DataElem *d2, TVVariant target, int column) +{ + int type; + + if(!d1) return FALSE; + + if (!d1->hasValidValue(column)) return FALSE; + + if(!target.isValid()) return FALSE; + + type = d1->getField(column).type(); + + if(d2) { + if (type != d2->getField(column).type()) { + /* can't do compare */ + qWarning("Tried to compare two incompatable types"); + return FALSE; + } + return target.closer(d1->getField(column), d2->getField(column)); + } + return target.close(d1->getField(column)); +} |