aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h
blob: e22f747718a1a47a526001120ecbdfe7c8eaa42b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0

#pragma once

#include "qmldesignercorelib_global.h"
#include "import.h"
#include "nodelistproperty.h"
#include "modelnode.h"

#include <qmljs/qmljsscopechain.h>

#include <QStringList>
#include <QTimer>

namespace QmlDesigner {

class RewriterView;
class DocumentMessage;

struct QmlTypeData;

namespace Internal {

class DifferenceHandler;
class ReadingContext;

class TextToModelMerger
{
    TextToModelMerger(const TextToModelMerger&);
    TextToModelMerger &operator=(const TextToModelMerger&);

public:
    static QmlJS::Document::MutablePtr createParsedDocument(const QUrl &url, const QString &data, QList<DocumentMessage> *errors);

    TextToModelMerger(RewriterView *reWriterView);
    bool isActive() const;

    void setupImports(const QmlJS::Document::Ptr &doc, DifferenceHandler &differenceHandler);
#ifndef QDS_USE_PROJECTSTORAGE
    void setupPossibleImports();
#endif
    void setupUsedImports();
    bool load(const QString &data, DifferenceHandler &differenceHandler);

    RewriterView *view() const
    { return m_rewriterView; }

#ifndef QDS_USE_PROJECTSTORAGE
    const QmlJS::ScopeChain *scopeChain() const
    { return m_scopeChain.data(); }
#endif

    const QmlJS::Document *document() const
    { return m_document.data(); }

    const QmlJS::ViewerContext &vContext() const
    { return m_vContext; }

protected:
    void setActive(bool active);

public:
    void syncNode(ModelNode &modelNode,
                  QmlJS::AST::UiObjectMember *astNode,
                  ReadingContext *context,
                  DifferenceHandler &differenceHandler);
    QmlDesigner::PropertyName syncScriptBinding(ModelNode &modelNode,
                              const QString &prefix,
                              QmlJS::AST::UiScriptBinding *script,
                              ReadingContext *context,
                              DifferenceHandler &differenceHandler);
    void syncNodeId(ModelNode &modelNode, const QString &astObjectId,
                    DifferenceHandler &differenceHandler);
    void syncNodeProperty(AbstractProperty &modelProperty,
                          QmlJS::AST::UiObjectBinding *binding,
                          ReadingContext *context,
                          const TypeName &astType,
                          DifferenceHandler &differenceHandler);
    void syncExpressionProperty(AbstractProperty &modelProperty,
                                const QString &javascript,
                                const TypeName &astType,
                                DifferenceHandler &differenceHandler);
    void syncSignalHandler(AbstractProperty &modelProperty,
                           const QString &javascript,
                           DifferenceHandler &differenceHandler);
    void syncArrayProperty(AbstractProperty &modelProperty,
                           const QList<QmlJS::AST::UiObjectMember *> &arrayMembers,
                           ReadingContext *context,
                           DifferenceHandler &differenceHandler);
    void syncSignalDeclarationProperty(AbstractProperty &modelProperty,
                            const QString &signature,
                            DifferenceHandler &differenceHandler);
    void syncVariantProperty(AbstractProperty &modelProperty,
                             const QVariant &astValue,
                             const TypeName &astType,
                             DifferenceHandler &differenceHandler);
    void syncNodeListProperty(NodeListProperty &modelListProperty,
                              const QList<QmlJS::AST::UiObjectMember *> arrayMembers,
                              ReadingContext *context,
                              DifferenceHandler &differenceHandler);
    ModelNode createModelNode(const QmlDesigner::NodeMetaInfo &nodeMetaInfo,
                              const TypeName &typeName,
                              int majorVersion,
                              int minorVersion,
                              bool isImplicitComponent,
                              QmlJS::AST::UiObjectMember *astNode,
                              ReadingContext *context,
                              DifferenceHandler &differenceHandler);
    QStringList syncGroupedProperties(ModelNode &modelNode,
                                      const QString &name,
                                      QmlJS::AST::UiObjectMemberList *members,
                                      ReadingContext *context,
                                      DifferenceHandler &differenceHandler);

    void setupComponentDelayed(const ModelNode &node, bool synchronous);
    void setupCustomParserNodeDelayed(const ModelNode &node, bool synchronous);
    void clearImplicitComponentDelayed(const ModelNode &node, bool synchronous);

    void delayedSetup();

    QSet<QPair<QString, QString>> qrcMapping() const;

    QList<QmlTypeData> getQMLSingletons() const;

    void clearPossibleImportKeys();

private:
    void setupCustomParserNode(const ModelNode &node);
    void setupComponent(const ModelNode &node);
    void clearImplicitComponent(const ModelNode &node);
    void collectLinkErrors(QList<DocumentMessage> *errors, const ReadingContext &ctxt);
    void collectImportErrors(QList<DocumentMessage> *errors);
    void collectSemanticErrorsAndWarnings(QList<DocumentMessage> *errors,
                                          QList<DocumentMessage> *warnings);
    void populateQrcMapping(const QString &filePath);
    void addIsoIconQrcMapping(const QUrl &fileUrl);

