propertyeditorvalue.cpp 13.4 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

#include "propertyeditorvalue.h"
31
#include <QRegExp>
32
#include <QUrl>
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <abstractview.h>
#include <nodeabstractproperty.h>
#include <nodeproperty.h>
#include <model.h>
#include <nodemetainfo.h>
#include <metainfo.h>
#include <qmlobjectnode.h>

//using namespace QmlDesigner;

PropertyEditorValue::PropertyEditorValue(QObject *parent)
   : QObject(parent),
   m_isInSubState(false),
   m_isInModel(false),
   m_isBound(false),
   m_isValid(false),
   m_complexNode(new PropertyEditorNodeWrapper(this))
{
}

QVariant PropertyEditorValue::value() const
{
    QVariant returnValue = m_value;
Marco Bubke's avatar
Marco Bubke committed
56
    if (modelNode().isValid() && modelNode().metaInfo().isValid() && modelNode().metaInfo().hasProperty(name()))
57
        if (modelNode().metaInfo().propertyTypeName(name()) == "QUrl")
58
59
60
61
62
63
64
        returnValue = returnValue.toUrl().toString();
    return returnValue;
}

static bool cleverDoubleCompare(QVariant value1, QVariant value2)
{ //we ignore slight changes on doubles
    if ((value1.type() == QVariant::Double) && (value2.type() == QVariant::Double)) {
65
66
        int a = value1.toDouble() * 100;
        int b = value2.toDouble() * 100;
67

68
        if (qFuzzyCompare((qreal(a) / 100), (qreal(b) / 100)))
69
70
            return true;
    }
71
72
73
    return false;
}

74
75
76
77
78
79
80
81
82
83
84
static bool cleverColorCompare(QVariant value1, QVariant value2)
{
    if ((value1.type() == QVariant::Color) && (value2.type() == QVariant::Color)) {
        QColor c1 = value1.value<QColor>();
        QColor c2 = value2.value<QColor>();
        QString a = c1.name();
        QString b = c2.name();
        if (a != b)
            return false;
        return (c1.alpha() == c2.alpha());
    }
85
    if ((value1.type() == QVariant::String) && (value2.type() == QVariant::Color))
86
        return cleverColorCompare(QVariant(QColor(value1.toString())), value2);
87
    if ((value1.type() == QVariant::Color) && (value2.type() == QVariant::String))
88
89
90
91
        return cleverColorCompare(value1, QVariant(QColor(value2.toString())));
    return false;
}

92
93
94

/* "red" is the same color as "#ff0000"
  To simplify editing we convert all explicit color names in the hash format */
95
static void fixAmbigousColorNames(const QmlDesigner::ModelNode &modelNode, const QmlDesigner::PropertyName &name, QVariant *value)
96
97
98
99
100
{
    if (modelNode.isValid() && modelNode.metaInfo().isValid()
            && (modelNode.metaInfo().propertyTypeName(name) == "QColor"
                || modelNode.metaInfo().propertyTypeName(name) == "color")) {
        if ((value->type() == QVariant::Color)) {
101
102
103
104
105
            QColor color = value->value<QColor>();
            int alpha = color.alpha();
            color = QColor(color.name());
            color.setAlpha(alpha);
            *value = color;
106
        } else if (value->toString() != QLatin1String("transparent")) {
107
108
109
110
111
            *value = QColor(value->toString()).name();
        }
    }
}

112
static void fixUrl(const QmlDesigner::ModelNode &modelNode, const QmlDesigner::PropertyName &name, QVariant *value)
113
114
115
116
{
    if (modelNode.isValid() && modelNode.metaInfo().isValid()
            && (modelNode.metaInfo().propertyTypeName(name) == "QUrl"
                || modelNode.metaInfo().propertyTypeName(name) == "url")) {
117
        if (!value->isValid())
118
119
120
121
            *value = QString(QLatin1String(""));
    }
}

122
123
void PropertyEditorValue::setValueWithEmit(const QVariant &value)
{
124
    if (m_value != value || isBound()) {
125
        QVariant newValue = value;
Marco Bubke's avatar
Marco Bubke committed
126
        if (modelNode().isValid() && modelNode().metaInfo().isValid() && modelNode().metaInfo().hasProperty(name()))
127
            if (modelNode().metaInfo().propertyTypeName(name()) == "QUrl")
128
129
130
131
            newValue = QUrl(newValue.toString());

        if (cleverDoubleCompare(newValue, m_value))
            return;
132
133
        if (cleverColorCompare(newValue, m_value))
            return;
134
135
        setValue(newValue);
        m_isBound = false;
136
        emit valueChanged(name(), value);
137
        emit valueChangedQml();
138
139
140
141
142
143
        emit isBoundChanged();
    }
}

void PropertyEditorValue::setValue(const QVariant &value)
{
144
145
146
147
148
149
    if ((m_value != value) &&
        !cleverDoubleCompare(value, m_value) &&
        !cleverColorCompare(value, m_value))

        m_value = value;

150
    fixAmbigousColorNames(modelNode(), name(), &m_value);
151
    fixUrl(modelNode(), name(), &m_value);
152

153
154
    if (m_value.isValid())
        emit valueChangedQml();
155
    emit isBoundChanged();
156

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
}

