1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qbs.
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 The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "propertydeclaration.h"
41 
42 #include "deprecationinfo.h"
43 #include <api/languageinfo.h>
44 
45 #include <logging/translator.h>
46 
47 #include <tools/error.h>
48 #include <tools/qttools.h>
49 #include <tools/stringconstants.h>
50 
51 #include <QtCore/qmetatype.h>
52 #include <QtCore/qshareddata.h>
53 #include <QtCore/qstringlist.h>
54 #include <QtCore/qvariant.h>
55 
56 namespace qbs {
57 namespace Internal {
58 
59 // returns QMetaType::UnknownType for types that do not need conversion
variantType(PropertyDeclaration::Type t)60 static QMetaType::Type variantType(PropertyDeclaration::Type t)
61 {
62     switch (t) {
63     case PropertyDeclaration::UnknownType:
64         break;
65     case PropertyDeclaration::Boolean:
66         return QMetaType::Bool;
67     case PropertyDeclaration::Integer:
68         return QMetaType::Int;
69     case PropertyDeclaration::Path:
70         return QMetaType::QString;
71     case PropertyDeclaration::PathList:
72         return QMetaType::QStringList;
73     case PropertyDeclaration::String:
74         return QMetaType::QString;
75     case PropertyDeclaration::StringList:
76         return QMetaType::QStringList;
77     case PropertyDeclaration::VariantList:
78         return QMetaType::QVariantList;
79     case PropertyDeclaration::Variant:
80         break;
81     }
82     return QMetaType::UnknownType;
83 }
84 
85 class PropertyDeclarationData : public QSharedData
86 {
87 public:
PropertyDeclarationData()88     PropertyDeclarationData()
89         : type(PropertyDeclaration::UnknownType)
90         , flags(PropertyDeclaration::DefaultFlags)
91     {
92     }
93 
94     QString name;
95     PropertyDeclaration::Type type;
96     PropertyDeclaration::Flags flags;
97     QStringList allowedValues;
98     QString description;
99     QString initialValueSource;
100     QStringList functionArgumentNames;
101     DeprecationInfo deprecationInfo;
102 };
103 
104 
PropertyDeclaration()105 PropertyDeclaration::PropertyDeclaration()
106     : d(new PropertyDeclarationData)
107 {
108 }
109 
PropertyDeclaration(const QString & name,Type type,const QString & initialValue,Flags flags)110 PropertyDeclaration::PropertyDeclaration(const QString &name, Type type,
111                                          const QString &initialValue, Flags flags)
112     : d(new PropertyDeclarationData)
113 {
114     d->name = name;
115     d->type = type;
116     d->initialValueSource = initialValue;
117     d->flags = flags;
118 }
119 
120 PropertyDeclaration::PropertyDeclaration(const PropertyDeclaration &other) = default;
121 
122 PropertyDeclaration::~PropertyDeclaration() = default;
123 
124 PropertyDeclaration &PropertyDeclaration::operator=(const PropertyDeclaration &other) = default;
125 
isValid() const126 bool PropertyDeclaration::isValid() const
127 {
128     return d && d->type != UnknownType;
129 }
130 
isScalar() const131 bool PropertyDeclaration::isScalar() const
132 {
133     // ### Should be determined by a PropertyOption in the future.
134     return d->type != PathList && d->type != StringList && d->type != VariantList;
135 }
136 
boolString()137 static QString boolString() { return QStringLiteral("bool"); }
intString()138 static QString intString() { return QStringLiteral("int"); }
pathListString()139 static QString pathListString() { return QStringLiteral("pathList"); }
stringString()140 static QString stringString() { return QStringLiteral("string"); }
stringListString()141 static QString stringListString() { return QStringLiteral("stringList"); }
varString()142 static QString varString() { return QStringLiteral("var"); }
variantString()143 static QString variantString() { return QStringLiteral("variant"); }
varListString()144 static QString varListString() { return QStringLiteral("varList"); }
145 
propertyTypeFromString(const QString & typeName)146 PropertyDeclaration::Type PropertyDeclaration::propertyTypeFromString(const QString &typeName)
147 {
148     if (typeName == boolString())
149         return PropertyDeclaration::Boolean;
150     if (typeName == intString())
151         return PropertyDeclaration::Integer;
152     if (typeName == StringConstants::pathType())
153         return PropertyDeclaration::Path;
154     if (typeName == pathListString())
155         return PropertyDeclaration::PathList;
156     if (typeName == stringString())
157         return PropertyDeclaration::String;
158     if (typeName == stringListString())
159         return PropertyDeclaration::StringList;
160     if (typeName == varString() || typeName == variantString())
161         return PropertyDeclaration::Variant;
162     if (typeName == varListString())
163         return PropertyDeclaration::VariantList;
164     return PropertyDeclaration::UnknownType;
165 }
166 
typeString() const167 QString PropertyDeclaration::typeString() const
168 {
169     return typeString(type());
170 }
171 
typeString(PropertyDeclaration::Type t)172 QString PropertyDeclaration::typeString(PropertyDeclaration::Type t)
173 {
174     switch (t) {
175     case Boolean: return boolString();
176     case Integer: return intString();
177     case Path: return StringConstants::pathType();
178     case PathList: return pathListString();
179     case String: return stringString();
180     case StringList: return stringListString();
181     case Variant: return variantString();
182     case VariantList: return varListString();
183     case UnknownType: return QStringLiteral("unknown");
184     }
185     Q_UNREACHABLE(); // For stupid compilers.
186 }
187 
name() const188 const QString &PropertyDeclaration::name() const
189 {
190     return d->name;
191 }
192 
setName(const QString & name)193 void PropertyDeclaration::setName(const QString &name)
194 {
195     d->name = name;
196 }
197 
type() const198 PropertyDeclaration::Type PropertyDeclaration::type() const
199 {
200     return d->type;
201 }
202 
setType(PropertyDeclaration::Type t)203 void PropertyDeclaration::setType(PropertyDeclaration::Type t)
204 {
205     d->type = t;
206 }
207 
flags() const208 PropertyDeclaration::Flags PropertyDeclaration::flags() const
209 {
210     return d->flags;
211 }
212 
setFlags(Flags f)213 void PropertyDeclaration::setFlags(Flags f)
214 {
215     d->flags = f;
216 }
217 
allowedValues() const218 const QStringList &PropertyDeclaration::allowedValues() const
219 {
220     return d->allowedValues;
221 }
222 
setAllowedValues(const QStringList & v)223 void PropertyDeclaration::setAllowedValues(const QStringList &v)
224 {
225     d->allowedValues = v;
226 }
227 
description() const228 const QString &PropertyDeclaration::description() const
229 {
230     return d->description;
231 }
232 
setDescription(const QString & str)233 void PropertyDeclaration::setDescription(const QString &str)
234 {
235     d->description = str;
236 }
237 
initialValueSource() const238 const QString &PropertyDeclaration::initialValueSource() const
239 {
240     return d->initialValueSource;
241 }
242 
setInitialValueSource(const QString & str)243 void PropertyDeclaration::setInitialValueSource(const QString &str)
244 {
245     d->initialValueSource = str;
246 }
247 
functionArgumentNames() const248 const QStringList &PropertyDeclaration::functionArgumentNames() const
249 {
250     return d->functionArgumentNames;
251 }
252 
setFunctionArgumentNames(const QStringList & lst)253 void PropertyDeclaration::setFunctionArgumentNames(const QStringList &lst)
254 {
255     d->functionArgumentNames = lst;
256 }
257 
isDeprecated() const258 bool PropertyDeclaration::isDeprecated() const
259 {
260     return d->deprecationInfo.isValid();
261 }
262 
isExpired() const263 bool PropertyDeclaration::isExpired() const
264 {
265     return isDeprecated() && deprecationInfo().removalVersion() <= LanguageInfo::qbsVersion();
266 }
267 
deprecationInfo() const268 const DeprecationInfo &PropertyDeclaration::deprecationInfo() const
269 {
270     return d->deprecationInfo;
271 }
272 
setDeprecationInfo(const DeprecationInfo & deprecationInfo)273 void PropertyDeclaration::setDeprecationInfo(const DeprecationInfo &deprecationInfo)
274 {
275     d->deprecationInfo = deprecationInfo;
276 }
277 
278 // see also: EvaluatorScriptClass::convertToPropertyType()
convertToPropertyType(const QVariant & v,Type t,const QStringList & namePrefix,const QString & key)279 QVariant PropertyDeclaration::convertToPropertyType(const QVariant &v, Type t,
280     const QStringList &namePrefix, const QString &key)
281 {
282     if (v.isNull() || !v.isValid())
283         return v;
284     const auto vt = variantType(t);
285     if (vt == QMetaType::UnknownType)
286         return v;
287 
288     // Handle the foo,bar,bla stringlist syntax.
289     if (t == PropertyDeclaration::StringList && v.userType() == QMetaType::QString)
290         return v.toString().split(QLatin1Char(','));
291 
292     QVariant c = v;
293     if (!qVariantConvert(c, vt)) {
294         QStringList name = namePrefix;
295         name << key;
296         throw ErrorInfo(Tr::tr("Value '%1' of property '%2' has incompatible type.")
297                         .arg(v.toString(), name.join(QLatin1Char('.'))));
298     }
299     return c;
300 }
301 
302 } // namespace Internal
303 } // namespace qbs
304