    static QString textAt(const QmlJS::Document::Ptr &doc,
                          const QmlJS::SourceLocation &location);
    static QString textAt(const QmlJS::Document::Ptr &doc,
                          const QmlJS::SourceLocation &from,
                          const QmlJS::SourceLocation &to);

private:
    RewriterView *m_rewriterView;
    bool m_isActive;
#ifndef QDS_USE_PROJECTSTORAGE
    QSharedPointer<const QmlJS::ScopeChain> m_scopeChain;
#endif
    QmlJS::Document::Ptr m_document;
    QTimer m_setupTimer;
    QSet<ModelNode> m_setupComponentList;
    QSet<ModelNode> m_setupCustomParserList;
    QSet<ModelNode> m_clearImplicitComponentList;
    QmlJS::ViewerContext m_vContext;
    QSet<QPair<QString, QString> > m_qrcMapping;
    Imports m_possibleModules;
    int m_previousPossibleModulesSize = -1;
    bool m_hasVersionlessImport = false;
};

class DifferenceHandler
{
public:
    DifferenceHandler(TextToModelMerger *textToModelMerger):
            m_merger(textToModelMerger)
    {}
    virtual ~DifferenceHandler() = default;

    virtual void modelMissesImport(const QmlDesigner::Import &import) = 0;
    virtual void importAbsentInQMl(const QmlDesigner::Import &import) = 0;
    virtual void bindingExpressionsDiffer(BindingProperty &modelProperty,
                                          const QString &javascript,
                                          const TypeName &astType) = 0;
    virtual void signalHandlerSourceDiffer(SignalHandlerProperty &modelProperty,
                                          const QString &javascript) = 0;
    virtual void signalDeclarationSignatureDiffer(SignalDeclarationProperty &modelProperty,
                                                       const QString &signature) = 0;
    virtual void shouldBeBindingProperty(AbstractProperty &modelProperty,
                                         const QString &javascript,
                                         const TypeName &astType) = 0;
    virtual void shouldBeSignalHandlerProperty(AbstractProperty &modelProperty,
                                         const QString &javascript) = 0;
    virtual void shouldBeSignalDeclarationProperty(AbstractProperty &modelProperty,
                                               const QString &signature) = 0;
    virtual void shouldBeNodeListProperty(AbstractProperty &modelProperty,
                                          const QList<QmlJS::AST::UiObjectMember *> arrayMembers,
                                          ReadingContext *context) = 0;
    virtual void variantValuesDiffer(VariantProperty &modelProperty, const QVariant &qmlVariantValue, const TypeName &dynamicTypeName) = 0;
    virtual void shouldBeVariantProperty(AbstractProperty &modelProperty, const QVariant &qmlVariantValue, const TypeName &dynamicTypeName) = 0;
    virtual void shouldBeNodeProperty(AbstractProperty &modelProperty,
                                      const NodeMetaInfo &nodeMetaInfo,
                                      const TypeName &typeName,
                                      int majorVersion,
                                      int minorVersion,
                                      QmlJS::AST::UiObjectMember *astNode,
                                      const TypeName &dynamicPropertyType,
                                      ReadingContext *context)
        = 0;
    virtual void modelNodeAbsentFromQml(ModelNode &modelNode) = 0;
    virtual ModelNode listPropertyMissingModelNode(NodeListProperty &modelProperty,
                                                   ReadingContext *context,
                                                   QmlJS::AST::UiObjectMember *arrayMember) = 0;
    virtual void typeDiffers(bool isRootNode,
                             ModelNode &modelNode,
                             const NodeMetaInfo &nodeMetaInfo,
                             const TypeName &typeName,
                             int majorVersion,
                             int minorVersion,
                             QmlJS::AST::UiObjectMember *astNode,
                             ReadingContext *context)
        = 0;
    virtual void propertyAbsentFromQml(AbstractProperty &modelProperty) = 0;
    virtual void idsDiffer(ModelNode &modelNode, const QString &qmlId) = 0;
    virtual bool isAmender() const = 0;

protected:
    TextToModelMerger *m_merger;
};

class ModelValidator: public DifferenceHandler
{
public:
    ModelValidator(TextToModelMerger *textToModelMerger):
            DifferenceHandler(textToModelMerger)
    {}
    ~ModelValidator() override = default;

