-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Highlight Crates a Track is in #598
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
Changes from all commits
eb5cf7e
3832e41
dccb519
c48d33a
a096fb6
ca3f011
34ce420
5d09cfa
915c682
f2fb6bf
8f27dc3
4dbc7ac
d9c3db3
29cd09a
dc1f573
dbb60d8
6552667
d6692f0
89e3ad3
986013d
939428f
4a75b85
dd64f07
994300c
6cf15ba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| #include "library/cratehighlightdelegate.h" | ||
| #include "library/treeitem.h" | ||
| #include "trackinfoobject.h" | ||
| #include "libraryfeature.h" | ||
| #include "cratefeature.h" | ||
|
|
||
| CrateHighlightDelegate::CrateHighlightDelegate(QObject* parent) | ||
| : QStyledItemDelegate(parent) { | ||
| } | ||
|
|
||
| // This will be called to by Qt before painting the TreeView-Item. Set up styles here | ||
| void CrateHighlightDelegate::initStyleOption(QStyleOptionViewItem* option, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add here a comment, when it is called? |
||
| const QModelIndex& index) const { | ||
| if (!index.isValid()) { | ||
| return; | ||
| } | ||
|
|
||
| QStyledItemDelegate::initStyleOption(option, index); | ||
| QStyleOptionViewItemV4 *optionV4 = qstyleoption_cast<QStyleOptionViewItemV4*>(option); | ||
|
|
||
| // If the item has no parent then it is a top-level sidebar item and its | ||
| // internalPointer is of type SidebarModel*, not TreeItem*. | ||
| if (!index.parent().isValid()) { | ||
| return; | ||
| } | ||
|
|
||
| TreeItem* item = static_cast<TreeItem*>(index.internalPointer()); | ||
| if (item == NULL) { | ||
| return; | ||
| } | ||
|
|
||
| LibraryFeature* pFeature = item->getFeature(); | ||
| if (pFeature == NULL) { | ||
| return; | ||
| } | ||
|
|
||
| TrackPointer pTrack = pFeature->getSelectedTrack(); | ||
| if (pTrack.isNull()) { | ||
| return; | ||
| } | ||
|
|
||
| if (pFeature->isTrackInChildModel(pTrack->getId(), item->dataPath())){ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This leads finally to a conains() call for every crate which end up in while loop that compare key and item.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Of cause the "is it worth" question should be solved first.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a little tricky due to the structure of the delegate -- but yes that would be better. This could be done without a delegate by changing TreeItemModel::data() to return a bolded font for the Qt::FontRole if the crate is selected. That way you could get the list of crates/playlists that should be bold in BasePlaylistFeature/CrateFeature and then tell TreeItemModel to make those entires bold.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I had no luck with those roles, nothing changed if I used them. So I chose the delegate.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is also a case where SidebarModel -> TreeItemModel is tripping things up. I'll send you a PR |
||
| optionV4->font.setBold(true); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| #include <QStyledItemDelegate> | ||
|
|
||
| class CrateHighlightDelegate : public QStyledItemDelegate { | ||
|
|
||
| public: | ||
| CrateHighlightDelegate(QObject* parent = 0); | ||
|
|
||
| void initStyleOption(QStyleOptionViewItem* option, const QModelIndex& index) const; | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,32 @@ CrateDAO::~CrateDAO() { | |
|
|
||
| void CrateDAO::initialize() { | ||
| qDebug() << "CrateDAO::initialize()"; | ||
|
|
||
| //get the count to allocate HashMap | ||
| int tracksInCratesCount = 0; | ||
| QSqlQuery query(m_database); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does query.size() return a valid value with sqlite? Than we can get around the second query. If not, you need not Query if tracksInCratesCount == 0
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. according to http://stackoverflow.com/questions/5373184/qtsql-sqlite-and-support-for-size-function it doesn't. |
||
| query.prepare("SELECT COUNT(*) from " CRATE_TRACKS_TABLE); | ||
|
|
||
| if (!query.exec()) { | ||
| LOG_FAILED_QUERY(query); | ||
| } | ||
|
|
||
| tracksInCratesCount = query.value(0).toInt(); | ||
|
|
||
| m_cratesTrackIsIn.reserve(tracksInCratesCount); | ||
|
|
||
| //now fetch all Tracks from all crates and insert them into the hashmap | ||
| query.prepare("SELECT track_id, crate_id from " CRATE_TRACKS_TABLE); | ||
| if (!query.exec()) { | ||
| LOG_FAILED_QUERY(query); | ||
| } | ||
|
|
||
| const int trackIdColumn = query.record().indexOf("track_id"); | ||
| const int crateIdColumn = query.record().indexOf("crate_id"); | ||
| while (query.next()) { | ||
| m_cratesTrackIsIn.insert(query.value(crateIdColumn).toInt(), | ||
| query.value(trackIdColumn).toInt()); | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This basically copies the whole crates table to memory. Do we have test data, how this compares to the original solution? Is there an alternative way to speed up the sql lookups e.g. a temp table?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's right -- but it's not that much memory (roughly 16-bytes per tuple so we're talking about like 16MB if every track was in a playlist in a 1-million track library). The main issue is keeping them in sync and since the DAO is already the gate-keeper it will do that fine. I think having an in-memory index for fast lookups will help for bugs like these too: For a GMail-style label delegate in the main library view we will need a fast lookup in memory because I can only think of 2 other ways:
Going with option 1 would mean terrible things for UI performance. Going with option 2 would mean adding a track to a crate would invalidate / recompute the library SQLite view which I don't think would be speedy.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It's currently hard to capture UI jankiness in a test. But it blocks the UI thread -- that's for sure. Until we can merge Nazar's work and keep the UI thread unblocked when doing DB operations then I think we should go this route.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, which way to go?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is finally a decision of taste. If you have a working solution that has a reasonable CPU load it is a good one. This and to quoted bugs can be solved with an in memory table and with an sql qerry. Outlook for the future: Without the non blocking SQL access, an internal table access will block the GUI shorter, than an sql query, but we need more CPU to keep the table up to date and there is an amount of additional code maintenance and complexity. For now it looks like the internal table wins. I think I will test it on my atom net-book, once we consider this as merge-able. By the way: Nazars branch needs a new maintainer. The latest version is already working, but it falls behind the master branch. The next steps to do is to merge it with master by crawling up the master branch one by one database related commit. You will find it here: #73
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
At the moment this branch contains a working solution. I've worked with it a while without performance problems. I'm on an i5 with 16Gig RAM so your atom would be the better test-case.
So what about a test on your atom platform and when scolling by holding down arrowkeys or sth. like this isn't slowed down merge this as is and else test the other solution to see whats better? I've just looked in nazars branch... will take a while to get into this... |
||
| } | ||
|
|
||
| unsigned int CrateDAO::crateCount() { | ||
|
|
@@ -236,6 +262,9 @@ bool CrateDAO::deleteCrate(const int crateId) { | |
| transaction.commit(); | ||
|
|
||
| emit(deleted(crateId)); | ||
|
|
||
| //Update in-memory map | ||
| m_cratesTrackIsIn.remove(crateId); | ||
| return true; | ||
| } | ||
|
|
||
|
|
@@ -334,6 +363,7 @@ bool CrateDAO::addTrackToCrate(const int trackId, const int crateId) { | |
|
|
||
| emit(trackAdded(crateId, trackId)); | ||
| emit(changed(crateId)); | ||
| m_cratesTrackIsIn.insert(crateId, trackId); | ||
| return true; | ||
| } | ||
|
|
||
|
|
@@ -359,6 +389,7 @@ int CrateDAO::addTracksToCrate(const int crateId, QList<int>* trackIdList) { | |
| // Emitting the trackAdded signals for each trackID outside the transaction | ||
| foreach(int trackId, *trackIdList) { | ||
| emit(trackAdded(crateId, trackId)); | ||
| m_cratesTrackIsIn.insert(crateId, trackId); | ||
| } | ||
|
|
||
| emit(changed(crateId)); | ||
|
|
@@ -381,6 +412,7 @@ bool CrateDAO::removeTrackFromCrate(const int trackId, const int crateId) { | |
|
|
||
| emit(trackRemoved(crateId, trackId)); | ||
| emit(changed(crateId)); | ||
| m_cratesTrackIsIn.remove(crateId, trackId); | ||
| return true; | ||
| } | ||
|
|
||
|
|
@@ -401,6 +433,7 @@ bool CrateDAO::removeTracksFromCrate(const QList<int>& ids, const int crateId) { | |
| } | ||
| foreach (int trackId, ids) { | ||
| emit(trackRemoved(crateId, trackId)); | ||
| m_cratesTrackIsIn.remove(crateId, trackId); | ||
| } | ||
| emit(changed(crateId)); | ||
| return true; | ||
|
|
@@ -421,4 +454,9 @@ void CrateDAO::removeTracksFromCrates(const QList<int>& ids) { | |
| // TODO(XXX) should we emit this for all crates? | ||
| // emit(trackRemoved(crateId, trackId)); | ||
| // emit(changed(crateId)); | ||
| // remove those tracks from memory-map | ||
| } | ||
|
|
||
| bool CrateDAO::isTrackInCrate(const int trackId, const int crateId) { | ||
| return m_cratesTrackIsIn.contains(crateId, trackId); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is redundant with library.cpp:229 -- all LibraryFeatures should already get this signal. Did you find that it wasn't being delivered?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops, I got that backwards.