forked from qt-creator/qt-creator
QmlDesigner: Implementing NodeHints
This class evaluates expressions from .metainfo files. Those expressions can script and control the behavior of items in the designer. Change-Id: I9f1ec7dd70f1124a684afe6620de5b81c8cc5a30 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
committed by
Tim Jenssen
parent
11eb66643c
commit
c1e3fd9f3e
@@ -19,6 +19,7 @@ SOURCES += $$PWD/model/abstractview.cpp \
|
|||||||
$$PWD/metainfo/metainfo.cpp \
|
$$PWD/metainfo/metainfo.cpp \
|
||||||
$$PWD/metainfo/metainforeader.cpp \
|
$$PWD/metainfo/metainforeader.cpp \
|
||||||
$$PWD/metainfo/nodemetainfo.cpp \
|
$$PWD/metainfo/nodemetainfo.cpp \
|
||||||
|
$$PWD/metainfo/nodehints.cpp \
|
||||||
$$PWD/metainfo/itemlibraryinfo.cpp \
|
$$PWD/metainfo/itemlibraryinfo.cpp \
|
||||||
$$PWD/metainfo/subcomponentmanager.cpp \
|
$$PWD/metainfo/subcomponentmanager.cpp \
|
||||||
$$PWD/model/internalproperty.cpp \
|
$$PWD/model/internalproperty.cpp \
|
||||||
@@ -87,6 +88,7 @@ HEADERS += $$PWD/include/qmldesignercorelib_global.h \
|
|||||||
$$PWD/include/metainfo.h \
|
$$PWD/include/metainfo.h \
|
||||||
$$PWD/include/metainforeader.h \
|
$$PWD/include/metainforeader.h \
|
||||||
$$PWD/include/nodemetainfo.h \
|
$$PWD/include/nodemetainfo.h \
|
||||||
|
$$PWD/include/nodehints.h \
|
||||||
$$PWD/include/itemlibraryinfo.h \
|
$$PWD/include/itemlibraryinfo.h \
|
||||||
$$PWD/model/internalproperty.h \
|
$$PWD/model/internalproperty.h \
|
||||||
$$PWD/include/modelnode.h \
|
$$PWD/include/modelnode.h \
|
||||||
|
111
src/plugins/qmldesigner/designercore/include/nodehints.h
Normal file
111
src/plugins/qmldesigner/designercore/include/nodehints.h
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** 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 The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QString>
|
||||||
|
#include "modelnode.h"
|
||||||
|
|
||||||
|
#include "qmldesignercorelib_global.h"
|
||||||
|
#include "invalidmetainfoexception.h"
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QDeclarativeContext;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
class MetaInfo;
|
||||||
|
class Model;
|
||||||
|
class AbstractProperty;
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
|
class MetaInfoPrivate;
|
||||||
|
class MetaInfoReader;
|
||||||
|
class SubComponentManagerPrivate;
|
||||||
|
class ItemLibraryEntryData;
|
||||||
|
class NodeMetaInfoPrivate;
|
||||||
|
}
|
||||||
|
|
||||||
|
class QMLDESIGNERCORE_EXPORT NodeHints
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NodeHints();
|
||||||
|
NodeHints(const ModelNode &modelNode);
|
||||||
|
|
||||||
|
bool canBeContainer() const;
|
||||||
|
bool forceClip() const;
|
||||||
|
bool doesLayoutChildren() const;
|
||||||
|
bool canBeDroppedInFormEditor() const;
|
||||||
|
bool canBeDroppedInNavigator() const;
|
||||||
|
bool isMovable() const;
|
||||||
|
bool isStackedContainer() const;
|
||||||
|
QString indexPropertyForStackedContainer() const;
|
||||||
|
|
||||||
|
QHash<QString, QString> hints() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ModelNode modelNode() const;
|
||||||
|
bool isValid() const;
|
||||||
|
Model *model() const;
|
||||||
|
bool evaluateBooleanExpression(const QString &hintName, bool defaultValue) const;
|
||||||
|
|
||||||
|
ModelNode m_modelNode;
|
||||||
|
QHash<QString, QString> m_hints;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class JSObject : public QObject {
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(bool hasParent READ hasParent NOTIFY modelNodeChanged)
|
||||||
|
Q_PROPERTY(bool hasChildren READ hasChildren NOTIFY modelNodeChanged)
|
||||||
|
Q_PROPERTY(bool currentParentIsRoot READ currentParentIsRoot NOTIFY modelNodeChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
JSObject();
|
||||||
|
JSObject(QObject *parent = 0);
|
||||||
|
void setModelNode(const ModelNode &node);
|
||||||
|
bool hasParent() const;
|
||||||
|
bool hasChildren() const;
|
||||||
|
bool currentParentIsRoot() const;
|
||||||
|
|
||||||
|
Q_INVOKABLE bool isSubclassOf(const QString &typeName);
|
||||||
|
Q_INVOKABLE bool rootItemIsSubclassOf(const QString &typeName);
|
||||||
|
Q_INVOKABLE bool currentParentIsSubclassOf(const QString &typeName);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void modelNodeChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ModelNode m_modelNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
} //Internal
|
||||||
|
|
||||||
|
} //QmlDesigner
|
258
src/plugins/qmldesigner/designercore/metainfo/nodehints.cpp
Normal file
258
src/plugins/qmldesigner/designercore/metainfo/nodehints.cpp
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** 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 The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "nodehints.h"
|
||||||
|
#include "model.h"
|
||||||
|
|
||||||
|
#include "metainfo.h"
|
||||||
|
#include <enumeration.h>
|
||||||
|
#include <rewriterview.h>
|
||||||
|
#include <propertyparser.h>
|
||||||
|
#include <nodeabstractproperty.h>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include <qmljs/qmljsscopechain.h>
|
||||||
|
#include <qmljs/parser/qmljsast_p.h>
|
||||||
|
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||||
|
#include <qmljs/qmljsvalueowner.h>
|
||||||
|
#include <languageutils/fakemetaobject.h>
|
||||||
|
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <itemlibraryinfo.h>
|
||||||
|
|
||||||
|
#include <QJSEngine>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
static QJSEngine *s_qJSEngine= nullptr;
|
||||||
|
static JSObject *s_jsObject = nullptr;
|
||||||
|
|
||||||
|
static QVariant evaluateExpression(const QString &expression, const ModelNode &modelNode)
|
||||||
|
{
|
||||||
|
if (!s_qJSEngine) {
|
||||||
|
s_qJSEngine = new QJSEngine;
|
||||||
|
s_jsObject = new JSObject(s_qJSEngine);
|
||||||
|
QJSValue jsValue = s_qJSEngine->newQObject(s_jsObject);
|
||||||
|
s_qJSEngine->globalObject().setProperty("model", jsValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
s_jsObject->setModelNode(modelNode);
|
||||||
|
return s_qJSEngine->evaluate(expression).toVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
} //Internal
|
||||||
|
|
||||||
|
QmlDesigner::NodeHints::NodeHints()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QmlDesigner::NodeHints::NodeHints(const ModelNode &node) : m_modelNode(node)
|
||||||
|
{
|
||||||
|
if (isValid()) {
|
||||||
|
const ItemLibraryInfo *libraryInfo = model()->metaInfo().itemLibraryInfo();
|
||||||
|
QList <ItemLibraryEntry> itemLibraryEntryList = libraryInfo->entriesForType(
|
||||||
|
modelNode().type(), modelNode().majorVersion(), modelNode().minorVersion());
|
||||||
|
m_hints = itemLibraryEntryList.first().hints();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NodeHints::canBeContainer() const
|
||||||
|
{
|
||||||
|
/* The default is true for now to avoid confusion. Once our .metaInfo files in Qt
|
||||||
|
use the feature we can change the default to false. */
|
||||||
|
|
||||||
|
if (!isValid())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return evaluateBooleanExpression("canBeContainer", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NodeHints::forceClip() const
|
||||||
|
{
|
||||||
|
if (!isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return evaluateBooleanExpression("forceClip", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NodeHints::doesLayoutChildren() const
|
||||||
|
{
|
||||||
|
if (!isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return evaluateBooleanExpression("doesLayoutChildren", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NodeHints::canBeDroppedInFormEditor() const
|
||||||
|
{
|
||||||
|
if (!isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return evaluateBooleanExpression("canBeDroppedInFormEditor", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NodeHints::canBeDroppedInNavigator() const
|
||||||
|
{
|
||||||
|
if (!isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return evaluateBooleanExpression("canBeDroppedInNavigator", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NodeHints::isMovable() const
|
||||||
|
{
|
||||||
|
if (!isValid())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return evaluateBooleanExpression("isMovable", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NodeHints::isStackedContainer() const
|
||||||
|
{
|
||||||
|
if (!isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return evaluateBooleanExpression("isStackedContainer", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString NodeHints::indexPropertyForStackedContainer() const
|
||||||
|
{
|
||||||
|
if (!isValid())
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
const QString expression = m_hints.value("indexPropertyForStackedContainer");
|
||||||
|
|
||||||
|
if (expression.isEmpty())
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
return Internal::evaluateExpression(expression, modelNode()).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<QString, QString> NodeHints::hints() const
|
||||||
|
{
|
||||||
|
return m_hints;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelNode NodeHints::modelNode() const
|
||||||
|
{
|
||||||
|
return m_modelNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NodeHints::isValid() const
|
||||||
|
{
|
||||||
|
return modelNode().isValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
Model *NodeHints::model() const
|
||||||
|
{
|
||||||
|
return modelNode().model();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NodeHints::evaluateBooleanExpression(const QString &hintName, bool defaultValue) const
|
||||||
|
{
|
||||||
|
const QString expression = m_hints.value(hintName);
|
||||||
|
|
||||||
|
if (expression.isEmpty())
|
||||||
|
return defaultValue;
|
||||||
|
|
||||||
|
return Internal::evaluateExpression(expression, modelNode()).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
QmlDesigner::Internal::JSObject::JSObject::JSObject(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSObject::setModelNode(const ModelNode &node)
|
||||||
|
{
|
||||||
|
m_modelNode = node;
|
||||||
|
emit modelNodeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSObject::hasParent() const
|
||||||
|
{
|
||||||
|
return !m_modelNode.isRootNode()
|
||||||
|
&& m_modelNode.hasParentProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSObject::hasChildren() const
|
||||||
|
{
|
||||||
|
return m_modelNode.hasAnySubModelNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSObject::currentParentIsRoot() const
|
||||||
|
{
|
||||||
|
return m_modelNode.hasParentProperty()
|
||||||
|
&& m_modelNode.parentProperty().isValid()
|
||||||
|
&& m_modelNode.parentProperty().parentModelNode().isRootNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSObject::isSubclassOf(const QString &typeName)
|
||||||
|
{
|
||||||
|
NodeMetaInfo metaInfo = m_modelNode.metaInfo();
|
||||||
|
|
||||||
|
if (metaInfo.isValid())
|
||||||
|
metaInfo.isSubclassOf(typeName.toUtf8());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSObject::rootItemIsSubclassOf(const QString &typeName)
|
||||||
|
{
|
||||||
|
NodeMetaInfo metaInfo = m_modelNode.view()->rootModelNode().metaInfo();
|
||||||
|
|
||||||
|
if (metaInfo.isValid())
|
||||||
|
metaInfo.isSubclassOf(typeName.toUtf8());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSObject::currentParentIsSubclassOf(const QString &typeName)
|
||||||
|
{
|
||||||
|
if ( m_modelNode.hasParentProperty()
|
||||||
|
&& m_modelNode.parentProperty().isValid()) {
|
||||||
|
NodeMetaInfo metaInfo = m_modelNode.parentProperty().parentModelNode().metaInfo();
|
||||||
|
if (metaInfo.isValid())
|
||||||
|
metaInfo.isSubclassOf(typeName.toUtf8());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject::JSObject()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} //Internal
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -257,6 +257,7 @@ Project {
|
|||||||
"include/nodeinstanceview.h",
|
"include/nodeinstanceview.h",
|
||||||
"include/nodelistproperty.h",
|
"include/nodelistproperty.h",
|
||||||
"include/nodemetainfo.h",
|
"include/nodemetainfo.h",
|
||||||
|
"include/nodehints.h",
|
||||||
"include/nodeproperty.h",
|
"include/nodeproperty.h",
|
||||||
"include/notimplementedexception.h",
|
"include/notimplementedexception.h",
|
||||||
"include/plaintexteditmodifier.h",
|
"include/plaintexteditmodifier.h",
|
||||||
@@ -294,6 +295,7 @@ Project {
|
|||||||
"metainfo/metainfo.cpp",
|
"metainfo/metainfo.cpp",
|
||||||
"metainfo/metainforeader.cpp",
|
"metainfo/metainforeader.cpp",
|
||||||
"metainfo/nodemetainfo.cpp",
|
"metainfo/nodemetainfo.cpp",
|
||||||
|
"metainfo/nodehints.cpp",
|
||||||
"metainfo/subcomponentmanager.cpp",
|
"metainfo/subcomponentmanager.cpp",
|
||||||
"model/abstractproperty.cpp",
|
"model/abstractproperty.cpp",
|
||||||
"model/abstractview.cpp",
|
"model/abstractview.cpp",
|
||||||
|
Reference in New Issue
Block a user