    void modelMissesImport(const QmlDesigner::Import &import) override;
    void importAbsentInQMl(const QmlDesigner::Import &import) override;
    void bindingExpressionsDiffer(BindingProperty &modelProperty,
                                  const QString &javascript,
                                  const TypeName &astType) override;
    void shouldBeBindingProperty(AbstractProperty &modelProperty,
                                 const QString &javascript,
                                 const TypeName &astType) override;
    void signalHandlerSourceDiffer(SignalHandlerProperty &modelProperty,
                                   const QString &javascript) override;
    void signalDeclarationSignatureDiffer(SignalDeclarationProperty &modelProperty,
                                          const QString &signature) override;
    void shouldBeSignalDeclarationProperty(AbstractProperty &modelProperty,
                                           const QString &signature) override;
    void shouldBeSignalHandlerProperty(AbstractProperty &modelProperty,
                                       const QString &javascript) override;
    void shouldBeNodeListProperty(AbstractProperty &modelProperty,
                                  const QList<QmlJS::AST::UiObjectMember *> arrayMembers,
                                  ReadingContext *context) override;
    void variantValuesDiffer(VariantProperty &modelProperty, const QVariant &qmlVariantValue, const TypeName &dynamicTypeName) override;
    void shouldBeVariantProperty(AbstractProperty &modelProperty, const QVariant &qmlVariantValue, const TypeName &dynamicTypeName) override;
    void shouldBeNodeProperty(AbstractProperty &modelProperty,
                              const NodeMetaInfo &nodeMetaInfo,
                              const TypeName &typeName,
                              int majorVersion,
                              int minorVersion,
                              QmlJS::AST::UiObjectMember *astNode,
                              const TypeName &dynamicPropertyType,
                              ReadingContext *context) override;

    void modelNodeAbsentFromQml(ModelNode &modelNode) override;
    ModelNode listPropertyMissingModelNode(NodeListProperty &modelProperty,
                                           ReadingContext *context,
                                           QmlJS::AST::UiObjectMember *arrayMember) override;
    void typeDiffers(bool isRootNode,
                     ModelNode &modelNode,
                     const NodeMetaInfo &nodeMetaInfo,
                     const TypeName &typeName,
                     int majorVersion,
                     int minorVersion,
                     QmlJS::AST::UiObjectMember *astNode,
                     ReadingContext *context) override;
    void propertyAbsentFromQml(AbstractProperty &modelProperty) override;
    void idsDiffer(ModelNode &modelNode, const QString &qmlId) override;
    bool isAmender() const override {return false; }
};

class ModelAmender: public DifferenceHandler
{
public:
    ModelAmender(TextToModelMerger *textToModelMerger):
            DifferenceHandler(textToModelMerger)
    {}
    ~ModelAmender() override = default;

    void modelMissesImport(const QmlDesigner::Import &import) override;
    void importAbsentInQMl(const QmlDesigner::Import &import) override;
    void bindingExpressionsDiffer(BindingProperty &modelProperty,
                                  const QString &javascript,
                                  const TypeName &astType) override;
    void shouldBeBindingProperty(AbstractProperty &modelProperty,
                                 const QString &javascript,
                                 const TypeName &astType) override;
    void signalHandlerSourceDiffer(SignalHandlerProperty &modelProperty,
                                   const QString &javascript) override;
    void signalDeclarationSignatureDiffer(SignalDeclarationProperty &modelProperty,
                                          const QString &signature) override;
    void shouldBeSignalDeclarationProperty(AbstractProperty &modelProperty,
                                           const QString &signature) override;
    void shouldBeSignalHandlerProperty(AbstractProperty &modelProperty,
                                       const QString &javascript) override;
    void shouldBeNodeListProperty(AbstractProperty &modelProperty,
                                  const QList<QmlJS::AST::UiObjectMember *> arrayMembers,
                                  ReadingContext *context) override;
    void variantValuesDiffer(VariantProperty &modelProperty, const QVariant &qmlVariantValue, const TypeName &dynamicType) override;
    void shouldBeVariantProperty(AbstractProperty &modelProperty, const QVariant &qmlVariantValue, const TypeName &dynamicTypeName) override;
    void shouldBeNodeProperty(AbstractProperty &modelProperty,
                              const NodeMetaInfo &nodeMetaInfo,
                              const TypeName &typeName,
                              int majorVersion,
                              int minorVersion,
                              QmlJS::AST::UiObjectMember *astNode,
                              const TypeName &dynamicPropertyType,
                              ReadingContext *context) override;

    void modelNodeAbsentFromQml(ModelNode &modelNode) override;
    ModelNode listPropertyMissingModelNode(NodeListProperty &modelProperty,
                                           ReadingContext *context,
                                           QmlJS::AST::UiObjectMember *arrayMember) override;
    void typeDiffers(bool isRootNode,
                     ModelNode &modelNode,
                     const NodeMetaInfo &nodeMetaInfo,
                     const TypeName &typeName,
                     int majorVersion,
                     int minorVersion,
                     QmlJS::AST::UiObjectMember *astNode,
                     ReadingContext *context) override;
    void propertyAbsentFromQml(AbstractProperty &modelProperty) override;
    void idsDiffer(ModelNode &modelNode, const QString &qmlId) override;
    bool isAmender() const override {return true; }
};

} //Internal
} //QmlDesigner