Correct text alignment preservation and add basic options parsing

Also add a test case and Remove some dead code along the way.

Task-number: QDS-2071
Change-Id: If34d4e152860ec9ab098f07e36e3a5dc4368c67f
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Michael Brüning
2020-05-31 22:58:33 +02:00
parent c2bba223e6
commit 6419059362
6 changed files with 302 additions and 57 deletions

View File

@@ -41,6 +41,7 @@ struct ReparentInfo {
bool alreadyReparented;
};
class StylesheetMerger {
public:
StylesheetMerger(AbstractView*, AbstractView*);
@@ -60,11 +61,21 @@ private:
void syncBindingProperties(ModelNode &outputNode, const ModelNode &inputNode);
void syncAuxiliaryProperties(ModelNode &outputNode, const ModelNode &inputNode);
void syncVariantProperties(ModelNode &outputNode, const ModelNode &inputNode);
void parseTemplateOptions();
AbstractView *m_templateView;
AbstractView *m_styleView;
QHash<QString, ReparentInfo> m_reparentInfoHash;
QHash<QString, QString> m_idReplacementHash;
struct Options {
bool preserveTextAlignment;
Options() : preserveTextAlignment(false)
{}
};
Options m_options;
};
}

View File

@@ -39,6 +39,42 @@
#include <QQueue>
#include <QRegularExpression>
namespace {
QPoint pointForModelNode(const QmlDesigner::ModelNode &node)
{
int x = 0;
if (node.hasVariantProperty("x"))
x = node.variantProperty("x").value().toInt();
int y = 0;
if (node.hasVariantProperty("y"))
y = node.variantProperty("y").value().toInt();
return QPoint(x, y);
}
QPoint parentPosition(const QmlDesigner::ModelNode &node)
{
QPoint p;
QmlDesigner::ModelNode currentNode = node;
while (currentNode.hasParentProperty()) {
currentNode = currentNode.parentProperty().parentModelNode();
p += pointForModelNode(currentNode);
}
return p;
}
bool isTextAlignmentProperty(const QmlDesigner::VariantProperty &property)
{
return property.name() == "horizontalAlignment"
|| property.name() == "verticalAlignment"
|| property.name() == "elide";
}
} // namespace
namespace QmlDesigner {
static void splitIdInBaseNameAndNumber(const QString &id, QString *baseId, int *number)
@@ -139,15 +175,18 @@ void StylesheetMerger::setupIdRenamingHash()
ModelNode StylesheetMerger::createReplacementNode(const ModelNode& styleNode, ModelNode &modelNode)
{
QList<QPair<PropertyName, QVariant> > propertyList;
QList<QPair<PropertyName, QVariant> > variantPropertyList;
QList<QPair<PropertyName, QVariant> > auxPropertyList;
NodeMetaInfo nodeMetaInfo = m_templateView->model()->metaInfo(styleNode.type());
for (const VariantProperty &variantProperty : modelNode.variantProperties()) {
if (nodeMetaInfo.hasProperty(variantProperty.name()))
if (!nodeMetaInfo.hasProperty(variantProperty.name()))
continue;
if (isTextAlignmentProperty(variantProperty) && !m_options.preserveTextAlignment && !styleNode.hasProperty(variantProperty.name()))
continue;
propertyList.append(QPair<PropertyName, QVariant>(variantProperty.name(), variantProperty.value()));
}
ModelNode newNode(m_templateView->createModelNode(styleNode.type(), nodeMetaInfo.majorVersion(), nodeMetaInfo.minorVersion(),
propertyList, variantPropertyList, styleNode.nodeSource(), styleNode.nodeSourceType()));
propertyList, auxPropertyList, styleNode.nodeSource(), styleNode.nodeSourceType()));
syncAuxiliaryProperties(newNode, modelNode);
syncBindingProperties(newNode, modelNode);
@@ -169,32 +208,6 @@ bool StylesheetMerger::idExistsInBothModels(const QString& id)
return m_templateView->hasId(id) && m_styleView->hasId(id);
}
QPoint pointForModelNode(const ModelNode &node)
{
int x = 0;
if (node.hasVariantProperty("x"))
x = node.variantProperty("x").value().toInt();
int y = 0;
if (node.hasVariantProperty("y"))
y = node.variantProperty("y").value().toInt();
return QPoint(x, y);
}
QPoint parentPosition(const ModelNode &node)
{
QPoint p;
ModelNode currentNode = node;
while (currentNode.hasParentProperty()) {
currentNode = currentNode.parentProperty().parentModelNode();
p += pointForModelNode(currentNode);
}
return p;
}
void StylesheetMerger::preprocessStyleSheet()
{
try {
@@ -349,10 +362,14 @@ void StylesheetMerger::applyStyleProperties(ModelNode &templateNode, const Model
templateNode.removeProperty(variantProperty.name());
templateNode.variantProperty(variantProperty.name()).setValue(variantProperty.value());
}
} else {
if (variantProperty.holdsEnumeration()) {
templateNode.variantProperty(variantProperty.name()).setEnumeration(variantProperty.enumeration().toEnumerationName());
} else {
templateNode.variantProperty(variantProperty.name()).setValue(variantProperty.value());
}
}
}
syncBindingProperties(templateNode, styleNode);
syncNodeProperties(templateNode, styleNode, true);
syncNodeListProperties(templateNode, styleNode, true);
@@ -365,12 +382,43 @@ static void removePropertyIfExists(ModelNode node, const PropertyName &propertyN
}
void StylesheetMerger::parseTemplateOptions()
{
if (!m_templateView->hasId(QStringLiteral("qds_stylesheet_merger_options")))
return;
ModelNode optionsNode = m_templateView->modelNodeForId(QStringLiteral("qds_stylesheet_merger_options"));
if (optionsNode.hasVariantProperty("preserveTextAlignment")) {
m_options.preserveTextAlignment = optionsNode.variantProperty("preserveTextAlignment").value().toBool();
}
try {
RewriterTransaction transaction(m_templateView, "remove-options-node");
optionsNode.destroy();
transaction.commit();
} catch (InvalidIdException &ide) {
qDebug().noquote() << "Invalid id exception while removing options from template.";
ide.createWarning();
} catch (InvalidReparentingException &rpe) {
qDebug().noquote() << "Invalid reparenting exception while removing options from template.";
rpe.createWarning();
} catch (InvalidModelNodeException &mne) {
qDebug().noquote() << "Invalid model node exception while removing options from template.";
mne.createWarning();
} catch (Exception &e) {
qDebug().noquote() << "Exception while removing options from template.";
e.createWarning();
}
}
void StylesheetMerger::merge()
{
ModelNode templateRootNode = m_templateView->rootModelNode();
ModelNode styleRootNode = m_styleView->rootModelNode();
// first, build up the hierarchy in the style sheet as we have it in the template
// first, look if there are any options present in the template
parseTemplateOptions();
// second, build up the hierarchy in the style sheet as we have it in the template
preprocessStyleSheet();
// build a hash of generated replacement ids

View File

@@ -3706,23 +3706,6 @@ void tst_TestCore::testCopyModelRewriter1()
QCOMPARE(textEdit1.toPlainText(), expected);
}
static void adjustPreservedProperties(const ModelNode& replacedNode, ModelNode& newNode) {
QSet<PropertyName> preservedProperties;
preservedProperties.insert("x");
preservedProperties.insert("y");
preservedProperties.insert("width");
preservedProperties.insert("height");
preservedProperties.insert("anchors");
// preservedProperties.insert("text ");
for (VariantProperty originalProperty : replacedNode.variantProperties()) {
VariantProperty prop;
if (preservedProperties.contains(originalProperty.name())) {
newNode.variantProperty(originalProperty.name()).setValue(originalProperty.value());
}
}
}
static QString readQmlFromFile(const QString& fileName)
{
QFile qmlFile(fileName);
@@ -3776,6 +3759,9 @@ void tst_TestCore::testMergeModelRewriter1_data()
QString buttonStyleUiQmlContents = readQmlFromFile(QString(TESTSRCDIR) + "/../data/merging/ButtonStyle.ui.qml");
QString buttonStyleUiExpectedQmlContents = readQmlFromFile(QString(TESTSRCDIR) + "/../data/merging/ButtonStyle.ui.Expected.qml");
QString buttonAbsoluteTemplateWithOptionsQmlContents = readQmlFromFile(QString(TESTSRCDIR) + "/../data/merging/ButtonAbsoluteTemplateWithOptions.qml");
QString buttonStyleUiWithOptionsExpectedQmlContents = readQmlFromFile(QString(TESTSRCDIR) + "/../data/merging/ButtonStyleWithOptions.ui.Expected.qml");
QTest::newRow("Simple style replacement") << simpleTemplateQmlContents << simpleStyleQmlContents << simpleExpectedQmlContents;
QTest::newRow("Complex style replacement") << complexTemplateQmlContents << complexStyleQmlContents << complexExpectedQmlContents;
QTest::newRow("Empty stylesheet") << emptyTemplateQmlContents << emptyStyleQmlContents << emptyExpectedQmlContents;
@@ -3788,6 +3774,8 @@ void tst_TestCore::testMergeModelRewriter1_data()
QTest::newRow("Button Outline styling") << buttonAbsoluteTemplateQmlContents << buttonOutlineStyleQmlContents << buttonOutlineExpectedQmlContents;
QTest::newRow("Button Designer styling") << buttonAbsoluteTemplateQmlContents << buttonStyleUiQmlContents << buttonStyleUiExpectedQmlContents;
QTest::newRow("Button Designer styling with options") << buttonAbsoluteTemplateWithOptionsQmlContents << buttonStyleUiQmlContents << buttonStyleUiWithOptionsExpectedQmlContents;
}
void tst_TestCore::testMergeModelRewriter1()

