PDA

View Full Version : Is this a Qt5 bug



acmezger
16th August 2013, 12:23
with Qt5 when in a ui file for a property an empty string is set:

then calling the designer will trigger my appropriate routine in my custom widget

however when loading the file with the QuiLoader the routine will not be triggered.

In Qt4.8.4 the routine was triggered.

Is this a new feature (unwanted) or a bug or one has to do something special ?

ChrisW67
16th August 2013, 21:09
What does an empty property have to do calling a routine? Code will only be executed in response to ui activity if you connect signals from ui objects to slots in your code.

acmezger
17th August 2013, 19:00
I do not think you are right. It is possible that a default string inside a custom widget has to be emptied. That is also the way that the designer responds to an ui file. It is also the way that Qt4.8.4 QuiLoader works. That this does not work in the Qt5.1 QuiLoader means that the above philosophy does not apply any more and that a lot of reprogramming is necessary in my case. So this new "feature" is for me not the continuation of an existing philophy and therefore for me an unwanted new feature or bug. The user has to decide if an empty string is significant or not. In any case such a change of philosophy could be mentioned and I wonder why the designer does is correctly but the QuiLoader does not!

ChrisW67
17th August 2013, 21:12
You are going to have to demonstrate the problem in code because I still have no idea what it is.

acmezger
18th August 2013, 10:04
Dear Chris,

There is not much to show, but perhaps I describe the problem more in detail:

I have a designer plugin with custom widgets. In one of my widgets a string property is initialized with a non empty string and write and read routines are defined for it.
I call the designer and when I drag my custom widget to the window I want to design, at that moment the property will have my default string.
In case I change that string or empty it and then create the ui file, the property in the ui file has the value I put in (empty or not) while the write routine is automatically called
When I call the designer again with the ui file, that property has therefore the right value (empty or not)
However when in my application program, I call the QuiLoader with the ui file , then for the non empty string the write routine is not called int Qt5.1 as was in Qt4.8.4 and previous, but for a non-empty string the routine gets called normally.

Anyhow I do not understand the difference I get between the behaviour of the designer and calling the QuiLoader myself, while I guess that the QuiLoader is also used by the designer.

Best regards

Anton

anda_skoa
18th August 2013, 14:25
Is it just the empty string or are none of the properties applied?

Cheers,
_

acmezger
20th August 2013, 07:08
all the properties are applied except the empty string

wysota
20th August 2013, 08:11
I also don't understand what your problem is but just trying to guess, I would assume that when loading a plugin in Designer some code of yours is called and when loading the same plugin via QUiLoader the code is not called. I have no idea how the code behaves in Qt5, but in Qt4 when a plugin is loaded into Designer, an instance of each widget offered by the plugin is created so that the Designer can query the widget for default values of each property (so that later when you ask it to reset the property value, it knows what to set). Then the widget is destroyed. This behaviour is not required for QUiLoader as it doesn't need to know default values for properties. It could be that in Qt4 QUiLoader used to perform the check for some reason and that this code was removed in Qt5. If that's the case then you were using an undocumented feature and you can't blame anyone that this behaviour has been changed. If I correctly understood your problem then please state what was your intent behind using that "feature". If I didn't understand what you mean then it is likely you should rephrase the problem again :)

anda_skoa
20th August 2013, 09:16
all the properties are applied except the empty string

This does sound like a bug to me as well.

If the UI file has a property element for a widget then this should lead to a setProperty() call.
If I understand you correctly that happens for all other properties and even for the string property if the value in the UI XML is not the empty string, correct?

I wonder if it would be possible to write a unit test which shows this behavior. I guess the tricky part would be the plugin but there must be other tests that use plugin functionality.

At least a very simple test project would be a good thing, i.e. a minimal custom widget with a string property in a plugin, a minimum .ui file and a simple program loading it.

Cheers,
_

wysota
20th August 2013, 09:44
If the UI file has a property element for a widget then this should lead to a setProperty() call.
And this happens only if the property value is different from the default value for that property.

This is the ui file for an empty form:

<ui version="4.0" >
<author></author>
<comment></comment>
<exportmacro></exportmacro>
<class>Form</class>
<widget class="QWidget" name="Form" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle" >
<string>Form</string>
</property>
</widget>
<pixmapfunction></pixmapfunction>
<connections/>
</ui>

