Merge lp:~mixxxcontributors/mixxx/features_setlog into lp:~mixxxdevelopers/mixxx/trunk
- features_setlog
- Merge into trunk
Proposed by
RJ Skerry-Ryan
Status: | Merged |
---|---|
Merged at revision: | 2990 |
Proposed branch: | lp:~mixxxcontributors/mixxx/features_setlog |
Merge into: | lp:~mixxxdevelopers/mixxx/trunk |
Diff against target: |
3293 lines (+1546/-628) 37 files modified
mixxx/build/depends.py (+5/-1) mixxx/res/html/setlogs.html (+10/-0) mixxx/res/mixxx.qrc (+3/-0) mixxx/src/basetrackplayer.cpp (+1/-1) mixxx/src/dlgautodj.cpp (+1/-1) mixxx/src/library/baseplaylistfeature.cpp (+411/-0) mixxx/src/library/baseplaylistfeature.h (+81/-0) mixxx/src/library/basesqltablemodel.cpp (+1/-1) mixxx/src/library/browse/browsetablemodel.cpp (+2/-5) mixxx/src/library/cratefeature.cpp (+104/-80) mixxx/src/library/cratefeature.h (+4/-2) mixxx/src/library/dao/cratedao.cpp (+5/-4) mixxx/src/library/dao/cratedao.h (+3/-2) mixxx/src/library/dao/playlistdao.cpp (+128/-62) mixxx/src/library/dao/playlistdao.h (+30/-9) mixxx/src/library/legacylibraryimporter.cpp (+1/-2) mixxx/src/library/library.cpp (+2/-1) mixxx/src/library/libraryfeature.h (+2/-1) mixxx/src/library/parser.cpp (+1/-1) mixxx/src/library/parsercsv.cpp (+233/-0) mixxx/src/library/parsercsv.h (+41/-0) mixxx/src/library/playlistfeature.cpp (+24/-341) mixxx/src/library/playlistfeature.h (+9/-54) mixxx/src/library/playlisttablemodel.cpp (+13/-1) mixxx/src/library/playlisttablemodel.h (+1/-0) mixxx/src/library/preparefeature.cpp (+11/-0) mixxx/src/library/setlogfeature.cpp (+263/-0) mixxx/src/library/setlogfeature.h (+48/-0) mixxx/src/library/sidebarmodel.cpp (+42/-19) mixxx/src/library/sidebarmodel.h (+1/-1) mixxx/src/library/trackcollection.cpp (+1/-1) mixxx/src/mixxx.cpp (+3/-8) mixxx/src/playerinfo.cpp (+29/-23) mixxx/src/playerinfo.h (+10/-1) mixxx/src/trackinfoobject.cpp (+13/-4) mixxx/src/trackinfoobject.h (+4/-2) mixxx/src/widget/wlibrarysidebar.cpp (+5/-0) |
To merge this branch: | bzr merge lp:~mixxxcontributors/mixxx/features_setlog |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
RJ Skerry-Ryan | Approve | ||
Review via email: mp+96964@code.launchpad.net |
Commit message
Description of the change
This branch brings Daniel Schürmann's session history feature to Mixxx. I have reviewed the branch and it looks good to me from a stability and product/feature point of view.
I think we need to decide from an artistic point of view what the root 'Set Log' page should look like (e.g. wording and the inclusion of a picture a-la the crates view). Also, should we call it "Set Logs" or just "History" or maybe "Set History"?
To post a comment you must log in.
Revision history for this message
RJ Skerry-Ryan (rryan) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'mixxx/build/depends.py' |
2 | --- mixxx/build/depends.py 2011-12-25 05:45:11 +0000 |
3 | +++ mixxx/build/depends.py 2012-03-12 04:25:21 +0000 |
4 | @@ -236,7 +236,8 @@ |
5 | # SoundTouch CPU optimizations are only for x86 |
6 | # architectures. SoundTouch automatically ignores these files when it is |
7 | # not being built for an architecture that supports them. |
8 | - cpu_detection = '#lib/%s/cpu_detect_x86_win.cpp' if build.toolchain_is_msvs else '#lib/%s/cpu_detect_x86_gcc.cpp' |
9 | + cpu_detection = '#lib/%s/cpu_detect_x86_win.cpp' if build.toolchain_is_msvs else \ |
10 | + '#lib/%s/cpu_detect_x86_gcc.cpp' |
11 | sources.append(cpu_detection % self.SOUNDTOUCH_PATH) |
12 | return sources |
13 | |
14 | @@ -415,7 +416,9 @@ |
15 | "library/preparefeature.cpp", |
16 | "library/autodjfeature.cpp", |
17 | "library/mixxxlibraryfeature.cpp", |
18 | + "library/baseplaylistfeature.cpp", |
19 | "library/playlistfeature.cpp", |
20 | + "library/setlogfeature.cpp", |
21 | |
22 | "library/browse/browsetablemodel.cpp", |
23 | "library/browse/browsethread.cpp", |
24 | @@ -473,6 +476,7 @@ |
25 | "library/parser.cpp", |
26 | "library/parserpls.cpp", |
27 | "library/parserm3u.cpp", |
28 | + "library/parsercsv.cpp", |
29 | |
30 | "bpm/bpmscheme.cpp", |
31 | |
32 | |
33 | === added file 'mixxx/res/html/setlogs.html' |
34 | --- mixxx/res/html/setlogs.html 1970-01-01 00:00:00 +0000 |
35 | +++ mixxx/res/html/setlogs.html 2012-03-12 04:25:21 +0000 |
36 | @@ -0,0 +1,10 @@ |
37 | +<h2>Set Logs</h2> |
38 | +<table border="0" cellpadding="5"> |
39 | + <tr> |
40 | + <td> |
41 | + <p>Set Logs are automatic generated lists of your last DJ sets.</p> |
42 | + <p>Every time you start Mixxx, a new Set Log is generated. You can export it as m3u playlist or play it again with Auto DJ.</p> |
43 | + <p>When you restart mixxx you can join the current Set Log with the previous one. The track played flags are restored.</p> |
44 | + </td> |
45 | + </tr> |
46 | +</table> |
47 | |
48 | === added file 'mixxx/res/images/library/ic_library_setlog.png' |
49 | Binary files mixxx/res/images/library/ic_library_setlog.png 1970-01-01 00:00:00 +0000 and mixxx/res/images/library/ic_library_setlog.png 2012-03-12 04:25:21 +0000 differ |
50 | === added file 'mixxx/res/images/library/ic_library_setlog_current.png' |
51 | Binary files mixxx/res/images/library/ic_library_setlog_current.png 1970-01-01 00:00:00 +0000 and mixxx/res/images/library/ic_library_setlog_current.png 2012-03-12 04:25:21 +0000 differ |
52 | === modified file 'mixxx/res/mixxx.qrc' |
53 | --- mixxx/res/mixxx.qrc 2011-12-22 18:43:09 +0000 |
54 | +++ mixxx/res/mixxx.qrc 2012-03-12 04:25:21 +0000 |
55 | @@ -2,6 +2,7 @@ |
56 | <qresource prefix="/"> |
57 | <file>html/crates.html</file> |
58 | <file>html/playlists.html</file> |
59 | + <file>html/setlogs.html</file> |
60 | <file>images/mixxx-icon.png</file> |
61 | <file>images/ic_mixxx_window.png</file> |
62 | <file>images/templates/logo_mixxx.png</file> |
63 | @@ -32,6 +33,8 @@ |
64 | <file>images/library/ic_library_rhythmbox.png</file> |
65 | <file>images/library/ic_library_traktor.png</file> |
66 | <file>images/library/ic_library_recordings.png</file> |
67 | + <file>images/library/ic_library_setlog.png</file> |
68 | + <file>images/library/ic_library_setlog_current.png</file> |
69 | <file>translations/mixxx_ar.qm</file> |
70 | <file>translations/mixxx_bg.qm</file> |
71 | <file>translations/mixxx_br.qm</file> |
72 | |
73 | === modified file 'mixxx/src/basetrackplayer.cpp' |
74 | --- mixxx/src/basetrackplayer.cpp 2012-01-09 00:43:24 +0000 |
75 | +++ mixxx/src/basetrackplayer.cpp 2012-03-12 04:25:21 +0000 |
76 | @@ -199,7 +199,7 @@ |
77 | if(!m_pLoadedTrack->getHeaderParsed()) |
78 | SoundSourceProxy::ParseHeader(m_pLoadedTrack.data()); |
79 | |
80 | - m_pLoadedTrack->setPlayed(true); |
81 | + // m_pLoadedTrack->setPlayedAndUpdatePlaycount(true); // Actually the song is loaded but not played |
82 | |
83 | // Generate waveform summary |
84 | //TODO: Consider reworking this visual resample stuff... need to ask rryan about this -- Albert. |
85 | |
86 | === modified file 'mixxx/src/dlgautodj.cpp' |
87 | --- mixxx/src/dlgautodj.cpp 2011-11-30 06:19:47 +0000 |
88 | +++ mixxx/src/dlgautodj.cpp 2012-03-12 04:25:21 +0000 |
89 | @@ -38,7 +38,7 @@ |
90 | "mixxx.db.model.autodj"); |
91 | int playlistId = m_playlistDao.getPlaylistIdFromName(AUTODJ_TABLE); |
92 | if (playlistId < 0) { |
93 | - m_playlistDao.createPlaylist(AUTODJ_TABLE, true); |
94 | + m_playlistDao.createPlaylist(AUTODJ_TABLE, PlaylistDAO::PLHT_AUTO_DJ); |
95 | playlistId = m_playlistDao.getPlaylistIdFromName(AUTODJ_TABLE); |
96 | } |
97 | m_pAutoDJTableModel->setPlaylist(playlistId); |
98 | |
99 | === added file 'mixxx/src/library/baseplaylistfeature.cpp' |
100 | --- mixxx/src/library/baseplaylistfeature.cpp 1970-01-01 00:00:00 +0000 |
101 | +++ mixxx/src/library/baseplaylistfeature.cpp 2012-03-12 04:25:21 +0000 |
102 | @@ -0,0 +1,411 @@ |
103 | +#include "library/baseplaylistfeature.h" |
104 | + |
105 | +#include "library/parser.h" |
106 | +#include "library/parserm3u.h" |
107 | +#include "library/parserpls.h" |
108 | +#include "library/parsercsv.h" |
109 | +#include "library/playlisttablemodel.h" |
110 | +#include "library/trackcollection.h" |
111 | +#include "mixxxkeyboard.h" |
112 | +#include "widget/wlibrary.h" |
113 | +#include "widget/wlibrarysidebar.h" |
114 | +#include "widget/wlibrarytextbrowser.h" |
115 | + |
116 | +BasePlaylistFeature::BasePlaylistFeature( |
117 | + QObject* parent, ConfigObject<ConfigValue>* pConfig, |
118 | + TrackCollection* pTrackCollection, |
119 | + QString rootViewName, QString rootViewUrl) |
120 | + : LibraryFeature(parent), |
121 | + m_pConfig(pConfig), |
122 | + m_pTrackCollection(pTrackCollection), |
123 | + m_playlistDao(pTrackCollection->getPlaylistDAO()), |
124 | + m_trackDao(pTrackCollection->getTrackDAO()), |
125 | + m_pPlaylistTableModel(NULL), |
126 | + m_playlistTableModel(this, pTrackCollection->getDatabase()), |
127 | + m_rootViewName(rootViewName), |
128 | + m_rootViewUrl(rootViewUrl) { |
129 | + m_pCreatePlaylistAction = new QAction(tr("New Playlist"),this); |
130 | + connect(m_pCreatePlaylistAction, SIGNAL(triggered()), |
131 | + this, SLOT(slotCreatePlaylist())); |
132 | + |
133 | + m_pAddToAutoDJAction = new QAction(tr("Add to Auto DJ Queue (bottom)"), this); |
134 | + connect(m_pAddToAutoDJAction, SIGNAL(triggered()), |
135 | + this, SLOT(slotAddToAutoDJ())); |
136 | + |
137 | + m_pAddToAutoDJTopAction = new QAction(tr("Add to Auto DJ Queue (top)"), this); |
138 | + connect(m_pAddToAutoDJTopAction, SIGNAL(triggered()), |
139 | + this, SLOT(slotAddToAutoDJTop())); |
140 | + |
141 | + m_pDeletePlaylistAction = new QAction(tr("Remove"),this); |
142 | + connect(m_pDeletePlaylistAction, SIGNAL(triggered()), |
143 | + this, SLOT(slotDeletePlaylist())); |
144 | + |
145 | + m_pRenamePlaylistAction = new QAction(tr("Rename"),this); |
146 | + connect(m_pRenamePlaylistAction, SIGNAL(triggered()), |
147 | + this, SLOT(slotRenamePlaylist())); |
148 | + |
149 | + m_pLockPlaylistAction = new QAction(tr("Lock"),this); |
150 | + connect(m_pLockPlaylistAction, SIGNAL(triggered()), |
151 | + this, SLOT(slotTogglePlaylistLock())); |
152 | + |
153 | + m_pImportPlaylistAction = new QAction(tr("Import Playlist"),this); |
154 | + connect(m_pImportPlaylistAction, SIGNAL(triggered()), |
155 | + this, SLOT(slotImportPlaylist())); |
156 | + |
157 | + m_pExportPlaylistAction = new QAction(tr("Export Playlist"), this); |
158 | + connect(m_pExportPlaylistAction, SIGNAL(triggered()), |
159 | + this, SLOT(slotExportPlaylist())); |
160 | + |
161 | + connect(&m_playlistDao, SIGNAL(added(int)), |
162 | + this, SLOT(slotPlaylistTableChanged(int))); |
163 | + |
164 | + connect(&m_playlistDao, SIGNAL(deleted(int)), |
165 | + this, SLOT(slotPlaylistTableChanged(int))); |
166 | + |
167 | + connect(&m_playlistDao, SIGNAL(renamed(int)), |
168 | + this, SLOT(slotPlaylistTableChanged(int))); |
169 | + |
170 | + connect(&m_playlistDao, SIGNAL(lockChanged(int)), |
171 | + this, SLOT(slotPlaylistTableChanged(int))); |
172 | +} |
173 | + |
174 | +BasePlaylistFeature::~BasePlaylistFeature() { |
175 | + delete m_pPlaylistTableModel; |
176 | + delete m_pCreatePlaylistAction; |
177 | + delete m_pDeletePlaylistAction; |
178 | + delete m_pImportPlaylistAction; |
179 | + delete m_pExportPlaylistAction; |
180 | + delete m_pAddToAutoDJAction; |
181 | + delete m_pAddToAutoDJTopAction; |
182 | + delete m_pRenamePlaylistAction; |
183 | + delete m_pLockPlaylistAction; |
184 | +} |
185 | + |
186 | +void BasePlaylistFeature::activate() { |
187 | + emit(showPage(QUrl(m_rootViewUrl))); |
188 | + emit(switchToView(m_rootViewName)); |
189 | +} |
190 | + |
191 | +void BasePlaylistFeature::activateChild(const QModelIndex& index) { |
192 | + //qDebug() << "BasePlaylistFeature::activateChild()" << index; |
193 | + |
194 | + // Switch the playlist table model's playlist. |
195 | + QString playlistName = index.data().toString(); |
196 | + int playlistId = m_playlistDao.getPlaylistIdFromName(playlistName); |
197 | + if (m_pPlaylistTableModel) { |
198 | + m_pPlaylistTableModel->setPlaylist(playlistId); |
199 | + emit(showTrackModel(m_pPlaylistTableModel)); |
200 | + } |
201 | +} |
202 | + |
203 | +void BasePlaylistFeature::slotRenamePlaylist() { |
204 | + QString oldName = m_lastRightClickedIndex.data().toString(); |
205 | + int playlistId = m_playlistDao.getPlaylistIdFromName(oldName); |
206 | + bool locked = m_playlistDao.isPlaylistLocked(playlistId); |
207 | + |
208 | + if (locked) { |
209 | + qDebug() << "Skipping playlist rename because playlist" << playlistId |
210 | + << "is locked."; |
211 | + return; |
212 | + } |
213 | + |
214 | + QString newName; |
215 | + bool validNameGiven = false; |
216 | + |
217 | + do { |
218 | + bool ok = false; |
219 | + newName = QInputDialog::getText(NULL, |
220 | + tr("Rename Playlist"), |
221 | + tr("New playlist name:"), |
222 | + QLineEdit::Normal, |
223 | + oldName, |
224 | + &ok).trimmed(); |
225 | + |
226 | + if (!ok || oldName == newName) { |
227 | + return; |
228 | + } |
229 | + |
230 | + int existingId = m_playlistDao.getPlaylistIdFromName(newName); |
231 | + |
232 | + if (existingId != -1) { |
233 | + QMessageBox::warning(NULL, |
234 | + tr("Renaming Playlist Failed"), |
235 | + tr("A playlist by that name already exists.")); |
236 | + } |
237 | + else if (newName.isEmpty()) { |
238 | + QMessageBox::warning(NULL, |
239 | + tr("Renaming Playlist Failed"), |
240 | + tr("A playlist cannot have a blank name.")); |
241 | + } |
242 | + else { |
243 | + validNameGiven = true; |
244 | + } |
245 | + } while (!validNameGiven); |
246 | + |
247 | + m_playlistDao.renamePlaylist(playlistId, newName); |
248 | + emit(featureUpdated()); |
249 | +} |
250 | + |
251 | +void BasePlaylistFeature::slotTogglePlaylistLock() { |
252 | + QString playlistName = m_lastRightClickedIndex.data().toString(); |
253 | + int playlistId = m_playlistDao.getPlaylistIdFromName(playlistName); |
254 | + bool locked = !m_playlistDao.isPlaylistLocked(playlistId); |
255 | + |
256 | + if (!m_playlistDao.setPlaylistLocked(playlistId, locked)) { |
257 | + qDebug() << "Failed to toggle lock of playlistId " << playlistId; |
258 | + } |
259 | +} |
260 | + |
261 | +void BasePlaylistFeature::slotCreatePlaylist() { |
262 | + if (!m_pPlaylistTableModel) { |
263 | + return; |
264 | + } |
265 | + |
266 | + QString name; |
267 | + bool validNameGiven = false; |
268 | + |
269 | + do { |
270 | + bool ok = false; |
271 | + name = QInputDialog::getText(NULL, |
272 | + tr("New Playlist"), |
273 | + tr("Playlist name:"), |
274 | + QLineEdit::Normal, |
275 | + tr("New Playlist"), |
276 | + &ok).trimmed(); |
277 | + |
278 | + if (!ok) |
279 | + return; |
280 | + |
281 | + int existingId = m_playlistDao.getPlaylistIdFromName(name); |
282 | + |
283 | + if (existingId != -1) { |
284 | + QMessageBox::warning(NULL, |
285 | + tr("Playlist Creation Failed"), |
286 | + tr("A playlist by that name already exists.")); |
287 | + } else if (name.isEmpty()) { |
288 | + QMessageBox::warning(NULL, |
289 | + tr("Playlist Creation Failed"), |
290 | + tr("A playlist cannot have a blank name.")); |
291 | + } else { |
292 | + validNameGiven = true; |
293 | + } |
294 | + |
295 | + } while (!validNameGiven); |
296 | + |
297 | + int playlistId = m_playlistDao.createPlaylist(name); |
298 | + |
299 | + if (playlistId != -1) { |
300 | + emit(featureUpdated()); |
301 | + emit(showTrackModel(m_pPlaylistTableModel)); |
302 | + } |
303 | + else { |
304 | + QMessageBox::warning(NULL, |
305 | + tr("Playlist Creation Failed"), |
306 | + tr("An unknown error occurred while creating playlist: ") |
307 | + + name); |
308 | + } |
309 | +} |
310 | + |
311 | +void BasePlaylistFeature::slotDeletePlaylist() { |
312 | + //qDebug() << "slotDeletePlaylist() row:" << m_lastRightClickedIndex.data(); |
313 | + int playlistId = m_playlistDao.getPlaylistIdFromName(m_lastRightClickedIndex.data().toString()); |
314 | + bool locked = m_playlistDao.isPlaylistLocked(playlistId); |
315 | + |
316 | + if (locked) { |
317 | + qDebug() << "Skipping playlist deletion because playlist" << playlistId << "is locked."; |
318 | + return; |
319 | + } |
320 | + |
321 | + if (m_lastRightClickedIndex.isValid()) { |
322 | + Q_ASSERT(playlistId >= 0); |
323 | + |
324 | + m_playlistDao.deletePlaylist(playlistId); |
325 | + emit(featureUpdated()); |
326 | + activate(); |
327 | + } |
328 | +} |
329 | + |
330 | +bool BasePlaylistFeature::dropAccept(QUrl url) { |
331 | + Q_UNUSED(url); |
332 | + return false; |
333 | +} |
334 | + |
335 | +bool BasePlaylistFeature::dragMoveAccept(QUrl url) { |
336 | + Q_UNUSED(url); |
337 | + return false; |
338 | +} |
339 | + |
340 | +void BasePlaylistFeature::slotImportPlaylist() { |
341 | + qDebug() << "slotImportPlaylist() row:" ; //<< m_lastRightClickedIndex.data(); |
342 | + |
343 | + if (!m_pPlaylistTableModel) { |
344 | + return; |
345 | + } |
346 | + |
347 | + QString playlist_file = QFileDialog::getOpenFileName( |
348 | + NULL, |
349 | + tr("Import Playlist"), |
350 | + QDesktopServices::storageLocation(QDesktopServices::MusicLocation), |
351 | + tr("Playlist Files (*.m3u *.m3u8 *.pls *.csv)")); |
352 | + // Exit method if user cancelled the open dialog. |
353 | + if (playlist_file.isNull() || playlist_file.isEmpty()) { |
354 | + return; |
355 | + } |
356 | + |
357 | + Parser* playlist_parser = NULL; |
358 | + |
359 | + if (playlist_file.endsWith(".m3u", Qt::CaseInsensitive) || |
360 | + playlist_file.endsWith(".m3u8", Qt::CaseInsensitive)) { |
361 | + playlist_parser = new ParserM3u(); |
362 | + } else if (playlist_file.endsWith(".pls", Qt::CaseInsensitive)) { |
363 | + playlist_parser = new ParserPls(); |
364 | + } else if (playlist_file.endsWith(".csv", Qt::CaseInsensitive)) { |
365 | + playlist_parser = new ParserCsv(); |
366 | + } else { |
367 | + return; |
368 | + } |
369 | + QList<QString> entries = playlist_parser->parse(playlist_file); |
370 | + |
371 | + // Iterate over the List that holds URLs of playlist entires |
372 | + for (int i = 0; i < entries.size(); ++i) { |
373 | + m_pPlaylistTableModel->addTrack(QModelIndex(), entries[i]); |
374 | + } |
375 | + |
376 | + // delete the parser object |
377 | + if (playlist_parser) { |
378 | + delete playlist_parser; |
379 | + } |
380 | +} |
381 | + |
382 | +void BasePlaylistFeature::slotExportPlaylist() { |
383 | + if (!m_pPlaylistTableModel) { |
384 | + return; |
385 | + } |
386 | + |
387 | + qDebug() << "Export playlist" << m_lastRightClickedIndex.data(); |
388 | + QString file_location = QFileDialog::getSaveFileName( |
389 | + NULL, |
390 | + tr("Export Playlist"), |
391 | + QDesktopServices::storageLocation(QDesktopServices::MusicLocation), |
392 | + tr("M3U Playlist (*.m3u);;M3U8 Playlist (*.m3u8);;" |
393 | + "PLS Playlist (*.pls);;Text CSV (*.csv);;Readable Text (*.txt)")); |
394 | + // Exit method if user cancelled the open dialog. |
395 | + if (file_location.isNull() || file_location.isEmpty()) { |
396 | + return; |
397 | + } |
398 | + |
399 | + // Create a new table model since the main one might have an active search. |
400 | + QScopedPointer<PlaylistTableModel> pPlaylistTableModel( |
401 | + new PlaylistTableModel(this, m_pTrackCollection, |
402 | + "mixxx.db.model.playlist_export")); |
403 | + |
404 | + pPlaylistTableModel->setPlaylist(m_pPlaylistTableModel->getPlaylist()); |
405 | + pPlaylistTableModel->setSort(0, Qt::AscendingOrder); |
406 | + pPlaylistTableModel->select(); |
407 | + |
408 | + // check config if relative paths are desired |
409 | + bool useRelativePath = static_cast<bool>(m_pConfig->getValueString( |
410 | + ConfigKey("[Library]", "UseRelativePathOnExport")).toInt()); |
411 | + |
412 | + if (file_location.endsWith(".csv", Qt::CaseInsensitive)) { |
413 | + ParserCsv::writeCSVFile(file_location, pPlaylistTableModel.data(), useRelativePath); |
414 | + } else if (file_location.endsWith(".txt", Qt::CaseInsensitive)) { |
415 | + ParserCsv::writeReadableTextFile(file_location, pPlaylistTableModel.data()); |
416 | + } else { |
417 | + // Create and populate a list of files of the playlist |
418 | + QList<QString> playlist_items; |
419 | + int rows = pPlaylistTableModel->rowCount(); |
420 | + for (int i = 0; i < rows; ++i) { |
421 | + QModelIndex index = pPlaylistTableModel->index(i, 0); |
422 | + playlist_items << pPlaylistTableModel->getTrackLocation(index); |
423 | + } |
424 | + |
425 | + if (file_location.endsWith(".pls", Qt::CaseInsensitive)) { |
426 | + ParserPls::writePLSFile(file_location, playlist_items, useRelativePath); |
427 | + } else if (file_location.endsWith(".m3u8", Qt::CaseInsensitive)) { |
428 | + ParserM3u::writeM3U8File(file_location, playlist_items, useRelativePath); |
429 | + } else { |
430 | + //default export to M3U if file extension is missing |
431 | + if(!file_location.endsWith(".m3u", Qt::CaseInsensitive)) |
432 | + { |
433 | + qDebug() << "Crate export: No valid file extension specified. Appending .m3u " |
434 | + << "and exporting to M3U."; |
435 | + file_location.append(".m3u"); |
436 | + } |
437 | + ParserM3u::writeM3UFile(file_location, playlist_items, useRelativePath); |
438 | + } |
439 | + } |
440 | +} |
441 | + |
442 | +void BasePlaylistFeature::slotAddToAutoDJ() { |
443 | + //qDebug() << "slotAddToAutoDJ() row:" << m_lastRightClickedIndex.data(); |
444 | + addToAutoDJ(false); // Top = True |
445 | +} |
446 | + |
447 | +void BasePlaylistFeature::slotAddToAutoDJTop() { |
448 | + //qDebug() << "slotAddToAutoDJTop() row:" << m_lastRightClickedIndex.data(); |
449 | + addToAutoDJ(true); // bTop = True |
450 | +} |
451 | + |
452 | +void BasePlaylistFeature::addToAutoDJ(bool bTop) { |
453 | + //qDebug() << "slotAddToAutoDJ() row:" << m_lastRightClickedIndex.data(); |
454 | + |
455 | + if (m_lastRightClickedIndex.isValid()) { |
456 | + int playlistId = m_playlistDao.getPlaylistIdFromName( |
457 | + m_lastRightClickedIndex.data().toString()); |
458 | + if (playlistId >= 0) { |
459 | + // Insert this playlist |
460 | + m_playlistDao.addToAutoDJQueue(playlistId, bTop); |
461 | + } |
462 | + } |
463 | + emit(featureUpdated()); |
464 | +} |
465 | + |
466 | +void BasePlaylistFeature::onLazyChildExpandation(const QModelIndex &index){ |
467 | + Q_UNUSED(index); |
468 | + //Nothing to do because the childmodel is not of lazy nature. |
469 | +} |
470 | + |
471 | +TreeItemModel* BasePlaylistFeature::getChildModel() { |
472 | + return &m_childModel; |
473 | +} |
474 | + |
475 | +void BasePlaylistFeature::bindWidget(WLibrarySidebar* sidebarWidget, |
476 | + WLibrary* libraryWidget, |
477 | + MixxxKeyboard* keyboard) { |
478 | + Q_UNUSED(sidebarWidget); |
479 | + Q_UNUSED(keyboard); |
480 | + WLibraryTextBrowser* edit = new WLibraryTextBrowser(libraryWidget); |
481 | + connect(this, SIGNAL(showPage(const QUrl&)), |
482 | + edit, SLOT(setSource(const QUrl&))); |
483 | + libraryWidget->registerView(m_rootViewName, edit); |
484 | +} |
485 | + |
486 | +/** |
487 | + * Clears the child model dynamically, but the invisible root item remains |
488 | + */ |
489 | +void BasePlaylistFeature::clearChildModel() { |
490 | + m_childModel.removeRows(0,m_playlistTableModel.rowCount()); |
491 | +} |
492 | + |
493 | +void BasePlaylistFeature::slotPlaylistTableChanged(int playlistId) { |
494 | + if (!m_pPlaylistTableModel) { |
495 | + return; |
496 | + } |
497 | + |
498 | + //qDebug() << "slotPlaylistTableChanged() playlistId:" << playlistId; |
499 | + PlaylistDAO::HiddenType type = m_playlistDao.getHiddenType(playlistId); |
500 | + if (type == PlaylistDAO::PLHT_SET_LOG || |
501 | + type == PlaylistDAO::PLHT_UNKNOWN) { // In case of a deleted Playlist |
502 | + clearChildModel(); |
503 | + m_playlistTableModel.select(); |
504 | + m_lastRightClickedIndex = constructChildModel(playlistId); |
505 | + |
506 | + if (type != PlaylistDAO::PLHT_UNKNOWN) { |
507 | + // Switch the view to the playlist. |
508 | + m_pPlaylistTableModel->setPlaylist(playlistId); |
509 | + // Update selection |
510 | + emit(featureSelect(this, m_lastRightClickedIndex)); |
511 | + } |
512 | + } |
513 | +} |
514 | |
515 | === added file 'mixxx/src/library/baseplaylistfeature.h' |
516 | --- mixxx/src/library/baseplaylistfeature.h 1970-01-01 00:00:00 +0000 |
517 | +++ mixxx/src/library/baseplaylistfeature.h 2012-03-12 04:25:21 +0000 |
518 | @@ -0,0 +1,81 @@ |
519 | +#ifndef BASEPLAYLISTFEATURE_H |
520 | +#define BASEPLAYLISTFEATURE_H |
521 | + |
522 | +#include <QSqlTableModel> |
523 | +#include <QAction> |
524 | + |
525 | +#include "library/libraryfeature.h" |
526 | +#include "library/dao/playlistdao.h" |
527 | +#include "library/dao/trackdao.h" |
528 | + |
529 | +class WLibrarySidebar; |
530 | +class WLibrary; |
531 | +class MixxxKeyboard; |
532 | +class PlaylistTableModel; |
533 | +class TrackCollection; |
534 | + |
535 | +class BasePlaylistFeature : public LibraryFeature { |
536 | + Q_OBJECT |
537 | + public: |
538 | + BasePlaylistFeature(QObject* parent, |
539 | + ConfigObject<ConfigValue>* pConfig, |
540 | + TrackCollection* pTrackCollection, |
541 | + QString rootViewName, QString rootViewUrl); |
542 | + virtual ~BasePlaylistFeature(); |
543 | + |
544 | + TreeItemModel* getChildModel(); |
545 | + |
546 | + void bindWidget(WLibrarySidebar* sidebarWidget, |
547 | + WLibrary* libraryWidget, |
548 | + MixxxKeyboard* keyboard); |
549 | + |
550 | + signals: |
551 | + void showPage(const QUrl& page); |
552 | + |
553 | + public slots: |
554 | + virtual void activate(); |
555 | + virtual void activateChild(const QModelIndex& index); |
556 | + virtual bool dropAccept(QUrl url); |
557 | + virtual bool dragMoveAccept(QUrl url); |
558 | + virtual void onLazyChildExpandation(const QModelIndex& index); |
559 | + |
560 | + void slotCreatePlaylist(); |
561 | + |
562 | + protected slots: |
563 | + void slotDeletePlaylist(); |
564 | + void slotAddToAutoDJ(); |
565 | + void slotAddToAutoDJTop(); |
566 | + void slotRenamePlaylist(); |
567 | + void slotTogglePlaylistLock(); |
568 | + void slotImportPlaylist(); |
569 | + void slotExportPlaylist(); |
570 | + void slotPlaylistTableChanged(int playlistId); |
571 | + |
572 | + protected: |
573 | + virtual QModelIndex constructChildModel(int selected_id) = 0; |
574 | + virtual void clearChildModel(); |
575 | + virtual void addToAutoDJ(bool bTop); |
576 | + |
577 | + ConfigObject<ConfigValue>* m_pConfig; |
578 | + TrackCollection* m_pTrackCollection; |
579 | + PlaylistDAO &m_playlistDao; |
580 | + TrackDAO &m_trackDao; |
581 | + PlaylistTableModel* m_pPlaylistTableModel; |
582 | + QAction *m_pCreatePlaylistAction; |
583 | + QAction *m_pDeletePlaylistAction; |
584 | + QAction *m_pAddToAutoDJAction; |
585 | + QAction *m_pAddToAutoDJTopAction; |
586 | + QAction *m_pRenamePlaylistAction; |
587 | + QAction *m_pLockPlaylistAction; |
588 | + QAction *m_pImportPlaylistAction; |
589 | + QAction *m_pExportPlaylistAction; |
590 | + QSqlTableModel m_playlistTableModel; |
591 | + QModelIndex m_lastRightClickedIndex; |
592 | + TreeItemModel m_childModel; |
593 | + |
594 | + private: |
595 | + QString m_rootViewName; |
596 | + QString m_rootViewUrl; |
597 | +}; |
598 | + |
599 | +#endif /* BASEPLAYLISTFEATURE_H */ |
600 | |
601 | === modified file 'mixxx/src/library/basesqltablemodel.cpp' |
602 | --- mixxx/src/library/basesqltablemodel.cpp 2011-12-28 20:30:15 +0000 |
603 | +++ mixxx/src/library/basesqltablemodel.cpp 2012-03-12 04:25:21 +0000 |
604 | @@ -628,7 +628,7 @@ |
605 | // QVariant::toFloat needs >= QT 4.6.x |
606 | pTrack->setBpm(static_cast<float>(value.toDouble())); |
607 | } else if (fieldIndex(LIBRARYTABLE_PLAYED) == column) { |
608 | - pTrack->setPlayed(value.toBool()); |
609 | + pTrack->setPlayedAndUpdatePlaycount(value.toBool()); |
610 | } else if (fieldIndex(LIBRARYTABLE_TIMESPLAYED) == column) { |
611 | pTrack->setTimesPlayed(value.toInt()); |
612 | } else if (fieldIndex(LIBRARYTABLE_RATING) == column) { |
613 | |
614 | === modified file 'mixxx/src/library/browse/browsetablemodel.cpp' |
615 | --- mixxx/src/library/browse/browsetablemodel.cpp 2011-12-28 20:30:15 +0000 |
616 | +++ mixxx/src/library/browse/browsetablemodel.cpp 2012-03-12 04:25:21 +0000 |
617 | @@ -22,7 +22,7 @@ |
618 | "mixxx.db.model.browse"), |
619 | QStandardItemModel(parent), |
620 | m_pTrackCollection(pTrackCollection), |
621 | - m_pRecordingManager(pRecordingManager) { |
622 | + m_pRecordingManager(pRecordingManager) { |
623 | QStringList header_data; |
624 | header_data.insert(COLUMN_FILENAME, tr("Filename")); |
625 | header_data.insert(COLUMN_ARTIST, tr("Artist")); |
626 | @@ -61,12 +61,9 @@ |
627 | connect(BrowseThread::getInstance(), SIGNAL(rowsAppended(const QList< QList<QStandardItem*> >&, BrowseTableModel*)), |
628 | this, SLOT(slotInsert(const QList< QList<QStandardItem*> >&, BrowseTableModel*)), |
629 | Qt::QueuedConnection); |
630 | - |
631 | } |
632 | |
633 | -BrowseTableModel::~BrowseTableModel() |
634 | -{ |
635 | - |
636 | +BrowseTableModel::~BrowseTableModel() { |
637 | } |
638 | |
639 | const QList<int>& BrowseTableModel::searchColumns() const { |
640 | |
641 | === modified file 'mixxx/src/library/cratefeature.cpp' |
642 | --- mixxx/src/library/cratefeature.cpp 2011-12-09 02:49:02 +0000 |
643 | +++ mixxx/src/library/cratefeature.cpp 2012-03-12 04:25:21 +0000 |
644 | @@ -9,6 +9,7 @@ |
645 | #include "library/parser.h" |
646 | #include "library/parserm3u.h" |
647 | #include "library/parserpls.h" |
648 | +#include "library/parsercsv.h" |
649 | |
650 | #include "library/cratetablemodel.h" |
651 | #include "library/trackcollection.h" |
652 | @@ -22,9 +23,11 @@ |
653 | CrateFeature::CrateFeature(QObject* parent, |
654 | TrackCollection* pTrackCollection, ConfigObject<ConfigValue>* pConfig) |
655 | : m_pTrackCollection(pTrackCollection), |
656 | + m_crateDao(pTrackCollection->getCrateDAO()), |
657 | m_crateListTableModel(this, pTrackCollection->getDatabase()), |
658 | - m_pConfig(pConfig), |
659 | - m_crateTableModel(this, pTrackCollection) { |
660 | + m_crateTableModel(this, pTrackCollection), |
661 | + m_pConfig(pConfig) { |
662 | + Q_UNUSED(parent); |
663 | m_pCreateCrateAction = new QAction(tr("New Crate"),this); |
664 | connect(m_pCreateCrateAction, SIGNAL(triggered()), |
665 | this, SLOT(slotCreateCrate())); |
666 | @@ -48,6 +51,19 @@ |
667 | connect(m_pExportPlaylistAction, SIGNAL(triggered()), |
668 | this, SLOT(slotExportPlaylist())); |
669 | |
670 | + connect(&m_crateDao, SIGNAL(added(int)), |
671 | + this, SLOT(slotCrateTableChanged(int))); |
672 | + |
673 | + connect(&m_crateDao, SIGNAL(deleted(int)), |
674 | + this, SLOT(slotCrateTableChanged(int))); |
675 | + |
676 | + connect(&m_crateDao, SIGNAL(renamed(int)), |
677 | + this, SLOT(slotCrateTableChanged(int))); |
678 | + |
679 | + connect(&m_crateDao, SIGNAL(lockChanged(int)), |
680 | + this, SLOT(slotCrateTableChanged(int))); |
681 | + |
682 | + |
683 | m_crateListTableModel.setTable("crates"); |
684 | m_crateListTableModel.setSort(m_crateListTableModel.fieldIndex("name"), |
685 | Qt::AscendingOrder); |
686 | @@ -57,7 +73,7 @@ |
687 | // construct child model |
688 | TreeItem *rootItem = new TreeItem(); |
689 | m_childModel.setRootItem(rootItem); |
690 | - constructChildModel(); |
691 | + constructChildModel(-1); |
692 | } |
693 | |
694 | CrateFeature::~CrateFeature() { |
695 | @@ -78,12 +94,13 @@ |
696 | } |
697 | |
698 | bool CrateFeature::dropAccept(QUrl url) { |
699 | + Q_UNUSED(url) |
700 | return false; |
701 | } |
702 | |
703 | bool CrateFeature::dropAcceptChild(const QModelIndex& index, QUrl url) { |
704 | QString crateName = index.data().toString(); |
705 | - int crateId = m_pTrackCollection->getCrateDAO().getCrateIdByName(crateName); |
706 | + int crateId = m_crateDao.getCrateIdByName(crateName); |
707 | |
708 | //XXX: See the comment in PlaylistFeature::dropAcceptChild() about |
709 | // QUrl::toLocalFile() vs. QUrl::toString() usage. |
710 | @@ -95,10 +112,8 @@ |
711 | qDebug() << "CrateFeature::dropAcceptChild adding track" |
712 | << trackId << "to crate" << crateId; |
713 | |
714 | - CrateDAO& crateDao = m_pTrackCollection->getCrateDAO(); |
715 | - |
716 | if (trackId >= 0) |
717 | - return crateDao.addTrackToCrate(trackId, crateId); |
718 | + return m_crateDao.addTrackToCrate(trackId, crateId); |
719 | return false; |
720 | } |
721 | |
722 | @@ -110,9 +125,8 @@ |
723 | bool CrateFeature::dragMoveAcceptChild(const QModelIndex& index, QUrl url) { |
724 | //TODO: Filter by supported formats regex and reject anything that doesn't match. |
725 | QString crateName = index.data().toString(); |
726 | - CrateDAO& crateDao = m_pTrackCollection->getCrateDAO(); |
727 | - int crateId = crateDao.getCrateIdByName(crateName); |
728 | - bool locked = crateDao.isCrateLocked(crateId); |
729 | + int crateId = m_crateDao.getCrateIdByName(crateName); |
730 | + bool locked = m_crateDao.isCrateLocked(crateId); |
731 | |
732 | QFileInfo file(url.toLocalFile()); |
733 | bool formatSupported = SoundSourceProxy::isFilenameSupported(file.fileName()); |
734 | @@ -143,7 +157,7 @@ |
735 | if (!index.isValid()) |
736 | return; |
737 | QString crateName = index.data().toString(); |
738 | - int crateId = m_pTrackCollection->getCrateDAO().getCrateIdByName(crateName); |
739 | + int crateId = m_crateDao.getCrateIdByName(crateName); |
740 | m_crateTableModel.setCrate(crateId); |
741 | emit(showTrackModel(&m_crateTableModel)); |
742 | } |
743 | @@ -160,10 +174,9 @@ |
744 | m_lastRightClickedIndex = index; |
745 | |
746 | QString crateName = index.data().toString(); |
747 | - CrateDAO& crateDAO = m_pTrackCollection->getCrateDAO(); |
748 | - int crateId = crateDAO.getCrateIdByName(crateName); |
749 | + int crateId = m_crateDao.getCrateIdByName(crateName); |
750 | |
751 | - bool locked = crateDAO.isCrateLocked(crateId); |
752 | + bool locked = m_crateDao.isCrateLocked(crateId); |
753 | |
754 | m_pDeleteCrateAction->setEnabled(!locked); |
755 | m_pRenameCrateAction->setEnabled(!locked); |
756 | @@ -186,7 +199,6 @@ |
757 | |
758 | QString name; |
759 | bool validNameGiven = false; |
760 | - CrateDAO& crateDao = m_pTrackCollection->getCrateDAO(); |
761 | |
762 | do { |
763 | bool ok = false; |
764 | @@ -199,7 +211,7 @@ |
765 | if (!ok) |
766 | return; |
767 | |
768 | - int existingId = crateDao.getCrateIdByName(name); |
769 | + int existingId = m_crateDao.getCrateIdByName(name); |
770 | |
771 | if (existingId != -1) { |
772 | QMessageBox::warning(NULL, |
773 | @@ -217,17 +229,10 @@ |
774 | |
775 | } while (!validNameGiven); |
776 | |
777 | - bool crateCreated = crateDao.createCrate(name); |
778 | + int crate_id = m_crateDao.createCrate(name); |
779 | |
780 | - if (crateCreated) { |
781 | - clearChildModel(); |
782 | - m_crateListTableModel.select(); |
783 | - constructChildModel(); |
784 | - // Switch to the new crate. |
785 | - int crate_id = crateDao.getCrateIdByName(name); |
786 | - m_crateTableModel.setCrate(crate_id); |
787 | + if (crate_id != -1) { |
788 | emit(showTrackModel(&m_crateTableModel)); |
789 | - // TODO(XXX) set sidebar selection |
790 | emit(featureUpdated()); |
791 | } else { |
792 | qDebug() << "Error creating crate with name " << name; |
793 | @@ -241,22 +246,19 @@ |
794 | |
795 | void CrateFeature::slotDeleteCrate() { |
796 | QString crateName = m_lastRightClickedIndex.data().toString(); |
797 | - CrateDAO &crateDao = m_pTrackCollection->getCrateDAO(); |
798 | - int crateId = crateDao.getCrateIdByName(crateName); |
799 | - bool locked = crateDao.isCrateLocked(crateId); |
800 | + int crateId = m_crateDao.getCrateIdByName(crateName); |
801 | + bool locked = m_crateDao.isCrateLocked(crateId); |
802 | |
803 | if (locked) { |
804 | qDebug() << "Skipping crate deletion because crate" << crateId << "is locked."; |
805 | return; |
806 | } |
807 | |
808 | - bool deleted = crateDao.deleteCrate(crateId); |
809 | + bool deleted = m_crateDao.deleteCrate(crateId); |
810 | |
811 | if (deleted) { |
812 | - clearChildModel(); |
813 | - m_crateListTableModel.select(); |
814 | - constructChildModel(); |
815 | emit(featureUpdated()); |
816 | + activate(); |
817 | } else { |
818 | qDebug() << "Failed to delete crateId" << crateId; |
819 | } |
820 | @@ -264,9 +266,8 @@ |
821 | |
822 | void CrateFeature::slotRenameCrate() { |
823 | QString oldName = m_lastRightClickedIndex.data().toString(); |
824 | - CrateDAO &crateDao = m_pTrackCollection->getCrateDAO(); |
825 | - int crateId = crateDao.getCrateIdByName(oldName); |
826 | - bool locked = crateDao.isCrateLocked(crateId); |
827 | + int crateId = m_crateDao.getCrateIdByName(oldName); |
828 | + bool locked = m_crateDao.isCrateLocked(crateId); |
829 | |
830 | if (locked) { |
831 | qDebug() << "Skipping crate rename because crate" << crateId << "is locked."; |
832 | @@ -289,7 +290,7 @@ |
833 | return; |
834 | } |
835 | |
836 | - int existingId = m_pTrackCollection->getCrateDAO().getCrateIdByName(newName); |
837 | + int existingId = m_crateDao.getCrateIdByName(newName); |
838 | |
839 | if (existingId != -1) { |
840 | QMessageBox::warning(NULL, |
841 | @@ -307,12 +308,8 @@ |
842 | } while (!validNameGiven); |
843 | |
844 | |
845 | - if (m_pTrackCollection->getCrateDAO().renameCrate(crateId, newName)) { |
846 | - clearChildModel(); |
847 | - m_crateListTableModel.select(); |
848 | - constructChildModel(); |
849 | + if (m_crateDao.renameCrate(crateId, newName)) { |
850 | emit(featureUpdated()); |
851 | - m_crateTableModel.setCrate(crateId); |
852 | } else { |
853 | qDebug() << "Failed to rename crateId" << crateId; |
854 | } |
855 | @@ -321,17 +318,12 @@ |
856 | void CrateFeature::slotToggleCrateLock() |
857 | { |
858 | QString crateName = m_lastRightClickedIndex.data().toString(); |
859 | - CrateDAO& crateDAO = m_pTrackCollection->getCrateDAO(); |
860 | - int crateId = crateDAO.getCrateIdByName(crateName); |
861 | - bool locked = !crateDAO.isCrateLocked(crateId); |
862 | + int crateId = m_crateDao.getCrateIdByName(crateName); |
863 | + bool locked = !m_crateDao.isCrateLocked(crateId); |
864 | |
865 | - if (!crateDAO.setCrateLocked(crateId, locked)) { |
866 | + if (!m_crateDao.setCrateLocked(crateId, locked)) { |
867 | qDebug() << "Failed to toggle lock of crateId " << crateId; |
868 | } |
869 | - |
870 | - TreeItem* crateItem = m_childModel.getItem(m_lastRightClickedIndex); |
871 | - crateItem->setIcon( |
872 | - locked ? QIcon(":/images/library/ic_library_locked.png") : QIcon()); |
873 | } |
874 | |
875 | |
876 | @@ -340,14 +332,14 @@ |
877 | * we require the sidebar model not to reset. |
878 | * This method queries the database and does dynamic insertion |
879 | */ |
880 | -void CrateFeature::constructChildModel() |
881 | +QModelIndex CrateFeature::constructChildModel(int selected_id) |
882 | { |
883 | QList<TreeItem*> data_list; |
884 | int nameColumn = m_crateListTableModel.record().indexOf("name"); |
885 | int idColumn = m_crateListTableModel.record().indexOf("id"); |
886 | - //Access the invisible root item |
887 | + int selected_row = -1; |
888 | + // Access the invisible root item |
889 | TreeItem* root = m_childModel.getItem(QModelIndex()); |
890 | - CrateDAO &crateDao = m_pTrackCollection->getCrateDAO(); |
891 | |
892 | for (int row = 0; row < m_crateListTableModel.rowCount(); ++row) { |
893 | QModelIndex ind = m_crateListTableModel.index(row, nameColumn); |
894 | @@ -355,14 +347,23 @@ |
895 | ind = m_crateListTableModel.index(row, idColumn); |
896 | int crate_id = m_crateListTableModel.data(ind).toInt(); |
897 | |
898 | - //Create the TreeItem whose parent is the invisible root item |
899 | + if (selected_id == crate_id) { |
900 | + // save index for selection |
901 | + selected_row = row; m_childModel.index(selected_row, 0); |
902 | + } |
903 | + |
904 | + // Create the TreeItem whose parent is the invisible root item |
905 | TreeItem* item = new TreeItem(crate_name, crate_name, this, root); |
906 | - bool locked = crateDao.isCrateLocked(crate_id); |
907 | + bool locked = m_crateDao.isCrateLocked(crate_id); |
908 | item->setIcon(locked ? QIcon(":/images/library/ic_library_locked.png") : QIcon()); |
909 | data_list.append(item); |
910 | } |
911 | - //Append all the newly created TreeItems in a dynamic way to the childmodel |
912 | + // Append all the newly created TreeItems in a dynamic way to the childmodel |
913 | m_childModel.insertRows(data_list, 0, m_crateListTableModel.rowCount()); |
914 | + if (selected_row == -1) { |
915 | + return QModelIndex(); |
916 | + } |
917 | + return m_childModel.index(selected_row, 0); |
918 | } |
919 | |
920 | /** |
921 | @@ -382,7 +383,7 @@ |
922 | NULL, |
923 | tr("Import Playlist"), |
924 | QDesktopServices::storageLocation(QDesktopServices::MusicLocation), |
925 | - tr("Playlist Files (*.m3u *.m3u8 *.pls)")); |
926 | + tr("Playlist Files (*.m3u *.m3u8 *.pls *.csv)")); |
927 | // Exit method if user cancelled the open dialog. |
928 | if (playlist_file.isNull() || playlist_file.isEmpty() ) return; |
929 | |
930 | @@ -394,6 +395,8 @@ |
931 | playlist_parser = new ParserM3u(); |
932 | } else if (playlist_file.endsWith(".pls", Qt::CaseInsensitive)) { |
933 | playlist_parser = new ParserPls(); |
934 | + } else if (playlist_file.endsWith(".csv", Qt::CaseInsensitive)) { |
935 | + playlist_parser = new ParserCsv(); |
936 | } else { |
937 | return; |
938 | } |
939 | @@ -423,16 +426,17 @@ |
940 | NULL, |
941 | tr("Export Crate"), |
942 | QDesktopServices::storageLocation(QDesktopServices::MusicLocation), |
943 | - tr("M3U Playlist (*.m3u);;M3U8 Playlist (*.m3u8);;PLS Playlist (*.pls)")); |
944 | + tr("M3U Playlist (*.m3u);;M3U8 Playlist (*.m3u8);;PLS Playlist (*.pls);;Text CSV (*.csv);;Readable Text (*.txt)")); |
945 | // Exit method if user cancelled the open dialog. |
946 | - if (file_location.isNull() || file_location.isEmpty()) |
947 | + if (file_location.isNull() || file_location.isEmpty()) { |
948 | return; |
949 | + } |
950 | // check config if relative paths are desired |
951 | bool useRelativePath = static_cast<bool>( |
952 | m_pConfig->getValueString( |
953 | ConfigKey("[Library]", "UseRelativePathOnExport")).toInt()); |
954 | |
955 | - // Create and populate a list of files of the crate |
956 | + // Create list of files of the crate |
957 | QList<QString> playlist_items; |
958 | // Create a new table model since the main one might have an active search. |
959 | QScopedPointer<CrateTableModel> pCrateTableModel( |
960 | @@ -440,24 +444,44 @@ |
961 | pCrateTableModel->setCrate(m_crateTableModel.getCrate()); |
962 | pCrateTableModel->select(); |
963 | int rows = pCrateTableModel->rowCount(); |
964 | - for (int i = 0; i < rows; ++i) { |
965 | - QModelIndex index = pCrateTableModel->index(i, 0); |
966 | - playlist_items << pCrateTableModel->getTrackLocation(index); |
967 | - } |
968 | - |
969 | - if (file_location.endsWith(".pls", Qt::CaseInsensitive)) { |
970 | - ParserPls::writePLSFile(file_location, playlist_items, useRelativePath); |
971 | - } else if (file_location.endsWith(".m3u8", Qt::CaseInsensitive)) { |
972 | - ParserM3u::writeM3U8File(file_location, playlist_items, |
973 | - useRelativePath); |
974 | - } else { |
975 | - // Default export to M3U if file extension is missing |
976 | - if (!file_location.endsWith(".m3u", Qt::CaseInsensitive)) { |
977 | - qDebug() << "Crate export: No valid file extension specified. Appending .m3u " |
978 | - << "and exporting to M3U."; |
979 | - file_location.append(".m3u"); |
980 | - } |
981 | - ParserM3u::writeM3UFile(file_location, playlist_items, useRelativePath); |
982 | - } |
983 | -} |
984 | - |
985 | + |
986 | + if (file_location.endsWith(".csv", Qt::CaseInsensitive)) { |
987 | + ParserCsv::writeCSVFile(file_location, pCrateTableModel.data(), useRelativePath); |
988 | + } else if (file_location.endsWith(".txt", Qt::CaseInsensitive)) { |
989 | + ParserCsv::writeReadableTextFile(file_location, pCrateTableModel.data()); |
990 | + } else{ |
991 | + // populate a list of files of the crate |
992 | + QList<QString> playlist_items; |
993 | + int rows = pCrateTableModel->rowCount(); |
994 | + for (int i = 0; i < rows; ++i) { |
995 | + QModelIndex index = m_crateTableModel.index(i, 0); |
996 | + playlist_items << m_crateTableModel.getTrackLocation(index); |
997 | + } |
998 | + |
999 | + if (file_location.endsWith(".pls", Qt::CaseInsensitive)) { |
1000 | + ParserPls::writePLSFile(file_location, playlist_items, useRelativePath); |
1001 | + } else if (file_location.endsWith(".m3u8", Qt::CaseInsensitive)) { |
1002 | + ParserM3u::writeM3U8File(file_location, playlist_items, useRelativePath); |
1003 | + } else { |
1004 | + //default export to M3U if file extension is missing |
1005 | + if(!file_location.endsWith(".m3u", Qt::CaseInsensitive)) |
1006 | + { |
1007 | + qDebug() << "Crate export: No valid file extension specified. Appending .m3u " |
1008 | + << "and exporting to M3U."; |
1009 | + file_location.append(".m3u"); |
1010 | + } |
1011 | + ParserM3u::writeM3UFile(file_location, playlist_items, useRelativePath); |
1012 | + } |
1013 | + } |
1014 | +} |
1015 | + |
1016 | +void CrateFeature::slotCrateTableChanged(int crateId) { |
1017 | + //qDebug() << "slotPlaylistTableChanged() playlistId:" << playlistId; |
1018 | + clearChildModel(); |
1019 | + m_crateListTableModel.select(); |
1020 | + m_lastRightClickedIndex = constructChildModel(crateId); |
1021 | + // Switch the view to the crate. |
1022 | + m_crateTableModel.setCrate(crateId); |
1023 | + // Update selection |
1024 | + emit(featureSelect(this, m_lastRightClickedIndex)); |
1025 | +} |
1026 | |
1027 | === modified file 'mixxx/src/library/cratefeature.h' |
1028 | --- mixxx/src/library/cratefeature.h 2011-03-12 13:10:25 +0000 |
1029 | +++ mixxx/src/library/cratefeature.h 2012-03-12 04:25:21 +0000 |
1030 | @@ -48,12 +48,14 @@ |
1031 | void slotToggleCrateLock(); |
1032 | void slotImportPlaylist(); |
1033 | void slotExportPlaylist(); |
1034 | + void slotCrateTableChanged(int playlistId); |
1035 | |
1036 | private: |
1037 | - void constructChildModel(); |
1038 | + QModelIndex constructChildModel(int selected_id); |
1039 | void clearChildModel(); |
1040 | - |
1041 | + |
1042 | TrackCollection* m_pTrackCollection; |
1043 | + CrateDAO& m_crateDao; |
1044 | QAction *m_pCreateCrateAction; |
1045 | QAction *m_pDeleteCrateAction; |
1046 | QAction *m_pRenameCrateAction; |
1047 | |
1048 | === modified file 'mixxx/src/library/dao/cratedao.cpp' |
1049 | --- mixxx/src/library/dao/cratedao.cpp 2011-12-18 20:23:14 +0000 |
1050 | +++ mixxx/src/library/dao/cratedao.cpp 2012-03-12 04:25:21 +0000 |
1051 | @@ -31,19 +31,19 @@ |
1052 | return query.value(0).toInt(); |
1053 | } |
1054 | |
1055 | -bool CrateDAO::createCrate(const QString& name) { |
1056 | +int CrateDAO::createCrate(const QString& name) { |
1057 | QSqlQuery query(m_database); |
1058 | query.prepare("INSERT INTO " CRATE_TABLE " (name) VALUES (:name)"); |
1059 | query.bindValue(":name", name); |
1060 | |
1061 | if (!query.exec()) { |
1062 | LOG_FAILED_QUERY(query); |
1063 | - return false; |
1064 | + return -1; |
1065 | } |
1066 | |
1067 | int crateId = query.lastInsertId().toInt(); |
1068 | emit(added(crateId)); |
1069 | - return true; |
1070 | + return crateId; |
1071 | } |
1072 | |
1073 | bool CrateDAO::renameCrate(int crateId, const QString& newName) { |
1074 | @@ -56,6 +56,7 @@ |
1075 | LOG_FAILED_QUERY(query); |
1076 | return false; |
1077 | } |
1078 | + emit(renamed(crateId)); |
1079 | return true; |
1080 | } |
1081 | |
1082 | @@ -71,7 +72,7 @@ |
1083 | LOG_FAILED_QUERY(query); |
1084 | return false; |
1085 | } |
1086 | - |
1087 | + emit(lockChanged(crateId)); |
1088 | return true; |
1089 | } |
1090 | |
1091 | |
1092 | === modified file 'mixxx/src/library/dao/cratedao.h' |
1093 | --- mixxx/src/library/dao/cratedao.h 2011-10-21 00:42:23 +0000 |
1094 | +++ mixxx/src/library/dao/cratedao.h 2012-03-12 04:25:21 +0000 |
1095 | @@ -28,7 +28,7 @@ |
1096 | void initialize(); |
1097 | |
1098 | unsigned int crateCount(); |
1099 | - bool createCrate(const QString& name); |
1100 | + int createCrate(const QString& name); |
1101 | bool deleteCrate(int crateId); |
1102 | bool renameCrate(int crateId, const QString& newName); |
1103 | bool setCrateLocked(int crateId, bool locked); |
1104 | @@ -47,6 +47,8 @@ |
1105 | void changed(int crateId); |
1106 | void trackAdded(int crateId, int trackId); |
1107 | void trackRemoved(int crateId, int trackId); |
1108 | + void renamed(int crateId); |
1109 | + void lockChanged(int crateId); |
1110 | |
1111 | private: |
1112 | QSqlDatabase& m_database; |
1113 | @@ -54,4 +56,3 @@ |
1114 | }; |
1115 | |
1116 | #endif /* CRATEDAO_H */ |
1117 | - |
1118 | |
1119 | === modified file 'mixxx/src/library/dao/playlistdao.cpp' |
1120 | --- mixxx/src/library/dao/playlistdao.cpp 2011-12-18 20:23:14 +0000 |
1121 | +++ mixxx/src/library/dao/playlistdao.cpp 2012-03-12 04:25:21 +0000 |
1122 | @@ -1,4 +1,3 @@ |
1123 | - |
1124 | #include <QtDebug> |
1125 | #include <QtCore> |
1126 | #include <QtSql> |
1127 | @@ -19,10 +18,7 @@ |
1128 | { |
1129 | } |
1130 | |
1131 | -/** Create a playlist with the given name. |
1132 | - @param name The name of the playlist to be created. |
1133 | -*/ |
1134 | -bool PlaylistDAO::createPlaylist(QString name, bool hidden) |
1135 | +int PlaylistDAO::createPlaylist(QString name, HiddenType hidden) |
1136 | { |
1137 | // qDebug() << "PlaylistDAO::createPlaylist" |
1138 | // << QThread::currentThread() |
1139 | @@ -38,7 +34,7 @@ |
1140 | if (!query.exec()) { |
1141 | LOG_FAILED_QUERY(query); |
1142 | m_database.rollback(); |
1143 | - return false; |
1144 | + return -1; |
1145 | } |
1146 | |
1147 | //Get the id of the last playlist. |
1148 | @@ -50,34 +46,33 @@ |
1149 | |
1150 | //qDebug() << "Inserting playlist" << name << "at position" << position; |
1151 | |
1152 | - query.prepare("INSERT INTO Playlists (name, position, hidden) " |
1153 | - "VALUES (:name, :position, :hidden)"); |
1154 | + query.prepare("INSERT INTO Playlists (name, position, hidden, date_created, date_modified) " |
1155 | + "VALUES (:name, :position, :hidden, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"); |
1156 | query.bindValue(":name", name); |
1157 | query.bindValue(":position", position); |
1158 | - query.bindValue(":hidden", hidden ? 1 : 0); |
1159 | + query.bindValue(":hidden", static_cast<int>(hidden)); |
1160 | |
1161 | if (!query.exec()) { |
1162 | LOG_FAILED_QUERY(query); |
1163 | m_database.rollback(); |
1164 | - return false; |
1165 | + return -1; |
1166 | } |
1167 | |
1168 | int playlistId = query.lastInsertId().toInt(); |
1169 | //Commit the transaction |
1170 | m_database.commit(); |
1171 | emit(added(playlistId)); |
1172 | - return true; |
1173 | + return playlistId; |
1174 | } |
1175 | |
1176 | -/** Find out the name of the playlist at the given position */ |
1177 | -QString PlaylistDAO::getPlaylistName(unsigned int position) |
1178 | +QString PlaylistDAO::getPlaylistName(int playlistId) |
1179 | { |
1180 | // qDebug() << "PlaylistDAO::getPlaylistName" << QThread::currentThread() << m_database.connectionName(); |
1181 | |
1182 | QSqlQuery query(m_database); |
1183 | query.prepare("SELECT name FROM Playlists " |
1184 | - "WHERE position = :position"); |
1185 | - query.bindValue(":position", position); |
1186 | + "WHERE id= :id"); |
1187 | + query.bindValue(":id", playlistId); |
1188 | |
1189 | if (!query.exec()) { |
1190 | LOG_FAILED_QUERY(query); |
1191 | @@ -108,8 +103,6 @@ |
1192 | return -1; |
1193 | } |
1194 | |
1195 | - |
1196 | -/** Delete a playlist */ |
1197 | void PlaylistDAO::deletePlaylist(int playlistId) |
1198 | { |
1199 | // qDebug() << "PlaylistDAO::deletePlaylist" << QThread::currentThread() << m_database.connectionName(); |
1200 | @@ -144,7 +137,6 @@ |
1201 | emit(deleted(playlistId)); |
1202 | } |
1203 | |
1204 | - |
1205 | void PlaylistDAO::renamePlaylist(int playlistId, const QString& newName) { |
1206 | QSqlQuery query(m_database); |
1207 | query.prepare("UPDATE Playlists SET name = :name WHERE id = :id"); |
1208 | @@ -152,23 +144,23 @@ |
1209 | query.bindValue(":id", playlistId); |
1210 | if (!query.exec()) { |
1211 | LOG_FAILED_QUERY(query); |
1212 | + return; |
1213 | } |
1214 | + emit(renamed(playlistId)); |
1215 | } |
1216 | |
1217 | - |
1218 | bool PlaylistDAO::setPlaylistLocked(int playlistId, bool locked) { |
1219 | + QSqlQuery query(m_database); |
1220 | + query.prepare("UPDATE Playlists SET locked = :lock WHERE id = :id"); |
1221 | // SQLite3 doesn't support boolean value. Using integer instead. |
1222 | - int lock = locked ? 1 : 0; |
1223 | - |
1224 | - QSqlQuery query(m_database); |
1225 | - query.prepare("UPDATE Playlists SET locked = :lock WHERE id = :id"); |
1226 | - query.bindValue(":lock", lock); |
1227 | + query.bindValue(":lock", static_cast<int>(locked)); |
1228 | query.bindValue(":id", playlistId); |
1229 | |
1230 | if (!query.exec()) { |
1231 | LOG_FAILED_QUERY(query); |
1232 | return false; |
1233 | } |
1234 | + emit(lockChanged(playlistId)); |
1235 | return true; |
1236 | } |
1237 | |
1238 | @@ -188,10 +180,8 @@ |
1239 | return false; |
1240 | } |
1241 | |
1242 | -/** Append a track to a playlist */ |
1243 | -void PlaylistDAO::appendTrackToPlaylist(int trackId, int playlistId) |
1244 | -{ |
1245 | - // qDebug() << "PlaylistDAO::appendTrackToPlaylist" |
1246 | +void PlaylistDAO::appendTracksToPlaylist(QList<int> trackIds, int playlistId) { |
1247 | + // qDebug() << "PlaylistDAO::appendTracksToPlaylist" |
1248 | // << QThread::currentThread() << m_database.connectionName(); |
1249 | |
1250 | // Start the transaction |
1251 | @@ -207,32 +197,44 @@ |
1252 | LOG_FAILED_QUERY(query); |
1253 | } |
1254 | |
1255 | - // Get the position of the highest playlist... |
1256 | + // Get the position of the highest track in the playlist. |
1257 | int position = 0; |
1258 | if (query.next()) { |
1259 | position = query.value(query.record().indexOf("position")).toInt(); |
1260 | } |
1261 | - position++; //Append after the last song. |
1262 | + // Append after the last song. If no songs or a failed query then 0 becomes |
1263 | + // 1. |
1264 | + position++; |
1265 | |
1266 | //Insert the song into the PlaylistTracks table |
1267 | query.prepare("INSERT INTO PlaylistTracks (playlist_id, track_id, position)" |
1268 | "VALUES (:playlist_id, :track_id, :position)"); |
1269 | query.bindValue(":playlist_id", playlistId); |
1270 | - query.bindValue(":track_id", trackId); |
1271 | - query.bindValue(":position", position); |
1272 | - |
1273 | - if (!query.exec()) { |
1274 | - LOG_FAILED_QUERY(query); |
1275 | + |
1276 | + |
1277 | + foreach (int trackId, trackIds) { |
1278 | + query.bindValue(":track_id", trackId); |
1279 | + query.bindValue(":position", position++); |
1280 | + if (!query.exec()) { |
1281 | + LOG_FAILED_QUERY(query); |
1282 | + } |
1283 | } |
1284 | |
1285 | // Commit the transaction |
1286 | m_database.commit(); |
1287 | |
1288 | - emit(trackAdded(playlistId, trackId, position)); |
1289 | + foreach (int trackId, trackIds) { |
1290 | + emit(trackAdded(playlistId, trackId, position)); |
1291 | + } |
1292 | emit(changed(playlistId)); |
1293 | } |
1294 | |
1295 | -/** Find out how many playlists exist. */ |
1296 | +void PlaylistDAO::appendTrackToPlaylist(int trackId, int playlistId) { |
1297 | + QList<int> tracks; |
1298 | + tracks.append(trackId); |
1299 | + appendTracksToPlaylist(tracks, playlistId); |
1300 | +} |
1301 | + |
1302 | unsigned int PlaylistDAO::playlistCount() |
1303 | { |
1304 | // qDebug() << "PlaylistDAO::playlistCount" << QThread::currentThread() << m_database.connectionName(); |
1305 | @@ -249,7 +251,7 @@ |
1306 | return numRecords; |
1307 | } |
1308 | |
1309 | -int PlaylistDAO::getPlaylistId(int position) |
1310 | +int PlaylistDAO::getPlaylistId(int index) |
1311 | { |
1312 | // qDebug() << "PlaylistDAO::getPlaylistId" |
1313 | // << QThread::currentThread() << m_database.connectionName(); |
1314 | @@ -257,37 +259,50 @@ |
1315 | QSqlQuery query(m_database); |
1316 | query.prepare("SELECT id FROM Playlists"); |
1317 | |
1318 | + if (!query.exec()) { |
1319 | + LOG_FAILED_QUERY(query); |
1320 | + return -1; |
1321 | + } |
1322 | + |
1323 | + int currentRow = 0; |
1324 | + while(query.next()) { |
1325 | + if (currentRow++ == index) { |
1326 | + int id = query.value(0).toInt(); |
1327 | + return id; |
1328 | + } |
1329 | + } |
1330 | + return -1; |
1331 | +} |
1332 | + |
1333 | +PlaylistDAO::HiddenType PlaylistDAO::getHiddenType(int playlistId) { |
1334 | + // qDebug() << "PlaylistDAO::getHiddenType" |
1335 | + // << QThread::currentThread() << m_database.connectionName(); |
1336 | + |
1337 | + QSqlQuery query(m_database); |
1338 | + query.prepare("SELECT hidden FROM Playlists WHERE id = :id"); |
1339 | + query.bindValue(":id", playlistId); |
1340 | + |
1341 | if (query.exec()) { |
1342 | - int currentRow = 0; |
1343 | - while(query.next()) { |
1344 | - if (currentRow++ == position) { |
1345 | - int id = query.value(0).toInt(); |
1346 | - return id; |
1347 | - } |
1348 | + if (query.next()) { |
1349 | + return static_cast<HiddenType>(query.value(0).toInt()); |
1350 | } |
1351 | } else { |
1352 | LOG_FAILED_QUERY(query); |
1353 | } |
1354 | - |
1355 | - return -1; |
1356 | + qDebug() << "PlaylistDAO::getHiddenType returns PLHT_UNKNOWN for playlistId " |
1357 | + << playlistId; |
1358 | + return PLHT_UNKNOWN; |
1359 | } |
1360 | |
1361 | bool PlaylistDAO::isHidden(int playlistId) { |
1362 | // qDebug() << "PlaylistDAO::isHidden" |
1363 | // << QThread::currentThread() << m_database.connectionName(); |
1364 | |
1365 | - QSqlQuery query(m_database); |
1366 | - query.prepare("SELECT hidden FROM Playlists WHERE id = :id"); |
1367 | - query.bindValue(":id", playlistId); |
1368 | - |
1369 | - if (query.exec()) { |
1370 | - if (query.next()) { |
1371 | - return query.value(0).toBool(); |
1372 | - } |
1373 | - } else { |
1374 | - LOG_FAILED_QUERY(query); |
1375 | + HiddenType ht = getHiddenType(playlistId); |
1376 | + if (ht == PLHT_NOT_HIDDEN) { |
1377 | + return false; |
1378 | } |
1379 | - return false; |
1380 | + return true; |
1381 | } |
1382 | |
1383 | void PlaylistDAO::removeTrackFromPlaylists(int trackId) { |
1384 | @@ -398,7 +413,7 @@ |
1385 | emit(changed(playlistId)); |
1386 | } |
1387 | |
1388 | -void PlaylistDAO::addToAutoDJQueue(int playlistId) { |
1389 | +void PlaylistDAO::addToAutoDJQueue(int playlistId, bool bTop) { |
1390 | //qDebug() << "Adding tracks from playlist " << playlistId << " to the Auto-DJ Queue"; |
1391 | |
1392 | // Query the PlaylistTracks database to locate tracks in the selected playlist |
1393 | @@ -408,12 +423,63 @@ |
1394 | query.bindValue(":plid", playlistId); |
1395 | if (!query.exec()) { |
1396 | LOG_FAILED_QUERY(query); |
1397 | + return; |
1398 | } |
1399 | |
1400 | // Get the ID of the Auto-DJ playlist |
1401 | int autoDJId = getPlaylistIdFromName(AUTODJ_TABLE); |
1402 | - // Loop through the tracks, adding them to the Auto-DJ Queue |
1403 | - while(query.next()) { |
1404 | - appendTrackToPlaylist(query.value(0).toInt(), autoDJId); |
1405 | - } |
1406 | + |
1407 | + // Loop through the tracks, adding them to the Auto-DJ Queue. Start at |
1408 | + // position 2 because position 1 was already loaded to the deck |
1409 | + int i = 2; |
1410 | + |
1411 | + while (query.next()) { |
1412 | + if (bTop) { |
1413 | + insertTrackIntoPlaylist(query.value(0).toInt(), autoDJId, i++); |
1414 | + } |
1415 | + else { |
1416 | + appendTrackToPlaylist(query.value(0).toInt(), autoDJId); |
1417 | + } |
1418 | + } |
1419 | +} |
1420 | + |
1421 | +int PlaylistDAO::getPreviousPlaylist(int currentPlaylistId, HiddenType hidden) { |
1422 | + // Find out the highest position existing in the playlist so we know what |
1423 | + // position this track should have. |
1424 | + QSqlQuery query(m_database); |
1425 | + query.prepare("SELECT max(id) as id FROM Playlists " |
1426 | + "WHERE id < :id AND hidden = :hidden"); |
1427 | + query.bindValue(":id", currentPlaylistId); |
1428 | + query.bindValue(":hidden", hidden); |
1429 | + |
1430 | + if (!query.exec()) { |
1431 | + LOG_FAILED_QUERY(query); |
1432 | + return -1; |
1433 | + } |
1434 | + |
1435 | + // Get the id of the highest playlist |
1436 | + int previousPlaylistId = -1; |
1437 | + if (query.next()) { |
1438 | + previousPlaylistId = query.value(query.record().indexOf("id")).toInt(); |
1439 | + } |
1440 | + return previousPlaylistId; |
1441 | +} |
1442 | + |
1443 | +void PlaylistDAO::copyPlaylistTracks(int sourcePlaylistID, int targetPlaylistId) { |
1444 | + // Query Tracks from the source Playlist |
1445 | + QSqlQuery query(m_database); |
1446 | + query.prepare("SELECT track_id FROM PlaylistTracks " |
1447 | + "WHERE playlist_id = :plid"); |
1448 | + query.bindValue(":plid", sourcePlaylistID); |
1449 | + |
1450 | + if (!query.exec()) { |
1451 | + LOG_FAILED_QUERY(query); |
1452 | + return; |
1453 | + } |
1454 | + |
1455 | + QList<int> trackIds; |
1456 | + while (query.next()) { |
1457 | + trackIds.append(query.value(0).toInt()); |
1458 | + } |
1459 | + appendTracksToPlaylist(trackIds, targetPlaylistId); |
1460 | } |
1461 | |
1462 | === modified file 'mixxx/src/library/dao/playlistdao.h' |
1463 | --- mixxx/src/library/dao/playlistdao.h 2011-10-21 00:42:23 +0000 |
1464 | +++ mixxx/src/library/dao/playlistdao.h 2012-03-12 04:25:21 +0000 |
1465 | @@ -13,17 +13,27 @@ |
1466 | const QString PLAYLISTTRACKSTABLE_TRACKID = "track_id"; |
1467 | const QString PLAYLISTTRACKSTABLE_POSITION = "position"; |
1468 | const QString PLAYLISTTRACKSTABLE_PLAYLISTID = "playlist_id"; |
1469 | +const QString PLAYLISTTRACKSTABLE_LOCATION = "location"; |
1470 | +const QString PLAYLISTTRACKSTABLE_ARTIST = "artist"; |
1471 | +const QString PLAYLISTTRACKSTABLE_TITLE = "title"; |
1472 | |
1473 | class PlaylistDAO : public QObject, public virtual DAO { |
1474 | Q_OBJECT |
1475 | public: |
1476 | + enum HiddenType { |
1477 | + PLHT_NOT_HIDDEN = 0, |
1478 | + PLHT_AUTO_DJ = 1, |
1479 | + PLHT_SET_LOG = 2, |
1480 | + PLHT_UNKNOWN = -1 |
1481 | + }; |
1482 | + |
1483 | PlaylistDAO(QSqlDatabase& database); |
1484 | virtual ~PlaylistDAO(); |
1485 | |
1486 | void initialize(); |
1487 | void setDatabase(QSqlDatabase& database) { m_database = database; }; |
1488 | /** Create a playlist */ |
1489 | - bool createPlaylist(QString name, bool hidden = false); |
1490 | + int createPlaylist(QString name, HiddenType type = PLHT_NOT_HIDDEN); |
1491 | /** Delete a playlist */ |
1492 | void deletePlaylist(int playlistId); |
1493 | /** Rename a playlist */ |
1494 | @@ -32,20 +42,24 @@ |
1495 | bool setPlaylistLocked(int playlistId, bool locked); |
1496 | /** Find out the state of a playlist lock */ |
1497 | bool isPlaylistLocked(int playlistId); |
1498 | - /** Append a track to a playlist */ |
1499 | + /** Append a list of tracks to a playlist */ |
1500 | + void appendTracksToPlaylist(QList<int> trackIds, int playlistId); |
1501 | + /** Append a track to a playlist */ |
1502 | void appendTrackToPlaylist(int trackId, int playlistId); |
1503 | /** Find out how many playlists exist. */ |
1504 | unsigned int playlistCount(); |
1505 | - /** Get the name of the playlist at the given position */ |
1506 | - QString getPlaylistName(unsigned int position); |
1507 | + /** Find out the name of the playlist at the given Id */ |
1508 | + QString getPlaylistName(int playlistId); |
1509 | // Get the playlist id by its name |
1510 | int getPlaylistIdFromName(QString name); |
1511 | - /** Get the id of the playlist at position. Note that the position is the |
1512 | - * natural position in the database table, not the display order position |
1513 | - * column stored in the database. */ |
1514 | - int getPlaylistId(int position); |
1515 | + // Get the id of the playlist at index. Note that the index is the natural |
1516 | + // position in the database table, not the display order position column |
1517 | + // stored in the database. |
1518 | + int getPlaylistId(int index); |
1519 | // Returns true if the playlist with playlistId is hidden |
1520 | bool isHidden(int playlistId); |
1521 | + // Returns the HiddenType of playlistId |
1522 | + HiddenType getHiddenType(int playlistId); |
1523 | /** Remove a track from all playlists */ |
1524 | void removeTrackFromPlaylists(int trackId); |
1525 | /** Remove a track from a playlist */ |
1526 | @@ -53,13 +67,20 @@ |
1527 | /** Insert a track into a specific position in a playlist */ |
1528 | void insertTrackIntoPlaylist(int trackId, int playlistId, int position); |
1529 | /** Add a playlist to the Auto-DJ Queue */ |
1530 | - void addToAutoDJQueue(int playlistId); |
1531 | + void addToAutoDJQueue(int playlistId, bool bTop); |
1532 | + // Get the preceding playlist of currentPlaylistId with the HiddenType |
1533 | + // hidden. Returns -1 if no such playlist exists. |
1534 | + int getPreviousPlaylist(int currentPlaylistId, HiddenType hidden); |
1535 | + // Append all the tracks in the source playlist to the target playlist. |
1536 | + void copyPlaylistTracks(int sourcePlaylistID, int targetPlaylistId); |
1537 | signals: |
1538 | void added(int playlistId); |
1539 | void deleted(int playlistId); |
1540 | void changed(int playlistId); |
1541 | void trackAdded(int playlistId, int trackId, int position); |
1542 | void trackRemoved(int playlistId, int trackId, int position); |
1543 | + void renamed(int playlistId); |
1544 | + void lockChanged(int playlistId); |
1545 | private: |
1546 | QSqlDatabase& m_database; |
1547 | DISALLOW_COPY_AND_ASSIGN(PlaylistDAO); |
1548 | |
1549 | === modified file 'mixxx/src/library/legacylibraryimporter.cpp' |
1550 | --- mixxx/src/library/legacylibraryimporter.cpp 2010-11-19 01:54:28 +0000 |
1551 | +++ mixxx/src/library/legacylibraryimporter.cpp 2012-03-12 04:25:21 +0000 |
1552 | @@ -148,8 +148,7 @@ |
1553 | |
1554 | //Create the playlist with the imported name. |
1555 | //qDebug() << "Importing playlist:" << current.name; |
1556 | - m_playlistDao.createPlaylist(current.name, false); |
1557 | - int playlistId = m_playlistDao.getPlaylistIdFromName(current.name); |
1558 | + int playlistId = m_playlistDao.createPlaylist(current.name); |
1559 | |
1560 | //For each track ID in the XML... |
1561 | QList<int> trackIDs = current.indexes; |
1562 | |
1563 | === modified file 'mixxx/src/library/library.cpp' |
1564 | --- mixxx/src/library/library.cpp 2011-09-25 06:39:39 +0000 |
1565 | +++ mixxx/src/library/library.cpp 2012-03-12 04:25:21 +0000 |
1566 | @@ -21,6 +21,7 @@ |
1567 | #include "library/promotracksfeature.h" |
1568 | #include "library/traktor/traktorfeature.h" |
1569 | #include "library/librarycontrol.h" |
1570 | +#include "library/setlogfeature.h" |
1571 | |
1572 | #include "widget/wtracktableview.h" |
1573 | #include "widget/wlibrary.h" |
1574 | @@ -60,6 +61,7 @@ |
1575 | addFeature(m_pCrateFeature); |
1576 | addFeature(new BrowseFeature(this, pConfig, m_pTrackCollection, m_pRecordingManager)); |
1577 | addFeature(new RecordingFeature(this, pConfig, m_pTrackCollection, m_pRecordingManager)); |
1578 | + addFeature(new SetlogFeature(this, pConfig, m_pTrackCollection)); |
1579 | addFeature(new PrepareFeature(this, pConfig, m_pTrackCollection)); |
1580 | //iTunes and Rhythmbox should be last until we no longer have an obnoxious |
1581 | //messagebox popup when you select them. (This forces you to reach for your |
1582 | @@ -141,7 +143,6 @@ |
1583 | ->select(m_pSidebarModel->getDefaultSelection(), |
1584 | QItemSelectionModel::SelectCurrent); |
1585 | m_pSidebarModel->activateDefaultSelection(); |
1586 | - |
1587 | } |
1588 | |
1589 | void Library::addFeature(LibraryFeature* feature) { |
1590 | |
1591 | === modified file 'mixxx/src/library/libraryfeature.h' |
1592 | --- mixxx/src/library/libraryfeature.h 2011-03-10 14:06:26 +0000 |
1593 | +++ mixxx/src/library/libraryfeature.h 2012-03-12 04:25:21 +0000 |
1594 | @@ -66,7 +66,8 @@ |
1595 | void featureIsLoading(LibraryFeature*); |
1596 | /** emit this signal if the foreign music collection has been imported/parsed. **/ |
1597 | void featureLoadingFinished(LibraryFeature*s); |
1598 | - |
1599 | + /** emit this signal to select pFeature **/ |
1600 | + void featureSelect(LibraryFeature* pFeature, const QModelIndex& index); |
1601 | |
1602 | }; |
1603 | |
1604 | |
1605 | === modified file 'mixxx/src/library/parser.cpp' |
1606 | --- mixxx/src/library/parser.cpp 2011-11-27 04:30:58 +0000 |
1607 | +++ mixxx/src/library/parser.cpp 2012-03-12 04:25:21 +0000 |
1608 | @@ -87,7 +87,7 @@ |
1609 | } |
1610 | |
1611 | const unsigned char* bytes = (const unsigned char *)string; |
1612 | - while(*bytes) { |
1613 | + while (*bytes) { |
1614 | if( (// ASCII |
1615 | bytes[0] == 0x09 || |
1616 | bytes[0] == 0x0A || |
1617 | |
1618 | === added file 'mixxx/src/library/parsercsv.cpp' |
1619 | --- mixxx/src/library/parsercsv.cpp 1970-01-01 00:00:00 +0000 |
1620 | +++ mixxx/src/library/parsercsv.cpp 2012-03-12 04:25:21 +0000 |
1621 | @@ -0,0 +1,233 @@ |
1622 | +// |
1623 | +// C++ Implementation: parsercsv |
1624 | +// |
1625 | +// Description: module to parse Comma-Separated Values (CSV) formated playlists (rfc4180) |
1626 | +// |
1627 | +// |
1628 | +// Author: Ingo Kossyk <kossyki@cs.tu-berlin.de>, (C) 2004 |
1629 | +// Author: Tobias Rafreider trafreider@mixxx.org, (C) 2011 |
1630 | +// Author: Daniel Schürmann daschuer@gmx.de, (C) 2011 |
1631 | +// |
1632 | +// Copyright: See COPYING file that comes with this distribution |
1633 | +// |
1634 | +// |
1635 | +#include <QTextStream> |
1636 | +#include <QDebug> |
1637 | +#include <QDir> |
1638 | +#include <QMessageBox> |
1639 | +#include <QUrl> |
1640 | + |
1641 | +#include "library/parsercsv.h" |
1642 | + |
1643 | +ParserCsv::ParserCsv() : Parser() { |
1644 | +} |
1645 | + |
1646 | +ParserCsv::~ParserCsv() { |
1647 | +} |
1648 | + |
1649 | +QList<QString> ParserCsv::parse(QString sFilename) { |
1650 | + QFile file(sFilename); |
1651 | + QString basepath = sFilename.section('/', 0, -2); |
1652 | + |
1653 | + clearLocations(); |
1654 | + //qDebug() << "ParserCsv: Starting to parse."; |
1655 | + if (file.open(QIODevice::ReadOnly) && !isBinary(sFilename)) { |
1656 | + QByteArray ba = file.readAll(); |
1657 | + |
1658 | + QList<QList<QString> > tokens = tokenize( ba, ','); |
1659 | + |
1660 | + // detect Location column |
1661 | + int loc_coll = 0x7fffffff; |
1662 | + if (tokens.size()) { |
1663 | + for (int i = 0; i < tokens[0].size(); ++i) { |
1664 | + if (tokens[0][i] == tr("Location")) { |
1665 | + loc_coll = i; |
1666 | + break; |
1667 | + } |
1668 | + } |
1669 | + for (int i = 1; i < tokens.size(); ++i) { |
1670 | + if (loc_coll < tokens[i].size()) { |
1671 | + // Todo: check if path is relative |
1672 | + QFileInfo fi = tokens[i][loc_coll]; |
1673 | + if (fi.isRelative()){ |
1674 | + // add base path |
1675 | + qDebug() << "is relative" << basepath << fi.filePath(); |
1676 | + fi.setFile(basepath,fi.filePath()); |
1677 | + } |
1678 | + m_sLocations.append(fi.filePath()); |
1679 | + } |
1680 | + } |
1681 | + } |
1682 | + |
1683 | + file.close(); |
1684 | + |
1685 | + if(m_sLocations.count() != 0) |
1686 | + return m_sLocations; |
1687 | + else |
1688 | + return QList<QString>(); // NULL pointer returned when no locations were found |
1689 | + |
1690 | + } |
1691 | + |
1692 | + file.close(); |
1693 | + return QList<QString>(); //if we get here something went wrong |
1694 | +} |
1695 | + |
1696 | +// Code was posted at http://www.qtcentre.org/threads/35511-Parsing-CSV-data |
1697 | +// by "adzajac" and adapted to use QT Classes |
1698 | +QList<QList<QString> > ParserCsv::tokenize(const QByteArray& str, char delimiter) { |
1699 | + QList<QList<QString> > tokens; |
1700 | + |
1701 | + unsigned int row = 0; |
1702 | + bool quotes = false; |
1703 | + QByteArray field = ""; |
1704 | + |
1705 | + tokens.append(QList<QString>()); |
1706 | + |
1707 | + for (int pos = 0; pos < str.length(); ++pos) { |
1708 | + char c = str[pos]; |
1709 | + if (!quotes && c == '"' ){ |
1710 | + quotes = true; |
1711 | + } else if (quotes && c== '"' ){ |
1712 | + if (pos + 1 < str.length() && str[pos+1]== '"') { |
1713 | + field.append(c); |
1714 | + pos++; |
1715 | + } else { |
1716 | + quotes = false; |
1717 | + } |
1718 | + } else if (!quotes && c == delimiter) { |
1719 | + if (isUtf8(field.data())) { |
1720 | + tokens[row].append(QString::fromUtf8(field)); |
1721 | + } else { |
1722 | + tokens[row].append(QString::fromLatin1(field)); |
1723 | + } |
1724 | + field.clear(); |
1725 | + } else if (!quotes && (c == '\r' || c == '\n')) { |
1726 | + if (isUtf8(field.data())) { |
1727 | + tokens[row].append(QString::fromUtf8(field)); |
1728 | + } else { |
1729 | + tokens[row].append(QString::fromLatin1(field)); |
1730 | + } |
1731 | + field.clear(); |
1732 | + tokens.append(QList<QString>()); |
1733 | + row++; |
1734 | + } else { |
1735 | + field.push_back(c); |
1736 | + } |
1737 | + } |
1738 | + return tokens; |
1739 | +} |
1740 | + |
1741 | +bool ParserCsv::writeCSVFile(const QString &file_str, BaseSqlTableModel* pPlaylistTableModel, bool useRelativePath) |
1742 | +{ |
1743 | + /* |
1744 | + * Important note: |
1745 | + * On Windows \n will produce a <CR><CL> (=\r\n) |
1746 | + * On Linux and OS X \n is <CR> (which remains \n) |
1747 | + */ |
1748 | + |
1749 | + QFile file(file_str); |
1750 | + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)){ |
1751 | + QMessageBox::warning(NULL,tr("Playlist Export Failed"), |
1752 | + tr("Could not create file")+" "+file_str); |
1753 | + return false; |
1754 | + } |
1755 | + //Base folder of file |
1756 | + QString base = file_str.section('/', 0, -2); |
1757 | + QDir base_dir(base); |
1758 | + |
1759 | + qDebug() << "Basepath: " << base; |
1760 | + QTextStream out(&file); |
1761 | + out.setCodec("UTF-8"); // rfc4180: Common usage of CSV is US-ASCII ... |
1762 | + // Using UTF-8 to get around codepage issues |
1763 | + // and it's the default encoding in Ooo Calc |
1764 | + |
1765 | + // writing header section |
1766 | + bool first = true; |
1767 | + int columns = pPlaylistTableModel->columnCount(); |
1768 | + for (int i = 0; i < columns; ++i) { |
1769 | + if (pPlaylistTableModel->isColumnInternal(i)) { |
1770 | + continue; |
1771 | + } |
1772 | + if (!first){ |
1773 | + out << ","; |
1774 | + } else { |
1775 | + first = false; |
1776 | + } |
1777 | + out << "\""; |
1778 | + QString field = pPlaylistTableModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString(); |
1779 | + out << field.replace('\"', "\"\""); // escape " |
1780 | + out << "\""; |
1781 | + } |
1782 | + out << "\r\n"; // CRLF according to rfc4180 |
1783 | + |
1784 | + |
1785 | + int rows = pPlaylistTableModel->rowCount(); |
1786 | + for (int j = 0; j < rows; j++) { |
1787 | + // writing fields section |
1788 | + first = true; |
1789 | + for(int i = 0; i < columns; ++i){ |
1790 | + if (pPlaylistTableModel->isColumnInternal(i)) { |
1791 | + continue; |
1792 | + } |
1793 | + if (!first){ |
1794 | + out << ","; |
1795 | + } else { |
1796 | + first = false; |
1797 | + } |
1798 | + out << "\""; |
1799 | + QString field = pPlaylistTableModel->data(pPlaylistTableModel->index(j,i)).toString(); |
1800 | + if (useRelativePath && i == pPlaylistTableModel->fieldIndex(PLAYLISTTRACKSTABLE_LOCATION)) { |
1801 | + field = base_dir.relativeFilePath(field); |
1802 | + } |
1803 | + out << field.replace('\"', "\"\""); // escape " |
1804 | + out << "\""; |
1805 | + } |
1806 | + out << "\r\n"; // CRLF according to rfc4180 |
1807 | + } |
1808 | + return true; |
1809 | +} |
1810 | + |
1811 | +bool ParserCsv::writeReadableTextFile(const QString &file_str, BaseSqlTableModel* pPlaylistTableModel) |
1812 | +{ |
1813 | + /* |
1814 | + * Important note: |
1815 | + * On Windows \n will produce a <CR><CL> (=\r\n) |
1816 | + * On Linux and OS X \n is <CR> (which remains \n) |
1817 | + */ |
1818 | + |
1819 | + QFile file(file_str); |
1820 | + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)){ |
1821 | + QMessageBox::warning(NULL,tr("Readable text Export Failed"), |
1822 | + tr("Could not create file")+" "+file_str); |
1823 | + return false; |
1824 | + } |
1825 | + |
1826 | + QTextStream out(&file); |
1827 | + |
1828 | + // export each row as "01. 00:00 Artist - Title" |
1829 | + |
1830 | + int i; // fieldIndex |
1831 | + int rows = pPlaylistTableModel->rowCount(); |
1832 | + for (int j = 0; j < rows; j++) { |
1833 | + // writing fields section |
1834 | + i = pPlaylistTableModel->fieldIndex(PLAYLISTTRACKSTABLE_POSITION); |
1835 | + if (i >= 0){ |
1836 | + int nr = pPlaylistTableModel->data(pPlaylistTableModel->index(j,i)).toInt(); |
1837 | + out << QString("%1.").arg(nr,2,10,QLatin1Char('0')); |
1838 | + } |
1839 | + // TODO(DSC) // Fill in Cue point |
1840 | + |
1841 | + i = pPlaylistTableModel->fieldIndex(PLAYLISTTRACKSTABLE_ARTIST); |
1842 | + if (i >= 0){ |
1843 | + out << " "; |
1844 | + out << pPlaylistTableModel->data(pPlaylistTableModel->index(j,i)).toString(); |
1845 | + } |
1846 | + i = pPlaylistTableModel->fieldIndex(PLAYLISTTRACKSTABLE_TITLE); |
1847 | + if (i >= 0){ |
1848 | + out << " - "; |
1849 | + out << pPlaylistTableModel->data(pPlaylistTableModel->index(j,i)).toString();; |
1850 | + } |
1851 | + out << "\n"; |
1852 | + } |
1853 | + return true; |
1854 | +} |
1855 | |
1856 | === added file 'mixxx/src/library/parsercsv.h' |
1857 | --- mixxx/src/library/parsercsv.h 1970-01-01 00:00:00 +0000 |
1858 | +++ mixxx/src/library/parsercsv.h 2012-03-12 04:25:21 +0000 |
1859 | @@ -0,0 +1,41 @@ |
1860 | +// |
1861 | +// C++ Interface: parserm3u |
1862 | +// |
1863 | +// Description: Interface header parse Comma-Separated Values (CSV) formated playlists (rfc4180) |
1864 | +// |
1865 | +// |
1866 | +// Author: Ingo Kossyk <kossyki@cs.tu-berlin.de>, (C) 2004 |
1867 | +// Author: Tobias Rafreider trafreider@mixxx.org, (C) 2011 |
1868 | +// Author: Daniel Schürmann daschuer@gmx.de, (C) 2011 |
1869 | +// |
1870 | +// Copyright: See COPYING file that comes with this distribution |
1871 | +// |
1872 | +// |
1873 | +#include "library/parser.h" |
1874 | +#include "library/basesqltablemodel.h" |
1875 | + |
1876 | +#ifndef PARSERCSV_H |
1877 | +#define PARSERCSV_H |
1878 | + |
1879 | +class QTextStream; |
1880 | + |
1881 | +class ParserCsv : public Parser |
1882 | +{ |
1883 | + Q_OBJECT |
1884 | +public: |
1885 | + ParserCsv(); |
1886 | + virtual ~ParserCsv(); |
1887 | + /**Overwriting function parse in class Parser**/ |
1888 | + QList<QString> parse(QString); |
1889 | + // Playlist Export |
1890 | + static bool writeCSVFile(const QString &file, BaseSqlTableModel* pPlaylistTableModel, bool useRelativePath); |
1891 | + // Readable Text export |
1892 | + static bool writeReadableTextFile(const QString &file, BaseSqlTableModel* pPlaylistTableModel); |
1893 | +private: |
1894 | + /**Reads a line from the file and returns filepath if a valid file**/ |
1895 | + QList<QList<QString> > tokenize(const QByteArray& str, char delimiter); |
1896 | + |
1897 | + |
1898 | +}; |
1899 | + |
1900 | +#endif |
1901 | |
1902 | === modified file 'mixxx/src/library/playlistfeature.cpp' |
1903 | --- mixxx/src/library/playlistfeature.cpp 2011-11-30 05:27:44 +0000 |
1904 | +++ mixxx/src/library/playlistfeature.cpp 2012-03-12 04:25:21 +0000 |
1905 | @@ -8,7 +8,7 @@ |
1906 | #include "library/parser.h" |
1907 | #include "library/parserm3u.h" |
1908 | #include "library/parserpls.h" |
1909 | - |
1910 | +#include "library/parsercsv.h" |
1911 | |
1912 | #include "widget/wlibrary.h" |
1913 | #include "widget/wlibrarysidebar.h" |
1914 | @@ -22,42 +22,10 @@ |
1915 | PlaylistFeature::PlaylistFeature(QObject* parent, |
1916 | TrackCollection* pTrackCollection, |
1917 | ConfigObject<ConfigValue>* pConfig) |
1918 | - : LibraryFeature(parent), |
1919 | - m_pTrackCollection(pTrackCollection), |
1920 | - m_playlistDao(pTrackCollection->getPlaylistDAO()), |
1921 | - m_trackDao(pTrackCollection->getTrackDAO()), |
1922 | - m_pConfig(pConfig), |
1923 | - m_playlistTableModel(this, pTrackCollection->getDatabase()) { |
1924 | + : BasePlaylistFeature(parent, pConfig, pTrackCollection, |
1925 | + "PLAYLISTHOME", "qrc:/html/playlists.html") { |
1926 | m_pPlaylistTableModel = new PlaylistTableModel(this, pTrackCollection, |
1927 | "mixxx.db.model.playlist"); |
1928 | - |
1929 | - m_pCreatePlaylistAction = new QAction(tr("New Playlist"),this); |
1930 | - connect(m_pCreatePlaylistAction, SIGNAL(triggered()), |
1931 | - this, SLOT(slotCreatePlaylist())); |
1932 | - |
1933 | - m_pAddToAutoDJAction = new QAction(tr("Add to Auto-DJ Queue"),this); |
1934 | - connect(m_pAddToAutoDJAction, SIGNAL(triggered()), |
1935 | - this, SLOT(slotAddToAutoDJ())); |
1936 | - |
1937 | - m_pDeletePlaylistAction = new QAction(tr("Remove"),this); |
1938 | - connect(m_pDeletePlaylistAction, SIGNAL(triggered()), |
1939 | - this, SLOT(slotDeletePlaylist())); |
1940 | - |
1941 | - m_pRenamePlaylistAction = new QAction(tr("Rename"),this); |
1942 | - connect(m_pRenamePlaylistAction, SIGNAL(triggered()), |
1943 | - this, SLOT(slotRenamePlaylist())); |
1944 | - |
1945 | - m_pLockPlaylistAction = new QAction(tr("Lock"),this); |
1946 | - connect(m_pLockPlaylistAction, SIGNAL(triggered()), |
1947 | - this, SLOT(slotTogglePlaylistLock())); |
1948 | - |
1949 | - m_pImportPlaylistAction = new QAction(tr("Import Playlist"),this); |
1950 | - connect(m_pImportPlaylistAction, SIGNAL(triggered()), |
1951 | - this, SLOT(slotImportPlaylist())); |
1952 | - m_pExportPlaylistAction = new QAction(tr("Export Playlist"), this); |
1953 | - connect(m_pExportPlaylistAction, SIGNAL(triggered()), |
1954 | - this, SLOT(slotExportPlaylist())); |
1955 | - |
1956 | // Setup the sidebar playlist model |
1957 | m_playlistTableModel.setTable("Playlists"); |
1958 | m_playlistTableModel.setFilter("hidden=0"); |
1959 | @@ -68,17 +36,10 @@ |
1960 | //construct child model |
1961 | TreeItem *rootItem = new TreeItem(); |
1962 | m_childModel.setRootItem(rootItem); |
1963 | - constructChildModel(); |
1964 | + constructChildModel(-1); |
1965 | } |
1966 | |
1967 | PlaylistFeature::~PlaylistFeature() { |
1968 | - delete m_pPlaylistTableModel; |
1969 | - delete m_pCreatePlaylistAction; |
1970 | - delete m_pDeletePlaylistAction; |
1971 | - delete m_pImportPlaylistAction; |
1972 | - delete m_pAddToAutoDJAction; |
1973 | - delete m_pRenamePlaylistAction; |
1974 | - delete m_pLockPlaylistAction; |
1975 | } |
1976 | |
1977 | QVariant PlaylistFeature::title() { |
1978 | @@ -89,31 +50,6 @@ |
1979 | return QIcon(":/images/library/ic_library_playlist.png"); |
1980 | } |
1981 | |
1982 | - |
1983 | -void PlaylistFeature::bindWidget(WLibrarySidebar* sidebarWidget, |
1984 | - WLibrary* libraryWidget, |
1985 | - MixxxKeyboard* keyboard) { |
1986 | - WLibraryTextBrowser* edit = new WLibraryTextBrowser(libraryWidget); |
1987 | - connect(this, SIGNAL(showPage(const QUrl&)), |
1988 | - edit, SLOT(setSource(const QUrl&))); |
1989 | - libraryWidget->registerView("PLAYLISTHOME", edit); |
1990 | -} |
1991 | - |
1992 | -void PlaylistFeature::activate() { |
1993 | - emit(showPage(QUrl("qrc:/html/playlists.html"))); |
1994 | - emit(switchToView("PLAYLISTHOME")); |
1995 | -} |
1996 | - |
1997 | -void PlaylistFeature::activateChild(const QModelIndex& index) { |
1998 | - //qDebug() << "PlaylistFeature::activateChild()" << index; |
1999 | - |
2000 | - //Switch the playlist table model's playlist. |
2001 | - QString playlistName = index.data().toString(); |
2002 | - int playlistId = m_playlistDao.getPlaylistIdFromName(playlistName); |
2003 | - m_pPlaylistTableModel->setPlaylist(playlistId); |
2004 | - emit(showTrackModel(m_pPlaylistTableModel)); |
2005 | -} |
2006 | - |
2007 | void PlaylistFeature::onRightClick(const QPoint& globalPos) { |
2008 | m_lastRightClickedIndex = QModelIndex(); |
2009 | |
2010 | @@ -142,6 +78,7 @@ |
2011 | menu.addAction(m_pCreatePlaylistAction); |
2012 | menu.addSeparator(); |
2013 | menu.addAction(m_pAddToAutoDJAction); |
2014 | + menu.addAction(m_pAddToAutoDJTopAction); |
2015 | menu.addAction(m_pRenamePlaylistAction); |
2016 | menu.addAction(m_pDeletePlaylistAction); |
2017 | menu.addAction(m_pLockPlaylistAction); |
2018 | @@ -151,156 +88,6 @@ |
2019 | menu.exec(globalPos); |
2020 | } |
2021 | |
2022 | -void PlaylistFeature::slotCreatePlaylist() { |
2023 | - QString name; |
2024 | - bool validNameGiven = false; |
2025 | - |
2026 | - do { |
2027 | - bool ok = false; |
2028 | - name = QInputDialog::getText(NULL, |
2029 | - tr("New Playlist"), |
2030 | - tr("Playlist name:"), |
2031 | - QLineEdit::Normal, |
2032 | - tr("New Playlist"), |
2033 | - &ok).trimmed(); |
2034 | - |
2035 | - if (!ok) |
2036 | - return; |
2037 | - |
2038 | - int existingId = m_playlistDao.getPlaylistIdFromName(name); |
2039 | - |
2040 | - if (existingId != -1) { |
2041 | - QMessageBox::warning(NULL, |
2042 | - tr("Playlist Creation Failed"), |
2043 | - tr("A playlist by that name already exists.")); |
2044 | - } else if (name.isEmpty()) { |
2045 | - QMessageBox::warning(NULL, |
2046 | - tr("Playlist Creation Failed"), |
2047 | - tr("A playlist cannot have a blank name.")); |
2048 | - } else { |
2049 | - validNameGiven = true; |
2050 | - } |
2051 | - |
2052 | - } while (!validNameGiven); |
2053 | - |
2054 | - bool playlistCreated = m_playlistDao.createPlaylist(name); |
2055 | - |
2056 | - if (playlistCreated) { |
2057 | - clearChildModel(); |
2058 | - m_playlistTableModel.select(); |
2059 | - constructChildModel(); |
2060 | - emit(featureUpdated()); |
2061 | - //Switch the view to the new playlist. |
2062 | - int playlistId = m_playlistDao.getPlaylistIdFromName(name); |
2063 | - m_pPlaylistTableModel->setPlaylist(playlistId); |
2064 | - // TODO(XXX) set sidebar selection |
2065 | - emit(showTrackModel(m_pPlaylistTableModel)); |
2066 | - } |
2067 | - else { |
2068 | - QMessageBox::warning(NULL, |
2069 | - tr("Playlist Creation Failed"), |
2070 | - tr("An unknown error occurred while creating playlist: ") |
2071 | - + name); |
2072 | - } |
2073 | -} |
2074 | - |
2075 | -void PlaylistFeature::slotRenamePlaylist() |
2076 | -{ |
2077 | - qDebug() << "slotRenamePlaylist()"; |
2078 | - |
2079 | - QString oldName = m_lastRightClickedIndex.data().toString(); |
2080 | - int playlistId = m_playlistDao.getPlaylistIdFromName(oldName); |
2081 | - bool locked = m_playlistDao.isPlaylistLocked(playlistId); |
2082 | - |
2083 | - if (locked) { |
2084 | - qDebug() << "Skipping playlist rename because playlist" << playlistId << "is locked."; |
2085 | - return; |
2086 | - } |
2087 | - |
2088 | - QString newName; |
2089 | - bool validNameGiven = false; |
2090 | - |
2091 | - do { |
2092 | - bool ok = false; |
2093 | - newName = QInputDialog::getText(NULL, |
2094 | - tr("Rename Playlist"), |
2095 | - tr("New playlist name:"), |
2096 | - QLineEdit::Normal, |
2097 | - oldName, |
2098 | - &ok).trimmed(); |
2099 | - |
2100 | - if (!ok || oldName == newName) { |
2101 | - return; |
2102 | - } |
2103 | - |
2104 | - int existingId = m_playlistDao.getPlaylistIdFromName(newName); |
2105 | - |
2106 | - if (existingId != -1) { |
2107 | - QMessageBox::warning(NULL, |
2108 | - tr("Renaming Playlist Failed"), |
2109 | - tr("A playlist by that name already exists.")); |
2110 | - } |
2111 | - else if (newName.isEmpty()) { |
2112 | - QMessageBox::warning(NULL, |
2113 | - tr("Renaming Playlist Failed"), |
2114 | - tr("A playlist cannot have a blank name.")); |
2115 | - } |
2116 | - else { |
2117 | - validNameGiven = true; |
2118 | - } |
2119 | - } while (!validNameGiven); |
2120 | - |
2121 | - m_playlistDao.renamePlaylist(playlistId, newName); |
2122 | - clearChildModel(); |
2123 | - m_playlistTableModel.select(); |
2124 | - constructChildModel(); |
2125 | - emit(featureUpdated()); |
2126 | - m_pPlaylistTableModel->setPlaylist(playlistId); |
2127 | -} |
2128 | - |
2129 | - |
2130 | -void PlaylistFeature::slotTogglePlaylistLock() |
2131 | -{ |
2132 | - QString playlistName = m_lastRightClickedIndex.data().toString(); |
2133 | - int playlistId = m_playlistDao.getPlaylistIdFromName(playlistName); |
2134 | - bool locked = !m_playlistDao.isPlaylistLocked(playlistId); |
2135 | - |
2136 | - if (!m_playlistDao.setPlaylistLocked(playlistId, locked)) { |
2137 | - qDebug() << "Failed to toggle lock of playlistId " << playlistId; |
2138 | - } |
2139 | - |
2140 | - TreeItem* playlistItem = m_childModel.getItem(m_lastRightClickedIndex); |
2141 | - playlistItem->setIcon(locked ? QIcon(":/images/library/ic_library_locked.png") : QIcon()); |
2142 | -} |
2143 | - |
2144 | -void PlaylistFeature::slotDeletePlaylist() |
2145 | -{ |
2146 | - //qDebug() << "slotDeletePlaylist() row:" << m_lastRightClickedIndex.data(); |
2147 | - int playlistId = m_playlistDao.getPlaylistIdFromName(m_lastRightClickedIndex.data().toString()); |
2148 | - bool locked = m_playlistDao.isPlaylistLocked(playlistId); |
2149 | - |
2150 | - if (locked) { |
2151 | - qDebug() << "Skipping playlist deletion because playlist" << playlistId << "is locked."; |
2152 | - return; |
2153 | - } |
2154 | - |
2155 | - if (m_lastRightClickedIndex.isValid() && |
2156 | - !m_playlistDao.isPlaylistLocked(playlistId)) { |
2157 | - Q_ASSERT(playlistId >= 0); |
2158 | - |
2159 | - clearChildModel(); |
2160 | - m_playlistDao.deletePlaylist(playlistId); |
2161 | - m_playlistTableModel.select(); |
2162 | - constructChildModel(); |
2163 | - emit(featureUpdated()); |
2164 | - } |
2165 | - |
2166 | -} |
2167 | - |
2168 | -bool PlaylistFeature::dropAccept(QUrl url) { |
2169 | - return false; |
2170 | -} |
2171 | - |
2172 | bool PlaylistFeature::dropAcceptChild(const QModelIndex& index, QUrl url) { |
2173 | //TODO: Filter by supported formats regex and reject anything that doesn't match. |
2174 | QString playlistName = index.data().toString(); |
2175 | @@ -333,10 +120,6 @@ |
2176 | return true; |
2177 | } |
2178 | |
2179 | -bool PlaylistFeature::dragMoveAccept(QUrl url) { |
2180 | - return false; |
2181 | -} |
2182 | - |
2183 | bool PlaylistFeature::dragMoveAcceptChild(const QModelIndex& index, QUrl url) { |
2184 | //TODO: Filter by supported formats regex and reject anything that doesn't match. |
2185 | |
2186 | @@ -349,23 +132,21 @@ |
2187 | return !locked && formatSupported; |
2188 | } |
2189 | |
2190 | -TreeItemModel* PlaylistFeature::getChildModel() { |
2191 | - return &m_childModel; |
2192 | -} |
2193 | + |
2194 | /** |
2195 | * Purpose: When inserting or removing playlists, |
2196 | * we require the sidebar model not to reset. |
2197 | * This method queries the database and does dynamic insertion |
2198 | */ |
2199 | -void PlaylistFeature::constructChildModel() |
2200 | +QModelIndex PlaylistFeature::constructChildModel(int selected_id) |
2201 | { |
2202 | QList<TreeItem*> data_list; |
2203 | int nameColumn = m_playlistTableModel.record().indexOf("name"); |
2204 | int idColumn = m_playlistTableModel.record().indexOf("id"); |
2205 | - |
2206 | - //Access the invisible root item |
2207 | + int selected_row = -1; |
2208 | + // Access the invisible root item |
2209 | TreeItem* root = m_childModel.getItem(QModelIndex()); |
2210 | - //Create new TreeItems for the playlists in the database |
2211 | + // Create new TreeItems for the playlists in the database |
2212 | for (int row = 0; row < m_playlistTableModel.rowCount(); ++row) { |
2213 | QModelIndex ind = m_playlistTableModel.index(row, nameColumn); |
2214 | QString playlist_name = m_playlistTableModel.data(ind).toString(); |
2215 | @@ -373,121 +154,23 @@ |
2216 | int playlist_id = m_playlistTableModel.data(ind).toInt(); |
2217 | bool locked = m_playlistDao.isPlaylistLocked(playlist_id); |
2218 | |
2219 | - //Create the TreeItem whose parent is the invisible root item |
2220 | + if (selected_id == playlist_id) { |
2221 | + // save index for selection |
2222 | + selected_row = row; |
2223 | + } |
2224 | + |
2225 | + // Create the TreeItem whose parent is the invisible root item |
2226 | TreeItem* item = new TreeItem(playlist_name, playlist_name, this, root); |
2227 | item->setIcon(locked ? QIcon(":/images/library/ic_library_locked.png") : QIcon()); |
2228 | data_list.append(item); |
2229 | } |
2230 | |
2231 | - //Append all the newly created TreeItems in a dynamic way to the childmodel |
2232 | + // Append all the newly created TreeItems in a dynamic way to the childmodel |
2233 | m_childModel.insertRows(data_list, 0, m_playlistTableModel.rowCount()); |
2234 | -} |
2235 | - |
2236 | -/** |
2237 | - * Clears the child model dynamically, but the invisible root item remains |
2238 | - */ |
2239 | -void PlaylistFeature::clearChildModel() |
2240 | -{ |
2241 | - m_childModel.removeRows(0,m_playlistTableModel.rowCount()); |
2242 | -} |
2243 | -void PlaylistFeature::slotImportPlaylist() |
2244 | -{ |
2245 | - qDebug() << "slotImportPlaylist() row:" ; //<< m_lastRightClickedIndex.data(); |
2246 | - |
2247 | - QString playlist_file = QFileDialog::getOpenFileName( |
2248 | - NULL, |
2249 | - tr("Import Playlist"), |
2250 | - QDesktopServices::storageLocation(QDesktopServices::MusicLocation), |
2251 | - tr("Playlist Files (*.m3u *.m3u8 *.pls)")); |
2252 | - // Exit method if user cancelled the open dialog. |
2253 | - if (playlist_file.isNull() || playlist_file.isEmpty()) { |
2254 | - return; |
2255 | - } |
2256 | - |
2257 | - Parser* playlist_parser = NULL; |
2258 | - |
2259 | - if (playlist_file.endsWith(".m3u", Qt::CaseInsensitive) || |
2260 | - playlist_file.endsWith(".m3u8", Qt::CaseInsensitive)) { |
2261 | - playlist_parser = new ParserM3u(); |
2262 | - } else if (playlist_file.endsWith(".pls", Qt::CaseInsensitive)) { |
2263 | - playlist_parser = new ParserPls(); |
2264 | - } else { |
2265 | - return; |
2266 | - } |
2267 | - QList<QString> entries = playlist_parser->parse(playlist_file); |
2268 | - |
2269 | - // Iterate over the List that holds URLs of playlist entires |
2270 | - for (int i = 0; i < entries.size(); ++i) { |
2271 | - m_pPlaylistTableModel->addTrack(QModelIndex(), entries[i]); |
2272 | - } |
2273 | - |
2274 | - // delete the parser object |
2275 | - if (playlist_parser) { |
2276 | - delete playlist_parser; |
2277 | - } |
2278 | -} |
2279 | -void PlaylistFeature::onLazyChildExpandation(const QModelIndex &index){ |
2280 | - //Nothing to do because the childmodel is not of lazy nature. |
2281 | -} |
2282 | - |
2283 | -void PlaylistFeature::slotExportPlaylist(){ |
2284 | - qDebug() << "Export playlist" << m_lastRightClickedIndex.data(); |
2285 | - QString file_location = QFileDialog::getSaveFileName( |
2286 | - NULL, |
2287 | - tr("Export Playlist"), |
2288 | - QDesktopServices::storageLocation(QDesktopServices::MusicLocation), |
2289 | - tr("M3U Playlist (*.m3u);;M3U8 Playlist (*.m3u8);;PLS Playlist (*.pls)")); |
2290 | - // Exit method if user cancelled the open dialog. |
2291 | - if (file_location.isNull() || file_location.isEmpty()) { |
2292 | - return; |
2293 | - } |
2294 | - // Create and populate a list of files of the playlist |
2295 | - QList<QString> playlist_items; |
2296 | - // Create a new table model since the main one might have an active search. |
2297 | - QScopedPointer<PlaylistTableModel> pPlaylistTableModel( |
2298 | - new PlaylistTableModel(this, m_pTrackCollection, |
2299 | - "mixxx.db.model.playlist_export")); |
2300 | - |
2301 | - pPlaylistTableModel->setPlaylist(m_pPlaylistTableModel->getPlaylist()); |
2302 | - pPlaylistTableModel->setSort(0, Qt::AscendingOrder); |
2303 | - pPlaylistTableModel->select(); |
2304 | - int rows = pPlaylistTableModel->rowCount(); |
2305 | - for (int i = 0; i < rows; ++i) { |
2306 | - QModelIndex index = pPlaylistTableModel->index(i, 0); |
2307 | - playlist_items << pPlaylistTableModel->getTrackLocation(index); |
2308 | - } |
2309 | - |
2310 | - // check config if relative paths are desired |
2311 | - bool useRelativePath = static_cast<bool>(m_pConfig->getValueString( |
2312 | - ConfigKey("[Library]", "UseRelativePathOnExport")).toInt()); |
2313 | - |
2314 | - if (file_location.endsWith(".m3u", Qt::CaseInsensitive)) { |
2315 | - ParserM3u::writeM3UFile(file_location, playlist_items, useRelativePath); |
2316 | - } else if (file_location.endsWith(".pls", Qt::CaseInsensitive)) { |
2317 | - ParserPls::writePLSFile(file_location,playlist_items, |
2318 | - useRelativePath); |
2319 | - } else if (file_location.endsWith(".m3u8", Qt::CaseInsensitive)) { |
2320 | - ParserM3u::writeM3U8File(file_location, playlist_items, |
2321 | - useRelativePath); |
2322 | - } else { |
2323 | - //default export to M3U if file extension is missing |
2324 | - |
2325 | - qDebug() << "Playlist export: No file extension specified. Appending .m3u " |
2326 | - << "and exporting to M3U."; |
2327 | - file_location.append(".m3u"); |
2328 | - ParserM3u::writeM3UFile(file_location, playlist_items, useRelativePath); |
2329 | - } |
2330 | -} |
2331 | - |
2332 | -void PlaylistFeature::slotAddToAutoDJ() { |
2333 | - //qDebug() << "slotAddToAutoDJ() row:" << m_lastRightClickedIndex.data(); |
2334 | - |
2335 | - if (m_lastRightClickedIndex.isValid()) { |
2336 | - int playlistId = m_playlistDao.getPlaylistIdFromName( |
2337 | - m_lastRightClickedIndex.data().toString()); |
2338 | - if (playlistId >= 0) { |
2339 | - m_playlistDao.addToAutoDJQueue(playlistId); |
2340 | - } |
2341 | - } |
2342 | - emit(featureUpdated()); |
2343 | -} |
2344 | + if (selected_row == -1) { |
2345 | + return QModelIndex(); |
2346 | + } |
2347 | + return m_childModel.index(selected_row, 0); |
2348 | +} |
2349 | + |
2350 | + |
2351 | |
2352 | === modified file 'mixxx/src/library/playlistfeature.h' |
2353 | --- mixxx/src/library/playlistfeature.h 2011-11-27 06:59:02 +0000 |
2354 | +++ mixxx/src/library/playlistfeature.h 2012-03-12 04:25:21 +0000 |
2355 | @@ -5,76 +5,31 @@ |
2356 | #define PLAYLISTFEATURE_H |
2357 | |
2358 | #include <QSqlTableModel> |
2359 | -#include <QAction> |
2360 | -#include <QList> |
2361 | |
2362 | -#include "library/libraryfeature.h" |
2363 | -#include "library/dao/playlistdao.h" |
2364 | -#include "library/dao/trackdao.h" |
2365 | -#include "treeitemmodel.h" |
2366 | +#include "library/baseplaylistfeature.h" |
2367 | #include "configobject.h" |
2368 | |
2369 | - |
2370 | -class PlaylistTableModel; |
2371 | class TrackCollection; |
2372 | |
2373 | -class PlaylistFeature : public LibraryFeature { |
2374 | +class PlaylistFeature : public BasePlaylistFeature { |
2375 | Q_OBJECT |
2376 | -public: |
2377 | - PlaylistFeature(QObject* parent, TrackCollection* pTrackCollection, ConfigObject<ConfigValue>* pConfig); |
2378 | + public: |
2379 | + PlaylistFeature(QObject* parent, TrackCollection* pTrackCollection, |
2380 | + ConfigObject<ConfigValue>* pConfig); |
2381 | virtual ~PlaylistFeature(); |
2382 | |
2383 | QVariant title(); |
2384 | QIcon getIcon(); |
2385 | |
2386 | - bool dropAccept(QUrl url); |
2387 | bool dropAcceptChild(const QModelIndex& index, QUrl url); |
2388 | - bool dragMoveAccept(QUrl url); |
2389 | bool dragMoveAcceptChild(const QModelIndex& index, QUrl url); |
2390 | |
2391 | - TreeItemModel* getChildModel(); |
2392 | - |
2393 | - void bindWidget(WLibrarySidebar* sidebarWidget, |
2394 | - WLibrary* libraryWidget, |
2395 | - MixxxKeyboard* keyboard); |
2396 | - signals: |
2397 | - void showPage(const QUrl& page); |
2398 | - |
2399 | -public slots: |
2400 | - void activate(); |
2401 | - void activateChild(const QModelIndex& index); |
2402 | + public slots: |
2403 | void onRightClick(const QPoint& globalPos); |
2404 | void onRightClickChild(const QPoint& globalPos, QModelIndex index); |
2405 | - void onLazyChildExpandation(const QModelIndex& index); |
2406 | - |
2407 | - void slotCreatePlaylist(); |
2408 | - void slotDeletePlaylist(); |
2409 | - void slotAddToAutoDJ(); |
2410 | - void slotRenamePlaylist(); |
2411 | - void slotTogglePlaylistLock(); |
2412 | - void slotImportPlaylist(); |
2413 | - void slotExportPlaylist(); |
2414 | - |
2415 | - |
2416 | - private: |
2417 | - void constructChildModel(); |
2418 | - void clearChildModel(); |
2419 | - |
2420 | - TrackCollection* m_pTrackCollection; |
2421 | - PlaylistTableModel* m_pPlaylistTableModel; |
2422 | - PlaylistDAO &m_playlistDao; |
2423 | - TrackDAO &m_trackDao; |
2424 | - QAction *m_pCreatePlaylistAction; |
2425 | - QAction *m_pDeletePlaylistAction; |
2426 | - QAction *m_pAddToAutoDJAction; |
2427 | - QAction *m_pRenamePlaylistAction; |
2428 | - QAction *m_pLockPlaylistAction; |
2429 | - QAction *m_pImportPlaylistAction; |
2430 | - QAction *m_pExportPlaylistAction; |
2431 | - QSqlTableModel m_playlistTableModel; |
2432 | - QModelIndex m_lastRightClickedIndex; |
2433 | - TreeItemModel m_childModel; |
2434 | - ConfigObject<ConfigValue>* m_pConfig; |
2435 | + |
2436 | + protected: |
2437 | + QModelIndex constructChildModel(int selected_id); |
2438 | }; |
2439 | |
2440 | #endif /* PLAYLISTFEATURE_H */ |
2441 | |
2442 | === modified file 'mixxx/src/library/playlisttablemodel.cpp' |
2443 | --- mixxx/src/library/playlisttablemodel.cpp 2011-12-18 20:23:14 +0000 |
2444 | +++ mixxx/src/library/playlisttablemodel.cpp 2012-03-12 04:25:21 +0000 |
2445 | @@ -94,6 +94,17 @@ |
2446 | return true; |
2447 | } |
2448 | |
2449 | +bool PlaylistTableModel::appendTrack(int trackId) { |
2450 | + if (trackId < 0) { |
2451 | + return false; |
2452 | + } |
2453 | + |
2454 | + m_playlistDao.appendTrackToPlaylist(trackId, m_iPlaylistId); |
2455 | + |
2456 | + select(); //Repopulate the data model. |
2457 | + return true; |
2458 | +} |
2459 | + |
2460 | TrackPointer PlaylistTableModel::getTrack(const QModelIndex& index) const { |
2461 | //FIXME: use position instead of location for playlist tracks? |
2462 | |
2463 | @@ -256,7 +267,7 @@ |
2464 | |
2465 | //Print out any SQL error, if there was one. |
2466 | if (query.lastError().isValid()) { |
2467 | - qDebug() << query.lastError(); |
2468 | + qDebug() << query.lastError(); |
2469 | } |
2470 | |
2471 | select(); |
2472 | @@ -326,6 +337,7 @@ |
2473 | } |
2474 | |
2475 | QItemDelegate* PlaylistTableModel::delegateForColumn(const int i) { |
2476 | + Q_UNUSED(i); |
2477 | return NULL; |
2478 | } |
2479 | |
2480 | |
2481 | === modified file 'mixxx/src/library/playlisttablemodel.h' |
2482 | --- mixxx/src/library/playlisttablemodel.h 2011-11-30 05:27:44 +0000 |
2483 | +++ mixxx/src/library/playlisttablemodel.h 2012-03-12 04:25:21 +0000 |
2484 | @@ -30,6 +30,7 @@ |
2485 | virtual void removeTrack(const QModelIndex& index); |
2486 | virtual void removeTracks(const QModelIndexList& indices); |
2487 | virtual bool addTrack(const QModelIndex& index, QString location); |
2488 | + virtual bool appendTrack(int trackId); |
2489 | virtual void moveTrack(const QModelIndex& sourceIndex, const QModelIndex& destIndex); |
2490 | virtual void shuffleTracks(const QModelIndex& currentIndex); |
2491 | |
2492 | |
2493 | === modified file 'mixxx/src/library/preparefeature.cpp' |
2494 | --- mixxx/src/library/preparefeature.cpp 2011-03-26 12:29:21 +0000 |
2495 | +++ mixxx/src/library/preparefeature.cpp 2012-03-12 04:25:21 +0000 |
2496 | @@ -78,34 +78,45 @@ |
2497 | } |
2498 | |
2499 | void PrepareFeature::activateChild(const QModelIndex& index) { |
2500 | + Q_UNUSED(index); |
2501 | } |
2502 | |
2503 | void PrepareFeature::onRightClick(const QPoint& globalPos) { |
2504 | + Q_UNUSED(globalPos); |
2505 | } |
2506 | |
2507 | void PrepareFeature::onRightClickChild(const QPoint& globalPos, |
2508 | QModelIndex index) { |
2509 | + Q_UNUSED(globalPos); |
2510 | + Q_UNUSED(index); |
2511 | } |
2512 | |
2513 | bool PrepareFeature::dropAccept(QUrl url) { |
2514 | + Q_UNUSED(url); |
2515 | return false; |
2516 | } |
2517 | |
2518 | bool PrepareFeature::dropAcceptChild(const QModelIndex& index, QUrl url) { |
2519 | + Q_UNUSED(index); |
2520 | + Q_UNUSED(url); |
2521 | return false; |
2522 | } |
2523 | |
2524 | bool PrepareFeature::dragMoveAccept(QUrl url) { |
2525 | + Q_UNUSED(url); |
2526 | return false; |
2527 | } |
2528 | |
2529 | bool PrepareFeature::dragMoveAcceptChild(const QModelIndex& index, |
2530 | QUrl url) { |
2531 | + Q_UNUSED(index); |
2532 | + Q_UNUSED(url); |
2533 | return false; |
2534 | } |
2535 | |
2536 | void PrepareFeature::onLazyChildExpandation(const QModelIndex &index){ |
2537 | //Nothing to do because the childmodel is not of lazy nature. |
2538 | + Q_UNUSED(index); |
2539 | } |
2540 | |
2541 | void PrepareFeature::analyzeTracks(QList<int> trackIds) { |
2542 | |
2543 | === added file 'mixxx/src/library/setlogfeature.cpp' |
2544 | --- mixxx/src/library/setlogfeature.cpp 1970-01-01 00:00:00 +0000 |
2545 | +++ mixxx/src/library/setlogfeature.cpp 2012-03-12 04:25:21 +0000 |
2546 | @@ -0,0 +1,263 @@ |
2547 | +#include <QtDebug> |
2548 | +#include <QMenu> |
2549 | +#include <QInputDialog> |
2550 | +#include <QFileDialog> |
2551 | +#include <QDesktopServices> |
2552 | +#include <QDateTime> |
2553 | + |
2554 | +#include "library/setlogfeature.h" |
2555 | + |
2556 | +#include "controlobject.h" |
2557 | +#include "library/playlisttablemodel.h" |
2558 | +#include "library/trackcollection.h" |
2559 | +#include "playerinfo.h" |
2560 | +#include "treeitem.h" |
2561 | + |
2562 | +SetlogFeature::SetlogFeature(QObject* parent, |
2563 | + ConfigObject<ConfigValue>* pConfig, |
2564 | + TrackCollection* pTrackCollection) |
2565 | + : BasePlaylistFeature(parent, pConfig, pTrackCollection, |
2566 | + "SETLOGHOME", "qrc:/html/setlogs.html") { |
2567 | + m_pPlaylistTableModel = new PlaylistTableModel(this, pTrackCollection, |
2568 | + "mixxx.db.model.setlog"); |
2569 | + m_pJoinWithPreviousAction = new QAction(tr("Join with previous"), this); |
2570 | + connect(m_pJoinWithPreviousAction, SIGNAL(triggered()), |
2571 | + this, SLOT(slotJoinWithPrevious())); |
2572 | + |
2573 | + //create a new playlist for today |
2574 | + QString set_log_name_format; |
2575 | + QString set_log_name; |
2576 | + |
2577 | + set_log_name = QDate::currentDate().toString(Qt::ISODate); |
2578 | + set_log_name_format = set_log_name + " (%1)"; |
2579 | + int i = 1; |
2580 | + |
2581 | + // calculate name of the todays setlog |
2582 | + while (m_playlistDao.getPlaylistIdFromName(set_log_name) != -1) { |
2583 | + set_log_name = set_log_name_format.arg(++i); |
2584 | + } |
2585 | + |
2586 | + m_playlistId = m_playlistDao.createPlaylist(set_log_name, |
2587 | + PlaylistDAO::PLHT_SET_LOG); |
2588 | + |
2589 | + if (m_playlistId == -1) { |
2590 | + qDebug() << "Playlist Creation Failed"; |
2591 | + qDebug() << "An unknown error occurred while creating playlist: " << set_log_name; |
2592 | + } |
2593 | + |
2594 | + // Setup the sidebar playlist model |
2595 | + m_playlistTableModel.setTable("Playlists"); |
2596 | + m_playlistTableModel.setFilter("hidden=2"); // PLHT_SET_LOG |
2597 | + m_playlistTableModel.setSort(m_playlistTableModel.fieldIndex("id"), |
2598 | + Qt::AscendingOrder); |
2599 | + m_playlistTableModel.select(); |
2600 | + |
2601 | + //construct child model |
2602 | + TreeItem *rootItem = new TreeItem(); |
2603 | + m_childModel.setRootItem(rootItem); |
2604 | + constructChildModel(-1); |
2605 | +} |
2606 | + |
2607 | +SetlogFeature::~SetlogFeature() { |
2608 | +} |
2609 | + |
2610 | +QVariant SetlogFeature::title() { |
2611 | + return tr("Set Logs"); |
2612 | +} |
2613 | + |
2614 | +QIcon SetlogFeature::getIcon() { |
2615 | + return QIcon(":/images/library/ic_library_setlog.png"); |
2616 | +} |
2617 | + |
2618 | +void SetlogFeature::bindWidget(WLibrarySidebar* sidebarWidget, |
2619 | + WLibrary* libraryWidget, |
2620 | + MixxxKeyboard* keyboard) { |
2621 | + BasePlaylistFeature::bindWidget(sidebarWidget, |
2622 | + libraryWidget, |
2623 | + keyboard); |
2624 | + connect(&PlayerInfo::Instance(), SIGNAL(currentPlayingDeckChanged(int)), |
2625 | + this, SLOT(slotPlayingDeckChanged(int))); |
2626 | +} |
2627 | + |
2628 | +void SetlogFeature::onRightClick(const QPoint& globalPos) { |
2629 | + Q_UNUSED(globalPos); |
2630 | + m_lastRightClickedIndex = QModelIndex(); |
2631 | + |
2632 | + // Create the right-click menu |
2633 | + // QMenu menu(NULL); |
2634 | + // menu.addAction(m_pCreatePlaylistAction); |
2635 | + // TODO(DASCHUER) add something like disable logging |
2636 | + // menu.exec(globalPos); |
2637 | +} |
2638 | + |
2639 | +void SetlogFeature::onRightClickChild(const QPoint& globalPos, QModelIndex index) { |
2640 | + //Save the model index so we can get it in the action slots... |
2641 | + m_lastRightClickedIndex = index; |
2642 | + QString playlistName = index.data().toString(); |
2643 | + int playlistId = m_playlistDao.getPlaylistIdFromName(playlistName); |
2644 | + |
2645 | + |
2646 | + bool locked = m_playlistDao.isPlaylistLocked(playlistId); |
2647 | + m_pDeletePlaylistAction->setEnabled(!locked); |
2648 | + m_pRenamePlaylistAction->setEnabled(!locked); |
2649 | + |
2650 | + m_pLockPlaylistAction->setText(locked ? tr("Unlock") : tr("Lock")); |
2651 | + |
2652 | + |
2653 | + //Create the right-click menu |
2654 | + QMenu menu(NULL); |
2655 | + //menu.addAction(m_pCreatePlaylistAction); |
2656 | + //menu.addSeparator(); |
2657 | + menu.addAction(m_pAddToAutoDJAction); |
2658 | + menu.addAction(m_pAddToAutoDJTopAction); |
2659 | + menu.addAction(m_pRenamePlaylistAction); |
2660 | + if (playlistId != m_playlistId) { |
2661 | + // Todays playlist should not be locked or deleted |
2662 | + menu.addAction(m_pDeletePlaylistAction); |
2663 | + menu.addAction(m_pLockPlaylistAction); |
2664 | + } |
2665 | + if (index.row() > 0) { |
2666 | + // The very first setlog cannot be joint |
2667 | + menu.addAction(m_pJoinWithPreviousAction); |
2668 | + } |
2669 | + menu.addSeparator(); |
2670 | + menu.addAction(m_pExportPlaylistAction); |
2671 | + menu.exec(globalPos); |
2672 | +} |
2673 | + |
2674 | +bool SetlogFeature::dropAcceptChild(const QModelIndex& index, QUrl url){ |
2675 | + Q_UNUSED(url); |
2676 | + Q_UNUSED(index); |
2677 | + return false; |
2678 | +} |
2679 | + |
2680 | +bool SetlogFeature::dragMoveAcceptChild(const QModelIndex& index, QUrl url) { |
2681 | + Q_UNUSED(url); |
2682 | + Q_UNUSED(index); |
2683 | + return false; |
2684 | +} |
2685 | + |
2686 | +/** |
2687 | + * Purpose: When inserting or removing playlists, |
2688 | + * we require the sidebar model not to reset. |
2689 | + * This method queries the database and does dynamic insertion |
2690 | +*/ |
2691 | +QModelIndex SetlogFeature::constructChildModel(int selected_id) |
2692 | +{ |
2693 | + QList<TreeItem*> data_list; |
2694 | + int nameColumn = m_playlistTableModel.record().indexOf("name"); |
2695 | + int idColumn = m_playlistTableModel.record().indexOf("id"); |
2696 | + int selected_row = -1; |
2697 | + // Access the invisible root item |
2698 | + TreeItem* root = m_childModel.getItem(QModelIndex()); |
2699 | + |
2700 | + // Create new TreeItems for the playlists in the database |
2701 | + for (int row = 0; row < m_playlistTableModel.rowCount(); ++row) { |
2702 | + QModelIndex ind = m_playlistTableModel.index(row, nameColumn); |
2703 | + QString playlist_name = m_playlistTableModel.data(ind).toString(); |
2704 | + ind = m_playlistTableModel.index(row, idColumn); |
2705 | + int playlist_id = m_playlistTableModel.data(ind).toInt(); |
2706 | + |
2707 | + if ( selected_id == playlist_id) { |
2708 | + // save index for selection |
2709 | + selected_row = row; |
2710 | + } |
2711 | + |
2712 | + // Create the TreeItem whose parent is the invisible root item |
2713 | + TreeItem* item = new TreeItem(playlist_name, playlist_name, this, root); |
2714 | + if (playlist_id == m_playlistId) { |
2715 | + item->setIcon(QIcon(":/images/library/ic_library_setlog_current.png")); |
2716 | + } else if (m_playlistDao.isPlaylistLocked(playlist_id)) { |
2717 | + item->setIcon(QIcon(":/images/library/ic_library_locked.png")); |
2718 | + } else { |
2719 | + item->setIcon(QIcon()); |
2720 | + } |
2721 | + data_list.append(item); |
2722 | + } |
2723 | + |
2724 | + // Append all the newly created TreeItems in a dynamic way to the childmodel |
2725 | + m_childModel.insertRows(data_list, 0, m_playlistTableModel.rowCount()); |
2726 | + if (selected_row == -1) { |
2727 | + return QModelIndex(); |
2728 | + } |
2729 | + return m_childModel.index(selected_row, 0); |
2730 | +} |
2731 | + |
2732 | +void SetlogFeature::slotJoinWithPrevious() { |
2733 | + //qDebug() << "slotJoinWithPrevious() row:" << m_lastRightClickedIndex.data(); |
2734 | + |
2735 | + if (m_lastRightClickedIndex.isValid()) { |
2736 | + int currentPlaylistId = m_playlistDao.getPlaylistIdFromName( |
2737 | + m_lastRightClickedIndex.data().toString()); |
2738 | + |
2739 | + if (currentPlaylistId >= 0) { |
2740 | + |
2741 | + bool locked = m_playlistDao.isPlaylistLocked(currentPlaylistId); |
2742 | + |
2743 | + if (locked) { |
2744 | + qDebug() << "Skipping playlist deletion because playlist" << currentPlaylistId << "is locked."; |
2745 | + return; |
2746 | + } |
2747 | + |
2748 | + // Add every track from right klicked playlist to that with the next smaller ID |
2749 | + int previousPlaylistId = m_playlistDao.getPreviousPlaylist(currentPlaylistId, PlaylistDAO::PLHT_SET_LOG); |
2750 | + if (previousPlaylistId >= 0) { |
2751 | + |
2752 | + m_pPlaylistTableModel->setPlaylist(previousPlaylistId); |
2753 | + |
2754 | + if (currentPlaylistId == m_playlistId) { |
2755 | + // mark all the Tracks in the previous Playlist as played |
2756 | + |
2757 | + m_pPlaylistTableModel->select(); |
2758 | + int rows = m_pPlaylistTableModel->rowCount(); |
2759 | + for(int i = 0; i < rows; ++i){ |
2760 | + QModelIndex index = m_pPlaylistTableModel->index(i,0); |
2761 | + if (index.isValid()) { |
2762 | + TrackPointer track = m_pPlaylistTableModel->getTrack(index); |
2763 | + // Do not update the playcount, just set played |
2764 | + // status. |
2765 | + track->setPlayed(true); |
2766 | + } |
2767 | + } |
2768 | + |
2769 | + // Change current setlog |
2770 | + m_playlistId = previousPlaylistId; |
2771 | + } |
2772 | + qDebug() << "slotJoinWithPrevious() current:" << currentPlaylistId << " previous:" << previousPlaylistId; |
2773 | + m_playlistDao.copyPlaylistTracks(currentPlaylistId, previousPlaylistId); |
2774 | + m_playlistDao.deletePlaylist(currentPlaylistId); |
2775 | + slotPlaylistTableChanged(previousPlaylistId); // For moving selection |
2776 | + emit(showTrackModel(m_pPlaylistTableModel)); |
2777 | + emit(featureUpdated()); |
2778 | + } |
2779 | + } |
2780 | + } |
2781 | +} |
2782 | + |
2783 | +void SetlogFeature::slotPlayingDeckChanged(int deck) { |
2784 | + if (deck > 0) { |
2785 | + QString chan = QString("[Channel%1]").arg(deck); |
2786 | + TrackPointer currentPlayingTrack = |
2787 | + PlayerInfo::Instance().getTrackInfo(chan); |
2788 | + if (!currentPlayingTrack) { |
2789 | + return; |
2790 | + } |
2791 | + int currentPlayingTrackId = currentPlayingTrack->getId(); |
2792 | + // We can only add tracks that are Mixxx library tracks, not external |
2793 | + // sources. |
2794 | + if (currentPlayingTrackId < 0) { |
2795 | + return; |
2796 | + } |
2797 | + |
2798 | + // Here the song is realy played, not only loaded. |
2799 | + currentPlayingTrack->setPlayedAndUpdatePlaycount(true); |
2800 | + |
2801 | + if (m_pPlaylistTableModel->getPlaylist() == m_playlistId) { |
2802 | + // View needs a refresh |
2803 | + m_pPlaylistTableModel->appendTrack(currentPlayingTrackId); |
2804 | + } else { |
2805 | + m_playlistDao.appendTrackToPlaylist(currentPlayingTrackId, |
2806 | + m_playlistId); |
2807 | + } |
2808 | + } |
2809 | +} |
2810 | |
2811 | === added file 'mixxx/src/library/setlogfeature.h' |
2812 | --- mixxx/src/library/setlogfeature.h 1970-01-01 00:00:00 +0000 |
2813 | +++ mixxx/src/library/setlogfeature.h 2012-03-12 04:25:21 +0000 |
2814 | @@ -0,0 +1,48 @@ |
2815 | +// setlogfeature.h |
2816 | + |
2817 | +#ifndef SETLOGFEATURE_H |
2818 | +#define SETLOGFEATURE_H |
2819 | + |
2820 | +#include <QSqlTableModel> |
2821 | +#include <QAction> |
2822 | + |
2823 | +#include "library/baseplaylistfeature.h" |
2824 | +#include "configobject.h" |
2825 | +#include "controlobjectthreadmain.h" |
2826 | + |
2827 | +class TrackCollection; |
2828 | + |
2829 | +class SetlogFeature : public BasePlaylistFeature { |
2830 | + Q_OBJECT |
2831 | +public: |
2832 | + SetlogFeature(QObject* parent, ConfigObject<ConfigValue>* pConfig, |
2833 | + TrackCollection* pTrackCollection); |
2834 | + virtual ~SetlogFeature(); |
2835 | + |
2836 | + QVariant title(); |
2837 | + QIcon getIcon(); |
2838 | + |
2839 | + bool dropAcceptChild(const QModelIndex& index, QUrl url); |
2840 | + bool dragMoveAcceptChild(const QModelIndex& index, QUrl url); |
2841 | + |
2842 | + virtual void bindWidget(WLibrarySidebar* sidebarWidget, |
2843 | + WLibrary* libraryWidget, |
2844 | + MixxxKeyboard* keyboard); |
2845 | + |
2846 | + public slots: |
2847 | + void onRightClick(const QPoint& globalPos); |
2848 | + void onRightClickChild(const QPoint& globalPos, QModelIndex index); |
2849 | + void slotJoinWithPrevious(); |
2850 | + |
2851 | + protected: |
2852 | + QModelIndex constructChildModel(int selected_id); |
2853 | + |
2854 | + private slots: |
2855 | + void slotPlayingDeckChanged(int deck); |
2856 | + |
2857 | + private: |
2858 | + QAction *m_pJoinWithPreviousAction; |
2859 | + int m_playlistId; |
2860 | +}; |
2861 | + |
2862 | +#endif /* SETLOGFEATURE_H */ |
2863 | |
2864 | === modified file 'mixxx/src/library/sidebarmodel.cpp' |
2865 | --- mixxx/src/library/sidebarmodel.cpp 2011-10-21 02:26:31 +0000 |
2866 | +++ mixxx/src/library/sidebarmodel.cpp 2012-03-12 04:25:21 +0000 |
2867 | @@ -17,11 +17,14 @@ |
2868 | |
2869 | void SidebarModel::addLibraryFeature(LibraryFeature* feature) { |
2870 | m_sFeatures.push_back(feature); |
2871 | - connect(feature, SIGNAL(featureUpdated()), this, SLOT(refreshData())); |
2872 | + connect(feature, SIGNAL(featureUpdated()), |
2873 | + this, SLOT(refreshData())); |
2874 | connect(feature, SIGNAL(featureIsLoading(LibraryFeature*)), |
2875 | this, SLOT(slotFeatureIsLoading(LibraryFeature*))); |
2876 | connect(feature, SIGNAL(featureLoadingFinished(LibraryFeature*)), |
2877 | - this,SLOT(slotFeatureLoadingFinished(LibraryFeature*))); |
2878 | + this, SLOT(slotFeatureLoadingFinished(LibraryFeature*))); |
2879 | + connect(feature, SIGNAL(featureSelect(LibraryFeature*, const QModelIndex&)), |
2880 | + this, SLOT(slotFeatureSelect(LibraryFeature*, const QModelIndex&))); |
2881 | |
2882 | QAbstractItemModel* model = feature->getChildModel(); |
2883 | |
2884 | @@ -108,19 +111,23 @@ |
2885 | return QModelIndex(); |
2886 | } else { |
2887 | TreeItem* tree_item = (TreeItem*)index.internalPointer(); |
2888 | + TreeItem* tree_item_parent = tree_item->parent(); |
2889 | // if we have selected an item at the first level of a childnode |
2890 | - if (tree_item->parent()->data() == "$root"){ |
2891 | - LibraryFeature* feature = tree_item->getFeature(); |
2892 | - for (int i = 0; i < m_sFeatures.size(); ++i) { |
2893 | - if (feature == m_sFeatures[i]) { |
2894 | - // create a ModelIndex for parent 'this' having a |
2895 | - // library feature at position 'i' |
2896 | - return createIndex(i, 0, (void*)this); |
2897 | + |
2898 | + if (tree_item_parent) { |
2899 | + if (tree_item_parent->data() == "$root"){ |
2900 | + LibraryFeature* feature = tree_item->getFeature(); |
2901 | + for (int i = 0; i < m_sFeatures.size(); ++i) { |
2902 | + if (feature == m_sFeatures[i]) { |
2903 | + // create a ModelIndex for parent 'this' having a |
2904 | + // library feature at position 'i' |
2905 | + return createIndex(i, 0, (void*)this); |
2906 | + } |
2907 | } |
2908 | } |
2909 | + // if we have selected an item at some deeper level of a childnode |
2910 | + return createIndex(tree_item_parent->row(), 0 , tree_item_parent); |
2911 | } |
2912 | - // if we have selected an item at some deeper level of a childnode |
2913 | - return createIndex(tree_item->parent()->row(), 0 , tree_item->parent()); |
2914 | } |
2915 | } |
2916 | return QModelIndex(); |
2917 | @@ -144,6 +151,7 @@ |
2918 | } |
2919 | |
2920 | int SidebarModel::columnCount(const QModelIndex& parent) const { |
2921 | + Q_UNUSED(parent); |
2922 | //qDebug() << "SidebarModel::columnCount parent=" << parent; |
2923 | // TODO(rryan) will we ever have columns? I don't think so. |
2924 | return 1; |
2925 | @@ -312,6 +320,8 @@ |
2926 | } |
2927 | |
2928 | void SidebarModel::slotDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) { |
2929 | + Q_UNUSED(topLeft); |
2930 | + Q_UNUSED(bottomRight); |
2931 | //qDebug() << "slotDataChanged topLeft:" << topLeft << "bottomRight:" << bottomRight; |
2932 | } |
2933 | |
2934 | @@ -330,12 +340,18 @@ |
2935 | } |
2936 | |
2937 | void SidebarModel::slotRowsInserted(const QModelIndex& parent, int start, int end) { |
2938 | - // qDebug() << "slotRowsInserted" << parent << start << end; |
2939 | + Q_UNUSED(parent); |
2940 | + Q_UNUSED(start); |
2941 | + Q_UNUSED(end); |
2942 | + // qDebug() << "slotRowsInserted" << parent << start << end; |
2943 | //QModelIndex newParent = translateSourceIndex(parent); |
2944 | endInsertRows(); |
2945 | } |
2946 | |
2947 | void SidebarModel::slotRowsRemoved(const QModelIndex& parent, int start, int end) { |
2948 | + Q_UNUSED(parent); |
2949 | + Q_UNUSED(start); |
2950 | + Q_UNUSED(end); |
2951 | //qDebug() << "slotRowsRemoved" << parent << start << end; |
2952 | //QModelIndex newParent = translateSourceIndex(parent); |
2953 | endRemoveRows(); |
2954 | @@ -356,7 +372,7 @@ |
2955 | void SidebarModel::slotFeatureIsLoading(LibraryFeature * feature) |
2956 | { |
2957 | featureRenamed(feature); |
2958 | - selectFeature(feature); |
2959 | + slotFeatureSelect(feature); |
2960 | } |
2961 | |
2962 | /* Tobias: This slot is somewhat redundant but I decided |
2963 | @@ -364,7 +380,7 @@ |
2964 | */ |
2965 | void SidebarModel::slotFeatureLoadingFinished(LibraryFeature * feature){ |
2966 | featureRenamed(feature); |
2967 | - selectFeature(feature); |
2968 | + slotFeatureSelect(feature); |
2969 | } |
2970 | |
2971 | void SidebarModel::featureRenamed(LibraryFeature* pFeature){ |
2972 | @@ -376,11 +392,18 @@ |
2973 | } |
2974 | } |
2975 | |
2976 | -void SidebarModel::selectFeature(LibraryFeature* pFeature) { |
2977 | - for (int i=0; i < m_sFeatures.size(); ++i) { |
2978 | - if (m_sFeatures[i] == pFeature) { |
2979 | - QModelIndex ind = index(i, 0); |
2980 | - emit(selectIndex(ind)); |
2981 | +void SidebarModel::slotFeatureSelect(LibraryFeature* pFeature, const QModelIndex& featureIndex) { |
2982 | + QModelIndex ind; |
2983 | + if (featureIndex.isValid()) { |
2984 | + TreeItem* item = (TreeItem*)featureIndex.internalPointer(); |
2985 | + ind = createIndex(featureIndex.row(), featureIndex.column(), item); |
2986 | + } else { |
2987 | + for (int i=0; i < m_sFeatures.size(); ++i) { |
2988 | + if (m_sFeatures[i] == pFeature) { |
2989 | + ind = index(i, 0); |
2990 | + break; |
2991 | + } |
2992 | } |
2993 | } |
2994 | + emit(selectIndex(ind)); |
2995 | } |
2996 | |
2997 | === modified file 'mixxx/src/library/sidebarmodel.h' |
2998 | --- mixxx/src/library/sidebarmodel.h 2011-03-27 20:12:33 +0000 |
2999 | +++ mixxx/src/library/sidebarmodel.h 2012-03-12 04:25:21 +0000 |
3000 | @@ -39,7 +39,7 @@ |
3001 | void doubleClicked(const QModelIndex& index); |
3002 | void rightClicked(const QPoint& globalPos, const QModelIndex& index); |
3003 | void refreshData(); |
3004 | - void selectFeature(LibraryFeature* pFeature); |
3005 | + void slotFeatureSelect(LibraryFeature* pFeature, const QModelIndex& index = QModelIndex()); |
3006 | |
3007 | // Slots for every single QAbstractItemModel signal |
3008 | // void slotColumnsAboutToBeInserted(const QModelIndex& parent, int start, int end); |
3009 | |
3010 | === modified file 'mixxx/src/library/trackcollection.cpp' |
3011 | --- mixxx/src/library/trackcollection.cpp 2011-12-28 20:30:15 +0000 |
3012 | +++ mixxx/src/library/trackcollection.cpp 2012-03-12 04:25:21 +0000 |
3013 | @@ -15,9 +15,9 @@ |
3014 | TrackCollection::TrackCollection(ConfigObject<ConfigValue>* pConfig) |
3015 | : m_pConfig(pConfig), |
3016 | m_db(QSqlDatabase::addDatabase("QSQLITE")), // defaultConnection |
3017 | - m_cueDao(m_db), |
3018 | m_playlistDao(m_db), |
3019 | m_crateDao(m_db), |
3020 | + m_cueDao(m_db), |
3021 | m_trackDao(m_db, m_cueDao, m_playlistDao, m_crateDao, pConfig), |
3022 | m_supportedFileExtensionsRegex( |
3023 | SoundSourceProxy::supportedFileExtensionsRegex(), |
3024 | |
3025 | === modified file 'mixxx/src/mixxx.cpp' |
3026 | --- mixxx/src/mixxx.cpp 2012-01-16 03:04:52 +0000 |
3027 | +++ mixxx/src/mixxx.cpp 2012-03-12 04:25:21 +0000 |
3028 | @@ -263,8 +263,6 @@ |
3029 | QDir().mkpath(QDir::homePath().append("/").append(SETTINGS_PATH)); |
3030 | } |
3031 | |
3032 | - |
3033 | - |
3034 | m_pLibrary = new Library(this, m_pConfig, |
3035 | bFirstRun || bUpgraded, |
3036 | m_pRecordingManager); |
3037 | @@ -432,12 +430,9 @@ |
3038 | |
3039 | m_pWidgetParent = NULL; |
3040 | // Loads the skin as a child of m_pView |
3041 | - // assignment itentional in next line |
3042 | - if (!(m_pWidgetParent = m_pSkinLoader->loadDefaultSkin(m_pView, |
3043 | - m_pKeyboard, |
3044 | - m_pPlayerManager, |
3045 | - m_pLibrary, |
3046 | - m_pVCManager))) { |
3047 | + // assignment intentional in next line |
3048 | + if (!(m_pWidgetParent = m_pSkinLoader->loadDefaultSkin( |
3049 | + m_pView, m_pKeyboard, m_pPlayerManager, m_pLibrary, m_pVCManager))) { |
3050 | qDebug() << "Could not load default skin."; |
3051 | } |
3052 | |
3053 | |
3054 | === modified file 'mixxx/src/playerinfo.cpp' |
3055 | --- mixxx/src/playerinfo.cpp 2011-03-25 05:31:57 +0000 |
3056 | +++ mixxx/src/playerinfo.cpp 2012-03-12 04:25:21 +0000 |
3057 | @@ -22,7 +22,7 @@ |
3058 | #include "engine/enginexfader.h" |
3059 | |
3060 | PlayerInfo::PlayerInfo() |
3061 | -{ |
3062 | + : m_currentlyPlayingDeck(0) { |
3063 | int i; |
3064 | m_iNumDecks = ControlObject::getControl(ConfigKey("[Master]","num_decks"))->get(); |
3065 | |
3066 | @@ -36,13 +36,12 @@ |
3067 | } |
3068 | |
3069 | m_COxfader = new ControlObjectThread(ControlObject::getControl(ConfigKey("[Master]","crossfader"))); |
3070 | + |
3071 | + startTimer(2000); |
3072 | } |
3073 | |
3074 | -PlayerInfo::~PlayerInfo() |
3075 | -{ |
3076 | +PlayerInfo::~PlayerInfo() { |
3077 | int i; |
3078 | - |
3079 | - |
3080 | m_loadedTrackMap.clear(); |
3081 | |
3082 | for (i = 1; i <= m_iNumDecks; i++) { |
3083 | @@ -57,14 +56,12 @@ |
3084 | delete m_COxfader; |
3085 | } |
3086 | |
3087 | -PlayerInfo &PlayerInfo::Instance() |
3088 | -{ |
3089 | +PlayerInfo &PlayerInfo::Instance() { |
3090 | static PlayerInfo playerInfo; |
3091 | return playerInfo; |
3092 | } |
3093 | |
3094 | -TrackPointer PlayerInfo::getTrackInfo(QString group) |
3095 | -{ |
3096 | +TrackPointer PlayerInfo::getTrackInfo(QString group) { |
3097 | QMutexLocker locker(&m_mutex); |
3098 | |
3099 | if (m_loadedTrackMap.contains(group)) { |
3100 | @@ -80,13 +77,15 @@ |
3101 | m_loadedTrackMap[group] = track; |
3102 | } |
3103 | |
3104 | -int PlayerInfo::getCurrentPlayingDeck() |
3105 | -{ |
3106 | +void PlayerInfo::timerEvent(QTimerEvent* pTimerEvent) { |
3107 | + updateCurrentPlayingDeck(); |
3108 | +} |
3109 | + |
3110 | +void PlayerInfo::updateCurrentPlayingDeck() { |
3111 | QMutexLocker locker(&m_mutex); |
3112 | int MaxVolume = 0; |
3113 | int MaxDeck = 0; |
3114 | int i; |
3115 | - |
3116 | |
3117 | for (i = 1; i <= m_iNumDecks; i++) { |
3118 | QString chan = QString("[Channel%1]").arg(i); |
3119 | @@ -95,10 +94,10 @@ |
3120 | float dvol; |
3121 | int orient; |
3122 | |
3123 | - if ( m_listCOPlay[chan]->get() == 0.0 ) |
3124 | + if (m_listCOPlay[chan]->get() == 0.0 ) |
3125 | continue; |
3126 | |
3127 | - if ( m_listCOpregain[chan]->get() <= 0.5 ) |
3128 | + if (m_listCOpregain[chan]->get() <= 0.5 ) |
3129 | continue; |
3130 | |
3131 | if ((fvol = m_listCOVolume[chan]->get()) == 0.0 ) |
3132 | @@ -106,7 +105,7 @@ |
3133 | |
3134 | EngineXfader::getXfadeGains(xfl, xfr, m_COxfader->get(), 1.0, 0.0); |
3135 | |
3136 | - // Orientation goes: left is 0, center is 1, right is 2. |
3137 | + // Orientation goes: left is 0, center is 1, right is 2. |
3138 | // Leave math out of it... |
3139 | orient = m_listCOOrientation[chan]->get(); |
3140 | if ( orient == 0 ) |
3141 | @@ -117,23 +116,30 @@ |
3142 | xfvol = 1; |
3143 | |
3144 | dvol = fvol * xfvol; |
3145 | - if ( dvol > MaxVolume ) { |
3146 | + if (dvol > MaxVolume ) { |
3147 | MaxDeck = i; |
3148 | MaxVolume = dvol; |
3149 | } |
3150 | } |
3151 | |
3152 | - return MaxDeck; |
3153 | -} |
3154 | - |
3155 | -TrackPointer PlayerInfo::getCurrentPlayingTrack() |
3156 | -{ |
3157 | + if (MaxDeck != m_currentlyPlayingDeck) { |
3158 | + m_currentlyPlayingDeck = MaxDeck; |
3159 | + m_mutex.unlock(); |
3160 | + emit(currentPlayingDeckChanged(MaxDeck)); |
3161 | + } |
3162 | +} |
3163 | + |
3164 | +int PlayerInfo::getCurrentPlayingDeck() { |
3165 | + QMutexLocker locker(&m_mutex); |
3166 | + return m_currentlyPlayingDeck; |
3167 | +} |
3168 | + |
3169 | +TrackPointer PlayerInfo::getCurrentPlayingTrack() { |
3170 | int deck = getCurrentPlayingDeck(); |
3171 | - if ( deck ) { |
3172 | + if (deck) { |
3173 | QString chan = QString("[Channel%1]").arg(deck); |
3174 | return getTrackInfo(chan); |
3175 | } |
3176 | - |
3177 | return TrackPointer(); |
3178 | } |
3179 | |
3180 | |
3181 | === modified file 'mixxx/src/playerinfo.h' |
3182 | --- mixxx/src/playerinfo.h 2011-03-23 09:20:56 +0000 |
3183 | +++ mixxx/src/playerinfo.h 2012-03-12 04:25:21 +0000 |
3184 | @@ -20,7 +20,7 @@ |
3185 | #include <QObject> |
3186 | #include <QMutex> |
3187 | #include <QMap> |
3188 | - |
3189 | +#include <QTimerEvent> |
3190 | |
3191 | class ControlObjectThread; |
3192 | |
3193 | @@ -35,7 +35,14 @@ |
3194 | void setTrackInfo(QString group, TrackPointer trackInfoObj); |
3195 | int getCurrentPlayingDeck(); |
3196 | TrackPointer getCurrentPlayingTrack(); |
3197 | + |
3198 | + signals: |
3199 | + void currentPlayingDeckChanged(int deck); |
3200 | + |
3201 | private: |
3202 | + void timerEvent(QTimerEvent* pTimerEvent); |
3203 | + void updateCurrentPlayingDeck(); |
3204 | + |
3205 | PlayerInfo(); |
3206 | ~PlayerInfo(); |
3207 | PlayerInfo(PlayerInfo const&); |
3208 | @@ -48,6 +55,8 @@ |
3209 | QMap<QString, ControlObjectThread*> m_listCOVolume; |
3210 | QMap<QString, ControlObjectThread*> m_listCOOrientation; |
3211 | QMap<QString, ControlObjectThread*> m_listCOpregain; |
3212 | + |
3213 | + int m_currentlyPlayingDeck; |
3214 | }; |
3215 | |
3216 | #endif |
3217 | |
3218 | === modified file 'mixxx/src/trackinfoobject.cpp' |
3219 | --- mixxx/src/trackinfoobject.cpp 2011-12-28 20:30:15 +0000 |
3220 | +++ mixxx/src/trackinfoobject.cpp 2012-03-12 04:25:21 +0000 |
3221 | @@ -557,7 +557,7 @@ |
3222 | |
3223 | void TrackInfoObject::incTimesPlayed() |
3224 | { |
3225 | - setPlayed(true); //setPlayed increases play count |
3226 | + setPlayedAndUpdatePlaycount(true); |
3227 | } |
3228 | |
3229 | bool TrackInfoObject::getPlayed() const |
3230 | @@ -567,20 +567,29 @@ |
3231 | return bPlayed; |
3232 | } |
3233 | |
3234 | -void TrackInfoObject::setPlayed(bool bPlayed) |
3235 | +void TrackInfoObject::setPlayedAndUpdatePlaycount(bool bPlayed) |
3236 | { |
3237 | QMutexLocker lock(&m_qMutex); |
3238 | if (bPlayed) { |
3239 | ++m_iTimesPlayed; |
3240 | - setDirty(true); |
3241 | + setDirty(true); |
3242 | } |
3243 | else if (m_bPlayed && !bPlayed) { |
3244 | --m_iTimesPlayed; |
3245 | - setDirty(true); |
3246 | + setDirty(true); |
3247 | } |
3248 | m_bPlayed = bPlayed; |
3249 | } |
3250 | |
3251 | +void TrackInfoObject::setPlayed(bool bPlayed) |
3252 | +{ |
3253 | + QMutexLocker lock(&m_qMutex); |
3254 | + if (bPlayed != m_bPlayed) { |
3255 | + m_bPlayed = bPlayed; |
3256 | + setDirty(true); |
3257 | + } |
3258 | +} |
3259 | + |
3260 | QString TrackInfoObject::getComment() const |
3261 | { |
3262 | QMutexLocker lock(&m_qMutex); |
3263 | |
3264 | === modified file 'mixxx/src/trackinfoobject.h' |
3265 | --- mixxx/src/trackinfoobject.h 2012-01-07 05:48:41 +0000 |
3266 | +++ mixxx/src/trackinfoobject.h 2012-03-12 04:25:21 +0000 |
3267 | @@ -189,8 +189,10 @@ |
3268 | void incTimesPlayed(); |
3269 | /** Returns true if track has been played this instance*/ |
3270 | bool getPlayed() const; |
3271 | - /** Set Played status*/ |
3272 | - void setPlayed(bool); |
3273 | + /** Set played status and increment or decrement playcount. */ |
3274 | + void setPlayedAndUpdatePlaycount(bool); |
3275 | + /** Set played status without affecting the playcount */ |
3276 | + void setPlayed(bool bPlayed); |
3277 | |
3278 | int getId() const; |
3279 | |
3280 | |
3281 | === modified file 'mixxx/src/widget/wlibrarysidebar.cpp' |
3282 | --- mixxx/src/widget/wlibrarysidebar.cpp 2011-03-27 21:15:15 +0000 |
3283 | +++ mixxx/src/widget/wlibrarysidebar.cpp 2012-03-12 04:25:21 +0000 |
3284 | @@ -199,4 +199,9 @@ |
3285 | QItemSelectionModel* pModel = new QItemSelectionModel(model()); |
3286 | pModel->select(index, QItemSelectionModel::Select); |
3287 | setSelectionModel(pModel); |
3288 | + |
3289 | + if (index.parent().isValid()) { |
3290 | + expand(index.parent()); |
3291 | + } |
3292 | + scrollTo(index); |
3293 | } |