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

Proposed by RJ Skerry-Ryan
Status: Merged
Merged at revision: 2489
Proposed branch: lp:~mixxxdevelopers/mixxx/features_library
Merge into: lp:~mixxxdevelopers/mixxx/trunk
Diff against target: 2332 lines (+1056/-419)
32 files modified
mixxx/build/depends.py (+4/-1)
mixxx/res/schema.xml (+18/-0)
mixxx/src/library/basesqltablemodel.cpp (+227/-5)
mixxx/src/library/basesqltablemodel.h (+10/-1)
mixxx/src/library/cratetablemodel.cpp (+22/-66)
mixxx/src/library/cratetablemodel.h (+0/-2)
mixxx/src/library/dao/trackdao.cpp (+32/-9)
mixxx/src/library/dao/trackdao.h (+4/-0)
mixxx/src/library/legacylibraryimporter.cpp (+10/-3)
mixxx/src/library/libraryscanner.cpp (+23/-13)
mixxx/src/library/librarytablemodel.cpp (+31/-83)
mixxx/src/library/librarytablemodel.h (+0/-2)
mixxx/src/library/missingtablemodel.cpp (+7/-58)
mixxx/src/library/missingtablemodel.h (+1/-1)
mixxx/src/library/playlisttablemodel.cpp (+5/-62)
mixxx/src/library/playlisttablemodel.h (+0/-51)
mixxx/src/library/rhythmboxtrackmodel.cpp (+3/-0)
mixxx/src/library/stardelegate.cpp (+114/-0)
mixxx/src/library/stardelegate.h (+56/-0)
mixxx/src/library/stareditor.cpp (+95/-0)
mixxx/src/library/stareditor.h (+61/-0)
mixxx/src/library/starrating.cpp (+74/-0)
mixxx/src/library/starrating.h (+62/-0)
mixxx/src/library/trackcollection.cpp (+4/-1)
mixxx/src/mixxx.cpp (+2/-2)
mixxx/src/player.cpp (+2/-0)
mixxx/src/trackinfoobject.cpp (+74/-0)
mixxx/src/trackinfoobject.h (+19/-0)
mixxx/src/widget/wlibrarytableview.cpp (+8/-1)
mixxx/src/widget/wstatuslight.cpp (+70/-39)
mixxx/src/widget/wstatuslight.h (+10/-12)
mixxx/src/widget/wtracktableview.cpp (+8/-7)
To merge this branch: bzr merge lp:~mixxxdevelopers/mixxx/features_library
Reviewer Review Type Date Requested Status
Albert Santoni Approve
Review via email: mp+38802@code.launchpad.net

Description of the change

This branch is the combination of both lp:~ywwg/mixxx/features_library and lp:~raffitea/mixxx/features_library.

The combined set of features added here by both Tobias and Owen are:

* Adding a times played column to the library
* Adding a rating column to the library
* Adding a played column to the library
* Version bump to schema version 6, clear all the headerstate so that the new columns show up
* Adding a checkbox widget to the times-played column which is shown next to the # of times the track was played in the library track table
* Adding a star-widget to the rating column in the library track table.
* Increase the play count of a track and set it played when it is successfully loaded to a player.
* Making search queries search based on individual terms instead of the whole phrase
* Search now searches album, location, comment, and title.
* Make artist, album, title, year, track number, genre, comment, BPM in the track table editable on a single click.
* Disable loading track by hitting enter to avoid accidental loads from editing
* Rewrite part of WStatusLight (Owen, can you describe what the change here was?)
* Test for the existence of the 1.7-library conversion file result and skip legacy import if it exists.
* Added some logic to record the creation date of a Track, but it isn't used anywhere as far as I can tell.

Thanks to Tobias and Owen for this great work!

To post a comment you must log in.
2489. By RJ Skerry-Ryan

Clear the prepare and missing headers on upgarde to schema version 6.

Revision history for this message
RAFFI TEA (raffitea) wrote :

