1 #include "library/crate/cratetablemodel.h"
2
3 #include <QtDebug>
4
5 #include "library/dao/trackschema.h"
6 #include "library/trackcollection.h"
7 #include "library/trackcollectionmanager.h"
8 #include "mixer/playermanager.h"
9 #include "moc_cratetablemodel.cpp"
10 #include "track/track.h"
11 #include "util/db/fwdsqlquery.h"
12
CrateTableModel(QObject * pParent,TrackCollectionManager * pTrackCollectionManager)13 CrateTableModel::CrateTableModel(QObject* pParent,
14 TrackCollectionManager* pTrackCollectionManager)
15 : BaseSqlTableModel(pParent, pTrackCollectionManager,
16 "mixxx.db.model.crate") {
17 }
18
~CrateTableModel()19 CrateTableModel::~CrateTableModel() {
20 }
21
selectCrate(CrateId crateId)22 void CrateTableModel::selectCrate(CrateId crateId) {
23 //qDebug() << "CrateTableModel::setCrate()" << crateId;
24 if (crateId == m_selectedCrate) {
25 qDebug() << "Already focused on crate " << crateId;
26 return;
27 }
28 m_selectedCrate = crateId;
29
30 QString tableName = QString("crate_%1").arg(m_selectedCrate.toString());
31 QStringList columns;
32 columns << LIBRARYTABLE_ID
33 << "'' AS " + LIBRARYTABLE_PREVIEW
34 // For sorting the cover art column we give LIBRARYTABLE_COVERART
35 // the same value as the cover hash.
36 << LIBRARYTABLE_COVERART_HASH + " AS " + LIBRARYTABLE_COVERART;
37 // We hide files that have been explicitly deleted in the library
38 // (mixxx_deleted = 0) from the view.
39 // They are kept in the database, because we treat crate membership as a
40 // track property, which persist over a hide / unhide cycle.
41 QString queryString = QString("CREATE TEMPORARY VIEW IF NOT EXISTS %1 AS "
42 "SELECT %2 FROM %3 "
43 "WHERE %4 IN (%5) "
44 "AND %6=0")
45 .arg(tableName,
46 columns.join(","),
47 LIBRARY_TABLE,
48 LIBRARYTABLE_ID,
49 CrateStorage::formatSubselectQueryForCrateTrackIds(crateId),
50 LIBRARYTABLE_MIXXXDELETED);
51 FwdSqlQuery(m_database, queryString).execPrepared();
52
53 columns[0] = LIBRARYTABLE_ID;
54 columns[1] = LIBRARYTABLE_PREVIEW;
55 columns[2] = LIBRARYTABLE_COVERART;
56 setTable(tableName, LIBRARYTABLE_ID, columns,
57 m_pTrackCollectionManager->internalCollection()->getTrackSource());
58 setSearch("");
59 setDefaultSort(fieldIndex("artist"), Qt::AscendingOrder);
60 }
61
addTrack(const QModelIndex & index,const QString & location)62 bool CrateTableModel::addTrack(const QModelIndex& index, const QString& location) {
63 Q_UNUSED(index);
64
65 // This will only succeed if the file actually exist.
66 TrackFile fileInfo(location);
67 if (!fileInfo.checkFileExists()) {
68 qDebug() << "CrateTableModel::addTrack:"
69 << "File"
70 << location
71 << "not found";
72 return false;
73 }
74
75 // If a track is dropped but it isn't in the library, then add it because
76 // the user probably dropped a file from outside Mixxx into this crate.
77 // If the track is already contained in the library it will not insert
78 // a duplicate. It also handles unremoving logic if the track has been
79 // removed from the library recently and re-adds it.
80 const TrackPointer pTrack = m_pTrackCollectionManager->getOrAddTrack(
81 TrackRef::fromFileInfo(fileInfo));
82 if (!pTrack) {
83 qDebug() << "CrateTableModel::addTrack:"
84 << "Failed to add track"
85 << location
86 << "to library";
87 return false;
88 }
89
90 QList<TrackId> trackIds;
91 trackIds.append(pTrack->getId());
92 if (!m_pTrackCollectionManager->internalCollection()->addCrateTracks(m_selectedCrate, trackIds)) {
93 qDebug() << "CrateTableModel::addTrack:"
94 << "Failed to add track"
95 << location
96 << "to crate"
97 << m_selectedCrate;
98 return false;
99 }
100
101 // TODO(rryan) just add the track don't select
102 select();
103 return true;
104 }
105
getCapabilities() const106 TrackModel::CapabilitiesFlags CrateTableModel::getCapabilities() const {
107 CapabilitiesFlags caps = TRACKMODELCAPS_NONE
108 | TRACKMODELCAPS_RECEIVEDROPS
109 | TRACKMODELCAPS_ADDTOPLAYLIST
110 | TRACKMODELCAPS_ADDTOCRATE
111 | TRACKMODELCAPS_ADDTOAUTODJ
112 | TRACKMODELCAPS_EDITMETADATA
113 | TRACKMODELCAPS_LOADTODECK
114 | TRACKMODELCAPS_LOADTOSAMPLER
115 | TRACKMODELCAPS_LOADTOPREVIEWDECK
116 | TRACKMODELCAPS_REMOVE_CRATE
117 | TRACKMODELCAPS_RESETPLAYED;
118 if (m_selectedCrate.isValid()) {
119 Crate crate;
120 if (m_pTrackCollectionManager->internalCollection()->crates().readCrateById(m_selectedCrate, &crate)) {
121 if (crate.isLocked()) {
122 caps |= TRACKMODELCAPS_LOCKED;
123 }
124 } else {
125 qWarning() << "Failed to read create" << m_selectedCrate;
126 }
127 }
128 return caps;
129 }
130
isColumnInternal(int column)131 bool CrateTableModel::isColumnInternal(int column) {
132 return column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_ID) ||
133 column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_PLAYED) ||
134 column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_MIXXXDELETED) ||
135 column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_BPM_LOCK) ||
136 column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_KEY_ID)||
137 column == fieldIndex(ColumnCache::COLUMN_TRACKLOCATIONSTABLE_FSDELETED) ||
138 (PlayerManager::numPreviewDecks() == 0 &&
139 column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_PREVIEW)) ||
140 column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_COVERART_SOURCE) ||
141 column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_COVERART_TYPE) ||
142 column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_COVERART_LOCATION) ||
143 column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_COVERART_HASH);;
144 }
145
addTracks(const QModelIndex & index,const QList<QString> & locations)146 int CrateTableModel::addTracks(const QModelIndex& index,
147 const QList<QString>& locations) {
148 Q_UNUSED(index);
149 // If a track is dropped but it isn't in the library, then add it because
150 // the user probably dropped a file from outside Mixxx into this crate.
151 QList<TrackId> trackIds = m_pTrackCollectionManager->internalCollection()->resolveTrackIdsFromLocations(
152 locations);
153 if (!m_pTrackCollectionManager->internalCollection()->addCrateTracks(m_selectedCrate, trackIds)) {
154 qWarning() << "CrateTableModel::addTracks could not add"
155 << locations.size()
156 << "tracks to crate" << m_selectedCrate;
157 return 0;
158 }
159
160 select();
161 return trackIds.size();
162 }
163
removeTracks(const QModelIndexList & indices)164 void CrateTableModel::removeTracks(const QModelIndexList& indices) {
165 VERIFY_OR_DEBUG_ASSERT(m_selectedCrate.isValid()) {
166 return;
167 }
168 if (indices.empty()) {
169 return;
170 }
171
172 Crate crate;
173 if (!m_pTrackCollectionManager->internalCollection()->crates().readCrateById(m_selectedCrate, &crate)) {
174 qWarning() << "Failed to read create" << m_selectedCrate;
175 return;
176 }
177
178 VERIFY_OR_DEBUG_ASSERT(!crate.isLocked()) {
179 return;
180 }
181
182 QList<TrackId> trackIds;
183 trackIds.reserve(indices.size());
184 for (const QModelIndex& index: indices) {
185 trackIds.append(getTrackId(index));
186 }
187 if (!m_pTrackCollectionManager->internalCollection()->removeCrateTracks(crate.getId(), trackIds)) {
188 qWarning() << "Failed to remove tracks from crate" << crate;
189 return;
190 }
191
192 select();
193 }
194