View File

@@ -0,0 +1,109 @@
import QtQuick 2.10
import QtQuick.Templates 2.1 as T
T.Button {
id: control
implicitWidth: Math.max(
background ? background.implicitWidth : 0,
contentItem.implicitWidth + leftPadding + rightPadding)
implicitHeight: Math.max(
background ? background.implicitHeight : 0,
contentItem.implicitHeight + topPadding + bottomPadding)
leftPadding: 4
rightPadding: 4
text: "My Button"
background: Item {
implicitWidth: buttonNormal.width
implicitHeight: buttonNormal.height
opacity: enabled ? 1 : 0.3
Rectangle {
id: buttonNormal
color: "#d4d4d4"
width: 100 //Bit of black magic to define the default size
height: 40
border.color: "gray"
border.width: 1
radius: 2
anchors.fill: parent //binding has to be preserved
Text {
id: normalText
x: 26
y: 14 //id only required to preserve binding
text: control.text //binding has to be preserved
//anchors.fill: parent
color: "gray"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
}
Rectangle {
id: buttonPressed
color: "#d4d4d4"
width: 100 //Bit of black magic to define the default size
height: 40
border.color: "gray"
border.width: 1
radius: 2
anchors.fill: parent //binding has to be preserved
Text {
x: 26
y: 14
id: pressedText //id only required to preserve binding
text: control.text //binding has to be preserved
//anchors.fill: parent
color: "black"
horizontalAlignment: Text.AlignHCenter // should not be preserved
verticalAlignment: Text.AlignVCenter // should not be preserved
elide: Text.ElideRight // should not be preserved
}
}
}
contentItem: Item {}
states: [
State {
name: "normal"
when: !control.down
PropertyChanges {
target: buttonPressed
visible: false
}
PropertyChanges {
target: buttonNormal
visible: true
}
},
State {
name: "down"
when: control.down
PropertyChanges {
target: buttonPressed
visible: true
}
PropertyChanges {
target: buttonNormal
visible: false
}
}
]
QtObject {
id: qds_stylesheet_merger_options
property bool preserveTextAlignment: true
}
}

View File

@@ -32,11 +32,8 @@ T.Button {
y: 50
color: "#bbbbbb"
text: control.text
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 24
font.letterSpacing: 0.594
font.pixelSize: 24
}
}
@@ -52,11 +49,8 @@ T.Button {
y: 50
color: "#e1e1e1"
text: control.text
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 24
font.letterSpacing: 0.594
font.pixelSize: 24
}
}