This is the generated Ui class:


/************************************************** ******************************
** Form generated from reading UI file 'form.ui'
**
** Created by: Qt User Interface Compiler version 5.1.0
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
************************************************** ******************************/

#ifndef FORM_H
#define FORM_H

#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QWidget>

QT_BEGIN_NAMESPACE

class Ui_Form
{
public:

void setupUi(QWidget *Form)
{
if (Form->objectName().isEmpty())
Form->setObjectName(QStringLiteral("Form"));
Form->resize(400, 300);

retranslateUi(Form);

QMetaObject::connectSlotsByName(Form);
} // setupUi

void retranslateUi(QWidget *Form)
{
Form->setWindowTitle(QApplication::translate("Form", "Form", 0));
} // retranslateUi

};

namespace Ui {
class Form: public Ui_Form {};
} // namespace Ui

QT_END_NAMESPACE

#endif // FORM_H

You can see the form (and the class) references only those properties that have non-default values. All others are silently ignored.

If you reset the "geometry" property to default in Designer, you get this (the "geometry" property is gone):

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="windowTitle">
<string>Form</string>
</property>
</widget>
<resources/>
<connections/>
</ui>

So the basic question is whether the UI file does refer to that property.

Edit: there is this code in QUiLoader (at least in the revision I have):


foreach (const DomProperty *p, properties) {
QUiTranslatableStringValue strVal;
const QString text = convertTranslatable(p, m_class, &strVal);
if (text.isEmpty())
continue;
const QByteArray name = p->attributeName().toUtf8();
if (dynamicTr) {
const QByteArray dynname = QByteArray(PROP_GENERIC_PREFIX + name);
o->setProperty(dynname, QVariant::fromValue(strVal));
anyTrs = trEnabled;
}
o->setProperty(name, text);
}

Which (lines #4-5) seems to imply that if a property has an empty string value in the ui file, it will be ignored. Note, this only applies to string properties.

acmezger
20th August 2013, 13:36
I think this must happen at another point of the code while

1. QuiLoader is more or less the same code in 4.8.2 and 5.1
2. in case of a property which is not empty, but has several blancs as below, the problem is the same
<property name="args">
<string notr="true"> </string>
</property>


I will try to point it down

thanks for your help

wysota
20th August 2013, 13:55
Blanks only matter if the XML parser says so. As far as the standard is concerned <a/> and <a> </a> may be equivalent.



Could you say why are you relying on such behaviour?

anda_skoa
20th August 2013, 15:03
Which (lines #4-5) seems to imply that if a property has an empty string value in the ui file, it will be ignored. Note, this only applies to string properties.

Right, but this is very strange behavior. It is up to the property setter to determine if nothing is to be done, e.g. if there was no change.

As we have seen designer will not even generate a property element if the default has no been changed, so if there is a propery element it is not the default.
UiLoader cannot just assume that empty string is the default for every possible string property.

It would be like assuming that all int properties are 0 by default and not calling their setter if the property element in the UI file has 0 as its content. Does QUiLoader do that?

Cheers,
_

wysota
20th August 2013, 15:12
As we have seen designer will not even generate a property element if the default has no been changed, so if there is a propery element it is not the default.
UiLoader cannot just assume that empty string is the default for every possible string property.
The actual code is a little bit more complex than what I posted.

convertTranslable() returns a string but this string is not really the value of the property. It will be empty when the property is not a string property (which is ok in this case) or when the property has notr set to "true" (or "yes").

In addition to that there is another loop elsewhere that iterates over all properties and sets them. Maybe the empty strings are caught there?



It would be like assuming that all int properties are 0 by default and not calling their setter if the property element in the UI file has 0 as its content.

Yeah, that would be stupid. However contrary to QString, int has no default value of its own so even "0" would have to be set to it.

acmezger
20th August 2013, 15:25
It is not in the quiloader.cpp that the problem is sitting. thre routins did not really change from qt4.8 to qt5.1. The problem must be elsewher, but I did not find it until now.
The interesting thing is still that the designer does it correctly, but an application program using quiloader gets this strange behaviour. As has been pointed out, it should be an user decision if a white space is relevant or not.

I hope somebody will find the relevant code.

wysota
20th August 2013, 15:48
It is not in the quiloader.cpp that the problem is sitting. thre routins did not really change from qt4.8 to qt5.1. The problem must be elsewher, but I did not find it until now.
The interesting thing is still that the designer does it correctly, but an application program using quiloader gets this strange behaviour. As has been pointed out, it should be an user decision if a white space is relevant or not.

Are you modifying the ui file by hand?

acmezger
20th August 2013, 17:17
No, I modify with the designer. However I do not think that is relevant.

wysota
20th August 2013, 18:38
No, I modify with the designer. However I do not think that is relevant.

So it is the Designer that inserts the empty property in the ui file? Is it the default value for that property?

This is relevant as usually trailing and leading whitespaces in xml tags are ignored so if you insert a number of pure spaces into the property, the parser will likely ignore them. If you want, you can use some other (even non-printable) character instead of a space and you should get your desired result. You can also just redefine your property -- if it is the number of spaces that is important, instead of the string property create an integer (or enum) property where you will keep the number. You can even implement the use-number-only-if-text-empty semantics.

acmezger
21st August 2013, 06:40
I could of course modify everything, but anyhow it worked fine in 4.8 and there is no real explanation what changed in 5.1

regards

wysota
21st August 2013, 07:37
You were using an undocumented feature in 4.8. Maybe they changed the behaviour because some other code was broken and was considered more important than your use-case.

anda_skoa
21st August 2013, 08:00
I am confused now. I thought the problem was that an empty string was not applied, but now it is about incorrect number of whitespaces?

Cheers,
_

acmezger
21st August 2013, 20:56
that does not explain why the designer handles an empty string correctly, but quiloader not!

regards

anda, it is about an empty string, the number of blancs is not important

regards

wysota
21st August 2013, 22:14
that does not explain why the designer handles an empty string correctly, but quiloader not!

"Correctly" is a relative term.


anda, it is about an empty string, the number of blancs is not important

Now I'm confused. So you say QUiLoader should call your method to replace the empty string with an empty string? That's not really how the property system works. If you are relying on such behavior then you are abusing the system. Property setters are for changing property values, not for something else. If you want to do some initialization or something like that, better do it either in the constructor or using QMetaObject::invokeMethod(..., Qt::QueuedConnection) to execute some code after the flow returns to the event loop.

Could you try to explain to us what your method is doing and why?

acmezger
22nd August 2013, 08:28
in my custom widget I initialize the property to a non-empty string. with the designer I construct my custom widget by emptying the string. This is reflected in the ui file. When I then load in my application with quiloader.load the routine responsible for setting this property is not called in qt5.1 but called in qt4.8

regards

wysota
22nd August 2013, 09:02
And why are you doing that?

acmezger
22nd August 2013, 09:41
my custom widget needs a default non-empty string that can be emptied by the user . in principle that should not matter

regards

wysota
22nd August 2013, 10:31
If you're not willing to share more information, then I can't help you, sorry.

acmezger
22nd August 2013, 10:51
9450945194489449
I can do not more than give you these attachments of a custom widget

anda_skoa
22nd August 2013, 12:56
that does not explain why the designer handles an empty string correctly, but quiloader not!

Indeed.



anda, it is about an empty string, the number of blancs is not important


Right. With the recent discussion on spaces I wasn't sure anymore if we were talking about empty strings or non-empty string with whitespace only.

Lets be sure :)
You have a widget like this


class Widget : public QWidget
{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText)

public:
explicit Widget(QWidget *parent = 0) : QWidget(parent), m_text("foo") {}

void setText(const QString &text) { m_text = text; }
QString text() const { return m_text;}

private:
QString m_text;
};


And what you expect to happen is something like this (using QtTest syntax)


Widget *w = new Widget;
QVERIFY(!w->text().isEmpty());

w->setProperty("text", QString());
QVERIFY(w->text().isEmpty());


Only that creation and setProperty() call should have been done by the QUiLoader, right?

Cheers,
_

acmezger
22nd August 2013, 13:55
yes, that is it. A better idea you can get through the sources a attached before

regards

acmezger
23rd August 2013, 17:03
Folks,

this is really a bug in QFormLoader and has been solved by the Qt-Gurus. see bug 33130

thanks to you all participating

regards

Anton