Fixed rounding errors in QtQuick1 to int conversions
[qt:qt.git] / src / declarative / qml / qdeclarativestringconverters.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "private/qdeclarativestringconverters_p.h"
43
44 #include <QtGui/qcolor.h>
45 #include <QtGui/qvector3d.h>
46 #include <QtCore/qpoint.h>
47 #include <QtCore/qrect.h>
48 #include <QtCore/qsize.h>
49 #include <QtCore/qvariant.h>
50 #include <QtCore/qdatetime.h>
51
52 QT_BEGIN_NAMESPACE
53
54 static uchar fromHex(const uchar c, const uchar c2)
55 {
56     uchar rv = 0;
57     if (c >= '0' && c <= '9')
58         rv += (c - '0') * 16;
59     else if (c >= 'A' && c <= 'F')
60         rv += (c - 'A' + 10) * 16;
61     else if (c >= 'a' && c <= 'f')
62         rv += (c - 'a' + 10) * 16;
63
64     if (c2 >= '0' && c2 <= '9')
65         rv += (c2 - '0');
66     else if (c2 >= 'A' && c2 <= 'F')
67         rv += (c2 - 'A' + 10);
68     else if (c2 >= 'a' && c2 <= 'f')
69         rv += (c2 - 'a' + 10);
70
71     return rv;
72 }
73
74 static uchar fromHex(const QString &s, int idx)
75 {
76     uchar c = s.at(idx).toAscii();
77     uchar c2 = s.at(idx + 1).toAscii();
78     return fromHex(c, c2);
79 }
80
81 QVariant QDeclarativeStringConverters::variantFromString(const QString &s)
82 {
83     if (s.isEmpty())
84         return QVariant(s);
85     bool ok = false;
86     QRectF r = rectFFromString(s, &ok);
87     if (ok) return QVariant(r);
88     QColor c = colorFromString(s, &ok);
89     if (ok) return QVariant(c);
90     QPointF p = pointFFromString(s, &ok);
91     if (ok) return QVariant(p);
92     QSizeF sz = sizeFFromString(s, &ok);
93     if (ok) return QVariant(sz);
94     QVector3D v = vector3DFromString(s, &ok);
95     if (ok) return QVariant::fromValue(v);
96
97     return QVariant(s);
98 }
99
100 namespace {
101 int qRoundDouble(double d)
102 {
103     return d >= double(0.0) ? int(d + double(0.5)) : int(d - int(d-1) + double(0.5)) + int(d-1);
104 }
105 }
106 QVariant QDeclarativeStringConverters::variantFromString(const QString &s, int preferredType, bool *ok)
107 {
108     switch (preferredType) {
109     case QMetaType::Int:
110         return QVariant(int(qRoundDouble(s.toDouble(ok))));
111     case QMetaType::UInt:
112         return QVariant(uint(qRoundDouble(s.toDouble(ok))));
113     case QMetaType::QColor:
114         return QVariant::fromValue(colorFromString(s, ok));
115 #ifndef QT_NO_DATESTRING
116     case QMetaType::QDate:
117         return QVariant::fromValue(dateFromString(s, ok));
118     case QMetaType::QTime:
119         return QVariant::fromValue(timeFromString(s, ok));
120     case QMetaType::QDateTime:
121         return QVariant::fromValue(dateTimeFromString(s, ok));
122 #endif // QT_NO_DATESTRING
123     case QMetaType::QPointF:
124         return QVariant::fromValue(pointFFromString(s, ok));
125     case QMetaType::QPoint:
126         return QVariant::fromValue(pointFFromString(s, ok).toPoint());
127     case QMetaType::QSizeF:
128         return QVariant::fromValue(sizeFFromString(s, ok));
129     case QMetaType::QSize:
130         return QVariant::fromValue(sizeFFromString(s, ok).toSize());
131     case QMetaType::QRectF:
132         return QVariant::fromValue(rectFFromString(s, ok));
133     case QMetaType::QRect:
134         return QVariant::fromValue(rectFFromString(s, ok).toRect());
135     case QMetaType::QVector3D:
136         return QVariant::fromValue(vector3DFromString(s, ok));
137     default:
138         if (ok) *ok = false;
139         return QVariant();
140     }
141 }
142
143 QColor QDeclarativeStringConverters::colorFromString(const QString &s, bool *ok)
144 {
145     if (s.length() == 9 && s.startsWith(QLatin1Char('#'))) {
146         uchar a = fromHex(s, 1);
147         uchar r = fromHex(s, 3);
148         uchar g = fromHex(s, 5);
149         uchar b = fromHex(s, 7);
150         if (ok) *ok = true;
151         return QColor(r, g, b, a);
152     } else {
153         QColor rv(s);
154         if (ok) *ok = rv.isValid();
155         return rv;
156     }
157 }
158
159 #ifndef QT_NO_DATESTRING
160 QDate QDeclarativeStringConverters::dateFromString(const QString &s, bool *ok)
161 {
162     QDate d = QDate::fromString(s, Qt::ISODate);
163     if (ok) *ok =  d.isValid();
164     return d;
165 }
166
167 QTime QDeclarativeStringConverters::timeFromString(const QString &s, bool *ok)
168 {
169     QTime t = QTime::fromString(s, Qt::ISODate);
170     if (ok) *ok = t.isValid();
171     return t;
172 }
173
174 QDateTime QDeclarativeStringConverters::dateTimeFromString(const QString &s, bool *ok)
175 {
176     QDateTime d = QDateTime::fromString(s, Qt::ISODate);
177     if (ok) *ok =  d.isValid();
178     return d;
179 }
180 #endif // QT_NO_DATESTRING
181
182 //expects input of "x,y"
183 QPointF QDeclarativeStringConverters::pointFFromString(const QString &s, bool *ok)
184 {
185     if (s.count(QLatin1Char(',')) != 1) {
186         if (ok)
187             *ok = false;
188         return QPointF();
189     }
190
191     bool xGood, yGood;
192     int index = s.indexOf(QLatin1Char(','));
193     qreal xCoord = s.left(index).toDouble(&xGood);
194     qreal yCoord = s.mid(index+1).toDouble(&yGood);
195     if (!xGood || !yGood) {
196         if (ok)
197             *ok = false;
198         return QPointF();
199     }
200
201     if (ok)
202         *ok = true;
203     return QPointF(xCoord, yCoord);
204 }
205
206 //expects input of "widthxheight"
207 QSizeF QDeclarativeStringConverters::sizeFFromString(const QString &s, bool *ok)
208 {
209     if (s.count(QLatin1Char('x')) != 1) {
210         if (ok)
211             *ok = false;
212         return QSizeF();
213     }
214
215     bool wGood, hGood;
216     int index = s.indexOf(QLatin1Char('x'));
217     qreal width = s.left(index).toDouble(&wGood);
218     qreal height = s.mid(index+1).toDouble(&hGood);
219     if (!wGood || !hGood) {
220         if (ok)
221             *ok = false;
222         return QSizeF();
223     }
224
225     if (ok)
226         *ok = true;
227     return QSizeF(width, height);
228 }
229
230 //expects input of "x,y,widthxheight" //### use space instead of second comma?
231 QRectF QDeclarativeStringConverters::rectFFromString(const QString &s, bool *ok)
232 {
233     if (s.count(QLatin1Char(',')) != 2 || s.count(QLatin1Char('x')) != 1) {
234         if (ok)
235             *ok = false;
236         return QRectF();
237     }
238
239     bool xGood, yGood, wGood, hGood;
240     int index = s.indexOf(QLatin1Char(','));
241     qreal x = s.left(index).toDouble(&xGood);
242     int index2 = s.indexOf(QLatin1Char(','), index+1);
243     qreal y = s.mid(index+1, index2-index-1).toDouble(&yGood);
244     index = s.indexOf(QLatin1Char('x'), index2+1);
245     qreal width = s.mid(index2+1, index-index2-1).toDouble(&wGood);
246     qreal height = s.mid(index+1).toDouble(&hGood);
247     if (!xGood || !yGood || !wGood || !hGood) {
248         if (ok)
249             *ok = false;
250         return QRectF();
251     }
252
253     if (ok)
254         *ok = true;
255     return QRectF(x, y, width, height);
256 }
257
258 //expects input of "x,y,z"
259 QVector3D QDeclarativeStringConverters::vector3DFromString(const QString &s, bool *ok)
260 {
261     if (s.count(QLatin1Char(',')) != 2) {
262         if (ok)
263             *ok = false;
264         return QVector3D();
265     }
266
267     bool xGood, yGood, zGood;
268     int index = s.indexOf(QLatin1Char(','));
269     int index2 = s.indexOf(QLatin1Char(','), index+1);
270     qreal xCoord = s.left(index).toDouble(&xGood);
271     qreal yCoord = s.mid(index+1, index2-index-1).toDouble(&yGood);
272     qreal zCoord = s.mid(index2+1).toDouble(&zGood);
273     if (!xGood || !yGood || !zGood) {
274         if (ok)
275             *ok = false;
276         return QVector3D();
277     }
278
279     if (ok)
280         *ok = true;
281     return QVector3D(xCoord, yCoord, zCoord);
282 }
283
284 QT_END_NAMESPACE