forked from qt-creator/qt-creator
QmlDesigner: Integrate Expression Builder
Task-number: QDS-10587 Change-Id: Ifc13a8364fccb74cb60d683f0e6c322d80baab50 Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
committed by
Henning Gründl
parent
cbf4273bab
commit
5e8b5ec1f0
@@ -559,8 +559,13 @@ QHash<int, QByteArray> ConnectionModel::roleNames() const
|
||||
}
|
||||
|
||||
ConnectionModelBackendDelegate::ConnectionModelBackendDelegate(ConnectionModel *parent)
|
||||
: QObject(parent), m_signalDelegate(parent->connectionView()), m_okStatementDelegate(parent),
|
||||
m_koStatementDelegate(parent), m_conditionListModel(parent)
|
||||
: QObject(parent)
|
||||
, m_signalDelegate(parent->connectionView())
|
||||
, m_okStatementDelegate(parent)
|
||||
, m_koStatementDelegate(parent)
|
||||
, m_conditionListModel(parent)
|
||||
, m_propertyTreeModel(parent->connectionView())
|
||||
, m_propertyListProxyModel(&m_propertyTreeModel)
|
||||
{
|
||||
connect(&m_signalDelegate, &PropertyTreeModelDelegate::commitData, this, [this]() {
|
||||
handleTargetChanged();
|
||||
@@ -753,6 +758,9 @@ void ConnectionModelBackendDelegate::setCurrentRow(int i)
|
||||
|
||||
m_currentRow = i;
|
||||
|
||||
m_propertyTreeModel.resetModel();
|
||||
m_propertyListProxyModel.setRowAndInternalId(0, -1);
|
||||
|
||||
//setup
|
||||
|
||||
ConnectionModel *model = qobject_cast<ConnectionModel *>(parent());
|
||||
@@ -870,6 +878,16 @@ void ConnectionModelBackendDelegate::setSource(const QString &source)
|
||||
emit sourceChanged();
|
||||
}
|
||||
|
||||
PropertyTreeModel *ConnectionModelBackendDelegate::propertyTreeModel()
|
||||
{
|
||||
return &m_propertyTreeModel;
|
||||
}
|
||||
|
||||
PropertyListProxyModel *ConnectionModelBackendDelegate::propertyListProxyModel()
|
||||
{
|
||||
return &m_propertyListProxyModel;
|
||||
}
|
||||
|
||||
void ConnectionModelBackendDelegate::setupCondition()
|
||||
{
|
||||
auto &condition = ConnectionEditorStatements::matchedCondition(m_handler);
|
||||
@@ -1575,30 +1593,83 @@ ConditionListModel::ConditionToken ConditionListModel::tokenFromComparativeState
|
||||
|
||||
void ConditionListModel::insertToken(int index, const QString &value)
|
||||
{
|
||||
beginInsertRows({}, index, index);
|
||||
|
||||
m_tokens.insert(index, valueToToken(value));
|
||||
validateAndRebuildTokens();
|
||||
resetModel();
|
||||
|
||||
endInsertRows();
|
||||
//resetModel();
|
||||
}
|
||||
|
||||
void ConditionListModel::updateToken(int index, const QString &value)
|
||||
{
|
||||
m_tokens[index] = valueToToken(value);
|
||||
validateAndRebuildTokens();
|
||||
resetModel();
|
||||
|
||||
dataChanged(createIndex(index, 0), createIndex(index, 0));
|
||||
//resetModel();
|
||||
}
|
||||
|
||||
void ConditionListModel::appendToken(const QString &value)
|
||||
{
|
||||
beginInsertRows({}, rowCount() - 1, rowCount() - 1);
|
||||
|
||||
insertToken(rowCount(), value);
|
||||
validateAndRebuildTokens();
|
||||
resetModel();
|
||||
|
||||
endInsertRows();
|
||||
//resetModel();
|
||||
}
|
||||
|
||||
void ConditionListModel::removeToken(int index)
|
||||
{
|
||||
beginRemoveRows({}, index, index);
|
||||
|
||||
m_tokens.remove(index, 1);
|
||||
validateAndRebuildTokens();
|
||||
resetModel();
|
||||
|
||||
endRemoveRows();
|
||||
|
||||
//resetModel();
|
||||
}
|
||||
|
||||
void ConditionListModel::insertIntermediateToken(int index, const QString &value)
|
||||
{
|
||||
beginInsertRows({}, index, index);
|
||||
|
||||
ConditionToken token;
|
||||
token.type = Intermediate;
|
||||
token.value = value;
|
||||
|
||||
m_tokens.insert(index, token);
|
||||
|
||||
endInsertRows();
|
||||
//resetModel();
|
||||
}
|
||||
|
||||
void ConditionListModel::insertShadowToken(int index, const QString &value)
|
||||
{
|
||||
beginInsertRows({}, index, index);
|
||||
|
||||
ConditionToken token;
|
||||
token.type = Shadow;
|
||||
token.value = value;
|
||||
|
||||
m_tokens.insert(index, token);
|
||||
|
||||
endInsertRows();
|
||||
|
||||
//resetModel();
|
||||
}
|
||||
|
||||
void ConditionListModel::setShadowToken(int index, const QString &value)
|
||||
{
|
||||
m_tokens[index].type = Shadow;
|
||||
m_tokens[index].value = value;
|
||||
|
||||
dataChanged(createIndex(index, 0), createIndex(index, 0));
|
||||
//resetModel();
|
||||
}
|
||||
|
||||
bool ConditionListModel::valid() const
|
||||
@@ -1655,20 +1726,29 @@ void ConditionListModel::command(const QString &string)
|
||||
}
|
||||
}
|
||||
|
||||
void ConditionListModel::setInvalid(const QString &errorMessage)
|
||||
void ConditionListModel::setInvalid(const QString &errorMessage, int index)
|
||||
{
|
||||
m_valid = false;
|
||||
m_errorMessage = errorMessage;
|
||||
|
||||
emit errorChanged();
|
||||
emit validChanged();
|
||||
|
||||
if (index != -1) {
|
||||
m_errorIndex = index;
|
||||
emit errorIndexChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ConditionListModel::setValid()
|
||||
{
|
||||
m_valid = true;
|
||||
m_errorMessage.clear();
|
||||
m_errorIndex = -1;
|
||||
|
||||
emit errorChanged();
|
||||
emit validChanged();
|
||||
emit errorIndexChanged();
|
||||
}
|
||||
|
||||
QString ConditionListModel::error() const
|
||||
@@ -1676,6 +1756,11 @@ QString ConditionListModel::error() const
|
||||
return m_errorMessage;
|
||||
}
|
||||
|
||||
int ConditionListModel::errorIndex() const
|
||||
{
|
||||
return m_errorIndex;
|
||||
}
|
||||
|
||||
void ConditionListModel::internalSetup()
|
||||
{
|
||||
setInvalid(tr("No Valid Condition"));
|
||||
@@ -1766,11 +1851,26 @@ int ConditionListModel::checkOrder() const
|
||||
it++;
|
||||
ret++;
|
||||
}
|
||||
|
||||
if (wasOperator)
|
||||
return ret;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ConditionListModel::validateAndRebuildTokens()
|
||||
{
|
||||
/// NEW
|
||||
auto it = m_tokens.begin();
|
||||
|
||||
while (it != m_tokens.end()) {
|
||||
if (it->type == Intermediate)
|
||||
*it = valueToToken(it->value);
|
||||
|
||||
it++;
|
||||
}
|
||||
// NEW
|
||||
|
||||
QString invalidValue;
|
||||
const bool invalidToken = Utils::contains(m_tokens,
|
||||
[&invalidValue](const ConditionToken &token) {
|
||||
@@ -1780,12 +1880,12 @@ void ConditionListModel::validateAndRebuildTokens()
|
||||
});
|
||||
|
||||
if (invalidToken) {
|
||||
setInvalid(tr("Invalid token %").arg(invalidToken));
|
||||
setInvalid(tr("Invalid token %1").arg(invalidValue));
|
||||
return;
|
||||
}
|
||||
|
||||
if (int firstError = checkOrder() != -1) {
|
||||
setInvalid(tr("Invalid order at %1").arg(firstError));
|
||||
setInvalid(tr("Invalid order at %1").arg(firstError), firstError);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1831,9 +1931,6 @@ ConnectionEditorStatements::ConditionToken ConditionListModel::toOperatorStateme
|
||||
if (token.value == "!==")
|
||||
return ConnectionEditorStatements::ConditionToken::Not;
|
||||
|
||||
if (token.value == "!==")
|
||||
return ConnectionEditorStatements::ConditionToken::Not;
|
||||
|
||||
if (token.value == ">")
|
||||
return ConnectionEditorStatements::ConditionToken::LargerThan;
|
||||
|
||||
|
||||
@@ -96,9 +96,10 @@ class ConditionListModel : public QAbstractListModel
|
||||
Q_PROPERTY(bool valid READ valid NOTIFY validChanged)
|
||||
Q_PROPERTY(bool empty READ empty NOTIFY emptyChanged)
|
||||
Q_PROPERTY(QString error READ error NOTIFY errorChanged)
|
||||
Q_PROPERTY(int errorIndex READ errorIndex NOTIFY errorIndexChanged)
|
||||
|
||||
public:
|
||||
enum ConditionType { Invalid, Operator, Literal, Variable };
|
||||
enum ConditionType { Intermediate, Invalid, Operator, Literal, Variable, Shadow };
|
||||
Q_ENUM(ConditionType)
|
||||
|
||||
struct ConditionToken
|
||||
@@ -129,22 +130,28 @@ public:
|
||||
Q_INVOKABLE void appendToken(const QString &value);
|
||||
Q_INVOKABLE void removeToken(int index);
|
||||
|
||||
Q_INVOKABLE void insertIntermediateToken(int index, const QString &value);
|
||||
Q_INVOKABLE void insertShadowToken(int index, const QString &value);
|
||||
Q_INVOKABLE void setShadowToken(int index, const QString &value);
|
||||
|
||||
bool valid() const;
|
||||
bool empty() const;
|
||||
|
||||
//for debugging
|
||||
Q_INVOKABLE void command(const QString &string);
|
||||
|
||||
void setInvalid(const QString &errorMessage);
|
||||
void setInvalid(const QString &errorMessage, int index = -1);
|
||||
void setValid();
|
||||
|
||||
QString error() const;
|
||||
int errorIndex() const;
|
||||
|
||||
signals:
|
||||
void validChanged();
|
||||
void emptyChanged();
|
||||
void conditionChanged();
|
||||
void errorChanged();
|
||||
void errorIndexChanged();
|
||||
|
||||
private:
|
||||
void internalSetup();
|
||||
@@ -162,6 +169,7 @@ private:
|
||||
QList<ConditionToken> m_tokens;
|
||||
bool m_valid = false;
|
||||
QString m_errorMessage;
|
||||
int m_errorIndex = -1;
|
||||
};
|
||||
|
||||
class ConnectionModelStatementDelegate : public QObject
|
||||
@@ -245,6 +253,9 @@ class ConnectionModelBackendDelegate : public QObject
|
||||
Q_PROPERTY(bool hasElse READ hasElse NOTIFY hasElseChanged)
|
||||
Q_PROPERTY(QString source READ source NOTIFY sourceChanged)
|
||||
|
||||
Q_PROPERTY(PropertyTreeModel *propertyTreeModel READ propertyTreeModel CONSTANT)
|
||||
Q_PROPERTY(PropertyListProxyModel *propertyListProxyModel READ propertyListProxyModel CONSTANT)
|
||||
|
||||
public:
|
||||
explicit ConnectionModelBackendDelegate(ConnectionModel *parent = nullptr);
|
||||
|
||||
@@ -282,6 +293,10 @@ private:
|
||||
ConditionListModel *conditionListModel();
|
||||
QString source() const;
|
||||
void setSource(const QString &source);
|
||||
|
||||
PropertyTreeModel *propertyTreeModel();
|
||||
PropertyListProxyModel *propertyListProxyModel();
|
||||
|
||||
void setupCondition();
|
||||
void setupHandlerAndStatements();
|
||||
|
||||
@@ -303,6 +318,8 @@ private:
|
||||
bool m_hasCondition = false;
|
||||
bool m_hasElse = false;
|
||||
QString m_source;
|
||||
PropertyTreeModel m_propertyTreeModel;
|
||||
PropertyListProxyModel m_propertyListProxyModel;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -88,10 +88,13 @@ public:
|
||||
0,
|
||||
"ConnectionModelStatementDelegate");
|
||||
|
||||
qmlRegisterType<ConditionListModel>("ConnectionsEditorEditorBackend",
|
||||
1,
|
||||
0,
|
||||
"ConditionListModel");
|
||||
qmlRegisterType<ConditionListModel>("ConnectionsEditorEditorBackend", 1, 0, "ConditionListModel");
|
||||
|
||||
qmlRegisterType<PropertyTreeModel>("ConnectionsEditorEditorBackend", 1, 0, "PropertyTreeModel");
|
||||
qmlRegisterType<PropertyListProxyModel>("ConnectionsEditorEditorBackend",
|
||||
1,
|
||||
0,
|
||||
"PropertyListProxyModel");
|
||||
|
||||
Theme::setupTheme(engine());
|
||||
|
||||
|
||||
@@ -155,7 +155,8 @@ QVariant PropertyTreeModel::data(const QModelIndex &index, int role) const
|
||||
if (role == RowRole)
|
||||
return index.row();
|
||||
|
||||
if (role == PropertyNameRole || role == PropertyPriorityRole || role == ExpressionRole) {
|
||||
if (role == PropertyNameRole || role == PropertyPriorityRole || role == ExpressionRole
|
||||
|| role == ChildCountRole) {
|
||||
if (!index.isValid())
|
||||
return {};
|
||||
|
||||
@@ -166,26 +167,33 @@ QVariant PropertyTreeModel::data(const QModelIndex &index, int role) const
|
||||
|
||||
DataCacheItem item = m_indexHash[index.internalId()];
|
||||
|
||||
if (item.propertyName.isEmpty()) { //node
|
||||
if (role == PropertyNameRole)
|
||||
return item.modelNode.displayName();
|
||||
|
||||
return true; //nodes are always shown
|
||||
}
|
||||
if (role == ChildCountRole)
|
||||
return rowCount(index);
|
||||
|
||||
if (role == ExpressionRole)
|
||||
return QString(item.modelNode.id() + item.propertyName);
|
||||
return QString(item.modelNode.id() + "." + item.propertyName);
|
||||
|
||||
if (role == PropertyNameRole)
|
||||
return item.propertyName;
|
||||
if (role == PropertyNameRole) {
|
||||
if (!item.propertyName.isEmpty())
|
||||
return QString::fromUtf8(item.propertyName);
|
||||
else
|
||||
return item.modelNode.displayName();
|
||||
}
|
||||
|
||||
static const auto priority = properityLists();
|
||||
if (std::find(priority.begin(), priority.end(), item.propertyName) != priority.end())
|
||||
return true; //listed priority properties
|
||||
return true; // listed priority properties
|
||||
|
||||
auto dynamic = getDynamicProperties(item.modelNode);
|
||||
if (std::find(dynamic.begin(), dynamic.end(), item.propertyName) != dynamic.end())
|
||||
return true; //dynamic properties have priority
|
||||
return true; // dynamic properties have priority
|
||||
|
||||
if (item.propertyName.isEmpty()) { //node
|
||||
//if (role == PropertyNameRole)
|
||||
// return item.modelNode.displayName();
|
||||
|
||||
return true; // nodes are always shown
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -216,7 +224,7 @@ QVariant PropertyTreeModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
return item.propertyName;
|
||||
return QString::fromUtf8(item.propertyName);
|
||||
|
||||
QFont f;
|
||||
auto priority = properityLists();
|
||||
@@ -241,7 +249,7 @@ QModelIndex PropertyTreeModel::index(int row, int column, const QModelIndex &par
|
||||
return {};
|
||||
|
||||
if (!hasIndex(row, column, parent))
|
||||
return QModelIndex();
|
||||
return {};
|
||||
|
||||
const int rootId = -1;
|
||||
|
||||
@@ -312,7 +320,7 @@ QModelIndex PropertyTreeModel::parent(const QModelIndex &index) const
|
||||
return ensureModelIndex(item.modelNode, row);
|
||||
}
|
||||
|
||||
QPersistentModelIndex PropertyTreeModel::indexForInernalIdAndRow(int internalId, int row)
|
||||
QPersistentModelIndex PropertyTreeModel::indexForInternalIdAndRow(int internalId, int row)
|
||||
{
|
||||
return createIndex(row, 0, internalId);
|
||||
}
|
||||
@@ -323,7 +331,7 @@ int PropertyTreeModel::rowCount(const QModelIndex &parent) const
|
||||
return 0;
|
||||
|
||||
if (!parent.isValid())
|
||||
return 1;
|
||||
return 1; //m_nodeList.size();
|
||||
|
||||
int internalId = parent.internalId();
|
||||
|
||||
@@ -783,7 +791,8 @@ QHash<int, QByteArray> PropertyTreeModel::roleNames() const
|
||||
{
|
||||
static QHash<int, QByteArray> roleNames{{PropertyNameRole, "propertyName"},
|
||||
{PropertyPriorityRole, "hasPriority"},
|
||||
{ExpressionRole, "expression"}};
|
||||
{ExpressionRole, "expression"},
|
||||
{ChildCountRole, "childCount"}};
|
||||
|
||||
return roleNames;
|
||||
}
|
||||
@@ -792,17 +801,24 @@ PropertyListProxyModel::PropertyListProxyModel(PropertyTreeModel *parent)
|
||||
: QAbstractListModel(), m_treeModel(parent)
|
||||
{}
|
||||
|
||||
void PropertyListProxyModel::setRowandInternalId(int row, int internalId)
|
||||
void PropertyListProxyModel::resetModel()
|
||||
{
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void PropertyListProxyModel::setRowAndInternalId(int row, int internalId)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << row << internalId;
|
||||
QTC_ASSERT(m_treeModel, return );
|
||||
|
||||
if (internalId == -1)
|
||||
m_parentIndex = m_treeModel->index(0, 0);
|
||||
else
|
||||
m_parentIndex = m_treeModel->indexForInernalIdAndRow(internalId, row);
|
||||
m_parentIndex = m_treeModel->index(row, 0, m_parentIndex);
|
||||
//m_parentIndex = m_treeModel->indexForInternalIdAndRow(internalId, row);
|
||||
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
resetModel();
|
||||
}
|
||||
|
||||
int PropertyListProxyModel::rowCount(const QModelIndex &) const
|
||||
@@ -820,6 +836,40 @@ QVariant PropertyListProxyModel::data(const QModelIndex &index, int role) const
|
||||
return m_treeModel->data(treeIndex, role);
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> PropertyListProxyModel::roleNames() const
|
||||
{
|
||||
return m_treeModel->roleNames();
|
||||
}
|
||||
|
||||
void PropertyListProxyModel::goInto(int row)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << row << m_parentIndex.internalId();
|
||||
setRowAndInternalId(row, 0); //m_parentIndex.internalId());
|
||||
|
||||
emit parentNameChanged();
|
||||
}
|
||||
|
||||
void PropertyListProxyModel::goUp()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
m_parentIndex = m_treeModel->parent(m_parentIndex);
|
||||
resetModel();
|
||||
|
||||
emit parentNameChanged();
|
||||
}
|
||||
|
||||
void PropertyListProxyModel::reset()
|
||||
{
|
||||
setRowAndInternalId(0, -1); // TODO ???
|
||||
|
||||
emit parentNameChanged();
|
||||
}
|
||||
|
||||
QString PropertyListProxyModel::parentName() const
|
||||
{
|
||||
return m_treeModel->data(m_parentIndex, PropertyTreeModel::UserRoles::PropertyNameRole).toString();
|
||||
}
|
||||
|
||||
PropertyTreeModelDelegate::PropertyTreeModelDelegate(ConnectionView *parent) : m_model(parent)
|
||||
{
|
||||
connect(&m_nameCombboBox, &StudioQmlComboBoxBackend::activated, this, [this]() {
|
||||
|
||||
@@ -31,6 +31,7 @@ public:
|
||||
PropertyNameRole = Qt::UserRole + 1,
|
||||
PropertyPriorityRole,
|
||||
ExpressionRole,
|
||||
ChildCountRole,
|
||||
RowRole,
|
||||
InternalIdRole
|
||||
};
|
||||
@@ -57,7 +58,7 @@ public:
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
||||
QModelIndex parent(const QModelIndex &index) const override;
|
||||
|
||||
QPersistentModelIndex indexForInernalIdAndRow(int internalId, int row);
|
||||
QPersistentModelIndex indexForInternalIdAndRow(int internalId, int row);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
@@ -70,14 +71,13 @@ public:
|
||||
};
|
||||
|
||||
void setPropertyType(PropertyTypes type);
|
||||
void setFilter(const QString &filter);
|
||||
Q_INVOKABLE void setFilter(const QString &filter);
|
||||
|
||||
QList<ModelNode> nodeList() const;
|
||||
|
||||
const std::vector<PropertyName> getProperties(const ModelNode &modelNode) const;
|
||||
ModelNode getModelNodeForId(const QString &id) const;
|
||||
|
||||
protected:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
private:
|
||||
@@ -127,12 +127,29 @@ private:
|
||||
class PropertyListProxyModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString parentName READ parentName NOTIFY parentNameChanged)
|
||||
|
||||
public:
|
||||
PropertyListProxyModel(PropertyTreeModel *parent);
|
||||
void setRowandInternalId(int row, int internalId);
|
||||
|
||||
void resetModel();
|
||||
|
||||
void setRowAndInternalId(int row, int internalId);
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
Q_INVOKABLE void goInto(int row);
|
||||
Q_INVOKABLE void goUp();
|
||||
Q_INVOKABLE void reset();
|
||||
|
||||
QString parentName() const;
|
||||
|
||||
signals:
|
||||
void parentNameChanged();
|
||||
|
||||
private:
|
||||
ModelNode m_modelNode;
|
||||
PropertyName m_propertyName;
|
||||
|
||||
Reference in New Issue
Block a user