QmlDesigner: Integrate Expression Builder

Task-number: QDS-10587
Change-Id: Ifc13a8364fccb74cb60d683f0e6c322d80baab50
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Henning Gruendl
2023-09-04 16:45:54 +02:00
committed by Henning Gründl
parent cbf4273bab
commit 5e8b5ec1f0
15 changed files with 1205 additions and 53 deletions

View File

@@ -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;

View File

@@ -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

View File

@@ -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());

View File

@@ -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]() {

View File

@@ -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;