QML: Add library table#4594
Conversation
2a9d6a7 to
455e0fc
Compare
|
similar to the waveform PR, I would like to keep QML moving quickly. If it's possible to get some experimental code merged in as a start, let's do it. |
c30b370 to
83a2d0c
Compare
|
Ok, I think this is ready to review. I'm particulary interested in feedback regard the custom The advantage of this is that the skin designer can decide what rows should be displayed, what order they should have, etc. and does not have to make assumptions about what column of the table contains what. Our playlist is displayed as a table, but semantically it's just a list of tracks, not a table. |
|
Rebased on #4673 to make stuff like |
a465bb4 to
a0a0c6e
Compare
|
Rebased, ready to review again. |
| \ | ||
| void QmlTableFromListModelColumn::getterSetterName( \ | ||
| const QJSValue& stringOrFunction) { \ | ||
| if (!stringOrFunction.isString() && !stringOrFunction.isCallable()) { \ |
There was a problem hiding this comment.
Due to the macro nature all this code is duplicated. It would be better to use helper functions for this.
This also helps to get around of some macro weirdness when debugging.
Maybe there is a chance to omit using the macro entirely. Currently it has already 7 parameter.
Maybe we can replace it wit 7 lines of c++ code forwarding to a template or something.
If you wish to go with the macro solution you may consider to use only the property name as parameter.
Like shown here:
Line 21 in d67b057
But I would prefer a c++ based solution even if it involves more writing initaly.
There was a problem hiding this comment.
This macro-based solution works fine IMHO. If you want to replace the macros in a follow-up PR, feel free to do so.
|
@Holzhaus With a fresh profile the library panel remains empty. Warnings only affect other QML files. |
What do you mean by "it remains empty"? Is this a regression from the current QML library? |
Ah, this is unrelated to this PR and also happens on main (with QML). The reason for this is the weird way the model is populated. It requires calling A workaround for diff --git a/res/qml/Library.qml b/res/qml/Library.qml
index 657cb58203..917e73147d 100644
--- a/res/qml/Library.qml
+++ b/res/qml/Library.qml
@@ -43,6 +43,7 @@ Item {
}
function loadSelectedTrackIntoNextAvailableDeck(play) {
+ model.select();
const url = model.get(currentIndex).fileUrl;
if (!url)
return ;
@@ -51,6 +52,7 @@ Item {
}
function loadSelectedTrack(group, play) {
+ model.select();
const url = model.get(currentIndex).fileUrl;
if (!url)
return ;
diff --git a/src/qml/qmllibrarytracklistmodel.h b/src/qml/qmllibrarytracklistmodel.h
index 490ff4508c..65b89cce46 100644
--- a/src/qml/qmllibrarytracklistmodel.h
+++ b/src/qml/qmllibrarytracklistmodel.h
@@ -1,4 +1,5 @@
#pragma once
+#include "library/trackmodel.h"
#include <QIdentityProxyModel>
#include <QtQml>
@@ -25,6 +26,10 @@ class QmlLibraryTrackListModel : public QIdentityProxyModel {
QmlLibraryTrackListModel(LibraryTableModel* pModel, QObject* pParent = nullptr);
~QmlLibraryTrackListModel() = default;
+ Q_INVOKABLE void select() {
+ dynamic_cast<TrackModel*>(sourceModel())->select();
+ }
+
QVariant data(const QModelIndex& index, int role) const override;
int columnCount(const QModelIndex& index = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override;Now, if you double click a track in the table after dragging and dropping a new track onto a deck, the new track shows up. :-/ |
|
This PR is marked as stale because it has been open 90 days with no activity. |
7251d5d to
17fb124
Compare
fa54d6e to
7f250a3
Compare
7f250a3 to
2280857
Compare
|
Merge? |
Swiftb0y
left a comment
There was a problem hiding this comment.
I'm still torn on the amount of boilerplate required for this. I'll take a closer look asap. Thank you for reviving this again.
Swiftb0y
left a comment
There was a problem hiding this comment.
don't think I can find the time for much more right now.
| Q_PROPERTY(int columnCount READ columnCount NOTIFY columnCountChanged FINAL) | ||
| Q_PROPERTY(QAbstractItemModel* sourceModel READ sourceModel WRITE | ||
| setSourceModel NOTIFY sourceModelChanged REQUIRED FINAL) | ||
| Q_PROPERTY(QQmlListProperty<mixxx::qml::QmlTableFromListModelColumn> columns | ||
| READ columns CONSTANT FINAL) |
There was a problem hiding this comment.
have you experimented with QProperty, could it reduce some of the boilerplate?
|
|
||
| class QmlTableFromListModel : public QAbstractTableModel, public QQmlParserStatus { |
There was a problem hiding this comment.
Can you add an explanation for why this class exists exactly?
| Keys.onEnterPressed: this.loadSelectedTrackIntoNextAvailableDeck(false) | ||
| Keys.onReturnPressed: this.loadSelectedTrackIntoNextAvailableDeck(false) | ||
| columnWidthProvider: function(column) { | ||
| switch (column) { |
There was a problem hiding this comment.
Is this related to the model defined in line 41? Could we make it so the custom default width is defined in model instead of here? Perhaps moving the model to be global property of library?
| Mixxx.TableFromListModelColumn { | ||
| decoration: "color" | ||
| edit: "fileUrl" | ||
| } |
There was a problem hiding this comment.
Could a Repeater be used here with the model defined at line 41?
| const QHash<int, QByteArray>& sourceRoleNames = m_pSourceModel->roleNames(); | ||
| for (auto it = sourceRoleNames.cbegin(); it != sourceRoleNames.cend(); it++) { | ||
| int roleId = it.key(); | ||
| m_sourceRoles.insert(QString::fromUtf8(it.value()), roleId); | ||
| } |
There was a problem hiding this comment.
Is the for-each loop format not possible here?
There was a problem hiding this comment.
I don't think so, we want both key and value.
There was a problem hiding this comment.
There is a new method asKeyValueRange in Qt 6.4 allowing this. Not sure if it is worth having behind preprocessor for when we upgrade to this Qt version?
| const QHash<int, QByteArray>& sourceRoleNames = m_pSourceModel->roleNames(); | |
| for (auto it = sourceRoleNames.cbegin(); it != sourceRoleNames.cend(); it++) { | |
| int roleId = it.key(); | |
| m_sourceRoles.insert(QString::fromUtf8(it.value()), roleId); | |
| } | |
| const QHash<int, QByteArray>& sourceRoleNames = m_pSourceModel->roleNames(); | |
| for (auto [roleId, value] : sourceRoleNames.asKeyValueRange()) { | |
| m_sourceRoles.insert(QString::fromUtf8(value), roleId); | |
| } |
| return m_getters; | ||
| } | ||
| const QHash<int, QString> QmlTableFromListModelColumn::supportedRoleNames() { | ||
| QHash<int, QString> names; |
There was a problem hiding this comment.
Perhaps this could be a constant like kRoleNames?
| QJSValue setterAtRole(const QString& roleName); | ||
| const QHash<QString, QJSValue> getters() const; | ||
| static const QHash<int, QString> supportedRoleNames(); | ||
| Q_SIGNALS: |
There was a problem hiding this comment.
perhaps using signals would be more consistent with the rest of the codebase
|
Marking this as draft for now @Holzhaus - feel free to mark it ready again once we should give it another go! |
Based on #4567 and #4654.