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

Grouped crates replacing crates #14130

Closed
wants to merge 18 commits into from
Closed
1 change: 0 additions & 1 deletion src/library/library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ Library::Library(
&Library::exportCrate, // signal-to-signal
Qt::DirectConnection);
#endif

m_pBrowseFeature = new BrowseFeature(
this, m_pConfig, pRecordingManager);
connect(m_pBrowseFeature,
Expand Down
572 changes: 548 additions & 24 deletions src/library/trackset/crate/cratefeature.cpp

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions src/library/trackset/crate/cratefeature.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,14 @@ class CrateFeature : public BaseTrackSetFeature {
void bindSidebarWidget(WLibrarySidebar* pSidebarWidget) override;

TreeItemModel* sidebarModel() const override;
QString fullPathFromIndex(const QModelIndex& index) const;
void reviewGroupCrateIds(const QString& fullPath, const QList<CrateId>& crateIds);

public slots:
void activate() override;
void activateChild(const QModelIndex& index) override;
void oldactivateChild(const QModelIndex& index);
// void oldactivateChild(const QModelIndex& index) override;
void onRightClick(const QPoint& globalPos) override;
void onRightClickChild(const QPoint& globalPos, const QModelIndex& index) override;
void slotCreateCrate();
Expand Down Expand Up @@ -77,6 +81,7 @@ class CrateFeature : public BaseTrackSetFeature {
void slotUpdateCrateLabels(const QSet<CrateId>& updatedCrateIds);

private:
QMap<QString, QList<CrateId>> groupCrateIds;
void initActions();
void connectLibrary(Library* pLibrary);
void connectTrackCollection();
Expand All @@ -90,7 +95,9 @@ class CrateFeature : public BaseTrackSetFeature {
const CrateSummary& crateSummary) const;

QModelIndex rebuildChildModel(CrateId selectedCrateId = CrateId());
QModelIndex oldrebuildChildModel(CrateId selectedCrateId = CrateId());
void updateChildModel(const QSet<CrateId>& updatedCrateIds);
void oldupdateChildModel(const QSet<CrateId>& updatedCrateIds);

CrateId crateIdFromIndex(const QModelIndex& index) const;
QModelIndex indexFromCrateId(CrateId crateId) const;
Expand Down Expand Up @@ -132,4 +139,6 @@ class CrateFeature : public BaseTrackSetFeature {
parented_ptr<QAction> m_pAnalyzeCrateAction;

QPointer<WLibrarySidebar> m_pSidebarWidget;
QString groupNameFromIndex(const QModelIndex& index) const;
void updateFullPathRecursive(TreeItem* pItem, const QString& parentPath);
};
190 changes: 187 additions & 3 deletions src/library/trackset/crate/cratetablemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,153 @@

namespace {

const bool sDebug = false;
const QString kModelName = QStringLiteral("crate");

} // anonymous namespace

CrateTableModel::CrateTableModel(
QObject* pParent,
TrackCollectionManager* pTrackCollectionManager)
TrackCollectionManager* pTrackCollectionManager,
UserSettingsPointer pConfig)
: TrackSetTableModel(
pParent,
pTrackCollectionManager,
"mixxx.db.model.crate") {
"mixxx.db.model.crate"),
m_pConfig(pConfig) {
}

QList<QVariantMap> CrateTableModel::getGroupedCrates() {
if (sDebug) {
qDebug() << "[GROUPEDCRATESTABLEMODEL] Generating grouped crates list.";
}

QList<QVariantMap> groupedCrates;

QSqlQuery query(m_database);
// QString queryString;

if (sDebug) {
qDebug() << "[GROUPEDCRATESTABLEMODEL] configvalue GroupedCratesLength = "
<< m_pConfig->getValue<int>(ConfigKey("[Library]", "GroupedCratesLength"));
qDebug() << "[GROUPEDCRATESTABLEMODEL] configvalue GroupedCratesFixedLength = "
<< m_pConfig->getValue<int>(ConfigKey("[Library]", "GroupedCratesFixedLength"), 0);
qDebug() << "[GROUPEDCRATESTABLEMODEL] configvalue GroupedCratesVarLengthMask = "
<< m_pConfig->getValue(ConfigKey("[Library]", "GroupedCratesVarLengthMask"));
}

// fixed prefix length
if (m_pConfig->getValue<int>(ConfigKey("[Library]", "GroupedCratesLength")) == 0) {
QString queryString =
QStringLiteral(
"SELECT DISTINCT "
" SUBSTR(name, 1, %1) AS group_name, "
" id AS crate_id, "
" name AS crate_name "
"FROM crates "
"WHERE show = 1 "
"ORDER BY LOWER(name)")
.arg(m_pConfig->getValue(
ConfigKey("[Library]",
"GroupedCratesFixedLength"),
0));
if (sDebug) {
qDebug() << "[GROUPEDCRATESTABLEMODEL] queryString: " << queryString;
}
if (!query.exec(queryString)) {
qWarning() << "[GROUPEDCRATESTABLEMODEL] Failed to execute grouped "
"crates query:"
<< query.lastError();
return groupedCrates;
}

while (query.next()) {
QVariantMap crateData;
// QString groupName = query.value("group_name").toString().trimmed();
QString groupName = query.value("group_name").toString();
crateData["group_name"] = groupName;
crateData["crate_id"] = query.value("crate_id");
crateData["crate_name"] = query.value("crate_name");
groupedCrates.append(crateData);
if (sDebug) {
qDebug() << "[GROUPEDCRATESTABLEMODEL] Grouped crates -> crate "
"added: "
<< crateData;
}
}
} else {
// Variable prefix length with mask, multiple occurrences -> multilevel subgroups
QString queryString = QStringLiteral(
"SELECT DISTINCT "
" id AS crate_id, "
" name AS crate_name "
"FROM crates "
"WHERE show = 1 "
"ORDER BY LOWER(name)");
if (sDebug) {
qDebug() << "[GROUPEDCRATESTABLEMODEL] queryString: " << queryString;
}
if (!query.exec(queryString)) {
qWarning() << "[GROUPEDCRATESTABLEMODEL] Failed to execute grouped "
"crates query:"
<< query.lastError();
return groupedCrates;
}
const QString& searchDelimit = m_pConfig->getValue(
ConfigKey("[Library]", "GroupedCratesVarLengthMask"));

while (query.next()) {
QString crateName = query.value("crate_name").toString();
if (crateName.contains(searchDelimit)) {
// QStringList groupHierarchy = crateName.split(searchDelimit, Qt::SkipEmptyParts);
QStringList groupHierarchy = crateName.split(searchDelimit);
QString currentGroup;

for (int i = 0; i < groupHierarchy.size(); ++i) {
// currentGroup += (i > 0 ? searchDelimit : "") + groupHierarchy[i].trimmed();
currentGroup += (i > 0 ? searchDelimit : "") + groupHierarchy[i];

QVariantMap crateData;
crateData["group_name"] = currentGroup;
crateData["crate_id"] = query.value("crate_id");
crateData["crate_name"] = crateName;

// Add only the full crate record for the last level
if (i == groupHierarchy.size() - 1) {
groupedCrates.append(crateData);
}

if (sDebug) {
qDebug() << "[GROUPEDCRATESTABLEMODEL] Grouped crates -> crate added: "
<< crateData;
}
}
} else {
// No delimiter in crate name -> root-level
QVariantMap crateData;
// crateData["group_name"] = crateName.trimmed();
crateData["group_name"] = crateName;
crateData["crate_id"] = query.value("crate_id");
crateData["crate_name"] = crateName;
groupedCrates.append(crateData);

if (sDebug) {
qDebug() << "[GROUPEDCRATESTABLEMODEL] Grouped crates -> "
"crate added at root level: "
<< crateData;
}
}
}
}
if (sDebug) {
qDebug() << "[GROUPEDCRATESTABLEMODEL] Grouped crates list generated "
"with"
<< groupedCrates.size() << "entries.";
}
return groupedCrates;
}

void CrateTableModel::selectCrate(CrateId crateId) {
//qDebug() << "CrateTableModel::setCrate()" << crateId;
if (crateId == m_selectedCrate) {
qDebug() << "Already focused on crate " << crateId;
return;
Expand Down Expand Up @@ -81,6 +213,58 @@ void CrateTableModel::selectCrate(CrateId crateId) {
setDefaultSort(fieldIndex("artist"), Qt::AscendingOrder);
}

void CrateTableModel::selectCrateGroup(const QString& groupName) {
if (sDebug) {
qDebug() << "[CrateTableModel] -> selectCrateGroup() -> Searching for "
"tracks in groups starting with:"
<< groupName;
}
const QString& checkStamp = QDateTime::currentDateTime().toString("hhmmss");

const QString& tableName = QStringLiteral("crate_%1").arg(checkStamp);

QStringList columns;
columns << LIBRARYTABLE_ID
<< "'' AS " + LIBRARYTABLE_PREVIEW
<< LIBRARYTABLE_COVERART_DIGEST + " AS " + LIBRARYTABLE_COVERART;

QString queryString =
QString("CREATE TEMPORARY VIEW IF NOT EXISTS %1 AS "
"SELECT %2 FROM %3 "
"WHERE library.id IN(SELECT crate_tracks.track_id from "
"crate_tracks "
"WHERE crate_tracks.crate_id IN(SELECT crates.id from "
"crates WHERE crates.name LIKE '%4%')) "
"AND %5=0")
.arg(tableName,
columns.join(","),
LIBRARY_TABLE,
groupName,
LIBRARYTABLE_MIXXXDELETED);

if (sDebug) {
qDebug() << "[CrateTableModel] -> Generated SQL Query:" << queryString;
}

// Execute the query
FwdSqlQuery(m_database, queryString).execPrepared();
columns[0] = LIBRARYTABLE_ID;
columns[1] = LIBRARYTABLE_PREVIEW;
columns[2] = LIBRARYTABLE_COVERART;

// Update the table and view
setTable(tableName,
LIBRARYTABLE_ID,
columns,
m_pTrackCollectionManager->internalCollection()->getTrackSource());
setDefaultSort(fieldIndex("artist"), Qt::AscendingOrder);

if (sDebug) {
qDebug() << "[CrateTableModel] -> Group table successfully created "
"with provided Crate IDs.";
}
}

bool CrateTableModel::addTrack(const QModelIndex& index, const QString& location) {
Q_UNUSED(index);

Expand Down
10 changes: 9 additions & 1 deletion src/library/trackset/crate/cratetablemodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,25 @@
#include "library/trackset/crate/crateid.h"
#include "library/trackset/tracksettablemodel.h"

constexpr int kInvalidCrateId = -1;

class CrateTableModel final : public TrackSetTableModel {
Q_OBJECT

public:
CrateTableModel(QObject* parent, TrackCollectionManager* pTrackCollectionManager);
CrateTableModel(
QObject* parent,
TrackCollectionManager* pTrackCollectionManager,
UserSettingsPointer pConfig);
~CrateTableModel() final = default;

void selectCrate(CrateId crateId = CrateId());
CrateId selectedCrate() const {
return m_selectedCrate;
}

void selectCrateGroup(const QString& groupName);
QList<QVariantMap> getGroupedCrates();
bool addTrack(const QModelIndex& index, const QString& location);

void removeTracks(const QModelIndexList& indices) final;
Expand All @@ -30,4 +37,5 @@ class CrateTableModel final : public TrackSetTableModel {
private:
CrateId m_selectedCrate;
QHash<CrateId, QString> m_searchTexts;
UserSettingsPointer m_pConfig;
};
11 changes: 11 additions & 0 deletions src/library/treeitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,14 @@ void TreeItem::removeChildren(int row, int count) {
qDeleteAll(m_children.constBegin() + row, m_children.constBegin() + (row + count));
constErase(&m_children, m_children.constBegin() + row, m_children.constBegin() + (row + count));
}

int TreeItem::getRow() const {
if (m_pParent) {
return m_pParent->m_children.indexOf(const_cast<TreeItem*>(this));
}
return kInvalidRow; // If this is a root item or parent is missing
}

int TreeItem::childCount() const {
return m_children.size();
}
18 changes: 18 additions & 0 deletions src/library/treeitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ class TreeItem final {

~TreeItem();

/////////////////////////////////////////////////////////////////////////
// Full Path Accessors
/////////////////////////////////////////////////////////////////////////

// Set the full path
void setFullPath(const QString& fullPath) {
m_fullPath = fullPath;
}

// Get the full path
QString fullPath() const {
return m_fullPath;
}

/////////////////////////////////////////////////////////////////////////
// Feature
Expand Down Expand Up @@ -68,6 +81,10 @@ class TreeItem final {
// or kInvalidRow if this is a root item without a parent.
int parentRow() const;

// Eve
int getRow() const;
int childCount() const;
// EVE

/////////////////////////////////////////////////////////////////////////
// Children
Expand Down Expand Up @@ -147,4 +164,5 @@ class TreeItem final {
QVariant m_data;
QIcon m_icon;
bool m_bold;
QString m_fullPath;
};
Loading
Loading