Please note that Jus requested a way to specify the rating colour via skins. I have not found a good solution to that since star rating editors are created from delegates and I do not know how to read from skin.xml there :-( A singleton 'SkinManager' would be great.

BTW: Star ratings look good on Windows and Ubuntu 9.04. On Ubuntu 10.10 is does not look nice anymore (maybe QT 7.0 related)

Revision history for this message
Albert Santoni (gamegod) wrote :
Revision history for this message
Albert Santoni (gamegod) wrote :

I've reviewed your code and everything pretty much looks good to me.

review: Approve
Revision history for this message
Albert Santoni (gamegod) wrote :

Actually, I lied. I think we should make the Key column hidden by default, since it'll probably be blank for most people, and we don't yet offer key analysis. What do you think?

Revision history for this message
RAFFI TEA (raffitea) wrote :

It sounds reasonable. How can I archive such a behaviour?

Revision history for this message
RAFFI TEA (raffitea) wrote :

Key columns are now hidden by default. Basically, I have extended TrackModel with a method 'isColumnHiddenByDefault(int column)'. All concrete TrackModels such as LibraryTableModel implement this method. So we can even hide more columns by default but a user can bring it to front on request.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'mixxx/build/depends.py'
2--- mixxx/build/depends.py 2010-10-19 00:05:55 +0000
3+++ mixxx/build/depends.py 2010-10-19 05:33:52 +0000
4@@ -454,6 +454,9 @@
5 "library/featuredartistswebview.cpp",
6 "library/bundledsongswebview.cpp",
7 "library/songdownloader.cpp",
8+ "library/starrating.cpp",
9+ "library/stardelegate.cpp",
10+ "library/stareditor.cpp",
11
12 "xmlparse.cpp",
13 "parser.cpp",
14@@ -676,7 +679,7 @@
15 build.env.Append(LINKFLAGS = ['/nodefaultlib:LIBCMT.lib',
16 '/nodefaultlib:LIBCMTd.lib',
17 '/entry:mainCRTStartup'])
18- # Makes the program not launch a shell first
19+ # Makes the program not launch a shell first
20 if build.toolchain_is_msvs:
21 build.env.Append(LINKFLAGS = '/subsystem:windows')
22 elif build.toolchain_is_gnu:
23
24=== modified file 'mixxx/res/schema.xml'
25--- mixxx/res/schema.xml 2010-09-14 14:45:35 +0000
26+++ mixxx/res/schema.xml 2010-10-19 05:33:52 +0000
27@@ -146,4 +146,22 @@
28 ALTER TABLE LibraryHashes ADD COLUMN needs_verification INTEGER DEFAULT 0;
29 </sql>
30 </revision>
31+ <revision version="6">
32+ <description>
33+ Add timesplayed and rating column. Reset header state.
34+ </description>
35+ <sql>
36+ ALTER TABLE library ADD COLUMN timesplayed integer DEFAULT 0;
37+ ALTER TABLE library ADD COLUMN rating integer DEFAULT 0;
38+
39+ UPDATE library SET timesplayed = played;
40+ UPDATE library SET played = 0;
41+
42+ DELETE FROM settings WHERE name="mixxx.db.model.library.header_state";
43+ DELETE FROM settings WHERE name="mixxx.db.model.playlist.header_state";
44+ DELETE FROM settings WHERE name="mixxx.db.model.crate.header_state";
45+ DELETE FROM settings WHERE name="mixxx.db.model.prepare.header_state";
46+ DELETE FROM settings WHERE name="mixxx.db.model.missing.header_state";
47+ </sql>
48+ </revision>
49 </schema>
50
51=== modified file 'mixxx/src/library/basesqltablemodel.cpp'
52--- mixxx/src/library/basesqltablemodel.cpp 2010-08-27 20:29:12 +0000
53+++ mixxx/src/library/basesqltablemodel.cpp 2010-10-19 05:33:52 +0000
54@@ -6,6 +6,9 @@
55 #include "trackinfoobject.h"
56 #include "library/trackcollection.h"
57 #include "library/basesqltablemodel.h"
58+#include "mixxxutils.cpp"
59+#include "library/starrating.h"
60+
61
62 BaseSqlTableModel::BaseSqlTableModel(QObject* parent,
63 TrackCollection* pTrackCollection,
64@@ -20,6 +23,44 @@
65 }
66
67 BaseSqlTableModel::~BaseSqlTableModel() {
68+
69+}
70+
71+void BaseSqlTableModel::initHeaderData() {
72+ //Set the column heading labels, rename them for translations and have
73+ //proper capitalization
74+ setHeaderData(fieldIndex(LIBRARYTABLE_TIMESPLAYED),
75+ Qt::Horizontal, tr("Played"));
76+ setHeaderData(fieldIndex(LIBRARYTABLE_ARTIST),
77+ Qt::Horizontal, tr("Artist"));
78+ setHeaderData(fieldIndex(LIBRARYTABLE_TITLE),
79+ Qt::Horizontal, tr("Title"));
80+ setHeaderData(fieldIndex(LIBRARYTABLE_ALBUM),
81+ Qt::Horizontal, tr("Album"));
82+ setHeaderData(fieldIndex(LIBRARYTABLE_GENRE),
83+ Qt::Horizontal, tr("Genre"));
84+ setHeaderData(fieldIndex(LIBRARYTABLE_YEAR),
85+ Qt::Horizontal, tr("Year"));
86+ setHeaderData(fieldIndex(LIBRARYTABLE_FILETYPE),
87+ Qt::Horizontal, tr("Type"));
88+ setHeaderData(fieldIndex(LIBRARYTABLE_LOCATION),
89+ Qt::Horizontal, tr("Location"));
90+ setHeaderData(fieldIndex(LIBRARYTABLE_COMMENT),
91+ Qt::Horizontal, tr("Comment"));
92+ setHeaderData(fieldIndex(LIBRARYTABLE_DURATION),
93+ Qt::Horizontal, tr("Duration"));
94+ setHeaderData(fieldIndex(LIBRARYTABLE_RATING),
95+ Qt::Horizontal, tr("Rating"));
96+ setHeaderData(fieldIndex(LIBRARYTABLE_BITRATE),
97+ Qt::Horizontal, tr("Bitrate"));
98+ setHeaderData(fieldIndex(LIBRARYTABLE_BPM),
99+ Qt::Horizontal, tr("BPM"));
100+ setHeaderData(fieldIndex(LIBRARYTABLE_TRACKNUMBER),
101+ Qt::Horizontal, tr("Track #"));
102+ setHeaderData(fieldIndex(LIBRARYTABLE_DATETIMEADDED),
103+ Qt::Horizontal, tr("Date Added"));
104+ setHeaderData(fieldIndex(PLAYLISTTRACKSTABLE_POSITION),
105+ Qt::Horizontal, tr("#"));
106 }
107
108 bool BaseSqlTableModel::select() {
109@@ -48,9 +89,10 @@
110 return result;
111 }
112
113-QVariant BaseSqlTableModel::data(const QModelIndex& index, int role) const {
114- if (!index.isValid())
115+QVariant BaseSqlTableModel::getBaseValue(const QModelIndex& index, int role) const {
116+ if (!index.isValid()) {
117 return QVariant();
118+ }
119
120 int row = index.row();
121 int col = index.column();
122@@ -62,7 +104,12 @@
123
124 int trackId = m_rowToTrackId[row];
125
126- if (role == Qt::DisplayRole && m_trackOverrides.contains(trackId)) {
127+ /*
128+ * The if-block below is only executed when a table item has been edited.
129+ *
130+ */
131+ if ((role == Qt::DisplayRole || role == Qt::ToolTipRole || role == Qt::EditRole) &&
132+ m_trackOverrides.contains(trackId)) {
133 //qDebug() << "Returning override for track" << trackId;
134 TrackPointer pTrack = m_trackDAO.getTrack(trackId);
135
136@@ -86,16 +133,146 @@
137 } else if (fieldIndex(LIBRARYTABLE_COMMENT) == col) {
138 return QVariant(pTrack->getComment());
139 } else if (fieldIndex(LIBRARYTABLE_DURATION) == col) {
140- return QVariant(pTrack->getDuration());
141+ return pTrack->getDuration();
142 } else if (fieldIndex(LIBRARYTABLE_BITRATE) == col) {
143 return QVariant(pTrack->getBitrate());
144 } else if (fieldIndex(LIBRARYTABLE_BPM) == col) {
145 return QVariant(pTrack->getBpm());
146+ } else if (fieldIndex(LIBRARYTABLE_PLAYED) == col) {
147+ return QVariant(pTrack->getPlayed());
148+ } else if (fieldIndex(LIBRARYTABLE_TIMESPLAYED) == col) {
149+ return QVariant(pTrack->getTimesPlayed());
150+ } else if (fieldIndex(LIBRARYTABLE_RATING) == col) {
151+ return pTrack->getRating();
152 }
153 }
154+
155+ // If none of these work, hand off to the lower layer to deal with. The role
156+ // might not be Edit/Display/ToolTip, or we might have a bug.
157 return QSqlTableModel::data(index, role);
158 }
159
160+
161+QVariant BaseSqlTableModel::data(const QModelIndex& index, int role) const {
162+ if (!index.isValid()) {
163+ return QVariant();
164+ }
165+
166+ int row = index.row();
167+ int col = index.column();
168+
169+ //qDebug() << "BaseSqlTableModel::data() column:" << col << "role:" << role;
170+
171+ // This value is the value in its most raw form. It was looked up either
172+ // from the SQL table or from the cached track layer.
173+ QVariant value = getBaseValue(index, role);
174+
175+ // Format the value based on whether we are in a tooltip, display, or edit
176+ // role
177+ if (role == Qt::ToolTipRole || role == Qt::DisplayRole) {
178+ if (index.column() == fieldIndex(LIBRARYTABLE_DURATION)) {
179+ if (qVariantCanConvert<int>(value))
180+ value = MixxxUtils::secondsToMinutes(qVariantValue<int>(value));
181+ } else if (index.column() == fieldIndex(LIBRARYTABLE_RATING)) {
182+ if (qVariantCanConvert<int>(value))
183+ value = qVariantFromValue(StarRating(value.toInt()));
184+ } else if (index.column() == fieldIndex(LIBRARYTABLE_TIMESPLAYED)) {
185+ if (qVariantCanConvert<int>(value))
186+ value = QString("(%1)").arg(value.toInt());
187+ } else if (index.column() == fieldIndex(LIBRARYTABLE_PLAYED)) {
188+ // Convert to a bool. Not really that useful since it gets converted
189+ // right back to a QVariant
190+ value = (value == "true") ? true : false;
191+ }
192+ } else if (role == Qt::EditRole) {
193+ if (index.column() == fieldIndex(LIBRARYTABLE_BPM)) {
194+ return value.toDouble();
195+ } else if (index.column() == fieldIndex(LIBRARYTABLE_TIMESPLAYED)) {
196+ return index.sibling(index.row(), fieldIndex(LIBRARYTABLE_PLAYED)).data().toBool();
197+ } else if (index.column() == fieldIndex(LIBRARYTABLE_RATING)) {
198+ if (qVariantCanConvert<int>(value))
199+ value = qVariantFromValue(StarRating(value.toInt()));
200+ }
201+ } else if (role == Qt::CheckStateRole) {
202+ if (index.column() == fieldIndex(LIBRARYTABLE_TIMESPLAYED)) {
203+ bool played = index.sibling(index.row(), fieldIndex(LIBRARYTABLE_PLAYED)).data().toBool();
204+ value = played ? Qt::Checked : Qt::Unchecked;
205+ }
206+ }
207+
208+ return value;
209+}
210+
211+bool BaseSqlTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
212+{
213+ if (!index.isValid())
214+ return false;
215+
216+ int row = index.row();
217+ int col = index.column();
218+
219+ //qDebug() << "BaseSqlTableModel::setData() column:" << col << "value:" << value << "role:" << role;
220+
221+ // Over-ride sets to TIMESPLAYED and re-direct them to PLAYED
222+ if (role == Qt::CheckStateRole) {
223+ if (index.column() == fieldIndex(LIBRARYTABLE_TIMESPLAYED)) {
224+ QString val = value.toInt() > 0 ? QString("true") : QString("false");
225+ QModelIndex playedIndex = index.sibling(index.row(), fieldIndex(LIBRARYTABLE_PLAYED));
226+ return setData(playedIndex, val, Qt::EditRole);
227+ }
228+ }
229+
230+ Q_ASSERT(m_rowToTrackId.contains(row));
231+ if (!m_rowToTrackId.contains(row)) {
232+ return QSqlTableModel::setData(index, value, role);
233+ }
234+
235+ int trackId = m_rowToTrackId[row];
236+ TrackPointer pTrack = m_trackDAO.getTrack(trackId);
237+
238+ // TODO(XXX) Qt properties could really help here.
239+ if (fieldIndex(LIBRARYTABLE_ARTIST) == col) {
240+ pTrack->setArtist(value.toString());
241+ } else if (fieldIndex(LIBRARYTABLE_TITLE) == col) {
242+ pTrack->setTitle(value.toString());
243+ } else if (fieldIndex(LIBRARYTABLE_ALBUM) == col) {
244+ pTrack->setAlbum(value.toString());
245+ } else if (fieldIndex(LIBRARYTABLE_YEAR) == col) {
246+ pTrack->setYear(value.toString());
247+ } else if (fieldIndex(LIBRARYTABLE_GENRE) == col) {
248+ pTrack->setGenre(value.toString());
249+ } else if (fieldIndex(LIBRARYTABLE_FILETYPE) == col) {
250+ pTrack->setType(value.toString());
251+ } else if (fieldIndex(LIBRARYTABLE_TRACKNUMBER) == col) {
252+ pTrack->setTrackNumber(value.toString());
253+ } else if (fieldIndex(LIBRARYTABLE_LOCATION) == col) {
254+ pTrack->setLocation(value.toString());
255+ } else if (fieldIndex(LIBRARYTABLE_COMMENT) == col) {
256+ pTrack->setComment(value.toString());
257+ } else if (fieldIndex(LIBRARYTABLE_DURATION) == col) {
258+ pTrack->setDuration(value.toInt());
259+ } else if (fieldIndex(LIBRARYTABLE_BITRATE) == col) {
260+ pTrack->setBitrate(value.toInt());
261+ } else if (fieldIndex(LIBRARYTABLE_BPM) == col) {
262+ //QVariant::toFloat needs >= QT 4.6.x
263+ pTrack->setBpm((float) value.toDouble());
264+ } else if (fieldIndex(LIBRARYTABLE_PLAYED) == col) {
265+ pTrack->setPlayed(value.toBool());
266+ } else if (fieldIndex(LIBRARYTABLE_TIMESPLAYED) == col) {
267+ pTrack->setTimesPlayed(value.toInt());
268+ } else if (fieldIndex(LIBRARYTABLE_RATING) == col) {
269+ StarRating starRating = qVariantValue<StarRating>(value);
270+ pTrack->setRating(starRating.starCount());
271+ }
272+
273+ // Do not save the track here. Changing the track dirties it and the caching
274+ // system will automatically save the track once it is unloaded from
275+ // memory. rryan 10/2010
276+ //m_trackDAO.saveTrack(pTrack);
277+
278+ return true;
279+}
280+
281 void BaseSqlTableModel::trackChanged(int trackId) {
282 m_trackOverrides.insert(trackId);
283 if (m_trackIdToRow.contains(trackId)) {
284@@ -129,7 +306,7 @@
285
286 QString table = m_qTableName;
287 QString field = database().driver()->escapeIdentifier(f.name(),
288- QSqlDriver::FieldName);
289+ QSqlDriver::FieldName);
290 s.append(QLatin1String("ORDER BY "));
291 QString sort_field = QString("%1.%2").arg(table).arg(field);
292
293@@ -149,3 +326,48 @@
294 s += m_eSortOrder == Qt::AscendingOrder ? QLatin1String(" ASC") : QLatin1String(" DESC");
295 return s;
296 }
297+
298+Qt::ItemFlags BaseSqlTableModel::readWriteFlags(const QModelIndex &index) const
299+{
300+ Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index);
301+ if (!index.isValid())
302+ return Qt::ItemIsEnabled;
303+
304+ //Enable dragging songs from this data model to elsewhere (like the waveform
305+ //widget to load a track into a Player).
306+ defaultFlags |= Qt::ItemIsDragEnabled;
307+
308+ if ( index.column() == fieldIndex(LIBRARYTABLE_FILETYPE)
309+ || index.column() == fieldIndex(LIBRARYTABLE_LOCATION)
310+ || index.column() == fieldIndex(LIBRARYTABLE_DURATION)
311+ || index.column() == fieldIndex(LIBRARYTABLE_BITRATE)
312+ || index.column() == fieldIndex(LIBRARYTABLE_DATETIMEADDED))
313+ {
314+ return defaultFlags | QAbstractItemModel::flags(index);
315+ }
316+ else if (index.column() == fieldIndex(LIBRARYTABLE_TIMESPLAYED)) {
317+ return defaultFlags | QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable;
318+ }
319+ else {
320+ return defaultFlags | QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
321+ }
322+}
323+
324+Qt::ItemFlags BaseSqlTableModel::readOnlyFlags(const QModelIndex &index) const
325+{
326+ Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index);
327+ if (!index.isValid())
328+ return Qt::ItemIsEnabled;
329+
330+ //Enable dragging songs from this data model to elsewhere (like the waveform widget to
331+ //load a track into a Player).
332+ defaultFlags |= Qt::ItemIsDragEnabled;
333+
334+ return defaultFlags;
335+
336+}
337+
338+Qt::ItemFlags BaseSqlTableModel::flags(const QModelIndex &index) const
339+{
340+ return readWriteFlags(index);
341+}
342
343=== modified file 'mixxx/src/library/basesqltablemodel.h'
344--- mixxx/src/library/basesqltablemodel.h 2010-07-15 19:07:16 +0000
345+++ mixxx/src/library/basesqltablemodel.h 2010-10-19 05:33:52 +0000
346@@ -23,12 +23,21 @@
347 virtual void setSort(int column, Qt::SortOrder order);
348 virtual bool select();
349 virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
350-
351+ virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
352+ /** Use this if you want a model that is read-only. */
353+ virtual Qt::ItemFlags readOnlyFlags(const QModelIndex &index) const;
354+ /** Use this if you want a model that can be changed */
355+ virtual Qt::ItemFlags readWriteFlags(const QModelIndex &index) const;
356+ /** calls readWriteFlags() by default */
357+ virtual Qt::ItemFlags flags(const QModelIndex &index) const;
358 protected:
359 virtual QString orderByClause() const;
360+ virtual void initHeaderData();
361 private slots:
362 void trackChanged(int trackId);
363 private:
364+ QVariant getBaseValue(const QModelIndex& index, int role = Qt::DisplayRole) const;
365+
366 QString m_qTableName;
367 int m_iSortColumn;
368 Qt::SortOrder m_eSortOrder;
369
370=== modified file 'mixxx/src/library/cratetablemodel.cpp'
371--- mixxx/src/library/cratetablemodel.cpp 2010-09-14 20:32:32 +0000
372+++ mixxx/src/library/cratetablemodel.cpp 2010-10-19 05:33:52 +0000
373@@ -33,11 +33,14 @@
374 QString queryString = QString("CREATE TEMPORARY VIEW IF NOT EXISTS %1 AS "
375 "SELECT "
376 "library." + LIBRARYTABLE_ID + "," +
377+ LIBRARYTABLE_PLAYED + "," +
378+ LIBRARYTABLE_TIMESPLAYED + "," +
379 LIBRARYTABLE_ARTIST + "," +
380 LIBRARYTABLE_TITLE + "," +
381 LIBRARYTABLE_ALBUM + "," +
382 LIBRARYTABLE_YEAR + "," +
383 LIBRARYTABLE_DURATION + "," +
384+ LIBRARYTABLE_RATING + "," +
385 LIBRARYTABLE_GENRE + "," +
386 LIBRARYTABLE_FILETYPE + "," +
387 LIBRARYTABLE_TRACKNUMBER + "," +
388@@ -69,34 +72,8 @@
389
390 select();
391
392- setHeaderData(fieldIndex(LIBRARYTABLE_ID),
393- Qt::Horizontal, tr("ID"));
394- setHeaderData(fieldIndex(LIBRARYTABLE_ARTIST),
395- Qt::Horizontal, tr("Artist"));
396- setHeaderData(fieldIndex(LIBRARYTABLE_TITLE),
397- Qt::Horizontal, tr("Title"));
398- setHeaderData(fieldIndex(LIBRARYTABLE_ALBUM),
399- Qt::Horizontal, tr("Album"));
400- setHeaderData(fieldIndex(LIBRARYTABLE_GENRE),
401- Qt::Horizontal, tr("Genre"));
402- setHeaderData(fieldIndex(LIBRARYTABLE_YEAR),
403- Qt::Horizontal, tr("Year"));
404- setHeaderData(fieldIndex(LIBRARYTABLE_FILETYPE),
405- Qt::Horizontal, tr("Type"));
406- setHeaderData(fieldIndex("location"),
407- Qt::Horizontal, tr("Location"));
408- setHeaderData(fieldIndex(LIBRARYTABLE_COMMENT),
409- Qt::Horizontal, tr("Comment"));
410- setHeaderData(fieldIndex(LIBRARYTABLE_DURATION),
411- Qt::Horizontal, tr("Duration"));
412- setHeaderData(fieldIndex(LIBRARYTABLE_TRACKNUMBER),
413- Qt::Horizontal, tr("Track #"));
414- setHeaderData(fieldIndex(LIBRARYTABLE_BITRATE),
415- Qt::Horizontal, tr("Bitrate"));
416- setHeaderData(fieldIndex(LIBRARYTABLE_BPM),
417- Qt::Horizontal, tr("BPM"));
418- setHeaderData(fieldIndex(LIBRARYTABLE_DATETIMEADDED),
419- Qt::Horizontal, tr("Date Added"));
420+ // BaseSqlTableModel sets up the header names
421+ initHeaderData();
422 }
423
424 bool CrateTableModel::addTrack(const QModelIndex& index, QString location) {
425@@ -186,12 +163,22 @@
426 filter = "(" + LibraryTableModel::DEFAULT_LIBRARYFILTER + ")";
427 else {
428 QSqlField search("search", QVariant::String);
429- search.setValue("%" + searchText + "%");
430- QString escapedText = database().driver()->formatValue(search);
431- filter = "(" + LibraryTableModel::DEFAULT_LIBRARYFILTER + " AND " +
432- "(artist LIKE " + escapedText + " OR " +
433- "album LIKE " + escapedText + " OR " +
434- "title LIKE " + escapedText + "))";
435+
436+
437+ filter = "(" + LibraryTableModel::DEFAULT_LIBRARYFILTER;
438+
439+ foreach(QString term, searchText.split(" "))
440+ {
441+ search.setValue("%" + term + "%");
442+ QString escapedText = database().driver()->formatValue(search);
443+ filter += " AND (artist LIKE " + escapedText + " OR " +
444+ "album LIKE " + escapedText + " OR " +
445+ "location LIKE " + escapedText + " OR " +
446+ "comment LIKE " + escapedText + " OR " +
447+ "title LIKE " + escapedText + ")";
448+ }
449+
450+ filter += ")";
451 }
452
453 setFilter(filter);
454@@ -203,6 +190,7 @@
455
456 bool CrateTableModel::isColumnInternal(int column) {
457 if (column == fieldIndex(LIBRARYTABLE_ID) ||
458+ column == fieldIndex(LIBRARYTABLE_PLAYED) ||
459 column == fieldIndex(LIBRARYTABLE_MIXXXDELETED) ||
460 column == fieldIndex(TRACKLOCATIONSTABLE_FSDELETED)) {
461 return true;
462@@ -235,42 +223,10 @@
463 return mimeData;
464 }
465
466-Qt::ItemFlags CrateTableModel::flags(const QModelIndex& index) const {
467- Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index);
468- if (!index.isValid())
469- return Qt::ItemIsEnabled;
470-
471- //Enable dragging songs from this data model to elsewhere (like the waveform
472- //widget to load a track into a Player).
473- defaultFlags |= Qt::ItemIsDragEnabled;
474-
475- return defaultFlags;
476-}
477-
478 QItemDelegate* CrateTableModel::delegateForColumn(int i) {
479 return NULL;
480 }
481
482-QVariant CrateTableModel::data(const QModelIndex& item, int role) const {
483- if (!item.isValid())
484- return QVariant();
485-
486- QVariant value;
487-
488- if (role == Qt::ToolTipRole)
489- value = BaseSqlTableModel::data(item, Qt::DisplayRole);
490- else
491- value = BaseSqlTableModel::data(item, role);
492-
493- if ((role == Qt::DisplayRole || role == Qt::ToolTipRole) &&
494- item.column() == fieldIndex(LIBRARYTABLE_DURATION)) {
495- if (qVariantCanConvert<int>(value)) {
496- value = MixxxUtils::secondsToMinutes(qVariantValue<int>(value));
497- }
498- }
499- return value;
500-}
501-
502 TrackModel::CapabilitiesFlags CrateTableModel::getCapabilities() const {
503 return TRACKMODELCAPS_RECEIVEDROPS | TRACKMODELCAPS_ADDTOPLAYLIST |
504 TRACKMODELCAPS_ADDTOCRATE | TRACKMODELCAPS_ADDTOAUTODJ;
505
506=== modified file 'mixxx/src/library/cratetablemodel.h'
507--- mixxx/src/library/cratetablemodel.h 2010-09-13 06:23:38 +0000
508+++ mixxx/src/library/cratetablemodel.h 2010-10-19 05:33:52 +0000
509@@ -20,9 +20,7 @@
510
511 void setCrate(int crateId);
512
513- virtual QVariant data(const QModelIndex& item, int role) const;
514 QMimeData* mimeData(const QModelIndexList &indexes) const;
515- Qt::ItemFlags flags(const QModelIndex &index) const;
516
517 // From TrackModel
518 virtual TrackPointer getTrack(const QModelIndex& index) const;
519
520=== modified file 'mixxx/src/library/dao/trackdao.cpp'
521--- mixxx/src/library/dao/trackdao.cpp 2010-09-17 04:15:33 +0000
522+++ mixxx/src/library/dao/trackdao.cpp 2010-10-19 05:33:52 +0000
523@@ -19,6 +19,18 @@
524
525 }
526
527+void TrackDAO::finish()
528+{
529+ //clear out played information on exit
530+ //crash prevention: if mixxx crashes, played information will be maintained
531+ qDebug() << "Clearing played information for this session";
532+ QSqlQuery query(m_database);
533+ if (!query.exec("UPDATE library SET played=0"))
534+ {
535+ qDebug() << "Error clearing played value";
536+ }
537+}
538+
539 TrackDAO::~TrackDAO()
540 {
541 }
542@@ -187,13 +199,15 @@
543
544 void TrackDAO::prepareLibraryInsert(QSqlQuery& query) {
545 query.prepare("INSERT INTO library (artist, title, album, year, genre, tracknumber, "
546- "filetype, location, comment, url, duration, "
547+ "filetype, location, comment, url, duration, rating, "
548 "bitrate, samplerate, cuepoint, bpm, wavesummaryhex, "
549+ "timesplayed, "
550 "channels, mixxx_deleted, header_parsed) "
551 "VALUES (:artist, "
552 ":title, :album, :year, :genre, :tracknumber, "
553- ":filetype, :location, :comment, :url, :duration, "
554+ ":filetype, :location, :comment, :url, :duration, :rating,"
555 ":bitrate, :samplerate, :cuepoint, :bpm, :wavesummaryhex, "
556+ ":timesplayed, "
557 ":channels, :mixxx_deleted, :header_parsed)");
558 }
559
560@@ -209,6 +223,7 @@
561 query.bindValue(":comment", pTrack->getComment());
562 query.bindValue(":url", pTrack->getURL());
563 query.bindValue(":duration", pTrack->getDuration());
564+ query.bindValue(":rating", pTrack->getRating());
565 query.bindValue(":bitrate", pTrack->getBitrate());
566 query.bindValue(":samplerate", pTrack->getSampleRate());
567 query.bindValue(":cuepoint", pTrack->getCuePoint());
568@@ -216,7 +231,7 @@
569 const QByteArray* pWaveSummary = pTrack->getWaveSummary();
570 if (pWaveSummary) //Avoid null pointer deref
571 query.bindValue(":wavesummaryhex", *pWaveSummary);
572- //query.bindValue(":timesplayed", pTrack->getCuePoint());
573+ query.bindValue(":timesplayed", pTrack->getTimesPlayed());
574 //query.bindValue(":datetime_added", pTrack->getDateAdded());
575 query.bindValue(":channels", pTrack->getChannels());
576 query.bindValue(":mixxx_deleted", 0);
577@@ -322,7 +337,7 @@
578 time.start();
579
580 //qDebug() << "TrackDAO::addTrack" << QThread::currentThread() << m_database.connectionName();
581- //qDebug() << "TrackCollection::addTrack(), inserting into DB";
582+ //qDebug() << "TrackCollection::addTrack(), inserting into DB";
583 Q_ASSERT(pTrack); //Why you be giving me NULL pTracks
584
585 //Start the transaction
586@@ -500,12 +515,14 @@
587 QString url = query.value(query.record().indexOf("url")).toString();
588 int duration = query.value(query.record().indexOf("duration")).toInt();
589 int bitrate = query.value(query.record().indexOf("bitrate")).toInt();
590+ int rating = query.value(query.record().indexOf("rating")).toInt();
591 int samplerate = query.value(query.record().indexOf("samplerate")).toInt();
592 int cuepoint = query.value(query.record().indexOf("cuepoint")).toInt();
593 QString bpm = query.value(query.record().indexOf("bpm")).toString();
594 QByteArray* wavesummaryhex = new QByteArray(
595 query.value(query.record().indexOf("wavesummaryhex")).toByteArray());
596- //int timesplayed = query.value(query.record().indexOf("timesplayed")).toInt();
597+ int timesplayed = query.value(query.record().indexOf("timesplayed")).toInt();
598+ int played = query.value(query.record().indexOf("played")).toInt();
599 int channels = query.value(query.record().indexOf("channels")).toInt();
600 int filesize = query.value(query.record().indexOf("filesize")).toInt();
601 QString filetype = query.value(query.record().indexOf("filetype")).toString();
602@@ -525,6 +542,7 @@
603 track->setYear(year);
604 track->setGenre(genre);
605 track->setTrackNumber(tracknumber);
606+ track->setRating(rating);
607
608 track->setComment(comment);
609 track->setURL(url);
610@@ -535,7 +553,8 @@
611 track->setBpm(bpm.toFloat());
612 track->setWaveSummary(wavesummaryhex, false);
613 delete wavesummaryhex;
614- //track->setTimesPlayed //Doesn't exist wtfbbq
615+ track->setTimesPlayed(timesplayed);
616+ track->setPlayed(played);
617 track->setChannels(channels);
618 track->setType(filetype);
619 track->setLocation(location);
620@@ -607,7 +626,8 @@
621 time.start();
622 QSqlQuery query(m_database);
623
624- query.prepare("SELECT library.id, artist, title, album, year, genre, tracknumber, filetype, track_locations.location as location, track_locations.filesize as filesize, comment, url, duration, bitrate, samplerate, cuepoint, bpm, wavesummaryhex, channels, header_parsed FROM Library INNER JOIN track_locations ON library.location = track_locations.id WHERE library.id=" + QString("%1").arg(id));
625+ query.prepare("SELECT library.id, artist, title, album, year, genre, tracknumber, filetype, rating, track_locations.location as location, track_locations.filesize as filesize, comment, url, duration, bitrate, samplerate, cuepoint, bpm, wavesummaryhex, channels, header_parsed, timesplayed, played FROM Library INNER JOIN track_locations ON library.location = track_locations.id WHERE library.id=" + QString("%1").arg(id));
626+
627 TrackPointer pTrack;
628
629 if (query.exec()) {
630@@ -641,9 +661,10 @@
631 "SET artist=:artist, "
632 "title=:title, album=:album, year=:year, genre=:genre, "
633 "filetype=:filetype, tracknumber=:tracknumber, "
634- "comment=:comment, url=:url, duration=:duration, "
635+ "comment=:comment, url=:url, duration=:duration, rating=:rating, "
636 "bitrate=:bitrate, samplerate=:samplerate, cuepoint=:cuepoint, "
637 "bpm=:bpm, wavesummaryhex=:wavesummaryhex, "
638+ "timesplayed=:timesplayed, played=:played, "
639 "channels=:channels, header_parsed=:header_parsed "
640 "WHERE id="+QString("%1").arg(trackId));
641 query.bindValue(":artist", pTrack->getArtist());
642@@ -660,10 +681,12 @@
643 query.bindValue(":samplerate", pTrack->getSampleRate());
644 query.bindValue(":cuepoint", pTrack->getCuePoint());
645 query.bindValue(":bpm", pTrack->getBpm());
646+ query.bindValue(":rating", pTrack->getRating());
647 const QByteArray* pWaveSummary = pTrack->getWaveSummary();
648 if (pWaveSummary) //Avoid null pointer deref
649 query.bindValue(":wavesummaryhex", *pWaveSummary);
650- //query.bindValue(":timesplayed", pTrack->getCuePoint());
651+ query.bindValue(":timesplayed", pTrack->getTimesPlayed());
652+ query.bindValue(":played", pTrack->getPlayed());
653 query.bindValue(":channels", pTrack->getChannels());
654 query.bindValue(":header_parsed", pTrack->getHeaderParsed() ? 1 : 0);
655 //query.bindValue(":location", pTrack->getLocation());
656
657=== modified file 'mixxx/src/library/dao/trackdao.h'
658--- mixxx/src/library/dao/trackdao.h 2010-09-13 06:23:38 +0000
659+++ mixxx/src/library/dao/trackdao.h 2010-10-19 05:33:52 +0000
660@@ -38,6 +38,9 @@
661 const QString LIBRARYTABLE_MIXXXDELETED = "mixxx_deleted";
662 const QString LIBRARYTABLE_DATETIMEADDED = "datetime_added";
663 const QString LIBRARYTABLE_HEADERPARSED = "header_parsed";
664+const QString LIBRARYTABLE_TIMESPLAYED = "timesplayed";
665+const QString LIBRARYTABLE_PLAYED = "played";
666+const QString LIBRARYTABLE_RATING = "rating";
667
668 const QString TRACKLOCATIONSTABLE_ID = "id";
669 const QString TRACKLOCATIONSTABLE_LOCATION = "location";
670@@ -52,6 +55,7 @@
671 public:
672 //TrackDAO() {};
673 TrackDAO(QSqlDatabase& database, CueDAO& cueDao);
674+ void finish();
675 virtual ~TrackDAO();
676 void setDatabase(QSqlDatabase& database) { m_database = database; };
677
678
679=== modified file 'mixxx/src/library/legacylibraryimporter.cpp'
680--- mixxx/src/library/legacylibraryimporter.cpp 2010-09-11 08:15:14 +0000
681+++ mixxx/src/library/legacylibraryimporter.cpp 2010-10-19 05:33:52 +0000
682@@ -174,9 +174,16 @@
683 }
684 }
685
686- //now change the file to mixxxtrack.bak so that its not readded next time program loads
687- file.copy(QDir::homePath().append("/").append(SETTINGS_PATH).append("mixxxtrack.bak"));
688- file.remove();
689+ QString upgrade_filename = QDir::homePath().append("/").append(SETTINGS_PATH).append("DBUPGRADED");
690+ //now create stub so that the library is not readded next time program loads
691+ QFile upgradefile(upgrade_filename);
692+ if (!upgradefile.open(QIODevice::WriteOnly | QIODevice::Text))
693+ qDebug() << "Couldn't open" << upgrade_filename << "for writing";
694+ else
695+ {
696+ file.write("",0);
697+ file.close();
698+ }
699 } else {
700 qDebug() << errorMsg << " line: " << errorLine << " column: " << errorColumn;
701 }
702
703=== modified file 'mixxx/src/library/libraryscanner.cpp'
704--- mixxx/src/library/libraryscanner.cpp 2010-09-18 19:30:15 +0000
705+++ mixxx/src/library/libraryscanner.cpp 2010-10-19 05:33:52 +0000
706@@ -55,10 +55,10 @@
707 */
708 QString iTunesArtFolder = "";
709 #if defined(__WINDOWS__)
710- iTunesArtFolder = QDesktopServices::storageLocation(QDesktopServices::MusicLocation) + "\\iTunes\\Album Artwork";
711- iTunesArtFolder.replace(QString("\\"), QString("/"));
712+ iTunesArtFolder = QDesktopServices::storageLocation(QDesktopServices::MusicLocation) + "\\iTunes\\Album Artwork";
713+ iTunesArtFolder.replace(QString("\\"), QString("/"));
714 #elif defined(__APPLE__)
715- iTunesArtFolder = QDesktopServices::storageLocation(QDesktopServices::MusicLocation) + "/iTunes/Album Artwork";
716+ iTunesArtFolder = QDesktopServices::storageLocation(QDesktopServices::MusicLocation) + "/iTunes/Album Artwork";
717 #endif
718 m_directoriesBlacklist << iTunesArtFolder;
719 qDebug() << "iTunes Album Art path is:" << iTunesArtFolder;
720@@ -109,7 +109,7 @@
721
722 //Print out any SQL error, if there was one.
723 if (query.lastError().isValid()) {
724- qDebug() << query.lastError();
725+ qDebug() << query.lastError();
726 }
727
728 QString dir;
729@@ -167,15 +167,25 @@
730
731 QTime t2;
732 t2.start();
733- //Try to upgrade the library from 1.7 (XML) to 1.8+ (DB) if needed
734- LegacyLibraryImporter libImport(m_trackDao, m_playlistDao);
735- connect(&libImport, SIGNAL(progress(QString)),
736- m_pProgress, SLOT(slotUpdate(QString)),
737- Qt::BlockingQueuedConnection);
738- m_database.transaction();
739- libImport.import();
740- m_database.commit();
741- qDebug("Legacy importer took %d ms", t2.elapsed());
742+
743+ //Try to upgrade the library from 1.7 (XML) to 1.8+ (DB) if needed. If the
744+ //upgrade_filename already exists, then do not try to upgrade since we have
745+ //already done it.
746+ QString upgrade_filename = QDir::homePath().append("/").append(SETTINGS_PATH).append("DBUPGRADED");
747+ qDebug() << "upgrade filename is " << upgrade_filename;
748+ QFile upgradefile(upgrade_filename);
749+ if (!upgradefile.exists())
750+ {
751+ LegacyLibraryImporter libImport(m_trackDao, m_playlistDao);
752+ connect(&libImport, SIGNAL(progress(QString)),
753+ m_pProgress, SLOT(slotUpdate(QString)),
754+ Qt::BlockingQueuedConnection);
755+ m_database.transaction();
756+ libImport.import();
757+ m_database.commit();
758+ qDebug("Legacy importer took %d ms", t2.elapsed());
759+
760+ }
761
762 //Refresh the name filters in case we loaded new
763 //SoundSource plugins.
764
765=== modified file 'mixxx/src/library/librarytablemodel.cpp'
766--- mixxx/src/library/librarytablemodel.cpp 2010-09-14 20:32:32 +0000
767+++ mixxx/src/library/librarytablemodel.cpp 2010-10-19 05:33:52 +0000
768@@ -20,11 +20,14 @@
769 query.prepare("CREATE TEMPORARY VIEW IF NOT EXISTS library_view AS "
770 "SELECT "
771 "library." + LIBRARYTABLE_ID + "," +
772+ "library." + LIBRARYTABLE_PLAYED + "," +
773+ "library." + LIBRARYTABLE_TIMESPLAYED + "," +
774 "library." + LIBRARYTABLE_ARTIST + "," +
775 "library." + LIBRARYTABLE_TITLE + "," +
776 "library." + LIBRARYTABLE_ALBUM + "," +
777 "library." + LIBRARYTABLE_YEAR + "," +
778 "library." + LIBRARYTABLE_DURATION + "," +
779+ "library." + LIBRARYTABLE_RATING + "," +
780 "library." + LIBRARYTABLE_GENRE + "," +
781 "library." + LIBRARYTABLE_FILETYPE + "," +
782 "library." + LIBRARYTABLE_TRACKNUMBER + "," +
783@@ -43,7 +46,7 @@
784
785 //Print out any SQL error, if there was one.
786 if (query.lastError().isValid()) {
787- qDebug() << __FILE__ << __LINE__ << query.lastError();
788+ qDebug() << __FILE__ << __LINE__ << query.lastError();
789 }
790
791 //setTable("library");
792@@ -56,34 +59,9 @@
793 //and shows it...
794 //setRelation(fieldIndex(LIBRARYTABLE_LOCATION), QSqlRelation("track_locations", "id", "location"));
795
796- //Set the column heading labels, rename them for translations and have
797- //proper capitalization
798- setHeaderData(fieldIndex(LIBRARYTABLE_ARTIST),
799- Qt::Horizontal, tr("Artist"));
800- setHeaderData(fieldIndex(LIBRARYTABLE_TITLE),
801- Qt::Horizontal, tr("Title"));
802- setHeaderData(fieldIndex(LIBRARYTABLE_ALBUM),
803- Qt::Horizontal, tr("Album"));
804- setHeaderData(fieldIndex(LIBRARYTABLE_GENRE),
805- Qt::Horizontal, tr("Genre"));
806- setHeaderData(fieldIndex(LIBRARYTABLE_YEAR),
807- Qt::Horizontal, tr("Year"));
808- setHeaderData(fieldIndex(LIBRARYTABLE_FILETYPE),
809- Qt::Horizontal, tr("Type"));
810- setHeaderData(fieldIndex(LIBRARYTABLE_LOCATION),
811- Qt::Horizontal, tr("Location"));
812- setHeaderData(fieldIndex(LIBRARYTABLE_COMMENT),
813- Qt::Horizontal, tr("Comment"));
814- setHeaderData(fieldIndex(LIBRARYTABLE_DURATION),
815- Qt::Horizontal, tr("Duration"));
816- setHeaderData(fieldIndex(LIBRARYTABLE_BITRATE),
817- Qt::Horizontal, tr("Bitrate"));
818- setHeaderData(fieldIndex(LIBRARYTABLE_BPM),
819- Qt::Horizontal, tr("BPM"));
820- setHeaderData(fieldIndex(LIBRARYTABLE_TRACKNUMBER),
821- Qt::Horizontal, tr("Track #"));
822- setHeaderData(fieldIndex(LIBRARYTABLE_DATETIMEADDED),
823- Qt::Horizontal, tr("Date Added"));
824+
825+ // BaseSqlTabelModel will setup the header info
826+ initHeaderData();
827
828 //Sets up the table filter so that we don't show "deleted" tracks (only show mixxx_deleted=0).
829 slotSearch("");
830@@ -126,15 +104,15 @@
831
832 TrackPointer LibraryTableModel::getTrack(const QModelIndex& index) const
833 {
834- int trackId = index.sibling(index.row(), fieldIndex(LIBRARYTABLE_ID)).data().toInt();
835- return m_trackDao.getTrack(trackId);
836+ int trackId = index.sibling(index.row(), fieldIndex(LIBRARYTABLE_ID)).data().toInt();
837+ return m_trackDao.getTrack(trackId);
838 }
839
840 QString LibraryTableModel::getTrackLocation(const QModelIndex& index) const
841 {
842- const int locationColumnIndex = fieldIndex(LIBRARYTABLE_LOCATION);
843- QString location = index.sibling(index.row(), locationColumnIndex).data().toString();
844- return location;
845+ const int locationColumnIndex = fieldIndex(LIBRARYTABLE_LOCATION);
846+ QString location = index.sibling(index.row(), locationColumnIndex).data().toString();
847+ return location;
848 }
849
850 void LibraryTableModel::removeTracks(const QModelIndexList& indices) {
851@@ -152,9 +130,9 @@
852
853 void LibraryTableModel::removeTrack(const QModelIndex& index)
854 {
855- int trackId = index.sibling(index.row(), fieldIndex(LIBRARYTABLE_ID)).data().toInt();
856- m_trackDao.removeTrack(trackId);
857- select(); //Repopulate the data model.
858+ int trackId = index.sibling(index.row(), fieldIndex(LIBRARYTABLE_ID)).data().toInt();
859+ m_trackDao.removeTrack(trackId);
860+ select(); //Repopulate the data model.
861 }
862
863 void LibraryTableModel::moveTrack(const QModelIndex& sourceIndex, const QModelIndex& destIndex)
864@@ -181,12 +159,21 @@
865 filter = "(" + LibraryTableModel::DEFAULT_LIBRARYFILTER + ")";
866 else {
867 QSqlField search("search", QVariant::String);
868- search.setValue("%" + searchText + "%");
869- QString escapedText = database().driver()->formatValue(search);
870- filter = "(" + LibraryTableModel::DEFAULT_LIBRARYFILTER + " AND " +
871- "(artist LIKE " + escapedText + " OR " +
872- "album LIKE " + escapedText + " OR " +
873- "title LIKE " + escapedText + "))";
874+
875+ filter = "(" + LibraryTableModel::DEFAULT_LIBRARYFILTER;
876+
877+ foreach(QString term, searchText.split(" "))
878+ {
879+ search.setValue("%" + term + "%");
880+ QString escapedText = database().driver()->formatValue(search);
881+ filter += " AND (artist LIKE " + escapedText + " OR " +
882+ "album LIKE " + escapedText + " OR " +
883+ "location LIKE " + escapedText + " OR " +
884+ "comment LIKE " + escapedText + " OR " +
885+ "title LIKE " + escapedText + ")";
886+ }
887+
888+ filter += ")";
889 }
890 setFilter(filter);
891 }
892@@ -205,6 +192,7 @@
893 (column == fieldIndex(LIBRARYTABLE_SAMPLERATE)) ||
894 (column == fieldIndex(LIBRARYTABLE_MIXXXDELETED)) ||
895 (column == fieldIndex(LIBRARYTABLE_HEADERPARSED)) ||
896+ (column == fieldIndex(LIBRARYTABLE_PLAYED)) ||
897 (column == fieldIndex(LIBRARYTABLE_CHANNELS)) ||
898 (column == fieldIndex(TRACKLOCATIONSTABLE_FSDELETED))) {
899 return true;
900@@ -216,26 +204,6 @@
901 return NULL;
902 }
903
904-QVariant LibraryTableModel::data(const QModelIndex& item, int role) const {
905- if (!item.isValid())
906- return QVariant();
907-
908- QVariant value;
909- if (role == Qt::ToolTipRole)
910- value = BaseSqlTableModel::data(item, Qt::DisplayRole);
911- else
912- value = BaseSqlTableModel::data(item, role);
913-
914- if ((role == Qt::DisplayRole || role == Qt::ToolTipRole) &&
915- item.column() == fieldIndex(LIBRARYTABLE_DURATION)) {
916- if (qVariantCanConvert<int>(value)) {
917- value = MixxxUtils::secondsToMinutes(qVariantValue<int>(value));
918- }
919- }
920-
921- return value;
922-}
923-
924 QMimeData* LibraryTableModel::mimeData(const QModelIndexList &indexes) const {
925 QMimeData *mimeData = new QMimeData();
926 QList<QUrl> urls;
927@@ -263,26 +231,6 @@
928 return mimeData;
929 }
930
931-Qt::ItemFlags LibraryTableModel::flags(const QModelIndex &index) const
932-{
933- Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index);
934- if (!index.isValid())
935- return Qt::ItemIsEnabled;
936-
937- //Enable dragging songs from this data model to elsewhere (like the waveform
938- //widget to load a track into a Player).
939- defaultFlags |= Qt::ItemIsDragEnabled;
940-
941- /** FIXME: This doesn't seem to work - Albert */
942- const int bpmColumnIndex = fieldIndex(LIBRARYTABLE_BPM);
943- if (index.column() == bpmColumnIndex)
944- {
945- return defaultFlags | Qt::ItemIsEditable;
946- }
947-
948- return defaultFlags;
949-}
950-
951 TrackModel::CapabilitiesFlags LibraryTableModel::getCapabilities() const
952 {
953 return TRACKMODELCAPS_RECEIVEDROPS | TRACKMODELCAPS_ADDTOPLAYLIST |
954
955=== modified file 'mixxx/src/library/librarytablemodel.h'
956--- mixxx/src/library/librarytablemodel.h 2010-09-13 06:23:38 +0000
957+++ mixxx/src/library/librarytablemodel.h 2010-10-19 05:33:52 +0000
958@@ -27,11 +27,9 @@
959 virtual bool addTrack(const QModelIndex& index, QString location);
960 virtual void moveTrack(const QModelIndex& sourceIndex,
961 const QModelIndex& destIndex);
962- virtual QVariant data(const QModelIndex& item, int role) const;
963
964
965 QMimeData* mimeData(const QModelIndexList &indexes) const;
966- Qt::ItemFlags flags(const QModelIndex &index) const;
967 QItemDelegate* delegateForColumn(const int i);
968 TrackModel::CapabilitiesFlags getCapabilities() const;
969 static const QString DEFAULT_LIBRARYFILTER;
970
971=== modified file 'mixxx/src/library/missingtablemodel.cpp'
972--- mixxx/src/library/missingtablemodel.cpp 2010-09-14 20:32:32 +0000
973+++ mixxx/src/library/missingtablemodel.cpp 2010-10-19 05:33:52 +0000
974@@ -25,11 +25,14 @@
975 query.prepare("CREATE TEMPORARY VIEW IF NOT EXISTS " + tableName + " AS "
976 "SELECT " +
977 "library." + LIBRARYTABLE_ID + "," +
978+ "library." + LIBRARYTABLE_PLAYED + "," +
979+ "library." + LIBRARYTABLE_TIMESPLAYED + "," +
980 "library." + LIBRARYTABLE_ARTIST + "," +
981 "library." + LIBRARYTABLE_TITLE + "," +
982 "library." + LIBRARYTABLE_ALBUM + "," +
983 "library." + LIBRARYTABLE_YEAR + "," +
984 "library." + LIBRARYTABLE_DURATION + "," +
985+ "library." + LIBRARYTABLE_RATING + "," +
986 "library." + LIBRARYTABLE_GENRE + "," +
987 "library." + LIBRARYTABLE_FILETYPE + "," +
988 "library." + LIBRARYTABLE_TRACKNUMBER + "," +
989@@ -58,36 +61,7 @@
990
991 qDebug() << "Created MissingTracksModel!";
992
993- //Set the column heading labels, rename them for translations and have
994- //proper capitalization
995- setHeaderData(fieldIndex("track_locations.location"),
996- Qt::Horizontal, tr("Location"));
997- setHeaderData(fieldIndex(LIBRARYTABLE_ARTIST),
998- Qt::Horizontal, tr("Artist"));
999- setHeaderData(fieldIndex(LIBRARYTABLE_TITLE),
1000- Qt::Horizontal, tr("Title"));
1001- setHeaderData(fieldIndex(LIBRARYTABLE_ALBUM),
1002- Qt::Horizontal, tr("Album"));
1003- setHeaderData(fieldIndex(LIBRARYTABLE_GENRE),
1004- Qt::Horizontal, tr("Genre"));
1005- setHeaderData(fieldIndex(LIBRARYTABLE_YEAR),
1006- Qt::Horizontal, tr("Year"));
1007- setHeaderData(fieldIndex(LIBRARYTABLE_FILETYPE),
1008- Qt::Horizontal, tr("Type"));
1009- setHeaderData(fieldIndex(LIBRARYTABLE_LOCATION),
1010- Qt::Horizontal, tr("Location"));
1011- setHeaderData(fieldIndex(LIBRARYTABLE_COMMENT),
1012- Qt::Horizontal, tr("Comment"));
1013- setHeaderData(fieldIndex(LIBRARYTABLE_DURATION),
1014- Qt::Horizontal, tr("Duration"));
1015- setHeaderData(fieldIndex(LIBRARYTABLE_TRACKNUMBER),
1016- Qt::Horizontal, tr("Track #"));
1017- setHeaderData(fieldIndex(LIBRARYTABLE_BITRATE),
1018- Qt::Horizontal, tr("Bitrate"));
1019- setHeaderData(fieldIndex(LIBRARYTABLE_BPM),
1020- Qt::Horizontal, tr("BPM"));
1021- setHeaderData(fieldIndex(LIBRARYTABLE_DATETIMEADDED),
1022- Qt::Horizontal, tr("Date Added"));
1023+ initHeaderData(); //derived from BaseSqlModel
1024
1025 slotSearch("");
1026
1027@@ -168,6 +142,7 @@
1028
1029 bool MissingTableModel::isColumnInternal(int column) {
1030 if (column == fieldIndex(LIBRARYTABLE_ID) ||
1031+ column == fieldIndex(LIBRARYTABLE_PLAYED) ||
1032 column == fieldIndex(LIBRARYTABLE_MIXXXDELETED) ||
1033 column == fieldIndex(TRACKLOCATIONSTABLE_FSDELETED))
1034 return true;
1035@@ -200,42 +175,16 @@
1036 return mimeData;
1037 }
1038
1039+/** Override flags from BaseSqlModel since we don't want edit this model */
1040 Qt::ItemFlags MissingTableModel::flags(const QModelIndex &index) const
1041 {
1042- Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index);
1043- if (!index.isValid())
1044- return Qt::ItemIsEnabled;
1045-
1046- //defaultFlags |= Qt::ItemIsDragEnabled;
1047- //defaultFlags = 0;
1048-
1049- return defaultFlags;
1050+ return readOnlyFlags(index);
1051 }
1052
1053 QItemDelegate* MissingTableModel::delegateForColumn(const int i) {
1054 return NULL;
1055 }
1056
1057-QVariant MissingTableModel::data(const QModelIndex& item, int role) const {
1058- if (!item.isValid())
1059- return QVariant();
1060-
1061- QVariant value;
1062-
1063- if (role == Qt::ToolTipRole)
1064- value = BaseSqlTableModel::data(item, Qt::DisplayRole);
1065- else
1066- value = BaseSqlTableModel::data(item, role);
1067-
1068- if ((role == Qt::DisplayRole || role == Qt::ToolTipRole) &&
1069- item.column() == fieldIndex(LIBRARYTABLE_DURATION)) {
1070- if (qVariantCanConvert<int>(value)) {
1071- value = MixxxUtils::secondsToMinutes(qVariantValue<int>(value));
1072- }
1073- }
1074- return value;
1075-}
1076-
1077 TrackModel::CapabilitiesFlags MissingTableModel::getCapabilities() const
1078 {
1079 return 0;
1080
1081=== modified file 'mixxx/src/library/missingtablemodel.h'
1082--- mixxx/src/library/missingtablemodel.h 2010-09-13 06:23:38 +0000
1083+++ mixxx/src/library/missingtablemodel.h 2010-10-19 05:33:52 +0000
1084@@ -26,7 +26,7 @@
1085 virtual void removeTracks(const QModelIndexList& indices);
1086 virtual bool addTrack(const QModelIndex& index, QString location);
1087 virtual void moveTrack(const QModelIndex& sourceIndex, const QModelIndex& destIndex);
1088- virtual QVariant data(const QModelIndex& item, int role) const;
1089+
1090 QMimeData* mimeData(const QModelIndexList &indexes) const;
1091 Qt::ItemFlags flags(const QModelIndex &index) const;
1092 QItemDelegate* delegateForColumn(const int i);
1093
1094=== modified file 'mixxx/src/library/playlisttablemodel.cpp'
1095--- mixxx/src/library/playlisttablemodel.cpp 2010-09-14 20:32:32 +0000
1096+++ mixxx/src/library/playlisttablemodel.cpp 2010-10-19 05:33:52 +0000
1097@@ -44,11 +44,14 @@
1098 "PlaylistTracks." + PLAYLISTTRACKSTABLE_POSITION + "," +
1099 //"playlist_id, " + //DEBUG
1100 "library." + LIBRARYTABLE_ID + "," +
1101+ "library." + LIBRARYTABLE_PLAYED + "," +
1102+ "library." + LIBRARYTABLE_TIMESPLAYED + "," +
1103 "library." + LIBRARYTABLE_ARTIST + "," +
1104 "library." + LIBRARYTABLE_TITLE + "," +
1105 "library." + LIBRARYTABLE_ALBUM + "," +
1106 "library." + LIBRARYTABLE_YEAR + "," +
1107 "library." + LIBRARYTABLE_DURATION + "," +
1108+ "library." + LIBRARYTABLE_RATING + "," +
1109 "library." + LIBRARYTABLE_GENRE + "," +
1110 "library." + LIBRARYTABLE_FILETYPE + "," +
1111 "library." + LIBRARYTABLE_TRACKNUMBER + "," +
1112@@ -79,36 +82,7 @@
1113
1114 setTable(playlistTableName);
1115
1116- //Set the column heading labels, rename them for translations and have
1117- //proper capitalization
1118- setHeaderData(fieldIndex(PLAYLISTTRACKSTABLE_POSITION),
1119- Qt::Horizontal, tr("#"));
1120- setHeaderData(fieldIndex(LIBRARYTABLE_ARTIST),
1121- Qt::Horizontal, tr("Artist"));
1122- setHeaderData(fieldIndex(LIBRARYTABLE_TITLE),
1123- Qt::Horizontal, tr("Title"));
1124- setHeaderData(fieldIndex(LIBRARYTABLE_ALBUM),
1125- Qt::Horizontal, tr("Album"));
1126- setHeaderData(fieldIndex(LIBRARYTABLE_GENRE),
1127- Qt::Horizontal, tr("Genre"));
1128- setHeaderData(fieldIndex(LIBRARYTABLE_YEAR),
1129- Qt::Horizontal, tr("Year"));
1130- setHeaderData(fieldIndex(LIBRARYTABLE_FILETYPE),
1131- Qt::Horizontal, tr("Type"));
1132- setHeaderData(fieldIndex("location"),
1133- Qt::Horizontal, tr("Location"));
1134- setHeaderData(fieldIndex(LIBRARYTABLE_COMMENT),
1135- Qt::Horizontal, tr("Comment"));
1136- setHeaderData(fieldIndex(LIBRARYTABLE_DURATION),
1137- Qt::Horizontal, tr("Duration"));
1138- setHeaderData(fieldIndex(LIBRARYTABLE_TRACKNUMBER),
1139- Qt::Horizontal, tr("Track #"));
1140- setHeaderData(fieldIndex(LIBRARYTABLE_BITRATE),
1141- Qt::Horizontal, tr("Bitrate"));
1142- setHeaderData(fieldIndex(LIBRARYTABLE_DATETIMEADDED),
1143- Qt::Horizontal, tr("Date Added"));
1144- setHeaderData(fieldIndex(LIBRARYTABLE_BPM),
1145- Qt::Horizontal, tr("BPM"));
1146+ initHeaderData(); //derived from BaseSqlModel
1147
1148 slotSearch("");
1149
1150@@ -323,6 +297,7 @@
1151
1152 bool PlaylistTableModel::isColumnInternal(int column) {
1153 if (column == fieldIndex(LIBRARYTABLE_ID) ||
1154+ column == fieldIndex(LIBRARYTABLE_PLAYED) ||
1155 column == fieldIndex(LIBRARYTABLE_MIXXXDELETED) ||
1156 column == fieldIndex(TRACKLOCATIONSTABLE_FSDELETED))
1157 return true;
1158@@ -354,43 +329,11 @@
1159 return mimeData;
1160 }
1161
1162-Qt::ItemFlags PlaylistTableModel::flags(const QModelIndex &index) const
1163-{
1164- Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index);
1165- if (!index.isValid())
1166- return Qt::ItemIsEnabled;
1167-
1168- //Enable dragging songs from this data model to elsewhere (like the waveform widget to
1169- //load a track into a Player).
1170- defaultFlags |= Qt::ItemIsDragEnabled;
1171-
1172- return defaultFlags;
1173-}
1174
1175 QItemDelegate* PlaylistTableModel::delegateForColumn(const int i) {
1176 return NULL;
1177 }
1178
1179-QVariant PlaylistTableModel::data(const QModelIndex& item, int role) const {
1180- if (!item.isValid())
1181- return QVariant();
1182-
1183- QVariant value;
1184-
1185- if (role == Qt::ToolTipRole)
1186- value = BaseSqlTableModel::data(item, Qt::DisplayRole);
1187- else
1188- value = BaseSqlTableModel::data(item, role);
1189-
1190- if ((role == Qt::DisplayRole || role == Qt::ToolTipRole) &&
1191- item.column() == fieldIndex(LIBRARYTABLE_DURATION)) {
1192- if (qVariantCanConvert<int>(value)) {
1193- value = MixxxUtils::secondsToMinutes(qVariantValue<int>(value));
1194- }
1195- }
1196- return value;
1197-}
1198-
1199 TrackModel::CapabilitiesFlags PlaylistTableModel::getCapabilities() const
1200 {
1201 TrackModel::CapabilitiesFlags caps = TRACKMODELCAPS_RECEIVEDROPS | TRACKMODELCAPS_REORDER | TRACKMODELCAPS_ADDTOCRATE | TRACKMODELCAPS_ADDTOPLAYLIST;
1202
1203=== added file 'mixxx/src/library/playlisttablemodel.h'
1204--- mixxx/src/library/playlisttablemodel.h 1970-01-01 00:00:00 +0000
1205+++ mixxx/src/library/playlisttablemodel.h 2010-10-19 05:33:52 +0000
1206@@ -0,0 +1,51 @@
1207+#ifndef PLAYLISTTABLEMODEL_H
1208+#define PLAYLISTTABLEMODEL_H
1209+
1210+#include <QtSql>
1211+#include <QItemDelegate>
1212+#include <QtCore>
1213+#include "trackmodel.h"
1214+#include "library/basesqltablemodel.h"
1215+#include "library/librarytablemodel.h"
1216+#include "library/dao/playlistdao.h"
1217+#include "library/dao/trackdao.h"
1218+
1219+class TrackCollection;
1220+
1221+class PlaylistTableModel : public BaseSqlTableModel, public virtual TrackModel
1222+{
1223+ Q_OBJECT
1224+ public:
1225+ PlaylistTableModel(QObject* parent, TrackCollection* pTrackCollection);
1226+ virtual ~PlaylistTableModel();
1227+ void setPlaylist(int playlistId);
1228+ virtual TrackPointer getTrack(const QModelIndex& index) const;
1229+ virtual QString getTrackLocation(const QModelIndex& index) const;
1230+ virtual void search(const QString& searchText);
1231+ virtual const QString currentSearch();
1232+ virtual bool isColumnInternal(int column);
1233+ virtual void removeTrack(const QModelIndex& index);
1234+ virtual void removeTracks(const QModelIndexList& indices);
1235+ virtual bool addTrack(const QModelIndex& index, QString location);
1236+ virtual void moveTrack(const QModelIndex& sourceIndex, const QModelIndex& destIndex);
1237+
1238+ QMimeData* mimeData(const QModelIndexList &indexes) const;
1239+
1240+ QItemDelegate* delegateForColumn(const int i);
1241+ TrackModel::CapabilitiesFlags getCapabilities() const;
1242+
1243+ private slots:
1244+ void slotSearch(const QString& searchText);
1245+
1246+ signals:
1247+ void doSearch(const QString& searchText);
1248+
1249+ private:
1250+ TrackCollection* m_pTrackCollection;
1251+ PlaylistDAO& m_playlistDao;
1252+ TrackDAO& m_trackDao;
1253+ int m_iPlaylistId;
1254+ QString m_currentSearch;
1255+};
1256+
1257+#endif
1258
1259=== removed file 'mixxx/src/library/playlisttablemodel.h'
1260--- mixxx/src/library/playlisttablemodel.h 2010-09-13 06:23:38 +0000
1261+++ mixxx/src/library/playlisttablemodel.h 1970-01-01 00:00:00 +0000
1262@@ -1,51 +0,0 @@
1263-#ifndef PLAYLISTTABLEMODEL_H
1264-#define PLAYLISTTABLEMODEL_H
1265-
1266-#include <QtSql>
1267-#include <QItemDelegate>
1268-#include <QtCore>
1269-#include "trackmodel.h"
1270-#include "library/basesqltablemodel.h"
1271-#include "library/librarytablemodel.h"
1272-#include "library/dao/playlistdao.h"
1273-#include "library/dao/trackdao.h"
1274-
1275-class TrackCollection;
1276-
1277-class PlaylistTableModel : public BaseSqlTableModel, public virtual TrackModel
1278-{
1279- Q_OBJECT
1280- public:
1281- PlaylistTableModel(QObject* parent, TrackCollection* pTrackCollection);
1282- virtual ~PlaylistTableModel();
1283- void setPlaylist(int playlistId);
1284- virtual TrackPointer getTrack(const QModelIndex& index) const;
1285- virtual QString getTrackLocation(const QModelIndex& index) const;
1286- virtual void search(const QString& searchText);
1287- virtual const QString currentSearch();
1288- virtual bool isColumnInternal(int column);
1289- virtual void removeTrack(const QModelIndex& index);
1290- virtual void removeTracks(const QModelIndexList& indices);
1291- virtual bool addTrack(const QModelIndex& index, QString location);
1292- virtual void moveTrack(const QModelIndex& sourceIndex, const QModelIndex& destIndex);
1293- virtual QVariant data(const QModelIndex& item, int role) const;
1294- QMimeData* mimeData(const QModelIndexList &indexes) const;
1295- Qt::ItemFlags flags(const QModelIndex &index) const;
1296- QItemDelegate* delegateForColumn(const int i);
1297- TrackModel::CapabilitiesFlags getCapabilities() const;
1298-
1299- private slots:
1300- void slotSearch(const QString& searchText);
1301-
1302- signals:
1303- void doSearch(const QString& searchText);
1304-
1305- private:
1306- TrackCollection* m_pTrackCollection;
1307- PlaylistDAO& m_playlistDao;
1308- TrackDAO& m_trackDao;
1309- int m_iPlaylistId;
1310- QString m_currentSearch;
1311-};
1312-
1313-#endif
1314
1315=== modified file 'mixxx/src/library/rhythmboxtrackmodel.cpp'
1316--- mixxx/src/library/rhythmboxtrackmodel.cpp 2010-10-15 21:17:06 +0000
1317+++ mixxx/src/library/rhythmboxtrackmodel.cpp 2010-10-19 05:33:52 +0000
1318@@ -160,6 +160,9 @@
1319 pTrack->setGenre(songNode.firstChildElement("genre").text());
1320 pTrack->setDuration(songNode.firstChildElement("duration").text().toUInt());
1321
1322+ // TODO(ywwg) why was this added? constructor above does the same -- rryan
1323+ pTrack->setLocation(trackLocation);
1324+
1325 // Have QObject handle deleting this track
1326 return TrackPointer(pTrack, &QObject::deleteLater);
1327 }
1328
1329=== added file 'mixxx/src/library/stardelegate.cpp'
1330--- mixxx/src/library/stardelegate.cpp 1970-01-01 00:00:00 +0000
1331+++ mixxx/src/library/stardelegate.cpp 2010-10-19 05:33:52 +0000
1332@@ -0,0 +1,114 @@
1333+/***************************************************************************
1334+ stardelegate.cpp
1335+ -------------------
1336+ copyright : (C) 2010 Tobias Rafreider
1337+ copyright : (C) 2009 Nokia Corporation
1338+
1339+***************************************************************************/
1340+
1341+/***************************************************************************
1342+ * *
1343+ * This program is free software; you can redistribute it and/or modify *
1344+ * it under the terms of the GNU General Public License as published by *
1345+ * the Free Software Foundation; either version 2 of the License, or *
1346+ * (at your option) any later version. *
1347+ * *
1348+ ***************************************************************************/
1349+
1350+
1351+#include <QtDebug>
1352+#include <QtGui>
1353+
1354+#include "stardelegate.h"
1355+#include "stareditor.h"
1356+#include "starrating.h"
1357+
1358+/*
1359+ * The function is invoked once for each item, represented by a QModelIndex object from the model.
1360+ * If the data stored in the item is a StarRating, we paint it use a star editor for displaying;
1361+ * otherwise, we let QItemDelegate paint it for us.
1362+ * This ensures that the StarDelegate can handle the most common data types.
1363+ */
1364+void StarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
1365+{
1366+ // Populate the correct colors based on the styling
1367+ QStyleOptionViewItem newOption = option;
1368+ initStyleOption(&newOption, index);
1369+
1370+ // Set the palette appropriately based on whether the row is selected or not
1371+ if (newOption.state & QStyle::State_Selected) {
1372+ painter->fillRect(newOption.rect, newOption.palette.highlight());
1373+ painter->setBrush(newOption.palette.highlightedText());
1374+ } else {
1375+ painter->fillRect(newOption.rect, newOption.palette.base());
1376+ painter->setBrush(newOption.palette.text());
1377+ }
1378+
1379+ if (qVariantCanConvert<StarRating>(index.data())) {
1380+ StarRating starRating = qVariantValue<StarRating>(index.data());
1381+ starRating.paint(painter, newOption.rect, newOption.palette, StarRating::ReadOnly);
1382+ } else {
1383+ QStyledItemDelegate::paint(painter, newOption, index);
1384+ }
1385+}
1386+
1387+QSize StarDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
1388+{
1389+ if (qVariantCanConvert<StarRating>(index.data())) {
1390+ StarRating starRating = qVariantValue<StarRating>(index.data());
1391+ return starRating.sizeHint();
1392+ } else {
1393+ return QStyledItemDelegate::sizeHint(option, index);
1394+ }
1395+}
1396+/*
1397+ * If the item is a StarRating, we create a StarEditor and connect
1398+ * its editingFinished() signal to our commitAndCloseEditor() slot,
1399+ * so we can update the model when the editor closes.
1400+ */
1401+QWidget *StarDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,const QModelIndex &index) const
1402+{
1403+ // Populate the correct colors based on the styling
1404+ QStyleOptionViewItem newOption = option;
1405+ initStyleOption(&newOption, index);
1406+
1407+ if (qVariantCanConvert<StarRating>(index.data())) {
1408+ StarEditor *editor = new StarEditor(parent, newOption);
1409+ connect(editor, SIGNAL(editingFinished()),
1410+ this, SLOT(commitAndCloseEditor()));
1411+ return editor;
1412+ } else {
1413+ return QStyledItemDelegate::createEditor(parent, newOption, index);
1414+ }
1415+}
1416+
1417+void StarDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
1418+{
1419+ if (qVariantCanConvert<StarRating>(index.data())) {
1420+ StarRating starRating = qVariantValue<StarRating>(index.data());
1421+ StarEditor *starEditor = qobject_cast<StarEditor *>(editor);
1422+ starEditor->setStarRating(starRating);
1423+ } else {
1424+ QStyledItemDelegate::setEditorData(editor, index);
1425+ }
1426+}
1427+
1428+void StarDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
1429+{
1430+ if (qVariantCanConvert<StarRating>(index.data())) {
1431+ StarEditor *starEditor = qobject_cast<StarEditor *>(editor);
1432+ model->setData(index, qVariantFromValue(starEditor->starRating()));
1433+ } else {
1434+ QStyledItemDelegate::setModelData(editor, model, index);
1435+ }
1436+}
1437+/*
1438+ * When the user is done editing, we emit commitData() and closeEditor() (both declared in QAbstractItemDelegate),
1439+ * to tell the model that there is edited data and to inform the view that the editor is no longer needed.
1440+ */
1441+void StarDelegate::commitAndCloseEditor()
1442+{
1443+ StarEditor *editor = qobject_cast<StarEditor *>(sender());
1444+ emit commitData(editor);
1445+ emit closeEditor(editor);
1446+}
1447
1448=== added file 'mixxx/src/library/stardelegate.h'
1449--- mixxx/src/library/stardelegate.h 1970-01-01 00:00:00 +0000
1450+++ mixxx/src/library/stardelegate.h 2010-10-19 05:33:52 +0000
1451@@ -0,0 +1,56 @@
1452+/***************************************************************************
1453+ stardelegate.h
1454+ -------------------
1455+ copyright : (C) 2010 Tobias Rafreider
1456+ copyright : (C) 2009 Nokia Corporation
1457+
1458+***************************************************************************/
1459+
1460+/***************************************************************************
1461+ * *
1462+ * This program is free software; you can redistribute it and/or modify *
1463+ * it under the terms of the GNU General Public License as published by *
1464+ * the Free Software Foundation; either version 2 of the License, or *
1465+ * (at your option) any later version. *
1466+ * *
1467+ ***************************************************************************/
1468+
1469+
1470+#ifndef STARDELEGATE_H
1471+#define STARDELEGATE_H
1472+
1473+#include <QStyledItemDelegate>
1474+
1475+/*
1476+ * When displaying data in a QListView, QTableView, or QTreeView,
1477+ * the individual items are drawn by a delegate.
1478+ * Also, when the user starts editing an item (e.g., by double-clicking the item),
1479+ * the delegate provides an editor widget that is placed on top of the item while editing takes place.
1480+ *
1481+ * By default a QListView, QTableView, or QTreeView has a QItemDelegate attached,
1482+ * which inherits QAbstractItemDelegate and handles the most common data types (notably int and QString).
1483+ * If we need to support custom data types, or want to customize the rendering or the editing for
1484+ * existing data types, we can subclass QAbstractItemDelegate or QItemDelegate or QStyledItemDelegate
1485+ */
1486+class StarDelegate : public QStyledItemDelegate
1487+{
1488+ Q_OBJECT
1489+
1490+public:
1491+ StarDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent) {}
1492+ /** reimplemented from QItemDelegate and is called whenever the view needs to repaint an item **/
1493+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
1494+ /** eturns an item's preferred size **/
1495+ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
1496+ /** called when the user starts editing an item: **/
1497+ QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,const QModelIndex &index) const;
1498+ /** called when an editor is created to initialize it with data from the model: **/
1499+ void setEditorData(QWidget *editor, const QModelIndex &index) const;
1500+ /** called when editing is finished, to commit data from the editor to the model: **/
1501+ void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
1502+
1503+private slots:
1504+ void commitAndCloseEditor();
1505+};
1506+
1507+#endif
1508
1509=== added file 'mixxx/src/library/stareditor.cpp'
1510--- mixxx/src/library/stareditor.cpp 1970-01-01 00:00:00 +0000
1511+++ mixxx/src/library/stareditor.cpp 2010-10-19 05:33:52 +0000
1512@@ -0,0 +1,95 @@
1513+/***************************************************************************
1514+ stareditor.cpp
1515+ -------------------
1516+ copyright : (C) 2010 Tobias Rafreider
1517+ copyright : (C) 2009 Nokia Corporation
1518+
1519+***************************************************************************/
1520+
1521+/***************************************************************************
1522+ * *
1523+ * This program is free software; you can redistribute it and/or modify *
1524+ * it under the terms of the GNU General Public License as published by *
1525+ * the Free Software Foundation; either version 2 of the License, or *
1526+ * (at your option) any later version. *
1527+ * *
1528+ ***************************************************************************/
1529+
1530+/***************************************************************************
1531+ * *
1532+ * StarEditor inherits QWidget and is used by StarDelegate to let the user *
1533+ * edit a star rating in the library using the mouse. *
1534+ * *
1535+ * The class has been adapted from the official "Star Delegate Example", *
1536+ * see http://doc.trolltech.com/4.5/itemviews-stardelegate.html *
1537+ ***************************************************************************/
1538+
1539+ #include <QtGui>
1540+
1541+ #include "stareditor.h"
1542+ #include "starrating.h"
1543+
1544+/*
1545+ * We enable mouse tracking on the widget so we can follow the cursor even
1546+ * when the user doesn't hold down any mouse button. We also turn on
1547+ * QWidget's auto-fill background feature to obtain an opaque background.
1548+ * (Without the call, the view's background would shine through the editor.)
1549+ */
1550+StarEditor::StarEditor(QWidget *parent, const QStyleOptionViewItem &option)
1551+ : QWidget(parent)
1552+{
1553+ setPalette(option.palette);
1554+ setMouseTracking(true);
1555+ setAutoFillBackground(true);
1556+}
1557+
1558+QSize StarEditor::sizeHint() const
1559+ {
1560+ return m_starRating.sizeHint();
1561+ }
1562+/*
1563+ * We simply call StarRating::paint() to draw the stars,
1564+ * just like we did when implementing StarDelegate
1565+ */
1566+void StarEditor::paintEvent(QPaintEvent *)
1567+ {
1568+ QPainter painter(this);
1569+ m_starRating.paint(&painter, rect(), palette(), StarRating::Editable);
1570+ }
1571+/*
1572+ * In the mouse event handler, we call setStarCount() on
1573+ * the private data member m_starRating to reflect the current cursor position,
1574+ * and we call QWidget::update() to force a repaint.
1575+ */
1576+ void StarEditor::mouseMoveEvent(QMouseEvent *event)
1577+ {
1578+ int star = starAtPosition(event->x());
1579+
1580+ if (star != m_starRating.starCount() && star != -1) {
1581+ m_starRating.setStarCount(star);
1582+ update();
1583+ }
1584+ }
1585+/*
1586+ * When the user releases a mouse button, we simply emit the editingFinished() signal.
1587+ */
1588+ void StarEditor::mouseReleaseEvent(QMouseEvent * /* event */)
1589+ {
1590+ emit editingFinished();
1591+ }
1592+/*
1593+ * The method uses basic linear algebra to find out which star is under the cursor.
1594+ */
1595+ int StarEditor::starAtPosition(int x)
1596+ {
1597+ // If the mouse is very close to the left edge, set 0 stars.
1598+ if (x < m_starRating.sizeHint().width() * 0.05) {
1599+ return 0;
1600+ }
1601+ int star = (x / (m_starRating.sizeHint().width() / m_starRating.maxStarCount())) + 1;
1602+
1603+ if (star <= 0 || star > m_starRating.maxStarCount())
1604+ return 0;
1605+
1606+ return star;
1607+ }
1608
1609=== added file 'mixxx/src/library/stareditor.h'
1610--- mixxx/src/library/stareditor.h 1970-01-01 00:00:00 +0000
1611+++ mixxx/src/library/stareditor.h 2010-10-19 05:33:52 +0000
1612@@ -0,0 +1,61 @@
1613+/***************************************************************************
1614+ stareditor.h
1615+ -------------------
1616+ copyright : (C) 2010 Tobias Rafreider
1617+ copyright : (C) 2009 Nokia Corporation
1618+
1619+***************************************************************************/
1620+
1621+/***************************************************************************
1622+ * *
1623+ * This program is free software; you can redistribute it and/or modify *
1624+ * it under the terms of the GNU General Public License as published by *
1625+ * the Free Software Foundation; either version 2 of the License, or *
1626+ * (at your option) any later version. *
1627+ * *
1628+ ***************************************************************************/
1629+
1630+/***************************************************************************
1631+ * *
1632+ * StarEditor inherits QWidget and is used by StarDelegate to let the user *
1633+ * edit a star rating in the library using the mouse. *
1634+ * *
1635+ * The class has been adapted from the official "Star Delegate Example", *
1636+ * see http://doc.trolltech.com/4.5/itemviews-stardelegate.html *
1637+ ***************************************************************************/
1638+
1639+#ifndef STAREDITOR_H
1640+#define STAREDITOR_H
1641+
1642+#include <QWidget>
1643+
1644+#include "starrating.h"
1645+
1646+class StarEditor : public QWidget
1647+{
1648+ Q_OBJECT
1649+
1650+public:
1651+ StarEditor(QWidget *parent, const QStyleOptionViewItem& option);
1652+
1653+ QSize sizeHint() const;
1654+ void setStarRating(const StarRating &starRating) {
1655+ m_starRating = starRating;
1656+ }
1657+ StarRating starRating() { return m_starRating; }
1658+
1659+signals:
1660+ void editingFinished();
1661+
1662+protected:
1663+ void paintEvent(QPaintEvent *event);
1664+ void mouseMoveEvent(QMouseEvent *event);
1665+ void mouseReleaseEvent(QMouseEvent *event);
1666+
1667+private:
1668+ int starAtPosition(int x);
1669+
1670+ StarRating m_starRating;
1671+};
1672+
1673+#endif
1674
1675=== added file 'mixxx/src/library/starrating.cpp'
1676--- mixxx/src/library/starrating.cpp 1970-01-01 00:00:00 +0000
1677+++ mixxx/src/library/starrating.cpp 2010-10-19 05:33:52 +0000
1678@@ -0,0 +1,74 @@
1679+/***************************************************************************
1680+ starrating.cpp
1681+ -------------------
1682+ copyright : (C) 2010 Tobias Rafreider
1683+ copyright : (C) 2009 Nokia Corporation
1684+
1685+***************************************************************************/
1686+
1687+/***************************************************************************
1688+ * *
1689+ * This program is free software; you can redistribute it and/or modify *
1690+ * it under the terms of the GNU General Public License as published by *
1691+ * the Free Software Foundation; either version 2 of the License, or *
1692+ * (at your option) any later version. *
1693+ * *
1694+ ***************************************************************************/
1695+
1696+
1697+#include <QtGui>
1698+#include <math.h>
1699+
1700+#include "starrating.h"
1701+
1702+const int PaintingScaleFactor = 20;
1703+
1704+
1705+
1706+StarRating::StarRating(int starCount, int maxStarCount)
1707+{
1708+ m_myStarCount = starCount;
1709+ m_myMaxStarCount = maxStarCount;
1710+
1711+ m_starPolygon << QPointF(1.0, 0.5);
1712+ for (int i = 1; i < 5; ++i)
1713+ m_starPolygon << QPointF(0.5 + 0.5 * cos(0.8 * i * 3.14), 0.5 + 0.5 * sin(0.8 * i * 3.14)); m_diamondPolygon << QPointF(0.4, 0.5) << QPointF(0.5, 0.4) << QPointF(0.6, 0.5) << QPointF(0.5, 0.6) << QPointF(0.4, 0.5);
1714+}
1715+
1716+QSize StarRating::sizeHint() const
1717+{
1718+ return PaintingScaleFactor * QSize(m_myMaxStarCount, 1);
1719+}
1720+
1721+/*
1722+ * function paints the stars in this StarRating object on a paint device
1723+ */
1724+void StarRating::paint(QPainter *painter, const QRect &rect, const QPalette &palette, EditMode mode) const
1725+{
1726+ painter->save();
1727+
1728+ painter->setRenderHint(QPainter::Antialiasing, true);
1729+ painter->setPen(Qt::NoPen);
1730+
1731+ // Workaround for painting issue. If we are editable, assume we are
1732+ // selected, so use the highlight and hightlightedText colors.
1733+ if (mode == Editable) {
1734+ painter->fillRect(rect, palette.highlight());
1735+ painter->setBrush(palette.highlightedText());
1736+ }
1737+
1738+ int yOffset = (rect.height() - PaintingScaleFactor) / 2;
1739+ painter->translate(rect.x(), rect.y() + yOffset);
1740+ painter->scale(PaintingScaleFactor, PaintingScaleFactor);
1741+
1742+ for (int i = 0; i < m_myMaxStarCount; ++i) {
1743+ if (i < m_myStarCount) {
1744+ painter->drawPolygon(m_starPolygon, Qt::WindingFill);
1745+ } else {
1746+ painter->drawPolygon(m_diamondPolygon, Qt::WindingFill);
1747+ }
1748+ painter->translate(1.0, 0.0);
1749+ }
1750+
1751+ painter->restore();
1752+}
1753
1754=== added file 'mixxx/src/library/starrating.h'
1755--- mixxx/src/library/starrating.h 1970-01-01 00:00:00 +0000
1756+++ mixxx/src/library/starrating.h 2010-10-19 05:33:52 +0000
1757@@ -0,0 +1,62 @@
1758+/***************************************************************************
1759+ starrating.h
1760+ -------------------
1761+ copyright : (C) 2010 Tobias Rafreider
1762+ copyright : (C) 2009 Nokia Corporation
1763+
1764+***************************************************************************/
1765+
1766+/***************************************************************************
1767+ * *
1768+ * This program is free software; you can redistribute it and/or modify *
1769+ * it under the terms of the GNU General Public License as published by *
1770+ * the Free Software Foundation; either version 2 of the License, or *
1771+ * (at your option) any later version. *
1772+ * *
1773+ ***************************************************************************/
1774+
1775+
1776+#ifndef STARRATING_H
1777+#define STARRATING_H
1778+
1779+#include <QMetaType>
1780+#include <QPointF>
1781+#include <QVector>
1782+#include <QPainter>
1783+#include <QStyledItemDelegate>
1784+
1785+/*
1786+ * The StarRating class represents a rating as a number of stars.
1787+ * In addition to holding the data, it is also capable of painting the stars on a QPaintDevice,
1788+ * which in this example is either a view or an editor.
1789+ * The myStarCount member variable stores the current rating, and myMaxStarCount stores
1790+ * the highest possible rating (typically 5).
1791+ */
1792+class StarRating
1793+{
1794+ public:
1795+ enum EditMode { Editable, ReadOnly };
1796+
1797+
1798+ StarRating(int starCount = 1, int maxStarCount = 5);
1799+
1800+ void paint(QPainter *painter, const QRect &rect, const QPalette &palette, EditMode mode) const;
1801+ QSize sizeHint() const;
1802+
1803+ int starCount() const { return m_myStarCount; }
1804+ int maxStarCount() const { return m_myMaxStarCount; }
1805+ void setStarCount(int starCount) { m_myStarCount = starCount; }
1806+ void setMaxStarCount(int maxStarCount) { m_myMaxStarCount = maxStarCount; }
1807+
1808+
1809+private:
1810+ QPolygonF m_starPolygon;
1811+ QPolygonF m_diamondPolygon;
1812+ int m_myStarCount;
1813+ int m_myMaxStarCount;
1814+
1815+};
1816+
1817+Q_DECLARE_METATYPE(StarRating)
1818+
1819+#endif
1820
1821=== modified file 'mixxx/src/library/trackcollection.cpp'
1822--- mixxx/src/library/trackcollection.cpp 2010-10-07 03:05:48 +0000
1823+++ mixxx/src/library/trackcollection.cpp 2010-10-19 05:33:52 +0000
1824@@ -44,6 +44,9 @@
1825 {
1826 // Save all tracks that haven't been saved yet.
1827 m_trackDao.saveDirtyTracks();
1828+ // TODO(XXX) Maybe fold saveDirtyTracks into TrackDAO::finish now that it
1829+ // exists? -- rryan 10/2010
1830+ m_trackDao.finish();
1831
1832 Q_ASSERT(!m_db.rollback()); //Rollback any uncommitted transaction
1833 //The above is an ASSERT because there should never be an outstanding
1834@@ -65,7 +68,7 @@
1835 return false;
1836 }
1837
1838- int requiredSchemaVersion = 5;
1839+ int requiredSchemaVersion = 6;
1840 if (!SchemaManager::upgradeToSchemaVersion(m_pConfig, m_db,
1841 requiredSchemaVersion)) {
1842 QMessageBox::warning(0, qApp->tr("Cannot upgrade database schema"),
1843
1844=== modified file 'mixxx/src/mixxx.cpp'
1845--- mixxx/src/mixxx.cpp 2010-10-18 21:55:09 +0000
1846+++ mixxx/src/mixxx.cpp 2010-10-19 05:33:52 +0000
1847@@ -185,10 +185,10 @@
1848 QDir dir(config->getValueString(ConfigKey("[Playlist]","Directory")));
1849 if ((config->getValueString(ConfigKey("[Playlist]","Directory")).length()<1) || (!dir.exists()))
1850 {
1851- QString fd = QFileDialog::getExistingDirectory(this,
1852+ QString fd = QFileDialog::getExistingDirectory(this,
1853 tr("Choose music library directory"),
1854 QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
1855-
1856+
1857 if (fd != "")
1858 {
1859 config->set(ConfigKey("[Playlist]","Directory"), fd);
1860
1861=== modified file 'mixxx/src/player.cpp'
1862--- mixxx/src/player.cpp 2010-10-07 09:03:35 +0000
1863+++ mixxx/src/player.cpp 2010-10-19 05:33:52 +0000
1864@@ -178,6 +178,8 @@
1865 if(!m_pLoadedTrack->getHeaderParsed())
1866 SoundSourceProxy::ParseHeader(m_pLoadedTrack.data());
1867
1868+ m_pLoadedTrack->incTimesPlayed();
1869+
1870 // Generate waveform summary
1871 //TODO: Consider reworking this visual resample stuff... need to ask rryan about this -- Albert.
1872 // TODO(rryan) : fix this crap -- the waveform renderers should be owned by
1873
1874=== modified file 'mixxx/src/trackinfoobject.cpp'
1875--- mixxx/src/trackinfoobject.cpp 2010-10-07 03:05:48 +0000
1876+++ mixxx/src/trackinfoobject.cpp 2010-10-19 05:33:52 +0000
1877@@ -48,6 +48,7 @@
1878 : m_qMutex(QMutex::Recursive) {
1879 m_sFilename = XmlParse::selectNodeQString(nodeHeader, "Filename");
1880 m_sLocation = XmlParse::selectNodeQString(nodeHeader, "Filepath") + "/" + m_sFilename;
1881+ QString create_date;
1882
1883 // We don't call initialize() here because it would end up calling parse()
1884 // on the file. Plus those initializations weren't done before, so it might
1885@@ -72,6 +73,11 @@
1886 m_bBpmConfirm = XmlParse::selectNodeQString(nodeHeader, "BpmConfirm").toInt();
1887 m_fBeatFirst = XmlParse::selectNodeQString(nodeHeader, "BeatFirst").toFloat();
1888 m_bHeaderParsed = false;
1889+ create_date = XmlParse::selectNodeQString(nodeHeader, "CreateDate");
1890+ if (create_date == "")
1891+ m_dCreateDate = fileInfo.created();
1892+ else
1893+ m_dCreateDate = QDateTime::fromString(create_date);
1894
1895 // Mixxx <1.8 recorded track IDs in mixxxtrack.xml, but we are going to
1896 // ignore those. Tracks will get a new ID from the database.
1897@@ -79,6 +85,7 @@
1898 m_iId = -1;
1899
1900 m_fCuePoint = XmlParse::selectNodeQString(nodeHeader, "CuePoint").toFloat();
1901+ m_bPlayed = false;
1902
1903 m_pVisualWave = 0;
1904 m_dVisualResampleRate = 0;
1905@@ -112,6 +119,7 @@
1906 m_iDuration = 0;
1907 m_iBitrate = 0;
1908 m_iTimesPlayed = 0;
1909+ m_bPlayed = false;
1910 m_fBpm = 0.;
1911 m_bBpmConfirm = false;
1912 m_bIsValid = false;
1913@@ -123,6 +131,8 @@
1914 m_iChannels = 0;
1915 m_fCuePoint = 0.0f;
1916 m_dVisualResampleRate = 0;
1917+ m_dCreateDate = QDateTime::currentDateTime();
1918+ m_Rating = 0;
1919
1920 // parse() parses the metadata from file. This is not a quick operation!
1921 if (parseHeader)
1922@@ -148,6 +158,7 @@
1923 {
1924 QMutexLocker lock(&m_qMutex);
1925
1926+ QString create_date;
1927 XmlParse::addElement( doc, header, "Filename", m_sFilename );
1928 //XmlParse::addElement( doc, header, "Filepath", m_sFilepath );
1929 XmlParse::addElement( doc, header, "Title", m_sTitle );
1930@@ -165,6 +176,7 @@
1931 XmlParse::addElement( doc, header, "BeatFirst", QString("%1").arg(m_fBeatFirst) );
1932 XmlParse::addElement( doc, header, "Id", QString("%1").arg(m_iId) );
1933 XmlParse::addElement( doc, header, "CuePoint", QString::number(m_fCuePoint) );
1934+ XmlParse::addElement( doc, header, "CreateDate", m_dCreateDate.toString() );
1935 //if (m_pWave) {
1936 //XmlParse::addHexElement(doc, header, "WaveSummaryHex", m_pWave);
1937 //}
1938@@ -255,6 +267,13 @@
1939 return m_sFilename;
1940 }
1941
1942+QDateTime TrackInfoObject::getCreateDate() const
1943+{
1944+ QMutexLocker lock(&m_qMutex);
1945+ QDateTime create_date = QDateTime(m_dCreateDate);
1946+ return create_date;
1947+}
1948+
1949 bool TrackInfoObject::exists() const
1950 {
1951 QMutexLocker lock(&m_qMutex);
1952@@ -439,13 +458,53 @@
1953 return m_iTimesPlayed;
1954 }
1955
1956+void TrackInfoObject::setTimesPlayed(int t)
1957+{
1958+ QMutexLocker lock(&m_qMutex);
1959+ bool dirty = t != m_iTimesPlayed;
1960+ m_iTimesPlayed = t;
1961+ if (dirty)
1962+ setDirty(true);
1963+}
1964+
1965 void TrackInfoObject::incTimesPlayed()
1966 {
1967 QMutexLocker lock(&m_qMutex);
1968+ std::cout << "Track Played:" << m_sArtist.toStdString() << " - " << m_sTitle.toStdString();
1969+ qDebug() << "Track Played:" << m_sArtist << " - " << m_sTitle;
1970+ m_bPlayed = true;
1971 ++m_iTimesPlayed;
1972 setDirty(true);
1973 }
1974
1975+bool TrackInfoObject::getPlayed() const
1976+{
1977+ QMutexLocker lock(&m_qMutex);
1978+ bool bPlayed = m_bPlayed;
1979+ return bPlayed;
1980+}
1981+
1982+void TrackInfoObject::setPlayed(bool bPlayed)
1983+{
1984+ QMutexLocker lock(&m_qMutex);
1985+ bool dirty = bPlayed != m_bPlayed;
1986+ m_bPlayed = bPlayed;
1987+ if (dirty)
1988+ {
1989+ if (bPlayed)
1990+ {
1991+ std::cout << "Track Played:" << m_sArtist.toStdString() << " - " << m_sTitle.toStdString();
1992+ qDebug() << "Track Played:" << m_sArtist << " - " << m_sTitle;
1993+ }
1994+ else
1995+ {
1996+ std::cout << "Track Unplayed:" << m_sArtist.toStdString() << " - " << m_sTitle.toStdString();
1997+ qDebug() << "Track Unplayed:" << m_sArtist << " - " << m_sTitle;
1998+ }
1999+ setDirty(true);
2000+ }
2001+}
2002+
2003 QString TrackInfoObject::getComment() const
2004 {
2005 QMutexLocker lock(&m_qMutex);
2006@@ -721,3 +780,18 @@
2007 QMutexLocker lock(&m_qMutex);
2008 return m_bLocationChanged;
2009 }
2010+/** Returns the rating */
2011+int TrackInfoObject::getRating() const{
2012+ QMutexLocker lock(&m_qMutex);
2013+
2014+ return m_Rating;
2015+}
2016+ /** Set rating */
2017+void TrackInfoObject::setRating (int rating){
2018+ QMutexLocker lock(&m_qMutex);
2019+
2020+ bool dirty = rating != m_Rating;
2021+ m_Rating = rating;
2022+ if (dirty)
2023+ setDirty(true);
2024+}
2025
2026=== modified file 'mixxx/src/trackinfoobject.h'
2027--- mixxx/src/trackinfoobject.h 2010-10-07 03:05:48 +0000
2028+++ mixxx/src/trackinfoobject.h 2010-10-19 05:33:52 +0000
2029@@ -19,6 +19,7 @@
2030 #define TRACKINFOOBJECT_H
2031
2032 #include <QList>
2033+#include <QDateTime>
2034 #include <QObject>
2035 #include <QFileInfo>
2036 #include <QMutex>
2037@@ -76,6 +77,8 @@
2038 QString getDirectory() const;
2039 // Returns the filename of the file.
2040 QString getFilename() const;
2041+ // Returns file creation date
2042+ QDateTime getCreateDate() const;
2043 // Returns the length of the file in bytes
2044 int getLength() const;
2045 // Returns whether the file exists on disk or not. Updated as of the time
2046@@ -152,11 +155,21 @@
2047 void setTrackNumber(QString);
2048 /** Return number of times the track has been played */
2049 int getTimesPlayed() const;
2050+ /** Set number of times the track has been played */
2051+ void setTimesPlayed(int t);
2052 /** Increment times played with one */
2053 void incTimesPlayed();
2054+ /** Returns true if track has been played this instance*/
2055+ bool getPlayed() const;
2056+ /** Set Played status*/
2057+ void setPlayed(bool);
2058
2059 int getId() const;
2060
2061+ /** Returns rating */
2062+ int getRating() const;
2063+ /** Sets rating */
2064+ void setRating(int);
2065
2066 /** Get URL for track */
2067 QString getURL();
2068@@ -282,10 +295,14 @@
2069 int m_iSampleRate;
2070 /** Number of channels */
2071 int m_iChannels;
2072+ /**Track rating */
2073+ int m_Rating;;
2074 /** Bitrate, number of kilobits per second of audio in the track*/
2075 int m_iBitrate;
2076 /** Number of times the track has been played */
2077 int m_iTimesPlayed;
2078+ /** Has this track been played this sessions? */
2079+ bool m_bPlayed;
2080 /** Beat per minutes (BPM) */
2081 float m_fBpm;
2082 /** Minimum BPM range. If this is 0.0, then the config min BPM will be used */
2083@@ -302,6 +319,8 @@
2084 int m_iId;
2085 /** Cue point in samples or something */
2086 float m_fCuePoint;
2087+ /** Date. creation date of file */
2088+ QDateTime m_dCreateDate;
2089
2090 // The list of cue points for the track
2091 QList<Cue*> m_cuePoints;
2092
2093=== modified file 'mixxx/src/widget/wlibrarytableview.cpp'
2094--- mixxx/src/widget/wlibrarytableview.cpp 2010-09-19 22:08:15 +0000
2095+++ mixxx/src/widget/wlibrarytableview.cpp 2010-10-19 05:33:52 +0000
2096@@ -8,6 +8,7 @@
2097 #include "widget/wwidget.h"
2098 #include "widget/wskincolor.h"
2099 #include "widget/wlibrarytableview.h"
2100+#include "../library/stardelegate.h"
2101
2102 WLibraryTableView::WLibraryTableView(QWidget* parent,
2103 ConfigObject<ConfigValue>* pConfig,
2104@@ -16,7 +17,13 @@
2105 m_pConfig(pConfig),
2106 m_vScrollBarPosKey(vScrollBarPosKey) {
2107
2108- //Setup properties for table
2109+ // Setup properties for table
2110+
2111+ // Editing starts when clicking on an already selected item.
2112+ setEditTriggers(QAbstractItemView::SelectedClicked);
2113+
2114+ // This is to support rating of tracks
2115+ setItemDelegate(new StarDelegate());
2116
2117 //Enable selection by rows and extended selection (ctrl/shift click)
2118 setSelectionBehavior(QAbstractItemView::SelectRows);
2119
2120=== modified file 'mixxx/src/widget/wstatuslight.cpp'
2121--- mixxx/src/widget/wstatuslight.cpp 2009-03-05 15:14:48 +0000
2122+++ mixxx/src/widget/wstatuslight.cpp 2010-10-19 05:33:52 +0000
2123@@ -26,59 +26,90 @@
2124
2125 WStatusLight::WStatusLight(QWidget * parent) : WWidget(parent)
2126 {
2127- m_pPixmapBack = 0;
2128- m_pPixmapSL = 0;
2129+ m_pPixmapSLs = 0;
2130+ m_iNoPos = 0;
2131+ m_iPos = 0;
2132+
2133+ setNoPos(0);
2134 }
2135
2136 WStatusLight::~WStatusLight()
2137 {
2138- resetPositions();
2139+ for (int i = 0; i < m_iNoPos; i++) {
2140+ WPixmapStore::deletePixmap(m_pPixmapSLs[i]);
2141+ }
2142+}
2143+
2144+void WStatusLight::setNoPos(int iNoPos)
2145+{
2146+ m_iNoPos = iNoPos;
2147+ m_fValue = 0.;
2148+
2149+ // If pixmap array is already allocated, delete it
2150+ if (m_pPixmapSLs)
2151+ delete [] m_pPixmapSLs;
2152+
2153+ if (m_iNoPos>0)
2154+ {
2155+ m_pPixmapSLs = new QPixmap*[m_iNoPos];
2156+ for (int i=0; i<m_iNoPos; ++i)
2157+ m_pPixmapSLs[i] = 0;
2158+ }
2159 }
2160
2161 void WStatusLight::setup(QDomNode node)
2162 {
2163 WWidget::setup(node);
2164-
2165- // Set pixmaps
2166- bool bHorizontal = false;
2167- if (!selectNode(node, "Horizontal").isNull() && selectNodeQString(node, "Horizontal")=="true")
2168- bHorizontal = true;
2169- setPixmaps(getPath(selectNodeQString(node, "PathBack")), getPath(selectNodeQString(node, "PathStatusLight")), bHorizontal);
2170-}
2171-
2172-void WStatusLight::resetPositions()
2173-{
2174- if (m_pPixmapBack)
2175- {
2176- WPixmapStore::deletePixmap(m_pPixmapBack);
2177- m_pPixmapBack = 0;
2178- WPixmapStore::deletePixmap(m_pPixmapSL);
2179- m_pPixmapSL = 0;
2180- }
2181-}
2182-
2183-void WStatusLight::setPixmaps(const QString &backFilename, const QString &vuFilename, bool bHorizontal)
2184-{
2185- m_pPixmapBack = WPixmapStore::getPixmap(backFilename);
2186- if (!m_pPixmapBack || m_pPixmapBack->size()==QSize(0,0))
2187- qDebug() << "WStatusLight: Error loading back pixmap" << backFilename;
2188- m_pPixmapSL = WPixmapStore::getPixmap(vuFilename);
2189- if (!m_pPixmapSL || m_pPixmapSL->size()==QSize(0,0))
2190- qDebug() << "WStatusLight: Error loading statuslight pixmap" << vuFilename;
2191-
2192- setFixedSize(m_pPixmapBack->size());
2193- m_bHorizontal = bHorizontal;
2194+ // Number of states
2195+ m_iNoPos = selectNodeInt(node, "NumberPos") + 1;
2196+ setNoPos(m_iNoPos);
2197+
2198+ for (int i=0; i<m_iNoPos; i++)
2199+ {
2200+ switch(i)
2201+ {
2202+ case 0:
2203+ // Set background pixmap if available
2204+ if (!selectNode(node, "BackPath").isNull())
2205+ setPixmap(0, getPath(selectNodeQString(node, "BackPath")));
2206+ else
2207+ m_pPixmapSLs[0] = 0;
2208+ break;
2209+ case 1:
2210+ setPixmap(1, getPath(selectNodeQString(node, "PathStatusLight")));
2211+ break;
2212+ default:
2213+ setPixmap(i, getPath(selectNodeQString(node, QString("PathStatusLight%1").arg(i))));
2214+ }
2215+ }
2216+}
2217+
2218+void WStatusLight::setPixmap(int iState, const QString &filename)
2219+{
2220+ int pixIdx = iState;
2221+ m_pPixmapSLs[pixIdx] = WPixmapStore::getPixmap(filename);
2222+ if (!m_pPixmapSLs[pixIdx])
2223+ qDebug() << "WPushButton: Error loading pixmap:" << filename << iState;
2224+
2225+ // Set size of widget equal to pixmap size
2226+ setFixedSize(m_pPixmapSLs[pixIdx]->size());
2227+}
2228+
2229+void WStatusLight::setValue(double v)
2230+{
2231+ if (m_iPos != (int)v)
2232+ {
2233+ m_iPos = (int)v;
2234+ update();
2235+ }
2236 }
2237
2238 void WStatusLight::paintEvent(QPaintEvent *)
2239 {
2240- if (m_pPixmapBack!=0 && m_pPixmapSL!=0)
2241+ if (m_pPixmapSLs[m_iPos])
2242 {
2243 QPainter p(this);
2244-
2245- if(m_fValue == 0)
2246- p.drawPixmap(0, 0, *m_pPixmapBack);
2247- else
2248- p.drawPixmap(0, 0, *m_pPixmapSL);
2249+ if(m_iPos != 0 && m_pPixmapSLs[0]) p.drawPixmap(0, 0, *m_pPixmapSLs[0]);
2250+ p.drawPixmap(0, 0, *m_pPixmapSLs[m_iPos]);
2251 }
2252 }
2253
2254=== modified file 'mixxx/src/widget/wstatuslight.h'
2255--- mixxx/src/widget/wstatuslight.h 2009-03-05 15:45:39 +0000
2256+++ mixxx/src/widget/wstatuslight.h 2010-10-19 05:33:52 +0000
2257@@ -31,26 +31,24 @@
2258 */
2259
2260 class WStatusLight : public WWidget {
2261- Q_OBJECT
2262-public:
2263+ Q_OBJECT
2264+ public:
2265 WStatusLight(QWidget *parent=0);
2266- ~WStatusLight();
2267+ virtual ~WStatusLight();
2268 void setup(QDomNode node);
2269- void setPixmaps(const QString &backFilename, const QString &vuFilename, bool bHorizontal=false);
2270-
2271-private:
2272- /** Set position number to zero and deallocate pixmaps */
2273- void resetPositions();
2274+ void setPixmap(int iState, const QString &filename);
2275+ void setNoPos(int iNoPos);
2276+ public slots:
2277+ void setValue(double v);
2278+ private:
2279 void paintEvent(QPaintEvent *);
2280
2281 /** Current position */
2282 int m_iPos;
2283- /** Number of positions associated with this knob */
2284+ /** Number of positions associated with this light */
2285 int m_iNoPos;
2286 /** Associated pixmaps */
2287- QPixmap *m_pPixmapBack, *m_pPixmapSL;
2288- /** True if it's a horizontal vu meter */
2289- bool m_bHorizontal;
2290+ QPixmap **m_pPixmapSLs;
2291 };
2292
2293 #endif
2294
2295=== modified file 'mixxx/src/widget/wtracktableview.cpp'
2296--- mixxx/src/widget/wtracktableview.cpp 2010-09-17 06:09:27 +0000
2297+++ mixxx/src/widget/wtracktableview.cpp 2010-10-19 05:33:52 +0000
2298@@ -31,12 +31,11 @@
2299 this, SLOT(slotPrevTrackInfo()));
2300
2301 m_pMenu = new QMenu(this);
2302+
2303 m_pPlaylistMenu = new QMenu(this);
2304 m_pPlaylistMenu->setTitle(tr("Add to Playlist"));
2305 m_pCrateMenu = new QMenu(this);
2306 m_pCrateMenu->setTitle(tr("Add to Crate"));
2307- //Disable editing
2308- //setEditTriggers(QAbstractItemView::NoEditTriggers);
2309
2310 //Create all the context m_pMenu->actions (stuff that shows up when you
2311 //right-click)
2312@@ -614,13 +613,15 @@
2313
2314 void WTrackTableView::keyPressEvent(QKeyEvent* event)
2315 {
2316- m_selectedIndices = this->selectionModel()->selectedRows();
2317+
2318 if (event->key() == Qt::Key_Return)
2319 {
2320- if (m_selectedIndices.size() > 0) {
2321- QModelIndex index = m_selectedIndices.at(0);
2322- slotMouseDoubleClicked(index);
2323- }
2324+ /*
2325+ * It is not a good idea if 'key_return'
2326+ * causes a track to load since we allow in-line editing
2327+ * of table items in general
2328+ */
2329+ return;
2330 }
2331 else if (event->key() == Qt::Key_BracketLeft)
2332 {

Subscribers

People subscribed via source and target branches