Commit c1e3fd9f authored by Thomas Hartmann's avatar Thomas Hartmann Committed by Tim Jenssen
Browse files

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's avatarTim Jenssen <tim.jenssen@qt.io>
parent 11eb6664
......@@ -19,6 +19,7 @@ SOURCES += $$PWD/model/abstractview.cpp \
$$PWD/metainfo/metainfo.cpp \
$$PWD/metainfo/metainforeader.cpp \
$$PWD/metainfo/nodemetainfo.cpp \
$$PWD/metainfo/nodehints.cpp \
$$PWD/metainfo/itemlibraryinfo.cpp \
$$PWD/metainfo/subcomponentmanager.cpp \
$$PWD/model/internalproperty.cpp \
......@@ -87,6 +88,7 @@ HEADERS += $$PWD/include/qmldesignercorelib_global.h \
$$PWD/include/metainfo.h \
$$PWD/include/metainforeader.h \
$$PWD/include/nodemetainfo.h \
$$PWD/include/nodehints.h \
$$PWD/include/itemlibraryinfo.h \
$$PWD/model/internalproperty.h \
$$PWD/include/modelnode.h \
......
/****************************************************************************
**
** 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
/****************************************************************************
**
** 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/nodelistproperty.h",
"include/nodemetainfo.h",
"include/nodehints.h",
"include/nodeproperty.h",
"include/notimplementedexception.h",
"include/plaintexteditmodifier.h",
......@@ -294,6 +295,7 @@ Project {
"metainfo/metainfo.cpp",
"metainfo/metainforeader.cpp",
"metainfo/nodemetainfo.cpp",
"metainfo/nodehints.cpp",
"metainfo/subcomponentmanager.cpp",
"model/abstractproperty.cpp",
"model/abstractview.cpp",
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment