Merge lp:~mixxxdevelopers/mixxx/library_features into lp:~mixxxdevelopers/mixxx/trunk
- library_features
- Merge into trunk
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 | ||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mixxx Development Team | Pending | ||
Review via email: mp+162700@code.launchpad.net |
Commit message
Description of the change
Getting the ball rolling on the code review for Max's library_features work.
RJ Skerry-Ryan (rryan) wrote : | # |
- 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
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")); |
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)
* BaseSqlTableMod el::relocateTra cks
- 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: :relocateDirect ory -- 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: :updateTrackLoc ations -- 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: :deleteTracksFr omFS -- 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...