Skip to content

(feat) add Library sidebar bookmarks#14508

Open
ronso0 wants to merge 13 commits into
mixxxdj:mainfrom
ronso0:lib-sidebar-bookmarks
Open

(feat) add Library sidebar bookmarks#14508
ronso0 wants to merge 13 commits into
mixxxdj:mainfrom
ronso0:lib-sidebar-bookmarks

Conversation

@ronso0
Copy link
Copy Markdown
Member

@ronso0 ronso0 commented Mar 21, 2025

Just recently I needed this again. I was doing a b2b session with a guest who had his music in various directories on a thumb drive. Switching between my and his tracks views was annoying.
Now it's just Alt+Up/Down 😁

The bookmark indicator alone is helpful if you want to only visually mark sidebar items, eg. some favorite History playlist or some directory in a huge list, without the next/prev functions.

Related feature request is #9912
Note: for easy testing I have included all fixes from #14556.

How to use

  • press Alt+B to bookmark the selected sidebar item (or remove bookmark)
  • press Alt+Up/Down to go to and highlight the previous/next bookmark.
    bookmarks are sorted by position in the tree, so Down really jumps to the next bookmark below.
    (note: missing bookmark items are skipped, but not removed from the list)
    -> this does not activate (load) the bookmark view
    -> useful for scrolling to a bookmark in order to drag tracks from the current view / from decks onto it
    -> press Enter to activate it

Quick demo, with and without activating the bookmark
(edit: auto-activation has now been disabled, see above)
sidebar-bookmarks_75_3

Implementation New struct `SidebarBookmark` holds all info to identify item: * data/label to find it in the tree * feature row, child level and parent row to sort bookmarks by position in the tree * feature row is also used to check only indices of the changed feature when the sidebar is updated

All bookmarked indices are stored QModelIndexList. This functions as quick lookup list for SidebarModel to paint the bookmarks.

Bookmarks and this index list are updated when the sidebar changed, eg. when playlists were added, removed etc. (when child tree models are rebuilt). By boomark data, we try to find the item in the updated tree, then store the new index and update the index list.
-- btw that was the real challenge here. If the sidebar is unchanged (ie. only labels (track count) are changed) it works by simply maintaining a QModelIndexList, but with potentially changing indices we need to store items' metadata to identify them later on and get their new indices.

New SidebarItemDelegate does the painting, and also detects left-click on Refresh icons.

Some new TreeItem members to help with BrowseFeature updates etc.

New extra feature / fix / slightly disruptive UI change

Recalling bookmarks in currently collapsed Computer trees causes a crash because the directory trees are rebuilt on expandation 1.
Now, the child trees are only build on initial expandation. On next re-expandation we check if child directories changed.
If yes, a refresh icon is added to indicate changes.
Trees can be rebuild on demand, either by clicking the Refresh icon or with the existing "Refresh directory tree" context menu action.
Note that this is noticeable only if the if child directories changed, so it's actually not that disruptive IMO
image

TODO

  • test with external features (iTunes, Banshee, Traktor ..)
  • polish
  • remove unneeded debug logs, qWarning -> qDebug

Known Issues

Nice to have

  • make bookmarks persist. cfg? db?
    I'd go with the config. I'm lazy and a [Bookmarks] group would do, keys are the [feature] names and values are comma-separated ids/paths 🤷
  • better styling than just a colored bar
  • COs for bookmark, next, prev
  • GUI controls to set and recall bookmarks?
    like hotcue buttons, click to set/recall, right-click to clear
    requires a Bookmark row or something..
  • menu actions to bookmark items?

Footnotes

  1. When switching to a bookmark in a collapsed tree, WLibrarySidebar calls QTreeView::scrollTo(index). This expands all the index' parents from current to top level. While doing this, QTreeView's expanded signal triggers BrowseFeature::onLazyChildExpandation which concurrently rebuilds the child tree, which emits signals to update the tree view and its model.
    Apparently we run into an QModelIndex or its TreeItem pointer in SidebarModel::parent that becomes invalid while we process it.
    Here's the backtrace

@ronso0 ronso0 force-pushed the lib-sidebar-bookmarks branch from d00f19b to 85479f9 Compare March 27, 2025 00:43
@github-actions github-actions Bot added the build label Mar 27, 2025
@ronso0 ronso0 force-pushed the lib-sidebar-bookmarks branch from 85479f9 to 3c73c1f Compare March 27, 2025 13:42
@ronso0 ronso0 changed the title [WIP] Library sidebar bookmarks (feat) add Library sidebar bookmarks Mar 27, 2025
Comment on lines +831 to +836
results = pChildModel->match(
pChildModel->getRootIndex(),
TreeItemModel::kDataRole,
bookmark.data,
1,
Qt::MatchWrap | Qt::MatchExactly | Qt::MatchRecursive);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I discovered by chance QAbstractItemModel::match() after I wrote my own recursive match() function that checked label and/or data 😬 🤦‍♂️ 😆

