diff options
author | Michael Brasser <michael.brasser@nokia.com> | 2009-04-22 04:47:24 (GMT) |
---|---|---|
committer | Michael Brasser <michael.brasser@nokia.com> | 2009-04-22 04:47:24 (GMT) |
commit | 2366667fc97eb6a56203b2dd7dac776ff4164abd (patch) | |
tree | b2acb6cc6bfe475d7e619e4788973b61fff775e0 /src/declarative/extra | |
parent | 2c762f3b8b284a7c6dc0c499b7052013bad5b707 (diff) | |
download | Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.zip Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.tar.gz Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.tar.bz2 |
Initial import of kinetic-dui branch from the old kinetic
Diffstat (limited to 'src/declarative/extra')
-rw-r--r-- | src/declarative/extra/extra.pri | 24 | ||||
-rw-r--r-- | src/declarative/extra/qfxintegermodel.cpp | 126 | ||||
-rw-r--r-- | src/declarative/extra/qfxintegermodel.h | 86 | ||||
-rw-r--r-- | src/declarative/extra/qmlnumberformatter.cpp | 214 | ||||
-rw-r--r-- | src/declarative/extra/qmlnumberformatter.h | 92 | ||||
-rw-r--r-- | src/declarative/extra/qmlsqlconnection.cpp | 441 | ||||
-rw-r--r-- | src/declarative/extra/qmlsqlconnection.h | 117 | ||||
-rw-r--r-- | src/declarative/extra/qmlsqlquery.cpp | 696 | ||||
-rw-r--r-- | src/declarative/extra/qmlsqlquery.h | 143 | ||||
-rw-r--r-- | src/declarative/extra/qmlxmllistmodel.cpp | 357 | ||||
-rw-r--r-- | src/declarative/extra/qmlxmllistmodel.h | 139 | ||||
-rw-r--r-- | src/declarative/extra/qnumberformat.cpp | 224 | ||||
-rw-r--r-- | src/declarative/extra/qnumberformat.h | 172 |
13 files changed, 2831 insertions, 0 deletions
diff --git a/src/declarative/extra/extra.pri b/src/declarative/extra/extra.pri new file mode 100644 index 0000000..83978f1 --- /dev/null +++ b/src/declarative/extra/extra.pri @@ -0,0 +1,24 @@ +SOURCES += \ + extra/qnumberformat.cpp \ + extra/qmlnumberformatter.cpp \ + extra/qfxintegermodel.cpp + +HEADERS += \ + extra/qnumberformat.h \ + extra/qmlnumberformatter.h \ + extra/qfxintegermodel.h + +contains(QT_CONFIG, xmlpatterns) { + QT+=xmlpatterns + SOURCES += extra/qmlxmllistmodel.cpp + HEADERS += extra/qmlxmllistmodel.h +} + +# SQL is permanently enabled :-/ +#contains(QT_CONFIG, sql) { + QT+= sql + SOURCES += extra/qmlsqlquery.cpp \ + extra/qmlsqlconnection.cpp + HEADERS += extra/qmlsqlquery.h \ + extra/qmlsqlconnection.h +#} diff --git a/src/declarative/extra/qfxintegermodel.cpp b/src/declarative/extra/qfxintegermodel.cpp new file mode 100644 index 0000000..3c4d0d9 --- /dev/null +++ b/src/declarative/extra/qfxintegermodel.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfxintegermodel.h" + + +QT_BEGIN_NAMESPACE +QML_DEFINE_TYPE(QFxIntegerModel, IntegerModel); + +class QFxIntegerModelPrivate +{ +public: + QFxIntegerModelPrivate() : min(0), max(0) {} + int min; + int max; +}; + +QFxIntegerModel::QFxIntegerModel(QObject *parent) + : QListModelInterface(parent) +{ + d = new QFxIntegerModelPrivate; +} + +QFxIntegerModel::~QFxIntegerModel() +{ + delete d; +} + +int QFxIntegerModel::minimum() const +{ + return d->min; +} + +void QFxIntegerModel::setMinimum(int min) +{ + d->min = min; +} + +int QFxIntegerModel::maximum() const +{ + return d->max; +} + +void QFxIntegerModel::setMaximum(int max) +{ + d->max = max; +} + +int QFxIntegerModel::count() const +{ + return qMax(0, d->max - d->min + 1); +} + +QHash<int,QVariant> QFxIntegerModel::data(int index, const QList<int> &roles) const +{ + QHash<int,QVariant> returnHash; + + for (int i = 0; i < roles.size(); ++i) { + int role = roles.at(i); + QVariant info; + switch(role) { + case Qt::DisplayRole: + info = QVariant(QString::number(d->min+index)); + break; + default: + break; + } + returnHash.insert(role, info); + } + return returnHash; +} + +QString QFxIntegerModel::toString(int role) const +{ + switch(role) { + case Qt::DisplayRole: + return QLatin1String("display"); + default: + return QLatin1String(""); + } +} + +QList<int> QFxIntegerModel::roles() const +{ + return QList<int>() << Qt::DisplayRole; +} + +QT_END_NAMESPACE diff --git a/src/declarative/extra/qfxintegermodel.h b/src/declarative/extra/qfxintegermodel.h new file mode 100644 index 0000000..3a48a56 --- /dev/null +++ b/src/declarative/extra/qfxintegermodel.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFXINTMODEL_H +#define QFXINTMODEL_H + +#include <QObject> +#include "qml.h" +#include <qlistmodelinterface.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) +class QFxIntegerModelPrivate; +class Q_DECLARATIVE_EXPORT QFxIntegerModel : public QListModelInterface +{ + Q_OBJECT +public: + QFxIntegerModel(QObject *parent=0); + ~QFxIntegerModel(); + + Q_PROPERTY(int minimum READ minimum WRITE setMinimum); + int minimum() const; + void setMinimum(int); + + Q_PROPERTY(int maximum READ maximum WRITE setMaximum); + int maximum() const; + void setMaximum(int); + + int count() const; + QHash<int, QVariant> data(int index, const QList<int> &roles) const; + QList<int> roles() const; + QString toString(int role) const; + +private: + QFxIntegerModelPrivate *d; +}; + +QML_DECLARE_TYPE(QFxIntegerModel); + + +QT_END_NAMESPACE + +QT_END_HEADER +#endif diff --git a/src/declarative/extra/qmlnumberformatter.cpp b/src/declarative/extra/qmlnumberformatter.cpp new file mode 100644 index 0000000..a12c4e6 --- /dev/null +++ b/src/declarative/extra/qmlnumberformatter.cpp @@ -0,0 +1,214 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlnumberformatter.h" +#include "private/qobject_p.h" + + +QT_BEGIN_NAMESPACE +//TODO: set locale +// docs +// this is a wrapper around qnumberformat (test integration) +// if number or format haven't been explictly set, text should be an empty string + +class QmlNumberFormatterPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlNumberFormatter) +public: + QmlNumberFormatterPrivate() : locale(QLocale::system()), number(0), classComplete(true) {} + + void updateText(); + + QLocale locale; + QString format; + QNumberFormat numberFormat; + QString text; + qreal number; + bool classComplete; +}; +/*! + \qmlclass NumberFormatter + \brief The NumberFormatter allows you to control the format of a number string. + + The format property documentation has more details on how the format can be manipulated. + + In the following example, the text element will display the text "1,234.57". + \code + <NumberFormatter id="Formatter" number="1234.5678" format="##,##0.##"/> + <Text text="{Formatter.text}"/> + \endcode + + */ +/*! + \class QmlNumberFormatter + \ingroup utility + \brief The QmlNumberFormatter class allows you to format a number to a particular string format/locale specific number format. +*/ + +QmlNumberFormatter::QmlNumberFormatter(QObject *parent) +: QObject(*(new QmlNumberFormatterPrivate), parent) +{ +} + +QmlNumberFormatter::~QmlNumberFormatter() +{ +} + +/*! + \qmlproperty string NumberFormatter::text + + The number in the specified format. + <br> + If no format is specified the text will be empty. +*/ + +QString QmlNumberFormatter::text() const +{ + Q_D(const QmlNumberFormatter); + return d->text; +} + +/*! + \qmlproperty qreal NumberFormatter::number + + A single point precision number. (Doubles are not yet supported) + +*/ +qreal QmlNumberFormatter::number() const +{ + Q_D(const QmlNumberFormatter); + return d->number; +} + +/*! + \qmlproperty string NumberFormatter::format + + The particular format the number will adhere to during the conversion to text. + <br> + The format syntax follows a style similar to the Unicode Standard (UTS35). + + The table below shows the characters, patterns that can be used in the format. + + <table border="0" align="center"> + <tr style="background-color: #D6E2E8"><th> Character </th><th> Meaning </th></tr> + <tr><td> # </td><td> Any digit(s), zero shows as absent (for leading/trailing zeroes) </td></tr> + <tr><td> 0 </td><td> Implicit digit. Zero will show in the case that the input number is too small.</td></tr> + <tr><td> . </td><td> Decimal separator. Output decimal seperator will be dependant on system locale.</td></tr> + <tr><td> , </td><td> Grouping separator. The number of digits (either #, or 0) between the grouping separator and the decimal (or the rightmost digit) will determine the groupingSize)</td></tr> + <tr><td> other </td><td> Any other character will be taken as a string literal and placed directly into the output string </td></tr> + </table> + + Invalid formats will not guarantee a meaningful text output.<br> + + \note <i>Input numbers that are too long for the given format will be rounded dependent on precison based on the position of the decimal point </i> + + The following table illustrates the output text created by applying some examples of numeric formats to the formatter. + + <table border="0" align="center"> + <tr style="background-color: #D6E2E8"><th> Format </th><th> Number </th><th> Output </th></tr> + <tr><td> ### </td><td> 123456 </td><td> 123456 </td></tr> + <tr><td> 000 </td><td> 123456 </td><td> 123456 </td></tr> + <tr><td> ###### </td><td> 1234 </td><td> 1234 </td></tr> + <tr><td> 000000 </td><td> 1234 </td><td> 001234 </td></tr> + <tr><td> ##,##0.## </td><td> 1234.456 </td><td> 1,234.46 (for US locale)<br> 1 234,46 (for FR locale)</td></tr> + <tr><td> 000000,000.# </td><td> 123456 </td><td> 000,123,456 (for US locale)<br> 000 123 456 (for FR locale)</td></tr> + <tr><td> 0.0### </td><td> 0.999997 </td><td> 1.0 </td></tr> + <tr><td> (000) 000 - 000 </td><td> 12345678 </td><td> (012) 345 - 678 </td></tr> + <tr><td> #A</td><td>12</td><td>12A</td></tr> + </table> + +*/ +QString QmlNumberFormatter::format() const +{ + Q_D(const QmlNumberFormatter); + return d->format; +} + +void QmlNumberFormatter::setNumber(const qreal &number) +{ + Q_D(QmlNumberFormatter); + if (d->number == number) + return; + d->number = number; + d->updateText(); +} + +void QmlNumberFormatter::setFormat(const QString &format) +{ + Q_D(QmlNumberFormatter); + //no format checking + if (format.isEmpty()) + d->format = QString::null; + else + d->format = format; + d->updateText(); +} + +void QmlNumberFormatterPrivate::updateText() +{ + Q_Q(QmlNumberFormatter); + if (!classComplete) + return; + + QNumberFormat tempFormat; + tempFormat.setFormat(format); + tempFormat.setNumber(number); + + text = tempFormat.text(); + + emit q->textChanged(); +} + +void QmlNumberFormatter::classBegin() +{ + Q_D(QmlNumberFormatter); + d->classComplete = false; +} + +void QmlNumberFormatter::classComplete() +{ + Q_D(QmlNumberFormatter); + d->classComplete = true; + d->updateText(); +} + +QML_DEFINE_TYPE(QmlNumberFormatter, NumberFormatter); +QT_END_NAMESPACE diff --git a/src/declarative/extra/qmlnumberformatter.h b/src/declarative/extra/qmlnumberformatter.h new file mode 100644 index 0000000..e053be5 --- /dev/null +++ b/src/declarative/extra/qmlnumberformatter.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLNUMBERFORMATTER_H +#define QMLNUMBERFORMATTER_H + +#include <qml.h> +#include "qnumberformat.h" + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) +class QmlNumberFormatterPrivate; +class Q_DECLARATIVE_EXPORT QmlNumberFormatter : public QObject, public QmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QmlParserStatus) + + Q_PROPERTY(QString text READ text NOTIFY textChanged) + Q_PROPERTY(QString format READ format WRITE setFormat) + Q_PROPERTY(qreal number READ number WRITE setNumber) +public: + QmlNumberFormatter(QObject *parent=0); + ~QmlNumberFormatter(); + + QString text() const; + + qreal number() const; + void setNumber(const qreal &); + + QString format() const; + void setFormat(const QString &); + + virtual void classBegin(); + virtual void classComplete(); + +Q_SIGNALS: + void textChanged(); + +private: + Q_DISABLE_COPY(QmlNumberFormatter) + Q_DECLARE_PRIVATE(QmlNumberFormatter) +}; + +QML_DECLARE_TYPE(QmlNumberFormatter); + + +QT_END_NAMESPACE + +QT_END_HEADER +#endif diff --git a/src/declarative/extra/qmlsqlconnection.cpp b/src/declarative/extra/qmlsqlconnection.cpp new file mode 100644 index 0000000..3e2032c --- /dev/null +++ b/src/declarative/extra/qmlsqlconnection.cpp @@ -0,0 +1,441 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlsqlconnection.h" +#include "private/qobject_p.h" + +#include <QSqlError> +#include <QSqlDriver> +#include <QDebug> + +#include <qml.h> +#include <qmlcontext.h> + +QT_BEGIN_NAMESPACE + +QML_DEFINE_TYPE(QmlSqlConnection, SqlConnection); + +class QmlSqlConnectionPrivate: public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlSqlConnection) +public: + QmlSqlConnectionPrivate() : port(0) {} + + int port; + QString name, databaseName, connectionOptions; + QString hostName, userName, password, driver; + QmlContext *context; +}; + +/*! + \qmlclass SqlConnection QmlSqlConnection + \brief The SqlConnection element describes a connection to an SQL database. +*/ + +/*! + \qmlproperty QString SqlConnection::name + \default + + Defines the connection's name. The name allows the connection to be + retrieved using the connection property of SqlQuery or when + QSqlDatabase::database() +*/ + +/*! + \qmlproperty QStringList SqlConnection::tables + + Defines the set of tables that exist in the database for the connection. +*/ + +/*! + \qmlproperty QString SqlConnection::databaseName + + Defines the connection's database name. This is used when opening the + connection to the database. +*/ + +/*! + \qmlproperty QString SqlConnection::driver + + Defines the driver type of the connection. This is used when opening the + connection to the database. +*/ + +/*! + \qmlproperty QString SqlConnection::connectOptions + + Defines the options used when connecting to the database. These are used + when opening the connection to the database. +*/ + +/*! + \qmlproperty QString SqlConnection::hostName + + Defines the connection's host name. This is used when opening the + connection to the database. +*/ + +/*! + \qmlproperty int SqlConnection::port + + Defines the connection's port number. This is used when opening the + connection to the database. +*/ + +/*! + \qmlproperty QString SqlConnection::userName + + Defines the connection's user name. This is used when opening the + connection to the database. +*/ + +/*! + \qmlproperty QString SqlConnection::password + + Defines the connection's password. This is used when opening the + connection to the database. +*/ + +/*! + \qmlproperty QString SqlConnection::lastError + + Defines the last error, if one occurred, when working with the database. + If the error occurred in conjunction with an SQL query the error will be + defined by SqlQuery::lastError. +*/ + +/*! + \class QmlSqlConnection + \brief The QmlSqlConnection class manages a connection to an SQL database. + + \qmltext + + The SqlConnection element works in a similar way to + QSqlDatabase::addDatabase(). It allows setting the database properties + such that the connection does not need to be set up in C++ code. + It differs from QSqlDatabase::addDatabase() in that it will automatically + open the database. + + The database can then either be used from an SqlQuery element using its id + as a bind, or using its name. If the database is set up externally to + Qml the query should connect using its name. + + \qml + <SqlConnection id="myConnection"> + <name>qmlConnection</name> + <driver>QSQLITE</driver> + <databaseName>"mydb.sqlite"</databaseName> + </SqlConnection> + <SqlQuery id="listmodel" connection="{myConnection}">SELECT * FROM mytable</SqlQuery> + <SqlQuery id="othermodel" connection="qmlConnection">SELECT * FROM myothertable</SqlQuery> + \endqml + + \endqmltext +*/ + +/*! + Constructs a QmlSqlConnection with the given \a parent. +*/ +QmlSqlConnection::QmlSqlConnection(QObject *parent) +: QObject(*(new QmlSqlConnectionPrivate), parent) +{ + Q_D(QmlSqlConnection); + d->context = QmlContext::activeContext(); +} + +/*! + Destroys the QmlSqlConnection. +*/ +QmlSqlConnection::~QmlSqlConnection() +{ + QSqlDatabase db = database(); + if (db.isOpen()) + db.close(); +} + +/*! + Returns the connection's name. + This is equivalent to QSqlDatabase::connectionName(). + \sa setName() +*/ +QString QmlSqlConnection::name() const +{ + Q_D(const QmlSqlConnection); + return d->name; +} + +/*! + Returns the connection's database name. + This is equivalent to QSqlDatabase::databaseName(). + \sa setDatabaseName() +*/ +QString QmlSqlConnection::databaseName() const +{ + Q_D(const QmlSqlConnection); + return d->databaseName; +} + +/*! + Returns the connect options string used for this connection. + + \sa setConnectOptions() +*/ +QString QmlSqlConnection::connectOptions() const +{ + Q_D(const QmlSqlConnection); + return d->connectionOptions; +} + +/*! + Returns the connection's host name. + \sa setHostName() +*/ +QString QmlSqlConnection::hostName() const +{ + Q_D(const QmlSqlConnection); + return d->hostName; +} + +/*! + Returns the connection's port number. The value is undefined if the port + number has not been set. + + \sa setPort() +*/ +int QmlSqlConnection::port() const +{ + Q_D(const QmlSqlConnection); + return d->port; +} + +/*! + Returns the connection's user name. + + \sa setUserName() +*/ +QString QmlSqlConnection::userName() const +{ + Q_D(const QmlSqlConnection); + return d->userName; +} + +/*! + Returns the connection's password. + + \sa setPassword)() +*/ +QString QmlSqlConnection::password() const +{ + Q_D(const QmlSqlConnection); + return d->password; +} + +/*! + Returns the connection's driver name. + + \sa setDriver() +*/ +QString QmlSqlConnection::driver() const +{ + Q_D(const QmlSqlConnection); + return d->driver; +} + +/*! + Returns a list of the database's tables. +*/ +QStringList QmlSqlConnection::tables() const +{ + return database().tables(); +} + +/*! + Sets the connection's name to the given \a name. + + \sa name() +*/ +void QmlSqlConnection::setName(const QString &name) +{ + Q_D(QmlSqlConnection); + d->name = name; +} + +/*! + Set's the connection's database name to the given \a name. + + \sa databaseName() +*/ +void QmlSqlConnection::setDatabaseName(const QString &name) +{ + Q_D(QmlSqlConnection); + d->databaseName = name; +} + +/*! + Sets the connection's options to the given \a options. + + \sa connectOptions(), QSqlDatabase::setConnectOptions() +*/ +void QmlSqlConnection::setConnectOptions(const QString &options) +{ + Q_D(QmlSqlConnection); + d->connectionOptions = options; +} + +/*! + Sets the connection's host name to the given \a name. + + \sa hostName() +*/ +void QmlSqlConnection::setHostName(const QString &name) +{ + Q_D(QmlSqlConnection); + d->hostName = name; +} + +/*! + Sets the connection's port number to the given \a port. + + \sa port() +*/ +void QmlSqlConnection::setPort(int port) +{ + Q_D(QmlSqlConnection); + d->port = port; +} + +/*! + Sets the connection's user name to the given \a name. + + \sa userName() +*/ +void QmlSqlConnection::setUserName(const QString &name) +{ + Q_D(QmlSqlConnection); + d->userName = name; +} + +/*! + Sets the connection's password to the given \a password. + + \sa password() +*/ +void QmlSqlConnection::setPassword(const QString &password) +{ + Q_D(QmlSqlConnection); + d->password = password; +} + +/*! + Returns information about the last error that occurred on the database. + + Failures that occur in conjunction with an individual query are + reported by QmlSqlQuery::lastError() +*/ +QString QmlSqlConnection::lastError() const +{ + return database().lastError().text(); +} + +/*! + Sets the connection's driver to the specified driver \a type. + + \sa driver(), QSqlDatabase::addDatabase() +*/ +void QmlSqlConnection::setDriver(const QString &type) +{ + Q_D(QmlSqlConnection); + d->driver = type; +} + +/*! + \reimp +*/ +void QmlSqlConnection::classComplete() +{ +} + +/*! + Returns the database object associated with this connection. + If the database is not yet open, it will open the database + passed on the settings specified for the SQL connection. +*/ +QSqlDatabase QmlSqlConnection::database() const +{ + Q_D(const QmlSqlConnection); + + QSqlDatabase db; + if (QSqlDatabase::connectionNames().contains(d->name)) { + db = QSqlDatabase::database(d->name); + } else { + db = QSqlDatabase::addDatabase( + d->driver.isEmpty() + ? QLatin1String("QSQLITE") + : d->driver, + d->name.isEmpty() + ? QLatin1String(QSqlDatabase::defaultConnection) + : d->name); + } + if (db.isOpen()) + return db; + if ((d->driver.isEmpty() || d->driver == QLatin1String("QSQLITE")) && d->context) { + // SQLITE uses files for databases, hence use relative pathing + // if possible. + QUrl url = d->context->resolvedUrl(d->databaseName); + if (url.isRelative() || url.scheme() == QLatin1String("file")) + db.setDatabaseName(url.toLocalFile()); + else + db.setDatabaseName(d->databaseName); + } else { + db.setDatabaseName(d->databaseName); + } + db.setConnectOptions(d->connectionOptions); + db.setHostName(d->hostName); + db.setPassword(d->password); + db.setPort(d->port); + db.setUserName(d->userName); + if (!db.open()) + qWarning() << "Failed to open database" << lastError(); + + return db; +} + +QT_END_NAMESPACE diff --git a/src/declarative/extra/qmlsqlconnection.h b/src/declarative/extra/qmlsqlconnection.h new file mode 100644 index 0000000..2cc5774 --- /dev/null +++ b/src/declarative/extra/qmlsqlconnection.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLSQLCONNECTION_H +#define QMLSQLCONNECTION_H + +#include <qml.h> +#include <QSqlDatabase> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) +class QSqlDatabase; +class QmlSqlConnectionPrivate; +class Q_DECLARATIVE_EXPORT QmlSqlConnection : public QObject, public QmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QmlParserStatus) + + Q_PROPERTY(QString name READ name WRITE setName); + Q_PROPERTY(QStringList tables READ tables); + Q_PROPERTY(QString databaseName READ databaseName WRITE setDatabaseName); + Q_PROPERTY(QString driver READ driver WRITE setDriver); + Q_PROPERTY(QString connectOptions READ connectOptions WRITE setConnectOptions); + Q_PROPERTY(QString hostName READ hostName WRITE setHostName); + Q_PROPERTY(int port READ port WRITE setPort); + Q_PROPERTY(QString userName READ userName WRITE setUserName); + Q_PROPERTY(QString password READ password WRITE setPassword); + Q_PROPERTY(QString lastError READ lastError); + Q_CLASSINFO("DefaultProperty", "name") +public: + QmlSqlConnection(QObject *parent = 0); + ~QmlSqlConnection(); + + QString name() const; + void setName(const QString &); + + QStringList tables() const; + + QString databaseName() const; + void setDatabaseName(const QString &); + + QString connectOptions() const; + void setConnectOptions(const QString &); + + QString hostName() const; + void setHostName(const QString &); + + int port() const; + void setPort(int); + + QString userName() const; + void setUserName(const QString &); + + QString password() const; + void setPassword(const QString &); + + QString driver() const; + void setDriver(const QString &); + + QString lastError() const; + + virtual void classComplete(); + + QSqlDatabase database() const; +private: + Q_DISABLE_COPY(QmlSqlConnection) + Q_DECLARE_PRIVATE(QmlSqlConnection) +}; + +QML_DECLARE_TYPE(QmlSqlConnection); + +QT_END_NAMESPACE + +QT_END_HEADER +#endif // QMLXMLLISTMODEL_H + diff --git a/src/declarative/extra/qmlsqlquery.cpp b/src/declarative/extra/qmlsqlquery.cpp new file mode 100644 index 0000000..39d3aa2 --- /dev/null +++ b/src/declarative/extra/qmlsqlquery.cpp @@ -0,0 +1,696 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlsqlquery.h" +#include "qmlsqlconnection.h" +#include "private/qobject_p.h" + +#include <QDebug> +#include <QSqlQuery> +#include <QSqlError> +#include <QSqlField> +#include <QSqlRecord> +#include <QSqlDatabase> +#include <QSqlDriver> + +QT_BEGIN_NAMESPACE +QML_DEFINE_TYPE(QmlSqlBind, SqlBind); +QML_DEFINE_TYPE(QmlSqlQuery, SqlQuery); + +class QmlSqlBindPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlSqlBind) +public: + QmlSqlBindPrivate() {} + + QString name; + QVariant value; +}; + +/*! + \qmlclass SqlBind QmlSqlBind + \brief the SqlBind element specifies a value binding for an SqlQuery element. +*/ + +/*! + \class QmlSqlBind + \brief the QmlSqlBind class specifies a value binding for a QmlSqlQuery. + + \qmltext + + \qml + By using bindings its possible to cause a SqlQuery to update itself + when values bound through the SqlBind change. Hence in the example + below the results for the SqlQuery will change as searchText changes. + + If the query is not a SELECT statement, the effects of the bound + values will only apply when the SqlQuery exec() slot is called. + + <SqlQuery> + SELECT * FROM mytable WHERE name LIKE :value + <bindings> + <SqlBind name=":value" value="{searchText + '%'}"/> + </bindings> + </SqlQuery> + <SqlQuery> + SELECT * FROM mytable WHERE type = ? + <bindings> + <SqlBind value="simple"/> + </bindings> + <SqlQuery> + \endqml + \endqmltext +*/ + +/*! + \fn void QmlSqlBind::valueChanged() + + This signal is emitted when the value property of the SqlBind changes. +*/ + +/*! + \qmlproperty QString SqlBind::name + + Defines the placeholder name of the bind. If no name is specified the + bind will use its position within the SqlQuery's bindings to bind + into the query. +*/ + +/*! + \qmlproperty QVariant SqlBind::value + + Defines the value to bind into the query. +*/ + +/*! + Constructs a QmlSqlVind with the given \a parent +*/ +QmlSqlBind::QmlSqlBind(QObject *parent) +: QObject(*(new QmlSqlBindPrivate()), parent) +{ +} + +/*! + Destroys the QmlSqlBind. +*/ +QmlSqlBind::~QmlSqlBind() +{ +} + +/*! + Returns the binding's name. + + \sa setName() +*/ +QString QmlSqlBind::name() const +{ + Q_D(const QmlSqlBind); + return d->name; +} + +/*! + Returns the binding's value. + + \sa setValue() +*/ +QVariant QmlSqlBind::value() const +{ + Q_D(const QmlSqlBind); + return d->value; +} + +/*! + Sets the binding's name to the given \a name. + + \sa name() +*/ +void QmlSqlBind::setName(const QString &name) +{ + Q_D(QmlSqlBind); + d->name = name; +} + +/*! + Sets the binding's value to the given \a value. + + \sa value() +*/ +void QmlSqlBind::setValue(const QVariant &value) +{ + Q_D(QmlSqlBind); + if (d->value != value) { + d->value = value; + emit valueChanged(); + } +} + +/*! + \reimp +*/ +void QmlSqlBind::classComplete() +{ +} + +class QmlSqlQueryPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlSqlQuery) +public: + QmlSqlQueryPrivate(QmlSqlQuery *owner) : isSel(false), query(NULL), requireCache(false), count(-1), binds(owner) {} + void prepareQuery() const; + void bindQuery() const; + void cacheQuery() const; + void grabRoles() const; + + QString queryText; + bool isSel; + QVariant connectionVariant; + mutable QSqlQuery *query; + mutable bool requireCache; + mutable int count; + mutable QList<int> roles; + mutable QStringList roleNames; + mutable QVector< QVector< QVariant > > cache; + + class QmlSqlBindList : public QmlList<QmlSqlBind *> + { + public: + QmlSqlBindList(QmlSqlQuery *owner) + : q(owner){} + + void append(QmlSqlBind *o) { + m_contents.append(o); + QObject::connect(o, SIGNAL(valueChanged()), q, SLOT(resetBinds())); + } + void clear() { m_contents.clear(); } + int count() const { return m_contents.count(); } + void removeAt(int pos) { return m_contents.removeAt(pos); } + QmlSqlBind *at(int pos) const { return m_contents.at(pos); } + void insert(int pos, QmlSqlBind *o) { m_contents.insert(pos, o); } + private: + QList<QmlSqlBind *> m_contents; + QmlSqlQuery *q; + }; + + QmlSqlBindList binds; +}; + +/*! + \qmlclass SqlQuery QmlSqlQuery + \brief The SqlQuery element describes a query into an SQL database. +*/ + +/* + \class QmlSqlQuery + \brief the QmlSqlQuery class manages a query into an SQL database. + + \qmltext + The SqlQuery element has three parts. The first is the query itself, + which can either be specified using the query property or by the + default text for the element. The second specifies the connection + to the database. This can either be a bound id from an SqlConnection + or the connections name. If the connection is specified in a QML + SqlConnection it is recommend to bind to the id to help ensure the + database is complete before attempting to attach to it. If no + connectoin is specified the default connection is used. + + It is also possible to bind values into the query using the bindings + property. See SqlBind for more information on how to bind values into + the query. + + If the query is a select statement it can be used as a model for a ListView. + The roles will be the columns of the result set. Use the SQL AS keyword + in the query if you want to override the column names from that of the + table selected. You should also use the AS keyword if there is no + appropriate table column name for the result column. + + \qml + <SqlQuery connection="{qmlConnectionId}" query="DELETE FROM mytable"/> + <SqlQuery connection="connectionName"> + SELECT * FROM mytable + </SqlQuery> + <SqlQuery>SELECT id AS recordId, (firstName || ' ' || lastName) AS fullName FROM mytable</SqlQuery> + \endqml + \endqmltext +*/ + +/*! + \qmlproperty QString SqlQuery::query + \default + + Defines the query text. +*/ + +/*! + \qmlproperty QVariant SqlQuery::connection + + Defines the connection to an SQL database used by the query. +*/ + +/*! + \qmlproperty QString SqlQuery::lastError + + Defines the last error, if one occurred, when working with the query. +*/ + +/*! + \qmlproperty list<SqlBind> SqlQuery::bindings + + The bindings property contains the list of values to bind into the + query. See SqlBind for more information. +*/ + +/*! + Constructs a QmlSqlQuery with the given \a parent. +*/ +QmlSqlQuery::QmlSqlQuery(QObject *parent) +: QListModelInterface(*(new QmlSqlQueryPrivate(this)), parent) +{ +} + +/*! + Destroys the QmlSqlQuery. +*/ +QmlSqlQuery::~QmlSqlQuery() +{ + Q_D(QmlSqlQuery); + if (d->query) + delete d->query; +} + +/*! + Returns the query's bound variables. +*/ +QmlList<QmlSqlBind *> *QmlSqlQuery::bindings() +{ + Q_D(QmlSqlQuery); + return &d->binds; +} + +/*! + Returns the query's bound variables. +*/ +const QmlList<QmlSqlBind *> *QmlSqlQuery::bindings() const +{ + Q_D(const QmlSqlQuery); + return &d->binds; +} + +/*! + Returns the query text. + + \sa setQuery() +*/ +QString QmlSqlQuery::query() const +{ + Q_D(const QmlSqlQuery); + return d->queryText; +} + +/*! + Sets the query text to the given \a text. +*/ +void QmlSqlQuery::setQuery(const QString &text) +{ + Q_D(QmlSqlQuery); + if (text != d->queryText) { + d->queryText = text; + + static const QLatin1String select("select"); + d-> isSel = text.trimmed().indexOf(select, 0, Qt::CaseInsensitive) == 0; + + if (d->query) + resetQuery(); + } +} + +/*! + Returns the query's connection specifier. + + \sa setConnection() +*/ +QVariant QmlSqlQuery::connection() const +{ + Q_D(const QmlSqlQuery); + return d->connectionVariant; +} + +/*! + Sets the query's connection specifier. + + \sa connection() +*/ +void QmlSqlQuery::setConnection(const QVariant &connection) +{ + Q_D(QmlSqlQuery); + if (connection != d->connectionVariant) { + d->connectionVariant = connection; + if (d->query) + resetQuery(); + else if (d->count == 0) // data has been requested + d->prepareQuery(); + } +} + +/*! + Returns the set of values for a given set of requested \a roles for the + specified \a row of the query result set. Returns an empty hash if the + query is not a select statement. + + \sa count(), roles(), toString() +*/ +QHash<int,QVariant> QmlSqlQuery::data(int row, const QList<int> &roles) const +{ + Q_D(const QmlSqlQuery); + if (!d->query) + d->prepareQuery(); + QHash<int, QVariant> result; + + if (!d->isSel) + return result; + + Q_ASSERT(row >= 0 && row <= d->count); + + if (!d->requireCache) + d->query->seek(row); + + for (int i = 0; i < roles.count(); ++i) { + int column = roles[i]; + Q_ASSERT(column >= 0 && column < d->cache.size()); + if (d->requireCache) + result.insert(column, d->cache[column].at(row)); + else + result.insert(column, d->query->value(column)); + } + return result; +} + +/*! + Returns the number of rows in the query result set. Returns 0 if + the query is not a select statement. + + \sa data(), roles(), toString() +*/ +int QmlSqlQuery::count() const +{ + Q_D(const QmlSqlQuery); + if (!d->query) + d->prepareQuery(); + return d->count; +} + +/*! + Returns the list of role integer identifiers for the query result set. + Returns and empty list if the query is not a select statement. + + \sa data(), count(), toString() +*/ +QList<int> QmlSqlQuery::roles() const +{ + Q_D(const QmlSqlQuery); + if (!d->query) + d->prepareQuery(); + + if (!d->isSel) + return QList<int>(); + + if (d->roleNames.isEmpty() && !d->requireCache) { + d->query->seek(0); + d->grabRoles(); + } + + return d->roles; +} + +/*! + Returns the corresponding role name for the given \a role identifier. + + \sa data(), roles(), toString() +*/ +QString QmlSqlQuery::toString(int role) const +{ + Q_D(const QmlSqlQuery); + if (!d->query) + d->prepareQuery(); + + if (d->roleNames.isEmpty() && !d->requireCache) { + d->query->seek(0); + d->grabRoles(); + } + + return d->roleNames[role]; +} + +/*! + Returns information about the last error that occurred on the query. +*/ +QString QmlSqlQuery::lastError() const +{ + Q_D(const QmlSqlQuery); + if (d->query) + return d->query->lastError().text(); + return QString(); +} + +/*! + \reimp +*/ +void QmlSqlQuery::classComplete() +{ + Q_D(QmlSqlQuery); + if (!d->query) + d->prepareQuery(); +} + +/*! + \internal + Rebinds the query, and if needed, emits rows inserted or rows + added so any attached ListView elements will correctly. + + This slot is called automatically when the SqlBind elements in + the bindings property of the query change. +*/ +void QmlSqlQuery::resetBinds() +{ + Q_D(QmlSqlQuery); + if (!d->query) + return; + int oldcount = d->count; + d->cache.resize(0); + d->roles.clear(); + d->roleNames.clear(); + d->bindQuery(); + if (d->isSel) { + if (!d->query->isActive()) { + if (!d->query->exec()) + qWarning() << "failed to execute query" << d->query->lastQuery() << d->query->boundValues() << d->query->lastError().text(); + } + d->cacheQuery(); // may finish query + emitChanges(oldcount); + } +} + +/*! + Executes the query. For SELECT statements this is normally only required + if the database changes outside of the SQL query element. Statements that + modify the database, such as UPDATE and INSERT, will not be applied until + this function is called. +*/ +void QmlSqlQuery::exec() +{ + Q_D(QmlSqlQuery); + if (!d->query) + d->prepareQuery(); + Q_ASSERT(d->query); + + if (d->isSel) { + int oldcount = d->count; + d->cache.resize(0); + d->roles.clear(); + d->roleNames.clear(); + if (!d->query->exec()) + qWarning() << "failed to execute query" << d->query->lastQuery() << d->query->boundValues() << d->query->lastError().text(); + d->cacheQuery(); // may finish query + emitChanges(oldcount); + } else { + if (!d->query->exec()) + qWarning() << "failed to execute query" << d->query->lastQuery() << d->query->boundValues() << d->query->lastError().text(); + d->query->finish(); + } +} + +/*! + \internal + + Resets the query and query cache. +*/ +void QmlSqlQuery::resetQuery() +{ + Q_D(QmlSqlQuery); + Q_ASSERT(d->query != 0); + delete d->query; + d->query = 0; + d->cache.resize(0); + d->roles.clear(); + d->roleNames.clear(); + int oldcount = d->count; + d->prepareQuery(); + emitChanges(oldcount); +} + +/*! + \internal + + emits row number changes based of differences between the given + \a oldcount and the current count of the query result set. +*/ +void QmlSqlQuery::emitChanges(int oldcount) +{ + Q_D(QmlSqlQuery); + if (d->count > oldcount) + emit itemsInserted(oldcount, d->count-oldcount); + else if (d->count < oldcount) + emit itemsRemoved(d->count, oldcount-d->count); + if (d->count > 0 && oldcount > 0) + emit itemsChanged(0, qMin(d->count, oldcount), roles()); +} + +/* + Prepares the query. If the query starts with SELECT it is assumed to + be a SELECT statement and the query is also executed. +*/ +void QmlSqlQueryPrivate::prepareQuery() const +{ + QObject *object = qvariant_cast<QObject*>(connectionVariant); + QmlSqlConnection *connection = qobject_cast<QmlSqlConnection *>(object); + QString connectionString = qvariant_cast<QString>(connectionVariant); + + Q_ASSERT(query == 0); + QSqlDatabase db = connection ? connection->database() + : QSqlDatabase::database(connectionString.isEmpty() + ? QLatin1String(QSqlDatabase::defaultConnection) + : connectionString, false); + + if (!db.isOpen()) { + count = 0; + return; + } + + query = new QSqlQuery(db); + + requireCache = + query->driver()->hasFeature(QSqlDriver::SimpleLocking) + || !query->driver()->hasFeature(QSqlDriver::QuerySize); + + if (requireCache) + query->setForwardOnly(true); + if (!query->prepare(queryText)) + qWarning() << "failed to prepare query" << query->lastQuery() << query->lastError().text(); + bindQuery(); + if (isSel) { + if (!query->exec()) + qWarning() << "failed to execute query" << query->lastQuery() << query->boundValues() << query->lastError().text(); + cacheQuery(); + } +} + +/* + Binds values into the prepared query using the bindings property of the SqlQuery element. +*/ +void QmlSqlQueryPrivate::bindQuery() const +{ + for (int i = 0; i < binds.count(); ++i) { + QmlSqlBind *bind = binds.at(i); + if (bind->name().isEmpty()) { + query->bindValue(i, bind->value()); + } else { + query->bindValue(bind->name(), bind->value()); + } + } +} + +/* + If the query is connected to a database with simple locking or + that cannot ask for the count of a result set, caches the required + data of the query and finishes the query to release locks. + + Otherwise just caches the count of the query. +*/ +void QmlSqlQueryPrivate::cacheQuery() const +{ + if (requireCache) { + int row = 0; + while (query->next()) { + if (roleNames.isEmpty()) { + grabRoles(); + cache.resize(roleNames.count()); + } + Q_ASSERT(cache.size() > 0); + for (int i = 0; i < cache.size(); ++i) { + cache[i].append(query->value(i)); + } + row++; + } + count = row; + query->finish(); + } else { + count = query->size(); + } +} + +/* + Gets the column names for the roles of the SqlQuery element. + + The query must be active and on a valid row. +*/ +void QmlSqlQueryPrivate::grabRoles() const +{ + Q_ASSERT(query); + Q_ASSERT(query->isValid()); + Q_ASSERT(roleNames.isEmpty()); + Q_ASSERT(roles.isEmpty()); + + QSqlRecord record = query->record(); + for (int i = 0; i < record.count(); ++i) { + roleNames.append(record.fieldName(i)); + roles.append(i); + } +} +QT_END_NAMESPACE diff --git a/src/declarative/extra/qmlsqlquery.h b/src/declarative/extra/qmlsqlquery.h new file mode 100644 index 0000000..984483c --- /dev/null +++ b/src/declarative/extra/qmlsqlquery.h @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLSQLQUERYMODEL_H +#define QMLSQLQUERYMODEL_H + +#include <qml.h> +#include <QListModelInterface> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlSqlBindPrivate; +class Q_DECLARATIVE_EXPORT QmlSqlBind : public QObject, public QmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QmlParserStatus) + + Q_PROPERTY(QString name READ name WRITE setName) + Q_PROPERTY(QVariant value READ value WRITE setValue) + + Q_CLASSINFO("DefaultValue", "value"); + +public: + QmlSqlBind(QObject *parent = 0); + ~QmlSqlBind(); + + QString name() const; + QVariant value() const; + + void setName(const QString &name); + void setValue(const QVariant &); + + virtual void classComplete(); + +Q_SIGNALS: + void valueChanged(); + +private: + Q_DISABLE_COPY(QmlSqlBind) + Q_DECLARE_PRIVATE(QmlSqlBind) +}; + +QML_DECLARE_TYPE(QmlSqlBind); + +class QSqlQuery; +class QmlSqlQueryPrivate; +class Q_DECLARATIVE_EXPORT QmlSqlQuery : public QListModelInterface, public QmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QmlParserStatus) + + Q_PROPERTY(QString query READ query WRITE setQuery) + Q_PROPERTY(QVariant connection READ connection WRITE setConnection) + Q_PROPERTY(QString lastError READ lastError) + + Q_PROPERTY(QmlList<QmlSqlBind *> *bindings READ bindings) + + Q_CLASSINFO("DefaultProperty", "query") +public: + QmlSqlQuery(QObject *parent = 0); + ~QmlSqlQuery(); + + QString query() const; + void setQuery(const QString &); + + QVariant connection() const; + void setConnection(const QVariant &); + + virtual QHash<int,QVariant> data(int index, const QList<int> &roles = (QList<int>())) const; + virtual int count() const; + virtual QList<int> roles() const; + virtual QString toString(int role) const; + + QString lastError() const; + + virtual void classComplete(); + + QmlList<QmlSqlBind *> *bindings(); + const QmlList<QmlSqlBind *> *bindings() const; + +public slots: + void exec(); + +private slots: + void resetBinds(); + void resetQuery(); + +private: + void emitChanges(int oldcount); + + Q_DISABLE_COPY(QmlSqlQuery) + Q_DECLARE_PRIVATE(QmlSqlQuery) +}; + +QML_DECLARE_TYPE(QmlSqlQuery); + +QT_END_NAMESPACE + +QT_END_HEADER +#endif + diff --git a/src/declarative/extra/qmlxmllistmodel.cpp b/src/declarative/extra/qmlxmllistmodel.cpp new file mode 100644 index 0000000..13faab2 --- /dev/null +++ b/src/declarative/extra/qmlxmllistmodel.cpp @@ -0,0 +1,357 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlxmllistmodel.h" +#include "private/qobject_p.h" + +#include <QtDeclarative/qmlcontext.h> +#include <QtDeclarative/qmlengine.h> +#include <QDebug> +#include <QXmlQuery> +#include <QXmlResultItems> +#include <QXmlNodeModelIndex> +#include <QBuffer> +#include <QNetworkRequest> +#include <QNetworkReply> + +QT_BEGIN_NAMESPACE + +QML_DEFINE_TYPE(XmlListModelRole, Role); +QML_DEFINE_TYPE(QmlXmlListModel, XmlListModel); + +//TODO: do something smart while waiting for data to load +// error handling (currently quite fragile) +// profile doQuery and doSubquery +// some sort of loading indication while we wait for initial data load (status property similar to QWebImage?) +// support complex/nested objects? +// how do we handle data updates (like rss feed -- usually items inserted at beginning) + +/*! + \qmlclass XmlListModel + \brief The XmlListModel class allows you to specify a model using XQuery. + + XmlListModel allows you to construct a model from XML data that can then be used as a data source + for the view classes (ListView, PathView, GridView) and any other classes that interact with model + data (like Repeater). + + The following is an example of a model containing news from a Yahoo RSS feed: + \qml + <XmlListModel id="FeedModel" src="http://rss.news.yahoo.com/rss/oceania" query="doc($src)/rss/channel/item"> + <Role name="title" query="title/string()"/> + <Role name="link" query="link/string()"/> + <Role name="description" query="description/string()" isCData="true"/> + </XmlListModel> + \endqml + \note The model is currently static, so the above is really just a snapshot of an RSS feed. +*/ + +class QmlXmlListModelPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlXmlListModel) +public: + QmlXmlListModelPrivate() : size(-1), highestRole(Qt::UserRole), reply(0), context(0), roleObjects(this) {} + + QString src; + QString query; + QString namespaces; + QList<int> roles; + QStringList roleNames; + mutable QList<QList<QVariant> > data; + int size; + int highestRole; + QNetworkReply *reply; + mutable QByteArray xml; + QString prefix; + QmlContext *context; + + struct RoleList : public QmlConcreteList<XmlListModelRole *> + { + RoleList(QmlXmlListModelPrivate *p) + : model(p) {} + virtual void append(XmlListModelRole *role) { + QmlConcreteList<XmlListModelRole *>::append(role); + model->roles << model->highestRole; + model->roleNames << role->name(); + ++model->highestRole; + } + //XXX clear, removeAt, and insert need to invalidate any cached data (in data table) as well + // (and the model should emit the appropriate signals) + virtual void clear() + { + model->roles.clear(); + model->roleNames.clear(); + QmlConcreteList<XmlListModelRole *>::clear(); + } + virtual void removeAt(int i) + { + model->roles.removeAt(i); + model->roleNames.removeAt(i); + QmlConcreteList<XmlListModelRole *>::removeAt(i); + } + virtual void insert(int i, XmlListModelRole *role) + { + QmlConcreteList<XmlListModelRole *>::insert(i, role); + model->roles.insert(i, model->highestRole); + model->roleNames.insert(i, role->name()); + ++model->highestRole; + } + + QmlXmlListModelPrivate *model; + }; + + RoleList roleObjects; +}; + +QmlXmlListModel::QmlXmlListModel(QObject *parent) + : QListModelInterface(*(new QmlXmlListModelPrivate), parent) +{ + Q_D(QmlXmlListModel); + d->context = QmlContext::activeContext(); +} + +QmlXmlListModel::~QmlXmlListModel() +{ +} + +QmlList<XmlListModelRole *> *QmlXmlListModel::roleObjects() +{ + Q_D(QmlXmlListModel); + return &d->roleObjects; +} + +QHash<int,QVariant> QmlXmlListModel::data(int index, const QList<int> &roles) const +{ + Q_D(const QmlXmlListModel); + QHash<int, QVariant> rv; + + if (index > d->data.count() - 1) + doSubquery(index); + + for (int i = 0; i < roles.size(); ++i) { + int role = roles.at(i); + int roleIndex = d->roles.indexOf(role); + rv.insert(role, d->data.at(index).at(roleIndex)); + } + return rv; +} + +int QmlXmlListModel::count() const +{ + Q_D(const QmlXmlListModel); + return d->size; +} + +QList<int> QmlXmlListModel::roles() const +{ + Q_D(const QmlXmlListModel); + return d->roles; +} + +QString QmlXmlListModel::toString(int role) const +{ + Q_D(const QmlXmlListModel); + int index = d->roles.indexOf(role); + if (index == -1) + return QString(); + return d->roleNames.at(index); +} + +QString QmlXmlListModel::src() const +{ + Q_D(const QmlXmlListModel); + return d->src; +} + +void QmlXmlListModel::setSrc(const QString &src) +{ + Q_D(QmlXmlListModel); + d->src = src; +} + +QString QmlXmlListModel::query() const +{ + Q_D(const QmlXmlListModel); + return d->query; +} + +void QmlXmlListModel::setQuery(const QString &query) +{ + Q_D(QmlXmlListModel); + d->query = query; +} + +QString QmlXmlListModel::namespaceDeclarations() const +{ + Q_D(const QmlXmlListModel); + return d->namespaces; +} + +void QmlXmlListModel::setNamespaceDeclarations(const QString &declarations) +{ + Q_D(QmlXmlListModel); + d->namespaces = declarations; +} + +void QmlXmlListModel::classComplete() +{ + fetch(); +} + +void QmlXmlListModel::fetch() +{ + Q_D(QmlXmlListModel); + if (d->src.isEmpty()) { + qWarning() << "Can't fetch empty src string"; + //clear existing data? + //int count = d->data.count(); + //d->data.clear(); + //emit itemsRemoved(0, count); + return; + } + + QNetworkRequest req((QUrl(d->src))); + req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + d->reply = d->context->engine()->networkAccessManager()->get(req); + QObject::connect(d->reply, SIGNAL(finished()), + this, SLOT(requestFinished())); +} + +void QmlXmlListModel::requestFinished() +{ + Q_D(QmlXmlListModel); + if(d->reply->error() != QNetworkReply::NoError) { + d->reply->deleteLater(); + d->reply = 0; + } else { + QByteArray data = d->reply->readAll(); + doQuery(data); + d->reply->deleteLater(); + d->reply = 0; + } +} + +void QmlXmlListModel::doQuery(QByteArray &rawData) +{ + Q_D(QmlXmlListModel); + QString r; + QXmlQuery query; + QBuffer rawBuffer(&rawData); + rawBuffer.open(QIODevice::ReadOnly); + query.bindVariable(QLatin1String("src"), &rawBuffer); + query.setQuery(d->namespaces + d->query); + query.evaluateTo(&r); + //qDebug() << r; + + //always need a single root element + QByteArray xml = "<dummy:items xmlns:dummy=\"http://qtsotware.com/dummy\">\n" + r.toUtf8() + "</dummy:items>"; + QBuffer b(&xml); + b.open(QIODevice::ReadOnly); + //qDebug() << xml; + + QString namespaces = QLatin1String("declare namespace dummy=\"http://qtsotware.com/dummy\";\n") + d->namespaces; + QString prefix = QLatin1String("doc($inputDocument)/dummy:items") + + d->query.mid(d->query.lastIndexOf(QLatin1Char('/'))); + + //figure out how many items we are dealing with + int count = -1; + { + QXmlResultItems result; + QXmlQuery countquery; + countquery.bindVariable(QLatin1String("inputDocument"), &b); + countquery.setQuery(namespaces + QLatin1String("count(") + prefix + QLatin1String(")")); + countquery.evaluateTo(&result); + QXmlItem item(result.next()); + if (item.isAtomicValue()) + count = item.toAtomicValue().toInt(); + b.seek(0); + prefix += QLatin1String("[%1]/"); + } + //qDebug() << count; + + QXmlQuery subquery; + subquery.bindVariable(QLatin1String("inputDocument"), &b); + d->prefix = namespaces + prefix; + d->xml = xml; + + d->size = count; + emit itemsInserted(0, count); +} + +void QmlXmlListModel::doSubquery(int index) const +{ + Q_D(const QmlXmlListModel); + //qDebug() << "doSubQuery" << index; + QBuffer b(&d->xml); + b.open(QIODevice::ReadOnly); + + QXmlQuery subquery; + subquery.bindVariable(QLatin1String("inputDocument"), &b); + + //XXX should we use an array of objects or something else rather than a table? + for (int j = d->data.count(); j <= index; ++j) { + QList<QVariant> resultList; + for (int i = 0; i < d->roleObjects.size(); ++i) { + XmlListModelRole *role = d->roleObjects.at(i); + subquery.setQuery(d->prefix.arg(j+1) + role->query()); + if (role->isStringList()) { + QStringList data; + subquery.evaluateTo(&data); + resultList << QVariant(data); + //qDebug() << data; + } else { + QString s; + subquery.evaluateTo(&s); + if (role->isCData()) { + //un-escape + s.replace(QLatin1String("<"), QLatin1String("<")); + s.replace(QLatin1String(">"), QLatin1String(">")); + s.replace(QLatin1String("&"), QLatin1String("&")); + } + resultList << s; + //qDebug() << s; + } + b.seek(0); + } + d->data << resultList; + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/extra/qmlxmllistmodel.h b/src/declarative/extra/qmlxmllistmodel.h new file mode 100644 index 0000000..a8f3087 --- /dev/null +++ b/src/declarative/extra/qmlxmllistmodel.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLXMLLISTMODEL_H +#define QMLXMLLISTMODEL_H + +#include <qml.h> +#include <QListModelInterface> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlContext; +class Q_DECLARATIVE_EXPORT XmlListModelRole : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString name READ name WRITE setName) + Q_PROPERTY(QString query READ query WRITE setQuery) + Q_PROPERTY(bool isCData READ isCData WRITE setIsCData) + Q_PROPERTY(bool isStringList READ isStringList WRITE setIsStringList) + +public: + XmlListModelRole() : m_isList(false), m_isCData(false) {} + ~XmlListModelRole() {} + + QString name() const { return m_name; } + void setName(const QString &name) { m_name = name; } + + QString query() const { return m_query; } + void setQuery(const QString &query) { m_query = query; } + + bool isStringList() const { return m_isList; } + void setIsStringList(bool b) { m_isList = b; } + + bool isCData() const { return m_isCData; } + void setIsCData(bool b) { m_isCData = b; } + +private: + QString m_name; + QString m_query; + bool m_isList; + bool m_isCData; +}; +QML_DECLARE_TYPE(XmlListModelRole); + +class QmlXmlListModelPrivate; +class Q_DECLARATIVE_EXPORT QmlXmlListModel : public QListModelInterface, public QmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QmlParserStatus) + + Q_PROPERTY(QString src READ src WRITE setSrc) + Q_PROPERTY(QString query READ query WRITE setQuery) + Q_PROPERTY(QString namespaceDeclarations READ namespaceDeclarations WRITE setNamespaceDeclarations) + Q_PROPERTY(QmlList<XmlListModelRole *> *roles READ roleObjects) + Q_CLASSINFO("DefaultProperty", "roles") +public: + QmlXmlListModel(QObject *parent = 0); + ~QmlXmlListModel(); + + virtual QHash<int,QVariant> data(int index, const QList<int> &roles = (QList<int>())) const; + virtual int count() const; + virtual QList<int> roles() const; + virtual QString toString(int role) const; + + QmlList<XmlListModelRole *> *roleObjects(); + + QString src() const; + void setSrc(const QString&); + + QString query() const; + void setQuery(const QString&); + + QString namespaceDeclarations() const; + void setNamespaceDeclarations(const QString&); + + virtual void classComplete(); + void fetch(); + +protected: + void doQuery(QByteArray &rawData); + void doSubquery(int index) const; + +private Q_SLOTS: + void requestFinished(); + +private: + Q_DECLARE_PRIVATE(QmlXmlListModel) + Q_DISABLE_COPY(QmlXmlListModel) +}; + +QML_DECLARE_TYPE(QmlXmlListModel); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLXMLLISTMODEL_H diff --git a/src/declarative/extra/qnumberformat.cpp b/src/declarative/extra/qnumberformat.cpp new file mode 100644 index 0000000..79e328a --- /dev/null +++ b/src/declarative/extra/qnumberformat.cpp @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnumberformat.h" + + +QT_BEGIN_NAMESPACE +QML_DEFINE_TYPE(QNumberFormat,NumberFormat); + +QNumberFormat::QNumberFormat(QObject *parent) : QObject(parent), _number(0), _type(Decimal), + _groupingSize(0) +{ + _locale = QLocale::system(); + _groupingSeparator = _locale.groupSeparator(); + _decimalSeparator = _locale.decimalPoint(); + _currencySymbol = QLatin1Char('$'); +} + +QNumberFormat::~QNumberFormat() +{ + +} + +void QNumberFormat::updateText() +{ + QTime t; + t.start(); + static int totalTime; + + handleFormat(); + + totalTime += t.elapsed(); + emit textChanged(); +} + +void QNumberFormat::handleFormat() +{ + // ### is extremely messy + if (_format.isEmpty()) { + _text = QString(QLatin1String("%1")).arg(_number, -1, 'f', -1); + return; + } + + QString inputString; + + // ### possible to use the following parsed data in the future + + int remainingLength = _format.size(); + int currentIndex = _format.size()-1; + + int maxDigits = 0; + int minDigits = 0; + int decimalLength = 0; + + while (remainingLength > 0) { + switch(_format.at(currentIndex).unicode()) { + case ',': + if (decimalLength && !_groupingSize) + setGroupingSize(maxDigits - decimalLength); + else if (!_groupingSize) + setGroupingSize(maxDigits); + break; + case '.': + if (!decimalLength) + decimalLength = maxDigits; + break; + case '0': + minDigits++; + case '#': + maxDigits++; + break; + default: + break; + } + currentIndex--; + remainingLength--; + } + + // round given the decimal length/precision + inputString = QString(QLatin1String("%1")).arg(_number, -1, 'f', decimalLength); + + QStringList parts = inputString.split(QLatin1Char('.')); + QStringList formatParts = _format.split(QLatin1Char('.')); + + if (formatParts.size() > 2 || parts.size() > 2 ) + return; + + QString formatInt = formatParts.at(0); + + QString formatDec; + if (formatParts.size() == 2) + formatDec = formatParts.at(1); + + QString integer = parts.at(0); + + QString decimal; + if (parts.size() == 2) + decimal = parts.at(1); + + QString outputDecimal = formatDecimal(formatDec, decimal); + QString outputInteger = formatInteger(formatInt, integer); + + // insert separators + if (_groupingSize) { + unsigned int count = 0; + for (int i = outputInteger.size()-1; i > 0; i--) { + if (outputInteger.at(i).digitValue() >= 0) { + if (count == _groupingSize - 1) { + count = 0; + outputInteger.insert(i, _groupingSeparator); + } + else + count++; + } + } + } + if (!outputDecimal.isEmpty()) + _text = outputInteger + _decimalSeparator + outputDecimal; + else + _text = outputInteger; +} + +QString QNumberFormat::formatInteger(const QString &formatInt, const QString &integer) +{ + if (formatInt.isEmpty() || integer.isEmpty()) + return QString(); + + QString outputInteger; + int formatIndex = formatInt.size()-1; + + //easier for carry? + for (int index= integer.size()-1; index >= 0; index--) { + if (formatIndex < 0) { + outputInteger.push_front(integer.at(index)); + } + else { + switch(formatInt.at(formatIndex).unicode()) { + case '0': + if (index > integer.size()-1) { + outputInteger.push_front(QLatin1Char('0')); + break; + } + case '#': + outputInteger.push_front(integer.at(index)); + break; + case ',': + index++; + break; + default: + outputInteger.push_front(formatInt.at(formatIndex)); + index++; + break; + } + formatIndex--; + } + } + while (formatIndex >= 0) { + if (formatInt.at(formatIndex).unicode() != '#' && formatInt.at(formatIndex).unicode() != ',') + outputInteger.push_front(formatInt.at(formatIndex)); + formatIndex--; + } + return outputInteger; +} + +QString QNumberFormat::formatDecimal(const QString &formatDec, const QString &decimal) +{ + QString outputDecimal; + + // up to max 6 decimal places + for (int index=formatDec.size()-1; index >= 0; index--) { + switch(formatDec.at(index).unicode()) { + case '0': + outputDecimal.push_front(decimal.at(index)); + break; + case '#': + if (decimal.at(index) != QLatin1Char('0') || outputDecimal.size() > 0) + outputDecimal.push_front(decimal.at(index)); + break; + default: + outputDecimal.push_front(formatDec.at(index)); + break; + } + } + return outputDecimal; +} +QT_END_NAMESPACE diff --git a/src/declarative/extra/qnumberformat.h b/src/declarative/extra/qnumberformat.h new file mode 100644 index 0000000..6ee333c --- /dev/null +++ b/src/declarative/extra/qnumberformat.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NUMBERFORMAT_H +#define NUMBERFORMAT_H + +#include "qml.h" +#include <QtGui> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +// TODO +// be able to set Locale, instead of default system for dynamic formatting +// add currency support +// add additional syntax, extend to format scientific, percentiles, significant digits etc + + +class QNumberFormat : public QObject +{ + Q_OBJECT + Q_ENUMS(NumberType) +public: + QNumberFormat(QObject *parent=0); + ~QNumberFormat(); + + enum NumberType { + Percent, + Scientific, + Currency, + Decimal + }; + + //external property, only visible + Q_PROPERTY(QString text READ text NOTIFY textChanged); + + //mutatable properties to modify the output (text) + Q_PROPERTY(qreal number READ number WRITE setNumber); + Q_PROPERTY(QString format READ format WRITE setFormat); + Q_PROPERTY(QLocale locale READ locale WRITE setLocale); + + //Format specific settings + Q_PROPERTY(unsigned short groupingSeparator READ groupingSeparator WRITE setGroupingSeparator); + Q_PROPERTY(unsigned short decimalSeperator READ decimalSeparator WRITE setDecimalSeparator); + Q_PROPERTY(unsigned int groupingSize READ groupingSize WRITE setGroupingSize); + Q_PROPERTY(unsigned short currencySymbol READ currencySymbol WRITE setCurrencySymbol); + + + QString text() const { return _text; } + + qreal number() const { return _number; } + void setNumber(qreal n) { + if (_number == n) + return; + _number = n; + updateText(); + } + + QString format() const { return _format; } + void setFormat(const QString &format) { + if (format.isEmpty()) + _format = QString::null; + else if (_format == format) + return; + + _format = format; + updateText(); + } + + QLocale locale() const { return _locale; } + void setLocale(const QLocale &locale) { _locale = locale; updateText(); } + + //Do we deal with unicode standard? or create our own + // ### since this is the backend for the number conversions, we will use the unicode + // the front-end will handle the QChar/QString -> short int + + unsigned short groupingSeparator() { return _groupingSeparator.unicode(); } + void setGroupingSeparator(unsigned short unicodeSymbol) + { + _groupingSeparator = QChar(unicodeSymbol); + } + + unsigned short decimalSeparator() { return _decimalSeparator.unicode(); } + void setDecimalSeparator(unsigned short unicodeSymbol) + { + _decimalSeparator = QChar(unicodeSymbol); + } + + unsigned short currencySymbol() { return _currencySymbol.unicode(); } + void setCurrencySymbol(unsigned short unicodeSymbol) + { + _currencySymbol = QChar(unicodeSymbol); + } + + unsigned int groupingSize() { return _groupingSize; } + void setGroupingSize(unsigned int size) + { + _groupingSize = size; + } + +Q_SIGNALS: + void textChanged(); + +private: + void updateText(); + void handleFormat(); + QString formatInteger(const QString &formatInt, const QString &integer); + QString formatDecimal(const QString &formatDec, const QString &decimal); + + qreal _number; + NumberType _type; + QChar _groupingSeparator; + QChar _decimalSeparator; + QChar _currencySymbol; + unsigned int _groupingSize; + + QLocale _locale; + QString _format; + + // only hooked member at the moment + QString _text; + +}; +QML_DECLARE_TYPE(QNumberFormat); + + +QT_END_NAMESPACE + +QT_END_HEADER +#endif |