Merge lp:~mixxxdevelopers/mixxx/library_features into lp:~mixxxdevelopers/mixxx/trunk

Proposed by RJ Skerry-Ryan
Status: Needs review
Proposed branch: lp:~mixxxdevelopers/mixxx/library_features
Merge into: lp:~mixxxdevelopers/mixxx/trunk
Diff against target: 5250 lines (+1538/-949)
77 files modified
mixxx/build/depends.py (+1/-0)
mixxx/res/schema.xml (+14/-0)
mixxx/src/dlgautodj.cpp (+5/-2)
mixxx/src/dlgautodj.h (+1/-0)
mixxx/src/dlgpreferences.cpp (+5/-0)
mixxx/src/dlgpreferences.h (+2/-0)
mixxx/src/dlgprefplaylist.cpp (+87/-9)
mixxx/src/dlgprefplaylist.h (+9/-0)
mixxx/src/dlgprefplaylistdlg.ui (+40/-26)
mixxx/src/dlgprefrecord.cpp (+1/-4)
mixxx/src/library/autodjfeature.cpp (+2/-0)
mixxx/src/library/autodjfeature.h (+3/-0)
mixxx/src/library/baseexternalplaylistmodel.cpp (+3/-3)
mixxx/src/library/baseexternalplaylistmodel.h (+3/-1)
mixxx/src/library/baseexternaltrackmodel.cpp (+3/-3)
mixxx/src/library/baseexternaltrackmodel.h (+3/-1)
mixxx/src/library/baseplaylistfeature.cpp (+5/-4)
mixxx/src/library/baseplaylistfeature.h (+0/-1)
mixxx/src/library/basesqltablemodel.cpp (+79/-9)
mixxx/src/library/basesqltablemodel.h (+60/-48)
mixxx/src/library/basetrackcache.cpp (+2/-0)
mixxx/src/library/browse/browsefeature.cpp (+23/-2)
mixxx/src/library/browse/browsefeature.h (+3/-0)
mixxx/src/library/browse/browsetablemodel.cpp (+2/-1)
mixxx/src/library/browse/browsetablemodel.h (+1/-1)
mixxx/src/library/browse/browsethread.h (+7/-9)
mixxx/src/library/browse/foldertreemodel.cpp (+1/-0)
mixxx/src/library/cratefeature.cpp (+10/-7)
mixxx/src/library/cratefeature.h (+3/-0)
mixxx/src/library/cratetablemodel.cpp (+46/-62)
mixxx/src/library/cratetablemodel.h (+7/-20)
mixxx/src/library/dao/directorydao.cpp (+143/-0)
mixxx/src/library/dao/directorydao.h (+31/-0)
mixxx/src/library/dao/trackdao.cpp (+307/-76)
mixxx/src/library/dao/trackdao.h (+17/-7)
mixxx/src/library/hiddentablemodel.cpp (+42/-50)
mixxx/src/library/hiddentablemodel.h (+2/-15)
mixxx/src/library/itunes/itunesfeature.cpp (+24/-22)
mixxx/src/library/itunes/itunesfeature.h (+5/-1)
mixxx/src/library/library.cpp (+79/-19)
mixxx/src/library/library.h (+16/-1)
mixxx/src/library/libraryfeature.h (+4/-3)
mixxx/src/library/libraryscanner.cpp (+40/-26)
mixxx/src/library/libraryscanner.h (+6/-3)
mixxx/src/library/librarytablemodel.cpp (+44/-66)
mixxx/src/library/librarytablemodel.h (+2/-21)
mixxx/src/library/missingtablemodel.cpp (+0/-125)
mixxx/src/library/missingtablemodel.h (+0/-41)
mixxx/src/library/mixxxlibraryfeature.cpp (+4/-4)
mixxx/src/library/mixxxlibraryfeature.h (+5/-1)
mixxx/src/library/playlistfeature.cpp (+6/-5)
mixxx/src/library/playlistfeature.h (+5/-1)
mixxx/src/library/playlisttablemodel.cpp (+56/-96)
mixxx/src/library/playlisttablemodel.h (+14/-30)
mixxx/src/library/preparelibrarytablemodel.cpp (+2/-13)
mixxx/src/library/preparelibrarytablemodel.h (+2/-7)
mixxx/src/library/promotracksfeature.cpp (+1/-1)
mixxx/src/library/proxytrackmodel.cpp (+16/-11)
mixxx/src/library/proxytrackmodel.h (+3/-4)
mixxx/src/library/rhythmbox/rhythmboxfeature.cpp (+6/-4)
mixxx/src/library/rhythmbox/rhythmboxfeature.h (+4/-1)
mixxx/src/library/setlogfeature.cpp (+6/-5)
mixxx/src/library/stardelegate.cpp (+11/-3)
mixxx/src/library/stardelegate.h (+2/-0)
mixxx/src/library/trackcollection.cpp (+28/-14)
mixxx/src/library/trackcollection.h (+12/-1)
mixxx/src/library/trackmodel.h (+18/-12)
mixxx/src/library/traktor/traktorfeature.cpp (+14/-10)
mixxx/src/library/traktor/traktorfeature.h (+8/-3)
mixxx/src/library/treeitem.cpp (+6/-0)
mixxx/src/mixxx.cpp (+56/-27)
mixxx/src/mixxx.h (+2/-1)
mixxx/src/playermanager.cpp (+8/-0)
mixxx/src/soundsourceproxy.h (+1/-1)
mixxx/src/waveform/waveform.h (+1/-1)
mixxx/src/widget/wtracktableview.cpp (+44/-4)
mixxx/src/widget/wtracktableview.h (+4/-0)
To merge this branch: bzr merge lp:~mixxxdevelopers/mixxx/library_features
Reviewer Review Type Date Requested Status
Mixxx Development Team Pending
Review via email: mp+162700@code.launchpad.net

Description of the change

Getting the ball rolling on the code review for Max's library_features work.

To post a comment you must log in.
Revision history for this message
RJ Skerry-Ryan (rryan) wrote :
Download full text (3.2 KiB)

Hey Max -- I know you aren't ready to merge this yet but I gave it a quick skim while getting chromaprint on the build server and thought I'd shoot you some comments:

* DlgPrefPlaylist
  - SQL queries should not be done here -- need to be abstracted away by a DAO.
  - Shouldn't rely on the default DB connection existing -- TrackCollection needs to get passed into DlgPreferences. (We could change the creation order in the future and this code would break -- better to have it enforced by code)

* BaseSqlTableModel::relocateTracks
  - It would be cool if you could handle the use case where you select a whole album and hit relocate. Either maybe auto-magically detecting that the rest of the selected missing files are in the same directory as the first missing one relocated or maybe by letting the user pick a directory if it is clear that all the selected files were in the same directory originally. This would be a handy speedup.

* DirectoryDAO::addDirectory -- I don't see multiple queries so I don't think it needs a transaction.

* DirectoryDAO::relocateDirectory -- the string arguments in these queries are untrusted and need escaping. Use QSqlQuery::bindValue see TrackDAO::updateTrack for an example.

* DirectoryDAO::getDirIds, DirectoryDAO::getDirId -- same comment RE: escaping.

* DirectoryDAO::updateTrackLocations -- same comments re: escaping. Also this sets every track_locations entry to have the directory. Based on the calls to this function I'm not sure that was the intended functionality. What's this function supposed to do?

* TrackDAO::deleteTracksFromFS -- QMessageBox / GUI code shouldn't be in the DAO's (especially if all this code goes to its own thread eventually). Instead, have the caller pass in a list of stuff that you append un-removeable file paths to or something similar.

* TrackDAO -- some of your queries are using strings that need escaping .. you can only use string construction of the query for when you know the values are safe (i.e. a list of numeric IDs that you join together with commas.) or when you are using table names, column names, and other constants. Strings coming from user input (names, directories, paths, etc.) all need escaping.

* I'm scared of adding delete-on-filesystem code to Mixxx. Is it worth it to let the user do that? The cost of failure is huge in loss of user trust.

And now, about checksumming:

Checksumming every file when we add it to the library has to come with a huge performance hit to the library scanner. Have you noticed this? Albert and I considered checksums when we first wrote the SQLite library but didn't go with it because of this issue. I thought it would be a good compromise to do the checksums in the analyser queue (because it would be much less noticed there) and then only use the checksum for re-unification if it is present.

And now some comments about the checksum implementation itself:

* We should store version information about the checksum with it in a checksum_version column or with a unique string prefix to put on the front (I prefer a separate column since separators never end up being as unique as you thought they were).

* RE: md5 -- we probably don't need a c...

Read more...

3264. By Max Linke <kain88@640X4.kel.wh.lokal>

fix cratetablemodel.cpp, library is not shown there is something off

3265. By Max Linke <kain88@640X4.kel.wh.lokal>

disabled previewDeck to make everything work for now

3266. By Max Linke <kain88@640X4.kel.wh.lokal>

reenabled preview deck, fixed temporary view that is created by the tablemodels

3267. By Max Linke <kain88@640X4.kel.wh.lokal>

changed name for chromaprint library in scons

3268. By Max Linke <kain88@640X4.kel.wh.lokal>

added missing files

3269. By Max Linke <kain88@640X4.kel.wh.lokal>

I'm stupid -.-

3270. By Max Linke <kain88@640X4.kel.wh.lokal>

next try for the build server

3271. By RJ Skerry-Ryan

Check for chromaprint_p.

3272. By RJ Skerry-Ryan

Check for chromaprint_p.

3273. By RJ Skerry-Ryan

Try detecting chromaprint after chromaprint_p?

3274. By RJ Skerry-Ryan

Roll-back r3273.

3275. By RJ Skerry-Ryan

Add chromaprint to LIBS manually after CheckLib passes.

3276. By RJ Skerry-Ryan

Add CHROMAPRINT_NODLL to CPPDEFINES.

3277. By RJ Skerry-Ryan

Typo.

3278. By RJ Skerry-Ryan

Only define CHROMAPRINT_NODLL for static_dependencies.

3279. By RJ Skerry-Ryan

Link fftw3 on Windows only.

3280. By Max Linke <kain88@640X4.kel.wh.lokal>

merge with trunk, library scanner does not add songs

3281. By Max Linke <kain88@640X4.kel.wh.lokal>

does launchpad use my email now?

3282. By Max Linke <kain88@640X4.kel.wh.lokal>

next try

3283. By Max Linke <email address hidden>

next try 2

3284. By Max Linke <email address hidden>

removed fringerprinting feature that is moved into chromaprint branch

3285. By Max Linke <email address hidden>

merge with trunk

3286. By Max Linke <email address hidden>

merge with trunk

3287. By Max Linke <email address hidden>

merge with trunk

3288. By Max Linke <email address hidden>

merge with trunk

Unmerged revisions

3288. By Max Linke <email address hidden>

merge with trunk

3287. By Max Linke <email address hidden>

merge with trunk

3286. By Max Linke <email address hidden>

merge with trunk

3285. By Max Linke <email address hidden>

merge with trunk

3284. By Max Linke <email address hidden>

removed fringerprinting feature that is moved into chromaprint branch

3283. By Max Linke <email address hidden>

next try 2

3282. By Max Linke <kain88@640X4.kel.wh.lokal>

next try

3281. By Max Linke <kain88@640X4.kel.wh.lokal>

does launchpad use my email now?

3280. By Max Linke <kain88@640X4.kel.wh.lokal>

merge with trunk, library scanner does not add songs

3279. By RJ Skerry-Ryan