View File

@@ -0,0 +1,95 @@
import QtQuick 2.10
import QtQuick.Templates 2.1 as T
T.Button {
id: control
implicitWidth: Math.max(
background ? background.implicitWidth : 0,
contentItem.implicitWidth + leftPadding + rightPadding)
implicitHeight: Math.max(
background ? background.implicitHeight : 0,
contentItem.implicitHeight + topPadding + bottomPadding)
leftPadding: 4
rightPadding: 4
text: "My Button"
background: Item {
implicitWidth: buttonNormal.width
implicitHeight: buttonNormal.height
opacity: enabled ? 1 : 0.3
Image {
id: buttonNormal
width: 100
height: 40
anchors.fill: parent
source: "assets/buttonNormal.png"
Text {
id: normalText
x: 58
y: 50
color: "#bbbbbb"
text: control.text
elide: Text.ElideRight
font.letterSpacing: 0.594
font.pixelSize: 24
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Image {
id: buttonPressed
width: 100
height: 40
anchors.fill: parent
source: "assets/buttonPressed.png"
Text {
id: pressedText
x: 58
y: 50
color: "#e1e1e1"
text: control.text
elide: Text.ElideRight
font.letterSpacing: 0.594
font.pixelSize: 24
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
}
contentItem: Item {}
states: [
State {
name: "normal"
when: !control.down
PropertyChanges {
target: buttonPressed
visible: false
}
PropertyChanges {
target: buttonNormal
visible: true
}
},
State {
name: "down"
when: control.down
PropertyChanges {
target: buttonPressed
visible: true
}
PropertyChanges {
target: buttonNormal
visible: false
}
}
]
}