Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Track: Add missing NOTIFY signals for Q_PROPERTY declarations #3924

Merged
merged 8 commits into from
Jun 4, 2021

Conversation

Holzhaus
Copy link
Member

This fixes some clazy-qproperty-without-notify warnings. Every
Q_PROPERTY should either have a NOTIFY signal or be declared as
CONSTANT.

See this for details:

This fixes some clazy-qproperty-without-notify warnings. Every
`Q_PROPERTY` should either have a `NOTIFY` signal or be declared as
`CONSTANT`.

See this for details:
- https://github.com/KDE/clazy/blob/master/docs/checks/README-qproperty-without-notify.md
- https://doc.qt.io/qt-5.12/properties.html
@Holzhaus
Copy link
Member Author

@daschuer With this, I can emit the proper signals in #3911 atomically. This should also improve QML performance with lots of decks/samplers.

@uklotzde
Copy link
Contributor

uklotzde commented May 29, 2021

All those properties might also change when invoking one of the following functions:

  • replaceMetadataFromSource()
  • mergeExtraMetadataFromSource() (probably no properties affected yet)
  • replaceRecord()
  • exportMetadata()
  • setAudioProperties()
  • updateStreamInfoFromSource()

We could simply trigger all property changed signals in the first step to ensure consistency, especially for the first 4 methods.

Q_PROPERTY(int timesPlayed READ getTimesPlayed NOTIFY timesPlayedChanged)
Q_PROPERTY(QString comment READ getComment WRITE setComment NOTIFY commentChanged)
Q_PROPERTY(double bpm READ getBpm NOTIFY bpmUpdated)
Q_PROPERTY(QString bpmFormatted READ getBpmText STORED false NOTIFY bpmUpdated)
Copy link
Contributor

@uklotzde uklotzde May 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change signal has a different type than the property. Is this intended? I would expect that all change signals emit the actual property type.

This also applies to the key text and formatted duration.

Copy link
Member Author

@Holzhaus Holzhaus May 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The signals without parameters are intended:

A NOTIFY signal is optional. If defined, it should specify one existing signal in that class that is emitted whenever the value of the property changes. NOTIFY signals for MEMBER variables must take zero or one parameter, which must be of the same type as the property.

https://doc.qt.io/qt-5.12/properties.html

The type mismatch is unintended though :D

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -84,6 +84,9 @@ Track::Track(
<< "->"
<< numberOfInstancesBefore + 1;
}

connect(this, &Track::titleChanged, this, &Track::infoChanged);
connect(this, &Track::artistChanged, this, &Track::infoChanged);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to call the additional signals explicit.
For less magic to consider in case of future refactoring.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You want me to add slots that only contain emit infoChanged() ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I mean copy emit infoChanged() below emit artistChanged()

Than the call tree has one interruption less when debugging.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Than we can consider to get rid of infoChanged() in favor of changed()

Copy link
Member Author

@Holzhaus Holzhaus May 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the signal signature is incompatible. I added the direct emit statements as you suggested.

@Holzhaus
Copy link
Member Author

  • exportMetadata()

Does this really modify any metadata?

  • setAudioProperties()
  • updateStreamInfoFromSource()

This can only change the duration, right?

I added some commits, please have a look.

@uklotzde
Copy link
Contributor

Ok, exportMetadata() doesn't seem to modify any of those exposed properties. It might only update hidden, internal members.

Duration should be the only Q_PROPERTY that is affected by stream info changes.

@Holzhaus
Copy link
Member Author

Ok, then I think this is ready.

Q_PROPERTY(int timesPlayed READ getTimesPlayed NOTIFY timesPlayedChanged)
Q_PROPERTY(QString comment READ getComment WRITE setComment NOTIFY commentChanged)
Q_PROPERTY(double bpm READ getBpm NOTIFY bpmUpdated)
Q_PROPERTY(QString bpmFormatted READ getBpmText STORED false NOTIFY bpmTextChanged)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about consistently adopting the Text prefix for all formatted (= derived text) properties, i.e. bpmFormatted -> bpmText for consistency?

This also applies to key -> keyText / keysUpdated -> keyTextUpdated.

Even worse are the naming inconsistencies of the various duration properties. I didn't check how much code would be affected.

Managing all those updates and their dependencies is tedious and error prone.. Unfortunately, I have no idea how to adopt and apply FRP principles in Qt/QML or what idiomatic patterns they propose instead.

void trackNumberChanged(const QString&);
void trackTotalChanged(const QString&);
void commentChanged(const QString&);
void bpmTextChanged();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do some signals carry the value and others not?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, even the docs don't apply a consistent approach:

https://doc.qt.io/qt-5/properties.html

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 or 1 parameter are allowed, but if the new value is provided as a parameter than it's type must match the type of the property.

In order to keep the number of signals low let's apply the following rationale:

  • For native properties without any derived properties provide the new value if possible
  • For properties with derived properties use the name of the native property, reuse the signal for all derived properties, and don't provide any value.

By applying this rule we need to revert bpmTextChanged to bpmChanged.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Track object with its thread synchronization is a bastard and not really suitable for this purpose. What we actually would need is a distinction between view model and domain model classes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For native properties without any derived properties provide the new
value if possible. For properties with derived properties use the name
of the native property, reuse the signal for all derived properties, and
don't provide any value.
Copy link
Member

@daschuer daschuer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is a signal missing in:
Track::setType(const QString& sType)
Track::setBitrate(int iBitrate)
Track::setURL(const QString& url)
Track::shiftCuePositionsMillis(double milliseconds)
Track::setRating (int rating)
Track::setBpmLocked(bool bpmLocked)

I am unsure if everything is correct in
Track::updateStreamInfoFromSource()
There is either an emitMetadataChanged() missing, or an redundant markDirtyAndUnlock(&lock); call.

src/track/track.cpp Outdated Show resolved Hide resolved
src/track/track.cpp Show resolved Hide resolved
@Holzhaus
Copy link
Member Author

Holzhaus commented Jun 1, 2021

is a signal missing in:
Track::setType(const QString& sType)
Track::setBitrate(int iBitrate)
Track::setURL(const QString& url)
Track::shiftCuePositionsMillis(double milliseconds)
Track::setRating (int rating)
Track::setBpmLocked(bool bpmLocked)

None of those is a Q_PROPERTY. We can add more if we need to, but this is out of scope here.

I am unsure if everything is correct in
Track::updateStreamInfoFromSource()
There is either an emitMetadataChanged() missing, or an redundant markDirtyAndUnlock(&lock); call.

Good catch, added the missing durationChanged signal.

@Holzhaus Holzhaus requested a review from daschuer June 1, 2021 19:11
@uklotzde
Copy link
Contributor

uklotzde commented Jun 4, 2021

@daschuer Ping

@daschuer
Copy link
Member

daschuer commented Jun 4, 2021

LGTM, thank you.

@daschuer daschuer merged commit 3ab1e5f into mixxxdj:main Jun 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

3 participants