Skip to content

Commit e76622b

Browse files
author
Milkii Brewster
committed
restore last selected library feature/playlist/crate on restart
implements #10125 persists the currently selected sidebar item (feature or child) to user settings and restores it on next mixxx startup. uses feature iconname + child data for robust matching across sessions. gracefully falls back to default selection if saved item not found. config keys: - [Library] LastSelectedFeature: stores feature icon name (programmatic identifier) - [Library] LastSelectedChild: stores child item data (playlist/crate id) changes based on pr feedback: - use iconName() instead of title() for feature identification (non-translated, version-stable) - use QAbstractItemModel::match() with recursive flag to simplify child lookup - add bounds checking to prevent out-of-bounds access - reuse clicked() method for activation to eliminate code duplication
1 parent a00ef82 commit e76622b

3 files changed

Lines changed: 115 additions & 0 deletions

File tree

src/library/library.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ Library::Library(
7979
m_pAnalysisFeature(nullptr) {
8080
qRegisterMetaType<LibraryRemovalType>("LibraryRemovalType");
8181

82+
// provide config to sidebar model for selection persistence
83+
m_pSidebarModel->setConfig(m_pConfig);
84+
8285
m_pKeyNotation.reset(
8386
new ControlObject(mixxx::library::prefs::kKeyNotationConfigKey));
8487

src/library/sidebarmodel.cpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <QTimer>
44
#include <QUrl>
5+
#include <functional>
56

67
#include "library/libraryfeature.h"
78
#include "library/treeitem.h"
@@ -94,6 +95,16 @@ void SidebarModel::setDefaultSelection(unsigned int index) {
9495
}
9596

9697
void SidebarModel::activateDefaultSelection() {
98+
// try to restore previously selected item
99+
QModelIndex savedIndex = restoreSavedSelection();
100+
if (savedIndex.isValid()) {
101+
emit selectIndex(savedIndex, true /* scrollTo */);
102+
// reuse clicked() method to activate the restored selection
103+
clicked(savedIndex);
104+
return;
105+
}
106+
107+
// fallback to default selection if restoration failed
97108
if (m_iDefaultSelectedIndex <
98109
static_cast<unsigned int>(m_sFeatures.size())) {
99110
emit selectIndex(getDefaultSelection(), true /* scrollTo */);
@@ -354,6 +365,9 @@ void SidebarModel::clicked(const QModelIndex& index) {
354365
// this event.
355366
stopPressedUntilClickedTimer();
356367
if (index.isValid()) {
368+
// save the selection for restoration on restart
369+
saveCurrentSelection(index);
370+
357371
if (index.internalPointer() == this) {
358372
m_sFeatures[index.row()]->activate();
359373
} else {
@@ -610,3 +624,90 @@ void SidebarModel::slotFeatureSelect(LibraryFeature* pFeature,
610624
}
611625
emit selectIndex(ind, scrollTo);
612626
}
627+
628+
void SidebarModel::saveCurrentSelection(const QModelIndex& index) {
629+
if (!m_pConfig || !index.isValid()) {
630+
return;
631+
}
632+
633+
QString featureIconName;
634+
QString childData;
635+
636+
if (index.internalPointer() == this) {
637+
// root feature selected
638+
if (index.row() >= 0 && index.row() < m_sFeatures.size()) {
639+
featureIconName = m_sFeatures[index.row()]->iconName();
640+
}
641+
} else {
642+
// child item selected
643+
TreeItem* pTreeItem = static_cast<TreeItem*>(index.internalPointer());
644+
if (pTreeItem) {
645+
LibraryFeature* pFeature = pTreeItem->feature();
646+
if (pFeature) {
647+
featureIconName = pFeature->iconName();
648+
childData = pTreeItem->getData().toString();
649+
}
650+
}
651+
}
652+
653+
if (!featureIconName.isEmpty()) {
654+
m_pConfig->setValue(
655+
ConfigKey("[Library]", "LastSelectedFeature"),
656+
featureIconName);
657+
m_pConfig->setValue(
658+
ConfigKey("[Library]", "LastSelectedChild"),
659+
childData);
660+
}
661+
}
662+
663+
QModelIndex SidebarModel::restoreSavedSelection() {
664+
if (!m_pConfig || m_sFeatures.isEmpty()) {
665+
return QModelIndex();
666+
}
667+
668+
QString savedFeatureIconName = m_pConfig->getValueString(
669+
ConfigKey("[Library]", "LastSelectedFeature"));
670+
QString savedChildData = m_pConfig->getValueString(
671+
ConfigKey("[Library]", "LastSelectedChild"));
672+
673+
if (savedFeatureIconName.isEmpty()) {
674+
return QModelIndex();
675+
}
676+
677+
// find the feature by icon name (non-translated, programmatic identifier)
678+
for (int i = 0; i < m_sFeatures.size(); ++i) {
679+
if (m_sFeatures[i]->iconName() == savedFeatureIconName) {
680+
// if no child data, return the feature root
681+
if (savedChildData.isEmpty()) {
682+
return index(i, 0);
683+
}
684+
685+
// search for matching child by data using QAbstractItemModel::match()
686+
QAbstractItemModel* pChildModel = m_sFeatures[i]->sidebarModel();
687+
if (pChildModel && pChildModel->rowCount() > 0) {
688+
QModelIndexList matches = pChildModel->match(
689+
pChildModel->index(0, 0),
690+
SidebarModel::DataRole,
691+
savedChildData,
692+
1, // stop at first match
693+
Qt::MatchExactly | Qt::MatchRecursive);
694+
695+
if (!matches.isEmpty() && matches.first().isValid()) {
696+
// translate child model index to sidebar model index
697+
QModelIndex childIndex = matches.first();
698+
TreeItem* pTreeItem = static_cast<TreeItem*>(
699+
childIndex.internalPointer());
700+
if (pTreeItem) {
701+
return createIndex(childIndex.row(), childIndex.column(), pTreeItem);
702+
}
703+
}
704+
}
705+
706+
// child not found, return feature root
707+
return index(i, 0);
708+
}
709+
}
710+
711+
// feature not found
712+
return QModelIndex();
713+
}

src/library/sidebarmodel.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
#include <QAbstractItemModel>
44
#include <QList>
55
#include <QModelIndex>
6+
#include <QString>
67
#include <QVariant>
78

9+
#include "preferences/usersettings.h"
10+
811
class LibraryFeature;
912
class QTimer;
1013

@@ -25,6 +28,10 @@ class SidebarModel : public QAbstractItemModel {
2528
QObject* parent = nullptr);
2629
~SidebarModel() override = default;
2730

31+
void setConfig(UserSettingsPointer pConfig) {
32+
m_pConfig = pConfig;
33+
}
34+
2835
void addLibraryFeature(LibraryFeature* feature);
2936
QModelIndex getDefaultSelection();
3037
void setDefaultSelection(unsigned int index);
@@ -93,10 +100,14 @@ class SidebarModel : public QAbstractItemModel {
93100
QModelIndex translateSourceIndex(const QModelIndex& parent);
94101
QModelIndex translateIndex(const QModelIndex& index, const QAbstractItemModel* model);
95102
void featureRenamed(LibraryFeature*);
103+
void saveCurrentSelection(const QModelIndex& index);
104+
QModelIndex restoreSavedSelection();
105+
96106
unsigned int m_iDefaultSelectedIndex; /** Index of the item in the sidebar model to select at startup. */
97107

98108
QTimer* const m_pressedUntilClickedTimer;
99109
QModelIndex m_pressedIndex;
110+
UserSettingsPointer m_pConfig;
100111

101112
void startPressedUntilClickedTimer(const QModelIndex& pressedIndex);
102113
void stopPressedUntilClickedTimer();

0 commit comments

Comments
 (0)