QString PropertyEditorValue::expression() const
{

    return m_expression;
}

void PropertyEditorValue::setExpressionWithEmit(const QString &expression)
{
    if ( m_expression != expression) {
        setExpression(expression);
        emit expressionChanged(name());
    }
}

void PropertyEditorValue::setExpression(const QString &expression)
{
    if ( m_expression != expression) {
        m_expression = expression;
177
        emit expressionChanged(QString());
178
179
180
    }
}

181
182
183
184
185
QString PropertyEditorValue::valueToString() const
{
    return value().toString();
}

186
187
bool PropertyEditorValue::isInSubState() const
{
188
    const QmlDesigner::QmlObjectNode objectNode(modelNode());
189
    return objectNode.isValid() && objectNode.currentState().isValid() && objectNode.propertyAffectedByCurrentState(name());
190
191
192
193
}

bool PropertyEditorValue::isBound() const
{
194
195
    const QmlDesigner::QmlObjectNode objectNode(modelNode());
    return objectNode.isValid() && objectNode.hasBindingProperty(name());
196
197
198
199
}

bool PropertyEditorValue::isInModel() const
{
200
    return modelNode().isValid() && modelNode().hasProperty(name());
201
202
}

203
QmlDesigner::PropertyName PropertyEditorValue::name() const
204
205
206
207
{
    return m_name;
}

208
void PropertyEditorValue::setName(const QmlDesigner::PropertyName &name)
209
210
211
212
213
214
215
{
    m_name = name;
}


bool PropertyEditorValue::isValid() const
{
216
    return m_isValid;
217
218
219
220
221
222
223
}

void PropertyEditorValue::setIsValid(bool valid)
{
    m_isValid = valid;
}

224
225
226
bool PropertyEditorValue::isTranslated() const
{
    if (modelNode().isValid() && modelNode().metaInfo().isValid() && modelNode().metaInfo().hasProperty(name()))
227
        if (modelNode().metaInfo().propertyTypeName(name()) == "QString" || modelNode().metaInfo().propertyTypeName(name()) == "string") {
228
229
230
231
232
233
234
235
236
237
238
239
            const QmlDesigner::QmlObjectNode objectNode(modelNode());
            if (objectNode.isValid() && objectNode.hasBindingProperty(name())) {
                //qsTr()
                QRegExp rx("qsTr(\"*\")");
                rx.setPatternSyntax(QRegExp::Wildcard);
                return rx.exactMatch(expression());
            }
            return false;
        }
    return false;
}

240
QmlDesigner::ModelNode PropertyEditorValue::modelNode() const
241
242
243
244
{
    return m_modelNode;
}

245
void PropertyEditorValue::setModelNode(const QmlDesigner::ModelNode &modelNode)
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
{
    if (modelNode != m_modelNode) {
        m_modelNode = modelNode;
        m_complexNode->update();
        emit modelNodeChanged();
    }
}

PropertyEditorNodeWrapper* PropertyEditorValue::complexNode()
{
    return m_complexNode;
}

void PropertyEditorValue::resetValue()
{
261
262
    if (m_value.isValid() || isBound()) {
        m_value = QVariant();
263
        m_isBound = false;
264
        emit valueChanged(name(), QVariant());
265
266
267
    }
}

268
269
void PropertyEditorValue::registerDeclarativeTypes()
{
Roberto Raggi's avatar
Roberto Raggi committed
270
271
272
    qmlRegisterType<PropertyEditorValue>("Bauhaus",1,0,"PropertyEditorValue");
    qmlRegisterType<PropertyEditorNodeWrapper>("Bauhaus",1,0,"PropertyEditorNodeWrapper");
    qmlRegisterType<QDeclarativePropertyMap>("Bauhaus",1,0,"QDeclarativePropertyMap");
273
274
}

275
PropertyEditorNodeWrapper::PropertyEditorNodeWrapper(PropertyEditorValue* parent) : QObject(parent), m_valuesPropertyMap(this)
276
277
278
279
280
{
    m_editorValue = parent;
    connect(m_editorValue, SIGNAL(modelNodeChanged()), this, SLOT(update()));
}

281
PropertyEditorNodeWrapper::PropertyEditorNodeWrapper(QObject *parent) : QObject(parent), m_editorValue(NULL)
282
283
284
285
286
287
288
289
290
291
292
293
294
{
}

bool PropertyEditorNodeWrapper::exists()
{
    if (!(m_editorValue && m_editorValue->modelNode().isValid()))
        return false;

    return m_modelNode.isValid();
}

QString PropertyEditorNodeWrapper::type()
{
295
    if (!(m_modelNode.isValid()))
296
        return QString();
297

298
    return QString::fromUtf8(m_modelNode.simplifiedTypeName());
299
300
301

}

302
QmlDesigner::ModelNode PropertyEditorNodeWrapper::parentModelNode() const
303
304
305
306
{
    return  m_editorValue->modelNode();
}

307
QmlDesigner::PropertyName PropertyEditorNodeWrapper::propertyName() const
308
309
310
311
{
    return m_editorValue->name();
}

312
QDeclarativePropertyMap* PropertyEditorNodeWrapper::properties()
313
{
314
    return &m_valuesPropertyMap;
315
316
317
318
}

void PropertyEditorNodeWrapper::add(const QString &type)
{
319
    QmlDesigner::TypeName propertyType = type.toUtf8();
320
321

    if ((m_editorValue && m_editorValue->modelNode().isValid())) {
322
        if (propertyType.isEmpty())
323
            propertyType = m_editorValue->modelNode().metaInfo().propertyTypeName(m_editorValue->name());
324
325
        while (propertyType.contains('*')) //strip star
            propertyType.chop(1);
326
        m_modelNode = m_editorValue->modelNode().view()->createModelNode(propertyType, 4, 7);
327
        m_editorValue->modelNode().nodeAbstractProperty(m_editorValue->name()).reparentHere(m_modelNode);
328
        if (!m_modelNode.isValid())
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
            qWarning("PropertyEditorNodeWrapper::add failed");
    } else {
        qWarning("PropertyEditorNodeWrapper::add failed - node invalid");
    }
    setup();
}

void PropertyEditorNodeWrapper::remove()
{
    if ((m_editorValue && m_editorValue->modelNode().isValid())) {
        if (QmlDesigner::QmlObjectNode(m_modelNode).isValid())
            QmlDesigner::QmlObjectNode(m_modelNode).destroy();
        m_editorValue->modelNode().removeProperty(m_editorValue->name());
    } else {
        qWarning("PropertyEditorNodeWrapper::remove failed - node invalid");
    }
    m_modelNode = QmlDesigner::ModelNode();

    foreach (const QString &propertyName, m_valuesPropertyMap.keys())
        m_valuesPropertyMap.clear(propertyName);
    foreach (QObject *object, m_valuesPropertyMap.children())
        delete object;
    emit propertiesChanged();
    emit existsChanged();
}

355
void PropertyEditorNodeWrapper::changeValue(const QString &propertyName)
356
{
357
358
    const QmlDesigner::PropertyName name = propertyName.toUtf8();

359
360
    if (name.isNull())
        return;
361
362
363
364
365
366
    if (m_modelNode.isValid()) {
        QmlDesigner::QmlObjectNode fxObjectNode(m_modelNode);

        PropertyEditorValue *valueObject = qvariant_cast<PropertyEditorValue *>(m_valuesPropertyMap.value(name));

        if (valueObject->value().isValid())
367
            fxObjectNode.setVariantProperty(name, valueObject->value());
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
        else
            fxObjectNode.removeVariantProperty(name);
    }
}

void PropertyEditorNodeWrapper::setup()
{
    Q_ASSERT(m_editorValue);
    Q_ASSERT(m_editorValue->modelNode().isValid());
    if ((m_editorValue->modelNode().isValid() && m_modelNode.isValid())) {
        QmlDesigner::QmlObjectNode fxObjectNode(m_modelNode);
        foreach ( const QString &propertyName, m_valuesPropertyMap.keys())
            m_valuesPropertyMap.clear(propertyName);
        foreach (QObject *object, m_valuesPropertyMap.children())
            delete object;

384
        foreach (const QmlDesigner::PropertyName &propertyName, m_modelNode.metaInfo().propertyNames()) {
385
386
387
388
            if (fxObjectNode.isValid()) {
                PropertyEditorValue *valueObject = new PropertyEditorValue(&m_valuesPropertyMap);
                valueObject->setName(propertyName);
                valueObject->setValue(fxObjectNode.instanceValue(propertyName));
Robert Loehning's avatar
Robert Loehning committed
389
                connect(valueObject, SIGNAL(valueChanged(QString,QVariant)), &m_valuesPropertyMap, SIGNAL(valueChanged(QString,QVariant)));
390
391
                m_valuesPropertyMap.insert(propertyName, QVariant::fromValue(valueObject));
            }
392
393
        }
    }
Robert Loehning's avatar
Robert Loehning committed
394
    connect(&m_valuesPropertyMap, SIGNAL(valueChanged(QString,QVariant)), this, SLOT(changeValue(QString)));
395
396
397
398
399
400
401
402

    emit propertiesChanged();
    emit existsChanged();
}

void PropertyEditorNodeWrapper::update()
{
    if (m_editorValue && m_editorValue->modelNode().isValid()) {
403
        if (m_editorValue->modelNode().hasProperty(m_editorValue->name()) && m_editorValue->modelNode().property(m_editorValue->name()).isNodeProperty())
404
405
406
407
408
409
            m_modelNode = m_editorValue->modelNode().nodeProperty(m_editorValue->name()).modelNode();
        setup();
        emit existsChanged();
        emit typeChanged();
    }
}
410