qmlmodelview.cpp 15.1 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** 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, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29
30
31
32
33
34

#include "qmlmodelview.h"
#include "qmlobjectnode.h"
#include "qmlitemnode.h"
#include "itemlibraryinfo.h"
#include "mathutils.h"
35
#include "invalididexception.h"
36
37
38
#include <QDir>
#include <QFileInfo>
#include <QDebug>
39
#include <QMessageBox>
40
41
#include <QPlainTextEdit>
#include <utils/fileutils.h>
42
43
#include "nodeabstractproperty.h"
#include "variantproperty.h"
44
#include "rewritingexception.h"
45
46
47
#include "rewriterview.h"
#include "plaintexteditmodifier.h"
#include "modelmerger.h"
48
#include "nodemetainfo.h"
49

50
51
#include <utils/qtcassert.h>

52
53
54
namespace QmlDesigner {

QmlModelView::QmlModelView(QObject *parent)
55
    : AbstractView(parent)
56
57
58
59
60
{
}

void QmlModelView::setCurrentState(const QmlModelState &state)
{
61
    if (!state.isValid())
62
        return;
63

64
65
66
67
68
    if (!model())
        return;

    if (actualStateNode() != state.modelNode())
        setAcutalStateNode(state.modelNode());
69
70
71
72
}

QmlModelState QmlModelView::currentState() const
{
Marco Bubke's avatar
Marco Bubke committed
73
    return QmlModelState(actualStateNode());
74
75
76
77
78
79
80
}

QmlModelState QmlModelView::baseState() const
{
    return QmlModelState::createBaseState(this);
}

81
82
83
84
85
QmlModelStateGroup QmlModelView::rootStateGroup() const
{
    return QmlModelStateGroup(rootModelNode());
}

86
QmlObjectNode QmlModelView::createQmlObjectNode(const TypeName &typeString,
87
88
89
90
91
92
93
                     int majorVersion,
                     int minorVersion,
                     const PropertyListType &propertyList)
{
    return QmlObjectNode(createModelNode(typeString, majorVersion, minorVersion, propertyList));
}

94
QmlItemNode QmlModelView::createQmlItemNode(const TypeName &typeString,
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
                                int majorVersion,
                                int minorVersion,
                                const PropertyListType &propertyList)
{
    return createQmlObjectNode(typeString, majorVersion, minorVersion, propertyList).toQmlItemNode();
}

QmlItemNode QmlModelView::createQmlItemNodeFromImage(const QString &imageName, const QPointF &position, QmlItemNode parentNode)
{
    if (!parentNode.isValid())
        parentNode = rootQmlItemNode();

    if (!parentNode.isValid())
        return QmlItemNode();

    QmlItemNode newNode;
    RewriterTransaction transaction = beginRewriterTransaction();
    {
113
        const QString newImportUrl = QLatin1String("QtQuick");
114
        const QString newImportVersion = QLatin1String("1.1");
115
116
117
118
119
120
121
122
123
124
125
126
        Import newImport = Import::createLibraryImport(newImportUrl, newImportVersion);

        foreach (const Import &import, model()->imports()) {
            if (import.isLibraryImport()
                && import.url() == newImport.url()
                && import.version() == newImport.version()) {
                // reuse this import
                newImport = import;
                break;
            }
        }

127
        if (!model()->imports().contains(newImport))
128
            model()->changeImports(QList<Import>() << newImport, QList<Import>());
129

130
131
132
        QList<QPair<PropertyName, QVariant> > propertyPairList;
        propertyPairList.append(qMakePair(PropertyName("x"), QVariant( round(position.x(), 4))));
        propertyPairList.append(qMakePair(PropertyName("y"), QVariant( round(position.y(), 4))));
133
134
135
136
137
138
139
140
141

        QString relativeImageName = imageName;

        //use relative path
        if (QFileInfo(model()->fileUrl().toLocalFile()).exists()) {
            QDir fileDir(QFileInfo(model()->fileUrl().toLocalFile()).absolutePath());
            relativeImageName = fileDir.relativeFilePath(imageName);
        }

142
        propertyPairList.append(qMakePair(PropertyName("source"), QVariant(relativeImageName)));
143
        newNode = createQmlItemNode("QtQuick.Image", -1, -1, propertyPairList);
144
145
146
147
148
149
150
        parentNode.nodeAbstractProperty("data").reparentHere(newNode);

        Q_ASSERT(newNode.isValid());

        QString id;
        int i = 1;
        QString name("image");
151
        name.remove(QLatin1Char(' '));
152
153
154
155
156
157
        do {
            id = name + QString::number(i);
            i++;
        } while (hasId(id)); //If the name already exists count upwards

        newNode.setId(id);
158
        if (!currentState().isBaseState()) {
159
160
            newNode.modelNode().variantProperty("opacity") = 0;
            newNode.setVariantProperty("opacity", 1);
161
        }
162
163
164
165
166
167
168
169
170

        Q_ASSERT(newNode.isValid());
    }

    Q_ASSERT(newNode.isValid());

    return newNode;
}

171
QmlItemNode QmlModelView::createQmlItemNode(const ItemLibraryEntry &itemLibraryEntry, const QPointF &position, QmlItemNode parentNode)
172
173
174
175
176
177
178
{
    if (!parentNode.isValid())
        parentNode = rootQmlItemNode();

    Q_ASSERT(parentNode.isValid());

    QmlItemNode newNode;
179
180
181

    try {
        RewriterTransaction transaction = beginRewriterTransaction();
182
183
184
185
186
187

        NodeMetaInfo metaInfo = model()->metaInfo(itemLibraryEntry.typeName());

        int minorVersion = metaInfo.minorVersion();
        int majorVersion = metaInfo.majorVersion();

188
        if (itemLibraryEntry.typeName().contains('.')) {
189
190
191
192
193

            const QString newImportUrl = itemLibraryEntry.requiredImport();

            if (!itemLibraryEntry.requiredImport().isEmpty()) {
                const QString newImportVersion = QString("%1.%2").arg(QString::number(itemLibraryEntry.majorVersion()), QString::number(itemLibraryEntry.minorVersion()));
194

195
                Import newImport = Import::createLibraryImport(newImportUrl, newImportVersion);
196
197
198
199
                if (itemLibraryEntry.majorVersion() == -1 && itemLibraryEntry.minorVersion() == -1)
                    newImport = Import::createFileImport(newImportUrl, QString());
                else
                    newImport = Import::createLibraryImport(newImportUrl, newImportVersion);
200
201
202
203
204
205
206
207
208

                foreach (const Import &import, model()->imports()) {
                    if (import.isLibraryImport()
                            && import.url() == newImport.url()
                            && import.version() == newImport.version()) {
                        // reuse this import
                        newImport = import;
                        break;
                    }
209
210
                }

211
                if (!model()->hasImport(newImport, true, true))
212
                    model()->changeImports(QList<Import>() << newImport, QList<Import>());
213
214
215
            }
        }

216
217
218
        QList<QPair<PropertyName, QVariant> > propertyPairList;
        propertyPairList.append(qMakePair(PropertyName("x"), QVariant(round(position.x(), 4))));
        propertyPairList.append(qMakePair(PropertyName("y"), QVariant(round(position.y(), 4))));
219

220
221
222
223
        if (itemLibraryEntry.qml().isEmpty()) {
            foreach (const PropertyContainer &property, itemLibraryEntry.properties())
                propertyPairList.append(qMakePair(property.name(), property.value()));

224
            newNode = createQmlItemNode(itemLibraryEntry.typeName(), majorVersion, minorVersion, propertyPairList);
225
226
227
228
229
230
231
232
233
234
235
236
        } else {
            QScopedPointer<Model> inputModel(Model::create("QtQuick.Rectangle", 1, 0, model()));
            inputModel->setFileUrl(model()->fileUrl());
            QPlainTextEdit textEdit;


            textEdit.setPlainText(Utils::FileReader::fetchQrc(itemLibraryEntry.qml()));
            NotIndentingTextEditModifier modifier(&textEdit);

            QScopedPointer<RewriterView> rewriterView(new RewriterView(RewriterView::Amend, 0));
            rewriterView->setCheckSemanticErrors(false);
            rewriterView->setTextModifier(&modifier);
Marco Bubke's avatar
Marco Bubke committed
237
            inputModel->setRewriterView(rewriterView.data());
238
239

            if (rewriterView->errors().isEmpty() && rewriterView->rootModelNode().isValid()) {
240
241
242
243
244
                ModelNode rootModelNode = rewriterView->rootModelNode();
                inputModel->detachView(rewriterView.data());

                rootModelNode.variantProperty("x") = propertyPairList.first().second;
                rootModelNode.variantProperty("y") = propertyPairList.at(1).second;
245

246
                ModelMerger merger(this);
Orgad Shaneh's avatar
Orgad Shaneh committed
247
                newNode = merger.insertModel(rootModelNode);
248
249
250
            }
        }

251
        if (parentNode.hasDefaultProperty())
252
            parentNode.nodeAbstractProperty(parentNode.defaultProperty()).reparentHere(newNode);
253

254
255
        if (!newNode.isValid())
            return newNode;
256
257
258

        QString id;
        int i = 1;
259
        QString name(itemLibraryEntry.name().toLower());
260
261
        //remove forbidden characters
        name.replace(QRegExp(QLatin1String("[^a-zA-Z0-9_]")), QLatin1String("_"));
262
263
264
265
266
        do {
            id = name + QString::number(i);
            i++;
        } while (hasId(id)); //If the name already exists count upwards

267
        newNode.setId(id);
268

269
        if (!currentState().isBaseState()) {
270
271
            newNode.modelNode().variantProperty("opacity") = 0;
            newNode.setVariantProperty("opacity", 1);
272
        }
273
274
275

        Q_ASSERT(newNode.isValid());
    }
276
277
278
279
280
281
282
    catch (RewritingException &e) {
        QMessageBox::warning(0, "Error", e.description());
    }
    catch (InvalidIdException &e) {
        // should never happen
        QMessageBox::warning(0, tr("Invalid Id"), e.description());
    }
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
334
335
336
337
338
339
340

    Q_ASSERT(newNode.isValid());

    return newNode;
}

QmlObjectNode QmlModelView::rootQmlObjectNode() const
{
    return QmlObjectNode(rootModelNode());
}

QmlItemNode QmlModelView::rootQmlItemNode() const
{
    return rootQmlObjectNode().toQmlItemNode();
}

void QmlModelView::setSelectedQmlObjectNodes(const QList<QmlObjectNode> &selectedNodeList)
{
    setSelectedModelNodes(QmlDesigner::toModelNodeList(selectedNodeList));
}

void QmlModelView::selectQmlObjectNode(const QmlObjectNode &node)
{
     selectModelNode(node.modelNode());
}

void QmlModelView::deselectQmlObjectNode(const QmlObjectNode &node)
{
    deselectModelNode(node.modelNode());
}

QList<QmlObjectNode> QmlModelView::selectedQmlObjectNodes() const
{
    return toQmlObjectNodeList(selectedModelNodes());
}

QList<QmlItemNode> QmlModelView::selectedQmlItemNodes() const
{
    return toQmlItemNodeList(selectedModelNodes());
}

void QmlModelView::setSelectedQmlItemNodes(const QList<QmlItemNode> &selectedNodeList)
{
    return setSelectedModelNodes(QmlDesigner::toModelNodeList(selectedNodeList));
}

QmlObjectNode QmlModelView::fxObjectNodeForId(const QString &id)
{
    return QmlObjectNode(modelNodeForId(id));
}

NodeInstance QmlModelView::instanceForModelNode(const ModelNode &modelNode)
{
    return nodeInstanceView()->instanceForNode(modelNode);
}

bool QmlModelView::hasInstanceForModelNode(const ModelNode &modelNode)
{
Thomas Hartmann's avatar
Thomas Hartmann committed
341
    return nodeInstanceView() && nodeInstanceView()->hasInstanceForNode(modelNode);
342
343
344
345
}

void QmlModelView::modelAttached(Model *model)
{
346
    AbstractView::modelAttached(model);
347
348
349
350
}

void QmlModelView::modelAboutToBeDetached(Model *model)
{
351
    AbstractView::modelAboutToBeDetached(model);
352
353
}

354
355
356
357
358
359
360
361
void QmlModelView::nodeOrderChanged(const NodeListProperty &/*listProperty*/, const ModelNode &/*movedNode*/, int /*oldIndex*/)
{

}

void QmlModelView::nodeCreated(const ModelNode &/*createdNode*/) {}
void QmlModelView::nodeAboutToBeRemoved(const ModelNode &/*removedNode*/) {}
void QmlModelView::nodeRemoved(const ModelNode &/*removedNode*/, const NodeAbstractProperty &/*parentProperty*/, PropertyChangeFlags /*propertyChange*/) {}
362
void QmlModelView::nodeAboutToBeReparented(const ModelNode &/*node*/, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/) {}
363
364
365
366
367
368
369
370
371
372
void QmlModelView::nodeReparented(const ModelNode &/*node*/, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/) {}
void QmlModelView::nodeIdChanged(const ModelNode& /*node*/, const QString& /*newId*/, const QString& /*oldId*/) {}
void QmlModelView::propertiesAboutToBeRemoved(const QList<AbstractProperty>& /*propertyList*/) {}
void QmlModelView::propertiesRemoved(const QList<AbstractProperty>& /*propertyList*/) {}
void QmlModelView::variantPropertiesChanged(const QList<VariantProperty>& /*propertyList*/, PropertyChangeFlags /*propertyChange*/) {}
void QmlModelView::bindingPropertiesChanged(const QList<BindingProperty>& /*propertyList*/, PropertyChangeFlags /*propertyChange*/) {}
void QmlModelView::rootNodeTypeChanged(const QString &/*type*/, int, int /*minorVersion*/) {}
void QmlModelView::scriptFunctionsChanged(const ModelNode &/*node*/, const QStringList &/*scriptFunctionList*/) {}
void QmlModelView::selectedNodesChanged(const QList<ModelNode> &/*selectedNodeList*/, const QList<ModelNode> &/*lastSelectedNodeList*/) {}

373

374
375
376
void QmlModelView::instancesCompleted(const QVector<ModelNode> &/*completedNodeList*/)
{
}
377

378
void QmlModelView::instanceInformationsChange(const QMultiHash<ModelNode, InformationName> &/*informationChangeHash*/)
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
{

}

void QmlModelView::instancesRenderImageChanged(const QVector<ModelNode> &/*nodeList*/)
{

}

void QmlModelView::instancesPreviewImageChanged(const QVector<ModelNode> &/*nodeList*/)
{

}

void QmlModelView::instancesChildrenChanged(const QVector<ModelNode> &/*nodeList*/)
{

}

398
399
400
401
void QmlModelView::importsChanged(const QList<Import> &/*addedImports*/, const QList<Import> &/*removedImports*/)
{

}
402

403
404
405
406
407
void QmlModelView::instancesToken(const QString &/*tokenName*/, int /*tokenNumber*/, const QVector<ModelNode> &/*nodeVector*/)
{

}

408
void QmlModelView::nodeSourceChanged(const ModelNode &, const QString & /*newNodeSource*/)
409
410
411
412
{

}

413
414
415
416
417
418
419
420
421
422
void QmlModelView::rewriterBeginTransaction()
{

}

void QmlModelView::rewriterEndTransaction()
{

}

Thomas Hartmann's avatar
Thomas Hartmann committed
423
void QmlModelView::actualStateChanged(const ModelNode & /*node*/)
424
425
426
427
{

}

428
void QmlModelView::instancePropertyChange(const QList<QPair<ModelNode, PropertyName> > & /*propertyList*/)
429
430
431
{
}

432
433
434
ModelNode QmlModelView::createQmlState(const QmlDesigner::PropertyListType &propertyList)
{

Eike Ziller's avatar
Eike Ziller committed
435
    QTC_CHECK(rootModelNode().majorQtQuickVersion() < 3);
436

437
    if (rootModelNode().majorQtQuickVersion() > 1)
438
        return createModelNode("QtQuick.State", 2, 0, propertyList);
439
    else
440
441
442
        return createModelNode("QtQuick.State", 1, 0, propertyList);
}

443
444

} //QmlDesigner