Link fftw3 on Windows only.

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 2013-05-16 01:40:06 +0000
3+++ mixxx/build/depends.py 2013-05-18 16:32:26 +0000
4@@ -569,6 +569,7 @@
5 "library/libraryfeature.cpp",
6 "library/preparefeature.cpp",
7 "library/autodjfeature.cpp",
8+ "library/dao/directorydao.cpp",
9 "library/mixxxlibraryfeature.cpp",
10 "library/baseplaylistfeature.cpp",
11 "library/playlistfeature.cpp",
12
13=== modified file 'mixxx/res/schema.xml'
14--- mixxx/res/schema.xml 2013-05-07 03:17:23 +0000
15+++ mixxx/res/schema.xml 2013-05-18 16:32:26 +0000
16@@ -338,4 +338,18 @@
17 ALTER TABLE Library ADD COLUMN keys_sub_version TEXT;
18 </sql>
19 </revision>
20+ <revision version="19" min_compatible="3">
21+ <description>
22+ Add directories table
23+ </description>
24+ <sql>
25+ CREATE TABLE IF NOT EXISTS directories (
26+ dir_id INTEGER primary key AUTOINCREMENT,
27+ directory varchar(1024)
28+ );
29+ CREATE UNIQUE INDEX directory_idx ON directories(directory);
30+ ALTER TABLE track_locations ADD COLUMN maindir_id INTEGER DEFAULT 0;
31+ ALTER TABLE track_locations ADD COLUMN checksum varchar(1024);
32+ </sql>
33+ </revision>
34 </schema>
35
36=== modified file 'mixxx/src/dlgautodj.cpp'
37--- mixxx/src/dlgautodj.cpp 2013-05-18 16:23:08 +0000
38+++ mixxx/src/dlgautodj.cpp 2013-05-18 16:32:26 +0000
39@@ -43,14 +43,17 @@
40 box->insertWidget(1, m_pTrackTableView);
41
42 m_pAutoDJTableModel = new PlaylistTableModel(this, pTrackCollection,
43- "mixxx.db.model.autodj");
44+ "mixxx.db.model.autodj",
45+ m_pConfig);
46+ connect(this, SIGNAL(configChanged(QString,QString)),
47+ m_pAutoDJTableModel, SLOT(slotConfigChanged(QString,QString)));
48 PlaylistDAO& playlistDao = pTrackCollection->getPlaylistDAO();
49 int playlistId = playlistDao.getPlaylistIdFromName(AUTODJ_TABLE);
50 if (playlistId < 0) {
51 playlistId = playlistDao.createPlaylist(AUTODJ_TABLE,
52 PlaylistDAO::PLHT_AUTO_DJ);
53 }
54- m_pAutoDJTableModel->setPlaylist(playlistId);
55+ m_pAutoDJTableModel->setTableModel(playlistId);
56 m_pTrackTableView->loadTrackModel(m_pAutoDJTableModel);
57
58 // Override some playlist-view properties:
59
60=== modified file 'mixxx/src/dlgautodj.h'
61--- mixxx/src/dlgautodj.h 2013-04-12 15:27:07 +0000
62+++ mixxx/src/dlgautodj.h 2013-05-18 16:32:26 +0000
63@@ -47,6 +47,7 @@
64
65 signals:
66 void loadTrack(TrackPointer tio);
67+ void configChanged(QString,QString);
68 void loadTrackToPlayer(TrackPointer tio, QString group, bool);
69
70 private:
71
72=== modified file 'mixxx/src/dlgpreferences.cpp'
73--- mixxx/src/dlgpreferences.cpp 2013-05-12 10:15:29 +0000
74+++ mixxx/src/dlgpreferences.cpp 2013-05-18 16:32:26 +0000
75@@ -80,6 +80,11 @@
76 addPageWidget(m_wsound);
77 m_wplaylist = new DlgPrefPlaylist(this, config);
78 addPageWidget(m_wplaylist);
79+ connect(m_wplaylist, SIGNAL(configChanged(QString,QString)),
80+ this, SIGNAL(configChanged(QString,QString)));
81+ connect(m_wplaylist, SIGNAL(dirsChanged(QString,QString)),
82+ this, SIGNAL(dirsChanged(QString,QString)));
83+
84 m_wcontrols = new DlgPrefControls(this, mixxx, pSkinLoader, pPlayerManager, config);
85 addPageWidget(m_wcontrols);
86 m_weq = new DlgPrefEQ(this, config);
87
88=== modified file 'mixxx/src/dlgpreferences.h'
89--- mixxx/src/dlgpreferences.h 2013-05-12 10:15:29 +0000
90+++ mixxx/src/dlgpreferences.h 2013-05-18 16:32:26 +0000
91@@ -74,6 +74,8 @@
92 signals:
93 void closeDlg();
94 void showDlg();
95+ void configChanged(QString, QString);
96+ void dirsChanged(QString, QString);
97 protected:
98 bool eventFilter(QObject*, QEvent*);
99 private:
100
101=== modified file 'mixxx/src/dlgprefplaylist.cpp'
102--- mixxx/src/dlgprefplaylist.cpp 2013-05-18 16:23:08 +0000
103+++ mixxx/src/dlgprefplaylist.cpp 2013-05-18 16:32:26 +0000
104@@ -15,6 +15,9 @@
105 * *
106 ***************************************************************************/
107
108+#include <QSqlDatabase>
109+#include <QSqlQuery>
110+#include <QSqlRecord>
111 #include <QUrl>
112 #include <QDesktopServices>
113 #include <QFileDialog>
114@@ -30,6 +33,8 @@
115
116 DlgPrefPlaylist::DlgPrefPlaylist(QWidget * parent, ConfigObject<ConfigValue> * config)
117 : QWidget(parent),
118+ m_model(),
119+ m_dirsModified(false),
120 m_pconfig(config) {
121 setupUi(this);
122 slotUpdate();
123@@ -51,6 +56,10 @@
124
125 connect(PushButtonBrowsePlaylist, SIGNAL(clicked()),
126 this, SLOT(slotBrowseDir()));
127+ connect(PushButtonRemovePlaylist, SIGNAL(clicked()),
128+ this, SLOT(slotRemoveDir()));
129+ connect(pushButton_2, SIGNAL(clicked()),
130+ this, SLOT(slotRelocateDir()));
131 //connect(pushButtonM4A, SIGNAL(clicked()), this, SLOT(slotM4ACheck()));
132 connect(pushButtonExtraPlugins, SIGNAL(clicked()),
133 this, SLOT(slotExtraPlugins()));
134@@ -74,6 +83,40 @@
135 DlgPrefPlaylist::~DlgPrefPlaylist() {
136 }
137
138+bool DlgPrefPlaylist::initializeModel(){
139+ // this will hook into the default connection, so we don't need to
140+ // provide anymore information. This works because the Library is
141+ // created before the Preferences and a connection already exists.
142+ // --kain88 July 2012
143+ QSqlDatabase database = QSqlDatabase::database();
144+ QSqlQuery query;
145+ query.prepare("SELECT directory from directories");
146+ if (!query.exec()) {
147+ qDebug() << "damn there are no directories to display";
148+ return false;
149+ }
150+ // save which index was selected
151+ const int selected = list->currentIndex().row();
152+ m_model.clear();
153+ while(query.next()){
154+ QStandardItem* pitem = new QStandardItem(
155+ query.value(query.record().indexOf("directory"))
156+ .toString());
157+ m_model.appendRow(pitem);
158+ }
159+ list->setModel(&m_model);
160+ // first select the first index then change it to selected if it still exists
161+ list->setCurrentIndex(list->model()->index(0, 0));
162+ for (int i=0 ; i<list->model()->rowCount() ; ++i) {
163+ const QModelIndex index = list->model()->index(i, 0);
164+ if (index.row() == selected) {
165+ list->setCurrentIndex(index);
166+ break;
167+ }
168+ }
169+ return true;
170+}
171+
172 void DlgPrefPlaylist::slotExtraPlugins() {
173 QDesktopServices::openUrl(QUrl(MIXXX_ADDONS_URL));
174 }
175@@ -141,9 +184,8 @@
176 }*/
177
178 void DlgPrefPlaylist::slotUpdate() {
179- // Library Path
180- LineEditSongfiles->setText(m_pconfig->getValueString(
181- ConfigKey("[Playlist]","Directory")));
182+ // Song path
183+ initializeModel();
184 //Bundled songs stat tracking
185 checkBoxPromoStats->setChecked((bool)m_pconfig->getValueString(
186 ConfigKey("[Promo]","StatTracking")).toInt());
187@@ -159,14 +201,41 @@
188 ConfigKey("[Library]","ShowITunesLibrary"),"1").toInt());
189 checkBox_show_traktor->setChecked((bool)m_pconfig->getValueString(
190 ConfigKey("[Library]","ShowTraktorLibrary"),"1").toInt());
191+ checkBox_show_missing->setChecked((bool)m_pconfig->getValueString(
192+ ConfigKey("[Library]","ShowMissingSongs"),"1").toInt());
193 }
194
195 void DlgPrefPlaylist::slotBrowseDir() {
196 QString fd = QFileDialog::getExistingDirectory(this,
197- tr("Choose music library directory"),
198- m_pconfig->getValueString(ConfigKey("[Playlist]","Directory")));
199+ tr("Choose music library directory"),
200+ QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
201 if (fd != "") {
202- LineEditSongfiles->setText(fd);
203+ emit(dirsChanged("added",fd));
204+ slotUpdate();
205+ m_dirsModified = true;
206+ }
207+}
208+
209+void DlgPrefPlaylist::slotRemoveDir() {
210+ QModelIndex index = list->currentIndex();
211+ QString fd = index.data().toString();
212+ emit(dirsChanged("removed",fd));
213+ slotUpdate();
214+ m_dirsModified = true;
215+}
216+
217+void DlgPrefPlaylist::slotRelocateDir() {
218+ QModelIndex index = list->currentIndex();
219+ QString currentFd = index.data().toString();
220+ QString fd = QFileDialog::getExistingDirectory(this,
221+ tr("Choose music library directory"),
222+ QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
223+
224+ //use !(~)! as a sign where the string has to be seperated later
225+ if(!fd.isEmpty()){
226+ emit(dirsChanged("relocate",fd+"!(~)!"+currentFd));
227+ slotUpdate();
228+ m_dirsModified = true;
229 }
230 }
231
232@@ -186,10 +255,19 @@
233 m_pconfig->set(ConfigKey("[Library]","ShowTraktorLibrary"),
234 ConfigValue((int)checkBox_show_traktor->isChecked()));
235
236- if (LineEditSongfiles->text() !=
237- m_pconfig->getValueString(ConfigKey("[Playlist]","Directory"))) {
238- m_pconfig->set(ConfigKey("[Playlist]","Directory"), LineEditSongfiles->text());
239+ // Update playlist if path has changed
240+ if (m_dirsModified) {
241 emit(apply());
242 }
243+
244+ //update TM if ShowMissingSongs has changed
245+ if ((int)checkBox_show_missing->isChecked() != m_pconfig->getValueString(
246+ ConfigKey("[Library]",
247+ "ShowMissingSongs"),"1").toInt()) {
248+ m_pconfig->set(ConfigKey("[Library]","ShowMissingSongs"),
249+ ConfigValue((int)checkBox_show_missing->isChecked()));
250+
251+ emit(configChanged("[Library]","ShowMissingSongs"));
252+ }
253 m_pconfig->Save();
254 }
255
256=== modified file 'mixxx/src/dlgprefplaylist.h'
257--- mixxx/src/dlgprefplaylist.h 2013-05-18 16:23:08 +0000
258+++ mixxx/src/dlgprefplaylist.h 2013-05-18 16:32:26 +0000
259@@ -18,6 +18,8 @@
260 #ifndef DLGPREFPLAYLIST_H
261 #define DLGPREFPLAYLIST_H
262
263+#include <QStandardItemModel>
264+
265 #include "ui_dlgprefplaylistdlg.h"
266 #include "configobject.h"
267
268@@ -37,6 +39,8 @@
269 void slotUpdate();
270 // Dialog to browse for music file directory
271 void slotBrowseDir();
272+ void slotRemoveDir();
273+ void slotRelocateDir();
274 // Apply changes to widget
275 void slotApply();
276 // Starts up the PluginDownloader if the plugin isn't present
277@@ -53,8 +57,13 @@
278
279 signals:
280 void apply();
281+ void configChanged(QString, QString);
282+ void dirsChanged(QString, QString);
283
284 private:
285+ bool initializeModel();
286+ QStandardItemModel m_model;
287+ bool m_dirsModified;
288 ConfigObject<ConfigValue> *m_pconfig;
289 // SoundSource Plugin Downloader
290 //PluginDownloader* m_pPluginDownloader;
291
292=== modified file 'mixxx/src/dlgprefplaylistdlg.ui'
293--- mixxx/src/dlgprefplaylistdlg.ui 2012-12-09 17:41:04 +0000
294+++ mixxx/src/dlgprefplaylistdlg.ui 2013-05-18 16:32:26 +0000
295@@ -41,30 +41,47 @@
296 <bool>false</bool>
297 </property>
298 <property name="buddy">
299- <cstring>LineEditSongfiles</cstring>
300- </property>
301- </widget>
302- </item>
303- <item row="0" column="1">
304- <widget class="QLineEdit" name="LineEditSongfiles">
305- <property name="minimumSize">
306+ <cstring>list</cstring>
307+ </property>
308+ </widget>
309+ </item>
310+ <item row="3" column="1">
311+ <widget class="QPushButton" name="PushButtonRemovePlaylist">
312+ <property name="font">
313+ <font/>
314+ </property>
315+ <property name="text">
316+ <string>Remove</string>
317+ </property>
318+ </widget>
319+ </item>
320+ <item row="1" column="0" rowspan="3">
321+ <widget class="QListView" name="list">
322+ <property name="iconSize">
323 <size>
324- <width>100</width>
325- <height>10</height>
326+ <width>16</width>
327+ <height>16</height>
328 </size>
329 </property>
330- <property name="font">
331- <font/>
332+ <property name="uniformItemSizes">
333+ <bool>true</bool>
334 </property>
335 </widget>
336 </item>
337- <item row="0" column="2">
338+ <item row="1" column="1">
339 <widget class="QPushButton" name="PushButtonBrowsePlaylist">
340 <property name="font">
341 <font/>
342 </property>
343 <property name="text">
344- <string>Browse...</string>
345+ <string>Add</string>
346+ </property>
347+ </widget>
348+ </item>
349+ <item row="2" column="1">
350+ <widget class="QPushButton" name="pushButton_2">
351+ <property name="text">
352+ <string>Relocate</string>
353 </property>
354 </widget>
355 </item>
356@@ -181,6 +198,16 @@
357 </property>
358 </widget>
359 </item>
360+ <item row="4" column="0">
361+ <widget class="QCheckBox" name="checkBox_show_missing">
362+ <property name="text">
363+ <string>Show Missing Songs</string>
364+ </property>
365+ <property name="checked">
366+ <bool>true</bool>
367+ </property>
368+ </widget>
369+ </item>
370 </layout>
371 </widget>
372 </item>
373@@ -230,19 +257,6 @@
374 </layout>
375 </widget>
376 </item>
377- <item>
378- <spacer name="verticalSpacer">
379- <property name="orientation">
380- <enum>Qt::Vertical</enum>
381- </property>
382- <property name="sizeHint" stdset="0">
383- <size>
384- <width>20</width>
385- <height>40</height>
386- </size>
387- </property>
388- </spacer>
389- </item>
390 </layout>
391 </widget>
392 <layoutdefault spacing="6" margin="11"/>
393
394=== modified file 'mixxx/src/dlgprefrecord.cpp'
395--- mixxx/src/dlgprefrecord.cpp 2013-05-15 06:09:40 +0000
396+++ mixxx/src/dlgprefrecord.cpp 2013-05-18 16:32:26 +0000
397@@ -47,10 +47,7 @@
398 if (recordingsPath == "") {
399 // Initialize recordings path in config to old default path.
400 // Do it here so we show current value in UI correctly.
401- QString musicDir = config->getValueString(ConfigKey("[Playlist]","Directory"));
402- if (musicDir.isEmpty()) {
403- musicDir = QDesktopServices::storageLocation(QDesktopServices::MusicLocation);
404- }
405+ QString musicDir = QDesktopServices::storageLocation(QDesktopServices::MusicLocation);
406 QDir recordDir(musicDir + "/Mixxx/Recordings");
407 recordingsPath = recordDir.absolutePath();
408 }
409
410=== modified file 'mixxx/src/library/autodjfeature.cpp'
411--- mixxx/src/library/autodjfeature.cpp 2013-05-12 22:17:32 +0000
412+++ mixxx/src/library/autodjfeature.cpp 2013-05-18 16:32:26 +0000
413@@ -45,6 +45,8 @@
414 libraryWidget->registerView(m_sAutoDJViewName, m_pAutoDJView);
415 connect(m_pAutoDJView, SIGNAL(loadTrack(TrackPointer)),
416 this, SIGNAL(loadTrack(TrackPointer)));
417+ connect(this, SIGNAL(configChanged(QString,QString)),
418+ m_pAutoDJView, SIGNAL(configChanged(QString,QString)));
419 connect(m_pAutoDJView, SIGNAL(loadTrackToPlayer(TrackPointer, QString, bool)),
420 this, SIGNAL(loadTrackToPlayer(TrackPointer, QString, bool)));
421 }
422
423=== modified file 'mixxx/src/library/autodjfeature.h'
424--- mixxx/src/library/autodjfeature.h 2012-12-12 17:23:33 +0000
425+++ mixxx/src/library/autodjfeature.h 2013-05-18 16:32:26 +0000
426@@ -35,6 +35,9 @@
427
428 TreeItemModel* getChildModel();
429
430+ signals:
431+ void configChanged(QString,QString);
432+
433 public slots:
434 void activate();
435
436
437=== modified file 'mixxx/src/library/baseexternalplaylistmodel.cpp'
438--- mixxx/src/library/baseexternalplaylistmodel.cpp 2012-11-25 11:17:13 +0000
439+++ mixxx/src/library/baseexternalplaylistmodel.cpp 2013-05-18 16:32:26 +0000
440@@ -6,10 +6,10 @@
441 BaseExternalPlaylistModel::BaseExternalPlaylistModel(
442 QObject* parent, TrackCollection* pTrackCollection,
443 QString settingsNamespace, QString playlistsTable,
444- QString playlistTracksTable, QString trackSource)
445+ QString playlistTracksTable, QString trackSource,
446+ ConfigObject<ConfigValue>* pConfig)
447 : BaseSqlTableModel(parent, pTrackCollection,
448- pTrackCollection->getDatabase(),
449- settingsNamespace),
450+ pConfig, settingsNamespace),
451 m_playlistsTable(playlistsTable),
452 m_playlistTracksTable(playlistTracksTable),
453 m_trackSource(trackSource),
454
455=== modified file 'mixxx/src/library/baseexternalplaylistmodel.h'
456--- mixxx/src/library/baseexternalplaylistmodel.h 2012-11-22 06:59:01 +0000
457+++ mixxx/src/library/baseexternalplaylistmodel.h 2013-05-18 16:32:26 +0000
458@@ -10,13 +10,15 @@
459 #include "library/librarytablemodel.h"
460 #include "library/dao/playlistdao.h"
461 #include "library/dao/trackdao.h"
462+#include "configobject.h"
463
464 class BaseExternalPlaylistModel : public BaseSqlTableModel {
465 Q_OBJECT
466 public:
467 BaseExternalPlaylistModel(QObject* pParent, TrackCollection* pTrackCollection,
468 QString settingsNamespace, QString playlistsTable,
469- QString playlistTracksTable, QString trackSource);
470+ QString playlistTracksTable, QString trackSource,
471+ ConfigObject<ConfigValue>* pConfig);
472 virtual ~BaseExternalPlaylistModel();
473
474 virtual TrackPointer getTrack(const QModelIndex& index) const;
475
476=== modified file 'mixxx/src/library/baseexternaltrackmodel.cpp'
477--- mixxx/src/library/baseexternaltrackmodel.cpp 2012-11-25 11:17:13 +0000
478+++ mixxx/src/library/baseexternaltrackmodel.cpp 2013-05-18 16:32:26 +0000
479@@ -6,10 +6,10 @@
480 TrackCollection* pTrackCollection,
481 QString settingsNamespace,
482 QString trackTable,
483- QString trackSource)
484+ QString trackSource,
485+ ConfigObject<ConfigValue>* pConfig)
486 : BaseSqlTableModel(parent, pTrackCollection,
487- pTrackCollection->getDatabase(),
488- settingsNamespace),
489+ pConfig, settingsNamespace),
490 m_pTrackCollection(pTrackCollection),
491 m_database(m_pTrackCollection->getDatabase()) {
492 connect(this, SIGNAL(doSearch(const QString&)),
493
494=== modified file 'mixxx/src/library/baseexternaltrackmodel.h'
495--- mixxx/src/library/baseexternaltrackmodel.h 2012-11-22 06:59:01 +0000
496+++ mixxx/src/library/baseexternaltrackmodel.h 2013-05-18 16:32:26 +0000
497@@ -9,6 +9,7 @@
498 #include "library/trackmodel.h"
499 #include "library/basesqltablemodel.h"
500 #include "trackinfoobject.h"
501+#include "configobject.h"
502
503 class TrackCollection;
504
505@@ -18,7 +19,8 @@
506 BaseExternalTrackModel(QObject* parent, TrackCollection* pTrackCollection,
507 QString settingsNamespace,
508 QString trackTable,
509- QString trackSource);
510+ QString trackSource,
511+ ConfigObject<ConfigValue>* pConfig);
512 virtual ~BaseExternalTrackModel();
513
514 TrackModel::CapabilitiesFlags getCapabilities() const;
515
516=== modified file 'mixxx/src/library/baseplaylistfeature.cpp'
517--- mixxx/src/library/baseplaylistfeature.cpp 2013-05-12 22:17:32 +0000
518+++ mixxx/src/library/baseplaylistfeature.cpp 2013-05-18 16:32:26 +0000
519@@ -22,6 +22,7 @@
520 m_trackDao(pTrackCollection->getTrackDAO()),
521 m_pPlaylistTableModel(NULL),
522 m_rootViewName(rootViewName) {
523+
524 m_pCreatePlaylistAction = new QAction(tr("New Playlist"),this);
525 connect(m_pCreatePlaylistAction, SIGNAL(triggered()),
526 this, SLOT(slotCreatePlaylist()));
527@@ -96,7 +97,7 @@
528 QString playlistName = index.data().toString();
529 int playlistId = m_playlistDao.getPlaylistIdFromName(playlistName);
530 if (m_pPlaylistTableModel) {
531- m_pPlaylistTableModel->setPlaylist(playlistId);
532+ m_pPlaylistTableModel->setTableModel(playlistId);
533 emit(showTrackModel(m_pPlaylistTableModel));
534 }
535 }
536@@ -337,11 +338,12 @@
537 }
538
539 // Create a new table model since the main one might have an active search.
540+ // This PTM will only use tracks that are not deleted from the FS
541 QScopedPointer<PlaylistTableModel> pPlaylistTableModel(
542 new PlaylistTableModel(this, m_pTrackCollection,
543- "mixxx.db.model.playlist_export"));
544+ "mixxx.db.model.playlist_export", m_pConfig));
545
546- pPlaylistTableModel->setPlaylist(m_pPlaylistTableModel->getPlaylist());
547+ pPlaylistTableModel->setTableModel(m_pPlaylistTableModel->getPlaylist());
548 pPlaylistTableModel->setSort(pPlaylistTableModel->fieldIndex(PLAYLISTTRACKSTABLE_POSITION), Qt::AscendingOrder);
549 pPlaylistTableModel->select();
550
551@@ -476,4 +478,3 @@
552 void BasePlaylistFeature::clearChildModel() {
553 m_childModel.removeRows(0, m_playlistList.size());
554 }
555-
556
557=== modified file 'mixxx/src/library/baseplaylistfeature.h'
558--- mixxx/src/library/baseplaylistfeature.h 2013-02-23 10:40:40 +0000
559+++ mixxx/src/library/baseplaylistfeature.h 2013-05-18 16:32:26 +0000
560@@ -76,7 +76,6 @@
561
562 private:
563 virtual QString getRootViewHtml() const = 0;
564-
565 QString m_rootViewName;
566 };
567
568
569=== modified file 'mixxx/src/library/basesqltablemodel.cpp'
570--- mixxx/src/library/basesqltablemodel.cpp 2013-05-14 22:25:44 +0000
571+++ mixxx/src/library/basesqltablemodel.cpp 2013-05-18 16:32:26 +0000
572@@ -20,16 +20,17 @@
573
574 BaseSqlTableModel::BaseSqlTableModel(QObject* pParent,
575 TrackCollection* pTrackCollection,
576- QSqlDatabase db,
577+ ConfigObject<ConfigValue>* pConfig,
578 QString settingsNamespace)
579 : QAbstractTableModel(pParent),
580- TrackModel(db, settingsNamespace),
581- m_currentSearch(""),
582+ TrackModel(pTrackCollection->getDatabase(), settingsNamespace),
583 m_previewDeckGroup(PlayerManager::groupForPreviewDeck(0)),
584 m_iPreviewDeckTrackId(-1),
585 m_pTrackCollection(pTrackCollection),
586 m_trackDAO(m_pTrackCollection->getTrackDAO()),
587- m_database(db) {
588+ m_pConfig(pConfig),
589+ m_currentSearch(""),
590+ m_database(pTrackCollection->getDatabase()) {
591 m_bInitialized = false;
592 m_bDirty = true;
593 m_iSortColumn = 0;
594@@ -214,7 +215,6 @@
595
596 QLinkedList<int> tableColumnIndices;
597 foreach (QString column, m_tableColumns) {
598- Q_ASSERT(record.indexOf(column) == m_tableColumnIndex[column]);
599 tableColumnIndices.push_back(record.indexOf(column));
600 }
601
602@@ -227,6 +227,8 @@
603 QSet<int> trackIds;
604 while (query.next()) {
605 int id = query.value(idColumn).toInt();
606+
607+
608 trackIds.insert(id);
609
610 RowInfo thisRowInfo;
611@@ -359,7 +361,7 @@
612 m_bDirty = true;
613 }
614
615-void BaseSqlTableModel::search(const QString& searchText, const QString extraFilter) {
616+void BaseSqlTableModel::search(const QString& searchText, const QString& extraFilter) {
617 if (sDebug) {
618 qDebug() << this << "search" << searchText;
619 }
620@@ -436,7 +438,8 @@
621 if (!index.isValid() || (role != Qt::DisplayRole &&
622 role != Qt::EditRole &&
623 role != Qt::CheckStateRole &&
624- role != Qt::ToolTipRole)) {
625+ role != Qt::ToolTipRole &&
626+ role != Qt::BackgroundColorRole)) {
627 return QVariant();
628 }
629
630@@ -451,6 +454,13 @@
631 // role
632 switch (role) {
633 case Qt::ToolTipRole:
634+ if(index.sibling(index.row(),
635+ fieldIndex(TRACKLOCATIONSTABLE_FSDELETED)).data().toInt()==1){
636+ QString warning(tr("No such file at : "));
637+ value = QVariant(QString(warning+index.sibling(index.row(),
638+ fieldIndex(LIBRARYTABLE_LOCATION)).data().toString()));
639+ }
640+ break;
641 case Qt::DisplayRole:
642 if (column == fieldIndex(LIBRARYTABLE_DURATION)) {
643 if (qVariantCanConvert<int>(value)) {
644@@ -499,6 +509,14 @@
645 value = locked ? Qt::Checked : Qt::Unchecked;
646 }
647 break;
648+ case Qt::BackgroundColorRole:
649+ if (index.sibling(index.row(),
650+ fieldIndex(TRACKLOCATIONSTABLE_FSDELETED)).data().toInt()==1){
651+ //TODO kain88 choose a better looking color, this will also
652+ // have to be changed in stardelegate
653+ value = QVariant(QColor(Qt::red));
654+ }
655+ break;
656 default:
657 break;
658 }
659@@ -626,6 +644,10 @@
660 return index.sibling(index.row(), fieldIndex(m_idColumn)).data().toInt();
661 }
662
663+TrackPointer BaseSqlTableModel::getTrack(const QModelIndex& index) const {
664+ return m_trackDAO.getTrack(getTrackId(index));
665+}
666+
667 QString BaseSqlTableModel::getTrackLocation(const QModelIndex& index) const {
668 if (!index.isValid()) {
669 return "";
670@@ -656,7 +678,6 @@
671 if (sDebug) {
672 qDebug() << this << "trackChanged" << trackIds.size();
673 }
674-
675 const int numColumns = columnCount();
676 foreach (int trackId, trackIds) {
677 QLinkedList<int> rows = getTrackRows(trackId);
678@@ -717,7 +738,8 @@
679 const QModelIndex& index, int role) const {
680 if (role != Qt::DisplayRole &&
681 role != Qt::ToolTipRole &&
682- role != Qt::EditRole) {
683+ role != Qt::EditRole &&
684+ role != Qt::BackgroundColorRole) {
685 return QVariant();
686 }
687
688@@ -822,3 +844,51 @@
689 // there.
690 select(); //Repopulate the data model.
691 }
692+
693+void BaseSqlTableModel::slotConfigChanged(QString identifier, QString key){
694+ Q_UNUSED(identifier);
695+ if (key=="ShowMissingSongs") {
696+ setTableModel();
697+ select();
698+ }
699+}
700+
701+void BaseSqlTableModel::setTableModel(int id) {
702+ Q_UNUSED(id);
703+}
704+
705+void BaseSqlTableModel::relocateTracks(const QModelIndexList& indices) {
706+ foreach (QModelIndex index, indices) {
707+ int trackId = getTrackId(index);
708+ TrackPointer ptrack = m_trackDAO.getTrack(trackId);
709+ if (!ptrack) {
710+ qDebug() << "strange I can't get that thing";
711+ }
712+ QString newLocation = QFileDialog::getOpenFileName(QApplication::desktop(),
713+ QString(ptrack->getTitle()),
714+ ptrack->getLocation());
715+
716+ if (!newLocation.isEmpty()) {
717+ if (!m_trackDAO.relocateTrack(ptrack, newLocation)) {
718+ QMessageBox::warning(NULL, tr("Mixxx"),
719+ tr("The track could not be relocated"));
720+ }
721+ }
722+ }
723+ setTableModel();
724+ select();
725+}
726+
727+bool BaseSqlTableModel::isColumnInternal(int column) {
728+ Q_UNUSED(column);
729+ return false;
730+}
731+
732+bool BaseSqlTableModel::isColumnHiddenByDefault(int column) {
733+ Q_UNUSED(column);
734+ return false;
735+}
736+
737+TrackModel::CapabilitiesFlags BaseSqlTableModel::getCapabilities() const {
738+ return TRACKMODELCAPS_NONE;
739+}
740
741=== modified file 'mixxx/src/library/basesqltablemodel.h'
742--- mixxx/src/library/basesqltablemodel.h 2013-01-17 08:16:08 +0000
743+++ mixxx/src/library/basesqltablemodel.h 2013-05-18 16:32:26 +0000
744@@ -22,21 +22,43 @@
745 public:
746 BaseSqlTableModel(QObject* pParent,
747 TrackCollection* pTrackCollection,
748- QSqlDatabase db, QString settingsNamespace);
749+ ConfigObject<ConfigValue>* pConfig,
750+ QString settingsNamespace);
751 virtual ~BaseSqlTableModel();
752
753- ////////////////////////////////////////////////////////////////////////////
754- // Methods implemented from QAbstractItemModel
755- ////////////////////////////////////////////////////////////////////////////
756-
757- virtual void sort(int column, Qt::SortOrder order);
758- virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
759- virtual bool setData(const QModelIndex& index, const QVariant& value, int role=Qt::EditRole);
760- virtual int columnCount(const QModelIndex& parent=QModelIndex()) const;
761- virtual int rowCount(const QModelIndex& parent=QModelIndex()) const;
762- virtual bool setHeaderData(int section, Qt::Orientation orientation,
763+ // functions that HAVE to be implemented in a child class
764+ virtual void setTableModel(int id=-1);
765+ virtual bool isColumnInternal(int column);
766+ virtual bool isColumnHiddenByDefault(int column);
767+ virtual TrackModel::CapabilitiesFlags getCapabilities() const;
768+ // calls readWriteFlags() by default, reimplement this if the child calls
769+ // should be readOnly
770+ virtual Qt::ItemFlags flags(const QModelIndex &index) const;
771+ // function to reimplement for external libraries
772+ virtual TrackPointer getTrack(const QModelIndex& index) const;
773+
774+ // Other public methods
775+ int getTrackId(const QModelIndex& index) const;
776+ void search(const QString& searchText, const QString& extraFilter=QString());
777+ void setSearch(const QString& searchText, const QString extraFilter=QString());
778+ const QString currentSearch() const;
779+ void setSort(int column, Qt::SortOrder order);
780+ int fieldIndex(const QString& fieldName) const;
781+ void select();
782+ QString getTrackLocation(const QModelIndex& index) const;
783+ QAbstractItemDelegate* delegateForColumn(const int i, QObject* pParent);
784+ void relocateTracks(const QModelIndexList& indices);
785+ void hideTracks(const QModelIndexList& indices);
786+
787+ // Methods reimplemented from QAbstractItemModel
788+ void sort(int column, Qt::SortOrder order);
789+ int rowCount(const QModelIndex& parent=QModelIndex()) const;
790+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
791+ bool setData(const QModelIndex& index, const QVariant& value, int role=Qt::EditRole);
792+ int columnCount(const QModelIndex& parent=QModelIndex()) const;
793+ bool setHeaderData(int section, Qt::Orientation orientation,
794 const QVariant &value, int role=Qt::EditRole);
795- virtual QVariant headerData(int section, Qt::Orientation orientation,
796+ QVariant headerData(int section, Qt::Orientation orientation,
797 int role=Qt::DisplayRole) const;
798 virtual QMimeData* mimeData(const QModelIndexList &indexes) const;
799
800@@ -44,44 +66,33 @@
801 // Other public methods
802 ////////////////////////////////////////////////////////////////////////////
803
804- virtual void search(const QString& searchText, const QString extraFilter=QString());
805- virtual void setSearch(const QString& searchText, const QString extraFilter=QString());
806- virtual const QString currentSearch() const;
807- virtual void setSort(int column, Qt::SortOrder order);
808- virtual int fieldIndex(const QString& fieldName) const;
809- virtual void select();
810- virtual int getTrackId(const QModelIndex& index) const;
811- virtual QString getTrackLocation(const QModelIndex& index) const;
812- virtual QAbstractItemDelegate* delegateForColumn(const int i, QObject* pParent);
813- virtual void hideTracks(const QModelIndexList& indices);
814 // Returns true if the BaseSqlTableModel has been initialized. Calling data
815 // access methods on a BaseSqlTableModel which is not initialized is likely
816 // to cause instability / crashes.
817 bool initialized() const { return m_bInitialized; }
818
819- protected:
820+ protected://functions
821 // Returns the row of trackId in this result set. If trackId is not present,
822 // returns -1.
823- virtual const QLinkedList<int> getTrackRows(int trackId) const;
824-
825- virtual void setTable(const QString& tableName,
826- const QString& trackIdColumn,
827- const QStringList& tableColumns,
828- QSharedPointer<BaseTrackCache> trackSource);
829- QSqlDatabase database() const;
830-
831- /** Use this if you want a model that is read-only. */
832- virtual Qt::ItemFlags readOnlyFlags(const QModelIndex &index) const;
833- /** Use this if you want a model that can be changed */
834- virtual Qt::ItemFlags readWriteFlags(const QModelIndex &index) const;
835- /** calls readWriteFlags() by default */
836- virtual Qt::ItemFlags flags(const QModelIndex &index) const;
837-
838- // Set the columns used for searching. Names must correspond to the column
839- // names in the table provided to setTable. Must be called after setTable is
840- // called.
841- virtual QString orderByClause() const;
842- virtual void initHeaderData();
843+ const QLinkedList<int> getTrackRows(int trackId) const;
844+ void setTable(const QString& tableName, const QString& trackIdColumn,
845+ const QStringList& tableColumns,
846+ QSharedPointer<BaseTrackCache> trackSource);
847+ void initHeaderData();
848+
849+ // Use this if you want a model that is read-only.
850+ Qt::ItemFlags readOnlyFlags(const QModelIndex &index) const;
851+ // Use this if you want a model that can be changed
852+ Qt::ItemFlags readWriteFlags(const QModelIndex &index) const;
853+
854+ //variables
855+ TrackCollection* m_pTrackCollection;
856+ TrackDAO& m_trackDAO;
857+ ConfigObject<ConfigValue>* m_pConfig;
858+ QSqlDatabase m_database;
859+
860+ protected slots:
861+ void slotConfigChanged(QString,QString);
862
863 private slots:
864 void tracksChanged(QSet<int> trackIds);
865@@ -90,6 +101,11 @@
866 private:
867 inline void setTrackValueForColumn(TrackPointer pTrack, int column, QVariant value);
868 QVariant getBaseValue(const QModelIndex& index, int role = Qt::DisplayRole) const;
869+ // Set the columns used for searching. Names must correspond to the column
870+ // names in the table provided to setTable. Must be called after setTable is
871+ // called.
872+ QString orderByClause() const;
873+ QSqlDatabase database() const;
874
875 struct RowInfo {
876 int trackId;
877@@ -106,6 +122,7 @@
878 return order < other.order;
879 }
880 };
881+ QVector<RowInfo> m_rowInfo;
882
883 QString m_tableName;
884 QString m_idColumn;
885@@ -120,7 +137,6 @@
886 bool m_bInitialized;
887 bool m_bDirty;
888 QSqlRecord m_queryRecord;
889- QVector<RowInfo> m_rowInfo;
890 QHash<int, int> m_trackSortOrder;
891 QHash<int, QLinkedList<int> > m_trackIdToRows;
892
893@@ -132,10 +148,6 @@
894
895 QVector<QHash<int, QVariant> > m_headerInfo;
896
897- TrackCollection* m_pTrackCollection;
898- TrackDAO& m_trackDAO;
899- QSqlDatabase m_database;
900-
901 DISALLOW_COPY_AND_ASSIGN(BaseSqlTableModel);
902 };
903
904
905=== modified file 'mixxx/src/library/basetrackcache.cpp'
906--- mixxx/src/library/basetrackcache.cpp 2013-04-25 04:56:07 +0000
907+++ mixxx/src/library/basetrackcache.cpp 2013-05-18 16:32:26 +0000
908@@ -87,6 +87,7 @@
909 qDebug() << this << "slotTracksAdded" << trackIds.size();
910 }
911 updateTracksInIndex(trackIds);
912+ buildIndex();
913 }
914
915 void BaseTrackCache::slotDbTrackAdded(TrackPointer pTrack) {
916@@ -118,6 +119,7 @@
917 }
918 QSet<int> trackIds;
919 trackIds.insert(trackId);
920+ updateTracksInIndex(trackIds);
921 emit(tracksChanged(trackIds));
922 }
923
924
925=== modified file 'mixxx/src/library/browse/browsefeature.cpp'
926--- mixxx/src/library/browse/browsefeature.cpp 2013-01-01 11:53:13 +0000
927+++ mixxx/src/library/browse/browsefeature.cpp 2013-05-18 16:32:26 +0000
928@@ -29,7 +29,12 @@
929 m_pConfig(pConfig),
930 m_browseModel(this, pTrackCollection, pRecordingManager),
931 m_proxyModel(&m_browseModel),
932- m_pTrackCollection(pTrackCollection) {
933+ m_pAddtoLibraryAction(NULL),
934+ m_pLastRightClickedItem(NULL),
935+ m_pTrackCollection(pTrackCollection){
936+
937+ connect(this, SIGNAL(dirsChanged(QString,QString)),
938+ parent, SLOT(slotDirsChanged(QString,QString)));
939
940 m_pAddQuickLinkAction = new QAction(tr("Add to Quick Links"),this);
941 connect(m_pAddQuickLinkAction, SIGNAL(triggered()), this, SLOT(slotAddQuickLink()));
942@@ -37,6 +42,10 @@
943 m_pRemoveQuickLinkAction = new QAction(tr("Remove from Quick Links"),this);
944 connect(m_pRemoveQuickLinkAction, SIGNAL(triggered()), this, SLOT(slotRemoveQuickLink()));
945
946+ m_pAddtoLibraryAction = new QAction(tr("Add to Library"),this);
947+ connect(m_pAddtoLibraryAction, SIGNAL(triggered()),
948+ this, SLOT(slotAddToLibrary()));
949+
950 m_proxyModel.setFilterCaseSensitivity(Qt::CaseInsensitive);
951 m_proxyModel.setSortCaseSensitivity(Qt::CaseInsensitive);
952
953@@ -75,7 +84,7 @@
954
955 // show root directory on UNIX-based operating systems
956 TreeItem* root_folder_item = new TreeItem(
957- QDir::rootPath(), QDir::rootPath(), this, rootItem);
958+ QDir::homePath(), QDir::homePath(), this, rootItem);
959 rootItem->appendChild(root_folder_item);
960 #endif
961
962@@ -100,11 +109,14 @@
963 m_pQuickLinkItem->appendChild(item);
964 }
965
966+
967 // initialize the model
968 m_childModel.setRootItem(rootItem);
969 }
970
971 BrowseFeature::~BrowseFeature() {
972+ //delete m_pLastRightClickedItem;
973+ // delete m_pQuickLinkItem;
974 }
975
976 QVariant BrowseFeature::title() {
977@@ -124,6 +136,14 @@
978 saveQuickLinks();
979 }
980
981+void BrowseFeature::slotAddToLibrary() {
982+ if (!m_pLastRightClickedItem) {
983+ return;
984+ }
985+ QString spath = m_pLastRightClickedItem->dataPath().toString();
986+ emit dirsChanged("added" ,spath);
987+}
988+
989 void BrowseFeature::slotRemoveQuickLink() {
990 if (!m_pLastRightClickedItem) {
991 return;
992@@ -200,6 +220,7 @@
993 }
994
995 menu.addAction(m_pAddQuickLinkAction);
996+ menu.addAction(m_pAddtoLibraryAction);
997 menu.exec(globalPos);
998 onLazyChildExpandation(index);
999 }
1000
1001=== modified file 'mixxx/src/library/browse/browsefeature.h'
1002--- mixxx/src/library/browse/browsefeature.h 2013-01-01 11:53:13 +0000
1003+++ mixxx/src/library/browse/browsefeature.h 2013-05-18 16:32:26 +0000
1004@@ -38,6 +38,7 @@
1005 public slots:
1006 void slotAddQuickLink();
1007 void slotRemoveQuickLink();
1008+ void slotAddToLibrary();
1009 void activate();
1010 void activateChild(const QModelIndex& index);
1011 void onRightClickChild(const QPoint& globalPos, QModelIndex index);
1012@@ -45,6 +46,7 @@
1013
1014 signals:
1015 void setRootIndex(const QModelIndex&);
1016+ void dirsChanged(QString,QString);
1017
1018 private:
1019 QString getRootViewHtml() const;
1020@@ -60,6 +62,7 @@
1021 FolderTreeModel m_childModel;
1022 QAction* m_pAddQuickLinkAction;
1023 QAction* m_pRemoveQuickLinkAction;
1024+ QAction* m_pAddtoLibraryAction;
1025 TreeItem* m_pLastRightClickedItem;
1026 TreeItem* m_pQuickLinkItem;
1027 QStringList m_quickLinkList;
1028
1029=== modified file 'mixxx/src/library/browse/browsetablemodel.cpp'
1030--- mixxx/src/library/browse/browsetablemodel.cpp 2013-01-19 12:15:22 +0000
1031+++ mixxx/src/library/browse/browsetablemodel.cpp 2013-05-18 16:32:26 +0000
1032@@ -124,7 +124,8 @@
1033 return QLinkedList<int>();
1034 }
1035
1036-void BrowseTableModel::search(const QString& searchText) {
1037+void BrowseTableModel::search(const QString& searchText, const QString& extraFilter) {
1038+ Q_UNUSED(extraFilter);
1039 Q_UNUSED(searchText);
1040 }
1041
1042
1043=== modified file 'mixxx/src/library/browse/browsetablemodel.h'
1044--- mixxx/src/library/browse/browsetablemodel.h 2012-08-10 15:03:46 +0000
1045+++ mixxx/src/library/browse/browsetablemodel.h 2013-05-18 16:32:26 +0000
1046@@ -42,7 +42,7 @@
1047 virtual int getTrackId(const QModelIndex& index) const;
1048 TrackModel::CapabilitiesFlags getCapabilities() const;
1049 virtual const QLinkedList<int> getTrackRows(int trackId) const;
1050- virtual void search(const QString& searchText);
1051+ virtual void search(const QString& searchText,const QString& extraFilter=QString());
1052 virtual void removeTrack(const QModelIndex& index);
1053 virtual void removeTracks(const QModelIndexList& indices);
1054 virtual bool addTrack(const QModelIndex& index, QString location);
1055
1056=== modified file 'mixxx/src/library/browse/browsethread.h'
1057--- mixxx/src/library/browse/browsethread.h 2012-03-13 04:36:19 +0000
1058+++ mixxx/src/library/browse/browsethread.h 2013-05-18 16:32:26 +0000
1059@@ -11,15 +11,13 @@
1060 #include <QStandardItem>
1061 #include <QList>
1062
1063-/*
1064- * This class is a singleton and represents a thread
1065- * that is used to read ID3 metadata
1066- * from a particular folder.
1067- *
1068- * The BroseTableModel uses this class.
1069- * Note: Don't call getInstance() from places
1070- * other than the GUI thread.
1071- */
1072+// This class is a singleton and represents a thread
1073+// that is used to read ID3 metadata
1074+// from a particular folder.
1075+//
1076+// The BroseTableModel uses this class.
1077+// Note: Don't call getInstance() from places
1078+// other than the GUI thread.
1079 class BrowseTableModel;
1080
1081 class BrowseThread : public QThread {
1082
1083=== modified file 'mixxx/src/library/browse/foldertreemodel.cpp'
1084--- mixxx/src/library/browse/foldertreemodel.cpp 2012-07-18 21:22:53 +0000
1085+++ mixxx/src/library/browse/foldertreemodel.cpp 2013-05-18 16:32:26 +0000
1086@@ -25,6 +25,7 @@
1087 }
1088
1089 FolderTreeModel::~FolderTreeModel() {
1090+ qDebug() << "~FolderTreeModel()";
1091 }
1092
1093 /* A tree model of the filesystem should be initialized lazy.
1094
1095=== modified file 'mixxx/src/library/cratefeature.cpp'
1096--- mixxx/src/library/cratefeature.cpp 2013-04-22 19:29:54 +0000
1097+++ mixxx/src/library/cratefeature.cpp 2013-05-18 16:32:26 +0000
1098@@ -20,10 +20,11 @@
1099 #include "soundsourceproxy.h"
1100
1101 CrateFeature::CrateFeature(QObject* parent,
1102- TrackCollection* pTrackCollection, ConfigObject<ConfigValue>* pConfig)
1103+ TrackCollection* pTrackCollection,
1104+ ConfigObject<ConfigValue>* pConfig)
1105 : m_pTrackCollection(pTrackCollection),
1106 m_crateDao(pTrackCollection->getCrateDAO()),
1107- m_crateTableModel(this, pTrackCollection),
1108+ m_crateTableModel(this, pTrackCollection,pConfig),
1109 m_pConfig(pConfig) {
1110 Q_UNUSED(parent);
1111 m_pCreateCrateAction = new QAction(tr("New Crate"),this);
1112@@ -65,6 +66,9 @@
1113 connect(&m_crateDao, SIGNAL(lockChanged(int)),
1114 this, SLOT(slotCrateTableChanged(int)));
1115
1116+ connect(this, SIGNAL(configChanged(QString,QString)),
1117+ &m_crateTableModel, SLOT(slotConfigChanged(QString,QString)));
1118+
1119 // construct child model
1120 TreeItem *rootItem = new TreeItem();
1121 m_childModel.setRootItem(rootItem);
1122@@ -156,7 +160,7 @@
1123 return;
1124 QString crateName = index.data().toString();
1125 int crateId = m_crateDao.getCrateIdByName(crateName);
1126- m_crateTableModel.setCrate(crateId);
1127+ m_crateTableModel.setTableModel(crateId);
1128 emit(showTrackModel(&m_crateTableModel));
1129 }
1130
1131@@ -473,7 +477,6 @@
1132 }
1133
1134 QList<QString> entries = playlist_parser->parse(playlist_file);
1135- //qDebug() << "Size of Imported Playlist: " << entries.size();
1136
1137 //Iterate over the List that holds URLs of playlist entires
1138 m_crateTableModel.addTracks(QModelIndex(), entries);
1139@@ -503,8 +506,8 @@
1140 QList<QString> playlist_items;
1141 // Create a new table model since the main one might have an active search.
1142 QScopedPointer<CrateTableModel> pCrateTableModel(
1143- new CrateTableModel(this, m_pTrackCollection));
1144- pCrateTableModel->setCrate(m_crateTableModel.getCrate());
1145+ new CrateTableModel(this, m_pTrackCollection,m_pConfig));
1146+ pCrateTableModel->setTableModel(m_crateTableModel.getCrate());
1147 pCrateTableModel->select();
1148
1149 if (file_location.endsWith(".csv", Qt::CaseInsensitive)) {
1150@@ -542,7 +545,7 @@
1151 clearChildModel();
1152 m_lastRightClickedIndex = constructChildModel(crateId);
1153 // Switch the view to the crate.
1154- m_crateTableModel.setCrate(crateId);
1155+ m_crateTableModel.setTableModel(crateId);
1156 // Update selection
1157 emit(featureSelect(this, m_lastRightClickedIndex));
1158 }
1159
1160=== modified file 'mixxx/src/library/cratefeature.h'
1161--- mixxx/src/library/cratefeature.h 2013-05-18 16:23:08 +0000
1162+++ mixxx/src/library/cratefeature.h 2013-05-18 16:32:26 +0000
1163@@ -34,6 +34,9 @@
1164
1165 TreeItemModel* getChildModel();
1166
1167+ signals:
1168+ void configChanged(QString,QString);
1169+
1170 public slots:
1171 void activate();
1172 void activateChild(const QModelIndex& index);
1173
1174=== modified file 'mixxx/src/library/cratetablemodel.cpp'
1175--- mixxx/src/library/cratetablemodel.cpp 2013-04-22 19:29:54 +0000
1176+++ mixxx/src/library/cratetablemodel.cpp 2013-05-18 16:32:26 +0000
1177@@ -4,53 +4,69 @@
1178 #include <QtDebug>
1179
1180 #include "library/cratetablemodel.h"
1181-
1182-#include "library/dao/cratedao.h"
1183-#include "library/librarytablemodel.h"
1184 #include "library/queryutil.h"
1185 #include "library/trackcollection.h"
1186 #include "mixxxutils.cpp"
1187 #include "playermanager.h"
1188
1189-CrateTableModel::CrateTableModel(QObject* pParent, TrackCollection* pTrackCollection)
1190+CrateTableModel::CrateTableModel(QObject* pParent,
1191+ TrackCollection* pTrackCollection,
1192+ ConfigObject<ConfigValue>* pConfig)
1193 : BaseSqlTableModel(pParent, pTrackCollection,
1194- pTrackCollection->getDatabase(),
1195- "mixxx.db.model.crate"),
1196- m_pTrackCollection(pTrackCollection),
1197- m_iCrateId(-1) {
1198- connect(this, SIGNAL(doSearch(const QString&)),
1199- this, SLOT(slotSearch(const QString&)));
1200+ pConfig, "mixxx.db.model.crate"),
1201+ m_iCrateId(-1),
1202+ m_crateDAO(pTrackCollection->getCrateDAO()) {
1203 }
1204
1205 CrateTableModel::~CrateTableModel() {
1206 }
1207
1208-void CrateTableModel::setCrate(int crateId) {
1209+void CrateTableModel::setTableModel(int crateId) {
1210 //qDebug() << "CrateTableModel::setCrate()" << crateId;
1211+ if (crateId == m_iCrateId) {
1212+ qDebug() << "Already focused on crate " << crateId;
1213+ return;
1214+ } else if (crateId == -1) {
1215+ // calls from parent class use -1 as id then just set the current crate
1216+ crateId = m_iCrateId;
1217+ }
1218 m_iCrateId = crateId;
1219
1220- QString tableName = QString("crate_%1").arg(m_iCrateId);
1221+ QString tableName = QString("crate_%1_").arg(m_iCrateId);
1222 QSqlQuery query(m_pTrackCollection->getDatabase());
1223 FieldEscaper escaper(m_pTrackCollection->getDatabase());
1224+
1225 QStringList columns;
1226- columns << CRATETRACKSTABLE_TRACKID + " as " + LIBRARYTABLE_ID
1227+ QStringList tableColumns;
1228+ QString filter;
1229+ columns << "crate_tracks."+CRATETRACKSTABLE_TRACKID + " as " + LIBRARYTABLE_ID
1230 << "'' as preview";
1231+ tableColumns << CRATETRACKSTABLE_TRACKID;
1232+ bool showMissing = m_pConfig->getValueString(ConfigKey("[Library]","ShowMissingSongs"),"1").toInt();
1233+ if(showMissing){
1234+ filter = "library.mixxx_deleted=0";
1235+ tableName.append("_missing");
1236+ } else {
1237+ filter = "library.mixxx_deleted=0 AND track_locations.fs_deleted=0";
1238+ }
1239
1240 // We drop files that have been explicitly deleted from mixxx
1241 // (mixxx_deleted=0) from the view. There was a bug in <= 1.9.0 where
1242- // removed files were not removed from playlists, so some users will have
1243+ // removed files were not removed from crates, so some users will have
1244 // libraries where this is the case.
1245 QString queryString = QString(
1246 "CREATE TEMPORARY VIEW IF NOT EXISTS %1 AS "
1247 "SELECT %2 FROM %3 "
1248 "INNER JOIN library ON library.id = %3.%4 "
1249- "WHERE %3.%5 = %6 AND library.mixxx_deleted = 0")
1250+ "INNER JOIN track_locations ON track_locations.id=crate_tracks.track_id "
1251+ "WHERE %3.%5 = %6 AND %7")
1252 .arg(escaper.escapeString(tableName),
1253 columns.join(","),
1254 CRATE_TRACKS_TABLE,
1255 CRATETRACKSTABLE_TRACKID,
1256 CRATETRACKSTABLE_CRATEID,
1257- QString::number(crateId));
1258+ QString::number(crateId),
1259+ filter);
1260 query.prepare(queryString);
1261 if (!query.exec()) {
1262 LOG_FAILED_QUERY(query);
1263@@ -103,10 +119,9 @@
1264 fileInfoList.append(QFileInfo(fileLocation));
1265 }
1266
1267- TrackDAO& trackDao = m_pTrackCollection->getTrackDAO();
1268- QList<int> trackIDs = trackDao.addTracks(fileInfoList, true);
1269+ QList<int> trackIDs = m_trackDAO.addTracks(fileInfoList, true);
1270
1271- int tracksAdded = m_pTrackCollection->getCrateDAO().addTracksToCrate(
1272+ int tracksAdded = m_crateDAO.addTracksToCrate(
1273 trackIDs, m_iCrateId);
1274 if (tracksAdded > 0) {
1275 select();
1276@@ -120,58 +135,19 @@
1277 return tracksAdded;
1278 }
1279
1280-TrackPointer CrateTableModel::getTrack(const QModelIndex& index) const {
1281- int trackId = getTrackId(index);
1282- return m_pTrackCollection->getTrackDAO().getTrack(trackId);
1283-}
1284-
1285 void CrateTableModel::removeTracks(const QModelIndexList& indices) {
1286- CrateDAO& crateDao = m_pTrackCollection->getCrateDAO();
1287- bool locked = crateDao.isCrateLocked(m_iCrateId);
1288+ bool locked = m_crateDAO.isCrateLocked(m_iCrateId);
1289
1290 if (!locked) {
1291 QList<int> trackIds;
1292 foreach (QModelIndex index, indices) {
1293 trackIds.append(getTrackId(index));
1294 }
1295- crateDao.removeTracksFromCrate(trackIds, m_iCrateId);
1296+ m_crateDAO.removeTracksFromCrate(trackIds, m_iCrateId);
1297 select();
1298 }
1299 }
1300
1301-void CrateTableModel::removeTrack(const QModelIndex& index) {
1302- CrateDAO& crateDao = m_pTrackCollection->getCrateDAO();
1303- bool locked = crateDao.isCrateLocked(m_iCrateId);
1304-
1305- if (!locked) {
1306- int trackId = getTrackId(index);
1307- if (m_pTrackCollection->getCrateDAO().
1308- removeTrackFromCrate(trackId, m_iCrateId)) {
1309- select();
1310- } else {
1311- // TODO(XXX) feedback
1312- }
1313- }
1314-}
1315-
1316-void CrateTableModel::moveTrack(const QModelIndex& sourceIndex,
1317- const QModelIndex& destIndex) {
1318- Q_UNUSED(sourceIndex);
1319- Q_UNUSED(destIndex);
1320- return;
1321-}
1322-
1323-void CrateTableModel::search(const QString& searchText) {
1324- // qDebug() << "CrateTableModel::search()" << searchText
1325- // << QThread::currentThread();
1326- emit(doSearch(searchText));
1327-}
1328-
1329-void CrateTableModel::slotSearch(const QString& searchText) {
1330- BaseSqlTableModel::search(
1331- searchText, LibraryTableModel::DEFAULT_LIBRARYFILTER);
1332-}
1333-
1334 bool CrateTableModel::isColumnInternal(int column) {
1335 if (column == fieldIndex(LIBRARYTABLE_ID) ||
1336 column == fieldIndex(CRATETRACKSTABLE_TRACKID) ||
1337@@ -179,6 +155,7 @@
1338 column == fieldIndex(LIBRARYTABLE_MIXXXDELETED) ||
1339 column == fieldIndex(LIBRARYTABLE_BPM_LOCK) ||
1340 column == fieldIndex(TRACKLOCATIONSTABLE_FSDELETED) ||
1341+ column == fieldIndex(TRACKLOCATIONSTABLE_MAINDIRID) ||
1342 (PlayerManager::numPreviewDecks() == 0 && column == fieldIndex("preview"))) {
1343 return true;
1344 }
1345@@ -202,12 +179,12 @@
1346 | TRACKMODELCAPS_LOADTOSAMPLER
1347 | TRACKMODELCAPS_LOADTOPREVIEWDECK
1348 | TRACKMODELCAPS_REMOVE
1349+ | TRACKMODELCAPS_RELOCATE
1350 | TRACKMODELCAPS_BPMLOCK
1351 | TRACKMODELCAPS_CLEAR_BEATS
1352 | TRACKMODELCAPS_RESETPLAYED;
1353
1354- CrateDAO& crateDao = m_pTrackCollection->getCrateDAO();
1355- bool locked = crateDao.isCrateLocked(m_iCrateId);
1356+ bool locked = m_crateDAO.isCrateLocked(m_iCrateId);
1357
1358 if (locked) {
1359 caps |= TRACKMODELCAPS_LOCKED;
1360@@ -215,3 +192,10 @@
1361
1362 return caps;
1363 }
1364+
1365+void CrateTableModel::moveTrack(const QModelIndex& sourceIndex,
1366+ const QModelIndex& destIndex) {
1367+ Q_UNUSED(sourceIndex);
1368+ Q_UNUSED(destIndex);
1369+ return;
1370+}
1371
1372=== modified file 'mixxx/src/library/cratetablemodel.h'
1373--- mixxx/src/library/cratetablemodel.h 2013-04-22 19:29:54 +0000
1374+++ mixxx/src/library/cratetablemodel.h 2013-05-18 16:32:26 +0000
1375@@ -4,48 +4,35 @@
1376 #ifndef CRATETABLEMODEL_H
1377 #define CRATETABLEMODEL_H
1378
1379-#include <QItemDelegate>
1380-#include <QSqlTableModel>
1381-
1382 #include "library/basesqltablemodel.h"
1383-
1384-class TrackCollection;
1385+#include "library/dao/cratedao.h"
1386
1387 class CrateTableModel : public BaseSqlTableModel {
1388 Q_OBJECT
1389 public:
1390- CrateTableModel(QObject* parent, TrackCollection* pTrackCollection);
1391+ CrateTableModel(QObject* parent, TrackCollection* pTrackCollection,
1392+ ConfigObject<ConfigValue>* pConfig);
1393 virtual ~CrateTableModel();
1394
1395- void setCrate(int crateId);
1396+ void setTableModel(int crateId=-1);
1397 int getCrate() const {
1398 return m_iCrateId;
1399 }
1400
1401 // From TrackModel
1402- TrackPointer getTrack(const QModelIndex& index) const;
1403- void search(const QString& searchText);
1404 bool isColumnInternal(int column);
1405 bool isColumnHiddenByDefault(int column);
1406- void removeTrack(const QModelIndex& index);
1407 void removeTracks(const QModelIndexList& indices);
1408- bool addTrack(const QModelIndex& index, QString location);
1409+ bool addTrack(const QModelIndex &index, QString location);
1410 // Returns the number of unsuccessful track additions
1411- int addTracks(const QModelIndex& index,
1412- const QList <QString> &locations);
1413+ int addTracks(const QModelIndex& index,const QList <QString> &locations);
1414 void moveTrack(const QModelIndex& sourceIndex,
1415 const QModelIndex& destIndex);
1416 TrackModel::CapabilitiesFlags getCapabilities() const;
1417
1418- private slots:
1419- void slotSearch(const QString& searchText);
1420-
1421- signals:
1422- void doSearch(const QString& searchText);
1423-
1424 private:
1425- TrackCollection* m_pTrackCollection;
1426 int m_iCrateId;
1427+ CrateDAO& m_crateDAO;
1428 };
1429
1430 #endif /* CRATETABLEMODEL_H */
1431
1432=== added file 'mixxx/src/library/dao/directorydao.cpp'
1433--- mixxx/src/library/dao/directorydao.cpp 1970-01-01 00:00:00 +0000
1434+++ mixxx/src/library/dao/directorydao.cpp 2013-05-18 16:32:26 +0000
1435@@ -0,0 +1,143 @@
1436+#include <QtSql>
1437+#include <QtDebug>
1438+#include <QStringBuilder>
1439+
1440+#include "directorydao.h"
1441+#include "library/queryutil.h"
1442+
1443+DirectoryDAO::DirectoryDAO(QSqlDatabase& database)
1444+ : m_database(database) {
1445+}
1446+
1447+DirectoryDAO::DirectoryDAO(const DirectoryDAO& directoryDao)
1448+ : m_database(directoryDao.m_database){
1449+}
1450+
1451+DirectoryDAO::~DirectoryDAO(){
1452+}
1453+
1454+void DirectoryDAO::initialize()
1455+{
1456+ qDebug() << "DirectoryDAO::initialize" << QThread::currentThread()
1457+ << m_database.connectionName();
1458+}
1459+
1460+bool DirectoryDAO::addDirectory(QString dir){
1461+ ScopedTransaction transaction(m_database);
1462+ QSqlQuery query(m_database);
1463+ query.prepare("INSERT OR REPLACE INTO directories (directory) "
1464+ "VALUES (\""% dir %"\")");
1465+
1466+ if (!query.exec()) {
1467+ qDebug() << "Adding new dir ("% dir %") failed:"
1468+ <<query.lastError();
1469+ return false;
1470+ }
1471+ transaction.commit();
1472+ return true;
1473+}
1474+
1475+bool DirectoryDAO::purgeDirectory(QString dir){
1476+ QSqlQuery query(m_database);
1477+ query.prepare("DELETE FROM directories WHERE directory=\"" % dir % "\"");
1478+
1479+ if (!query.exec()) {
1480+ qDebug() << "purging dir ("%dir%") failed:"<<query.lastError();
1481+ return false;
1482+ }
1483+ return true;
1484+}
1485+
1486+bool DirectoryDAO::relocateDirectory(QString oldFolder, QString newFolder){
1487+ ScopedTransaction transaction(m_database);
1488+ QSqlQuery query(m_database);
1489+
1490+ // update directory in directories table
1491+ query.prepare("UPDATE "%DIRECTORYDAO_TABLE%" SET "%DIRECTORYDAO_DIR%"="
1492+ "\":newFolder\" WHERE "%DIRECTORYDAO_DIR%"=\":oldFolder\"");
1493+ query.bindValue(":newFolder", newFolder);
1494+ query.bindValue(":oldFolder", oldFolder);
1495+ if (!query.exec()) {
1496+ LOG_FAILED_QUERY(query) << "coud not relocate directory";
1497+ return false;
1498+ }
1499+
1500+ // update location and directory in track_locations table
1501+ query.prepare("UPDATE track_locations SET location="
1502+ "REPLACE(location,\":oldFolder\",\":newFolder\")"
1503+ ", directory="
1504+ "REPLACE(directory,\":oldFolder\",\":newFolder\") "
1505+ "WHERE "%DIRECTORYDAO_DIR%"=\":oldFolder\"");
1506+ query.bindValue(":newFolder", newFolder);
1507+ query.bindValue(":oldFolder", oldFolder);
1508+ if (!query.exec()) {
1509+ LOG_FAILED_QUERY(query) << "coud not relocate path of tracks";
1510+ return false;
1511+ }
1512+
1513+ // updating the dir_id column is not necessary because it does not change
1514+
1515+ transaction.commit();
1516+ return true;
1517+}
1518+
1519+QStringList DirectoryDAO::getDirs(){
1520+ QSqlQuery query(m_database);
1521+ query.prepare("SELECT " % DIRECTORYDAO_DIR % " FROM " % DIRECTORYDAO_TABLE);
1522+ if (!query.exec()) {
1523+ LOG_FAILED_QUERY(query) << "There are no directories saved in the db";
1524+ }
1525+ QStringList dirs;
1526+ while (query.next()) {
1527+ dirs << query.value(query.record().indexOf(DIRECTORYDAO_DIR)).toString();
1528+ }
1529+ return dirs;
1530+}
1531+
1532+QList<int> DirectoryDAO::getDirIds(QStringList& dirs){
1533+ QSqlQuery query(m_database);
1534+ query.prepare("SELECT " % DIRECTORYDAO_ID % " FROM " % DIRECTORYDAO_TABLE %
1535+ " WHERE " % DIRECTORYDAO_DIR %" in (\":dirs\")");
1536+ query.bindValue(":dirs", dirs.join("\",\"") );
1537+ if (!query.exec()) {
1538+ LOG_FAILED_QUERY(query) << "couldn't find directory:"<<dirs;
1539+ }
1540+ QList<int> ids;
1541+ while (query.next()) {
1542+ ids.append(query.value(query.record().indexOf(DIRECTORYDAO_ID)).toInt());
1543+ }
1544+
1545+ return ids;
1546+}
1547+
1548+//TODO(kain88) check if this is not obsolete because of getDirIds
1549+int DirectoryDAO::getDirId(const QString dir){
1550+ QSqlQuery query(m_database);
1551+ query.prepare("SELECT " % DIRECTORYDAO_ID % " FROM " % DIRECTORYDAO_TABLE %
1552+ " WHERE " % DIRECTORYDAO_DIR %" in (\":dir\")");
1553+ query.bindValue(":dir",dir);
1554+ if (!query.exec()) {
1555+ LOG_FAILED_QUERY(query) << "couldn't find directory:"<<dir;
1556+ }
1557+ int id=0;
1558+ while (query.next()) {
1559+ id = query.value(query.record().indexOf(DIRECTORYDAO_ID)).toInt();
1560+ }
1561+ return id;
1562+}
1563+
1564+// Only call this when an update happens from an old library version!!!
1565+// TODO move this into update code
1566+bool DirectoryDAO::updateTrackLocations(QString dir){
1567+ QString dirId = QString::number(getDirId(dir));
1568+ ScopedTransaction transaction(m_database);
1569+ QSqlQuery query(m_database);
1570+ query.prepare("UPDATE track_locations SET maindir_id = :dirId");
1571+ query.bindValue(":dirId", dirId);
1572+ if (!query.exec()) {
1573+ LOG_FAILED_QUERY(query) << " could not update TrackLocations";
1574+ return false;
1575+ }
1576+ transaction.commit();
1577+ return true;
1578+}
1579
1580=== added file 'mixxx/src/library/dao/directorydao.h'
1581--- mixxx/src/library/dao/directorydao.h 1970-01-01 00:00:00 +0000
1582+++ mixxx/src/library/dao/directorydao.h 2013-05-18 16:32:26 +0000
1583@@ -0,0 +1,31 @@
1584+#ifndef DIRECTORYDAO_H
1585+#define DIRECTORYDAO_H
1586+
1587+#include <QSqlDatabase>
1588+#include "library/dao/dao.h"
1589+
1590+const QString DIRECTORYDAO_DIR = "directory";
1591+const QString DIRECTORYDAO_ID = "dir_id";
1592+const QString DIRECTORYDAO_TABLE = "directories";
1593+
1594+class DirectoryDAO : public DAO {
1595+ public:
1596+ // normal method
1597+ DirectoryDAO(QSqlDatabase& database);
1598+ DirectoryDAO(const DirectoryDAO& directoryDao);
1599+ virtual ~DirectoryDAO();
1600+
1601+ void initialize();
1602+ bool addDirectory(QString dir);
1603+ bool purgeDirectory(QString dir);
1604+ bool relocateDirectory(QString oldFolder,QString newFolder);
1605+ bool updateTrackLocations(QString dir);
1606+ QList<int> getDirIds(QStringList& dirs);
1607+ int getDirId(const QString dir);
1608+ QStringList getDirs();
1609+
1610+ private:
1611+ QSqlDatabase m_database;
1612+};
1613+
1614+#endif //DIRECTORYDAO_H
1615
1616=== modified file 'mixxx/src/library/dao/trackdao.cpp'
1617--- mixxx/src/library/dao/trackdao.cpp 2013-05-03 23:33:12 +0000
1618+++ mixxx/src/library/dao/trackdao.cpp 2013-05-18 16:32:26 +0000
1619@@ -1,6 +1,7 @@
1620 #include <QtDebug>
1621 #include <QtCore>
1622 #include <QtSql>
1623+#include <QMessageBox>
1624
1625 #include "library/dao/trackdao.h"
1626
1627@@ -14,6 +15,7 @@
1628 #include "library/dao/cuedao.h"
1629 #include "library/dao/playlistdao.h"
1630 #include "library/dao/analysisdao.h"
1631+#include "library/dao/directorydao.h"
1632
1633 QHash<int, TrackWeakPointer> TrackDAO::m_sTracks;
1634 QMutex TrackDAO::m_sTracksMutex;
1635@@ -30,12 +32,14 @@
1636 PlaylistDAO& playlistDao,
1637 CrateDAO& crateDao,
1638 AnalysisDao& analysisDao,
1639+ DirectoryDAO& directoryDao,
1640 ConfigObject<ConfigValue> * pConfig)
1641 : m_database(database),
1642 m_cueDao(cueDao),
1643 m_playlistDao(playlistDao),
1644 m_crateDao(crateDao),
1645 m_analysisDao(analysisDao),
1646+ m_directoryDAO(directoryDao),
1647 m_pConfig(pConfig),
1648 m_trackCache(TRACK_CACHE_SIZE),
1649 m_pQueryTrackLocationInsert(NULL),
1650@@ -268,7 +272,8 @@
1651
1652 // No need to check here if the querys exist, this is already done in
1653 // addTracksAdd, which is the only function that calls this
1654-void TrackDAO::bindTrackToTrackLocationsInsert(TrackInfoObject* pTrack) {
1655+void TrackDAO::bindTrackToTrackLocationsInsert(TrackInfoObject* pTrack, int dirId,
1656+ QString& checksum) {
1657 // gets called only in addTracksAdd
1658 m_pQueryTrackLocationInsert->bindValue(":location", pTrack->getLocation());
1659 m_pQueryTrackLocationInsert->bindValue(":directory", pTrack->getDirectory());
1660@@ -277,6 +282,8 @@
1661 // Should this check pTrack->exists()?
1662 m_pQueryTrackLocationInsert->bindValue(":fs_deleted", 0);
1663 m_pQueryTrackLocationInsert->bindValue(":needs_verification", 0);
1664+ m_pQueryTrackLocationInsert->bindValue(":maindir_id", dirId);
1665+ m_pQueryTrackLocationInsert->bindValue(":checksum", checksum);
1666 }
1667
1668 // No need to check here if the querys exist, this is already done in
1669@@ -335,7 +342,6 @@
1670 }
1671
1672 void TrackDAO::addTracksPrepare() {
1673-
1674 if (m_pQueryLibraryInsert || m_pQueryTrackLocationInsert ||
1675 m_pQueryLibrarySelect || m_pQueryTrackLocationSelect ||
1676 m_pTransaction) {
1677@@ -353,9 +359,8 @@
1678 m_pQueryLibrarySelect = new QSqlQuery(m_database);
1679
1680 m_pQueryTrackLocationInsert->prepare("INSERT INTO track_locations "
1681- "(location, directory, filename, filesize, fs_deleted, needs_verification) "
1682- "VALUES (:location, :directory, :filename, :filesize, :fs_deleted, :needs_verification)"
1683- );
1684+ "(location, directory, filename, filesize, fs_deleted, needs_verification, maindir_id, checksum) "
1685+ "VALUES (:location, :directory, :filename, :filesize, :fs_deleted, :needs_verification, :maindir_id, :checksum)");
1686
1687 m_pQueryTrackLocationSelect->prepare("SELECT id FROM track_locations WHERE location=:location");
1688
1689@@ -398,7 +403,8 @@
1690 m_tracksAddedSet.clear();
1691 }
1692
1693-bool TrackDAO::addTracksAdd(TrackInfoObject* pTrack, bool unremove) {
1694+bool TrackDAO::addTracksAdd(TrackInfoObject* pTrack, bool unremove,const int dirId) {
1695+
1696
1697 if (!m_pQueryLibraryInsert || !m_pQueryTrackLocationInsert ||
1698 !m_pQueryLibrarySelect || !m_pQueryTrackLocationSelect) {
1699@@ -409,11 +415,12 @@
1700
1701 int trackLocationId = -1;
1702 int trackId = -1;
1703+ QString checksum = calcChecksum(*pTrack);
1704
1705 // Insert the track location into the corresponding table. This will fail
1706 // silently if the location is already in the table because it has a UNIQUE
1707 // constraint.
1708- bindTrackToTrackLocationsInsert(pTrack);
1709+ bindTrackToTrackLocationsInsert(pTrack,dirId,checksum);
1710
1711 if (!m_pQueryTrackLocationInsert->exec()) {
1712 qDebug() << "Location " << pTrack->getLocation() << " is already in the DB";
1713@@ -522,7 +529,7 @@
1714 }
1715
1716 addTracksPrepare();
1717- addTracksAdd(pTrack, unremove);
1718+ addTracksAdd(pTrack, unremove, 0);
1719 addTracksFinish();
1720 }
1721
1722@@ -530,6 +537,8 @@
1723 bool unremove) {
1724 QSqlQuery query(m_database);
1725 QList<int> trackIDs;
1726+ TrackInfoObject* pTrack;
1727+
1728
1729 // Create a temporary database of the paths of all the imported tracks.
1730 query.prepare("CREATE TEMP TABLE playlist_import "
1731@@ -589,7 +598,8 @@
1732 while (query.next()) {
1733 QString filePath = query.value(query.record().indexOf("location")).toString();
1734 TrackInfoObject* pTrack = new TrackInfoObject(QFileInfo(filePath));
1735- addTracksAdd(pTrack, unremove);
1736+ //TODO kain88 fix dirID
1737+ addTracksAdd(pTrack, unremove,0);
1738 int trackID = pTrack->getId();
1739 if (trackID >= 0) {
1740 trackIDs.append(trackID);
1741@@ -625,6 +635,7 @@
1742
1743 // This signal is received by basetrackcache to remove the tracks from cache
1744 QSet<int> tracksRemovedSet = QSet<int>::fromList(ids);
1745+ uncacheTracks(tracksRemovedSet);
1746 emit(tracksRemoved(tracksRemovedSet));
1747 }
1748
1749@@ -647,6 +658,7 @@
1750 LOG_FAILED_QUERY(query);
1751 }
1752 QSet<int> tracksAddedSet = QSet<int>::fromList(ids);
1753+ uncacheTracks(tracksAddedSet);
1754 emit(tracksAdded(tracksAddedSet));
1755 }
1756
1757@@ -675,18 +687,17 @@
1758
1759 FieldEscaper escaper(m_database);
1760 QStringList locationList;
1761- QSet<QString> dirs;
1762+ QStringList dirs;
1763 while (query.next()) {
1764 QString filePath = query.value(query.record().indexOf("location")).toString();
1765 locationList << escaper.escapeString(filePath);
1766 QString directory = query.value(query.record().indexOf("directory")).toString();
1767- dirs.insert(directory);
1768+ dirs << directory;
1769 }
1770
1771 QStringList dirList;
1772- for (QSet<QString>::const_iterator it = dirs.constBegin();
1773- it != dirs.constEnd(); ++it) {
1774- dirList << escaper.escapeString(*it);
1775+ foreach(QString dir, dirs) {
1776+ dirList << escaper.escapeString(dir);
1777 }
1778
1779 if (locationList.empty()) {
1780@@ -724,16 +735,68 @@
1781 transaction.commit();
1782
1783 // also need to clean playlists, crates, cues and track_analyses
1784-
1785 m_cueDao.deleteCuesForTracks(ids);
1786 m_playlistDao.removeTracksFromPlaylists(ids);
1787 m_crateDao.removeTracksFromCrates(ids);
1788 m_analysisDao.deleteAnalysises(ids);
1789
1790 QSet<int> tracksRemovedSet = QSet<int>::fromList(ids);
1791+ uncacheTracks(tracksRemovedSet);
1792 emit(tracksRemoved(tracksRemovedSet));
1793 }
1794
1795+//TODO(kain88) check if this works as desired
1796+QStringList TrackDAO::deleteTracksFromFS(QList<int> ids){
1797+ if (ids.empty()) {
1798+ return QStringList();
1799+ }
1800+
1801+ QStringList idList;
1802+ foreach (int id, ids) {
1803+ idList << QString::number(id);
1804+ }
1805+
1806+ QSqlQuery query(m_database);
1807+ query.prepare("SELECT track_locations.location, track_locations.directory FROM "
1808+ "track_locations INNER JOIN library ON library.location = "
1809+ "track_locations.id WHERE library.id in (:idList)");
1810+ query.bindValue("idList", idList.join(","));
1811+ if (!query.exec()) {
1812+ LOG_FAILED_QUERY(query);
1813+ }
1814+
1815+ FieldEscaper escaper(m_database);
1816+ QStringList locationList;
1817+ while (query.next()) {
1818+ locationList << escaper.escapeString(query.value(
1819+ query.record().indexOf("location")).toString());
1820+ }
1821+
1822+ QStringList failed;
1823+ foreach (QString loc, locationList) {
1824+ if (!QFile::remove(loc)) {
1825+ failed.append(loc);
1826+ }
1827+ }
1828+
1829+ query.prepare("SELECT libary.id FROM library INNER JOIN track_locations ON "
1830+ "library.location = track_locations.id WHERE "
1831+ "track_locations.location in (:locList)");
1832+ query.bindValue(":locList", failed.join(","));
1833+
1834+ if (!query.exec()) {
1835+ LOG_FAILED_QUERY(query);
1836+ }
1837+
1838+ while (query.next()) {
1839+ ids.removeAll(query.value(query.record().indexOf("if")).toInt());
1840+ }
1841+ // clean all DB entries AFTER the file is removed, otherwise the remove
1842+ // function fails.
1843+ purgeTracks(ids);
1844+ return failed;
1845+}
1846+
1847 // deleter of the TrackInfoObject, for delete a Track from Library use hide or purge
1848 // static
1849 void TrackDAO::deleteTrack(TrackInfoObject* pTrack) {
1850@@ -764,7 +827,8 @@
1851 "filetype, rating, key, track_locations.location as location, "
1852 "track_locations.filesize as filesize, comment, url, duration, bitrate, "
1853 "samplerate, cuepoint, bpm, replaygain, channels, "
1854- "header_parsed, timesplayed, played, beats_version, beats_sub_version, beats, datetime_added, bpm_lock "
1855+ "header_parsed, timesplayed, played, beats_version, beats_sub_version, beats, "
1856+ "datetime_added, bpm_lock "
1857 "FROM Library "
1858 "INNER JOIN track_locations "
1859 "ON library.location = track_locations.id "
1860@@ -1035,19 +1099,16 @@
1861 // Mark all the tracks whose paths begin with libraryPath as invalid.
1862 // That means we'll need to later check that those tracks actually
1863 // (still) exist as part of the library scanning procedure.
1864-void TrackDAO::invalidateTrackLocationsInLibrary(QString libraryPath) {
1865+void TrackDAO::invalidateTrackLocationsInLibrary() {
1866 //qDebug() << "TrackDAO::invalidateTrackLocations" << QThread::currentThread() << m_database.connectionName();
1867 //qDebug() << "invalidateTrackLocations(" << libraryPath << ")";
1868- libraryPath += "%"; //Add wildcard to SQL query to match subdirectories!
1869
1870 QSqlQuery query(m_database);
1871 query.prepare("UPDATE track_locations "
1872- "SET needs_verification=1 "
1873- "WHERE directory LIKE :directory");
1874- query.bindValue(":directory", libraryPath);
1875+ "SET needs_verification=1");
1876 if (!query.exec()) {
1877 LOG_FAILED_QUERY(query)
1878- << "Couldn't mark tracks in directory" << libraryPath
1879+ << "Couldn't mark tracks in directory "
1880 << "as needing verification.";
1881 }
1882 }
1883@@ -1087,13 +1148,24 @@
1884 LOG_FAILED_QUERY(query)
1885 << "Couldn't mark tracks in" << directories.size() << "directories as verified.";
1886 }
1887+ // qDebug() << directories;
1888 }
1889
1890 void TrackDAO::markUnverifiedTracksAsDeleted() {
1891 //qDebug() << "TrackDAO::markUnverifiedTracksAsDeleted" << QThread::currentThread() << m_database.connectionName();
1892- //qDebug() << "markUnverifiedTracksAsDeleted()";
1893-
1894+ qDebug() << "markUnverifiedTracksAsDeleted()";
1895+
1896 QSqlQuery query(m_database);
1897+ query.prepare("SELECT id FROM track_locations WHERE needs_verification=1");
1898+ QSet<int> trackIds;
1899+ if (!query.exec()) {
1900+ LOG_FAILED_QUERY(query)
1901+ << "Couldn't find unverified tracks";
1902+ }
1903+ while (query.next()){
1904+ trackIds.insert(query.value(query.record().indexOf("id")).toInt());
1905+ }
1906+ emit(tracksRemoved(trackIds));
1907 query.prepare("UPDATE track_locations "
1908 "SET fs_deleted=1, needs_verification=0 "
1909 "WHERE needs_verification=1");
1910@@ -1121,55 +1193,54 @@
1911 // and see if another "file" with the same name and filesize exists in the track_locations
1912 // table. That means the file has moved instead of being deleted outright, and so
1913 // we can salvage your existing metadata that you have in your DB (like cue points, etc.).
1914-void TrackDAO::detectMovedFiles(QSet<int>* pTracksMovedSetOld, QSet<int>* pTracksMovedSetNew) {
1915+void TrackDAO::detectMovedFiles(QSet<int>& tracksMovedSetOld, QSet<int>& tracksMovedSetNew) {
1916 //This function should not start a transaction on it's own!
1917 //When it's called from libraryscanner.cpp, there already is a transaction
1918 //started!
1919-
1920 QSqlQuery query(m_database);
1921 QSqlQuery query2(m_database);
1922 QSqlQuery query3(m_database);
1923 int oldTrackLocationId = -1;
1924 int newTrackLocationId = -1;
1925- QString filename;
1926- int fileSize;
1927+ QString checksum;
1928+ int duration = -1;
1929+ int fileSize = -1;
1930
1931- query.prepare("SELECT id, filename, filesize FROM track_locations WHERE fs_deleted=1");
1932+ query.prepare("SELECT track_locations.id, checksum, filesize, duration FROM track_locations "
1933+ "INNER JOIN library ON track_locations.id=library.location "
1934+ "WHERE fs_deleted=1");
1935
1936 if (!query.exec()) {
1937 LOG_FAILED_QUERY(query);
1938 }
1939
1940- query2.prepare("SELECT id FROM track_locations WHERE "
1941- "fs_deleted=0 AND "
1942- "filename=:filename AND "
1943- "filesize=:filesize");
1944+ query2.prepare("SELECT track_locations.id FROM track_locations "
1945+ "INNER JOIN library ON track_locations.id=library.location "
1946+ "WHERE fs_deleted=0 AND "
1947+ "checksum=:checksum AND "
1948+ "filesize=:filesize AND "
1949+ "duration=:duration");
1950
1951 //For each track that's been "deleted" on disk...
1952 while (query.next()) {
1953 newTrackLocationId = -1; //Reset this var
1954 oldTrackLocationId = query.value(query.record().indexOf("id")).toInt();
1955- filename = query.value(query.record().indexOf("filename")).toString();
1956+ checksum = query.value(query.record().indexOf("checksum")).toString();
1957 fileSize = query.value(query.record().indexOf("filesize")).toInt();
1958+ duration = query.value(query.record().indexOf("duration")).toInt();
1959
1960- query2.bindValue(":filename", filename);
1961+ query2.bindValue(":checksum", checksum);
1962 query2.bindValue(":filesize", fileSize);
1963+ query2.bindValue(":duration", duration);
1964 Q_ASSERT(query2.exec());
1965
1966 Q_ASSERT(query2.size() <= 1); //WTF duplicate tracks?
1967- while (query2.next())
1968- {
1969+ while (query2.next()) {
1970 newTrackLocationId = query2.value(query2.record().indexOf("id")).toInt();
1971- }
1972-
1973- //If we found a moved track...
1974- if (newTrackLocationId >= 0)
1975- {
1976- qDebug() << "Found moved track!" << filename;
1977+ qDebug() << "Found moved track!" << checksum;
1978
1979 //Remove old row from track_locations table
1980- query3.prepare("DELETE FROM track_locations WHERE "
1981- "id=:id");
1982+ query3.prepare("DELETE FROM track_locations WHERE id=:id");
1983 query3.bindValue(":id", oldTrackLocationId);
1984 Q_ASSERT(query3.exec());
1985
1986@@ -1181,42 +1252,37 @@
1987 "location=:location");
1988 query3.bindValue(":location", newTrackLocationId);
1989 Q_ASSERT(query3.exec());
1990-
1991- while (query3.next())
1992- {
1993- int newTrackId = query3.value(query3.record().indexOf("id")).toInt();
1994- query3.prepare("DELETE FROM library WHERE "
1995- "id=:newid");
1996- query3.bindValue(":newid", newTrackLocationId);
1997- Q_ASSERT(query3.exec());
1998-
1999- // We collect all the new tracks the where added to BaseTrackCache as well
2000- pTracksMovedSetNew->insert(newTrackId);
2001+ // We collect all the new tracks the where added to BaseTrackCache as well
2002+ while (query3.next()) {
2003+ int newTrackId = query3.value(0).toInt();
2004+ tracksMovedSetNew.insert(newTrackId);
2005 }
2006+ // Delete the track
2007+ query3.prepare("DELETE FROM library WHERE "
2008+ "id=:newid");
2009+ query3.bindValue(":newid", newTrackLocationId);
2010+ Q_ASSERT(query3.exec());
2011
2012 //Update the location foreign key for the existing row in the library table
2013 //to point to the correct row in the track_locations table.
2014+ query3.prepare("UPDATE library "
2015+ "SET location=:newloc WHERE location=:oldloc");
2016+ query3.bindValue(":newloc", newTrackLocationId);
2017+ query3.bindValue(":oldloc", oldTrackLocationId);
2018+ Q_ASSERT(query3.exec());
2019+
2020+ // We collect all the old tracks that has to be updated in BaseTrackCache as well
2021 query3.prepare("SELECT id FROM library WHERE "
2022 "location=:location");
2023- query3.bindValue(":location", oldTrackLocationId);
2024+ query3.bindValue(":location", newTrackLocationId);
2025 Q_ASSERT(query3.exec());
2026-
2027-
2028- while (query3.next())
2029- {
2030- int oldTrackId = query3.value(query3.record().indexOf("id")).toInt();
2031-
2032- query3.prepare("UPDATE library "
2033- "SET location=:newloc WHERE id=:oldid");
2034- query3.bindValue(":newloc", newTrackLocationId);
2035- query3.bindValue(":oldid", oldTrackId);
2036- Q_ASSERT(query3.exec());
2037-
2038- // We collect all the old tracks that has to be updated in BaseTrackCache as well
2039- pTracksMovedSetOld->insert(oldTrackId);
2040+ while (query3.next()) {
2041+ int oldTrackId = query3.value(0).toInt();
2042+ tracksMovedSetOld.insert(oldTrackId);
2043 }
2044 }
2045 }
2046+ databaseTracksMoved(tracksMovedSetOld, tracksMovedSetNew);
2047 }
2048
2049 void TrackDAO::clearCache() {
2050@@ -1248,7 +1314,125 @@
2051 return false;
2052 }
2053
2054-void TrackDAO::verifyTracksOutside(const QString& libraryPath, volatile bool* pCancel) {
2055+bool TrackDAO::relocateTrack(TrackPointer pTrack, QString newLocation) {
2056+ int newFileSize=-1;
2057+ int newDuration=-1;
2058+ int newTrackLocationId = -1;
2059+ int oldTrackLocationId = -1;
2060+ QString oldCheckSum;
2061+ QString newCheckSum;
2062+ int newMainDirId=0;
2063+ QString oldLocation = pTrack->getLocation();
2064+ int oldFileSize = pTrack->getLength();
2065+ int oldDuration = pTrack->getDuration();
2066+ int id = getTrackId(pTrack->getLocation());
2067+
2068+ ScopedTransaction transaction(m_database);
2069+ // see if this track is not already in the database and retrieve information
2070+ QSqlQuery query(m_database);
2071+ query.prepare("SELECT track_locations.id, checksum, filesize, duration FROM track_locations "
2072+ "INNER JOIN library ON track_locations.id=library.location "
2073+ "WHERE location= \"" + newLocation + "\"");
2074+ if (!query.exec())
2075+ LOG_FAILED_QUERY(query);
2076+
2077+ while (query.next()) {
2078+ newTrackLocationId = query.value(query.record().indexOf("id")).toInt();
2079+ newFileSize = query.value(query.record().indexOf("filesize")).toInt();
2080+ newCheckSum = query.value(query.record().indexOf("checksum")).toString();
2081+ newDuration = query.value(query.record().indexOf("duration")).toInt();
2082+ }
2083+
2084+ // retrieve information about the old track
2085+ query.prepare("SELECT id, checksum FROM track_locations "
2086+ "WHERE location = \""+oldLocation+"\"");
2087+ if (!query.exec())
2088+ LOG_FAILED_QUERY(query);
2089+ while (query.next()) {
2090+ oldCheckSum = query.value(query.record().indexOf("checksum")).toString();
2091+ oldTrackLocationId = query.value(query.record().indexOf("id")).toInt();
2092+ //qDebug() << oldTrackLocationId << " old id";
2093+ }
2094+
2095+ // check if the new track is in a Folder that mixxx watches
2096+ query.prepare("SELECT dir_id, directory FROM directories");
2097+ if (!query.exec()) {
2098+ LOG_FAILED_QUERY(query) << "There are no directories saved in the db";
2099+ }
2100+ while (query.next()) {
2101+ QString dir = query.value(query.record().indexOf("directory")).toString();
2102+ if (newLocation.contains(dir)) {
2103+ newMainDirId = query.value(query.record().indexOf("dir_id")).toInt();
2104+ }
2105+ }
2106+
2107+ // check we already know a track in that location and make sanity check
2108+ // that this new track actually is the same as the old one
2109+ if (newTrackLocationId >= 0 &&
2110+ ((newFileSize == oldFileSize) &&
2111+ (oldCheckSum==newCheckSum) &&
2112+ (newDuration==oldDuration))) {
2113+
2114+ //The library scanner will have added a new row to the Library
2115+ //table which corresponds to the track in the new location. We need
2116+ //to remove that so we don't end up with two rows in the library table
2117+ //for the same track.
2118+ query.prepare("DELETE FROM library INNER JOIN track_locations ON "
2119+ "library.locations = track_locations.id WHERE library.location=:newid");
2120+ query.bindValue(":newid", newTrackLocationId);
2121+ Q_ASSERT(query.exec());
2122+
2123+ // Update the location foreign key for the existing row in the library table
2124+ // to point to the correct row in the track_locations table.
2125+ query.prepare("UPDATE track_locations "
2126+ "SET location=:newloc, maindir_id=:dirid WHERE location=:oldloc");
2127+ query.bindValue(":newloc", "\"" +newLocation + "\"");
2128+ query.bindValue(":dirid",newMainDirId);
2129+ query.bindValue(":oldloc","\"" +oldLocation + "\"");
2130+ Q_ASSERT(query.exec());
2131+ } else {
2132+ // New locazion was unknown,
2133+ // we can simply change the location
2134+ TrackInfoObject newTrack(newLocation);
2135+ QString filename = newTrack.getFilename();
2136+ QString location = newTrack.getLocation();
2137+ QString directory = newTrack.getDirectory();
2138+ newFileSize = newTrack.getLength();
2139+ newDuration = newTrack.getDuration();
2140+
2141+ newCheckSum = calcChecksum(newLocation);
2142+ if ((newCheckSum != oldCheckSum) && (oldFileSize != newFileSize)
2143+ && (newDuration!=oldDuration)) {
2144+ qDebug() << "that is another song";
2145+ qDebug() << "checksum " << oldCheckSum << " vs " << newCheckSum;
2146+ qDebug() << "filesize " << oldFileSize << " vs " << newFileSize;
2147+ qDebug() << "duration " << oldDuration << " vs " << newDuration;
2148+ return false;
2149+ }
2150+
2151+ query.prepare("UPDATE track_locations "
2152+ "SET location=\""+location+"\", filename=\""+filename+"\","
2153+ " directory=\""+directory+"\", "
2154+ "fs_deleted=0, maindir_id= "+QString::number(newMainDirId)+
2155+ " WHERE id="+QString::number(oldTrackLocationId));
2156+
2157+ // qDebug() << "will update it";
2158+ // qDebug() << query.lastQuery();
2159+ if (!query.exec()) {
2160+ LOG_FAILED_QUERY(query) << " update failed";
2161+ return false;
2162+ }
2163+ }
2164+ transaction.commit();
2165+ // remove tracks from cache and BTC
2166+ QSet<int> ids;
2167+ ids.insert(id);
2168+ databaseTracksMoved(ids,ids);
2169+ uncacheTracks(ids);
2170+ return true;
2171+}
2172+
2173+void TrackDAO::verifyTracksOutside(volatile bool* pCancel) {
2174 // This function is called from the LibraryScanner Thread
2175 ScopedTransaction transaction(m_database);
2176 QSqlQuery query(m_database);
2177@@ -1258,10 +1442,7 @@
2178 query.setForwardOnly(true);
2179 query.prepare("SELECT location "
2180 "FROM track_locations "
2181- "WHERE directory NOT LIKE '" +
2182- libraryPath +
2183- "/%'"); //Add wildcard to SQL query to match subdirectories!
2184-
2185+ "WHERE maindir_id=0");
2186 if (!query.exec()) {
2187 LOG_FAILED_QUERY(query);
2188 return;
2189@@ -1287,3 +1468,53 @@
2190 qDebug() << "verifyTracksOutside finished";
2191 }
2192
2193+void TrackDAO::markTrackAsDeleted(TrackPointer pTrack){
2194+ int id = pTrack->getId();
2195+ ScopedTransaction transaction(m_database);
2196+ QSqlQuery query;
2197+ query.prepare("UPDATE track_locations SET fs_deleted=1 WHERE id="+QString::number(id));
2198+ if (!query.exec()) {
2199+ LOG_FAILED_QUERY(query) << "Could not mark Track as deleted";
2200+ return;
2201+ }
2202+ transaction.commit();
2203+ QSet<int> ids;
2204+ ids.insert(id);
2205+ uncacheTracks(ids);
2206+ emit(tracksRemoved(ids));
2207+}
2208+
2209+
2210+void TrackDAO::uncacheTracks(QSet<int> ids){
2211+ QMutexLocker locker(&m_sTracksMutex);
2212+ foreach (int id, ids) {
2213+ m_sTracks.remove(id);
2214+ m_trackCache.remove(id);
2215+ }
2216+}
2217+
2218+QString TrackDAO::calcChecksum(TrackInfoObject& pTrack) {
2219+ return calcChecksum(pTrack.getLocation());
2220+}
2221+
2222+QString TrackDAO::calcChecksum(QString location){
2223+ QFile file(location);
2224+ if (!file.exists()) {
2225+ return QString();
2226+ }
2227+ file.open(QIODevice::ReadOnly);
2228+ const int block_size = 4096;
2229+ char buffer[block_size];
2230+ int bytes_read;
2231+ // only ID3v1-Tags are at the end of the file and have a fixed size of
2232+ // 128byte this way we only calc the checksum of the audio
2233+ file.seek(file.size() - 2*block_size);
2234+
2235+ QCryptographicHash hash(QCryptographicHash::Md5);
2236+ if ( (bytes_read = file.read(buffer, block_size)) ) {
2237+ hash.addData(buffer,bytes_read);
2238+ }
2239+ return hash.result().toHex();
2240+}
2241+
2242+
2243
2244=== modified file 'mixxx/src/library/dao/trackdao.h'
2245--- mixxx/src/library/dao/trackdao.h 2013-04-22 19:29:54 +0000
2246+++ mixxx/src/library/dao/trackdao.h 2013-05-18 16:32:26 +0000
2247@@ -52,12 +52,15 @@
2248 const QString TRACKLOCATIONSTABLE_FILESIZE = "filesize";
2249 const QString TRACKLOCATIONSTABLE_FSDELETED = "fs_deleted";
2250 const QString TRACKLOCATIONSTABLE_NEEDSVERIFICATION = "needs_verification";
2251+const QString TRACKLOCATIONSTABLE_FINGERPRINT = "fingerprint";
2252+const QString TRACKLOCATIONSTABLE_MAINDIRID = "maindir_id";
2253
2254 class ScopedTransaction;
2255 class PlaylistDAO;
2256 class AnalysisDao;
2257 class CueDAO;
2258 class CrateDAO;
2259+class DirectoryDAO;
2260
2261 class TrackDAO : public QObject, public virtual DAO {
2262 Q_OBJECT
2263@@ -66,8 +69,8 @@
2264 // synchronized on track metadata change
2265 TrackDAO(QSqlDatabase& database, CueDAO& cueDao,
2266 PlaylistDAO& playlistDao, CrateDAO& crateDao,
2267- AnalysisDao& analysisDao,
2268- ConfigObject<ConfigValue>* pConfig);
2269+ AnalysisDao& analysisDao, DirectoryDAO& directoryDao,
2270+ ConfigObject<ConfigValue>* pConfig = NULL);
2271 virtual ~TrackDAO();
2272
2273 void finish();
2274@@ -81,25 +84,28 @@
2275 int addTrack(const QString& file, bool unremove);
2276 int addTrack(const QFileInfo& fileInfo, bool unremove);
2277 void addTracksPrepare();
2278- bool addTracksAdd(TrackInfoObject* pTrack, bool unremove);
2279+ bool addTracksAdd(TrackInfoObject* pTrack, bool unremove,const int dirId);
2280 void addTracksFinish();
2281 QList<int> addTracks(const QList<QFileInfo> &fileInfoList, bool unremove);
2282 void hideTracks(QList<int> ids);
2283 void purgeTracks(QList<int> ids);
2284+ QStringList deleteTracksFromFS(QList<int> ids);
2285 void unhideTracks(QList<int> ids);
2286 TrackPointer getTrack(int id, bool cacheOnly=false) const;
2287 bool isDirty(int trackId);
2288+ bool relocateTrack(TrackPointer pTrack, QString newLocation);
2289+ void markTrackAsDeleted(TrackPointer pTrack);
2290
2291 // Scanning related calls. Should be elsewhere or private somehow.
2292 void markTrackLocationAsVerified(QString location);
2293 void markTracksInDirectoriesAsVerified(QStringList directories);
2294- void invalidateTrackLocationsInLibrary(QString libraryPath);
2295+ void invalidateTrackLocationsInLibrary();
2296 void markUnverifiedTracksAsDeleted();
2297 void markTrackLocationsAsDeleted(QString directory);
2298- void detectMovedFiles(QSet<int>* pTracksMovedSetNew, QSet<int>* pTracksMovedSetOld);
2299+ void detectMovedFiles(QSet<int>& tracksMovedSetNew, QSet<int>& tracksMovedSetOld);
2300 void databaseTrackAdded(TrackPointer pTrack);
2301 void databaseTracksMoved(QSet<int> tracksMovedSetOld, QSet<int> tracksMovedSetNew);
2302- void verifyTracksOutside(const QString& libraryPath, volatile bool* pCancel);
2303+ void verifyTracksOutside(volatile bool* pCancel);
2304
2305 signals:
2306 void trackDirty(int trackId);
2307@@ -134,10 +140,13 @@
2308 void saveTrack(TrackInfoObject* pTrack);
2309 void updateTrack(TrackInfoObject* pTrack);
2310 void addTrack(TrackInfoObject* pTrack, bool unremove);
2311+ QString calcChecksum(TrackInfoObject& pTrack);
2312+ QString calcChecksum(QString location);
2313 TrackPointer getTrackFromDB(int id) const;
2314 QString absoluteFilePath(QString location);
2315+ void uncacheTracks(QSet<int> ids);
2316
2317- void bindTrackToTrackLocationsInsert(TrackInfoObject* pTrack);
2318+ void bindTrackToTrackLocationsInsert(TrackInfoObject* pTrack, int dirId,QString& checksum);
2319 void bindTrackToLibraryInsert(TrackInfoObject* pTrack, int trackLocationId);
2320
2321 void writeAudioMetaData(TrackInfoObject* pTrack);
2322@@ -149,6 +158,7 @@
2323 PlaylistDAO &m_playlistDao;
2324 CrateDAO &m_crateDao;
2325 AnalysisDao& m_analysisDao;
2326+ DirectoryDAO& m_directoryDAO;
2327 ConfigObject<ConfigValue> * m_pConfig;
2328 static QHash<int, TrackWeakPointer> m_sTracks;
2329 static QMutex m_sTracksMutex;
2330
2331=== modified file 'mixxx/src/library/hiddentablemodel.cpp'
2332--- mixxx/src/library/hiddentablemodel.cpp 2012-06-20 15:49:14 +0000
2333+++ mixxx/src/library/hiddentablemodel.cpp 2013-05-18 16:32:26 +0000
2334@@ -1,28 +1,25 @@
2335-#include <QtCore>
2336-#include <QtGui>
2337-#include <QtSql>
2338-#include "library/trackcollection.h"
2339+#include <QMessageBox>
2340+
2341 #include "library/hiddentablemodel.h"
2342-#include "library/librarytablemodel.h"
2343-#include "mixxxutils.cpp"
2344-
2345
2346 HiddenTableModel::HiddenTableModel(QObject* parent,
2347 TrackCollection* pTrackCollection)
2348 : BaseSqlTableModel(parent, pTrackCollection,
2349- pTrackCollection->getDatabase(),
2350- "mixxx.db.model.missing"),
2351- m_pTrackCollection(pTrackCollection),
2352- m_trackDao(m_pTrackCollection->getTrackDAO()) {
2353-
2354+ NULL,"mixxx.db.model.missing") {
2355+ setTableModel();
2356+}
2357+
2358+HiddenTableModel::~HiddenTableModel() {
2359+}
2360+
2361+void HiddenTableModel::setTableModel(int id){
2362+ Q_UNUSED(id);
2363 QSqlQuery query;
2364- QString tableName("hidden_songs");
2365+ QString tableName("hidden_songs_");
2366
2367 QStringList columns;
2368 columns << "library." + LIBRARYTABLE_ID;
2369-
2370- QString filter("mixxx_deleted");
2371-
2372+ QString filter("mixxx_deleted=1");
2373 query.prepare("CREATE TEMPORARY VIEW IF NOT EXISTS " + tableName + " AS "
2374 "SELECT "
2375 + columns.join(",") +
2376@@ -36,7 +33,7 @@
2377
2378 //Print out any SQL error, if there was one.
2379 if (query.lastError().isValid()) {
2380- qDebug() << __FILE__ << __LINE__ << query.lastError();
2381+ qDebug() << __FILE__ << __LINE__ << query.lastError();
2382 }
2383
2384 QStringList tableColumns;
2385@@ -48,26 +45,6 @@
2386 setDefaultSort(fieldIndex("artist"), Qt::AscendingOrder);
2387 setSearch("");
2388
2389- connect(this, SIGNAL(doSearch(const QString&)),
2390- this, SLOT(slotSearch(const QString&)));
2391-}
2392-
2393-HiddenTableModel::~HiddenTableModel() {
2394-}
2395-
2396-bool HiddenTableModel::addTrack(const QModelIndex& index, QString location) {
2397- Q_UNUSED(index);
2398- Q_UNUSED(location);
2399- return false;
2400-}
2401-
2402-TrackPointer HiddenTableModel::getTrack(const QModelIndex& index) const {
2403- //FIXME: use position instead of location for playlist tracks?
2404-
2405- //const int locationColumnIndex = this->fieldIndex(LIBRARYTABLE_LOCATION);
2406- //QString location = index.sibling(index.row(), locationColumnIndex).data().toString();
2407- int trackId = getTrackId(index);
2408- return m_trackDao.getTrack(trackId);
2409 }
2410
2411 void HiddenTableModel::purgeTracks(const QModelIndexList& indices) {
2412@@ -78,7 +55,7 @@
2413 trackIds.append(trackId);
2414 }
2415
2416- m_trackDao.purgeTracks(trackIds);
2417+ m_trackDAO.purgeTracks(trackIds);
2418
2419 // TODO(rryan) : do not select, instead route event to BTC and notify from
2420 // there.
2421@@ -93,22 +70,34 @@
2422 trackIds.append(trackId);
2423 }
2424
2425- m_trackDao.unhideTracks(trackIds);
2426+ m_trackDAO.unhideTracks(trackIds);
2427
2428 // TODO(rryan) : do not select, instead route event to BTC and notify from
2429 // there.
2430 select(); //Repopulate the data model.
2431 }
2432
2433-
2434-void HiddenTableModel::search(const QString& searchText) {
2435- // qDebug() << "HiddenTableModel::search()" << searchText
2436- // << QThread::currentThread();
2437- emit(doSearch(searchText));
2438-}
2439-
2440-void HiddenTableModel::slotSearch(const QString& searchText) {
2441- BaseSqlTableModel::search(searchText);
2442+void HiddenTableModel::deleteTracks(const QModelIndexList& indices) {
2443+ QMessageBox::StandardButton btn = QMessageBox::question(
2444+ NULL, tr("Confirm Delete"),
2445+ tr("Are you sure you want to delete these files?"),
2446+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
2447+ if (btn == QMessageBox::No) {
2448+ return ;
2449+ }
2450+
2451+ QList<int> trackIds;
2452+ foreach (QModelIndex index, indices) {
2453+ int trackId = getTrackId(index);
2454+ trackIds.append(trackId);
2455+ }
2456+ QStringList failed = m_trackDAO.deleteTracksFromFS(trackIds);
2457+ if (!failed.isEmpty()) {
2458+ QMessageBox::warning(NULL, tr("Mixxx"),
2459+ tr("The following track (%1) could not be removed"
2460+ "because the files are still in use").arg(failed.join(",")));
2461+ }
2462+ select(); //Repopulate the data model.
2463 }
2464
2465 bool HiddenTableModel::isColumnInternal(int column) {
2466@@ -116,7 +105,8 @@
2467 column == fieldIndex(LIBRARYTABLE_PLAYED) ||
2468 column == fieldIndex(LIBRARYTABLE_BPM_LOCK) ||
2469 column == fieldIndex(LIBRARYTABLE_MIXXXDELETED) ||
2470- column == fieldIndex(TRACKLOCATIONSTABLE_FSDELETED)) {
2471+ column == fieldIndex(TRACKLOCATIONSTABLE_FSDELETED) ||
2472+ column == fieldIndex(TRACKLOCATIONSTABLE_MAINDIRID)) {
2473 return true;
2474 }
2475 return false;
2476@@ -136,5 +126,7 @@
2477 TrackModel::CapabilitiesFlags HiddenTableModel::getCapabilities() const {
2478 return TRACKMODELCAPS_NONE
2479 | TRACKMODELCAPS_PURGE
2480- | TRACKMODELCAPS_UNHIDE;
2481+ | TRACKMODELCAPS_UNHIDE
2482+ | TRACKMODELCAPS_RELOCATE
2483+ | TRACKMODELCAPS_DELETEFS;
2484 }
2485
2486=== modified file 'mixxx/src/library/hiddentablemodel.h'
2487--- mixxx/src/library/hiddentablemodel.h 2013-05-18 16:23:08 +0000
2488+++ mixxx/src/library/hiddentablemodel.h 2013-05-18 16:32:26 +0000
2489@@ -3,33 +3,20 @@
2490
2491 #include "library/basesqltablemodel.h"
2492
2493-class TrackCollection;
2494-
2495 class HiddenTableModel : public BaseSqlTableModel {
2496 Q_OBJECT
2497 public:
2498 HiddenTableModel(QObject* parent, TrackCollection* pTrackCollection);
2499 virtual ~HiddenTableModel();
2500- TrackPointer getTrack(const QModelIndex& index) const;
2501- void search(const QString& searchText);
2502+ void setTableModel(int id = -1);
2503 bool isColumnInternal(int column);
2504 bool isColumnHiddenByDefault(int column);
2505 void purgeTracks(const QModelIndexList& indices);
2506+ void deleteTracks(const QModelIndexList& indices);
2507 void unhideTracks(const QModelIndexList& indices);
2508- bool addTrack(const QModelIndex& index, QString location);
2509
2510 Qt::ItemFlags flags(const QModelIndex &index) const;
2511 TrackModel::CapabilitiesFlags getCapabilities() const;
2512-
2513- private slots:
2514- void slotSearch(const QString& searchText);
2515-
2516- signals:
2517- void doSearch(const QString& searchText);
2518-
2519- private:
2520- TrackCollection* m_pTrackCollection;
2521- TrackDAO& m_trackDao;
2522 };
2523
2524 #endif
2525
2526=== modified file 'mixxx/src/library/itunes/itunesfeature.cpp'
2527--- mixxx/src/library/itunes/itunesfeature.cpp 2013-01-01 11:53:13 +0000
2528+++ mixxx/src/library/itunes/itunesfeature.cpp 2013-05-18 16:32:26 +0000
2529@@ -25,10 +25,12 @@
2530 #endif
2531 }
2532
2533-ITunesFeature::ITunesFeature(QObject* parent, TrackCollection* pTrackCollection)
2534+ITunesFeature::ITunesFeature(QObject* parent, TrackCollection* pTrackCollection
2535+ ,ConfigObject<ConfigValue>* pConfig)
2536 : BaseExternalLibraryFeature(parent, pTrackCollection),
2537- m_pTrackCollection(pTrackCollection),
2538- m_cancelImport(false) {
2539+ m_pTrackCollection(pTrackCollection),
2540+ m_cancelImport(false),
2541+ m_pConfig(pConfig) {
2542 QString tableName = "itunes_library";
2543 QString idColumn = "id";
2544 QStringList columns;
2545@@ -53,13 +55,13 @@
2546 this, m_pTrackCollection,
2547 "mixxx.db.model.itunes",
2548 "itunes_library",
2549- "itunes");
2550+ "itunes",m_pConfig);
2551 m_pITunesPlaylistModel = new BaseExternalPlaylistModel(
2552 this, m_pTrackCollection,
2553 "mixxx.db.model.itunes_playlist",
2554 "itunes_playlists",
2555 "itunes_playlist_tracks",
2556- "itunes");
2557+ "itunes",m_pConfig);
2558 m_isActivated = false;
2559 m_title = tr("iTunes");
2560
2561@@ -86,7 +88,7 @@
2562 "mixxx.db.model.itunes_playlist",
2563 "itunes_playlists",
2564 "itunes_playlist_tracks",
2565- "itunes");
2566+ "itunes", m_pConfig);
2567 pModel->setPlaylist(playlist);
2568 return pModel;
2569 }
2570@@ -360,12 +362,12 @@
2571 void ITunesFeature::parseTracks(QXmlStreamReader &xml) {
2572 QSqlQuery query(m_database);
2573 query.prepare("INSERT INTO itunes_library (id, artist, title, album, year, genre, comment, tracknumber,"
2574- "bpm, bitrate,"
2575- "duration, location,"
2576- "rating ) "
2577- "VALUES (:id, :artist, :title, :album, :year, :genre, :comment, :tracknumber,"
2578- ":bpm, :bitrate,"
2579- ":duration, :location," ":rating )");
2580+ "bpm, bitrate,"
2581+ "duration, location,"
2582+ "rating ) "
2583+ "VALUES (:id, :artist, :title, :album, :year, :genre, :comment, :tracknumber,"
2584+ ":bpm, :bitrate,"
2585+ ":duration, :location," ":rating )");
2586
2587
2588 bool in_container_dictionary = false;
2589@@ -533,7 +535,7 @@
2590 TreeItem* rootItem = new TreeItem();
2591 QSqlQuery query_insert_to_playlists(m_database);
2592 query_insert_to_playlists.prepare("INSERT INTO itunes_playlists (id, name) "
2593- "VALUES (:id, :name)");
2594+ "VALUES (:id, :name)");
2595
2596 QSqlQuery query_insert_to_playlist_tracks(m_database);
2597 query_insert_to_playlist_tracks.prepare(
2598@@ -545,9 +547,9 @@
2599 //We process and iterate the <dict> tags holding playlist summary information here
2600 if (xml.isStartElement() && xml.name() == "dict") {
2601 parsePlaylist(xml,
2602- query_insert_to_playlists,
2603- query_insert_to_playlist_tracks,
2604- rootItem);
2605+ query_insert_to_playlists,
2606+ query_insert_to_playlist_tracks,
2607+ rootItem);
2608 continue;
2609 }
2610 if (xml.isEndElement()) {
2611@@ -570,7 +572,7 @@
2612 }
2613
2614 void ITunesFeature::parsePlaylist(QXmlStreamReader &xml, QSqlQuery &query_insert_to_playlists,
2615- QSqlQuery &query_insert_to_playlist_tracks, TreeItem* root) {
2616+ QSqlQuery &query_insert_to_playlist_tracks, TreeItem* root) {
2617 //qDebug() << "Parse Playlist";
2618
2619 QString playlistname;
2620@@ -623,7 +625,7 @@
2621 bool success = query_insert_to_playlists.exec();
2622 if (!success) {
2623 qDebug() << "SQL Error in ITunesTableModel.cpp: line" << __LINE__
2624- << " " << query_insert_to_playlists.lastError();
2625+ << " " << query_insert_to_playlists.lastError();
2626 return;
2627 }
2628 //append the playlist to the child model
2629@@ -646,7 +648,7 @@
2630 //Insert tracks if we are not in a pre-build playlist
2631 if (!isSystemPlaylist && !query_insert_to_playlist_tracks.exec()) {
2632 qDebug() << "SQL Error in ITunesFeature.cpp: line" << __LINE__ << " "
2633- << query_insert_to_playlist_tracks.lastError();
2634+ << query_insert_to_playlist_tracks.lastError();
2635 qDebug() << "trackid" << track_reference;
2636 qDebug() << "playlistname; " << playlistname;
2637 qDebug() << "-----------------";
2638@@ -670,10 +672,10 @@
2639
2640 if (!success) {
2641 qDebug() << "Could not delete remove old entries from table "
2642- << table_name << " : " << query.lastError();
2643+ << table_name << " : " << query.lastError();
2644 } else {
2645 qDebug() << "iTunes table entries of '"
2646- << table_name <<"' have been cleared.";
2647+ << table_name <<"' have been cleared.";
2648 }
2649 }
2650
2651@@ -693,7 +695,7 @@
2652 NULL,
2653 tr("Error Loading iTunes Library"),
2654 tr("There was an error loading your iTunes library. Some of "
2655- "your iTunes tracks or playlists may not have loaded."));
2656+ "your iTunes tracks or playlists may not have loaded."));
2657 }
2658 // calls a slot in the sidebarmodel such that 'isLoading' is removed from the feature title.
2659 m_title = tr("iTunes");
2660
2661=== modified file 'mixxx/src/library/itunes/itunesfeature.h'
2662--- mixxx/src/library/itunes/itunesfeature.h 2013-01-01 11:53:13 +0000
2663+++ mixxx/src/library/itunes/itunesfeature.h 2013-05-18 16:32:26 +0000
2664@@ -14,6 +14,7 @@
2665 #include "library/trackcollection.h"
2666 #include "library/treeitemmodel.h"
2667 #include "library/treeitem.h"
2668+#include "configobject.h"
2669
2670 class BaseExternalTrackModel;
2671 class BaseExternalPlaylistModel;
2672@@ -21,7 +22,8 @@
2673 class ITunesFeature : public BaseExternalLibraryFeature {
2674 Q_OBJECT
2675 public:
2676- ITunesFeature(QObject* parent, TrackCollection* pTrackCollection);
2677+ ITunesFeature(QObject* parent, TrackCollection* pTrackCollection
2678+ ,ConfigObject<ConfigValue>* pConfig);
2679 virtual ~ITunesFeature();
2680 static bool isSupported();
2681
2682@@ -62,6 +64,8 @@
2683 bool m_isActivated;
2684 QString m_dbfile;
2685
2686+ ConfigObject<ConfigValue>* m_pConfig;
2687+
2688 QFutureWatcher<TreeItem*> m_future_watcher;
2689 QFuture<TreeItem*> m_future;
2690 QString m_title;
2691
2692=== modified file 'mixxx/src/library/library.cpp'
2693--- mixxx/src/library/library.cpp 2013-05-18 16:23:08 +0000
2694+++ mixxx/src/library/library.cpp 2013-05-18 16:32:26 +0000
2695@@ -2,6 +2,8 @@
2696 // Created 8/23/2009 by RJ Ryan (rryan@mit.edu)
2697
2698 #include <QItemSelectionModel>
2699+#include <QFuture>
2700+#include <QtConcurrentMap>
2701
2702 #include "library/library.h"
2703 #include "library/libraryfeature.h"
2704@@ -41,48 +43,50 @@
2705 m_pSidebarModel(new SidebarModel(parent)),
2706 m_pTrackCollection(new TrackCollection(pConfig)),
2707 m_pLibraryControl(new LibraryControl),
2708- m_pRecordingManager(pRecordingManager) {
2709+ m_pRecordingManager(pRecordingManager),
2710+ m_directoryDAO(m_pTrackCollection->getDirectoryDAO()) {
2711
2712 // TODO(rryan) -- turn this construction / adding of features into a static
2713 // method or something -- CreateDefaultLibrary
2714- m_pMixxxLibraryFeature = new MixxxLibraryFeature(this, m_pTrackCollection,m_pConfig);
2715- addFeature(m_pMixxxLibraryFeature);
2716+ m_pMixxxLibraryFeature = new MixxxLibraryFeature(this, m_pTrackCollection,pConfig);
2717+ addFeature(m_pMixxxLibraryFeature,true);
2718
2719 #ifdef __PROMO__
2720 if (PromoTracksFeature::isSupported(m_pConfig)) {
2721 m_pPromoTracksFeature = new PromoTracksFeature(this, pConfig,
2722 m_pTrackCollection,
2723 firstRun);
2724- addFeature(m_pPromoTracksFeature);
2725+ addFeature(m_pPromoTracksFeature,false);
2726 } else {
2727 m_pPromoTracksFeature = NULL;
2728 }
2729 #endif
2730
2731- addFeature(new AutoDJFeature(this, pConfig, m_pTrackCollection));
2732+ addFeature(new AutoDJFeature(this, pConfig, m_pTrackCollection),true);
2733 m_pPlaylistFeature = new PlaylistFeature(this, m_pTrackCollection, pConfig);
2734- addFeature(m_pPlaylistFeature);
2735+ addFeature(m_pPlaylistFeature,true);
2736 m_pCrateFeature = new CrateFeature(this, m_pTrackCollection, pConfig);
2737- addFeature(m_pCrateFeature);
2738- addFeature(new BrowseFeature(this, pConfig, m_pTrackCollection, m_pRecordingManager));
2739- addFeature(new RecordingFeature(this, pConfig, m_pTrackCollection, m_pRecordingManager));
2740- addFeature(new SetlogFeature(this, pConfig, m_pTrackCollection));
2741+ addFeature(m_pCrateFeature,true);
2742+ addFeature(new BrowseFeature(this, pConfig, m_pTrackCollection, m_pRecordingManager),false);
2743+ addFeature(new RecordingFeature(this, pConfig, m_pTrackCollection, m_pRecordingManager),false);
2744+ // the history should show ALL songs
2745+ addFeature(new SetlogFeature(this, pConfig, m_pTrackCollection),false);
2746 m_pPrepareFeature = new PrepareFeature(this, pConfig, m_pTrackCollection);
2747- addFeature(m_pPrepareFeature);
2748+ addFeature(m_pPrepareFeature,false);
2749 //iTunes and Rhythmbox should be last until we no longer have an obnoxious
2750 //messagebox popup when you select them. (This forces you to reach for your
2751 //mouse or keyboard if you're using MIDI control and you scroll through them...)
2752 if (RhythmboxFeature::isSupported() &&
2753 pConfig->getValueString(ConfigKey("[Library]","ShowRhythmboxLibrary"),"1").toInt()) {
2754- addFeature(new RhythmboxFeature(this, m_pTrackCollection));
2755+ addFeature(new RhythmboxFeature(this, m_pTrackCollection,pConfig),false);
2756 }
2757 if (ITunesFeature::isSupported() &&
2758 pConfig->getValueString(ConfigKey("[Library]","ShowITunesLibrary"),"1").toInt()) {
2759- addFeature(new ITunesFeature(this, m_pTrackCollection));
2760+ addFeature(new ITunesFeature(this, m_pTrackCollection, pConfig),false);
2761 }
2762 if (TraktorFeature::isSupported() &&
2763 pConfig->getValueString(ConfigKey("[Library]","ShowTraktorLibrary"),"1").toInt()) {
2764- addFeature(new TraktorFeature(this, m_pTrackCollection));
2765+ addFeature(new TraktorFeature(this, m_pTrackCollection,pConfig),false);
2766 }
2767
2768 //Show the promo tracks view on first run, otherwise show the library
2769@@ -157,7 +161,7 @@
2770 }
2771 }
2772
2773-void Library::addFeature(LibraryFeature* feature) {
2774+void Library::addFeature(LibraryFeature* feature, bool config) {
2775 Q_ASSERT(feature);
2776 m_features.push_back(feature);
2777 m_pSidebarModel->addLibraryFeature(feature);
2778@@ -171,15 +175,19 @@
2779 this, SLOT(slotLoadTrackToPlayer(TrackPointer, QString, bool)));
2780 connect(feature, SIGNAL(restoreSearch(const QString&)),
2781 this, SLOT(slotRestoreSearch(const QString&)));
2782+ if (config) {
2783+ connect(this, SIGNAL(configChanged(QString,QString)),
2784+ feature, SIGNAL(configChanged(QString,QString)));
2785+ }
2786 }
2787
2788 void Library::slotShowTrackModel(QAbstractItemModel* model) {
2789- //qDebug() << "Library::slotShowTrackModel" << model;
2790- TrackModel* trackModel = dynamic_cast<TrackModel*>(model);
2791- Q_ASSERT(trackModel);
2792+ qDebug() << "Library::slotShowTrackModel" << model;
2793+ m_ptrackModel = dynamic_cast<TrackModel*>(model);
2794+ Q_ASSERT(m_ptrackModel);
2795 emit(showTrackModel(model));
2796 emit(switchToView(m_sTrackViewName));
2797- emit(restoreSearch(trackModel->currentSearch()));
2798+ emit(restoreSearch(m_ptrackModel->currentSearch()));
2799 }
2800
2801 void Library::slotSwitchToView(const QString& view) {
2802@@ -242,3 +250,55 @@
2803 #endif
2804 return QList<TrackPointer>();
2805 }
2806+
2807+MixxxLibraryFeature* Library::getpMixxxLibraryFeature(){
2808+ return m_pMixxxLibraryFeature;
2809+}
2810+
2811+void Library::slotDirsChanged(QString op, QString dir){
2812+ qDebug() << "kain88 slotDirsChanged";
2813+ qDebug() << op << '\t' << dir;
2814+ if (op=="added") {
2815+ m_directoryDAO.addDirectory(dir);
2816+ } else if (op=="removed") {
2817+ purgeTracks(m_directoryDAO.getDirId(dir));
2818+ m_directoryDAO.purgeDirectory(dir);
2819+ } else if (op=="relocate") {
2820+ // see dlgprefplaylist for this
2821+ QStringList dirs = dir.split("!(~)!");
2822+ QString newFolder = dirs[0];
2823+ QString oldFolder = dirs[1];
2824+ m_directoryDAO.relocateDirectory(oldFolder,newFolder);
2825+ } else if (op=="update") {
2826+ // this will be signaled from the library scanner if the db needs to be
2827+ // updated
2828+ m_directoryDAO.addDirectory(dir);
2829+ m_directoryDAO.updateTrackLocations(dir);
2830+ }
2831+}
2832+
2833+void Library::purgeTracks(const int dirId) {
2834+ QSqlQuery query;
2835+ QList<int> trackIds;
2836+ query.prepare("SELECT library.id FROM library INNER JOIN track_locations "
2837+ "ON library.location=track_locations.id "
2838+ "WHERE maindir_id="+QString::number(dirId));
2839+
2840+ if (!query.exec()) {
2841+ qDebug() << "could not purge tracks from libraryPath "<<dirId;
2842+ }
2843+
2844+ while (query.next()) {
2845+ trackIds.append(query.value(query.record().indexOf("id")).toInt());
2846+ }
2847+ qDebug() << "starting to purge Tracks " << trackIds;
2848+ m_pTrackCollection->getTrackDAO().purgeTracks(trackIds);
2849+}
2850+
2851+void Library::slotLoadTrackFailed(TrackPointer pTrack){
2852+ m_pTrackCollection->getTrackDAO().markTrackAsDeleted(pTrack);
2853+}
2854+
2855+QStringList Library::getDirs(){
2856+ return m_directoryDAO.getDirs();
2857+}
2858
2859=== modified file 'mixxx/src/library/library.h'
2860--- mixxx/src/library/library.h 2013-02-09 00:38:39 +0000
2861+++ mixxx/src/library/library.h 2013-05-18 16:32:26 +0000
2862@@ -14,7 +14,9 @@
2863 #include "configobject.h"
2864 #include "trackinfoobject.h"
2865 #include "recording/recordingmanager.h"
2866+#include "mixxxlibraryfeature.h"
2867 #include "preparefeature.h"
2868+#include "library/dao/directorydao.h"
2869
2870 class TrackModel;
2871 class TrackCollection;
2872@@ -24,6 +26,7 @@
2873 class WLibrarySidebar;
2874 class WLibrary;
2875 class WSearchLineEdit;
2876+class PromoTracksFeature;
2877 class MixxxLibraryFeature;
2878 class PlaylistFeature;
2879 class CrateFeature;
2880@@ -42,8 +45,10 @@
2881 MixxxKeyboard* pKeyboard);
2882 void bindSidebarWidget(WLibrarySidebar* sidebarWidget);
2883
2884- void addFeature(LibraryFeature* feature);
2885+ void addFeature(LibraryFeature* feature, bool config);
2886 QList<TrackPointer> getTracksToAutoLoad();
2887+ MixxxLibraryFeature* getpMixxxLibraryFeature();
2888+ QStringList getDirs();
2889
2890 // TODO(rryan) Transitionary only -- the only reason this is here is so the
2891 // waveform widgets can signal to a player to load a track. This can be
2892@@ -65,6 +70,8 @@
2893 void slotRefreshLibraryModels();
2894 void slotCreatePlaylist();
2895 void slotCreateCrate();
2896+ void slotDirsChanged(QString,QString);
2897+ void slotLoadTrackFailed(TrackPointer pTrack);
2898 void onSkinLoadFinished();
2899
2900 signals:
2901@@ -73,11 +80,17 @@
2902 void loadTrack(TrackPointer pTrack);
2903 void loadTrackToPlayer(TrackPointer pTrack, QString group, bool play = false);
2904 void restoreSearch(const QString&);
2905+ void configChanged(QString, QString);
2906+ void dirsChanged(QString,QString);
2907+ void loadTrackFailed(TrackPointer);
2908 void search(const QString& text);
2909 void searchCleared();
2910 void searchStarting();
2911
2912 private:
2913+ void purgeTracks(const int dirId);
2914+ static QString mpChanged(const QString);
2915+
2916 ConfigObject<ConfigValue>* m_pConfig;
2917 SidebarModel* m_pSidebarModel;
2918 TrackCollection* m_pTrackCollection;
2919@@ -94,6 +107,8 @@
2920 PrepareFeature* m_pPrepareFeature;
2921 LibraryControl* m_pLibraryControl;
2922 RecordingManager* m_pRecordingManager;
2923+ TrackModel* m_ptrackModel;
2924+ DirectoryDAO m_directoryDAO;
2925 };
2926
2927 #endif /* LIBRARY_H */
2928
2929=== modified file 'mixxx/src/library/libraryfeature.h'
2930--- mixxx/src/library/libraryfeature.h 2013-02-03 18:50:24 +0000
2931+++ mixxx/src/library/libraryfeature.h 2013-05-18 16:32:26 +0000
2932@@ -9,6 +9,7 @@
2933 #include <QModelIndex>
2934 #include <QObject>
2935 #include <QString>
2936+#include <QStringList>
2937 #include <QVariant>
2938 #include <QAbstractItemModel>
2939 #include <QUrl>
2940@@ -87,11 +88,11 @@
2941 void restoreSearch(const QString&);
2942 // emit this signal before you parse a large music collection, e.g., iTunes, Traktor.
2943 void featureIsLoading(LibraryFeature*);
2944- // emit this signal if the foreign music collection has been imported/parsed.
2945+ // emit this signal if the foreign music collection has been imported/parsed.
2946 void featureLoadingFinished(LibraryFeature*s);
2947- // emit this signal to select pFeature
2948+ // emit this signal to select pFeature
2949 void featureSelect(LibraryFeature* pFeature, const QModelIndex& index);
2950-
2951+ void availableDirsChanged(QList<int>);
2952 };
2953
2954 #endif /* LIBRARYFEATURE_H */
2955
2956=== modified file 'mixxx/src/library/libraryscanner.cpp'
2957--- mixxx/src/library/libraryscanner.cpp 2013-02-09 22:06:46 +0000
2958+++ mixxx/src/library/libraryscanner.cpp 2013-05-18 16:32:26 +0000
2959@@ -33,9 +33,10 @@
2960 m_cueDao(m_database),
2961 m_playlistDao(m_database),
2962 m_crateDao(m_database),
2963+ m_directoryDao(m_database),
2964 m_analysisDao(m_database, collection->getConfig()),
2965 m_trackDao(m_database, m_cueDao, m_playlistDao, m_crateDao,
2966- m_analysisDao, collection->getConfig()),
2967+ m_analysisDao,m_directoryDao, collection->getConfig()),
2968 // Don't initialize m_database here, we need to do it in run() so the DB
2969 // conn is in the right thread.
2970 m_nameFilters(SoundSourceProxy::supportedFileExtensionsString().split(" ")),
2971@@ -51,6 +52,17 @@
2972 connect(this, SIGNAL(scanFinished()),
2973 &(collection->getTrackDAO()), SLOT(clearCache()));
2974
2975+ //connect the new trackDAO with the default BaseTrackCacheR
2976+ connect(&m_trackDao, SIGNAL(tracksRemoved(QSet<int>)),
2977+ &*(collection->getTrackSource(QString("default"))),
2978+ SLOT(slotTracksRemoved(QSet<int>)));
2979+ connect(&m_trackDao, SIGNAL(tracksAdded(QSet<int>)),
2980+ &*(collection->getTrackSource(QString("default"))),
2981+ SLOT(slotTracksAdded(QSet<int>)));
2982+ connect(this, SIGNAL(tracksRestored(QSet<int>)),
2983+ &*(collection->getTrackSource(QString("default"))),
2984+ SLOT(slotTracksAdded(QSet<int>)));
2985+
2986 // The "Album Artwork" folder within iTunes stores Album Arts.
2987 // It has numerous hundreds of sub folders but no audio files
2988 // We put this folder on a "black list"
2989@@ -128,7 +140,7 @@
2990 // Rollback any uncommitted transaction
2991 if (m_database.rollback()) {
2992 qDebug() << "ERROR: There was a transaction in progress while closing the library scanner connection."
2993- << "There is a logic error somewhere.";
2994+ << "There is a logic error somewhere.";
2995 }
2996 // Close our database connection
2997 m_database.close();
2998@@ -214,7 +226,7 @@
2999 // verification of their existance...
3000 // (ie. we want to check they're still on your hard drive where
3001 // we think they are)
3002- m_trackDao.invalidateTrackLocationsInLibrary(m_qLibraryPath);
3003+ m_trackDao.invalidateTrackLocationsInLibrary();
3004
3005 qDebug() << "Recursively scanning library.";
3006 // Start scanning the library.
3007@@ -224,19 +236,26 @@
3008 m_trackDao.addTracksPrepare();
3009 QStringList verifiedDirectories;
3010
3011- bool bScanFinishedCleanly = recursiveScan(m_qLibraryPath, verifiedDirectories);
3012-
3013- if (!bScanFinishedCleanly) {
3014- qDebug() << "Recursive scan interrupted.";
3015- } else {
3016- qDebug() << "Recursive scan finished cleanly.";
3017+ QStringList dirs = m_directoryDao.getDirs();
3018+ QSet<int> restoredTracks;
3019+ bool bScanFinishedCleanly=false;
3020+ //recursivly scan each dir that is saved in the directories table
3021+ foreach (QString dir , dirs) {
3022+ int dirId = m_directoryDao.getDirId(dir);
3023+ bScanFinishedCleanly = recursiveScan(dir,verifiedDirectories,restoredTracks,dirId);
3024+ //Verify all Tracks inside Library but outside the library path
3025+ if (!bScanFinishedCleanly) {
3026+ qDebug() << "Recursive scan interrupted.";
3027+ } else {
3028+ qDebug() << "Recursive scan finished cleanly.";
3029+ }
3030 }
3031+ m_trackDao.verifyTracksOutside(&m_bCancelLibraryScan);
3032
3033 // Runs inside a transaction
3034 m_trackDao.addTracksFinish();
3035-
3036- //Verify all Tracks inside Library but outside the library path
3037- m_trackDao.verifyTracksOutside(m_qLibraryPath, &m_bCancelLibraryScan);
3038+ // this will cause BaseTrackCache to update the index of all restored tracks
3039+ emit(tracksRestored(restoredTracks));
3040
3041 // Start a transaction for all the library hashing (moved file detection)
3042 // stuff.
3043@@ -263,7 +282,7 @@
3044 // Check to see if the "deleted" tracks showed up in another location,
3045 // and if so, do some magic to update all our tables.
3046 qDebug() << "Detecting moved files.";
3047- m_trackDao.detectMovedFiles(&tracksMovedSetOld, &tracksMovedSetNew);
3048+ m_trackDao.detectMovedFiles(tracksMovedSetOld, tracksMovedSetNew);
3049
3050 // Remove the hashes for any directories that have been
3051 // marked as deleted to clean up. We need to do this otherwise
3052@@ -289,10 +308,8 @@
3053 emit(scanFinished());
3054 }
3055
3056-void LibraryScanner::scan(QString libraryPath, QWidget *parent)
3057-{
3058- m_qLibraryPath = libraryPath;
3059- m_pProgress = new LibraryScannerDlg(parent);
3060+void LibraryScanner::scan() {
3061+ m_pProgress = new LibraryScannerDlg();
3062 m_pProgress->setAttribute(Qt::WA_DeleteOnClose);
3063
3064 // The important part here is that we need to use
3065@@ -314,7 +331,7 @@
3066 this, SLOT(cancel()));
3067 connect(&m_trackDao, SIGNAL(progressVerifyTracksOutside(QString)),
3068 m_pProgress, SLOT(slotUpdate(QString)));
3069- scan();
3070+ start();
3071 }
3072
3073 //slot
3074@@ -328,15 +345,11 @@
3075 m_bCancelLibraryScan = 0;
3076 }
3077
3078-void LibraryScanner::scan()
3079-{
3080- start(); // Starts the thread by calling run()
3081-}
3082-
3083 // Recursively scan a music library. Doesn't import tracks for any directories that
3084 // have already been scanned and have not changed. Changes are tracked by performing
3085 // a hash of the directory's file list, and those hashes are stored in the database.
3086-bool LibraryScanner::recursiveScan(QString dirPath, QStringList& verifiedDirectories) {
3087+bool LibraryScanner::recursiveScan(QString dirPath, QStringList& verifiedDirectories,
3088+ QSet<int>& restoredTracks, const int dirId) {
3089 QDirIterator fileIt(dirPath, m_nameFilters, QDir::Files | QDir::NoDotAndDotDot);
3090 QString currentFile;
3091 bool bScanFinishedCleanly = true;
3092@@ -376,7 +389,8 @@
3093 }
3094
3095 // Rescan that mofo!
3096- bScanFinishedCleanly = m_pCollection->importDirectory(dirPath, m_trackDao, m_nameFilters, &m_bCancelLibraryScan);
3097+ bScanFinishedCleanly = m_pCollection->importDirectory(dirPath, m_trackDao, m_nameFilters,
3098+ restoredTracks,dirId,&m_bCancelLibraryScan);
3099 } else { //prevHash == newHash
3100 // Add the directory to the verifiedDirectories list, so that later they
3101 // (and the tracks inside them) will be marked as verified
3102@@ -401,7 +415,7 @@
3103 if (m_directoriesBlacklist.contains(nextPath))
3104 continue;
3105
3106- if (!recursiveScan(nextPath, verifiedDirectories)) {
3107+ if (!recursiveScan(nextPath, verifiedDirectories,restoredTracks,dirId)) {
3108 bScanFinishedCleanly = false;
3109 }
3110 }
3111
3112=== modified file 'mixxx/src/library/libraryscanner.h'
3113--- mixxx/src/library/libraryscanner.h 2012-12-06 17:11:14 +0000
3114+++ mixxx/src/library/libraryscanner.h 2013-05-18 16:32:26 +0000
3115@@ -16,7 +16,6 @@
3116 * *
3117 ***************************************************************************/
3118
3119-
3120 #ifndef LIBRARYSCANNER_H
3121 #define LIBRARYSCANNER_H
3122
3123@@ -27,6 +26,7 @@
3124 #include "library/dao/cratedao.h"
3125 #include "library/dao/cuedao.h"
3126 #include "library/dao/libraryhashdao.h"
3127+#include "library/dao/directorydao.h"
3128 #include "library/dao/playlistdao.h"
3129 #include "library/dao/trackdao.h"
3130 #include "library/dao/analysisdao.h"
3131@@ -46,18 +46,20 @@
3132 void run();
3133 void scan(QString libraryPath, QWidget *parent);
3134 void scan();
3135- bool recursiveScan(QString dirPath, QStringList& verifiedDirectories);
3136+
3137 public slots:
3138 void cancel();
3139 void resetCancel();
3140 signals:
3141 void scanFinished();
3142 void progressHashing(QString);
3143+ void tracksRestored(QSet<int>);
3144 private:
3145+ bool recursiveScan(QString dirPath, QStringList& verifiedDirectories,
3146+ QSet<int>& restoredTracks,const int dirId);
3147 TrackCollection* m_pCollection; // The library trackcollection
3148 QSqlDatabase m_database; // Hang on to a different DB connection
3149 // since we run in a different thread */
3150- QString m_qLibraryPath; // The path to the library on disk
3151 LibraryScannerDlg* m_pProgress; // The library scanning window
3152
3153 LibraryHashDAO m_libraryHashDao;
3154@@ -65,6 +67,7 @@
3155 PlaylistDAO m_playlistDao;
3156 CrateDAO m_crateDao;
3157 AnalysisDao m_analysisDao;
3158+ DirectoryDAO m_directoryDao;
3159 TrackDAO m_trackDao;
3160
3161 QStringList m_nameFilters;
3162
3163=== modified file 'mixxx/src/library/librarytablemodel.cpp'
3164--- mixxx/src/library/librarytablemodel.cpp 2012-11-25 11:17:13 +0000
3165+++ mixxx/src/library/librarytablemodel.cpp 2013-05-18 16:32:26 +0000
3166@@ -1,33 +1,53 @@
3167-#include <QtCore>
3168-#include <QtGui>
3169-#include <QtSql>
3170
3171-#include "library/trackcollection.h"
3172 #include "library/librarytablemodel.h"
3173 #include "library/queryutil.h"
3174+#include "controlobjectthread.h"
3175+#include "controlobject.h"
3176 #include "mixxxutils.cpp"
3177 #include "playermanager.h"
3178
3179 const QString LibraryTableModel::DEFAULT_LIBRARYFILTER =
3180- "mixxx_deleted=0 AND fs_deleted=0";
3181+ "mixxx_deleted=0 AND fs_deleted=0";
3182
3183 LibraryTableModel::LibraryTableModel(QObject* parent,
3184 TrackCollection* pTrackCollection,
3185+ ConfigObject<ConfigValue>* pConfig,
3186 QString settingsNamespace)
3187- : BaseSqlTableModel(parent, pTrackCollection,
3188- pTrackCollection->getDatabase(),
3189- settingsNamespace),
3190- m_trackDao(pTrackCollection->getTrackDAO()) {
3191+ : BaseSqlTableModel(parent, pTrackCollection, pConfig, settingsNamespace){
3192+ setTableModel();
3193+}
3194+
3195+LibraryTableModel::~LibraryTableModel() {
3196+}
3197+
3198+void LibraryTableModel::setTableModel(int id){
3199+ Q_UNUSED(id);
3200 QStringList columns;
3201- columns << "library." + LIBRARYTABLE_ID;
3202- columns << "'' as preview";
3203-
3204- QSqlQuery query(pTrackCollection->getDatabase());
3205- QString queryString = "CREATE TEMPORARY VIEW IF NOT EXISTS library_view AS "
3206- "SELECT " + columns.join(",") +
3207+ columns << "library."+LIBRARYTABLE_ID << "'' as preview";
3208+
3209+ //prepareLibrary give a NULL to the constructor so check for it
3210+ bool showMissing;
3211+ if (m_pConfig) {
3212+ showMissing = m_pConfig->getValueString(
3213+ ConfigKey("[Library]","ShowMissingSongs"),"1").toInt();
3214+ } else {
3215+ showMissing = false;
3216+ }
3217+ QString tableName = "library_view";
3218+ QString libraryFilter;
3219+ if (showMissing) {
3220+ libraryFilter = "mixxx_deleted=0";
3221+ tableName.append("_missing");
3222+ } else {
3223+ libraryFilter = "mixxx_deleted=0 AND fs_deleted=0";
3224+ }
3225+
3226+ QSqlQuery query(m_pTrackCollection->getDatabase());
3227+ QString queryString = "CREATE TEMPORARY VIEW IF NOT EXISTS "+tableName+" AS "
3228+ "SELECT " + columns.join(", ") +
3229 " FROM library INNER JOIN track_locations "
3230 "ON library.location = track_locations.id "
3231- "WHERE (" + LibraryTableModel::DEFAULT_LIBRARYFILTER + ")";
3232+ "WHERE (" + libraryFilter + ")";
3233 query.prepare(queryString);
3234 if (!query.exec()) {
3235 LOG_FAILED_QUERY(query);
3236@@ -36,36 +56,16 @@
3237 QStringList tableColumns;
3238 tableColumns << LIBRARYTABLE_ID;
3239 tableColumns << "preview";
3240- setTable("library_view", LIBRARYTABLE_ID, tableColumns,
3241- pTrackCollection->getTrackSource("default"));
3242+ setTable(tableName, LIBRARYTABLE_ID, tableColumns,
3243+ m_pTrackCollection->getTrackSource("default"));
3244
3245 // BaseSqlTabelModel will setup the header info
3246 initHeaderData();
3247
3248 setSearch("");
3249 setDefaultSort(fieldIndex("artist"), Qt::AscendingOrder);
3250-
3251- connect(this, SIGNAL(doSearch(const QString&)),
3252- this, SLOT(slotSearch(const QString&)));
3253-}
3254-
3255-LibraryTableModel::~LibraryTableModel() {
3256-}
3257-
3258-bool LibraryTableModel::addTrack(const QModelIndex& index, QString location) {
3259- Q_UNUSED(index);
3260- QFileInfo fileInfo(location);
3261-
3262- // Adds track, does not insert duplicates, handles unremoving logic.
3263- int trackId = m_trackDao.addTrack(fileInfo, true);
3264- if (trackId >= 0) {
3265- // TODO(rryan) do not select since we will get a signal. instead, do
3266- // something nice UI wise and select the track they dropped.
3267- select(); //Repopulate the data model.
3268- return true;
3269- }
3270- return false;
3271-}
3272+}
3273+
3274
3275 int LibraryTableModel::addTracks(const QModelIndex& index, QList<QString> locations) {
3276 Q_UNUSED(index);
3277@@ -73,35 +73,11 @@
3278 foreach (QString fileLocation, locations) {
3279 fileInfoList.append(QFileInfo(fileLocation));
3280 }
3281- QList<int> trackIds = m_trackDao.addTracks(fileInfoList, true);
3282+ QList<int> trackIds = m_trackDAO.addTracks(fileInfoList, true);
3283 select();
3284 return trackIds.size();
3285 }
3286
3287-TrackPointer LibraryTableModel::getTrack(const QModelIndex& index) const {
3288- int trackId = getTrackId(index);
3289- return m_trackDao.getTrack(trackId);
3290-}
3291-
3292-void LibraryTableModel::moveTrack(const QModelIndex& sourceIndex,
3293- const QModelIndex& destIndex) {
3294- Q_UNUSED(sourceIndex);
3295- Q_UNUSED(destIndex);
3296- // Does nothing because we don't support reordering tracks in the library,
3297- // and getCapabilities() reports that.
3298-}
3299-
3300-void LibraryTableModel::search(const QString& searchText) {
3301- // qDebug() << "LibraryTableModel::search()" << searchText
3302- // << QThread::currentThread();
3303- emit(doSearch(searchText));
3304-}
3305-
3306-void LibraryTableModel::slotSearch(const QString& searchText) {
3307- // qDebug() << "slotSearch()" << searchText << QThread::currentThread();
3308- BaseSqlTableModel::search(searchText);
3309-}
3310-
3311 bool LibraryTableModel::isColumnInternal(int column) {
3312 if ((column == fieldIndex(LIBRARYTABLE_ID)) ||
3313 (column == fieldIndex(LIBRARYTABLE_URL)) ||
3314@@ -115,6 +91,7 @@
3315 (column == fieldIndex(LIBRARYTABLE_BPM_LOCK)) ||
3316 (column == fieldIndex(LIBRARYTABLE_CHANNELS)) ||
3317 (column == fieldIndex(TRACKLOCATIONSTABLE_FSDELETED)) ||
3318+ (column == fieldIndex(TRACKLOCATIONSTABLE_MAINDIRID)) ||
3319 (PlayerManager::numPreviewDecks() == 0 && column == fieldIndex("preview"))) {
3320 return true;
3321 }
3322@@ -141,5 +118,6 @@
3323 | TRACKMODELCAPS_HIDE
3324 | TRACKMODELCAPS_BPMLOCK
3325 | TRACKMODELCAPS_CLEAR_BEATS
3326- | TRACKMODELCAPS_RESETPLAYED;
3327+ | TRACKMODELCAPS_RESETPLAYED
3328+ | TRACKMODELCAPS_RELOCATE;
3329 }
3330
3331=== modified file 'mixxx/src/library/librarytablemodel.h'
3332--- mixxx/src/library/librarytablemodel.h 2013-05-18 16:23:08 +0000
3333+++ mixxx/src/library/librarytablemodel.h 2013-05-18 16:32:26 +0000
3334@@ -1,43 +1,24 @@
3335 #ifndef LIBRARYTABLEMODEL_H
3336 #define LIBRARYTABLEMODEL_H
3337
3338-#include <QtSql>
3339-#include <QtCore>
3340-
3341 #include "library/basesqltablemodel.h"
3342-#include "library/trackmodel.h"
3343-#include "library/dao/trackdao.h"
3344-
3345-class TrackCollection;
3346
3347 class LibraryTableModel : public BaseSqlTableModel {
3348 Q_OBJECT
3349 public:
3350 LibraryTableModel(QObject* parent, TrackCollection* pTrackCollection,
3351+ ConfigObject<ConfigValue>* pConfig,
3352 QString settingsNamespace="mixxx.db.model.library");
3353 virtual ~LibraryTableModel();
3354+ void setTableModel(int id =-1);
3355
3356- TrackPointer getTrack(const QModelIndex& index) const;
3357- void search(const QString& searchText);
3358 bool isColumnInternal(int column);
3359 bool isColumnHiddenByDefault(int column);
3360- bool addTrack(const QModelIndex& index, QString location);
3361 // Takes a list of locations and add the tracks to the library. Returns the
3362 // number of successful additions.
3363 int addTracks(const QModelIndex& index, QList<QString> locations);
3364- void moveTrack(const QModelIndex& sourceIndex,
3365- const QModelIndex& destIndex);
3366 TrackModel::CapabilitiesFlags getCapabilities() const;
3367 static const QString DEFAULT_LIBRARYFILTER;
3368-
3369- private:
3370- TrackDAO& m_trackDao;
3371-
3372- private slots:
3373- void slotSearch(const QString& searchText);
3374-
3375- signals:
3376- void doSearch(const QString& searchText);
3377 };
3378
3379 #endif
3380
3381=== added file 'mixxx/src/library/missingtablemodel.cpp'
3382--- mixxx/src/library/missingtablemodel.cpp 1970-01-01 00:00:00 +0000
3383+++ mixxx/src/library/missingtablemodel.cpp 2013-05-18 16:32:26 +0000
3384@@ -0,0 +1,126 @@
3385+#include <QtCore>
3386+#include <QtGui>
3387+#include <QtSql>
3388+#include "library/trackcollection.h"
3389+#include "library/missingtablemodel.h"
3390+#include "library/librarytablemodel.h"
3391+#include "mixxxutils.cpp"
3392+
3393+const QString MissingTableModel::MISSINGFILTER = "mixxx_deleted=0 AND fs_deleted=1";
3394+
3395+MissingTableModel::MissingTableModel(QObject* parent,
3396+ TrackCollection* pTrackCollection)
3397+ : BaseSqlTableModel(parent, pTrackCollection,
3398+ //TODO kain88 this is not quite right
3399+ NULL,
3400+ "mixxx.db.model.missing"),
3401+ m_pTrackCollection(pTrackCollection),
3402+ m_trackDao(m_pTrackCollection->getTrackDAO()) {
3403+
3404+ QSqlQuery query;
3405+ //query.prepare("DROP VIEW " + playlistTableName);
3406+ //query.exec();
3407+ QString tableName("missing_songs");
3408+
3409+ QStringList columns;
3410+ columns << "library." + LIBRARYTABLE_ID;
3411+
3412+ query.prepare("CREATE TEMPORARY VIEW IF NOT EXISTS " + tableName + " AS "
3413+ "SELECT "
3414+ + columns.join(",") +
3415+ " FROM library "
3416+ "INNER JOIN track_locations "
3417+ "ON library.location=track_locations.id "
3418+ "WHERE " + MissingTableModel::MISSINGFILTER);
3419+ if (!query.exec()) {
3420+ qDebug() << query.executedQuery() << query.lastError();
3421+ }
3422+
3423+ //Print out any SQL error, if there was one.
3424+ if (query.lastError().isValid()) {
3425+ qDebug() << __FILE__ << __LINE__ << query.lastError();
3426+ }
3427+
3428+ QStringList tableColumns;
3429+ tableColumns << LIBRARYTABLE_ID;
3430+ setTable(tableName, LIBRARYTABLE_ID, tableColumns,
3431+ m_pTrackCollection->getTrackSource("default"));
3432+
3433+ initHeaderData();
3434+ setDefaultSort(fieldIndex("artist"), Qt::AscendingOrder);
3435+ setSearch("");
3436+
3437+ connect(this, SIGNAL(doSearch(const QString&)),
3438+ this, SLOT(slotSearch(const QString&)));
3439+}
3440+
3441+MissingTableModel::~MissingTableModel() {
3442+}
3443+
3444+bool MissingTableModel::addTrack(const QModelIndex& index, QString location) {
3445+ Q_UNUSED(index);
3446+ Q_UNUSED(location);
3447+ return false;
3448+}
3449+
3450+TrackPointer MissingTableModel::getTrack(const QModelIndex& index) const {
3451+ //FIXME: use position instead of location for playlist tracks?
3452+
3453+ //const int locationColumnIndex = this->fieldIndex(LIBRARYTABLE_LOCATION);
3454+ //QString location = index.sibling(index.row(), locationColumnIndex).data().toString();
3455+ int trackId = getTrackId(index);
3456+ return m_trackDao.getTrack(trackId);
3457+}
3458+
3459+void MissingTableModel::purgeTracks(const QModelIndexList& indices) {
3460+ QList<int> trackIds;
3461+
3462+ foreach (QModelIndex index, indices) {
3463+ int trackId = getTrackId(index);
3464+ trackIds.append(trackId);
3465+ }
3466+
3467+ m_trackDao.purgeTracks(trackIds);
3468+
3469+ // TODO(rryan) : do not select, instead route event to BTC and notify from
3470+ // there.
3471+ select(); //Repopulate the data model.
3472+}
3473+
3474+
3475+void MissingTableModel::search(const QString& searchText) {
3476+ // qDebug() << "MissingTableModel::search()" << searchText
3477+ // << QThread::currentThread();
3478+ emit(doSearch(searchText));
3479+}
3480+
3481+void MissingTableModel::slotSearch(const QString& searchText) {
3482+ BaseSqlTableModel::search(searchText);
3483+}
3484+
3485+bool MissingTableModel::isColumnInternal(int column) {
3486+ if (column == fieldIndex(LIBRARYTABLE_ID) ||
3487+ column == fieldIndex(LIBRARYTABLE_PLAYED) ||
3488+ column == fieldIndex(LIBRARYTABLE_BPM_LOCK) ||
3489+ column == fieldIndex(LIBRARYTABLE_MIXXXDELETED) ||
3490+ column == fieldIndex(TRACKLOCATIONSTABLE_FSDELETED)) {
3491+ return true;
3492+ }
3493+ return false;
3494+}
3495+bool MissingTableModel::isColumnHiddenByDefault(int column) {
3496+ if (column == fieldIndex(LIBRARYTABLE_KEY)) {
3497+ return true;
3498+ }
3499+ return false;
3500+}
3501+
3502+/** Override flags from BaseSqlModel since we don't want edit this model */
3503+Qt::ItemFlags MissingTableModel::flags(const QModelIndex &index) const {
3504+ return readOnlyFlags(index);
3505+}
3506+
3507+TrackModel::CapabilitiesFlags MissingTableModel::getCapabilities() const {
3508+ return TRACKMODELCAPS_NONE
3509+ | TRACKMODELCAPS_PURGE;
3510+}
3511
3512=== removed file 'mixxx/src/library/missingtablemodel.cpp'
3513--- mixxx/src/library/missingtablemodel.cpp 2013-05-01 02:15:05 +0000
3514+++ mixxx/src/library/missingtablemodel.cpp 1970-01-01 00:00:00 +0000
3515@@ -1,125 +0,0 @@
3516-#include <QtCore>
3517-#include <QtGui>
3518-#include <QtSql>
3519-#include "library/trackcollection.h"
3520-#include "library/missingtablemodel.h"
3521-#include "library/librarytablemodel.h"
3522-#include "mixxxutils.cpp"
3523-
3524-const QString MissingTableModel::MISSINGFILTER = "mixxx_deleted=0 AND fs_deleted=1";
3525-
3526-MissingTableModel::MissingTableModel(QObject* parent,
3527- TrackCollection* pTrackCollection)
3528- : BaseSqlTableModel(parent, pTrackCollection,
3529- pTrackCollection->getDatabase(),
3530- "mixxx.db.model.missing"),
3531- m_pTrackCollection(pTrackCollection),
3532- m_trackDao(m_pTrackCollection->getTrackDAO()) {
3533-
3534- QSqlQuery query(pTrackCollection->getDatabase());
3535- //query.prepare("DROP VIEW " + playlistTableName);
3536- //query.exec();
3537- QString tableName("missing_songs");
3538-
3539- QStringList columns;
3540- columns << "library." + LIBRARYTABLE_ID;
3541-
3542- query.prepare("CREATE TEMPORARY VIEW IF NOT EXISTS " + tableName + " AS "
3543- "SELECT "
3544- + columns.join(",") +
3545- " FROM library "
3546- "INNER JOIN track_locations "
3547- "ON library.location=track_locations.id "
3548- "WHERE " + MissingTableModel::MISSINGFILTER);
3549- if (!query.exec()) {
3550- qDebug() << query.executedQuery() << query.lastError();
3551- }
3552-
3553- //Print out any SQL error, if there was one.
3554- if (query.lastError().isValid()) {
3555- qDebug() << __FILE__ << __LINE__ << query.lastError();
3556- }
3557-
3558- QStringList tableColumns;
3559- tableColumns << LIBRARYTABLE_ID;
3560- setTable(tableName, LIBRARYTABLE_ID, tableColumns,
3561- m_pTrackCollection->getTrackSource("default"));
3562-
3563- initHeaderData();
3564- setDefaultSort(fieldIndex("artist"), Qt::AscendingOrder);
3565- setSearch("");
3566-
3567- connect(this, SIGNAL(doSearch(const QString&)),
3568- this, SLOT(slotSearch(const QString&)));
3569-}
3570-
3571-MissingTableModel::~MissingTableModel() {
3572-}
3573-
3574-bool MissingTableModel::addTrack(const QModelIndex& index, QString location) {
3575- Q_UNUSED(index);
3576- Q_UNUSED(location);
3577- return false;
3578-}
3579-
3580-TrackPointer MissingTableModel::getTrack(const QModelIndex& index) const {
3581- //FIXME: use position instead of location for playlist tracks?
3582-
3583- //const int locationColumnIndex = this->fieldIndex(LIBRARYTABLE_LOCATION);
3584- //QString location = index.sibling(index.row(), locationColumnIndex).data().toString();
3585- int trackId = getTrackId(index);
3586- return m_trackDao.getTrack(trackId);
3587-}
3588-
3589-void MissingTableModel::purgeTracks(const QModelIndexList& indices) {
3590- QList<int> trackIds;
3591-
3592- foreach (QModelIndex index, indices) {
3593- int trackId = getTrackId(index);
3594- trackIds.append(trackId);
3595- }
3596-
3597- m_trackDao.purgeTracks(trackIds);
3598-
3599- // TODO(rryan) : do not select, instead route event to BTC and notify from
3600- // there.
3601- select(); //Repopulate the data model.
3602-}
3603-
3604-
3605-void MissingTableModel::search(const QString& searchText) {
3606- // qDebug() << "MissingTableModel::search()" << searchText
3607- // << QThread::currentThread();
3608- emit(doSearch(searchText));
3609-}
3610-
3611-void MissingTableModel::slotSearch(const QString& searchText) {
3612- BaseSqlTableModel::search(searchText);
3613-}
3614-
3615-bool MissingTableModel::isColumnInternal(int column) {
3616- if (column == fieldIndex(LIBRARYTABLE_ID) ||
3617- column == fieldIndex(LIBRARYTABLE_PLAYED) ||
3618- column == fieldIndex(LIBRARYTABLE_BPM_LOCK) ||
3619- column == fieldIndex(LIBRARYTABLE_MIXXXDELETED) ||
3620- column == fieldIndex(TRACKLOCATIONSTABLE_FSDELETED)) {
3621- return true;
3622- }
3623- return false;
3624-}
3625-bool MissingTableModel::isColumnHiddenByDefault(int column) {
3626- if (column == fieldIndex(LIBRARYTABLE_KEY)) {
3627- return true;
3628- }
3629- return false;
3630-}
3631-
3632-/** Override flags from BaseSqlModel since we don't want edit this model */
3633-Qt::ItemFlags MissingTableModel::flags(const QModelIndex &index) const {
3634- return readOnlyFlags(index);
3635-}
3636-
3637-TrackModel::CapabilitiesFlags MissingTableModel::getCapabilities() const {
3638- return TRACKMODELCAPS_NONE
3639- | TRACKMODELCAPS_PURGE;
3640-}
3641
3642=== added file 'mixxx/src/library/missingtablemodel.h'
3643--- mixxx/src/library/missingtablemodel.h 1970-01-01 00:00:00 +0000
3644+++ mixxx/src/library/missingtablemodel.h 2013-05-18 16:32:26 +0000
3645@@ -0,0 +1,41 @@
3646+#ifndef MISSINGTABLEMODEL_H
3647+#define MISSINGTABLEMODEL_H
3648+
3649+#include <QtSql>
3650+#include <QItemDelegate>
3651+#include <QtCore>
3652+
3653+#include "trackmodel.h"
3654+#include "library/dao/trackdao.h"
3655+#include "library/basesqltablemodel.h"
3656+
3657+class TrackCollection;
3658+
3659+class MissingTableModel : public BaseSqlTableModel {
3660+ Q_OBJECT
3661+ public:
3662+ MissingTableModel(QObject* parent, TrackCollection* pTrackCollection);
3663+ virtual ~MissingTableModel();
3664+ virtual TrackPointer getTrack(const QModelIndex& index) const;
3665+ virtual void search(const QString& searchText);
3666+ virtual bool isColumnInternal(int column);
3667+ virtual bool isColumnHiddenByDefault(int column);
3668+ virtual void purgeTracks(const QModelIndexList& indices);
3669+ virtual bool addTrack(const QModelIndex& index, QString location);
3670+
3671+ Qt::ItemFlags flags(const QModelIndex &index) const;
3672+ TrackModel::CapabilitiesFlags getCapabilities() const;
3673+
3674+ private slots:
3675+ void slotSearch(const QString& searchText);
3676+
3677+ signals:
3678+ void doSearch(const QString& searchText);
3679+
3680+ private:
3681+ TrackCollection* m_pTrackCollection;
3682+ TrackDAO& m_trackDao;
3683+ static const QString MISSINGFILTER;
3684+};
3685+
3686+#endif
3687
3688=== removed file 'mixxx/src/library/missingtablemodel.h'
3689--- mixxx/src/library/missingtablemodel.h 2012-08-10 15:03:46 +0000
3690+++ mixxx/src/library/missingtablemodel.h 1970-01-01 00:00:00 +0000
3691@@ -1,41 +0,0 @@
3692-#ifndef MISSINGTABLEMODEL_H
3693-#define MISSINGTABLEMODEL_H
3694-
3695-#include <QtSql>
3696-#include <QItemDelegate>
3697-#include <QtCore>
3698-
3699-#include "trackmodel.h"
3700-#include "library/dao/trackdao.h"
3701-#include "library/basesqltablemodel.h"
3702-
3703-class TrackCollection;
3704-
3705-class MissingTableModel : public BaseSqlTableModel {
3706- Q_OBJECT
3707- public:
3708- MissingTableModel(QObject* parent, TrackCollection* pTrackCollection);
3709- virtual ~MissingTableModel();
3710- virtual TrackPointer getTrack(const QModelIndex& index) const;
3711- virtual void search(const QString& searchText);
3712- virtual bool isColumnInternal(int column);
3713- virtual bool isColumnHiddenByDefault(int column);
3714- virtual void purgeTracks(const QModelIndexList& indices);
3715- virtual bool addTrack(const QModelIndex& index, QString location);
3716-
3717- Qt::ItemFlags flags(const QModelIndex &index) const;
3718- TrackModel::CapabilitiesFlags getCapabilities() const;
3719-
3720- private slots:
3721- void slotSearch(const QString& searchText);
3722-
3723- signals:
3724- void doSearch(const QString& searchText);
3725-
3726- private:
3727- TrackCollection* m_pTrackCollection;
3728- TrackDAO& m_trackDao;
3729- static const QString MISSINGFILTER;
3730-};
3731-
3732-#endif
3733
3734=== modified file 'mixxx/src/library/mixxxlibraryfeature.cpp'
3735--- mixxx/src/library/mixxxlibraryfeature.cpp 2013-01-17 08:16:08 +0000
3736+++ mixxx/src/library/mixxxlibraryfeature.cpp 2013-05-18 16:32:26 +0000
3737@@ -1,13 +1,10 @@
3738 // mixxxlibraryfeature.cpp
3739 // Created 8/23/2009 by RJ Ryan (rryan@mit.edu)
3740
3741-#include <QtDebug>
3742-
3743 #include "library/mixxxlibraryfeature.h"
3744
3745 #include "library/basetrackcache.h"
3746 #include "library/librarytablemodel.h"
3747-#include "library/missingtablemodel.h"
3748 #include "library/hiddentablemodel.h"
3749 #include "library/queryutil.h"
3750 #include "library/trackcollection.h"
3751@@ -88,11 +85,14 @@
3752 connect(&m_trackDao, SIGNAL(dbTrackAdded(TrackPointer)),
3753 pBaseTrackCache, SLOT(slotDbTrackAdded(TrackPointer)));
3754
3755+
3756 m_pBaseTrackCache = QSharedPointer<BaseTrackCache>(pBaseTrackCache);
3757 pTrackCollection->addTrackSource(QString("default"), m_pBaseTrackCache);
3758
3759 // These rely on the 'default' track source being present.
3760- m_pLibraryTableModel = new LibraryTableModel(this, pTrackCollection);
3761+ m_pLibraryTableModel = new LibraryTableModel(this, pTrackCollection,pConfig);
3762+ connect(this,SIGNAL(configChanged(QString,QString)),
3763+ m_pLibraryTableModel, SLOT(slotConfigChanged(QString, QString)));
3764
3765 TreeItem* pRootItem = new TreeItem();
3766 TreeItem* pmissingChildItem = new TreeItem(kMissingTitle, kMissingTitle,
3767
3768=== modified file 'mixxx/src/library/mixxxlibraryfeature.h'
3769--- mixxx/src/library/mixxxlibraryfeature.h 2013-01-17 08:16:08 +0000
3770+++ mixxx/src/library/mixxxlibraryfeature.h 2013-05-18 16:32:26 +0000
3771@@ -7,6 +7,7 @@
3772 #include <QStringListModel>
3773
3774 #include "library/libraryfeature.h"
3775+#include "configobject.h"
3776 #include "library/dao/trackdao.h"
3777 #include "treeitemmodel.h"
3778 #include "configobject.h"
3779@@ -34,12 +35,16 @@
3780 void bindWidget(WLibrary* pLibrary,
3781 MixxxKeyboard* pKeyboard);
3782
3783+ signals:
3784+ void configChanged(QString, QString);
3785+
3786 public slots:
3787 void activate();
3788 void activateChild(const QModelIndex& index);
3789 void refreshLibraryModels();
3790
3791 private:
3792+ TrackCollection* m_pTrackCollection;
3793 const QString kMissingTitle;
3794 const QString kHiddenTitle;
3795 QSharedPointer<BaseTrackCache> m_pBaseTrackCache;
3796@@ -49,7 +54,6 @@
3797 TreeItemModel m_childModel;
3798 TrackDAO& m_trackDao;
3799 ConfigObject<ConfigValue>* m_pConfig;
3800- TrackCollection* m_pTrackCollection;
3801 };
3802
3803 #endif /* MIXXXLIBRARYFEATURE_H */
3804
3805=== modified file 'mixxx/src/library/playlistfeature.cpp'
3806--- mixxx/src/library/playlistfeature.cpp 2013-05-12 22:17:32 +0000
3807+++ mixxx/src/library/playlistfeature.cpp 2013-05-18 16:32:26 +0000
3808@@ -22,11 +22,12 @@
3809 PlaylistFeature::PlaylistFeature(QObject* parent,
3810 TrackCollection* pTrackCollection,
3811 ConfigObject<ConfigValue>* pConfig)
3812- : BasePlaylistFeature(parent, pConfig, pTrackCollection,
3813- "PLAYLISTHOME") {
3814+ : BasePlaylistFeature(parent, pConfig, pTrackCollection,"PLAYLISTHOME") {
3815 m_pPlaylistTableModel = new PlaylistTableModel(this, pTrackCollection,
3816- "mixxx.db.model.playlist");
3817-
3818+ "mixxx.db.model.playlist",
3819+ pConfig);
3820+ connect(this, SIGNAL(configChanged(QString,QString)),
3821+ m_pPlaylistTableModel, SLOT(slotConfigChanged(QString,QString)));
3822 //construct child model
3823 TreeItem *rootItem = new TreeItem();
3824 m_childModel.setRootItem(rootItem);
3825@@ -179,7 +180,7 @@
3826
3827 if (type != PlaylistDAO::PLHT_UNKNOWN) {
3828 // Switch the view to the playlist.
3829- m_pPlaylistTableModel->setPlaylist(playlistId);
3830+ m_pPlaylistTableModel->setTableModel(playlistId);
3831 // Update selection
3832 emit(featureSelect(this, m_lastRightClickedIndex));
3833 }
3834
3835=== modified file 'mixxx/src/library/playlistfeature.h'
3836--- mixxx/src/library/playlistfeature.h 2013-05-18 16:23:08 +0000
3837+++ mixxx/src/library/playlistfeature.h 2013-05-18 16:32:26 +0000
3838@@ -15,7 +15,8 @@
3839 class PlaylistFeature : public BasePlaylistFeature {
3840 Q_OBJECT
3841 public:
3842- PlaylistFeature(QObject* parent, TrackCollection* pTrackCollection,
3843+ PlaylistFeature(QObject* parent,
3844+ TrackCollection* pTrackCollection,
3845 ConfigObject<ConfigValue>* pConfig);
3846 virtual ~PlaylistFeature();
3847
3848@@ -25,6 +26,9 @@
3849 bool dropAcceptChild(const QModelIndex& index, QList<QUrl> urls, QWidget *pSource);
3850 bool dragMoveAcceptChild(const QModelIndex& index, QUrl url);
3851
3852+ signals:
3853+ void configChanged(QString,QString);
3854+
3855 public slots:
3856 void onRightClick(const QPoint& globalPos);
3857 void onRightClickChild(const QPoint& globalPos, QModelIndex index);
3858
3859=== modified file 'mixxx/src/library/playlisttablemodel.cpp'
3860--- mixxx/src/library/playlisttablemodel.cpp 2013-05-12 22:17:32 +0000
3861+++ mixxx/src/library/playlisttablemodel.cpp 2013-05-18 16:32:26 +0000
3862@@ -1,50 +1,56 @@
3863-#include <QtCore>
3864-#include <QtGui>
3865-#include <QtSql>
3866-#include <QDateTime>
3867-#include "library/trackcollection.h"
3868 #include "library/playlisttablemodel.h"
3869 #include "library/queryutil.h"
3870 #include "mixxxutils.cpp"
3871 #include "playermanager.h"
3872
3873 PlaylistTableModel::PlaylistTableModel(QObject* parent,
3874- TrackCollection* pTrackCollection,
3875- QString settingsNamespace,
3876- bool showAll)
3877- : BaseSqlTableModel(parent, pTrackCollection,
3878- pTrackCollection->getDatabase(),
3879- settingsNamespace),
3880- m_pTrackCollection(pTrackCollection),
3881- m_playlistDao(m_pTrackCollection->getPlaylistDAO()),
3882- m_trackDao(m_pTrackCollection->getTrackDAO()),
3883- m_iPlaylistId(-1) {
3884- connect(this, SIGNAL(doSearch(const QString&)),
3885- this, SLOT(slotSearch(const QString&)));
3886- m_showAll = showAll;
3887+ TrackCollection* pTrackCollection,
3888+ QString settingsNamespace,
3889+ ConfigObject<ConfigValue>* pConfig,
3890+ bool showAll)
3891+ : BaseSqlTableModel(parent, pTrackCollection, pConfig, settingsNamespace),
3892+ m_playlistDao(m_pTrackCollection->getPlaylistDAO()),
3893+ m_iPlaylistId(-1),
3894+ m_showAll(showAll) {
3895 }
3896
3897 PlaylistTableModel::~PlaylistTableModel() {
3898 }
3899
3900-void PlaylistTableModel::setPlaylist(int playlistId) {
3901+void PlaylistTableModel::setTableModel(int playlistId) {
3902 //qDebug() << "PlaylistTableModel::setPlaylist" << playlistId;
3903
3904- if (m_iPlaylistId == playlistId) {
3905+ if (playlistId == m_iPlaylistId) {
3906 qDebug() << "Already focused on playlist " << playlistId;
3907 return;
3908+ } else if (playlistId == -1) {
3909+ // calls from parent class use -1 as id then just set the current playlist
3910+ playlistId = m_iPlaylistId;
3911 }
3912
3913 m_iPlaylistId = playlistId;
3914- QString playlistTableName = "playlist_" + QString::number(m_iPlaylistId);
3915+ QString playlistTableName = "playlist_" + QString::number(m_iPlaylistId)+"_";
3916+
3917 QSqlQuery query(m_pTrackCollection->getDatabase());
3918 FieldEscaper escaper(m_pTrackCollection->getDatabase());
3919
3920 QStringList columns;
3921- columns << PLAYLISTTRACKSTABLE_TRACKID + " as " + LIBRARYTABLE_ID
3922- << PLAYLISTTRACKSTABLE_POSITION
3923- << PLAYLISTTRACKSTABLE_DATETIMEADDED
3924- << "'' as preview";
3925+ QStringList tableColumns;
3926+ QString filter;
3927+ columns << "PlaylistTracks."+PLAYLISTTRACKSTABLE_TRACKID + " as " + LIBRARYTABLE_ID
3928+ << "PlaylistTracks."+PLAYLISTTRACKSTABLE_POSITION
3929+ << "PlaylistTracks."+PLAYLISTTRACKSTABLE_DATETIMEADDED
3930+ << "'' as preview";
3931+ tableColumns << PLAYLISTTRACKSTABLE_TRACKID
3932+ << PLAYLISTTRACKSTABLE_POSITION
3933+ << PLAYLISTTRACKSTABLE_DATETIMEADDED;
3934+ bool showMissing = m_pConfig->getValueString(ConfigKey("[Library]","ShowMissingSongs"),"1").toInt();
3935+ if (showMissing) {
3936+ filter = "library.mixxx_deleted=0";
3937+ playlistTableName.append("_missing");
3938+ } else {
3939+ filter = "library.mixxx_deleted=0 AND track_locations.fs_deleted=0";
3940+ }
3941
3942 // We drop files that have been explicitly deleted from mixxx
3943 // (mixxx_deleted=0) from the view. There was a bug in <= 1.9.0 where
3944@@ -54,12 +60,13 @@
3945 "CREATE TEMPORARY VIEW IF NOT EXISTS %1 AS "
3946 "SELECT %2 FROM PlaylistTracks "
3947 "INNER JOIN library ON library.id = PlaylistTracks.track_id "
3948+ "INNER JOIN track_locations ON track_locations.id=PlaylistTracks.track_id "
3949 "WHERE PlaylistTracks.playlist_id = %3")
3950 .arg(escaper.escapeString(playlistTableName),
3951 columns.join(","),
3952 QString::number(playlistId));
3953 if (!m_showAll) {
3954- queryString.append(" AND library.mixxx_deleted = 0");
3955+ queryString.append(" AND " + filter);
3956 }
3957 query.prepare(queryString);
3958 if (!query.exec()) {
3959@@ -68,7 +75,7 @@
3960
3961 columns[0] = LIBRARYTABLE_ID;
3962 columns[3] = "preview";
3963- setTable(playlistTableName, columns[0], columns,
3964+ setTable(playlistTableName, tableColumns[0], tableColumns,
3965 m_pTrackCollection->getTrackSource("default"));
3966 initHeaderData();
3967 setSearch("");
3968@@ -76,45 +83,6 @@
3969 setSort(defaultSortColumn(), defaultSortOrder());
3970 }
3971
3972-bool PlaylistTableModel::addTrack(const QModelIndex& index, QString location) {
3973- const int positionColumn = fieldIndex(PLAYLISTTRACKSTABLE_POSITION);
3974- int position = index.sibling(index.row(), positionColumn).data().toInt();
3975-
3976- // Handle weird cases like a drag-and-drop to an invalid index
3977- if (position <= 0) {
3978- position = rowCount() + 1;
3979- }
3980-
3981- // If a track is dropped but it isn't in the library, then add it because
3982- // the user probably dropped a file from outside Mixxx into this playlist.
3983- QFileInfo fileInfo(location);
3984-
3985- // Adds track, does not insert duplicates, handles unremoving logic.
3986- int trackId = m_trackDao.addTrack(fileInfo, true);
3987-
3988- // Do nothing if the location still isn't in the database.
3989- if (trackId < 0) {
3990- return false;
3991- }
3992-
3993- m_playlistDao.insertTrackIntoPlaylist(trackId, m_iPlaylistId, position);
3994-
3995- // TODO(rryan) signal an add to the base, don't select
3996- select(); //Repopulate the data model.
3997- return true;
3998-}
3999-
4000-bool PlaylistTableModel::appendTrack(int trackId) {
4001- if (trackId < 0) {
4002- return false;
4003- }
4004-
4005- bool bSuccess = m_playlistDao.appendTrackToPlaylist(trackId, m_iPlaylistId);
4006-
4007- select(); //Repopulate the data model.
4008- return bSuccess;
4009-}
4010-
4011 int PlaylistTableModel::addTracks(const QModelIndex& index, QList<QString> locations) {
4012 const int positionColumn = fieldIndex(PLAYLISTTRACKSTABLE_POSITION);
4013 int position = index.sibling(index.row(), positionColumn).data().toInt();
4014@@ -129,7 +97,7 @@
4015 fileInfoList.append(QFileInfo(fileLocation));
4016 }
4017
4018- QList<int> trackIds = m_trackDao.addTracks(fileInfoList, true);
4019+ QList<int> trackIds = m_trackDAO.addTracks(fileInfoList, true);
4020
4021 int tracksAdded = m_playlistDao.insertTracksIntoPlaylist(
4022 trackIds, m_iPlaylistId, position);
4023@@ -144,13 +112,15 @@
4024 return tracksAdded;
4025 }
4026
4027-TrackPointer PlaylistTableModel::getTrack(const QModelIndex& index) const {
4028- //FIXME: use position instead of location for playlist tracks?
4029-
4030- //const int locationColumnIndex = this->fieldIndex(LIBRARYTABLE_LOCATION);
4031- //QString location = index.sibling(index.row(), locationColumnIndex).data().toString();
4032- int trackId = getTrackId(index);
4033- return m_trackDao.getTrack(trackId);
4034+bool PlaylistTableModel::appendTrack(int trackId) {
4035+ if (trackId < 0) {
4036+ return false;
4037+ }
4038+
4039+ m_playlistDao.appendTrackToPlaylist(trackId, m_iPlaylistId);
4040+
4041+ select(); //Repopulate the data model.
4042+ return true;
4043 }
4044
4045 void PlaylistTableModel::removeTrack(const QModelIndex& index) {
4046@@ -226,18 +196,17 @@
4047
4048 //Insert the song into the PlaylistTracks table
4049
4050- /** ALGORITHM for code below
4051- Case 1: destination < source (newPos < oldPos)
4052- 1) Set position = -1 where pos=source -- Gives that track a dummy index to keep stuff simple.
4053- 2) Decrement position where pos > source
4054- 3) increment position where pos > dest
4055- 4) Set position = dest where pos=-1 -- Move track from dummy pos to final destination.
4056+ // ALGORITHM for code below
4057+ // Case 1: destination < source (newPos < oldPos)
4058+ // 1) Set position = -1 where pos=source -- Gives that track a dummy index to keep stuff simple.
4059+ // 2) Decrement position where pos > source
4060+ // 3) increment position where pos > dest
4061+ // 4) Set position = dest where pos=-1 -- Move track from dummy pos to final destination.
4062
4063- Case 2: destination > source (newPos > oldPos)
4064- 1) Set position=-1 where pos=source -- Give track a dummy index again.
4065- 2) Decrement position where pos > source AND pos <= dest
4066- 3) Set postion=dest where pos=-1 -- Move that track from dummy pos to final destination
4067- */
4068+ // Case 2: destination > source (newPos > oldPos)
4069+ // 1) Set position=-1 where pos=source -- Give track a dummy index again.
4070+ // 2) Decrement position where pos > source AND pos <= dest
4071+ // 3) Set postion=dest where pos=-1 -- Move that track from dummy pos to final destination
4072
4073 QString queryString;
4074 if (newPosition < oldPosition) {
4075@@ -336,17 +305,6 @@
4076 select();
4077 }
4078
4079-void PlaylistTableModel::search(const QString& searchText) {
4080- // qDebug() << "PlaylistTableModel::search()" << searchText
4081- // << QThread::currentThread();
4082- emit(doSearch(searchText));
4083-}
4084-
4085-void PlaylistTableModel::slotSearch(const QString& searchText) {
4086- BaseSqlTableModel::search(
4087- searchText, LibraryTableModel::DEFAULT_LIBRARYFILTER);
4088-}
4089-
4090 bool PlaylistTableModel::isColumnInternal(int column) {
4091 if (column == fieldIndex(LIBRARYTABLE_ID) ||
4092 column == fieldIndex(PLAYLISTTRACKSTABLE_TRACKID) ||
4093@@ -354,6 +312,7 @@
4094 column == fieldIndex(LIBRARYTABLE_MIXXXDELETED) ||
4095 column == fieldIndex(LIBRARYTABLE_BPM_LOCK) ||
4096 column == fieldIndex(TRACKLOCATIONSTABLE_FSDELETED) ||
4097+ column == fieldIndex(TRACKLOCATIONSTABLE_MAINDIRID) ||
4098 (PlayerManager::numPreviewDecks() == 0 && column == fieldIndex("preview"))) {
4099 return true;
4100 }
4101@@ -380,6 +339,7 @@
4102 | TRACKMODELCAPS_LOADTOSAMPLER
4103 | TRACKMODELCAPS_LOADTOPREVIEWDECK
4104 | TRACKMODELCAPS_REMOVE
4105+ | TRACKMODELCAPS_RELOCATE
4106 | TRACKMODELCAPS_BPMLOCK
4107 | TRACKMODELCAPS_CLEAR_BEATS
4108 | TRACKMODELCAPS_RESETPLAYED;
4109
4110=== modified file 'mixxx/src/library/playlisttablemodel.h'
4111--- mixxx/src/library/playlisttablemodel.h 2012-08-10 15:03:46 +0000
4112+++ mixxx/src/library/playlisttablemodel.h 2013-05-18 16:32:26 +0000
4113@@ -1,54 +1,38 @@
4114 #ifndef PLAYLISTTABLEMODEL_H
4115 #define PLAYLISTTABLEMODEL_H
4116
4117-#include <QtSql>
4118-#include <QItemDelegate>
4119-#include <QtCore>
4120-
4121 #include "library/basesqltablemodel.h"
4122 #include "library/dao/playlistdao.h"
4123-#include "library/dao/trackdao.h"
4124-#include "library/librarytablemodel.h"
4125-
4126-class TrackCollection;
4127
4128 class PlaylistTableModel : public BaseSqlTableModel {
4129 Q_OBJECT
4130 public:
4131 PlaylistTableModel(QObject* parent, TrackCollection* pTrackCollection,
4132- QString settingsNamespace,bool showAll=false);
4133+ QString settingsNamespace,
4134+ ConfigObject<ConfigValue>* pConfig,
4135+ bool showAll=false);
4136 virtual ~PlaylistTableModel();
4137- void setPlaylist(int playlistId);
4138+ void setTableModel(int playlistId = -1);
4139+
4140 int getPlaylist() const {
4141 return m_iPlaylistId;
4142 }
4143- virtual TrackPointer getTrack(const QModelIndex& index) const;
4144
4145- virtual void search(const QString& searchText);
4146- virtual bool isColumnInternal(int column);
4147- virtual bool isColumnHiddenByDefault(int column);
4148- virtual void removeTrack(const QModelIndex& index);
4149- virtual void removeTracks(const QModelIndexList& indices);
4150- virtual bool addTrack(const QModelIndex& index, QString location);
4151- virtual bool appendTrack(int trackId);
4152+ bool isColumnInternal(int column);
4153+ bool isColumnHiddenByDefault(int column);
4154+ void removeTrack(const QModelIndex& index);
4155+ void removeTracks(const QModelIndexList& indices);
4156 // Adding multiple tracks at one to a playlist. Returns the number of
4157 // successful additions.
4158- virtual int addTracks(const QModelIndex& index, QList<QString> locations);
4159- virtual void moveTrack(const QModelIndex& sourceIndex, const QModelIndex& destIndex);
4160- virtual void shuffleTracks(const QModelIndex& shuffleStartIndex);
4161-
4162+ int addTracks(const QModelIndex& index, QList<QString> locations);
4163+ bool appendTrack(int trackId);
4164+ void moveTrack(const QModelIndex& sourceIndex,
4165+ const QModelIndex& destIndex);
4166+ void shuffleTracks(const QModelIndex& shuffleStartIndex);
4167 TrackModel::CapabilitiesFlags getCapabilities() const;
4168
4169- private slots:
4170- void slotSearch(const QString& searchText);
4171-
4172- signals:
4173- void doSearch(const QString& searchText);
4174-
4175 private:
4176- TrackCollection* m_pTrackCollection;
4177 PlaylistDAO& m_playlistDao;
4178- TrackDAO& m_trackDao;
4179 int m_iPlaylistId;
4180 bool m_showAll;
4181 };
4182
4183=== modified file 'mixxx/src/library/preparelibrarytablemodel.cpp'
4184--- mixxx/src/library/preparelibrarytablemodel.cpp 2012-12-08 14:33:51 +0000
4185+++ mixxx/src/library/preparelibrarytablemodel.cpp 2013-05-18 16:32:26 +0000
4186@@ -2,34 +2,23 @@
4187
4188 #include "preparelibrarytablemodel.h"
4189 #include "library/trackcollection.h"
4190+#include "configobject.h"
4191
4192 const QString RECENT_FILTER = "datetime_added > datetime('now', '-7 days')";
4193
4194 PrepareLibraryTableModel::PrepareLibraryTableModel(QObject* parent,
4195 TrackCollection* pTrackCollection)
4196- : LibraryTableModel(parent, pTrackCollection,
4197+ : LibraryTableModel(parent, pTrackCollection, NULL,
4198 "mixxx.db.model.prepare") {
4199 m_bShowRecentSongs = true;
4200 setSearch("", RECENT_FILTER);
4201
4202- connect(this, SIGNAL(doSearch(const QString&)),
4203- this, SLOT(slotSearch(const QString&)));
4204 }
4205
4206
4207 PrepareLibraryTableModel::~PrepareLibraryTableModel() {
4208 }
4209
4210-void PrepareLibraryTableModel::search(const QString& searchText) {
4211- // qDebug() << "PrepareLibraryTableModel::search()" << searchText
4212- // << QThread::currentThread();
4213- emit(doSearch(searchText));
4214-}
4215-
4216-void PrepareLibraryTableModel::slotSearch(const QString& searchText) {
4217- BaseSqlTableModel::search(searchText,
4218- m_bShowRecentSongs ? RECENT_FILTER : QString());
4219-}
4220
4221 void PrepareLibraryTableModel::showRecentSongs() {
4222 m_bShowRecentSongs = true;
4223
4224=== modified file 'mixxx/src/library/preparelibrarytablemodel.h'
4225--- mixxx/src/library/preparelibrarytablemodel.h 2012-11-25 11:17:13 +0000
4226+++ mixxx/src/library/preparelibrarytablemodel.h 2013-05-18 16:32:26 +0000
4227@@ -8,18 +8,13 @@
4228 {
4229 Q_OBJECT
4230 public:
4231- PrepareLibraryTableModel(QObject* parent, TrackCollection* pTrackCollection);
4232+ PrepareLibraryTableModel(QObject* parent,
4233+ TrackCollection* pTrackCollection);
4234 virtual ~PrepareLibraryTableModel();
4235
4236- virtual void search(const QString& searchText);
4237-
4238 public slots:
4239 void showRecentSongs();
4240 void showAllSongs();
4241- private slots:
4242- void slotSearch(const QString& searchText);
4243- signals:
4244- void doSearch(const QString& searchText);
4245 private:
4246 bool m_bShowRecentSongs;
4247 };
4248
4249=== modified file 'mixxx/src/library/promotracksfeature.cpp'
4250--- mixxx/src/library/promotracksfeature.cpp 2012-12-12 17:23:33 +0000
4251+++ mixxx/src/library/promotracksfeature.cpp 2013-05-18 16:32:26 +0000
4252@@ -46,7 +46,7 @@
4253 m_pTrackCollection(pTrackCollection),
4254 m_pFeaturedArtistsView(NULL),
4255 m_pBundledSongsView(NULL),
4256- m_downloadsTableModel(this, pTrackCollection),
4257+ m_downloadsTableModel(this, pTrackCollection,config),
4258 m_bFirstRun(firstRun) {
4259
4260 m_sPromoRemoteHTMLLocation = QString("http://promo.mixxx.org/%1/index.html").arg(MIXXX_PROMO_VERSION); //m_pConfig->getConfigPath() + "/promo/promotracks.html";
4261
4262=== modified file 'mixxx/src/library/proxytrackmodel.cpp'
4263--- mixxx/src/library/proxytrackmodel.cpp 2013-01-19 12:15:22 +0000
4264+++ mixxx/src/library/proxytrackmodel.cpp 2013-05-18 16:32:26 +0000
4265@@ -2,6 +2,7 @@
4266 // Created 10/22/2009 by RJ Ryan (rryan@mit.edu)
4267
4268 #include <QtCore>
4269+#include <QMessageBox>
4270 #include <QVariant>
4271
4272 #include "library/proxytrackmodel.h"
4273@@ -40,7 +41,8 @@
4274 return m_pTrackModel->getTrackLocation(indexSource);
4275 }
4276
4277-void ProxyTrackModel::search(const QString& searchText) {
4278+void ProxyTrackModel::search(const QString& searchText, const QString& extraFilter) {
4279+ Q_UNUSED(extraFilter);
4280 if (m_bHandleSearches) {
4281 m_currentSearch = searchText;
4282 setFilterFixedString(searchText);
4283@@ -64,10 +66,6 @@
4284 return m_pTrackModel->isColumnHiddenByDefault(column);
4285 }
4286
4287-void ProxyTrackModel::removeTrack(const QModelIndex& index) {
4288- QModelIndex indexSource = mapToSource(index);
4289- m_pTrackModel->removeTrack(indexSource);
4290-}
4291
4292 void ProxyTrackModel::removeTracks(const QModelIndexList& indices) {
4293 QModelIndexList translatedList;
4294@@ -78,11 +76,6 @@
4295 m_pTrackModel->removeTracks(translatedList);
4296 }
4297
4298-bool ProxyTrackModel::addTrack(const QModelIndex& index, QString location) {
4299- QModelIndex indexSource = mapToSource(index);
4300- return m_pTrackModel->addTrack(indexSource, location);
4301-}
4302-
4303 void ProxyTrackModel::moveTrack(const QModelIndex& sourceIndex,
4304 const QModelIndex& destIndex) {
4305 QModelIndex sourceIndexSource = mapToSource(sourceIndex);
4306@@ -95,7 +88,19 @@
4307 }
4308
4309 TrackModel::CapabilitiesFlags ProxyTrackModel::getCapabilities() const {
4310- return m_pTrackModel->getCapabilities();
4311+ return TRACKMODELCAPS_NONE
4312+ | TRACKMODELCAPS_DELETEFS;
4313+}
4314+
4315+void ProxyTrackModel::deleteTracks(const QModelIndexList& indices){
4316+ QMessageBox::StandardButton btn = QMessageBox::question(
4317+ NULL, tr("Confirm Delete"),
4318+ tr("Are you sure you want to delete these files?"),
4319+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
4320+ if (btn == QMessageBox::No) {
4321+ return ;
4322+ }
4323+ //TODO(kain88) ask rryan what the row of the location field is
4324 }
4325
4326 bool ProxyTrackModel::filterAcceptsRow(int sourceRow,
4327
4328=== modified file 'mixxx/src/library/proxytrackmodel.h'
4329--- mixxx/src/library/proxytrackmodel.h 2012-11-25 09:33:00 +0000
4330+++ mixxx/src/library/proxytrackmodel.h 2013-05-18 16:32:26 +0000
4331@@ -16,7 +16,7 @@
4332 // calling the composed TrackModel. If the bHandleSearches flag is set, the
4333 // TrackModel search calls will not be delivered to the composed TrackModel
4334 // because filtering is handled by the QSortFilterProxyModel.
4335-class ProxyTrackModel : public QSortFilterProxyModel, public virtual TrackModel {
4336+class ProxyTrackModel : public QSortFilterProxyModel, public TrackModel {
4337 public:
4338 // Construct a new ProxyTrackModel with pTrackModel as the TrackModel it
4339 // composes. If bHandleSearches is true, then search signals will not be
4340@@ -29,15 +29,14 @@
4341 virtual QString getTrackLocation(const QModelIndex& index) const;
4342 virtual int getTrackId(const QModelIndex& index) const;
4343 virtual const QLinkedList<int> getTrackRows(int trackId) const;
4344- virtual void search(const QString& searchText);
4345+ virtual void search(const QString& searchText,const QString& extraFilter=QString());
4346 virtual const QString currentSearch() const;
4347 virtual bool isColumnInternal(int column);
4348 virtual bool isColumnHiddenByDefault(int column);
4349- virtual void removeTrack(const QModelIndex& index);
4350 virtual void removeTracks(const QModelIndexList& indices);
4351- virtual bool addTrack(const QModelIndex& index, QString location);
4352 virtual void moveTrack(const QModelIndex& sourceIndex,
4353 const QModelIndex& destIndex);
4354+ void deleteTracks(const QModelIndexList& indices);
4355 virtual QAbstractItemDelegate* delegateForColumn(const int i, QObject* pParent);
4356 virtual TrackModel::CapabilitiesFlags getCapabilities() const;
4357
4358
4359=== modified file 'mixxx/src/library/rhythmbox/rhythmboxfeature.cpp'
4360--- mixxx/src/library/rhythmbox/rhythmboxfeature.cpp 2013-01-01 11:53:13 +0000
4361+++ mixxx/src/library/rhythmbox/rhythmboxfeature.cpp 2013-05-18 16:32:26 +0000
4362@@ -9,9 +9,11 @@
4363 #include "library/treeitem.h"
4364 #include "library/queryutil.h"
4365
4366-RhythmboxFeature::RhythmboxFeature(QObject* parent, TrackCollection* pTrackCollection)
4367+RhythmboxFeature::RhythmboxFeature(QObject* parent, TrackCollection* pTrackCollection,
4368+ ConfigObject<ConfigValue> *pConfig)
4369 : BaseExternalLibraryFeature(parent, pTrackCollection),
4370 m_pTrackCollection(pTrackCollection),
4371+ m_pConfig(pConfig),
4372 m_cancelImport(false) {
4373 QString tableName = "rhythmbox_library";
4374 QString idColumn = "id";
4375@@ -37,13 +39,13 @@
4376 this, m_pTrackCollection,
4377 "mixxx.db.model.rhythmbox",
4378 "rhythmbox_library",
4379- "rhythmbox");
4380+ "rhythmbox",m_pConfig);
4381 m_pRhythmboxPlaylistModel = new BaseExternalPlaylistModel(
4382 this, m_pTrackCollection,
4383 "mixxx.db.model.rhythmbox_playlist",
4384 "rhythmbox_playlists",
4385 "rhythmbox_playlist_tracks",
4386- "rhythmbox");
4387+ "rhythmbox",m_pConfig);
4388
4389 m_isActivated = false;
4390 m_title = tr("Rhythmbox");
4391@@ -76,7 +78,7 @@
4392 "mixxx.db.model.rhythmbox_playlist",
4393 "rhythmbox_playlists",
4394 "rhythmbox_playlist_tracks",
4395- "rhythmbox");
4396+ "rhythmbox", m_pConfig);
4397 pModel->setPlaylist(playlist);
4398 return pModel;
4399 }
4400
4401=== modified file 'mixxx/src/library/rhythmbox/rhythmboxfeature.h'
4402--- mixxx/src/library/rhythmbox/rhythmboxfeature.h 2013-01-01 11:53:13 +0000
4403+++ mixxx/src/library/rhythmbox/rhythmboxfeature.h 2013-05-18 16:32:26 +0000
4404@@ -14,6 +14,7 @@
4405 #include "library/baseexternallibraryfeature.h"
4406 #include "library/treeitemmodel.h"
4407 #include "library/trackcollection.h"
4408+#include "configobject.h"
4409
4410 class BaseExternalTrackModel;
4411 class BaseExternalPlaylistModel;
4412@@ -21,7 +22,8 @@
4413 class RhythmboxFeature : public BaseExternalLibraryFeature {
4414 Q_OBJECT
4415 public:
4416- RhythmboxFeature(QObject* parent, TrackCollection*);
4417+ RhythmboxFeature(QObject* parent, TrackCollection* pTrackCollection,
4418+ ConfigObject<ConfigValue> *pConfig);
4419 virtual ~RhythmboxFeature();
4420 static bool isSupported();
4421
4422@@ -54,6 +56,7 @@
4423 QFutureWatcher<TreeItem*> m_track_watcher;
4424 QFuture<TreeItem*> m_track_future;
4425 TreeItemModel m_childModel;
4426+ ConfigObject<ConfigValue> *m_pConfig;
4427 bool m_cancelImport;
4428
4429 // Removes all rows from a given table
4430
4431=== modified file 'mixxx/src/library/setlogfeature.cpp'
4432--- mixxx/src/library/setlogfeature.cpp 2013-05-12 22:17:32 +0000
4433+++ mixxx/src/library/setlogfeature.cpp 2013-05-18 16:32:26 +0000
4434@@ -17,11 +17,10 @@
4435 SetlogFeature::SetlogFeature(QObject* parent,
4436 ConfigObject<ConfigValue>* pConfig,
4437 TrackCollection* pTrackCollection)
4438- : BasePlaylistFeature(parent, pConfig, pTrackCollection,
4439- "SETLOGHOME") {
4440+ : BasePlaylistFeature(parent, pConfig, pTrackCollection, "SETLOGHOME") {
4441 m_pPlaylistTableModel = new PlaylistTableModel(this, pTrackCollection,
4442 "mixxx.db.model.setlog",
4443- true);//show all tracks
4444+ pConfig, true);
4445 m_pJoinWithPreviousAction = new QAction(tr("Join with previous"), this);
4446 connect(m_pJoinWithPreviousAction, SIGNAL(triggered()),
4447 this, SLOT(slotJoinWithPrevious()));
4448@@ -181,7 +180,7 @@
4449 int previousPlaylistId = m_playlistDao.getPreviousPlaylist(currentPlaylistId, PlaylistDAO::PLHT_SET_LOG);
4450 if (previousPlaylistId >= 0) {
4451
4452- m_pPlaylistTableModel->setPlaylist(previousPlaylistId);
4453+ m_pPlaylistTableModel->setTableModel(previousPlaylistId);
4454
4455 if (currentPlaylistId == m_playlistId) {
4456 // mark all the Tracks in the previous Playlist as played
4457@@ -252,6 +251,8 @@
4458 return;
4459 }
4460
4461+ m_playlistDao.appendTrackToPlaylist(currentPlayingTrackId,
4462+ m_playlistId);
4463 if (m_pPlaylistTableModel->getPlaylist() == m_playlistId) {
4464 // View needs a refresh
4465 m_pPlaylistTableModel->appendTrack(currentPlayingTrackId);
4466@@ -277,7 +278,7 @@
4467
4468 if (type != PlaylistDAO::PLHT_UNKNOWN) {
4469 // Switch the view to the playlist.
4470- m_pPlaylistTableModel->setPlaylist(playlistId);
4471+ m_pPlaylistTableModel->setTableModel(playlistId);
4472 // Update selection
4473 emit(featureSelect(this, m_lastRightClickedIndex));
4474 }
4475
4476=== modified file 'mixxx/src/library/stardelegate.cpp'
4477--- mixxx/src/library/stardelegate.cpp 2012-11-30 09:17:37 +0000
4478+++ mixxx/src/library/stardelegate.cpp 2013-05-18 16:32:26 +0000
4479@@ -18,15 +18,19 @@
4480
4481 #include <QtDebug>
4482 #include <QtGui>
4483+#include <QTableView>
4484
4485 #include "stardelegate.h"
4486 #include "stareditor.h"
4487 #include "starrating.h"
4488+#include "library/trackmodel.h"
4489+#include "library/dao/trackdao.h"
4490
4491 StarDelegate::StarDelegate(QObject *pParent)
4492 : QStyledItemDelegate(pParent),
4493 m_isOneCellInEditMode(false) {
4494 m_pTableView = qobject_cast<QTableView *>(pParent);
4495+ m_pTrackModel = dynamic_cast<TrackModel*>(m_pTableView->model());
4496 connect(pParent, SIGNAL(entered(QModelIndex)),
4497 this, SLOT(cellEntered(QModelIndex)));
4498 }
4499@@ -41,7 +45,8 @@
4500 // Populate the correct colors based on the styling
4501 QStyleOptionViewItem newOption = option;
4502 initStyleOption(&newOption, index);
4503-
4504+ bool fsDeleted=index.sibling(index.row(),
4505+ m_pTrackModel->fieldIndex(TRACKLOCATIONSTABLE_FSDELETED)).data().toInt();
4506 // Set the palette appropriately based on whether the row is selected or
4507 // not. We also have to check if it is inactive or not and use the
4508 // appropriate ColorGroup.
4509@@ -54,7 +59,11 @@
4510 painter->setBrush(newOption.palette.color(
4511 colorGroup, QPalette::HighlightedText));
4512 } else {
4513- painter->fillRect(newOption.rect, newOption.palette.base());
4514+ if (fsDeleted) {
4515+ painter->fillRect(newOption.rect, QColor(Qt::red));
4516+ } else {
4517+ painter->fillRect(newOption.rect, newOption.palette.base());
4518+ }
4519 painter->setBrush(newOption.palette.text());
4520 }
4521
4522@@ -123,4 +132,3 @@
4523 m_currentEditedCellIndex = QModelIndex();
4524 }
4525 }
4526-
4527
4528=== modified file 'mixxx/src/library/stardelegate.h'
4529--- mixxx/src/library/stardelegate.h 2012-06-03 14:37:44 +0000
4530+++ mixxx/src/library/stardelegate.h 2013-05-18 16:32:26 +0000
4531@@ -21,6 +21,7 @@
4532
4533 #include <QStyledItemDelegate>
4534 #include <QTableView>
4535+#include "library/trackmodel.h"
4536
4537 /*
4538 * When displaying data in a QListView, QTableView, or QTreeView,
4539@@ -57,6 +58,7 @@
4540 QTableView *m_pTableView;
4541 QPersistentModelIndex m_currentEditedCellIndex;
4542 bool m_isOneCellInEditMode;
4543+ TrackModel* m_pTrackModel;
4544 };
4545
4546 #endif
4547
4548=== modified file 'mixxx/src/library/trackcollection.cpp'
4549--- mixxx/src/library/trackcollection.cpp 2013-05-07 03:17:23 +0000
4550+++ mixxx/src/library/trackcollection.cpp 2013-05-18 16:32:26 +0000
4551@@ -18,9 +18,10 @@
4552 m_playlistDao(m_db),
4553 m_crateDao(m_db),
4554 m_cueDao(m_db),
4555+ m_directoryDao(m_db),
4556 m_analysisDao(m_db, pConfig),
4557 m_trackDao(m_db, m_cueDao, m_playlistDao, m_crateDao,
4558- m_analysisDao, pConfig),
4559+ m_analysisDao, m_directoryDao, pConfig),
4560 m_supportedFileExtensionsRegex(
4561 SoundSourceProxy::supportedFileExtensionsRegex(),
4562 Qt::CaseInsensitive) {
4563@@ -72,7 +73,7 @@
4564 return false;
4565 }
4566
4567- int requiredSchemaVersion = 18;
4568+ int requiredSchemaVersion = 19;
4569 QString schemaFilename = m_pConfig->getResourcePath();
4570 schemaFilename.append("schema.xml");
4571 QString okToExit = tr("Click OK to exit.");
4572@@ -116,12 +117,19 @@
4573 return m_db;
4574 }
4575
4576-/** Do a non-recursive import of all the songs in a directory. Does NOT decend into subdirectories.
4577- @param trackDao The track data access object which provides a connection to the database. We use this parameter in order to make this function callable from separate threads. You need to use a different DB connection for each thread.
4578- @return true if the scan completed without being cancelled. False if the scan was cancelled part-way through.
4579-*/
4580+// Do a non-recursive import of all the songs in a directory. Does NOT
4581+// decend into subdirectories.
4582+// @param trackDao The track data access object which provides a
4583+// connection to the database. We use this parameter in order to make
4584+// this function callable from separate threads. You need to use a
4585+// different DB connection for each thread.
4586+// @return true if the scan completed without being cancelled.
4587+// False if the scan was cancelled part-way through.
4588 bool TrackCollection::importDirectory(QString directory, TrackDAO &trackDao,
4589- const QStringList & nameFilters, volatile bool* cancel) {
4590+ const QStringList & nameFilters,
4591+ QSet<int>& restoredTracks,
4592+ const int dirId,
4593+ volatile bool* cancel) {
4594 //qDebug() << "TrackCollection::importDirectory(" << directory<< ")";
4595
4596 emit(startedLoading());
4597@@ -149,15 +157,17 @@
4598 // it. If it does exist in the database, then it is either in the
4599 // user's library OR the user has "removed" the track via
4600 // "Right-Click -> Remove". These tracks stay in the library, but
4601- // their mixxx_deleted column is 1.
4602- if (!trackDao.trackExistsInDatabase(absoluteFilePath)) {
4603+ // their mixxx_deleted column is 1. It is also possible that the
4604+ // track was deleted and now restored, set these in restoredTracks
4605+ if (trackDao.trackExistsInDatabase(absoluteFilePath)) {
4606+ restoredTracks.insert(trackDao.getTrackId(absoluteFilePath));
4607+ } else {
4608 //qDebug() << "Loading" << it.fileName();
4609 emit(progressLoading(it.fileName()));
4610
4611 TrackPointer pTrack = TrackPointer(new TrackInfoObject(
4612 absoluteFilePath), &QObject::deleteLater);
4613-
4614- if (trackDao.addTracksAdd(pTrack.data(), false)) {
4615+ if (trackDao.addTracksAdd(pTrack.data(), false,dirId)) {
4616 // Successful added
4617 // signal the main instance of TrackDao, that there is a
4618 // new Track in the database
4619@@ -183,13 +193,17 @@
4620 return m_playlistDao;
4621 }
4622
4623+DirectoryDAO& TrackCollection::getDirectoryDAO() {
4624+ return m_directoryDao;
4625+}
4626+
4627 QSharedPointer<BaseTrackCache> TrackCollection::getTrackSource(
4628- const QString name) {
4629+ const QString name) {
4630 return m_trackSources.value(name, QSharedPointer<BaseTrackCache>());
4631 }
4632
4633-void TrackCollection::addTrackSource(
4634- const QString name, QSharedPointer<BaseTrackCache> trackSource) {
4635+void TrackCollection::addTrackSource(const QString name,
4636+ QSharedPointer<BaseTrackCache> trackSource) {
4637 Q_ASSERT(!m_trackSources.contains(name));
4638 m_trackSources[name] = trackSource;
4639 }
4640
4641=== modified file 'mixxx/src/library/trackcollection.h'
4642--- mixxx/src/library/trackcollection.h 2013-02-09 22:06:46 +0000
4643+++ mixxx/src/library/trackcollection.h 2013-05-18 16:32:26 +0000
4644@@ -31,6 +31,7 @@
4645 #include "library/dao/cuedao.h"
4646 #include "library/dao/playlistdao.h"
4647 #include "library/dao/analysisdao.h"
4648+#include "library/dao/directorydao.h"
4649
4650 class TrackInfoObject;
4651
4652@@ -51,7 +52,10 @@
4653
4654 /** Import the files in a given diretory, without recursing into subdirectories */
4655 bool importDirectory(QString directory, TrackDAO &trackDao,
4656- const QStringList & nameFilters, volatile bool* cancel);
4657+ const QStringList & nameFilters,
4658+ QSet<int>& restoredTracks,
4659+ const int dirId,
4660+ volatile bool* cancel);
4661
4662 void resetLibaryCancellation();
4663 QSqlDatabase& getDatabase();
4664@@ -59,6 +63,7 @@
4665 CrateDAO& getCrateDAO();
4666 TrackDAO& getTrackDAO();
4667 PlaylistDAO& getPlaylistDAO();
4668+ DirectoryDAO& getDirectoryDAO();
4669 QSharedPointer<BaseTrackCache> getTrackSource(const QString name);
4670 void addTrackSource(const QString name, QSharedPointer<BaseTrackCache> trackSource);
4671 void cancelLibraryScan();
4672@@ -81,7 +86,13 @@
4673 CueDAO m_cueDao;
4674 AnalysisDao m_analysisDao;
4675 TrackDAO m_trackDao;
4676+ DirectoryDAO m_directoryDao;
4677 const QRegExp m_supportedFileExtensionsRegex;
4678+ // Flag to raise when library scan should be cancelled
4679+ int bCancelLibraryScan;
4680+ QMutex m_libraryScanMutex;
4681+
4682+
4683 };
4684
4685 #endif
4686
4687=== modified file 'mixxx/src/library/trackmodel.h'
4688--- mixxx/src/library/trackmodel.h 2012-11-25 09:33:00 +0000
4689+++ mixxx/src/library/trackmodel.h 2013-05-18 16:32:26 +0000
4690@@ -43,7 +43,8 @@
4691 TRACKMODELCAPS_RESETPLAYED = 0x04000,
4692 TRACKMODELCAPS_HIDE = 0x08000,
4693 TRACKMODELCAPS_UNHIDE = 0x10000,
4694- TRACKMODELCAPS_PURGE = 0x20000
4695+ TRACKMODELCAPS_PURGE = 0x20000,
4696+ TRACKMODELCAPS_DELETEFS = 0x40000
4697 };
4698
4699 typedef int CapabilitiesFlags; /** Enables us to do ORing */
4700@@ -63,7 +64,10 @@
4701 virtual const QLinkedList<int> getTrackRows(int trackId) const = 0;
4702
4703 bool isTrackModel() { return true;}
4704- virtual void search(const QString& searchText) = 0;
4705+ virtual void search(const QString& searchText, const QString& extraFilter=QString()) {
4706+ Q_UNUSED(searchText);
4707+ Q_UNUSED(extraFilter);
4708+ };
4709 virtual const QString currentSearch() const = 0;
4710 virtual bool isColumnInternal(int column) = 0;
4711 // if no header state exists, we may hide some columns so that the user can
4712@@ -71,9 +75,7 @@
4713 virtual bool isColumnHiddenByDefault(int column) = 0;
4714 virtual const QList<int>& showableColumns() const { return m_emptyColumns; }
4715 virtual const QList<int>& searchColumns() const { return m_emptyColumns; }
4716- virtual void removeTrack(const QModelIndex& index) {
4717- Q_UNUSED(index);
4718- }
4719+
4720 virtual void removeTracks(const QModelIndexList& indices) {
4721 Q_UNUSED(indices);
4722 }
4723@@ -83,14 +85,15 @@
4724 virtual void unhideTracks(const QModelIndexList& indices) {
4725 Q_UNUSED(indices);
4726 }
4727+ virtual void relocateTracks(const QModelIndexList& indices) {
4728+ Q_UNUSED(indices);
4729+ }
4730+ virtual void deleteTracks(const QModelIndexList& indices) {
4731+ Q_UNUSED(indices);
4732+ }
4733 virtual void purgeTracks(const QModelIndexList& indices) {
4734 Q_UNUSED(indices);
4735 }
4736- virtual bool addTrack(const QModelIndex& index, QString location) {
4737- Q_UNUSED(index);
4738- Q_UNUSED(location);
4739- return false;
4740- }
4741 virtual int addTracks(const QModelIndex& index, QList<QString> locations) {
4742 Q_UNUSED(index);
4743 Q_UNUSED(locations);
4744@@ -133,10 +136,13 @@
4745 m_iDefaultSortColumn = sortColumn;
4746 m_eDefaultSortOrder = sortOrder;
4747 }
4748-
4749+
4750 virtual int fieldIndex(const QString& fieldName) const {
4751 Q_UNUSED(fieldName);
4752- return 0;
4753+ return -1;
4754+ }
4755+
4756+ virtual void select() {
4757 }
4758
4759 private:
4760
4761=== modified file 'mixxx/src/library/traktor/traktorfeature.cpp'
4762--- mixxx/src/library/traktor/traktorfeature.cpp 2013-01-01 11:53:13 +0000
4763+++ mixxx/src/library/traktor/traktorfeature.cpp 2013-05-18 16:32:26 +0000
4764@@ -11,17 +11,17 @@
4765 #include "library/traktor/traktorfeature.h"
4766
4767 #include "library/librarytablemodel.h"
4768-#include "library/missingtablemodel.h"
4769 #include "library/queryutil.h"
4770 #include "library/trackcollection.h"
4771 #include "library/treeitem.h"
4772
4773 TraktorTrackModel::TraktorTrackModel(QObject* parent,
4774- TrackCollection* pTrackCollection)
4775+ TrackCollection* pTrackCollection,
4776+ ConfigObject<ConfigValue> *pConfig)
4777 : BaseExternalTrackModel(parent, pTrackCollection,
4778 "mixxx.db.model.traktor_tablemodel",
4779 "traktor_library",
4780- "traktor") {
4781+ "traktor",pConfig) {
4782 }
4783
4784 bool TraktorTrackModel::isColumnHiddenByDefault(int column) {
4785@@ -33,12 +33,13 @@
4786 }
4787
4788 TraktorPlaylistModel::TraktorPlaylistModel(QObject* parent,
4789- TrackCollection* pTrackCollection)
4790+ TrackCollection* pTrackCollection,
4791+ ConfigObject<ConfigValue> *pConfig)
4792 : BaseExternalPlaylistModel(parent, pTrackCollection,
4793 "mixxx.db.model.traktor.playlistmodel",
4794 "traktor_playlists",
4795 "traktor_playlist_tracks",
4796- "traktor") {
4797+ "traktor", pConfig) {
4798 }
4799
4800 bool TraktorPlaylistModel::isColumnHiddenByDefault(int column) {
4801@@ -49,10 +50,12 @@
4802 return false;
4803 }
4804
4805-TraktorFeature::TraktorFeature(QObject* parent, TrackCollection* pTrackCollection)
4806+TraktorFeature::TraktorFeature(QObject* parent, TrackCollection* pTrackCollection,
4807+ ConfigObject<ConfigValue> *pConfig)
4808 : BaseExternalLibraryFeature(parent, pTrackCollection),
4809 m_pTrackCollection(pTrackCollection),
4810- m_cancelImport(false) {
4811+ m_cancelImport(false),
4812+ m_pConfig(pConfig) {
4813 QString tableName = "traktor_library";
4814 QString idColumn = "id";
4815 QStringList columns;
4816@@ -75,8 +78,8 @@
4817 columns, false)));
4818
4819 m_isActivated = false;
4820- m_pTraktorTableModel = new TraktorTrackModel(this, m_pTrackCollection);
4821- m_pTraktorPlaylistModel = new TraktorPlaylistModel(this, m_pTrackCollection);
4822+ m_pTraktorTableModel = new TraktorTrackModel(this, m_pTrackCollection,pConfig);
4823+ m_pTraktorPlaylistModel = new TraktorPlaylistModel(this, m_pTrackCollection,pConfig);
4824
4825 m_title = tr("Traktor");
4826
4827@@ -101,7 +104,8 @@
4828 }
4829
4830 BaseSqlTableModel* TraktorFeature::getPlaylistModelForPlaylist(QString playlist) {
4831- TraktorPlaylistModel* pModel = new TraktorPlaylistModel(this, m_pTrackCollection);
4832+ TraktorPlaylistModel* pModel = new TraktorPlaylistModel(this, m_pTrackCollection
4833+ ,m_pConfig);
4834 pModel->setPlaylist(playlist);
4835 return pModel;
4836 }
4837
4838=== modified file 'mixxx/src/library/traktor/traktorfeature.h'
4839--- mixxx/src/library/traktor/traktorfeature.h 2013-01-01 11:53:13 +0000
4840+++ mixxx/src/library/traktor/traktorfeature.h 2013-05-18 16:32:26 +0000
4841@@ -15,6 +15,7 @@
4842 #include "library/baseexternaltrackmodel.h"
4843 #include "library/baseexternalplaylistmodel.h"
4844 #include "library/treeitemmodel.h"
4845+#include "configobject.h"
4846
4847 class LibraryTableModel;
4848 class MissingTableModel;
4849@@ -24,21 +25,24 @@
4850 class TraktorTrackModel : public BaseExternalTrackModel {
4851 public:
4852 TraktorTrackModel(QObject* parent,
4853- TrackCollection* pTrackCollection);
4854+ TrackCollection* pTrackCollection,
4855+ ConfigObject<ConfigValue> *pConfig);
4856 virtual bool isColumnHiddenByDefault(int column);
4857 };
4858
4859 class TraktorPlaylistModel : public BaseExternalPlaylistModel {
4860 public:
4861 TraktorPlaylistModel(QObject* parent,
4862- TrackCollection* pTrackCollection);
4863+ TrackCollection* pTrackCollection,
4864+ ConfigObject<ConfigValue> *pConfig);
4865 virtual bool isColumnHiddenByDefault(int column);
4866 };
4867
4868 class TraktorFeature : public BaseExternalLibraryFeature {
4869 Q_OBJECT
4870 public:
4871- TraktorFeature(QObject* parent, TrackCollection*);
4872+ TraktorFeature(QObject* parent, TrackCollection*,
4873+ ConfigObject<ConfigValue> *pConfig);
4874 virtual ~TraktorFeature();
4875
4876 QVariant title();
4877@@ -70,6 +74,7 @@
4878 TrackCollection* m_pTrackCollection;
4879 // A separate db connection for the worker parsing thread
4880 QSqlDatabase m_database;
4881+ ConfigObject<ConfigValue> *m_pConfig;
4882 TraktorTrackModel* m_pTraktorTableModel;
4883 TraktorPlaylistModel* m_pTraktorPlaylistModel;
4884
4885
4886=== modified file 'mixxx/src/library/treeitem.cpp'
4887--- mixxx/src/library/treeitem.cpp 2013-05-18 16:23:08 +0000
4888+++ mixxx/src/library/treeitem.cpp 2013-05-18 16:32:26 +0000
4889@@ -45,6 +45,12 @@
4890 }
4891
4892 TreeItem::~TreeItem() {
4893+ qDebug() << "~TreeItem()";
4894+ //TODO(kain88) this causes a segfault during shutdown, no idea why
4895+ qDebug() << m_childItems << " empty " << m_childItems.isEmpty();
4896+ if (m_childItems.isEmpty()) {
4897+ return;
4898+ }
4899 qDeleteAll(m_childItems);
4900 }
4901
4902
4903=== modified file 'mixxx/src/mixxx.cpp'
4904--- mixxx/src/mixxx.cpp 2013-05-16 00:14:12 +0000
4905+++ mixxx/src/mixxx.cpp 2013-05-18 16:32:26 +0000
4906@@ -298,30 +298,14 @@
4907 m_pEngine->addChannel(pMicrophone);
4908 m_pSoundManager->registerInput(micInput, pMicrophone);
4909
4910- // Get Music dir
4911- bool hasChanged_MusicDir = false;
4912- QDir dir(m_pConfig->getValueString(ConfigKey("[Playlist]","Directory")));
4913- if (m_pConfig->getValueString(
4914- ConfigKey("[Playlist]","Directory")).length() < 1 || !dir.exists())
4915- {
4916- // TODO this needs to be smarter, we can't distinguish between an empty
4917- // path return value (not sure if this is normally possible, but it is
4918- // possible with the Windows 7 "Music" library, which is what
4919- // QDesktopServices::storageLocation(QDesktopServices::MusicLocation)
4920- // resolves to) and a user hitting 'cancel'. If we get a blank return
4921- // but the user didn't hit cancel, we need to know this and let the
4922- // user take some course of action -- bkgood
4923- QString fd = QFileDialog::getExistingDirectory(
4924- this, tr("Choose music library directory"),
4925- QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
4926-
4927- if (fd != "")
4928- {
4929- m_pConfig->set(ConfigKey("[Playlist]","Directory"), fd);
4930- m_pConfig->Save();
4931- hasChanged_MusicDir = true;
4932- }
4933+ // library dies in seemingly unrelated qtsql error about not having a
4934+ // sqlite driver if this path doesn't exist. Normally config->Save()
4935+ // above would make it but if it doesn't get run for whatever reason
4936+ // we get hosed -- bkgood
4937+ if (!QDir(QDir::homePath().append("/").append(SETTINGS_PATH)).exists()) {
4938+ QDir().mkpath(QDir::homePath().append("/").append(SETTINGS_PATH));
4939 }
4940+
4941 // Do not write meta data back to ID3 when meta data has changed
4942 // Because multiple TrackDao objects can exists for a particular track
4943 // writing meta data may ruine your MP3 file if done simultaneously.
4944@@ -375,6 +359,46 @@
4945 bFirstRun || bUpgraded,
4946 m_pRecordingManager);
4947 m_pPlayerManager->bindToLibrary(m_pLibrary);
4948+ connect(this, SIGNAL(dirsChanged(QString,QString)),
4949+ m_pLibrary, SLOT(slotDirsChanged(QString,QString)));
4950+
4951+ // Check if we update from an old db without relative library paths
4952+ // getValueString will return "" if no value was set
4953+ bool oldLibrary = m_pConfig->getValueString(ConfigKey("[Library]","newVersion"))=="";
4954+ qDebug() << "kain88 status of library version" << oldLibrary;
4955+ //TODO(kain88) mode this into update code
4956+ if (oldLibrary) {
4957+ QString dir = m_pConfig->getValueString(ConfigKey("[Playlist]","Directory"));
4958+ // adds the current library path to the directories table and updates
4959+ // track_locations for all tracks
4960+ if (dir!="") {
4961+ emit(dirsChanged("update",dir));
4962+ m_pConfig->set(ConfigKey("[Library]","newVersion"),ConfigValue((int)true));
4963+ m_pConfig->Save();
4964+ }
4965+ }
4966+
4967+ // Get Music dir
4968+ bool hasChanged_MusicDir = false;
4969+
4970+ QStringList dirs = m_pLibrary->getDirs();
4971+ if (dirs.size() < 1) {
4972+ // TODO(XXX) this needs to be smarter, we can't distinguish between an empty
4973+ // path return value (not sure if this is normally possible, but it is
4974+ // possible with the Windows 7 "Music" library, which is what
4975+ // QDesktopServices::storageLocation(QDesktopServices::MusicLocation)
4976+ // resolves to) and a user hitting 'cancel'. If we get a blank return
4977+ // but the user didn't hit cancel, we need to know this and let the
4978+ // user take some course of action -- bkgood
4979+ QString fd = QFileDialog::getExistingDirectory(
4980+ this, tr("Choose music library directory"),
4981+ QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
4982+ if (fd != "") {
4983+ //adds Folder to database
4984+ emit(dirsChanged("added",fd));
4985+ hasChanged_MusicDir = true;
4986+ }
4987+ }
4988
4989 // Call inits to invoke all other construction parts
4990
4991@@ -414,6 +438,11 @@
4992 // Initialize preference dialog
4993 m_pPrefDlg = new DlgPreferences(this, m_pSkinLoader, m_pSoundManager, m_pPlayerManager,
4994 m_pControllerManager, m_pVCManager, m_pConfig);
4995+ connect(m_pPrefDlg, SIGNAL(configChanged(QString,QString)),
4996+ m_pLibrary, SIGNAL(configChanged(QString,QString)));
4997+ connect(m_pPrefDlg, SIGNAL(dirsChanged(QString,QString)),
4998+ m_pLibrary, SLOT(slotDirsChanged(QString,QString)));
4999+
5000 m_pPrefDlg->setWindowIcon(QIcon(":/images/ic_mixxx_window.png"));
The diff has been truncated for viewing.