@ronso0 ronso0 force-pushed the lib-sidebar-bookmarks branch from 3c73c1f to 874604f Compare March 27, 2025 14:15
@github-actions github-actions Bot added the build label Mar 27, 2025
@ronso0 ronso0 force-pushed the lib-sidebar-bookmarks branch 3 times, most recently from eb7fc7c to cac2cdc Compare April 2, 2025 12:36
@github-actions github-actions Bot added the browse label Apr 2, 2025
@ronso0 ronso0 force-pushed the lib-sidebar-bookmarks branch from cac2cdc to 16537f6 Compare April 3, 2025 12:33
@ronso0
Copy link
Copy Markdown
Member Author

ronso0 commented Apr 3, 2025

I think it's now safe to say this is ready for real-life testing.
I'll still occasionally check the commits and polish it and let you know when I consider it ready for review.

@ronso0
Copy link
Copy Markdown
Member Author

ronso0 commented Aug 16, 2025

Yeah, ready for review!
I've used this a lot and didn't notice issues so far.

@ronso0 ronso0 mentioned this pull request Aug 20, 2025
@ronso0 ronso0 force-pushed the lib-sidebar-bookmarks branch from da0ed8f to 1a778fd Compare November 4, 2025 23:47
@ronso0
Copy link
Copy Markdown
Member Author

ronso0 commented Nov 6, 2025

Bookmarks are now persistent (I really wanted to avoid the redundant steps when starting a session).
I opted fo the config way, simply because I was too lazy to dive into the database stuff, do schema upgrade etc.
Admittedly it's not the most beautiful solution but so far it seesm to work.
Note: only bookmarks are restored where the referenced item is available directly after start. Meaning bookmarks for lazily created tree items in Computer can currently not be restored.

@ronso0 ronso0 force-pushed the lib-sidebar-bookmarks branch 2 times, most recently from d4d29c0 to 546e26d Compare November 6, 2025 14:53
@daschuer
Copy link
Copy Markdown
Member

daschuer commented Nov 7, 2025

I have not tested yet, I just stumbled about the refresh icon in two ways. Maybe because I have not fully understand the workflow.

  1. Why need the user be bothered with it at all?
  2. Do you detect changes but not display them due to lazy loading? The established icon would be a dot overlay.
  3. Or is it reload icon? Than a icon like in Firefox will also work.

@ronso0
Copy link
Copy Markdown
Member Author

ronso0 commented Nov 7, 2025

It's been a while since I did this, so I'm not entirely sure.

I tried to explain the main issue with recalling bookmarks in Computer here
TL;DR lazy tree rebuilding causes issues when programmtically going down / to a specific index in a collapsed tree

  1. Do you detect changes but not display them due to lazy loading?

I compare the child count only (actual on disk vs. currently in tree), if mismatch show the icon/button.
It's the count only so there may be undetected changes, like rename or del+new.

That's one of the situations where I tried to improve Computer, or at least hack around its flaws. My design and UI decisions may not be the best, happy to receive proposals.

And after all, this is about the Computer library view, so if there are file / dir changes you'd need to rescan anyway. And, in my experience at least, significant file / directory modifications are very rare while playing.

@ronso0
Copy link
Copy Markdown
Member Author

ronso0 commented Nov 7, 2025

Btw #15571 or similar is required to make this feature work satisfactorily.

@ronso0
Copy link
Copy Markdown
Member Author

ronso0 commented May 7, 2026

Nice, I managed to also restore Computer bookmarks.
Depending on the tree level they are usually still not available after start, but are marked once the respective tree item is expanded.

Will update this branch soon.

@ronso0 ronso0 force-pushed the lib-sidebar-bookmarks branch from 546e26d to aada682 Compare May 8, 2026 18:33
ronso0 added 9 commits May 8, 2026 20:55
On playlist addition/deletion playlist features now also receive the playlist type and can act
on their own playlist types only.
Previously, deleting a playlist triggered a child (tree) model rebuild in both PlaylistFeature and Setlogfeature.
Both would invoke rowsDeleted() and rowsInserted() in SidebarModel almost simultaneously. Ruling this out is
required to avoid concurrent access to the SidebarBookmark list in SidebarModel. Regular (thread) lock/block/wait
mechanisms can not be used because caller and receiver are in the same thread.
This allows to check if an item has unique data. Default is true.
SetlogFeature for example uses the same playlist id for its YEAR items, and for now that's
the only feature that overrides the default implementation.
Alt+B toggles bookmark flag
Alt+Up/Down jumps to prev/next (highlighted, not activated)
Enter to activate
color can be set in qss with
WLibrarySidebar {
  qproperty-bookmarkColor: #451231;
}
This can cause a crash when jumping to a SidebarBookmark in a currently collpased tree
(or, with many adjustments in sidebar & tree models, at least not give the desired result).

Only build the tree when there are currently no items, e.g. on initial expandation,
or rebuild when `forceRebuild` argument is true.
Else, if there is a mismatch between current and new items, show a refresh icon on the parent.

It's always possible to enforce a tree rebuild with the menu action "Refresh directory tree".
@ronso0 ronso0 force-pushed the lib-sidebar-bookmarks branch 2 times, most recently from a4ab825 to b3e75a6 Compare May 8, 2026 18:57
@ronso0 ronso0 force-pushed the lib-sidebar-bookmarks branch from b3e75a6 to fed92c9 Compare May 8, 2026 19:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants