1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "designermcumanager.h"
27 #include "qmldesignerconstants.h"
28 #include "qmldesignerplugin.h"
29 #include "designersettings.h"
30 #include "designdocument.h"
31 
32 #include <qmljs/qmljssimplereader.h>
33 
34 #include <utils/qtcassert.h>
35 
36 namespace QmlDesigner {
37 
readProperty(const QString property,const QmlJS::SimpleReaderNode::Ptr & node)38 static QString readProperty(const QString property, const QmlJS::SimpleReaderNode::Ptr &node)
39 {
40     const QVariant propertyVar = node->property(property);
41 
42     if (!propertyVar.isNull() && propertyVar.isValid())
43         return propertyVar.value<QString>();
44 
45     return {};
46 }
47 
readPropertyList(const QString & property,const QmlJS::SimpleReaderNode::Ptr & node)48 static QStringList readPropertyList(const QString &property, const QmlJS::SimpleReaderNode::Ptr &node)
49 {
50     const QVariant propertyVar = node->property(property);
51 
52     if (!propertyVar.isNull() && propertyVar.isValid())
53         return propertyVar.value<QStringList>();
54 
55     return {};
56 }
57 
instance()58 DesignerMcuManager &DesignerMcuManager::instance()
59 {
60     static DesignerMcuManager instance;
61 
62     return instance;
63 }
64 
mcuResourcesPath()65 QString DesignerMcuManager::mcuResourcesPath()
66 {
67     return Core::ICore::resourcePath("qmldesigner/qt4mcu").toString();
68 }
69 
isMCUProject() const70 bool DesignerMcuManager::isMCUProject() const
71 {
72     QmlDesigner::DesignDocument *designDocument = QmlDesigner::QmlDesignerPlugin::instance()
73                                                       ->documentManager().currentDesignDocument();
74     if (designDocument)
75         return designDocument->isQtForMCUsProject();
76 
77     return false;
78 }
79 
readMetadata()80 void DesignerMcuManager::readMetadata()
81 {
82     const QString mainMetadataFileName = "metadata.qml";
83 
84     m_defaultVersion = {};
85     m_versionsList.clear();
86 
87     QmlJS::SimpleReader reader;
88     const QmlJS::SimpleReaderNode::Ptr metadata =
89             reader.readFile(mcuResourcesPath() + "/" + mainMetadataFileName);
90     if (!metadata) {
91         qWarning() << "Designer MCU metadata:" << reader.errors();
92         return;
93     }
94 
95     const QmlJS::SimpleReaderNode::List versions = metadata->children();
96 
97     if (versions.isEmpty()) {
98         qWarning() << "Designer MCU metadata: metadata list is empty";
99         return;
100     }
101 
102     const QVariant defaultVersion = metadata->property("defaultVersion");
103     if (!defaultVersion.isNull() && defaultVersion.isValid()) {
104         for (const auto& version : versions) {
105             Version newVersion;
106 
107             const QVariant vId = version->property("id");
108             if (vId.isNull() || !vId.isValid())
109                 continue;
110 
111             const QVariant vName = version->property("name");
112             if (!vName.isNull() && vName.isValid())
113                 newVersion.name = vName.value<QString>();
114             else
115                 continue;
116 
117             const QVariant vPath = version->property("path");
118             if (!vPath.isNull() && vPath.isValid())
119                 newVersion.fileName = vPath.value<QString>();
120             else
121                 continue;
122 
123             m_versionsList.push_back(newVersion);
124 
125             if (vId == defaultVersion)
126                 m_defaultVersion = newVersion;
127         }
128     }
129 }
130 
readVersionData(const DesignerMcuManager::Version & version)131 void DesignerMcuManager::readVersionData(const DesignerMcuManager::Version &version)
132 {
133     m_currentVersion = {};
134     m_bannedItems.clear();
135     m_allowedImports.clear();
136     m_bannedImports.clear();
137     m_bannedProperties.clear();
138     m_allowedItemProperties.clear();
139     m_bannedComplexProperties.clear();
140 
141     QmlJS::SimpleReader reader;
142     const QmlJS::SimpleReaderNode::Ptr versionData =
143             reader.readFile(mcuResourcesPath() + "/" + version.fileName);
144     if (!versionData) {
145         qWarning() << "Designer MCU metadata:" << reader.errors();
146         return;
147     }
148 
149     const QmlJS::SimpleReaderNode::List info = versionData->children();
150 
151     if (info.isEmpty()) {
152         qWarning() << "Designer MCU metadata: metadata list is empty";
153         return;
154     }
155 
156     for (const auto& child : info) {
157         //handling specific item types:
158         if (child->name() == "ComplexProperty") {
159             if (child->propertyNames().contains("prefix")
160                     && child->propertyNames().contains("bannedProperties")) {
161                 const QString complexPropPrefix(readProperty("prefix", child));
162                 const QStringList complexPropBans(readPropertyList("bannedProperties", child));
163 
164                 if (!complexPropPrefix.isEmpty() && !complexPropBans.isEmpty())
165                     m_bannedComplexProperties.insert(complexPropPrefix, complexPropBans);
166             }
167 
168             continue;
169         }
170 
171         //handling allowed properties:
172         if (child->propertyNames().contains("allowedProperties")) {
173             ItemProperties allowedProperties;
174 
175             const QVariant childrenPropertyVar = child->property("allowChildren");
176 
177             if (!childrenPropertyVar.isNull() && childrenPropertyVar.isValid())
178                 allowedProperties.allowChildren = childrenPropertyVar.toBool();
179 
180             allowedProperties.properties = readPropertyList("allowedProperties", child);
181 
182             if (!allowedProperties.properties.isEmpty())
183                 m_allowedItemProperties.insert(child->name(), allowedProperties);
184         }
185 
186         //handling banned properties:
187         const QStringList bannedProperties = readPropertyList("bannedProperties", child);
188 
189         m_bannedProperties.unite(QSet<QString>(bannedProperties.begin(), bannedProperties.end()));
190     }
191 
192     const QList<QString> bannedItems = readPropertyList("bannedItems", versionData);
193 
194     m_bannedItems = QSet<QString>(bannedItems.begin(), bannedItems.end());
195     m_allowedImports = readPropertyList("allowedImports", versionData);
196     m_bannedImports = readPropertyList("bannedImports", versionData);
197     m_currentVersion = version;
198 }
199 
currentVersion() const200 DesignerMcuManager::Version DesignerMcuManager::currentVersion() const
201 {
202     return m_currentVersion;
203 }
204 
defaultVersion() const205 DesignerMcuManager::Version DesignerMcuManager::defaultVersion() const
206 {
207     return m_defaultVersion;
208 }
209 
versions() const210 DesignerMcuManager::VersionsList DesignerMcuManager::versions() const
211 {
212     return m_versionsList;
213 }
214 
bannedItems() const215 QSet<QString> DesignerMcuManager::bannedItems() const
216 {
217     return m_bannedItems;
218 }
219 
bannedProperties() const220 QSet<QString> DesignerMcuManager::bannedProperties() const
221 {
222     return m_bannedProperties;
223 }
224 
allowedImports() const225 QStringList DesignerMcuManager::allowedImports() const
226 {
227     return m_allowedImports;
228 }
229 
bannedImports() const230 QStringList DesignerMcuManager::bannedImports() const
231 {
232     return m_bannedImports;
233 }
234 
allowedItemProperties() const235 QHash<QString, DesignerMcuManager::ItemProperties> DesignerMcuManager::allowedItemProperties() const
236 {
237     return m_allowedItemProperties;
238 }
239 
bannedComplexProperties() const240 QHash<QString, QStringList> DesignerMcuManager::bannedComplexProperties() const
241 {
242     return m_bannedComplexProperties;
243 }
244 
DesignerMcuManager()245 DesignerMcuManager::DesignerMcuManager()
246 {
247     readMetadata();
248 
249     readVersionData(m_defaultVersion);
250 }
251 
~DesignerMcuManager()252 DesignerMcuManager::~DesignerMcuManager()
253 {
254 
255 }
256 
257 } // QmlDesigner
258