1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-09-06 12:10:47 +02:00

Compare commits

...

190 Commits

Author SHA1 Message Date
Leo Franchi
ce76c86171 Changelog for spotify config dialog 2012-07-25 09:39:01 -04:00
Leo Franchi
64d9a0f5d2 Keep config UI in sync with resolver 2012-07-25 09:38:22 -04:00
Leo Franchi
aa0f99bcce Some more fixes 2012-07-25 09:38:22 -04:00
Leo Franchi
5be032f39c New spotify config 2012-07-25 09:38:22 -04:00
Christian Muehlhaeuser
272add3c3b * Bumped to 0.5.5 and fixed ChangeLog width. 2012-07-25 14:37:42 +02:00
Leo Franchi
39e7314acf Changelog for 0.5.5 2012-07-25 08:34:06 -04:00
Dominik Schmidt
90e238a352 Rename FindLibEchonest to FindEchonest, make it version aware and overall more state of the art :P 2012-07-25 08:28:44 -04:00
Dominik Schmidt
20b62bfba3 xmpp: check for error presences in AvatarManager 2012-07-25 08:28:36 -04:00
Leo Franchi
6fa2ad19ee Fix osx compile 2012-07-25 08:27:34 -04:00
Leo Franchi
60f2e85965 Implement non-osx side of new search field For Compile Win 2012-07-25 08:27:26 -04:00
Leo Franchi
cbd9d4e0ce Update Qocoa QSearchField to latest, with hatstand's fix.
Now shortcuts work in the QSearchField, like c&p and select all
2012-07-25 08:27:21 -04:00
Leo Franchi
22a1f167b0 Bump libechonest required version to 2.0.0 2012-07-25 08:27:14 -04:00
Leo Franchi
44a5406a34 Adapt to new libechonest v2 api 2012-07-25 08:27:08 -04:00
Leo Franchi
611ca21ec6 Remove steering from echonest stations 2012-07-25 08:27:01 -04:00
Christian Muehlhaeuser
64274d6d39 * Added code-signing to OS X build scripts. 2012-07-25 08:26:54 -04:00
Hugo Lindström
34dc6d23ee Send resulthint when we have it 2012-07-25 08:26:34 -04:00
Leo Franchi
70a5050443 Pointer safety 2012-07-25 08:26:09 -04:00
Leo Franchi
2a19f20914 Pointer safety (Oops #20003) 2012-07-25 08:25:42 -04:00
Leo Franchi
33ca71a86a TWK-968: Part Two: Allow drop helper for mixed query/result lists. 2012-07-25 08:17:34 -04:00
Leo Franchi
485447be38 TWK-985: Log into spotify on return pressed in Spotify config 2012-07-25 08:17:25 -04:00
Christian Muehlhaeuser
4f2cbb32c5 * Fixed queue auto-collapsing when playing the last track in it. 2012-07-14 05:52:13 +02:00
Leo Franchi
edc6057354 Also allow multiple infoplugins to return data for artist top tracks 2012-07-14 05:52:07 +02:00
Tomahawk CI
7beab3aea8 Automatic merge of Transifex translations 2012-07-14 05:51:25 +02:00
Leo Franchi
3e3e76b66f Call sendMessage() with a QueuedConnection as it's cross-thread 2012-07-14 05:51:17 +02:00
Leo Franchi
c33d3c2a67 Let AlbumPlaylistInterface accept results from first good infoplugin result 2012-07-14 05:50:48 +02:00
Leo Franchi
56e997a159 Extra pointer safety 2012-07-14 05:50:41 +02:00
Leo Franchi
67d75543e6 TWK-968: Fix PlayableModel/DropJob for mixed mimetype 2012-07-14 05:50:29 +02:00
Christian Muehlhaeuser
e19423e08f * Updated ChangeLog. 2012-07-13 11:03:21 +02:00
Christian Muehlhaeuser
e041ce87fc * Bumped to 0.5.4. 2012-07-13 10:00:28 +02:00
Tomahawk CI
6eacdf808e Automatic merge of Transifex translations 2012-07-13 09:58:49 +02:00
Leo Franchi
b6d5c86952 Pointer safety 2012-07-13 09:58:40 +02:00
Leo Franchi
b7fb9a03bf Add spotify infoplugin for album lookups 2012-07-13 09:58:19 +02:00
Christian Muehlhaeuser
37fad49393 * Fixed Windows shutdown. 2012-07-13 09:50:16 +02:00
Christian Muehlhaeuser
fa83fde05e * Try not deleting cache. 2012-07-13 09:26:02 +02:00
Christian Muehlhaeuser
b3b34cacbd * Try not deleting the infoSystem on shutdown. Does it fix Windows crashes? 2012-07-13 08:06:59 +02:00
Christian Muehlhaeuser
d0f697cd4b * Friend class MusicScanner. 2012-07-12 10:47:38 +02:00
Christian Muehlhaeuser
c144a0142f * Fixed forgotten merge. 2012-07-12 10:24:19 +02:00
Christian Muehlhaeuser
318866d37a * Fixed broken merge. 2012-07-12 10:19:40 +02:00
Christian Muehlhaeuser
70e93faa3f * Added verbose shutdown debug output. 2012-07-12 10:17:07 +02:00
Christian Muehlhaeuser
89e21289a6 * Fixed broken merge. 2012-07-12 10:08:52 +02:00
Christian Muehlhaeuser
fe0d2d87fc * Updated ChangeLog. 2012-07-12 10:00:21 +02:00
Christian Muehlhaeuser
8531ca2234 * Fixed broken merge. 2012-07-12 09:52:42 +02:00
Christian Muehlhaeuser
8d5082fe2c * Really fix compiling on Windows. 2012-07-12 09:49:11 +02:00
Christian Muehlhaeuser
7672c7caec * Try to fix compiling on mingw. 2012-07-12 09:48:26 +02:00
Christian Muehlhaeuser
bf2139824d * Cleaned up DiagnosticsDialog. 2012-07-12 09:08:49 +02:00
Christian Muehlhaeuser
eb749b1e44 * Provide convenience openUrl( url ) method in TomahawkUtilsGui, since QDesktopServices fail to work on Windows. 2012-07-12 09:08:00 +02:00
Christian Muehlhaeuser
53226f37c2 * Expose logfile's path in Logger. 2012-07-12 09:07:52 +02:00
Christian Muehlhaeuser
20032a40b2 * Use a RAMDirectory if we can't open the regular lucene index file. 2012-07-12 09:06:58 +02:00
Tomahawk CI
a6d1bbb91e Automatic merge of Transifex translations 2012-07-12 09:06:50 +02:00
Jeff Mitchell
f7240a5d39 Increased pointer safety (oops 19400) 2012-07-12 09:06:39 +02:00
Jeff Mitchell
2142a04fda Increased pointer safety (oops 19336) 2012-07-12 09:05:55 +02:00
Jeff Mitchell
0406b38f1c * Merged 4-is-not-JSON bug to stable. 2012-07-12 09:04:47 +02:00
Tomahawk CI
8e2174baf1 Automatic merge of Transifex translations 2012-07-12 09:02:05 +02:00
Tomahawk CI
7caeaddc21 Automatic merge of Transifex translations 2012-07-12 09:01:57 +02:00
Tomahawk CI
f4a01ec6aa Automatic merge of Transifex translations 2012-07-12 09:01:42 +02:00
Christian Muehlhaeuser
ed81799294 * Merged music scanner fix. 2012-07-12 09:01:24 +02:00
Christian Muehlhaeuser
0283d534f0 * Remove overlays when filter changed. 2012-07-12 08:59:09 +02:00
Christian Muehlhaeuser
4a00ff4d24 * Fixed crash in ContextMenu. 2012-07-12 08:58:55 +02:00
Tomahawk CI
b98c535247 Automatic merge of Transifex translations 2012-07-12 08:58:38 +02:00
Christian Muehlhaeuser
fbcffed27b * Fixed FadingPixmap isn't initialized with m_isDefault being true. 2012-07-12 08:58:16 +02:00
Christian Muehlhaeuser
e521150d33 * Hooking up to resultsChanged() is enough in PlayableItem. 2012-07-12 08:58:16 +02:00
Christian Muehlhaeuser
2a0aa602b6 * Refetch cover when underlying metadata changed in PixmapDelegateFader. 2012-07-12 08:58:16 +02:00
Christian Muehlhaeuser
cf37aae430 * Emit resultsChanged() after adding / removing results in a Query. 2012-07-12 08:57:46 +02:00
Christian Muehlhaeuser
292f395c47 * Bumped to 0.5.3. 2012-07-06 01:59:42 +02:00
Christian Muehlhaeuser
047f3cc2d4 * Updated ChangeLog. 2012-07-06 01:59:26 +02:00
Tomahawk CI
97681ace31 Automatic merge of Transifex translations 2012-07-06 01:50:04 +02:00
Tomahawk CI
6be5257bc0 Automatic merge of Transifex translations 2012-07-06 01:49:58 +02:00
Tomahawk CI
8cfbe1f38b Automatic merge of Transifex translations 2012-07-06 01:49:48 +02:00
Christian Muehlhaeuser
8db8e42ec4 * Filter tree-model based on query, not result. 2012-07-06 01:47:19 +02:00
Christian Muehlhaeuser
9492055fc6 * Should fix crash when filtering collection. 2012-07-06 01:47:04 +02:00
Christian Muehlhaeuser
3dc624858b * Prevent crash in ViewHeader. 2012-07-06 01:45:55 +02:00
Christian Muehlhaeuser
f154c2bbcd * Correctly unset pause / spinner on GridView when a new track is loading. 2012-07-06 01:45:44 +02:00
Christian Muehlhaeuser
e9127ae3ec * Fixed Last.fm history importing. 2012-07-06 01:45:27 +02:00
Leo Franchi
c7d9d8e5b7 Seed pipeline job item with query immediately 2012-07-06 01:45:17 +02:00
Christian Muehlhaeuser
e525291213 * Don't load social actions twice. 2012-07-06 01:44:55 +02:00
Tomahawk CI
44269ee8f6 Automatic merge of Transifex translations 2012-07-06 01:44:47 +02:00
Christian Muehlhaeuser
53c4a2d675 * Add a vertical spacer item to the DiagnosticsDialog, so contents don't move around. 2012-07-06 01:44:40 +02:00
Christian Muehlhaeuser
ebfc53e009 * Emit coverChanged() even when we couldn't get a cover, so the views update / trigger new requests. 2012-07-06 01:44:28 +02:00
Tomahawk CI
190845a86e Automatic merge of Transifex translations 2012-07-06 01:44:06 +02:00
Leo Franchi
25af4f4275 Don't confuse QFileInfo 2012-07-05 16:49:48 -04:00
Jeff Mitchell
bca64a70ed along to you -> along with you 2012-07-05 14:49:28 -04:00
Jeff Mitchell
10462ee257 Having this replace in there actually breaks notification for me.
I'm guessing that this is notification-system dependent; however, we
can't show & to people not using HTML-based notification renderers.

The fix needs to lie with the notification renderer vendor.
2012-07-05 13:40:21 -04:00
Christian Muehlhaeuser
ba4532593b * Bumped to 0.5.2. 2012-07-01 22:39:40 +02:00
Christian Muehlhaeuser
c84fd28dd2 * Update ChangeLog. 2012-07-01 22:37:07 +02:00
Christian Muehlhaeuser
dbbb491a81 * Indicate invalid PlaylistEntries. 2012-07-01 22:33:53 +02:00
Christian Muehlhaeuser
bab5e27673 * Fixed crashes in DbCmd_SetPlaylistRevision. 2012-07-01 22:33:53 +02:00
Christian Muehlhaeuser
17f71bd366 * Don't ever accept invalid results coming from resolvers. 2012-07-01 22:33:53 +02:00
Christian Muehlhaeuser
e96bbc11e1 * Fixed cover loading in error case. 2012-07-01 08:57:34 +02:00
Christian Muehlhaeuser
d492ba0317 * spotify -> Spotify. 2012-07-01 06:48:22 +02:00
Leo Franchi
b6466a6027 Changelogify 2012-07-01 00:43:58 -04:00
Christian Muehlhaeuser
6b5d391cde * Remove debug output again. 2012-07-01 05:45:28 +02:00
Christian Muehlhaeuser
0680dec5df * Set m_coverLoaded to true even when we couldn't find any image. 2012-07-01 05:45:28 +02:00
Christian Muehlhaeuser
a4e8f4216c * Removed rc0. 2012-07-01 05:13:29 +02:00
Christian Muehlhaeuser
355c95e068 * Set m_coverLoaded to true before emitting the coverChanged signal. 2012-07-01 02:51:46 +02:00
Christian Muehlhaeuser
da07361ec0 * Bumped to 0.5.1. 2012-07-01 02:29:57 +02:00
Christian Muehlhaeuser
aafe8797ad * Don't crash when removing page in history. 2012-07-01 02:23:31 +02:00
Tomahawk CI
95343ca024 Automatic merge of Transifex translations 2012-07-01 00:21:51 +02:00
Leo Franchi
f85bcc1c64 No more libspotify in bundle 2012-07-01 00:21:15 +02:00
Christian Muehlhaeuser
e53e51aefc * Add 'Copy Artist/Album Link' context menu items. 2012-07-01 00:21:08 +02:00
Christian Muehlhaeuser
d22b33bc50 * Be prepared for empty query_ptrs being returned from Query::get(). 2012-07-01 00:20:59 +02:00
Christian Muehlhaeuser
c36414bb4c * Return empty query_ptr when query data is invalid. 2012-07-01 00:20:51 +02:00
Christian Muehlhaeuser
a78349f9f1 * Use 'large' album covers from Last.fm. 2012-07-01 00:20:43 +02:00
Stefan Derkits
fa41b96260 Ubuntu 11.10 needs explicit pthread, reenable finding & linking them 2012-07-01 00:17:55 +02:00
Tomahawk CI
7f2bf85663 Automatic merge of Transifex translations 2012-07-01 00:17:47 +02:00
Leo Franchi
85fe824df3 Also remove saved resolver path when uninstalling 2012-07-01 00:17:36 +02:00
Leo Franchi
c37bbb4deb Use headerpad_max_install_names on OS X builds 2012-07-01 00:17:23 +02:00
Leo Franchi
1a9bf84ab4 Don't copy to bundle any longer when installing binary resolvers on osx 2012-07-01 00:17:17 +02:00
Leo Franchi
a283ea1ed0 Do our own attica download fetching since we send the tomahawk version as well 2012-07-01 00:17:10 +02:00
Christian Muehlhaeuser
d27dd0785a * Use new Querylabel API. 2012-07-01 00:17:02 +02:00
Christian Muehlhaeuser
5e1f808d28 * Support setting Artist / Album on a QueryLabel directly. We need a proper 'CleverLabel' so badly. 2012-07-01 00:16:55 +02:00
Christian Muehlhaeuser
aba78c7a24 * Removed obsolete code. 2012-07-01 00:16:43 +02:00
Christian Muehlhaeuser
f45e92a24d * No more dragsource.type. 2012-07-01 00:16:27 +02:00
Christian Muehlhaeuser
5ae04043d4 * Properly drag Artists / Albums from QueryLabel. 2012-07-01 00:16:11 +02:00
Christian Muehlhaeuser
5f521a6cf5 * Use new PlayableModel API throughout app. 2012-07-01 00:15:53 +02:00
Christian Muehlhaeuser
a4b30dcecd * Adjust inheriting models to new PlayableModel API. 2012-07-01 00:15:44 +02:00
Christian Muehlhaeuser
700394a054 * Resolved a bunch more hidden overloaded virtual methods in PlayableModel. 2012-07-01 00:15:35 +02:00
Christian Muehlhaeuser
819ee17b74 * Use new PlayableModel API throughout app. 2012-07-01 00:15:11 +02:00
Christian Muehlhaeuser
79c55f1699 * Adjust inheriting models to new PlayableModel API. 2012-07-01 00:15:04 +02:00
Christian Muehlhaeuser
f42696de23 * Resolved a bunch of hidden overloaded virtual methods in PlayableModel. 2012-07-01 00:14:52 +02:00
Christian Muehlhaeuser
adfaf5ce53 * Fixed text-width calculation after my latest patch. 2012-07-01 00:13:08 +02:00
Christian Muehlhaeuser
32aca98a97 * Fix english translation plurals. 2012-07-01 00:12:59 +02:00
Tomahawk CI
294809debb Automatic merge of Transifex translations 2012-07-01 00:12:45 +02:00
Christian Muehlhaeuser
e4593079f3 * Proper fix for QueryLabel's context menu. 2012-07-01 00:11:40 +02:00
Christian Muehlhaeuser
cfa4210854 * Show correct context menus for album / artist QueryLabels. 2012-07-01 00:10:42 +02:00
Tomahawk CI
91084885fb Automatic merge of Transifex translations 2012-07-01 00:10:30 +02:00
Tomahawk CI
0b7f420bef Automatic merge of Transifex translations 2012-07-01 00:10:21 +02:00
Jeff Mitchell
046237f009 Fix compilation 2012-06-30 17:07:01 -04:00
Jeff Mitchell
85d9755a47 Merge pull request #103 from nowrep/master
FdoNotifyPlugin: Fixed showing notifications with & character
2012-06-30 17:01:35 -04:00
Jeff Mitchell
98bd7b1857 Fix another crash related to debug accessing null pointers 2012-06-29 10:06:37 -04:00
Jeff Mitchell
37510fc2d7 OK, really fix crash. Promise. 2012-06-29 10:05:08 -04:00
Jeff Mitchell
a91ad7dd5f Actually fix crash 2012-06-29 10:02:21 -04:00
Jeff Mitchell
2cc85c8f4f Fix accessing playlist that could be invalid inside debug 2012-06-29 10:00:07 -04:00
Christian Muehlhaeuser
19625fffd4 * Only return online results via web API. 2012-06-27 07:39:51 +02:00
Christian Muehlhaeuser
a98cab55b7 * Properly sort artists & albums in search widget. 2012-06-27 05:37:15 +02:00
Christian Muehlhaeuser
ec7b98e589 * Moved levenshtein method to TomahawkUtils. 2012-06-27 05:37:15 +02:00
Christian Muehlhaeuser
1262dcb60a * Retry on this sql error, too. 2012-06-27 05:37:15 +02:00
Christian Muehlhaeuser
fc9c6e6017 * Use new spinner integration API. 2012-06-27 05:37:15 +02:00
Christian Muehlhaeuser
fa4463dc88 * No need to check all results for playability. Their sorted by that, so we just check the first one. 2012-06-27 05:37:15 +02:00
Christian Muehlhaeuser
3fb403c695 * Allow to sort by composer and origin. 2012-06-27 05:37:15 +02:00
Christian Muehlhaeuser
fdb1d1b621 * Expose composer's sortname in Query's API. 2012-06-27 05:37:15 +02:00
Leo Franchi
127da50144 Forcibly kill spotify resolver before starting out own in case it's an old one 2012-06-27 01:02:53 +02:00
Leo Franchi
5640923d51 Don't assert on quit anymore, served its debug purpose 2012-06-27 01:02:53 +02:00
Leo Franchi
4a2ef91638 Looks like paths with spaces need to be esaped everywhere with QProcess... 2012-06-27 01:02:53 +02:00
Christian Muehlhaeuser
012556ca0a * Resolve dupe accelerator assignment. 2012-06-27 01:01:20 +02:00
Christian Muehlhaeuser
8d0a51cc64 * Updated ChangeLog. 2012-06-27 00:12:59 +02:00
Leo Franchi
253120a35c We no longer remove accounts when uninstalling from attica 2012-06-27 00:12:59 +02:00
Leo Franchi
671bd5361b Always re-install spotify resolver if path is no longer valid 2012-06-27 00:12:59 +02:00
Leo Franchi
3dc969a31f Style fix 2012-06-27 00:12:59 +02:00
Christian Muehlhaeuser
64a70f5073 * Don't accept empty queries from web API. 2012-06-27 00:12:59 +02:00
Christian Muehlhaeuser
1911d4b8a0 * Assert when trying to setup a query without artist or track. 2012-06-27 00:12:59 +02:00
Christian Muehlhaeuser
92229ce3e2 * Call wipeIndex via a single-shot timer to avoid dead-locks. 2012-06-27 00:12:59 +02:00
Christian Muehlhaeuser
7df3f867ea * Re-bind values for failed TomahawkSqlQueries. 2012-06-27 00:12:59 +02:00
Jeff Mitchell
6e66c4a192 Revert "See if this fixes lfranchi's assert"
This reverts commit e6af7b03d7.

Conflicts:

	src/libtomahawk/database/DatabaseImpl.cpp
2012-06-27 00:12:58 +02:00
Christian Muehlhaeuser
49fe0f945e * Elide temporary page's text when showing the delete button. 2012-06-26 05:57:25 +02:00
Christian Muehlhaeuser
0d915513b9 * Spit out error messages when we couldn't resolve a track, album or artist. 2012-06-26 05:57:25 +02:00
Christian Muehlhaeuser
6c69edd0e7 * Remove spinner when AudioEngine stopped. 2012-06-26 05:57:25 +02:00
Christian Muehlhaeuser
23c2c77869 * Style cleanup. 2012-06-26 05:57:25 +02:00
Christian Muehlhaeuser
cd7c64ac0a * Set m_finished when tracks are loaded in Artist- & AlbumPlaylistInterface. 2012-06-26 05:57:25 +02:00
Christian Muehlhaeuser
0637ee7338 * Added a isFinished and m_finished to PlaylistInterface. 2012-06-26 05:57:25 +02:00
Christian Muehlhaeuser
7765aa116b * Auto re-prepare query on weird 'no query' error. 2012-06-26 05:57:25 +02:00
Christian Muehlhaeuser
c46ed53930 * Don't scale now playing icon decoration when expanding a playlist item. 2012-06-26 05:57:25 +02:00
Christian Muehlhaeuser
22105d448a * Don't expand LovedTracksItem. 2012-06-26 05:57:25 +02:00
Christian Muehlhaeuser
4f4efdfbab * Use new RecentlyPlayedModel API. 2012-06-26 05:55:22 +02:00
Christian Muehlhaeuser
686730e27c * Use new Recently- Played/Added -Model's API. 2012-06-26 05:55:22 +02:00
Christian Muehlhaeuser
fdfe4d12d4 * Split up CTOR and setSource methods. 2012-06-26 05:55:22 +02:00
Christian Muehlhaeuser
669e7550f2 * Split up CTOR and setSource methods. 2012-06-26 05:55:22 +02:00
Christian Muehlhaeuser
d4a2294963 * Show loading spinner when loading charts. 2012-06-26 05:55:22 +02:00
Christian Muehlhaeuser
66b0ecc846 * Show a loading spinner when loading a collection. 2012-06-26 05:55:22 +02:00
Christian Muehlhaeuser
c3563a2449 * Remove comments. 2012-06-26 05:55:22 +02:00
Christian Muehlhaeuser
05efe29a67 * Don't show an info button for empty items. 2012-06-26 05:55:22 +02:00
Christian Muehlhaeuser
3480690479 * Automatically adjust crash-reporter's window size. 2012-06-26 05:55:22 +02:00
Christian Muehlhaeuser
a1fb66e024 * Don't reset current viewpage when the new page is the same as the current one. 2012-06-26 05:55:22 +02:00
Christian Muehlhaeuser
02e9f99ce4 * Make sure script-resolvers are executable before trying to execute them. 2012-06-26 05:55:22 +02:00
Christian Muehlhaeuser
95c74fe370 * Re-center play/pause buttons when resizing GridView. 2012-06-26 05:55:22 +02:00
Christian Muehlhaeuser
358226bdb1 * No need to manuall set fake query's results. 2012-06-26 05:52:54 +02:00
Christian Muehlhaeuser
a2d81d0099 * Respond to pings from external resolver. 2012-06-26 05:52:54 +02:00
Christian Muehlhaeuser
292e97fcee * Don't show resolver errors when built with RelWithDebInfo. 2012-06-26 05:52:53 +02:00
Christian Muehlhaeuser
6dafcf3c80 * Temporary fix for compiling madness. 2012-06-26 05:52:53 +02:00
Tomahawk CI
ee1b13aee6 Automatic merge of Transifex translations 2012-06-26 05:52:53 +02:00
Christian Muehlhaeuser
ce8eecd40f * Fixed compiling on Windows. I hope. 2012-06-26 05:52:53 +02:00
Christian Muehlhaeuser
f674b3b751 * Style cleanup. 2012-06-26 05:52:53 +02:00
Jeff Mitchell
44cd64a8b6 Add ChangeLog entries 2012-06-26 05:52:53 +02:00
Christian Muehlhaeuser
a9418fc8aa * Fixed OSX linking. 2012-06-26 05:50:57 +02:00
Christian Muehlhaeuser
44546763b9 * Fixed Windows includes. 2012-06-26 05:50:57 +02:00
Christian Muehlhaeuser
66a74ad6e2 * Fixed compiling on OSX. 2012-06-26 05:50:57 +02:00
Christian Muehlhaeuser
6aae2dd96f * Updated breakpad to latest version. 2012-06-26 05:50:56 +02:00
Christian Muehlhaeuser
ffd2cee2ff * Mutex protect logging. 2012-06-26 05:50:56 +02:00
Christian Muehlhaeuser
438f8444c3 * Init Database earlier. 2012-06-26 05:50:56 +02:00
Christian Muehlhaeuser
b55be311b4 * While not a bug, this shutdown check would have never been triggered. 2012-06-26 05:50:56 +02:00
Tomahawk CI
7a4d113af6 Automatic merge of Transifex translations 2012-06-26 05:50:56 +02:00
356 changed files with 18381 additions and 12509 deletions

View File

@@ -13,7 +13,7 @@ SET( TOMAHAWK_DESCRIPTION_SUMMARY "The social media player" )
SET( TOMAHAWK_VERSION_MAJOR 0 )
SET( TOMAHAWK_VERSION_MINOR 5 )
SET( TOMAHAWK_VERSION_PATCH 0 )
SET( TOMAHAWK_VERSION_PATCH 5 )
#SET( TOMAHAWK_VERSION_RC 0 )
@@ -35,8 +35,11 @@ IF( CMAKE_SYSTEM_PROCESSOR MATCHES "arm" )
ENDIF()
# add definitions based on build options
IF(WITH_BREAKPAD)
IF( WITH_BREAKPAD )
message(STATUS "Build with support for breakpad.")
IF( CMAKE_COMPILER_IS_GNUCXX )
ADD_DEFINITIONS( -DSTDC_HEADERS -std=gnu++98 )
ENDIF()
ENDIF()
# generate version string
@@ -101,8 +104,8 @@ if(PHONON_FOUND)
message(STATUS "Phonon found; ensure that phonon-vlc is at least 0.4")
endif()
macro_optional_find_package(LibEchonest 1.2.1)
macro_log_feature(LIBECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest 1.2.1 is needed for dynamic playlists and the infosystem")
macro_optional_find_package(Echonest 2.0.0)
macro_log_feature(ECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest 2.0.0 is needed for dynamic playlists and the infosystem")
macro_optional_find_package(CLucene 0.9.23)
macro_log_feature(CLucene_FOUND "CLucene" "The open-source, C++ search engine" "http://clucene.sf.net" TRUE "" "CLucene is used for indexing the collection")
@@ -157,8 +160,8 @@ SET( LIBPORTFWD_LIBRARIES ${LIBPORTFWD_LIBRARY} )
ADD_SUBDIRECTORY( ${THIRDPARTY_DIR}/libportfwd )
# we need pthreads too
#macro_optional_find_package(Threads)
#macro_log_feature(THREADS_FOUND "Threads" "Threading Library" "" TRUE "" "Platform specific library for threading")
macro_optional_find_package(Threads)
macro_log_feature(THREADS_FOUND "Threads" "Threading Library" "" TRUE "" "Platform specific library for threading")
macro_optional_find_package(KDE4)
macro_optional_find_package(KDE4Installed)

View File

@@ -0,0 +1,36 @@
# - Find libechonest
# Find the libechonest includes and the libechonest libraries
# This module defines
# ECHONEST_INCLUDE_DIR, root echonest include dir. Include echonest includes with echonest/foo.h
# ECHONEST_LIBRARIES, the path to libechonest
# ECHONEST_FOUND, whether libechonest was found
FIND_PACKAGE(PkgConfig QUIET)
PKG_CHECK_MODULES(PC_ECHONEST QUIET libechonest)
FIND_PATH(ECHONEST_INCLUDE_DIR NAMES echonest/Track.h
HINTS
${PC_ECHONEST_INCLUDEDIR}
${PC_ECHONEST_INCLUDE_DIRS}
${CMAKE_INSTALL_INCLUDEDIR}
${KDE4_INCLUDE_DIR}
)
FIND_LIBRARY(ECHONEST_LIBRARIES NAMES echonest
HINTS
${PC_ECHONEST_LIBDIR}
${PC_ECHONEST_LIBRARY_DIRS}
${CMAKE_INSTALL_LIBDIR}
${KDE4_LIB_DIR}
)
IF(ECHONEST_LIBRARIES AND ECHONEST_INCLUDE_DIR AND NOT PC_ECHONEST_VERSION)
MESSAGE(WARNING "You don't have pkg-config and so the libechonest version check does not work!")
ENDIF()
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Echonest
REQUIRED_VARS ECHONEST_LIBRARIES ECHONEST_INCLUDE_DIR
VERSION_VAR PC_ECHONEST_VERSION)
MARK_AS_ADVANCED(ECHONEST_INCLUDE_DIR ECHONEST_LIBRARIES)

View File

@@ -1,42 +0,0 @@
# - Find libechonest
# Find the libechonest includes and the libechonest libraries
# This module defines
# LIBECHONEST_INCLUDE_DIR, root echonest include dir. Include echonest includes with echonest/foo.h
# LIBECHONEST_LIBRARY, the path to libechonest
# LIBECHONEST_FOUND, whether libechonest was found
find_path(LIBECHONEST_INCLUDE_DIR NAMES echonest_export.h
HINTS
~/usr/include
/opt/local/include
/usr/include
/usr/local/include
/opt/kde4/include
${KDE4_INCLUDE_DIR}
PATH_SUFFIXES echonest
)
find_library( LIBECHONEST_LIBRARY NAMES echonest
PATHS
~/usr/lib
/opt/local/lib
/usr/lib
/usr/lib64
/usr/local/lib
/opt/kde4/lib
${KDE4_LIB_DIR}
)
if(LIBECHONEST_INCLUDE_DIR AND LIBECHONEST_LIBRARY)
set(LIBECHONEST_FOUND TRUE)
message(STATUS "Found libechonest: ${LIBECHONEST_INCLUDE_DIR}, ${LIBECHONEST_LIBRARY}")
else(LIBECHONEST_INCLUDE_DIR AND LIBECHONEST_LIBRARY)
set(LIBECHONEST_FOUND FALSE)
if (LIBECHONEST_FIND_REQUIRED)
message(FATAL_ERROR "Could NOT find required package libechonest")
endif(LIBECHONEST_FIND_REQUIRED)
endif(LIBECHONEST_INCLUDE_DIR AND LIBECHONEST_LIBRARY)
mark_as_advanced(LIBECHONEST_INCLUDE_DIR LIBECHONEST_LIBRARY)

View File

@@ -1,3 +1,40 @@
Version 0.5.5:
* Changed the Spotify config dialog to indicate when the user
is logged in.
* Fixed bug where the wrong avatar could be shown for a user.
* Fixed shortcuts not working in the global search field on OS X.
* Fixed The Echo Nest stations.
* Code-signed executable on OS X for GateKeeper.
* Fixed logging in to Spotify when pressing return in the config dialog.
* Fixed queue not auto-collapsing when playing the last track.
* Fixed bug where album listings would fail to show up.
* Improved stability.
* Fixed bug where it was not possible to drop a mixture of resolved
and unresolved tracks onto a playlist.
Version 0.5.4:
* Improved stability.
* Added support for Spotify album lookups.
* Fixed not always updating the database index after scanning.
* Fixed connection issue between Tomahawk peers.
Version 0.5.3:
* Fixed broken artist names when importing Last.fm playback history.
* Fixed crash when filtering collections.
Version 0.5.2:
* Fixed a crash when invalid results are coming back from a resolver or
are found in a playlist.
Version 0.5.1:
* Fixed a few issues with automatic downloading and launching
of the Spotify account.
* Show an error message when not able to resolve a requested song.
* Fixed a few crash and freeze issues.
* Better detection of local networks for the Local Network connector.
* Don't prompt for access permission for your own accounts.
* (OS X) Fixed not being able to connect to Last.fm.
Version 0.5.0:
* SOCKS5 proxy support improvements for resolvers and more.
* Initial Access Control support, allowing users to define who is able to
@@ -52,7 +89,7 @@ Version 0.4.0:
* Fixed bug where filter text would be one step behind filter value.
* Fixed bug where resolvers would enable themselves after auto-updating.
* Fixed occasional crash when dropping tracks onto New Station item.
* Added jump-to-current-track support for search results page.
* Added jump-to-current-track support for search results page.
* Fixed non-resolving tracks when dragging from album view.
* Fixed fetching album covers for albums with special characters.
* Show errors and continue gracefully when resolved audio is not available.
@@ -77,7 +114,7 @@ Version 0.4.0:
* Fixed out of sync Show/Hide menu items on OS X when hidden with cmd-h.
* Fixed /Volumes directory not showing up on OS X.
* Fixed startup crash on OS X.
Version 0.3.3:
* Automatically load Super Collection tracks when no official release
information is available.
@@ -89,7 +126,7 @@ Version 0.3.3:
* Fixed dupe menu entry appearing on OS X.
* Fixed invisible sidebar items on Linux.
Version 0.3.2:
Version 0.3.2:
* Improved syncing process, it's faster and more reliable now.
* Fixed UPnP issues.
* Fixed not updating collections and views after a collection changes.
@@ -143,7 +180,7 @@ Version 0.3.0:
* Added YouTube resolver.
* Fixed bug where going offline then online would not re-connect to many
peers.
* Added support for auto-updating live XSPF playlists.
* Added support for auto-updating live XSPF playlists.
* Don't show an age of 41 years for tracks that have no age information.
* Show config UI for resolvers that have them as soon as you add them.
* Add support for Echo Nest Personal Catalogs and User Radio. Synchronize

2
README
View File

@@ -34,7 +34,7 @@ Dependencies
TagLib 1.6.2 - http://developer.kde.org/~wheeler/taglib.html
Boost 1.3 - http://www.boost.org/
CLucene 0.9.23 (0.9.21 will fail) - http://clucene.sourceforge.net/download.shtml
libechonest 1.2.1 - http://projects.kde.org/projects/playground/libs/libechonest/
libechonest 2.0.0 - http://projects.kde.org/projects/playground/libs/libechonest/
Attica 0.4.0 - ftp://ftp.kde.org/pub/kde/stable/attica/
QuaZip 0.4.3 - http://quazip.sourceforge.net/

View File

@@ -45,6 +45,9 @@ VERSION=$1
header "Creating DMG"
cd ..
header "Signing bundle"
codesign -s "Developer ID Application: Leonardo Franchi" -f -v ./Tomahawk.app
$ROOT/../admin/mac/create-dmg.sh Tomahawk.app
mv Tomahawk.dmg Tomahawk-$VERSION.dmg

View File

@@ -28,9 +28,6 @@ FRAMEWORK_SEARCH_PATH=[
LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/Cellar/gettext/0.18.1.1/lib', '.']
LIBSPOTIFY_VERSION = commands.getoutput("brew ls -version libspotify | tr -s \" \" \"\\\\012\" | tail -n 1").strip()
LIBSPOTIFY_PATH = "/usr/local/lib/libspotify.%s.dylib" % LIBSPOTIFY_VERSION
VLC_PLUGINS=[
'libaccess_attachment_plugin.dylib',
#'libaccess_avio_plugin.dylib',
@@ -512,11 +509,6 @@ try:
except:
print 'Failed to find tomahawk_crash_reporter'
try:
FixPlugin(LIBSPOTIFY_PATH, "../Frameworks")
except:
print "Failed to copy libspotify from os: %s" % LIBSPOTIFY_PATH
for plugin in QT_PLUGINS:
FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin))

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -85,7 +85,7 @@ AudioControls::AudioControls( QWidget* parent )
ui->socialButton->setPixmap( RESPATH "images/share.png" );
ui->loveButton->setPixmap( RESPATH "images/not-loved.png" );
ui->loveButton->setCheckable( true );
ui->socialButton->setFixedSize( QSize( 20, 20 ) );
ui->loveButton->setFixedSize( QSize( 20, 20 ) );
@@ -352,7 +352,7 @@ AudioControls::onPlaybackStopped()
ui->ownerLabel->setText( "" );
ui->timeLabel->setText( "" );
ui->timeLeftLabel->setText( "" );
ui->coverImage->setPixmap( QPixmap(), true );
ui->coverImage->setPixmap( QPixmap(), false );
ui->seekSlider->setVisible( false );
m_sliderTimeLine.stop();
m_sliderTimeLine.setCurrentTime( 0 );
@@ -588,7 +588,7 @@ AudioControls::droppedTracks( QList< query_ptr > tracks )
{
// queue and play the first no matter what
GlobalActionManager::instance()->handlePlayTrack( tracks.first() );
ViewManager::instance()->queue()->model()->append( tracks );
ViewManager::instance()->queue()->model()->appendQueries( tracks );
}
}

View File

@@ -113,8 +113,7 @@ INCLUDE_DIRECTORIES(
${PHONON_INCLUDES}
${QJSON_INCLUDE_DIR}
${LIBATTICA_INCLUDE_DIR}
${LIBECHONEST_INCLUDE_DIR}
${LIBECHONEST_INCLUDE_DIR}/..
${ECHONEST_INCLUDE_DIR}
${LIBLASTFM_INCLUDE_DIRS}
${LIBLASTFM_INCLUDE_DIRS}/..
)
@@ -129,6 +128,8 @@ IF( UNIX )
ENDIF( UNIX )
IF( APPLE )
SET( CMAKE_LINKER_FLAGS "-headerpad_max_install_names ${CMAKE_LINKER_FLAGS}" )
INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/thirdparty/SPMediaKeyTap )
SET( tomahawkSources ${tomahawkSources} mac/TomahawkApp_Mac.mm mac/MacShortcutHandler.cpp )
@@ -198,7 +199,7 @@ TARGET_LINK_LIBRARIES( tomahawk
${OS_SPECIFIC_LINK_LIBRARIES}
${QT_LIBRARIES}
${MAC_EXTRA_LIBS}
${LIBECHONEST_LIBRARY}
${ECHONEST_LIBRARIES}
${QXTWEB_LIBRARIES}
${QJSON_LIBRARIES}
${TAGLIB_LIBRARIES}

View File

@@ -22,10 +22,6 @@
#include "config.h"
#include "accounts/AccountManager.h"
#include "network/Servent.h"
#include "SourceList.h"
#include <QLabel>
#include <QTextEdit>
#include <QDialogButtonBox>
@@ -34,8 +30,13 @@
#include <QClipboard>
#include <QDebug>
#include "utils/Logger.h"
#include "accounts/AccountManager.h"
#include "network/Servent.h"
#include "SourceList.h"
#include "sip/SipHandler.h"
#include "utils/TomahawkUtilsGui.h"
#include "utils/Logger.h"
DiagnosticsDialog::DiagnosticsDialog( QWidget *parent )
@@ -44,11 +45,10 @@ DiagnosticsDialog::DiagnosticsDialog( QWidget *parent )
{
ui->setupUi( this );
connect( ui->clipboardButton, SIGNAL( clicked() ), this, SLOT( copyToClipboard() ) );
connect( ui->buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) );
connect( ui->clipboardButton, SIGNAL( clicked() ), SLOT( copyToClipboard() ) );
connect( ui->logfileButton, SIGNAL( clicked() ), SLOT( openLogfile() ) );
connect( ui->buttonBox, SIGNAL( rejected() ), SLOT( reject() ) );
ui->scrollAreaWidgetContents->setLayout( new QVBoxLayout() );
updateLogView();
}
@@ -58,16 +58,10 @@ DiagnosticsDialog::updateLogView()
{
QString log;
log.append(
QString("TOMAHAWK DIAGNOSTICS LOG -%1 \n\n")
.arg( QDateTime::currentDateTime().toString() )
);
// network
log.append( QString( "TOMAHAWK DIAGNOSTICS LOG -%1 \n\n" ).arg( QDateTime::currentDateTime().toString() ) );
log.append( "TOMAHAWK-VERSION: " TOMAHAWK_VERSION "\n\n" );
// network
log.append( "NETWORK:\n General:\n" );
if ( Servent::instance()->visibleExternally() )
{
log.append(
@@ -86,10 +80,8 @@ DiagnosticsDialog::updateLogView()
log.append( " visible: false" );
}
ui->scrollAreaWidgetContents->layout()->addWidget( new QLabel( log, this ) );
// Peers / Accounts, TODO
ui->scrollAreaWidgetContents->layout()->addWidget( new QLabel( "ACCOUNTS:\n", this ) );
log.append( "ACCOUNTS:\n" );
const QList< Tomahawk::source_ptr > sources = SourceList::instance()->sources( true );
const QList< Tomahawk::Accounts::Account* > accounts = Tomahawk::Accounts::AccountManager::instance()->accounts( Tomahawk::Accounts::SipType );
foreach ( Tomahawk::Accounts::Account* account, accounts )
@@ -98,165 +90,98 @@ DiagnosticsDialog::updateLogView()
if ( !account || !account->sipPlugin() )
continue;
connect( account, SIGNAL( connectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ),
SLOT( onAccountConnectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ) );
connect( account, SIGNAL( error( int, QString ) ),
SLOT( onAccountError( int, QString ) ) );
connect( account, SIGNAL( connectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
connect( account, SIGNAL( error( int, QString ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
connect( account->sipPlugin(), SIGNAL( peerOnline( QString ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
connect( account->sipPlugin(), SIGNAL( peerOffline( QString ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
connect( account->sipPlugin(), SIGNAL( sipInfoReceived( QString, SipInfo ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
connect( account->sipPlugin(), SIGNAL( softwareVersionReceived( QString, QString ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
connect( account->sipPlugin(), SIGNAL( peerOnline( QString ) ), SLOT( onPeerOnline( QString ) ) );
connect( account->sipPlugin(), SIGNAL( peerOffline( QString ) ), SLOT( onPeerOffline( QString ) ) );
connect( account->sipPlugin(), SIGNAL( sipInfoReceived( QString, SipInfo ) ), SLOT( onSipInfoReceived( QString, SipInfo ) ) );
connect( account->sipPlugin(), SIGNAL( softwareVersionReceived( QString, QString ) ), SLOT( onSoftwareVersionReceived( QString, QString ) ) );
QLabel* accountInfoLabel = new QLabel( this );
ui->scrollAreaWidgetContents->layout()->addWidget( accountInfoLabel );
m_accountDescriptionStore.insert( account, accountInfoLabel );
updateAccountLabel( account );
log.append( accountLog( account ) + "\n" );
}
ui->text->setText( log );
}
void
DiagnosticsDialog::copyToClipboard()
{
QString log;
foreach ( QLabel* label, m_accountDescriptionStore.values() )
QApplication::clipboard()->setText( ui->text->toPlainText() );
}
void
DiagnosticsDialog::openLogfile()
{
TomahawkUtils::openUrl( Logger::logFile() );
}
QString
DiagnosticsDialog::accountLog( Tomahawk::Accounts::Account* account )
{
QString accountInfo;
QString stateString;
switch( account->connectionState() )
{
log += label->text() + "\n\n";
case Tomahawk::Accounts::Account::Connecting:
stateString = "Connecting";
break;
case Tomahawk::Accounts::Account::Connected:
stateString = "Connected";
break;
case Tomahawk::Accounts::Account::Disconnected:
stateString = "Disconnected";
break;
case Tomahawk::Accounts::Account::Disconnecting:
stateString = "Disconnecting";
}
accountInfo.append(
QString( " %2 (%1): %3 (%4)\n" )
.arg( account->accountServiceName() )
.arg( account->sipPlugin()->friendlyName() )
.arg( account->accountFriendlyName())
.arg( stateString )
);
QApplication::clipboard()->setText( log );
}
void
DiagnosticsDialog::onAccountConnectionStateChanged( Tomahawk::Accounts::Account::ConnectionState /* state */ )
{
Tomahawk::Accounts::Account* account = qobject_cast< Tomahawk::Accounts::Account* >( sender() );
Q_ASSERT( account );
updateAccountLabel( account );
}
void
DiagnosticsDialog::onAccountError( int /* errorId */ , QString /* errorString */ )
{
Tomahawk::Accounts::Account* account = qobject_cast< Tomahawk::Accounts::Account* >( sender() );
Q_ASSERT( account );
}
void
DiagnosticsDialog::onPeerOnline( const QString& )
{
Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account();
Q_ASSERT( account );
updateAccountLabel( account );
}
void
DiagnosticsDialog::onPeerOffline( const QString& )
{
Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account();
Q_ASSERT( account );
updateAccountLabel( account );
}
void
DiagnosticsDialog::onSipInfoReceived( const QString& /* peerId */ , const SipInfo& /* info */ )
{
Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account();
Q_ASSERT( account );
updateAccountLabel( account );
}
void
DiagnosticsDialog::onSoftwareVersionReceived( const QString& /* peerId */ , const QString& /* versionString */ )
{
Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account();
Q_ASSERT( account );
updateAccountLabel( account );
}
void
DiagnosticsDialog::updateAccountLabel( Tomahawk::Accounts::Account* account )
{
QLabel* accountInfoLabel = m_accountDescriptionStore.value( account );
if ( accountInfoLabel )
foreach( const QString& peerId, account->sipPlugin()->peersOnline() )
{
QString accountInfo;
QString stateString;
switch( account->connectionState() )
QString versionString = SipHandler::instance()->versionString( peerId );
SipInfo sipInfo = SipHandler::instance()->sipInfo( peerId );
if ( !sipInfo.isValid() )
{
case Tomahawk::Accounts::Account::Connecting:
stateString = "Connecting";
break;
case Tomahawk::Accounts::Account::Connected:
stateString = "Connected";
break;
case Tomahawk::Accounts::Account::Disconnected:
stateString = "Disconnected";
break;
case Tomahawk::Accounts::Account::Disconnecting:
stateString = "Disconnecting";
accountInfo.append(
QString(" %1: %2 %3" /*"(%4)"*/ "\n")
.arg( peerId )
.arg( "sipinfo invalid" )
.arg( versionString )
// .arg( connected ? "connected" : "not connected")
);
}
accountInfo.append(
QString( " %2 (%1): %3 (%4)\n" )
.arg( account->accountServiceName() )
.arg( account->sipPlugin()->friendlyName() )
.arg( account->accountFriendlyName())
.arg( stateString )
);
foreach( const QString& peerId, account->sipPlugin()->peersOnline() )
else if ( sipInfo.isVisible() )
{
QString versionString = SipHandler::instance()->versionString( peerId );
SipInfo sipInfo = SipHandler::instance()->sipInfo( peerId );
if ( !sipInfo.isValid() )
{
accountInfo.append(
QString(" %1: %2 %3" /*"(%4)"*/ "\n")
.arg( peerId )
.arg( "sipinfo invalid" )
.arg( versionString )
// .arg( connected ? "connected" : "not connected")
);
}
else if ( sipInfo.isVisible() )
{
accountInfo.append(
QString(" %1: %2:%3 %4" /*" (%5)"*/ "\n")
.arg( peerId )
.arg( sipInfo.host().hostName() )
.arg( sipInfo.port() )
.arg( versionString )
// .arg( connected ? "connected" : "not connected")
);
}
else
{
accountInfo.append(
QString(" %1: visible: false %2" /*" (%3)"*/ "\n")
.arg( peerId )
.arg( versionString )
// .arg( connected ? "connected" : "not connected")
);
}
accountInfo.append(
QString(" %1: %2:%3 %4" /*" (%5)"*/ "\n")
.arg( peerId )
.arg( sipInfo.host() )
.arg( sipInfo.port() )
.arg( versionString )
// .arg( connected ? "connected" : "not connected")
);
}
else
{
accountInfo.append(
QString(" %1: visible: false %2" /*" (%3)"*/ "\n")
.arg( peerId )
.arg( versionString )
// .arg( connected ? "connected" : "not connected")
);
}
accountInfo.append( "\n" );
accountInfoLabel->setText( accountInfo );
}
accountInfo.append( "\n" );
return accountInfo;
}

View File

@@ -45,19 +45,11 @@ public:
private slots:
void updateLogView();
void copyToClipboard();
void onAccountConnectionStateChanged( Tomahawk::Accounts::Account::ConnectionState state );
void onAccountError( int errorId, QString errorString );
void onPeerOnline( const QString& );
void onPeerOffline( const QString& );
void onSipInfoReceived( const QString& peerId, const SipInfo& info );
void onSoftwareVersionReceived( const QString& peerId, const QString& versionString );
void openLogfile();
QString accountLog( Tomahawk::Accounts::Account* );
void updateAccountLabel( Tomahawk::Accounts::Account* );
private:
QMap< Tomahawk::Accounts::Account*, QLabel* > m_accountDescriptionStore;
Ui::DiagnosticsDialog* ui;
};

View File

@@ -26,20 +26,10 @@
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
<widget class="QTextBrowser" name="text">
<property name="lineWrapMode">
<enum>QTextEdit::NoWrap</enum>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>708</width>
<height>386</height>
</rect>
</property>
</widget>
</widget>
</item>
</layout>
@@ -49,7 +39,14 @@
<item>
<widget class="QPushButton" name="clipboardButton">
<property name="text">
<string>Copy to Clipboard</string>
<string>&amp;Copy to Clipboard</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="logfileButton">
<property name="text">
<string>Open &amp;Log-file</string>
</property>
</widget>
</item>

View File

@@ -208,6 +208,7 @@ MusicScanner::listerFinished()
if ( m_filesToDelete.length() || m_scannedfiles.length() )
{
SourceList::instance()->getLocal()->updateIndexWhenSynced();
commitBatch( m_scannedfiles, m_filesToDelete );
m_scannedfiles.clear();
m_filesToDelete.clear();
@@ -335,7 +336,7 @@ MusicScanner::readFile( const QFileInfo& fi )
int bitrate = 0;
int duration = 0;
Tag *tag = Tag::fromFile( f );
if ( f.audioProperties() )
{

View File

@@ -200,7 +200,7 @@ TomahawkApp::init()
QFontMetrics fm( f );
TomahawkUtils::setHeaderHeight( fm.height() + 8 );
#endif
TomahawkUtils::setHeadless( m_headless );
TomahawkSettings* s = TomahawkSettings::instance();
@@ -210,11 +210,18 @@ TomahawkApp::init()
Q_UNUSED( TomahawkUtils::nam() );
m_audioEngine = QWeakPointer<AudioEngine>( new AudioEngine );
m_scanManager = QWeakPointer<ScanManager>( new ScanManager( this ) );
// init pipeline and resolver factories
new Pipeline();
m_servent = QWeakPointer<Servent>( new Servent( this ) );
connect( m_servent.data(), SIGNAL( ready() ), SLOT( initSIP() ) );
tDebug() << "Init Database.";
initDatabase();
m_scanManager = QWeakPointer<ScanManager>( new ScanManager( this ) );
#ifndef ENABLE_HEADLESS
Pipeline::instance()->addExternalResolverFactory( boost::bind( &QtScriptResolver::factory, _1 ) );
Pipeline::instance()->addExternalResolverFactory( boost::bind( &ScriptResolver::factory, _1 ) );
@@ -223,12 +230,6 @@ TomahawkApp::init()
connect( ActionCollection::instance()->getAction( "quit" ), SIGNAL( triggered() ), SLOT( quit() ), Qt::UniqueConnection );
#endif
m_servent = QWeakPointer<Servent>( new Servent( this ) );
connect( m_servent.data(), SIGNAL( ready() ), SLOT( initSIP() ) );
tDebug() << "Init Database.";
initDatabase();
QByteArray magic = QByteArray::fromBase64( enApiSecret );
QByteArray wand = QByteArray::fromBase64( QCoreApplication::applicationName().toLatin1() );
int length = magic.length(), n2 = wand.length();
@@ -359,35 +360,48 @@ TomahawkApp::~TomahawkApp()
if ( !m_session.isNull() )
delete m_session.data();
tLog() << "Deleting connector";
if ( !m_connector.isNull() )
delete m_connector.data();
tLog() << "Stopping pipeline";
if ( Pipeline::instance() )
Pipeline::instance()->stop();
tLog() << "Deleting servent";
if ( !m_servent.isNull() )
delete m_servent.data();
tLog() << "Deleting ScanManager";
if ( !m_scanManager.isNull() )
delete m_scanManager.data();
tLog() << "Deleting AudioEngine";
if ( !m_audioEngine.isNull() )
delete m_audioEngine.data();
tLog() << "Deleting AccountManager";
delete Tomahawk::Accounts::AccountManager::instance();
delete TomahawkUtils::Cache::instance();
#ifndef ENABLE_HEADLESS
delete m_mainwindow;
tLog() << "Deleting AtticaManager";
delete AtticaManager::instance();
tLog() << "Deleting Window";
delete m_mainwindow;
#endif
tLog() << "Deleting database";
if ( !m_database.isNull() )
delete m_database.data();
tLog() << "Deleting Pipeline";
delete Pipeline::instance();
tLog() << "Deleting InfoSystem";
if ( !m_infoSystem.isNull() )
delete m_infoSystem.data();
tLog() << "Deleting Cache";
delete TomahawkUtils::Cache::instance();
tLog() << "Finished shutdown.";
}

View File

@@ -59,10 +59,10 @@ public slots:
void disconnectPlugin();
void configurationChanged();
void sendMsg( const QString& to, const QString& msg )
void sendMsg( const QString& peerId, const SipInfo& info )
{
Q_UNUSED( to );
Q_UNUSED( msg );
Q_UNUSED( peerId );
Q_UNUSED( info );
}
void broadcastMsg( const QString &msg )
@@ -70,9 +70,9 @@ public slots:
Q_UNUSED( msg );
}
void addContact( const QString &jid, const QString& msg = QString() )
void addContact( const QString &peerId, const QString& msg = QString() )
{
Q_UNUSED( jid );
Q_UNUSED( peerId );
Q_UNUSED( msg );
}

View File

@@ -73,6 +73,11 @@ AvatarManager::fetchVCard( const QString& jid )
void
AvatarManager::onNewPresence( const Jreen::Presence& presence )
{
if ( presence.error() )
{
return;
}
Jreen::VCardUpdate::Ptr update = presence.payload<Jreen::VCardUpdate>();
if ( update )
{

View File

@@ -110,7 +110,7 @@ XmppSipPlugin::XmppSipPlugin( Account* account )
Jreen::JID jid = Jreen::JID( readUsername() );
// general client setup
m_client = new Jreen::Client( jid, m_currentPassword );
m_client = new Jreen::Client( jid, m_currentPassword );
setupClientHelper();
m_client->registerPayload( new TomahawkXmppMessageFactory );
@@ -425,32 +425,17 @@ XmppSipPlugin::errorMessage( Jreen::Client::DisconnectReason reason )
void
XmppSipPlugin::sendMsg( const QString& to, const QString& msg )
XmppSipPlugin::sendMsg( const QString& to, const SipInfo& info )
{
qDebug() << Q_FUNC_INFO << to << msg;
qDebug() << Q_FUNC_INFO << to << info;
if ( !m_client )
return;
/*******************************************************
* Obsolete this by a SipMessage class
*/
QJson::Parser parser;
bool ok;
QVariant v = parser.parse( msg.toAscii(), &ok );
if ( !ok || v.type() != QVariant::Map )
{
qDebug() << "Invalid JSON in Xmpp msg";
return;
}
QVariantMap m = v.toMap();
/*******************************************************/
TomahawkXmppMessage *sipMessage;
if ( m["visible"].toBool() )
if ( info.isVisible() )
{
sipMessage = new TomahawkXmppMessage( m["ip"].toString(), m["port"].toInt(), m["uniqname"].toString(), m["key"].toString() );
sipMessage = new TomahawkXmppMessage( info.host(), info.port(), info.uniqname(), info.key() );
}
else
sipMessage = new TomahawkXmppMessage();
@@ -467,13 +452,6 @@ XmppSipPlugin::sendMsg( const QString& to, const QString& msg )
void
XmppSipPlugin::broadcastMsg( const QString& msg )
{
if ( !m_client )
return;
foreach ( const Jreen::JID& jid, m_peers.keys() )
{
sendMsg( jid.full(), msg );
}
}
@@ -914,9 +892,7 @@ XmppSipPlugin::onNewIq( const Jreen::IQ& iq )
info.setVisible( sipMessage->visible() );
if ( sipMessage->visible() )
{
QHostInfo hi;
hi.setHostName( sipMessage->ip() );
info.setHost( hi );
info.setHost( sipMessage->ip() );
info.setPort( sipMessage->port() );
info.setUniqname( sipMessage->uniqname() );
info.setKey( sipMessage->key() );

View File

@@ -86,8 +86,8 @@ public slots:
virtual void disconnectPlugin();
virtual void checkSettings();
virtual void configurationChanged();
virtual void sendMsg( const QString& to, const QString& msg );
virtual void addContact( const QString& jid, const QString& msg = QString() );
virtual void sendMsg( const QString& peerId, const SipInfo& info );
virtual void addContact( const QString& peerId, const QString& msg = QString() );
void broadcastMsg( const QString& msg );
void showAddFriendDialog();

View File

@@ -64,7 +64,7 @@ public slots:
void advertise();
void sendMsg( const QString& , const QString& ) {}
void sendMsg( const QString& peerId , const SipInfo& ) {}
void broadcastMsg( const QString & ) {}
void addContact( const QString &, const QString& ) {}

View File

@@ -66,17 +66,17 @@ CrashReporter::CrashReporter( const QStringList& args )
m_minidump = m_dir + '/' + args.value( 2 ) + ".dmp";
m_product_name = args.value( 3 );
setFixedSize( sizeHint() );
//hide until "send report" has been clicked
ui.progressBar->setVisible( false );
ui.button->setVisible( false );
ui.progressLabel->setVisible( false );
connect( ui.sendButton, SIGNAL( clicked() ), SLOT( onSendButton() ));
connect( ui.sendButton, SIGNAL( clicked() ), SLOT( onSendButton() ) );
adjustSize();
setFixedSize( size() );
}
CrashReporter::~CrashReporter()
{
delete m_http;
@@ -186,6 +186,7 @@ CrashReporter::onFail( int error, const QString& errorString )
qDebug() << "Error:" << error << errorString;
}
void
CrashReporter::onSendButton()
{
@@ -194,5 +195,9 @@ CrashReporter::onSendButton()
ui.progressLabel->setVisible( true );
ui.sendButton->setEnabled( false );
ui.dontSendButton->setEnabled( false );
adjustSize();
setFixedSize( size() );
QTimer::singleShot( 0, this, SLOT( send() ) );
}

View File

@@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>438</width>
<height>246</height>
<width>376</width>
<height>216</height>
</rect>
</property>
<property name="sizePolicy">

View File

@@ -1,4 +1,4 @@
include_directories(${LIBECHONEST_INCLUDE_DIR})
include_directories(${ECHONEST_INCLUDE_DIR})
list(APPEND simple_plugins
Echonest

View File

@@ -109,7 +109,7 @@ FdoNotifyPlugin::notifyUser( const QString &messageText )
arguments << quint32( 0 ); //notification_id
arguments << QString(); //app_icon
arguments << QString( "Tomahawk" ); //summary
arguments << messageText; //body
arguments << QString( messageText ); //body
arguments << QStringList(); //actions
QVariantMap dict;
dict["desktop-entry"] = QString( "tomahawk" );

View File

@@ -174,17 +174,21 @@ Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData,
return;
}
if ( !output.isNull() && output.isValid() )
if ( output.isNull() )
{
m_coverLoaded = true;
}
else if ( output.isValid() )
{
QVariantMap returnedData = output.value< QVariantMap >();
const QByteArray ba = returnedData["imgbytes"].toByteArray();
if ( ba.length() )
{
m_coverBuffer = ba;
emit coverChanged();
}
m_coverLoaded = true;
emit coverChanged();
}
}
@@ -237,6 +241,6 @@ Album::infoid() const
{
if ( m_uuid.isEmpty() )
m_uuid = uuid();
return m_uuid;
}

View File

@@ -114,13 +114,17 @@ AlbumPlaylistInterface::tracks()
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
SIGNAL( finished( QString ) ),
SLOT( infoSystemFinished( QString ) ) );
}
else if ( m_mode == DatabaseMode && !m_databaseLoaded )
{
DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( m_collection );
cmd->setAlbum( m_album );
cmd->setSortOrder( DatabaseCommand_AllTracks::AlbumPosition );
connect( cmd, SIGNAL( tracks( QList<Tomahawk::query_ptr>, QVariant ) ),
SLOT( onTracksLoaded( QList<Tomahawk::query_ptr> ) ) );
@@ -178,9 +182,24 @@ AlbumPlaylistInterface::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData re
}
}
if ( !m_queries.isEmpty() )
{
infoSystemFinished( id() );
}
}
void
AlbumPlaylistInterface::infoSystemFinished( const QString& infoId )
{
if ( infoId != id() )
return;
m_infoSystemLoaded = true;
disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
this, SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ),
this, SLOT( infoSystemFinished( QString ) ) );
if ( m_queries.isEmpty() && m_mode == Mixed )
{
@@ -188,7 +207,7 @@ AlbumPlaylistInterface::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData re
cmd->setAlbum( m_album );
//this takes discnumber into account as well
cmd->setSortOrder( DatabaseCommand_AllTracks::AlbumPosition );
connect( cmd, SIGNAL( tracks( QList<Tomahawk::query_ptr>, QVariant ) ),
SLOT( onTracksLoaded( QList<Tomahawk::query_ptr> ) ) );
@@ -196,6 +215,7 @@ AlbumPlaylistInterface::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData re
}
else
{
m_finished = true;
emit tracksLoaded( m_mode, m_collection );
}
}
@@ -212,5 +232,6 @@ AlbumPlaylistInterface::onTracksLoaded( const QList< query_ptr >& tracks )
else
m_queries << tracks;
m_finished = true;
emit tracksLoaded( m_mode, m_collection );
}

View File

@@ -64,6 +64,7 @@ signals:
private slots:
void onTracksLoaded( const QList< Tomahawk::query_ptr >& tracks );
void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
void infoSystemFinished( const QString& infoId );
private:
QList< Tomahawk::query_ptr > m_queries;

View File

@@ -315,16 +315,20 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari
case Tomahawk::InfoSystem::InfoArtistImages:
{
if ( !output.isNull() && output.isValid() )
if ( output.isNull() )
{
m_coverLoaded = true;
}
else if ( output.isValid() )
{
const QByteArray ba = returnedData["imgbytes"].toByteArray();
if ( ba.length() )
{
m_coverBuffer = ba;
emit coverChanged();
}
m_coverLoaded = true;
emit coverChanged();
}
break;
@@ -353,7 +357,7 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari
if ( source == "last.fm" )
m_biography = bmap[ source ].toHash()[ "text" ].toString();
}
m_biographyLoaded = true;
emit biographyLoaded();
@@ -459,7 +463,7 @@ Artist::playlistInterface( ModelMode mode, const Tomahawk::collection_ptr& colle
pli = Tomahawk::playlistinterface_ptr( new Tomahawk::ArtistPlaylistInterface( this, mode, collection ) );
connect( pli.data(), SIGNAL( tracksLoaded( Tomahawk::ModelMode, Tomahawk::collection_ptr ) ),
SLOT( onTracksLoaded( Tomahawk::ModelMode, Tomahawk::collection_ptr ) ) );
m_playlistInterface[ mode ][ collection ] = pli;
}
@@ -479,6 +483,6 @@ Artist::infoid() const
{
if ( m_uuid.isEmpty() )
m_uuid = uuid();
return m_uuid;
}

View File

@@ -112,13 +112,17 @@ ArtistPlaylistInterface::tracks()
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
SIGNAL( finished( QString ) ),
SLOT( infoSystemFinished( QString ) ) );
}
else if ( m_mode == DatabaseMode && !m_databaseLoaded )
{
DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( m_collection );
cmd->setArtist( m_artist );
cmd->setSortOrder( DatabaseCommand_AllTracks::AlbumPosition );
connect( cmd, SIGNAL( tracks( QList<Tomahawk::query_ptr>, QVariant ) ),
SLOT( onTracksLoaded( QList<Tomahawk::query_ptr> ) ) );
@@ -176,9 +180,23 @@ ArtistPlaylistInterface::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData r
}
}
if ( !m_queries.isEmpty() )
infoSystemFinished( id() );
}
void
ArtistPlaylistInterface::infoSystemFinished( const QString &infoId )
{
if ( infoId != id() )
return;
m_infoSystemLoaded = true;
disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
this, SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ),
this, SLOT( infoSystemFinished( QString) ) );
if ( m_queries.isEmpty() && m_mode == Mixed )
{
@@ -186,7 +204,7 @@ ArtistPlaylistInterface::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData r
cmd->setArtist( m_artist );
//this takes discnumber into account as well
cmd->setSortOrder( DatabaseCommand_AllTracks::AlbumPosition );
connect( cmd, SIGNAL( tracks( QList<Tomahawk::query_ptr>, QVariant ) ),
SLOT( onTracksLoaded( QList<Tomahawk::query_ptr> ) ) );
@@ -194,6 +212,7 @@ ArtistPlaylistInterface::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData r
}
else
{
m_finished = true;
emit tracksLoaded( m_mode, m_collection );
}
}
@@ -210,5 +229,6 @@ ArtistPlaylistInterface::onTracksLoaded( const QList< query_ptr >& tracks )
else
m_queries << tracks;
m_finished = true;
emit tracksLoaded( m_mode, m_collection );
}

View File

@@ -63,6 +63,7 @@ signals:
private slots:
void onTracksLoaded( const QList< Tomahawk::query_ptr >& tracks );
void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
void infoSystemFinished( const QString& infoId );
private:
Q_DISABLE_COPY( ArtistPlaylistInterface )

View File

@@ -31,6 +31,9 @@
#include <QTemporaryFile>
#include <QDir>
#include <QTimer>
#include <QDomDocument>
#include <QDomElement>
#include <QDomNode>
#include "utils/Logger.h"
#include "accounts/ResolverAccount.h"
@@ -64,7 +67,7 @@ AtticaManager::AtticaManager( QObject* parent )
// resolvers
// m_manager.addProviderFile( QUrl( "http://bakery.tomahawk-player.org/resolvers/providers.xml" ) );
const QString url = QString( "http://bakery.tomahawk-player.org/resolvers/providers.xml?version=%1" ).arg( TomahawkUtils::appFriendlyVersion() );
const QString url = QString( "%1/resolvers/providers.xml?version=%2" ).arg( hostname() ).arg( TomahawkUtils::appFriendlyVersion() );
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( QUrl( url ) ) );
NewClosure( reply, SIGNAL( finished() ), this, SLOT( providerFetched( QNetworkReply* ) ), reply );
connect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( providerError( QNetworkReply::NetworkError ) ) );
@@ -90,6 +93,12 @@ AtticaManager::~AtticaManager()
}
QString
AtticaManager::hostname() const
{
return "http://bakery.tomahawk-player.org";
}
void
AtticaManager::loadPixmapsFromCache()
{
@@ -523,14 +532,15 @@ void AtticaManager::doInstallResolver( const Content& resolver, bool autoCreate,
m_resolverStates[ resolver.id() ].version = resolver.version();
emit resolverStateChanged( resolver.id() );
ItemJob< DownloadItem >* job = m_resolverProvider.downloadLink( resolver.id() );
connect( job, SIGNAL( finished( Attica::BaseJob* ) ), this, SLOT( resolverDownloadFinished( Attica::BaseJob* ) ) );
job->setProperty( "resolverId", resolver.id() );
job->setProperty( "createAccount", autoCreate );
job->setProperty( "handler", QVariant::fromValue< QObject* >( handler ) );
job->setProperty( "binarySignature", resolver.attribute("signature"));
job->start();
// ItemJob< DownloadItem >* job = m_resolverProvider.downloadLink( resolver.id() );
QUrl url( QString( "%1/resolvers/v1/content/download/%2/1" ).arg( hostname() ).arg( resolver.id() ) );
url.addQueryItem( "tomahawkversion", TomahawkUtils::appFriendlyVersion() );
QNetworkReply* r = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
NewClosure( r, SIGNAL( finished() ), this, SLOT( resolverDownloadFinished( QNetworkReply* ) ), r );
r->setProperty( "resolverId", resolver.id() );
r->setProperty( "createAccount", autoCreate );
r->setProperty( "handler", QVariant::fromValue< QObject* >( handler ) );
r->setProperty( "binarySignature", resolver.attribute("signature"));
}
@@ -552,25 +562,49 @@ AtticaManager::upgradeResolver( const Content& resolver )
void
AtticaManager::resolverDownloadFinished ( BaseJob* j )
AtticaManager::resolverDownloadFinished ( QNetworkReply *j )
{
ItemJob< DownloadItem >* job = static_cast< ItemJob< DownloadItem >* >( j );
Q_ASSERT( j );
if ( !j )
return;
if ( job->metadata().error() == Attica::Metadata::NoError )
if ( j->error() == QNetworkReply::NoError )
{
DownloadItem item = job->result();
QUrl url = item.url();
// download the resolver itself :)
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
connect( reply, SIGNAL( finished() ), this, SLOT( payloadFetched() ) );
reply->setProperty( "resolverId", job->property( "resolverId" ) );
reply->setProperty( "createAccount", job->property( "createAccount" ) );
reply->setProperty( "handler", job->property( "handler" ) );
reply->setProperty( "binarySignature", job->property( "binarySignature" ) );
QDomDocument doc;
doc.setContent( j );
const QDomNodeList nodes = doc.documentElement().elementsByTagName( "downloadlink" );
if ( nodes.length() < 1 )
{
tLog() << "Found no download link for resolver:" << doc.toString();
return;
}
QUrl url( nodes.item( 0 ).toElement().text() );
// download the resolver itself :)
tDebug() << "Downloading resolver from url:" << url.toString();
const QDomNodeList signatures = doc.documentElement().elementsByTagName( "signature" );
// Use the original signature provided
QString signature = j->property( "binarySignature" ).toString();
if ( signatures.size() > 0 )
{
// THis download has an overriding signature. Take that one instead
const QString sig = signatures.item( 0 ).toElement().text();
tLog() << "Found overridden signature in binary download:" << sig;
signature = sig;
}
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
connect( reply, SIGNAL( finished() ), this, SLOT( payloadFetched() ) );
reply->setProperty( "resolverId", j->property( "resolverId" ) );
reply->setProperty( "createAccount", j->property( "createAccount" ) );
reply->setProperty( "handler", j->property( "handler" ) );
reply->setProperty( "binarySignature", signature );
}
else
{
tLog() << "Failed to do resolver download job!" << job->metadata().error();
tLog() << "Failed to do resolver download job!" << j->errorString() << j->error();
}
}
@@ -703,19 +737,6 @@ AtticaManager::uninstallResolver( const Content& resolver )
m_resolverStates[ resolver.id() ].state = Uninstalled;
TomahawkSettingsGui::instanceGui()->setAtticaResolverState( resolver.id(), Uninstalled );
// remove account as well
QList< Tomahawk::Accounts::Account* > accounts = Tomahawk::Accounts::AccountManager::instance()->accounts( Tomahawk::Accounts::ResolverType );
foreach ( Tomahawk::Accounts::Account* account, accounts )
{
if ( Tomahawk::Accounts::AtticaResolverAccount* atticaAccount = qobject_cast< Tomahawk::Accounts::AtticaResolverAccount* >( account ) )
{
if ( atticaAccount->atticaId() == resolver.id() ) // this is the account we want to remove
{
Tomahawk::Accounts::AccountManager::instance()->removeAccount( atticaAccount );
}
}
}
}
doResolverRemove( resolver.id() );

View File

@@ -132,7 +132,7 @@ private slots:
void categoriesReturned( Attica::BaseJob* );
void resolversList( Attica::BaseJob* );
void binaryResolversList( Attica::BaseJob* );
void resolverDownloadFinished( Attica::BaseJob* );
void resolverDownloadFinished( QNetworkReply* );
void payloadFetched();
void loadPixmapsFromCache();
@@ -144,6 +144,7 @@ private slots:
private:
void doResolverRemove( const QString& id ) const;
void doInstallResolver( const Attica::Content& resolver, bool autoCreate, Tomahawk::Accounts::AtticaResolverAccount* handler );
QString hostname() const;
Attica::ProviderManager m_manager;

View File

@@ -17,7 +17,6 @@ add_definitions( -DQT_SHARED )
add_definitions( -DDLLEXPORT_PRO )
add_definitions( -DQT_SHAREDPOINTER_TRACK_POINTERS )
set( libGuiSources
ActionCollection.cpp
@@ -192,6 +191,7 @@ set( libSources
accounts/spotify/SpotifyAccount.cpp
accounts/spotify/SpotifyAccountConfig.cpp
accounts/spotify/SpotifyPlaylistUpdater.cpp
accounts/spotify/SpotifyInfoPlugin.cpp
accounts/lastfm/LastFmAccount.cpp
accounts/lastfm/LastFmConfig.cpp
@@ -327,8 +327,7 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.
${CMAKE_CURRENT_SOURCE_DIR}
${QT_INCLUDE_DIR}
${QJSON_INCLUDE_DIR}
${LIBECHONEST_INCLUDE_DIR}
${LIBECHONEST_INCLUDE_DIR}/..
${ECHONEST_INCLUDE_DIR}
${LIBLASTFM_INCLUDE_DIRS}
${LIBLASTFM_INCLUDE_DIRS}/..
${CLUCENE_INCLUDE_DIRS}
@@ -380,6 +379,8 @@ IF( APPLE )
FIND_LIBRARY( SCRIPTINGBRIDGE_LIBRARY ScriptingBridge )
MARK_AS_ADVANCED( COREAUDIO_LIBRARY COREFOUNDATION_LIBRARY FOUNDATION_LIBRARY SCRIPTINGBRIDGE_LIBRARY )
SET( CMAKE_SHARED_LINKER_FLAGS "-headerpad_max_install_names ${CMAKE_SHARED_LINKER_FLAGS}" )
SET( libSources ${libSources}
utils/TomahawkUtils_Mac.mm
mac/FileHelpers.mm
@@ -438,7 +439,7 @@ TARGET_LINK_LIBRARIES( tomahawklib
${PHONON_LIBS}
${TAGLIB_LIBRARIES}
${CLUCENE_LIBRARIES}
${LIBECHONEST_LIBRARY}
${ECHONEST_LIBRARIES}
${QT_QTSQL_LIBRARY}
${QT_QTUITOOLS_LIBRARY}
${QT_QTGUI_LIBRARY}

View File

@@ -85,9 +85,9 @@ ContextMenu::setQueries( const QList<Tomahawk::query_ptr>& queries )
if ( m_supportedActions & ActionStopAfter && itemCount() == 1 )
{
if ( AudioEngine::instance()->stopAfterTrack() == queries.first() )
m_sigmap->setMapping( addAction( tr( "&Continue Playback after this Track" ) ), ActionStopAfter );
m_sigmap->setMapping( addAction( tr( "Continue Playback after this &Track" ) ), ActionStopAfter );
else
m_sigmap->setMapping( addAction( tr( "&Stop Playback after this Track" ) ), ActionStopAfter );
m_sigmap->setMapping( addAction( tr( "Stop Playback after this &Track" ) ), ActionStopAfter );
}
addSeparator();
@@ -122,6 +122,9 @@ ContextMenu::setQueries( const QList<Tomahawk::query_ptr>& queries )
void
ContextMenu::setQuery( const Tomahawk::query_ptr& query )
{
if ( query.isNull() )
return;
QList<query_ptr> queries;
queries << query;
setQueries( queries );
@@ -151,8 +154,8 @@ ContextMenu::setAlbums( const QList<Tomahawk::album_ptr>& albums )
addSeparator();
/* if ( m_supportedActions & ActionCopyLink && itemCount() == 1 )
m_sigmap->setMapping( addAction( tr( "Copy Album &Link" ) ), ActionCopyLink ); */
if ( m_supportedActions & ActionCopyLink && itemCount() == 1 )
m_sigmap->setMapping( addAction( tr( "Copy Album &Link" ) ), ActionCopyLink );
foreach ( QAction* action, actions() )
{
@@ -193,8 +196,8 @@ ContextMenu::setArtists( const QList<Tomahawk::artist_ptr>& artists )
addSeparator();
/* if ( m_supportedActions & ActionCopyLink && itemCount() == 1 )
m_sigmap->setMapping( addAction( tr( "Copy Artist &Link" ) ), ActionCopyLink ); */
if ( m_supportedActions & ActionCopyLink && itemCount() == 1 )
m_sigmap->setMapping( addAction( tr( "Copy Artist &Link" ) ), ActionCopyLink );
foreach ( QAction* action, actions() )
{
@@ -224,7 +227,7 @@ ContextMenu::onTriggered( int action )
case ActionCopyLink:
copyLink();
break;
case ActionPage:
openPage();
break;
@@ -252,15 +255,15 @@ ContextMenu::addToQueue()
{
foreach ( const query_ptr& query, m_queries )
{
ViewManager::instance()->queue()->model()->append( query );
ViewManager::instance()->queue()->model()->appendQuery( query );
}
foreach ( const artist_ptr& artist, m_artists )
{
ViewManager::instance()->queue()->model()->append( artist );
ViewManager::instance()->queue()->model()->appendArtist( artist );
}
foreach ( const album_ptr& album, m_albums )
{
ViewManager::instance()->queue()->model()->append( album );
ViewManager::instance()->queue()->model()->appendAlbum( album );
}
ViewManager::instance()->showQueue();
@@ -274,6 +277,14 @@ ContextMenu::copyLink()
{
GlobalActionManager::instance()->copyToClipboard( m_queries.first() );
}
else if ( m_albums.count() )
{
GlobalActionManager::instance()->copyOpenLink( m_albums.first() );
}
else if ( m_artists.count() )
{
GlobalActionManager::instance()->copyOpenLink( m_artists.first() );
}
}
@@ -298,12 +309,15 @@ ContextMenu::openPage()
void
ContextMenu::onSocialActionsLoaded()
{
if ( m_queries.first()->loved() )
if ( m_queries.isEmpty() || m_queries.first().isNull() )
return;
if ( m_loveAction && m_queries.first()->loved() )
{
m_loveAction->setText( tr( "Un-&Love" ) );
m_loveAction->setIcon( QIcon( RESPATH "images/not-loved.png" ) );
}
else
else if ( m_loveAction )
{
m_loveAction->setText( tr( "&Love" ) );
m_loveAction->setIcon( QIcon( RESPATH "images/loved.png" ) );

View File

@@ -425,12 +425,18 @@ DropJob::tracksFromMixedData( const QMimeData *data )
QDataStream singleStream( &singleData, QIODevice::WriteOnly );
QMimeData singleMimeData;
if ( mimeType == "application/tomahawk.query.list" || mimeType == "application/tomahawk.result.list" )
if ( mimeType == "application/tomahawk.query.list" )
{
qlonglong query;
stream >> query;
singleStream << query;
}
else if ( mimeType == "application/tomahawk.result.list" )
{
qlonglong result;
stream >> result;
singleStream << result;
}
else if ( mimeType == "application/tomahawk.metadata.album" )
{
QString artist;
@@ -699,8 +705,21 @@ DropJob::removeDuplicates()
foreach ( const Tomahawk::query_ptr& item, m_resultList )
{
bool contains = false;
Q_ASSERT( !item.isNull() );
if ( item.isNull() )
{
m_resultList.removeOne( item );
continue;
}
foreach( const Tomahawk::query_ptr &tmpItem, list )
{
if ( tmpItem.isNull() )
{
list.removeOne( tmpItem );
continue;
}
if ( item->album() == tmpItem->album()
&& item->artist() == tmpItem->artist()
&& item->track() == tmpItem->track() )
@@ -726,10 +745,18 @@ DropJob::removeRemoteSources()
QList< Tomahawk::query_ptr > list;
foreach ( const Tomahawk::query_ptr& item, m_resultList )
{
Q_ASSERT( !item.isNull() );
if ( item.isNull() )
{
m_resultList.removeOne( item );
continue;
}
bool hasLocalSource = false;
foreach ( const Tomahawk::result_ptr& result, item->results() )
{
if ( !result->collection()->source().isNull() && result->collection()->source()->isLocal() )
if ( !result->collection().isNull() && !result->collection()->source().isNull() &&
!result->collection()->source().isNull() && result->collection()->source()->isLocal() )
hasLocalSource = true;
}
if ( hasLocalSource )

View File

@@ -553,7 +553,7 @@ GlobalActionManager::handleOpenCommand( const QUrl& url )
void
GlobalActionManager::handleOpenTrack( const query_ptr& q )
{
ViewManager::instance()->queue()->model()->append( q );
ViewManager::instance()->queue()->model()->appendQuery( q );
ViewManager::instance()->showQueue();
if ( !AudioEngine::instance()->isPlaying() && !AudioEngine::instance()->isPaused() )
@@ -570,7 +570,7 @@ GlobalActionManager::handleOpenTracks( const QList< query_ptr >& queries )
if ( queries.isEmpty() )
return;
ViewManager::instance()->queue()->model()->append( queries );
ViewManager::instance()->queue()->model()->appendQueries( queries );
ViewManager::instance()->showQueue();
if ( !AudioEngine::instance()->isPlaying() && !AudioEngine::instance()->isPaused() )
@@ -617,16 +617,15 @@ GlobalActionManager::doQueueAdd( const QStringList& parts, const QList< QPair< Q
{
if ( parts.size() && parts[ 0 ] == "track" )
{
if ( queueSpotify( parts, queryItems ) )
return true;
else if ( queueRdio( parts, queryItems ) )
return true;
QPair< QString, QString > pair;
QString title, artist, album, urlStr;
foreach ( pair, queryItems ) {
foreach ( pair, queryItems )
{
pair.second = pair.second.replace( "+", " " ); // QUrl::queryItems doesn't decode + to a space :(
if ( pair.first == "title" )
title = pair.second;
@@ -642,9 +641,12 @@ GlobalActionManager::doQueueAdd( const QStringList& parts, const QList< QPair< Q
{
// an individual; query to add to queue
query_ptr q = Query::get( artist, title, album, uuid(), false );
if ( q.isNull() )
return false;
if ( !urlStr.isEmpty() )
q->setResultHint( urlStr );
Pipeline::instance()->resolve( q, true );
Pipeline::instance()->resolve( q );
handleOpenTrack( q );
return true;
@@ -666,11 +668,13 @@ GlobalActionManager::doQueueAdd( const QStringList& parts, const QList< QPair< Q
{ // give it a web result hint
QFileInfo info( track.path() );
query_ptr q = Query::get( QString(), info.baseName(), QString(), uuid(), false );
if ( q.isNull() )
continue;
q->setResultHint( track.toString() );
Pipeline::instance()->resolve( q );
Pipeline::instance()->resolve( q, true );
ViewManager::instance()->queue()->model()->append( q );
ViewManager::instance()->queue()->model()->appendQuery( q );
ViewManager::instance()->showQueue();
}
return true;
@@ -1067,6 +1071,9 @@ GlobalActionManager::handlePlayCommand( const QUrl& url )
}
query_ptr q = Query::get( artist, title, album );
if ( q.isNull() )
return false;
if ( !urlStr.isEmpty() )
q->setResultHint( urlStr );
@@ -1155,18 +1162,25 @@ bool GlobalActionManager::handleBookmarkCommand(const QUrl& url)
urlStr = pair.second;
}
query_ptr q = Query::get( artist, title, album );
if ( q.isNull() )
return false;
if ( !urlStr.isEmpty() )
q->setResultHint( urlStr );
Pipeline::instance()->resolve( q, true );
Pipeline::instance()->resolve( q );
// now we add it to the special "bookmarks" playlist, creating it if it doesn't exist. if nothing is playing, start playing the track
QSharedPointer< LocalCollection > col = SourceList::instance()->getLocal()->collection().dynamicCast< LocalCollection >();
playlist_ptr bookmarkpl = col->bookmarksPlaylist();
if ( bookmarkpl.isNull() ) { // create it and do the deed then
if ( bookmarkpl.isNull() )
{
// create it and do the deed then
m_waitingToBookmark = q;
col->createBookmarksPlaylist();
connect( col.data(), SIGNAL( bookmarkPlaylistCreated( Tomahawk::playlist_ptr ) ), this, SLOT( bookmarkPlaylistCreated( Tomahawk::playlist_ptr ) ), Qt::UniqueConnection );
} else {
}
else
{
doBookmark( bookmarkpl, q );
}
@@ -1343,7 +1357,7 @@ GlobalActionManager::waitingForResolved( bool /* success */ )
AudioEngine::instance()->playItem( AudioEngine::instance()->playlist(), m_waitingToPlay->results().first() );
else
{
ViewManager::instance()->queue()->model()->append( m_waitingToPlay );
ViewManager::instance()->queue()->model()->appendQuery( m_waitingToPlay );
AudioEngine::instance()->play();
}
}

View File

@@ -272,9 +272,16 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results )
}
const query_ptr& q = m_qids.value( qid );
Q_ASSERT( !q.isNull() );
if ( q.isNull() )
return;
QList< result_ptr > cleanResults;
foreach ( const result_ptr& r, results )
{
if ( r.isNull() )
continue;
float score = q->howSimilar( r );
r->setScore( score );
if ( !q->isFullTextQuery() && score < MINSCORE )

View File

@@ -54,6 +54,7 @@ PlaylistEntry::setQueryVariant( const QVariant& v )
QString artist = m.value( "artist" ).toString();
QString album = m.value( "album" ).toString();
QString track = m.value( "track" ).toString();
m_query = Tomahawk::Query::get( artist, track, album );
}

View File

@@ -59,10 +59,11 @@ public:
PlaylistEntry();
virtual ~PlaylistEntry();
bool isValid() const { return !m_query.isNull(); }
void setQuery( const Tomahawk::query_ptr& q );
const Tomahawk::query_ptr& query() const;
// I wish Qt did this for me once i specified the Q_PROPERTIES:
void setQueryVariant( const QVariant& v );
QVariant queryVariant() const;

View File

@@ -29,6 +29,7 @@ using namespace Tomahawk;
PlaylistInterface::PlaylistInterface ()
: QObject()
, m_latchMode( PlaylistModes::StayOnSong )
, m_finished( false )
{
m_id = uuid();
}

View File

@@ -40,6 +40,7 @@ public:
const QString id() { return m_id; }
virtual QList< Tomahawk::query_ptr > tracks() = 0;
virtual bool isFinished() const { return m_finished; }
virtual int unfilteredTrackCount() const = 0;
virtual int trackCount() const = 0;
@@ -91,7 +92,8 @@ protected:
virtual QList<Tomahawk::query_ptr> filterTracks( const QList<Tomahawk::query_ptr>& queries );
PlaylistModes::LatchMode m_latchMode;
bool m_finished;
private:
Q_DISABLE_COPY( PlaylistInterface )

View File

@@ -82,6 +82,9 @@ PlaybackLog::PlaybackLog( const PlaybackLog& other )
query_ptr
Query::get( const QString& artist, const QString& track, const QString& album, const QID& qid, bool autoResolve )
{
if ( artist.trimmed().isEmpty() || track.trimmed().isEmpty() )
return query_ptr();
if ( qid.isEmpty() )
autoResolve = false;
@@ -98,6 +101,8 @@ Query::get( const QString& artist, const QString& track, const QString& album, c
query_ptr
Query::get( const QString& query, const QID& qid )
{
Q_ASSERT( !query.trimmed().isEmpty() );
query_ptr q = query_ptr( new Query( query, qid ), &QObject::deleteLater );
q->setWeakRef( q.toWeakRef() );
@@ -170,14 +175,14 @@ Query::updateSortNames()
if ( isFullTextQuery() )
{
m_artistSortname = DatabaseImpl::sortname( m_fullTextQuery, true );
m_composerSortName = DatabaseImpl::sortname( m_composer, true );
m_composerSortname = DatabaseImpl::sortname( m_composer, true );
m_albumSortname = DatabaseImpl::sortname( m_fullTextQuery );
m_trackSortname = m_albumSortname;
}
else
{
m_artistSortname = DatabaseImpl::sortname( m_artist, true );
m_composerSortName = DatabaseImpl::sortname( m_composer, true );
m_composerSortname = DatabaseImpl::sortname( m_composer, true );
m_albumSortname = DatabaseImpl::sortname( m_album );
m_trackSortname = DatabaseImpl::sortname( m_track );
}
@@ -189,7 +194,7 @@ Query::displayQuery() const
{
if ( !results().isEmpty() )
return results().first()->toQuery();
return m_ownRef.toStrongRef();
}
@@ -223,6 +228,7 @@ Query::addResults( const QList< Tomahawk::result_ptr >& newresults )
checkResults();
emit resultsAdded( newresults );
emit resultsChanged();
}
@@ -287,6 +293,7 @@ Query::removeResult( const Tomahawk::result_ptr& result )
emit resultsRemoved( result );
checkResults();
emit resultsChanged();
}
@@ -491,15 +498,20 @@ Query::toString() const
float
Query::howSimilar( const Tomahawk::result_ptr& r )
{
Q_ASSERT( !r->artist().isNull() );
Q_ASSERT( !r->album().isNull() );
if ( r->artist().isNull() || r->album().isNull() )
return 0.0;
// result values
const QString rArtistname = r->artist()->sortname();
const QString rAlbumname = DatabaseImpl::sortname( r->album()->name() );
const QString rAlbumname = r->album()->sortname();
const QString rTrackname = DatabaseImpl::sortname( r->track() );
// normal edit distance
int artdist = levenshtein( m_artistSortname, rArtistname );
int albdist = levenshtein( m_albumSortname, rAlbumname );
int trkdist = levenshtein( m_trackSortname, rTrackname );
int artdist = TomahawkUtils::levenshtein( m_artistSortname, rArtistname );
int albdist = TomahawkUtils::levenshtein( m_albumSortname, rAlbumname );
int trkdist = TomahawkUtils::levenshtein( m_trackSortname, rTrackname );
// max length of name
int mlart = qMax( m_artistSortname.length(), rArtistname.length() );
@@ -516,7 +528,7 @@ Query::howSimilar( const Tomahawk::result_ptr& r )
const QString artistTrackname = DatabaseImpl::sortname( fullTextQuery() );
const QString rArtistTrackname = DatabaseImpl::sortname( r->artist()->name() + " " + r->track() );
int atrdist = levenshtein( artistTrackname, rArtistTrackname );
int atrdist = TomahawkUtils::levenshtein( artistTrackname, rArtistTrackname );
int mlatr = qMax( artistTrackname.length(), rArtistTrackname.length() );
float dcatr = (float)( mlatr - atrdist ) / mlatr;
@@ -566,7 +578,7 @@ Query::playbackHistory( const Tomahawk::source_ptr& source ) const
history << log;
}
}
return history;
}
@@ -588,7 +600,7 @@ Query::playbackCount( const source_ptr& source )
if ( source.isNull() || log.source == source )
count++;
}
return count;
}
@@ -596,6 +608,9 @@ Query::playbackCount( const source_ptr& source )
void
Query::loadSocialActions()
{
if ( m_socialActionsLoaded )
return;
m_socialActionsLoaded = true;
query_ptr q = m_ownRef.toStrongRef();
@@ -670,12 +685,12 @@ Query::setLoved( bool loved )
trackInfo["album"] = album();
loveInfo[ "trackinfo" ] = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo );
Tomahawk::InfoSystem::InfoPushData pushData ( id(),
( loved ? Tomahawk::InfoSystem::InfoLove : Tomahawk::InfoSystem::InfoUnLove ),
loveInfo,
Tomahawk::InfoSystem::PushShortUrlFlag );
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( pushData );
DatabaseCommand_SocialAction* cmd = new DatabaseCommand_SocialAction( q, QString( "Love" ), loved ? QString( "true" ) : QString( "false" ) );
@@ -783,10 +798,10 @@ Query::coverLoaded() const
{
if ( m_albumPtr.isNull() )
return false;
if ( m_albumPtr->coverLoaded() && !m_albumPtr->cover( QSize( 0, 0 ) ).isNull() )
return true;
return m_artistPtr->coverLoaded();
}
@@ -809,7 +824,7 @@ Query::similarTracks() const
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo );
requestData.type = Tomahawk::InfoSystem::InfoTrackSimilars;
requestData.requestId = TomahawkUtils::infosystemRequestId();
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
@@ -821,7 +836,7 @@ Query::similarTracks() const
m_infoJobs++;
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
}
return m_similarTracks;
}
@@ -842,7 +857,7 @@ Query::lyrics() const
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo );
requestData.type = Tomahawk::InfoSystem::InfoTrackLyrics;
requestData.requestId = TomahawkUtils::infosystemRequestId();
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
@@ -854,7 +869,7 @@ Query::lyrics() const
m_infoJobs++;
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
}
return m_lyrics;
}
@@ -871,7 +886,7 @@ Query::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVaria
case InfoSystem::InfoTrackLyrics:
{
m_lyrics = output.value< QVariant >().toString().split( "\n" );
m_lyricsLoaded = true;
emit lyricsLoaded();
break;
@@ -887,7 +902,7 @@ Query::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVaria
m_similarTracks << Query::get( artists.at( i ), tracks.at( i ), QString(), uuid(), false );
}
Pipeline::instance()->resolve( m_similarTracks );
m_simTracksLoaded = true;
emit similarTracksLoaded();
@@ -917,83 +932,3 @@ Query::infoSystemFinished( QString target )
emit updated();
}
int
Query::levenshtein( const QString& source, const QString& target )
{
// Step 1
const int n = source.length();
const int m = target.length();
if ( n == 0 )
return m;
if ( m == 0 )
return n;
// Good form to declare a TYPEDEF
typedef QVector< QVector<int> > Tmatrix;
Tmatrix matrix;
matrix.resize( n + 1 );
// Size the vectors in the 2.nd dimension. Unfortunately C++ doesn't
// allow for allocation on declaration of 2.nd dimension of vec of vec
for ( int i = 0; i <= n; i++ )
{
QVector<int> tmp;
tmp.resize( m + 1 );
matrix.insert( i, tmp );
}
// Step 2
for ( int i = 0; i <= n; i++ )
matrix[i][0] = i;
for ( int j = 0; j <= m; j++ )
matrix[0][j] = j;
// Step 3
for ( int i = 1; i <= n; i++ )
{
const QChar s_i = source[i - 1];
// Step 4
for ( int j = 1; j <= m; j++ )
{
const QChar t_j = target[j - 1];
// Step 5
int cost;
if ( s_i == t_j )
cost = 0;
else
cost = 1;
// Step 6
const int above = matrix[i - 1][j];
const int left = matrix[i][j - 1];
const int diag = matrix[i - 1][j - 1];
int cell = ( ( ( left + 1 ) > ( diag + cost ) ) ? diag + cost : left + 1 );
if ( above + 1 < cell )
cell = above + 1;
// Step 6A: Cover transposition, in addition to deletion,
// insertion and substitution. This step is taken from:
// Berghel, Hal ; Roach, David : "An Extension of Ukkonen's
// Enhanced Dynamic Programming ASM Algorithm"
// (http://www.acm.org/~hlb/publications/asm/asm.html)
if ( i > 2 && j > 2 )
{
int trans = matrix[i - 2][j - 2] + 1;
if ( source[ i - 2 ] != t_j ) trans++;
if ( s_i != target[ j - 2 ] ) trans++;
if ( cell > trans ) cell = trans;
}
matrix[i][j] = cell;
}
}
// Step 7
return matrix[n][m];
}

View File

@@ -97,7 +97,7 @@ public:
QID id() const;
/// sorter for list of results
static bool resultSorter( const result_ptr &left, const result_ptr& right );
static bool resultSorter( const result_ptr& left, const result_ptr& right );
/// true when a perfect result has been found (score of 1.0)
bool solved() const { return m_solved; }
@@ -129,6 +129,7 @@ public:
QString resultHint() const { return m_resultHint; }
QString artistSortname() const { return m_artistSortname; }
QString composerSortname() const { return m_composerSortname; }
QString albumSortname() const { return m_albumSortname; }
QString trackSortname() const { return m_trackSortname; }
@@ -139,7 +140,7 @@ public:
int duration() const { return m_duration; }
unsigned int albumpos() const { return m_albumpos; }
unsigned int discnumber() const { return m_discnumber; }
query_ptr displayQuery() const;
#ifndef ENABLE_HEADLESS
@@ -220,7 +221,6 @@ private:
void checkResults();
void updateSortNames();
static int levenshtein( const QString& source, const QString& target );
void parseSocialActions();
@@ -233,7 +233,7 @@ private:
mutable QID m_qid;
QString m_artistSortname;
QString m_composerSortName;
QString m_composerSortname;
QString m_albumSortname;
QString m_trackSortname;
@@ -266,10 +266,10 @@ private:
bool m_simTracksLoaded;
QList<Tomahawk::query_ptr> m_similarTracks;
bool m_lyricsLoaded;
QStringList m_lyrics;
mutable int m_infoJobs;
};

View File

@@ -207,6 +207,10 @@ Result::toQuery()
if ( m_query.isNull() )
{
m_query = Tomahawk::Query::get( artist()->name(), track(), album()->name() );
if ( m_query.isNull() )
return query_ptr();
m_query->setAlbumPos( albumpos() );
m_query->setDiscNumber( discnumber() );
m_query->setDuration( duration() );

View File

@@ -36,6 +36,7 @@ class DatabaseCommand_LogPlayback;
class DatabaseCommand_SocialAction;
class DatabaseCommand_UpdateSearchIndex;
class DatabaseCommand_DeleteFiles;
class MusicScanner;
namespace Tomahawk
{
@@ -50,6 +51,7 @@ friend class ::DatabaseCommand_LogPlayback;
friend class ::DatabaseCommand_SocialAction;
friend class ::DatabaseCommand_AddFiles;
friend class ::DatabaseCommand_DeleteFiles;
friend class ::MusicScanner;
public:
enum AvatarStyle { Original, FancyStyle };

View File

@@ -305,7 +305,7 @@ ViewManager::show( const Tomahawk::collection_ptr& collection )
view = new TreeView();
TreeModel* model = new TreeModel();
view->setTreeModel( model );
if ( collection && collection->source()->isLocal() )
view->setEmptyTip( tr( "After you have scanned your music collection you will find your tracks right here." ) );
else
@@ -483,7 +483,7 @@ ViewManager::showRecentPlaysPage()
{
PlaylistView* pv = new PlaylistView( m_widget );
RecentlyPlayedModel* raModel = new RecentlyPlayedModel( source_ptr(), pv );
RecentlyPlayedModel* raModel = new RecentlyPlayedModel( pv );
raModel->setTitle( tr( "Recently Played Tracks" ) );
raModel->setDescription( tr( "Recently played tracks from all your friends" ) );
raModel->setStyle( PlayableModel::Large );
@@ -493,6 +493,7 @@ ViewManager::showRecentPlaysPage()
pv->setItemDelegate( del );
pv->setPlaylistModel( raModel );
raModel->setSource( source_ptr() );
m_recentPlaysWidget = pv;
}
@@ -570,7 +571,7 @@ ViewManager::historyBack()
return;
ViewPage* page = m_pageHistoryBack.takeLast();
if ( m_currentPage )
{
m_pageHistoryFwd << m_currentPage;
@@ -589,7 +590,7 @@ ViewManager::historyForward()
return;
ViewPage* page = m_pageHistoryFwd.takeLast();
if ( m_currentPage )
{
m_pageHistoryBack << m_currentPage;
@@ -615,14 +616,7 @@ ViewManager::destroyPage( ViewPage* page )
return;
tDebug() << Q_FUNC_INFO << "Deleting page:" << page->title();
if ( m_currentPage == page )
{
delete page;
m_currentPage = 0;
historyBack();
}
else if ( historyPages().contains( page ) )
if ( historyPages().contains( page ) )
{
m_pageHistoryBack.removeAll( page );
m_pageHistoryFwd.removeAll( page );
@@ -632,6 +626,13 @@ ViewManager::destroyPage( ViewPage* page )
delete page;
}
if ( m_currentPage == page )
{
m_currentPage = 0;
historyBack();
}
}
@@ -640,6 +641,8 @@ ViewManager::setPage( ViewPage* page, bool trackHistory )
{
if ( !page )
return;
if ( page == m_currentPage )
return;
// save the old playlist shuffle state in config before we change playlists
saveCurrentPlaylistSettings();
@@ -865,7 +868,7 @@ ViewManager::onWidgetDestroyed( QWidget* widget )
{
m_dynamicWidgets.remove( dynamicPlaylistForInterface( page->playlistInterface() ) );
}
m_pageHistoryBack.removeAll( page );
m_pageHistoryFwd.removeAll( page );
}

View File

@@ -132,7 +132,7 @@ LastFmConfig::onHistoryLoaded()
uint total = 0;
bool finished = false;
QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() );
try
{
lastfm::XmlQuery lfm;
@@ -140,24 +140,27 @@ LastFmConfig::onHistoryLoaded()
foreach ( lastfm::XmlQuery e, lfm.children( "track" ) )
{
// tDebug() << "Found:" << e["artist"].text() << e["name"].text() << e["date"].attribute( "uts" ).toUInt();
Tomahawk::query_ptr query = Query::get( e["artist"].text(), e["name"].text(), QString(), QString(), false );
// tDebug() << "Found:" << e.children( "artist" ).first()["name"].text() << e["name"].text() << e["date"].attribute( "uts" ).toUInt();
Tomahawk::query_ptr query = Query::get( e.children( "artist" ).first()["name"].text(), e["name"].text(), QString(), QString(), false );
if ( query.isNull() )
continue;
m_lastTimeStamp = e["date"].attribute( "uts" ).toUInt();
DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( query, DatabaseCommand_LogPlayback::Finished, m_lastTimeStamp );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
}
if ( !lfm.children( "recenttracks" ).isEmpty() )
{
lastfm::XmlQuery stats = lfm.children( "recenttracks" ).first();
uint page = stats.attribute( "page" ).toUInt();
total = stats.attribute( "totalPages" ).toUInt();
m_ui->progressBar->setMaximum( total );
m_ui->progressBar->setValue( page );
if ( page < total )
{
m_page = page + 1;
@@ -174,7 +177,7 @@ LastFmConfig::onHistoryLoaded()
tDebug() << "XmlQuery error:" << e.message();
finished = true;
}
if ( finished )
{
if ( m_page != total )

View File

@@ -212,7 +212,7 @@ LastFmInfoPlugin::scrobble()
return;
tLog() << Q_FUNC_INFO << "Scrobbling now:" << m_track.toString();
// FIXME: workaround for the duration-less dilandau (and others) tracks
if ( m_track.duration() == 0 )
m_track.setDuration( 31 );
@@ -525,7 +525,7 @@ LastFmInfoPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::In
imgurl.addEncodedQueryItem( "artist", QUrl::toPercentEncoding( artistName, "", "+" ) );
imgurl.addEncodedQueryItem( "album", QUrl::toPercentEncoding( albumName, "", "+" ) );
imgurl.addQueryItem( "autocorrect", QString::number( 1 ) );
imgurl.addQueryItem( "size", "largesquare" );
imgurl.addQueryItem( "size", "large" );
imgurl.addQueryItem( "api_key", "7a90f6672a04b809ee309af169f34b8b" );
QNetworkRequest req( imgurl );

View File

@@ -29,6 +29,8 @@
#include "Pipeline.h"
#include "accounts/AccountManager.h"
#include "utils/Closure.h"
#include "SpotifyInfoPlugin.h"
#include "infosystem/InfoSystem.h"
#ifndef ENABLE_HEADLESS
#include "jobview/JobStatusView.h"
@@ -80,6 +82,7 @@ SpotifyAccountFactory::icon() const
SpotifyAccount::SpotifyAccount( const QString& accountId )
: CustomAtticaAccount( accountId )
, m_preventEnabling( false )
, m_loggedIn( false )
{
init();
}
@@ -106,6 +109,12 @@ SpotifyAccount::init()
AtticaManager::instance()->registerCustomAccount( s_resolverId, this );
qRegisterMetaType< Tomahawk::Accounts::SpotifyPlaylistInfo* >( "Tomahawk::Accounts::SpotifyPlaylist*" );
if ( infoPlugin() && Tomahawk::InfoSystem::InfoSystem::instance()->workerThread() )
{
infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() );
Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() );
}
if ( !AtticaManager::instance()->resolversLoaded() )
{
// If we're still waiting to load, wait for the attica resolvers to come down the pipe
@@ -121,7 +130,6 @@ SpotifyAccount::init()
void
SpotifyAccount::delayedInit()
{
connect( AtticaManager::instance(), SIGNAL( resolverInstalled( QString ) ), this, SLOT( resolverInstalled( QString ) ) );
const Attica::Content res = AtticaManager::instance()->resolverForId( s_resolverId );
@@ -131,6 +139,11 @@ SpotifyAccount::delayedInit()
if ( !checkForResolver() && state != AtticaManager::Uninstalled )
{
// If the user manually deleted the resolver, mark it as uninstalled, so we re-fetch for the user
QVariantHash conf = configuration();
conf.remove( "path" );
setConfiguration( conf );
sync();
AtticaManager::instance()->uninstallResolver( res );
}
else if ( state == AtticaManager::Installed || !path.isEmpty() )
@@ -138,9 +151,15 @@ SpotifyAccount::delayedInit()
if ( !path.isEmpty() )
{
QFileInfo info( path );
// Resolver was deleted, so abort.
// Resolver was deleted, so abort and remove our manual override, as it's no longer valid
if ( !info.exists() )
{
QVariantHash conf = configuration();
conf.remove( "path" );
setConfiguration( conf );
sync();
return;
}
}
hookupResolver();
}
@@ -165,20 +184,44 @@ SpotifyAccount::hookupResolver()
}
qDebug() << "Starting spotify resolver with path:" << path;
if ( !m_spotifyResolver.isNull() )
{
delete m_spotifyResolver.data();
}
if ( !QFile::exists( path ) )
{
qWarning() << "Asked to hook up spotify resolver but it doesn't exist, ignoring";
return;
}
// HACK
// Since the resolver in 0.4.x used an incompatible version of kdsingleappguard, we can't auto-kill old resolvers on the
// 0.4.x->0.5.x upgrade. So we do it manually for a while
killExistingResolvers();
m_spotifyResolver = QWeakPointer< ScriptResolver >( qobject_cast< ScriptResolver* >( Pipeline::instance()->addScriptResolver( path ) ) );
connect( m_spotifyResolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) );
connect( m_spotifyResolver.data(), SIGNAL( customMessage( QString,QVariantMap ) ), this, SLOT( resolverMessage( QString, QVariantMap ) ) );
const bool hasMigrated = configuration().value( "hasMigrated" ).toBool();
if ( !hasMigrated )
{
qDebug() << "Getting credentials from spotify resolver to migrate to in-app config";
QVariantMap msg;
msg[ "_msgtype" ] = "getCredentials";
m_spotifyResolver.data()->sendMessage( msg );
}
// Always get logged in status
QVariantMap msg;
msg[ "_msgtype" ] = "getCredentials";
m_spotifyResolver.data()->sendMessage( msg );
}
void
SpotifyAccount::killExistingResolvers()
{
QProcess p;
#if defined(Q_OS_UNIX)
const int ret = p.execute( "killall -9 spotify_tomahawkresolver" );
qDebug() << "Tried to killall -9 spotify_tomahawkresolver with return code:" << ret;
#elif defined(Q_OS_WIN)
const int ret = p.execute( "taskkill.exe /F /im spotify_tomahawkresolver.exe" );
qDebug() << "Tried to taskkill.exe /F /im spotify_tomahawkresolver.exe with return code:" << ret;
#endif
}
@@ -228,13 +271,18 @@ SpotifyAccount::authenticate()
const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res );
qDebug() << "Spotify account authenticating...";
const QString path = configuration().value( "path" ).toString();
const QFileInfo info( path );
const bool manualResolverRemoved = !path.isEmpty() && !info.exists();
if ( m_spotifyResolver.isNull() && state == AtticaManager::Installed )
{
// We don;t have the resolver but it has been installed via attica already, so lets just turn it on
qDebug() << "No valid spotify resolver running, but attica reports it is installed, so start it up";
hookupResolver();
}
else if ( m_spotifyResolver.isNull() )
else if ( m_spotifyResolver.isNull() || manualResolverRemoved )
{
qDebug() << "Got null resolver but asked to authenticate, so installing if we have one from attica:" << res.isValid() << res.id();
if ( res.isValid() && !res.id().isEmpty() )
@@ -284,6 +332,18 @@ SpotifyAccount::connectionState() const
}
InfoSystem::InfoPluginPtr
SpotifyAccount::infoPlugin()
{
if ( m_infoPlugin.isNull() )
{
m_infoPlugin = QWeakPointer< InfoSystem::SpotifyInfoPlugin >( new InfoSystem::SpotifyInfoPlugin( this ) );
}
return InfoSystem::InfoPluginPtr( m_infoPlugin.data() );
}
void
SpotifyAccount::resolverInstalled(const QString& resolverId)
{
@@ -318,6 +378,11 @@ SpotifyAccount::setManualResolverPath( const QString &resolverPath )
setConfiguration( conf );
sync();
// uninstall
const Attica::Content res = AtticaManager::instance()->resolverForId( s_resolverId );
if ( AtticaManager::instance()->resolverState( res ) != AtticaManager::Uninstalled )
AtticaManager::instance()->uninstallResolver( res );
m_preventEnabling = false;
if ( !m_spotifyResolver.isNull() )
@@ -335,6 +400,13 @@ SpotifyAccount::setManualResolverPath( const QString &resolverPath )
}
bool
SpotifyAccount::loggedIn() const
{
return m_loggedIn;
}
void
SpotifyAccount::hookupAfterDeletion( bool autoEnable )
{
@@ -466,6 +538,15 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg
creds[ "highQuality" ] = msg.value( "highQuality" );
setCredentials( creds );
m_loggedIn = msg.value( "loggedIn", false ).toBool();
if ( m_loggedIn )
{
configurationWidget();
if ( !m_configWidget.isNull() )
m_configWidget.data()->loginResponse( true, QString(), creds[ "username" ].toString() );
}
qDebug() << "Set creds:" << creds.value( "username" ) << creds.value( "password" ) << msg.value( "username" ) << msg.value( "password" );
QVariantHash config = configuration();
@@ -483,8 +564,12 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg
QObject* receiver = m_qidToSlotMap[ qid ].first;
QString slot = m_qidToSlotMap[ qid ].second;
m_qidToSlotMap.remove( qid );
QVariant extraData;
if ( m_qidToExtraData.contains( qid ) )
extraData = m_qidToExtraData.take( qid );
QMetaObject::invokeMethod( receiver, slot.toLatin1(), Q_ARG( QString, msgType ), Q_ARG( QVariantMap, msg ) );
QMetaObject::invokeMethod( receiver, slot.toLatin1(), Q_ARG( QString, msgType ), Q_ARG( QVariantMap, msg ), Q_ARG( QVariant, extraData ) );
}
else if ( msgType == "allPlaylists" )
{
@@ -626,6 +711,8 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg
const bool success = msg.value( "success" ).toBool();
m_loggedIn = success;
if ( success )
createActions();
@@ -633,7 +720,7 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg
if ( m_configWidget.data() )
{
const QString message = msg.value( "message" ).toString();
m_configWidget.data()->loginResponse( success, message );
m_configWidget.data()->loginResponse( success, message, creds[ "username" ].toString() );
}
}
else if ( msgType == "playlistDeleted" )
@@ -646,6 +733,23 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg
SpotifyPlaylistUpdater* updater = m_updaters.take( plid );
updater->remove( false );
}
else if ( msgType == "status" )
{
const bool loggedIn = msg.value( "loggedIn" ).toBool();
const QString username = msg.value( "username" ).toString();
qDebug() << "Got status message with login info:" << loggedIn << username;
if ( !loggedIn || username.isEmpty() || credentials().value( "username").toString() != username )
m_loggedIn = false;
QVariantMap msg;
msg[ "_msgtype" ] = "status";
msg[ "_status" ] = 1;
sendMessage( msg );
return;
}
}
@@ -685,16 +789,17 @@ SpotifyAccount::icon() const
QWidget*
SpotifyAccount::configurationWidget()
{
if ( m_spotifyResolver.isNull() || !m_spotifyResolver.data()->running() )
return 0;
if ( m_configWidget.isNull() )
{
m_configWidget = QWeakPointer< SpotifyAccountConfig >( new SpotifyAccountConfig( this ) );
connect( m_configWidget.data(), SIGNAL( login( QString,QString ) ), this, SLOT( login( QString,QString ) ) );
connect( m_configWidget.data(), SIGNAL( logout() ), this, SLOT( logout() ) );
m_configWidget.data()->setPlaylists( m_allSpotifyPlaylists );
}
if ( m_spotifyResolver.isNull() || !m_spotifyResolver.data()->running() )
return 0;
return static_cast< QWidget* >( m_configWidget.data() );
}
@@ -774,7 +879,6 @@ SpotifyAccount::saveConfig()
void
SpotifyAccount::login( const QString& username, const QString& password )
{
// Send the result to the resolver
QVariantMap msg;
msg[ "_msgtype" ] = "login";
msg[ "username" ] = username;
@@ -786,6 +890,15 @@ SpotifyAccount::login( const QString& username, const QString& password )
}
void
SpotifyAccount::logout()
{
QVariantMap msg;
msg[ "_msgtype" ] = "logout";
m_spotifyResolver.data()->sendMessage( msg );
}
void
SpotifyAccount::startPlaylistSync( SpotifyPlaylistInfo* playlist )
{
@@ -802,7 +915,7 @@ SpotifyAccount::startPlaylistSync( SpotifyPlaylistInfo* playlist )
void
SpotifyAccount::startPlaylistSyncWithPlaylist( const QString& msgType, const QVariantMap& msg )
SpotifyAccount::startPlaylistSyncWithPlaylist( const QString& msgType, const QVariantMap& msg, const QVariant& )
{
Q_UNUSED( msgType );
qDebug() << Q_FUNC_INFO << "Got full spotify playlist body, creating a tomahawk playlist and enabling sync!!";
@@ -850,7 +963,7 @@ SpotifyAccount::startPlaylistSyncWithPlaylist( const QString& msgType, const QVa
void
SpotifyAccount::playlistCreated( const QString& msgType, const QVariantMap& msg )
SpotifyAccount::playlistCreated( const QString& msgType, const QVariantMap& msg, const QVariant& )
{
Q_UNUSED( msgType );
@@ -881,20 +994,20 @@ SpotifyAccount::playlistCreated( const QString& msgType, const QVariantMap& msg
QString
SpotifyAccount::sendMessage( const QVariantMap &m, QObject* obj, const QString& slot )
SpotifyAccount::sendMessage( const QVariantMap &m, QObject* obj, const QString& slot, const QVariant& extraData )
{
QVariantMap msg = m;
QString qid;
const QString qid = uuid();
if ( obj )
{
qid = QUuid::createUuid().toString().replace( "{", "" ).replace( "}", "" );
m_qidToSlotMap[ qid ] = qMakePair( obj, slot );
msg[ "qid" ] = qid;
}
m_qidToExtraData[ qid ] = extraData;
m_spotifyResolver.data()->sendMessage( msg );
return qid;

View File

@@ -35,6 +35,12 @@ class QTimer;
class ScriptResolver;
namespace Tomahawk {
namespace InfoSystem
{
class SpotifyInfoPlugin;
}
namespace Accounts {
class SpotifyAccountConfig;
@@ -89,11 +95,10 @@ public:
virtual void deauthenticate();
virtual QWidget* aclWidget() { return 0; }
virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin() { return Tomahawk::InfoSystem::InfoPluginPtr(); }
virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin();
virtual SipPlugin* sipPlugin() { return 0; }
virtual bool preventEnabling() const { return m_preventEnabling; }
QString sendMessage( const QVariantMap& msg, QObject* receiver = 0, const QString& slot = QString() );
void registerUpdaterForPlaylist( const QString& plId, SpotifyPlaylistUpdater* updater );
void unregisterUpdater( const QString& plid );
@@ -102,7 +107,11 @@ public:
void setManualResolverPath( const QString& resolverPath );
bool loggedIn() const;
public slots:
QString sendMessage( const QVariantMap& msg, QObject* receiver = 0, const QString& slot = QString(), const QVariant& extraData = QVariant() );
void aboutToShow( QAction* action, const Tomahawk::playlist_ptr& playlist );
void syncActionTriggered( bool );
void atticaLoaded(Attica::Content::List);
@@ -114,10 +123,12 @@ private slots:
void resolverMessage( const QString& msgType, const QVariantMap& msg );
void login( const QString& username, const QString& password );
void logout();
// SpotifyResolver message handlers, all take msgtype, msg as argument
// void <here>( const QString& msgType, const QVariantMap& msg );
void startPlaylistSyncWithPlaylist( const QString& msgType, const QVariantMap& msg );
void playlistCreated( const QString& msgType, const QVariantMap& msg );
// void <here>( const QString& msgType, const QVariantMap& msg, const QVariant& extraData );
void startPlaylistSyncWithPlaylist( const QString& msgType, const QVariantMap& msg, const QVariant& extraData );
void playlistCreated( const QString& msgType, const QVariantMap& msg, const QVariant& extraData );
void delayedInit();
void hookupAfterDeletion( bool autoEnable );
@@ -126,6 +137,7 @@ private:
void init();
bool checkForResolver();
void hookupResolver();
void killExistingResolvers();
void loadPlaylists();
void clearUser( bool permanentlyDelete = false );
@@ -142,8 +154,10 @@ private:
QWeakPointer<SpotifyAccountConfig> m_configWidget;
QWeakPointer<QWidget> m_aboutWidget;
QWeakPointer<ScriptResolver> m_spotifyResolver;
QWeakPointer< InfoSystem::SpotifyInfoPlugin > m_infoPlugin;
QMap<QString, QPair<QObject*, QString> > m_qidToSlotMap;
QMap<QString, QVariant > m_qidToExtraData;
// List of synced spotify playlists in config UI
QList< SpotifyPlaylistInfo* > m_allSpotifyPlaylists;
@@ -151,7 +165,7 @@ private:
QHash< QString, playlist_ptr > m_waitingForCreateReply;
bool m_preventEnabling;
bool m_preventEnabling, m_loggedIn;
SmartPointerList< QAction > m_customActions;
friend class ::SpotifyPlaylistUpdater;

View File

@@ -25,6 +25,7 @@
#include <QListWidget>
#include <QListWidgetItem>
#include <QShowEvent>
#include <QLabel>
using namespace Tomahawk;
using namespace Accounts;
@@ -32,16 +33,20 @@ using namespace Accounts;
SpotifyAccountConfig::SpotifyAccountConfig( SpotifyAccount *account )
: QWidget( 0 )
, m_ui( new Ui::SpotifyConfig )
, m_loggedInUser( 0 )
, m_account( account )
, m_playlistsLoading( 0 )
, m_loggedInManually( false )
, m_isLoggedIn( false )
{
m_ui->setupUi( this );
m_ui->loginButton->setDefault( true );
connect( m_ui->loginButton, SIGNAL( clicked( bool ) ), this, SLOT( doLogin() ) );
connect( m_ui->usernameEdit, SIGNAL( textChanged( QString ) ), this, SLOT( resetLoginButton() ) );
connect( m_ui->passwordEdit, SIGNAL( textChanged( QString ) ), this, SLOT( resetLoginButton() ) );
connect( m_ui->usernameEdit, SIGNAL( textEdited( QString ) ), this, SLOT( resetLoginButton() ) );
connect( m_ui->passwordEdit, SIGNAL( textEdited( QString ) ), this, SLOT( resetLoginButton() ) );
loadFromConfig();
m_playlistsLoading = new AnimatedSpinner( m_ui->playlistList );
@@ -61,10 +66,21 @@ SpotifyAccountConfig::showEvent( QShowEvent *event )
void
SpotifyAccountConfig::loadFromConfig()
{
m_ui->usernameEdit->setText( m_account->credentials().value( "username" ).toString() );
const QString username = m_account->credentials().value( "username" ).toString();
m_ui->usernameEdit->setText( username );
m_ui->passwordEdit->setText( m_account->credentials().value( "password" ).toString() );
m_ui->streamingCheckbox->setChecked( m_account->credentials().value( "highQuality" ).toBool() );
m_ui->deleteOnUnsync->setChecked( m_account->deleteOnUnsync() );
if ( m_account->loggedIn() )
{
qDebug() << "Loading spotify config widget with logged in username:" << username;
if ( !username.isEmpty() )
m_verifiedUsername = username;
showLoggedIn();
}
else
showLoggedOut();
}
void
@@ -132,28 +148,44 @@ SpotifyAccountConfig::setPlaylists( const QList<SpotifyPlaylistInfo *>& playlist
void
SpotifyAccountConfig::doLogin()
{
m_ui->loginButton->setText( tr( "Logging in..." ) );
m_ui->loginButton->setEnabled( false );
if ( !m_isLoggedIn )
{
m_ui->loginButton->setText( tr( "Logging in..." ) );
m_ui->loginButton->setEnabled( false );
m_playlistsLoading->fadeIn();
m_loggedInManually = true;
m_playlistsLoading->fadeIn();
m_loggedInManually = true;
emit login( username(), password() );
emit login( username(), password() );
}
else
{
// Log out
m_isLoggedIn = false;
m_loggedInManually = true;
m_verifiedUsername.clear();
m_ui->playlistList->clear();
emit logout();
showLoggedOut();
}
}
void
SpotifyAccountConfig::loginResponse( bool success, const QString& msg )
SpotifyAccountConfig::loginResponse( bool success, const QString& msg, const QString& username )
{
if ( success )
{
m_ui->loginButton->setText( tr( "Logged in!" ) );
m_ui->loginButton->setEnabled( false );
qDebug() << Q_FUNC_INFO << "Login response with username:" << username;
m_verifiedUsername = username;
m_isLoggedIn = true;
showLoggedIn();
}
else
{
setPlaylists( QList< SpotifyPlaylistInfo* >() );
m_playlistsLoading->fadeOut();
m_ui->loginButton->setText( tr( "Failed: %1" ).arg( msg ) );
m_ui->loginButton->setEnabled( true );
}
@@ -162,9 +194,51 @@ SpotifyAccountConfig::loginResponse( bool success, const QString& msg )
void
SpotifyAccountConfig::resetLoginButton()
SpotifyAccountConfig::showLoggedIn()
{
m_ui->passwordEdit->hide();
m_ui->passwordLabel->hide();
m_ui->usernameEdit->hide();
m_ui->usernameLabel->hide();
if ( !m_loggedInUser )
{
m_loggedInUser = new QLabel( this );
m_ui->verticalLayout->insertWidget( 1, m_loggedInUser, 0, Qt::AlignCenter );
}
qDebug() << "Showing logged in withuserame:" << m_verifiedUsername;
m_loggedInUser->show();
m_loggedInUser->setText( tr( "Logged in as %1" ).arg( m_verifiedUsername ) );
m_ui->loginButton->setText( tr( "Log Out" ) );
m_ui->loginButton->setEnabled( true );
}
void
SpotifyAccountConfig::showLoggedOut()
{
m_ui->passwordEdit->show();
m_ui->passwordLabel->show();
m_ui->usernameEdit->show();
m_ui->usernameLabel->show();
if ( m_loggedInUser )
m_loggedInUser->hide();
m_ui->loginButton->setText( tr( "Log In" ) );
m_ui->loginButton->setEnabled( true );
}
void
SpotifyAccountConfig::resetLoginButton()
{
if ( !m_isLoggedIn )
{
m_ui->loginButton->setText( tr( "Log In" ) );
m_ui->loginButton->setEnabled( true );
}
}

View File

@@ -23,6 +23,7 @@
#include <QVariantMap>
#include <QTimer>
class QLabel;
class AnimatedSpinner;
class QShowEvent;
@@ -55,14 +56,13 @@ public:
void loadFromConfig();
void saveSettings();
void loginResponse( bool success, const QString& msg );
void loginResponse( bool success, const QString& msg, const QString& username );
bool loggedInManually() const { return m_loggedInManually; }
signals:
void login( const QString& username, const QString& pw );
public slots:
// void verifyResult( const QString& msgType, const QVariantMap& msg );
void logout();
protected:
void showEvent( QShowEvent* event );
@@ -72,10 +72,15 @@ private slots:
void resetLoginButton();
private:
void showLoggedIn();
void showLoggedOut();
Ui::SpotifyConfig* m_ui;
QLabel* m_loggedInUser;
QString m_verifiedUsername;
SpotifyAccount* m_account;
AnimatedSpinner* m_playlistsLoading;
bool m_loggedInManually;
bool m_loggedInManually, m_isLoggedIn;
};
}

View File

@@ -0,0 +1,261 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SpotifyInfoPlugin.h"
#include "SpotifyAccount.h"
#include "utils/Closure.h"
using namespace Tomahawk;
using namespace Tomahawk::InfoSystem;
SpotifyInfoPlugin::SpotifyInfoPlugin( Accounts::SpotifyAccount* account )
: InfoPlugin()
, m_account( QWeakPointer< Accounts::SpotifyAccount >( account ) )
{
if ( !m_account.isNull() )
m_supportedGetTypes << InfoAlbumSongs;
}
SpotifyInfoPlugin::~SpotifyInfoPlugin()
{
}
void
SpotifyInfoPlugin::getInfo( InfoRequestData requestData )
{
switch ( requestData.type )
{
case InfoAlbumSongs:
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
dataError( requestData );
return;
}
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
if ( !hash.contains( "album" ) )
{
dataError( requestData );
return;
}
Tomahawk::InfoSystem::InfoStringHash criteria;
criteria[ "album" ] = hash[ "album" ];
if ( hash.contains( "artist" ) )
criteria["artist"] = hash["artist"];
emit getCachedInfo( criteria, 2419200000, requestData );
return;
}
default:
dataError( requestData );
}
}
void
SpotifyInfoPlugin::notInCacheSlot( InfoStringHash criteria, InfoRequestData requestData )
{
switch ( requestData.type )
{
case InfoAlbumSongs:
{
const QString album = criteria[ "album" ];
const QString artist = criteria[ "artist" ];
if ( m_account.isNull() || !m_account.data()->loggedIn() )
{
// No running spotify account, use our webservice
QUrl lookupUrl( "http://ws.spotify.com/search/1/album.json" );
lookupUrl.addQueryItem( "q", QString( "%1 %2" ).arg( album ).arg( album ) );
QNetworkReply * reply = TomahawkUtils::nam()->get( QNetworkRequest( lookupUrl ) );
NewClosure( reply, SIGNAL( finished() ), this, SLOT( albumIdLookupFinished( QNetworkReply*, Tomahawk::InfoSystem::InfoRequestData ) ), reply, requestData );
}
else
{
// Running resolver, so do the lookup through that
qDebug() << Q_FUNC_INFO << "Doing album lookup through spotify:" << album << artist;
QVariantMap message;
message[ "_msgtype" ] = "albumListing";
message[ "artist" ] = artist;
message[ "album" ] = album;
QMetaObject::invokeMethod( m_account.data(), "sendMessage", Qt::QueuedConnection, Q_ARG( QVariantMap, message ),
Q_ARG( QObject*, this ),
Q_ARG( QString, "albumListingResult" ),
Q_ARG( QVariant, QVariant::fromValue< InfoRequestData >( requestData ) ) );
}
break;
}
default:
{
Q_ASSERT( false );
break;
}
}
}
void
SpotifyInfoPlugin::albumListingResult( const QString& msgType, const QVariantMap& msg, const QVariant& extraData )
{
Q_ASSERT( msg.contains( "qid" ) );
Q_ASSERT( extraData.canConvert< InfoRequestData >() );
const InfoRequestData requestData = extraData.value< InfoRequestData >();
QVariantList tracks = msg.value( "tracks" ).toList();
QStringList trackNameList;
foreach ( const QVariant track, tracks )
{
const QVariantMap trackData = track.toMap();
if ( trackData.contains( "track" ) && !trackData[ "track" ].toString().isEmpty() )
trackNameList << trackData[ "track" ].toString();
}
qDebug() << Q_FUNC_INFO << "Successfully got album listing from spotify resolver";
trackListResult( trackNameList, requestData );
}
void
SpotifyInfoPlugin::albumIdLookupFinished( QNetworkReply* reply, const InfoRequestData& requestData )
{
Q_ASSERT( reply );
reply->deleteLater();
if ( reply->error() == QNetworkReply::NoError )
{
QJson::Parser p;
const QVariantMap response = p.parse( reply ).toMap();
if ( !response.contains( "albums" ) )
{
dataError( requestData );
return;
}
const QVariantList albums = response.value( "albums" ).toList();
if ( albums.isEmpty() )
{
dataError( requestData );
return;
}
const QVariantMap album = albums.first().toMap();
const QString id = album.value( "href" ).toString();
if ( id.isEmpty() || !id.contains( "spotify:album" ) )
{
qDebug() << "Empty or malformed spotify album ID from json:" << id << response;
dataError( requestData );
return;
}
qDebug() << "Doing spotify album lookup via webservice with ID:" << id;
QUrl lookupUrl( QString( "http://spotikea.tomahawk-player.org/browse/%1" ).arg( id ) );
QNetworkReply * reply = TomahawkUtils::nam()->get( QNetworkRequest( lookupUrl ) );
NewClosure( reply, SIGNAL( finished() ), this, SLOT( albumContentsLookupFinished( QNetworkReply*, Tomahawk::InfoSystem::InfoRequestData ) ), reply, requestData );
}
else
{
qDebug() << "Network Error retrieving ID from spotify metadata service:" << reply->error() << reply->errorString() << reply->url();
}
}
void
SpotifyInfoPlugin::albumContentsLookupFinished( QNetworkReply* reply, const InfoRequestData& requestData )
{
Q_ASSERT( reply );
reply->deleteLater();
if ( reply->error() == QNetworkReply::NoError )
{
QJson::Parser p;
const QVariantMap response = p.parse( reply ).toMap();
if ( !response.contains( "album" ) )
{
dataError( requestData );
return;
}
const QVariantMap album = response.value( "album" ).toMap();
if ( !album.contains( "result" ) || album.value( "result" ).toList().isEmpty() )
{
dataError( requestData );
return;
}
const QVariantList albumTracks = album.value( "result" ).toList();
QStringList trackNameList;
foreach ( const QVariant& track, albumTracks )
{
const QVariantMap trackMap = track.toMap();
if ( trackMap.contains( "title" ) )
trackNameList << trackMap.value( "title" ).toString();
}
qDebug() << Q_FUNC_INFO << "Successfully got album listing from spotikea service!";
if ( trackNameList.isEmpty() )
dataError( requestData );
else
trackListResult( trackNameList, requestData );
}
else
{
qDebug() << "Network Error retrieving ID from spotify metadata service:" << reply->error() << reply->errorString() << reply->url();
}
}
void
SpotifyInfoPlugin::dataError( InfoRequestData requestData )
{
emit info( requestData, QVariant() );
}
void
SpotifyInfoPlugin::trackListResult( const QStringList& trackNameList, const InfoRequestData& requestData )
{
QVariantMap returnedData;
returnedData["tracks"] = trackNameList;
emit info( requestData, returnedData );
Tomahawk::InfoSystem::InfoStringHash criteria;
criteria["artist"] = requestData.input.value< InfoStringHash>()["artist"];
criteria["album"] = requestData.input.value< InfoStringHash>()["album"];
emit updateCache( criteria, 0, requestData.type, returnedData );
}

View File

@@ -0,0 +1,72 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SPOTIFYINFOPLUGIN_H
#define SPOTIFYINFOPLUGIN_H
#include "infosystem/InfoSystem.h"
#include "DllMacro.h"
#include <QWeakPointer>
class QNetworkReply;
namespace Tomahawk
{
namespace Accounts
{
class SpotifyAccount;
}
namespace InfoSystem
{
class DLLEXPORT SpotifyInfoPlugin : public InfoPlugin
{
Q_OBJECT
public:
explicit SpotifyInfoPlugin( Accounts::SpotifyAccount* account );
virtual ~SpotifyInfoPlugin();
public slots:
void albumListingResult( const QString& msgType, const QVariantMap& msg, const QVariant& extraData );
protected slots:
virtual void init() {}
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData ) {}
private slots:
void albumIdLookupFinished( QNetworkReply* reply, const Tomahawk::InfoSystem::InfoRequestData& requestData );
void albumContentsLookupFinished( QNetworkReply* reply, const Tomahawk::InfoSystem::InfoRequestData& requestData );
private:
void dataError( InfoRequestData );
void trackListResult( const QStringList& trackNameList, const Tomahawk::InfoSystem::InfoRequestData& requestData );
QWeakPointer< Tomahawk::Accounts::SpotifyAccount > m_account;
};
}
}
#endif // SPOTIFYINFOPLUGIN_H

View File

@@ -1,6 +1,7 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2012, Leo Franchi <lfranchi@kde.org>
* Copyright 2012, Hugo Lindström <hugolm84@gmail.com>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -353,6 +354,8 @@ SpotifyPlaylistUpdater::tomahawkPlaylistRenamed(const QString &newT, const QStri
msg[ "newTitle" ] = newT;
msg[ "oldTitle" ] = oldT;
msg[ "playlistid" ] = m_spotifyId;
// TODO check return value
m_spotify.data()->sendMessage( msg, this, "onPlaylistRename" );
}
@@ -493,7 +496,7 @@ SpotifyPlaylistUpdater::plentryToVariant( const QList< plentry_ptr >& entries )
void
SpotifyPlaylistUpdater::onTracksInsertedReturn( const QString& msgType, const QVariantMap& msg )
SpotifyPlaylistUpdater::onTracksInsertedReturn( const QString& msgType, const QVariantMap& msg, const QVariant& )
{
const bool success = msg.value( "success" ).toBool();
@@ -577,7 +580,7 @@ SpotifyPlaylistUpdater::tomahawkTracksRemoved( const QList< query_ptr >& tracks
void
SpotifyPlaylistUpdater::onTracksRemovedReturn( const QString& msgType, const QVariantMap& msg )
SpotifyPlaylistUpdater::onTracksRemovedReturn( const QString& msgType, const QVariantMap& msg, const QVariant& )
{
const bool success = msg.value( "success" ).toBool();
@@ -626,7 +629,7 @@ SpotifyPlaylistUpdater::tomahawkTracksMoved( const QList< plentry_ptr >& tracks,
void
SpotifyPlaylistUpdater::onTracksMovedReturn( const QString& msgType, const QVariantMap& msg )
SpotifyPlaylistUpdater::onTracksMovedReturn( const QString& msgType, const QVariantMap& msg, const QVariant& )
{
const bool success = msg.value( "success" ).toBool();
@@ -674,9 +677,14 @@ SpotifyPlaylistUpdater::variantToQueries( const QVariantList& list )
{
QVariantMap trackMap = blob.toMap();
const query_ptr q = Query::get( trackMap.value( "artist" ).toString(), trackMap.value( "track" ).toString(), trackMap.value( "album" ).toString(), uuid(), false );
if ( trackMap.contains( "id" ) )
q->setProperty( "annotation", trackMap.value( "id" ) );
if ( q.isNull() )
continue;
if ( trackMap.contains( "id" ) )
{
q->setResultHint( trackMap.value( "id" ).toString() );
q->setProperty( "annotation", trackMap.value( "id" ) );
}
queries << q;
}

View File

@@ -1,7 +1,7 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2012, Leo Franchi <lfranchi@kde.org>
*
* Copyright 2012, Hugo Lindström <hugolm84@gmail.com>
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
@@ -74,9 +74,9 @@ protected:
private slots:
// SpotifyResolver message handlers, all take msgtype, msg as argument
void onTracksInsertedReturn( const QString& msgType, const QVariantMap& msg );
void onTracksRemovedReturn( const QString& msgType, const QVariantMap& msg );
void onTracksMovedReturn( const QString& msgType, const QVariantMap& msg );
void onTracksInsertedReturn( const QString& msgType, const QVariantMap& msg, const QVariant& extraData );
void onTracksRemovedReturn( const QString& msgType, const QVariantMap& msg, const QVariant& extraData );
void onTracksMovedReturn( const QString& msgType, const QVariantMap& msg, const QVariant& extraData );
void checkDeleteDialog() const;

View File

@@ -37,6 +37,9 @@
#include "infosystem/InfoSystem.h"
#include "Album.h"
#include "Pipeline.h"
#include "jobview/JobStatusView.h"
#include "jobview/JobStatusModel.h"
#include "jobview/ErrorStatusMessage.h"
#include "utils/Logger.h"
@@ -94,12 +97,9 @@ AudioEngine::AudioEngine()
AudioEngine::~AudioEngine()
{
tDebug() << Q_FUNC_INFO;
m_mediaObject->stop();
TomahawkSettings::instance()->setVolume( volume() );
delete m_audioOutput;
delete m_mediaObject;
}
@@ -604,8 +604,17 @@ AudioEngine::playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk:
{
if ( query->resolvingFinished() )
{
if ( query->numResults() )
if ( query->numResults() && query->results().first()->isOnline() )
{
playItem( playlist, query->results().first() );
return;
}
JobStatusView::instance()->model()->addJob(
new ErrorStatusMessage( tr( "Sorry, Tomahawk couldn't find the track '%1' by %2" ).arg( query->track() ).arg( query->artist() ), 15 ) );
if ( isStopped() )
emit stopped(); // we do this so the original caller knows we couldn't find this track
}
else
{
@@ -621,9 +630,18 @@ void
AudioEngine::playItem( const Tomahawk::artist_ptr& artist )
{
playlistinterface_ptr pli = artist->playlistInterface( Mixed );
if ( pli->trackCount() )
if ( pli->isFinished() )
{
playItem( pli, pli->tracks().first() );
if ( !pli->tracks().count() )
{
JobStatusView::instance()->model()->addJob(
new ErrorStatusMessage( tr( "Sorry, Tomahawk couldn't find the artist '%1'" ).arg( artist->name() ), 15 ) );
if ( isStopped() )
emit stopped(); // we do this so the original caller knows we couldn't find this track
}
else
playItem( pli, pli->tracks().first() );
}
else
{
@@ -638,9 +656,18 @@ void
AudioEngine::playItem( const Tomahawk::album_ptr& album )
{
playlistinterface_ptr pli = album->playlistInterface( Mixed );
if ( pli->trackCount() )
if ( pli->isFinished() )
{
playItem( pli, pli->tracks().first() );
if ( !pli->tracks().count() )
{
JobStatusView::instance()->model()->addJob(
new ErrorStatusMessage( tr( "Sorry, Tomahawk couldn't find the album '%1' by %2" ).arg( album->name() ).arg( album->artist()->name() ), 15 ) );
if ( isStopped() )
emit stopped(); // we do this so the original caller knows we couldn't find this track
}
else
playItem( pli, pli->tracks().first() );
}
else
{
@@ -734,7 +761,7 @@ AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState )
}
}
}
if ( newState == Phonon::PausedState || newState == Phonon::PlayingState || newState == Phonon::ErrorState )
{
tDebug() << "Phonon state now:" << newState;
@@ -860,10 +887,10 @@ AudioEngine::checkStateQueue()
m_mediaObject->play();
if ( paused )
setVolume( m_volume );
break;
}
case Paused:
{
m_volume = volume();

View File

@@ -138,7 +138,7 @@ private slots:
void sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType type );
void sendWaitingNotification() const;
void queueStateSafety();
private:

View File

@@ -100,7 +100,7 @@ TopTracksContext::onTracksFound( const QList<Tomahawk::query_ptr>& queries, Mode
{
Q_UNUSED( mode );
m_topHitsModel->append( queries );
m_topHitsModel->appendQueries( queries );
}

View File

@@ -162,11 +162,9 @@ DatabaseCommand_AddFiles::exec( DatabaseImpl* dbi )
m_ids << fileid;
added++;
}
qDebug() << "Inserted" << added << "tracks to database";
if ( added )
source()->updateIndexWhenSynced();
tDebug() << "Committing" << added << "tracks...";
emit done( m_files, source()->collection() );
}

View File

@@ -62,10 +62,13 @@ DatabaseCommand_DeleteDynamicPlaylist::postCommitHook()
if( playlist.isNull() )
playlist = source()->collection()->station( m_playlistguid );
qDebug() << "Just tried to load playlist for deletion:" << m_playlistguid << "Did we get a null one?" << playlist.isNull() << "is it a station?" << (playlist->mode() == OnDemand);
tLog( LOGVERBOSE ) << "Just tried to load playlist for deletion:" << m_playlistguid << "Did we get a null one?" << playlist.isNull();
Q_ASSERT( !playlist.isNull() );
playlist->reportDeleted( playlist );
if ( !playlist.isNull() )
{
tLog( LOGVERBOSE ) << "is it a station?" << ( playlist->mode() == OnDemand );
playlist->reportDeleted( playlist );
}
if( source()->isLocal() )
Servent::instance()->triggerDBSync();

View File

@@ -91,6 +91,8 @@ DatabaseCommand_GenericSelect::exec( DatabaseImpl* dbi )
artist = query.value( 1 ).toString();
qry = Tomahawk::Query::get( artist, track, QString() );
if ( qry.isNull() )
continue;
}
else if ( m_queryType == Artist )
{

View File

@@ -77,6 +77,9 @@ DatabaseCommand_LoadPlaylistEntries::generateEntries( DatabaseImpl* dbi )
e->setResultHint( query.value( 8 ).toString() );
Tomahawk::query_ptr q = Tomahawk::Query::get( query.value( 2 ).toString(), query.value( 1 ).toString(), query.value( 3 ).toString() );
if ( q.isNull() )
continue;
q->setResultHint( query.value( 8 ).toString() );
q->setProperty( "annotation", e->annotation() );
e->setQuery( q );

View File

@@ -54,6 +54,10 @@ DatabaseCommand_LogPlayback::postCommitHook()
// do not auto resolve this track
m_query = Tomahawk::Query::get( m_artist, m_track, QString() );
}
if ( m_query.isNull() )
return;
m_query->setPlayedBy( source(), m_playtime );
if ( m_action == Finished )

View File

@@ -111,11 +111,18 @@ DatabaseCommand_SetDynamicPlaylistRevision::postCommitHook()
if( playlist.isNull() ) // if it's neither an auto or station, it must not be auto-loaded, so we MUST have been told about it directly
rawPl = m_playlist;
if ( rawPl == 0 )
{
tLog() <<"Got null playlist with guid:" << playlistguid() << "from source and collection:" << source()->friendlyName() << source()->collection()->name() << "and mode is static?:" << (m_mode == Static);
Q_ASSERT( false );
return;
}
// workaround a bug in pre-0.1.0 tomahawks. they created dynamic playlists in OnDemand mode *always*, and then set the mode to the real one.
// now that we separate them, if we get them as one and then get a changed mode, the playlist ends up in the wrong bucket in Collection.
// so here we fix it if we have to.
// HACK
tDebug() << "Does this need the 0.3->0.1 playlist category hack fix?" << ( rawPl->mode() == Static && source()->collection()->autoPlaylist( playlistguid() ).isNull() )
tDebug() << "Does this need the 0.3->0.1 playlist category hack fix?" << ( rawPl->mode() == Static && source()->collection()->autoPlaylist( playlistguid() ).isNull() )
<< ( rawPl->mode() == OnDemand && source()->collection()->station( playlistguid() ).isNull() )
<< rawPl->mode() << source()->collection()->autoPlaylist( playlistguid() ).isNull() << source()->collection()->station( playlistguid() ).isNull();
if( rawPl->mode() == Static && source()->collection()->autoPlaylist( playlistguid() ).isNull() ) // should be here
@@ -123,13 +130,7 @@ DatabaseCommand_SetDynamicPlaylistRevision::postCommitHook()
else if ( rawPl->mode() == OnDemand && source()->collection()->station( playlistguid() ).isNull() ) // should be here
source()->collection()->moveAutoToStation( playlistguid() );
if ( rawPl == 0 )
{
tLog() <<"Got null playlist with guid:" << playlistguid() << "from source and collection:" << source()->friendlyName() << source()->collection()->name() << "and mode is static?:" << (m_mode == Static);
Q_ASSERT( false );
return;
}
if ( !m_controlsV.isEmpty() && m_controls.isEmpty() )
if ( !m_controlsV.isEmpty() && m_controls.isEmpty() )
{
QList<QVariantMap> controlMap;
foreach( const QVariant& v, m_controlsV )

View File

@@ -80,7 +80,6 @@ DatabaseCommand_SetPlaylistRevision::DatabaseCommand_SetPlaylistRevision(
tmp << s;
setOrderedguids( tmp );
setPlaylistguid( playlistguid );
}
@@ -100,7 +99,6 @@ DatabaseCommand_SetPlaylistRevision::postCommitHook()
playlist_ptr playlist = source()->collection()->playlist( m_playlistguid );
if ( playlist.isNull() )
{
qDebug() << m_playlistguid;
Q_ASSERT( !playlist.isNull() );
return;
}
@@ -150,7 +148,9 @@ DatabaseCommand_SetPlaylistRevision::exec( DatabaseImpl* lib )
foreach( const plentry_ptr& e, m_entries )
{
if ( e->query()->results().isEmpty() )
if ( !e->isValid() )
continue;
if ( !e->query()->numResults() )
continue;
adde.bindValue( 0, e->query()->results().first()->url() );
@@ -167,6 +167,9 @@ DatabaseCommand_SetPlaylistRevision::exec( DatabaseImpl* lib )
foreach( const plentry_ptr& e, m_entries )
{
if ( !e->isValid() )
continue;
adde.bindValue( 0, e->query()->track() );
adde.bindValue( 1, e->query()->artist() );
adde.bindValue( 2, e->query()->album() );
@@ -189,6 +192,9 @@ DatabaseCommand_SetPlaylistRevision::exec( DatabaseImpl* lib )
qDebug() << "Num new playlist_items to add:" << m_addedentries.length();
foreach( const plentry_ptr& e, m_addedentries )
{
if ( !e->isValid() )
continue;
// qDebug() << "Adding:" << e->guid() << e->query()->track() << e->query()->artist();
m_addedmap.insert( e->guid(), e ); // needed in postcommithook

View File

@@ -77,9 +77,11 @@ public:
m_addedentries.clear();
foreach( const QVariant& v, vlist )
{
PlaylistEntry * pep = new PlaylistEntry;
PlaylistEntry* pep = new PlaylistEntry;
QJson::QObjectHelper::qvariant2qobject( v.toMap(), pep );
m_addedentries << plentry_ptr(pep);
if ( pep->isValid() )
m_addedentries << plentry_ptr( pep );
}
}
@@ -88,6 +90,9 @@ public:
QVariantList vlist;
foreach( const plentry_ptr& pe, m_addedentries )
{
if ( !pe->isValid() )
continue;
QVariant v = QJson::QObjectHelper::qobject2qvariant( pe.data() );
vlist << v;
}

View File

@@ -328,9 +328,10 @@ DatabaseImpl::artistId( const QString& name_orig, bool autoCreate )
int id = 0;
QString sortname = DatabaseImpl::sortname( name_orig );
QString queryString = QString( "SELECT id FROM artist WHERE sortname = '%1'" ).arg( TomahawkSqlQuery::escape( sortname ) );
TomahawkSqlQuery query = newquery();
query.exec( queryString );
query.prepare( "SELECT id FROM artist WHERE sortname = ?" );
query.addBindValue( sortname );
query.exec();
if ( query.next() )
{
id = query.value( 0 ).toInt();

View File

@@ -49,15 +49,24 @@ FuzzyIndex::FuzzyIndex( QObject* parent, bool wipe )
QByteArray path = m_lucenePath.toUtf8();
const char* cPath = path.constData();
bool failed = false;
tDebug() << "Opening Lucene directory:" << path;
try
{
m_luceneDir = FSDirectory::getDirectory( cPath );
m_analyzer = _CLNEW SimpleAnalyzer();
m_luceneDir = FSDirectory::getDirectory( cPath );
}
catch ( CLuceneError& error )
{
tDebug() << "Caught CLucene error:" << error.what();
failed = true;
}
if ( failed )
{
tDebug() << "Initializing RAM directory instead.";
m_luceneDir = _CLNEW RAMDirectory();
wipe = true;
}
@@ -83,7 +92,7 @@ FuzzyIndex::wipeIndex()
endIndexing();
QTimer::singleShot( 0, this, SLOT( updateIndex() ) );
return true; // FIXME
}
@@ -189,8 +198,8 @@ FuzzyIndex::appendFields( const QMap< unsigned int, QMap< QString, QString > >&
catch( CLuceneError& error )
{
tDebug() << "Caught CLucene error:" << error.what();
wipeIndex();
QTimer::singleShot( 0, this, SLOT( wipeIndex() ) );
}
}
@@ -282,9 +291,9 @@ FuzzyIndex::search( const Tomahawk::query_ptr& query )
}
catch( CLuceneError& error )
{
tDebug() << "Caught CLucene error:" << error.what();
wipeIndex();
tDebug() << "Caught CLucene error:" << error.what() << query->toString();
QTimer::singleShot( 0, this, SLOT( wipeIndex() ) );
}
return resultsmap;
@@ -338,8 +347,8 @@ FuzzyIndex::searchAlbum( const Tomahawk::query_ptr& query )
catch( CLuceneError& error )
{
tDebug() << "Caught CLucene error:" << error.what();
wipeIndex();
QTimer::singleShot( 0, this, SLOT( wipeIndex() ) );
}
return resultsmap;

View File

@@ -61,7 +61,7 @@ public:
void beginIndexing();
void endIndexing();
void appendFields( const QMap< unsigned int, QMap< QString, QString > >& trackData );
signals:
void indexReady();
@@ -73,10 +73,9 @@ public slots:
private slots:
void updateIndex();
private:
bool wipeIndex();
private:
QMutex m_mutex;
QString m_lucenePath;

View File

@@ -51,6 +51,14 @@ TomahawkSqlQuery::escape( QString identifier )
}
bool
TomahawkSqlQuery::prepare( const QString& query )
{
m_query = query;
return QSqlQuery::prepare( query );
}
bool
TomahawkSqlQuery::exec( const QString& query )
{
@@ -76,6 +84,21 @@ TomahawkSqlQuery::exec()
unsigned int retries = 0;
while ( !QSqlQuery::exec() && ++retries < 10 )
{
if ( lastError().text().toLower().contains( "no query" ) ||
lastError().text().toLower().contains( "parameter count mismatch" ) )
{
tDebug() << Q_FUNC_INFO << "Re-preparing query!";
QMap< QString, QVariant > bv = boundValues();
prepare( m_query );
foreach ( const QString& key, bv.keys() )
{
tDebug() << Q_FUNC_INFO << "Rebinding key" << key << "with value" << bv.value( key );
bindValue( key, bv.value( key ) );
}
}
if ( isBusyError( lastError() ) )
retries = 0;
@@ -104,7 +127,7 @@ TomahawkSqlQuery::commitTransaction()
#endif
if ( log )
tLog( LOGSQL ) << "TomahawkSqlQuery::commitTransaction running in thread " << QThread::currentThread();
unsigned int retries = 0;
while ( !m_db.commit() && ++retries < 10 )
{
@@ -114,7 +137,7 @@ TomahawkSqlQuery::commitTransaction()
tDebug() << "INFO: Retrying failed commit:" << retries << lastError().text();
TomahawkUtils::msleep( 10 );
}
return ( retries < 10 );
}
@@ -136,5 +159,5 @@ TomahawkSqlQuery::isBusyError( const QSqlError& error ) const
{
const QString text = error.text().trimmed().toLower();
return ( text.contains( "no query" ) || text.contains( "locked" ) || text.contains( "busy" ) || text.isEmpty() );
return ( text.contains( "locked" ) || text.contains( "busy" ) || text.isEmpty() );
}

View File

@@ -35,17 +35,19 @@ public:
static QString escape( QString identifier );
bool prepare( const QString& query );
bool exec( const QString& query );
bool exec();
bool commitTransaction();
private:
bool isBusyError( const QSqlError& error ) const;
void showError();
QSqlDatabase m_db;
QString m_query;
};
#endif // TOMAHAWKSQLQUERY_H

View File

@@ -132,10 +132,11 @@ InfoBar::setDescription( const QString& s )
ui->descriptionLabel->setText( s );
}
void
InfoBar::setDescription( const artist_ptr& artist )
{
m_queryLabel->setQuery( Query::get( artist->name(), QString(), QString() ) );
m_queryLabel->setArtist( artist );
m_queryLabel->setExtraContentsMargins( 4, 0, 0, 0 );
if ( !m_queryLabel->isVisible() )
@@ -151,16 +152,17 @@ InfoBar::setDescription( const artist_ptr& artist )
}
void
InfoBar::setDescription( const album_ptr& )
InfoBar::setDescription( const album_ptr& )
{
// TODO
}
void
InfoBar::artistClicked()
{
if ( m_queryLabel && !m_queryLabel->query().isNull() )
ViewManager::instance()->show( Artist::get( m_queryLabel->artist() ) );
if ( m_queryLabel && !m_queryLabel->artist().isNull() )
ViewManager::instance()->show( m_queryLabel->artist() );
}
@@ -212,7 +214,6 @@ InfoBar::setUpdaters( const QList<PlaylistUpdaterInterface*>& updaters )
newUpdaterWidgets << updater->configurationWidget();
}
foreach ( QWidget* updaterWidget, m_updaterConfigurations )
{
updaterWidget->hide();

View File

@@ -26,8 +26,10 @@
#include <QListView>
#define ROW_HEIGHT 20
#define ICON_PADDING 1
#define ICON_PADDING 2
#define PADDING 2
JobStatusDelegate::JobStatusDelegate( QObject* parent )
: QStyledItemDelegate ( parent )
, m_parentView( qobject_cast< QListView* >( parent ) )
@@ -35,6 +37,7 @@ JobStatusDelegate::JobStatusDelegate( QObject* parent )
Q_ASSERT( m_parentView );
}
JobStatusDelegate::~JobStatusDelegate()
{
@@ -55,7 +58,7 @@ JobStatusDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
// painter->drawLine( opt.rect.topLeft(), opt.rect.topRight() );
painter->setRenderHint( QPainter::Antialiasing );
QRect iconRect( ICON_PADDING, ICON_PADDING + opt.rect.y(), ROW_HEIGHT - 2*ICON_PADDING, ROW_HEIGHT - 2*ICON_PADDING );
QRect iconRect( ICON_PADDING, ICON_PADDING + opt.rect.y(), ROW_HEIGHT - 2 * ICON_PADDING, ROW_HEIGHT - 2 * ICON_PADDING );
if ( allowMultiLine )
iconRect.moveTop( opt.rect.top() + opt.rect.height() / 2 - iconRect.height() / 2);
QPixmap p = index.data( Qt::DecorationRole ).value< QPixmap >();
@@ -71,22 +74,24 @@ JobStatusDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
if ( !rCol.isEmpty() )
{
const int w = fm.width( rCol );
const QRect rRect( opt.rect.right() - PADDING - w, PADDING + opt.rect.y(), w, opt.rect.height() - 2*PADDING );
const QRect rRect( opt.rect.right() - PADDING - w, PADDING + opt.rect.y(), w, opt.rect.height() - 2 * PADDING );
painter->drawText( rRect, Qt::AlignCenter, rCol );
rightEdge = rRect.left();
}
const int mainW = rightEdge - 3*PADDING - iconRect.right();
const int mainW = rightEdge - 4 * PADDING - iconRect.right();
QString mainText = index.data( Qt::DisplayRole ).toString();
QTextOption to( Qt::AlignLeft | Qt::AlignVCenter );
if ( !allowMultiLine )
mainText = fm.elidedText( mainText, Qt::ElideRight, mainW );
mainText = fm.elidedText( mainText, Qt::ElideRight, mainW );
else
to.setWrapMode( QTextOption::WrapAtWordBoundaryOrAnywhere );
painter->drawText( QRect( iconRect.right() + 2*PADDING, PADDING + opt.rect.y(), mainW, opt.rect.height() - 2*PADDING ), mainText, to );
painter->drawText( QRect( iconRect.right() + 4 * PADDING, PADDING + opt.rect.y(), mainW, opt.rect.height() - 2 * PADDING ), mainText, to );
}
QSize
JobStatusDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
@@ -102,11 +107,11 @@ JobStatusDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelInd
initStyleOption( &opt, index );
const QString text = index.data( Qt::DisplayRole ).toString();
const int leftEdge = ICON_PADDING + ROW_HEIGHT + 2*PADDING;
const int leftEdge = ICON_PADDING + ROW_HEIGHT + 2 * PADDING;
const QRect rect = opt.fontMetrics.boundingRect( leftEdge, opt.rect.top(), m_parentView->width() - leftEdge, 200, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, text );
m_cachedMultiLineHeights.insert( index, rect.height() + 4*PADDING );
m_cachedMultiLineHeights.insert( index, rect.height() + 4 * PADDING );
return QSize( QStyledItemDelegate::sizeHint ( option, index ).width(), rect.height() + 4*PADDING );
return QSize( QStyledItemDelegate::sizeHint ( option, index ).width(), rect.height() + 4 * PADDING );
}

View File

@@ -101,13 +101,12 @@ JobStatusView::setModel( JobStatusModel* m )
void
JobStatusView::customDelegateJobInserted( int row, JobStatusItem* item )
{
tLog() << Q_FUNC_INFO << "item is " << item << ", row is " << row;
tLog() << Q_FUNC_INFO << "item is" << item << ", row is" << row;
if ( !item )
return;
tLog() << Q_FUNC_INFO << "telling item to create delegate";
item->createDelegate( m_view );
tLog() << Q_FUNC_INFO << "item delegate is " << item->customDelegate();
tLog() << Q_FUNC_INFO << "item delegate is" << item->customDelegate();
m_view->setItemDelegateForRow( row, item->customDelegate() );
AclJobDelegate* delegate = qobject_cast< AclJobDelegate* >( item->customDelegate() );
if ( delegate )
@@ -127,7 +126,7 @@ JobStatusView::customDelegateJobInserted( int row, JobStatusItem* item )
void
JobStatusView::customDelegateJobRemoved( int row )
{
tLog() << Q_FUNC_INFO << "row is " << row;
tLog() << Q_FUNC_INFO << "row is" << row;
}
@@ -138,12 +137,12 @@ JobStatusView::refreshDelegates()
int count = m_model->rowCount();
for ( int i = 0; i < count; i++ )
{
tLog() << Q_FUNC_INFO << "checking row " << i;
tLog() << Q_FUNC_INFO << "checking row" << i;
QModelIndex index = m_model->index( i );
QVariant itemVar = index.data( JobStatusModel::JobDataRole );
if ( !itemVar.canConvert< JobStatusItem* >() || !itemVar.value< JobStatusItem* >() )
{
tLog() << Q_FUNC_INFO << "unable to fetch JobStatusItem* at row " << i;
tLog() << Q_FUNC_INFO << "unable to fetch JobStatusItem* at row" << i;
continue;
}
JobStatusItem* item = itemVar.value< JobStatusItem* >();

View File

@@ -30,7 +30,7 @@ LatchedStatusItem::LatchedStatusItem( const Tomahawk::source_ptr& from, const To
, m_to( to )
, m_parent( parent )
{
m_text = tr( "%1 is listening along to you!" ).arg( from->friendlyName() );
m_text = tr( "%1 is listening along with you!" ).arg( from->friendlyName() );
}
LatchedStatusItem::~LatchedStatusItem()

View File

@@ -29,11 +29,14 @@
QPixmap* PipelineStatusItem::s_pixmap = 0;
PipelineStatusItem::PipelineStatusItem()
PipelineStatusItem::PipelineStatusItem( const Tomahawk::query_ptr& q )
: JobStatusItem()
{
connect( Tomahawk::Pipeline::instance(), SIGNAL( resolving( Tomahawk::query_ptr ) ), this, SLOT( resolving( Tomahawk::query_ptr ) ) );
connect( Tomahawk::Pipeline::instance(), SIGNAL( idle() ), this, SLOT( idle() ) );
if ( !q.isNull() )
resolving( q );
}
@@ -102,11 +105,10 @@ PipelineStatusManager::PipelineStatusManager( QObject* parent )
void
PipelineStatusManager::resolving( const Tomahawk::query_ptr& p )
{
Q_UNUSED( p );
if ( m_curItem.isNull() )
{
// No current query item and we're resolving something, so show it
m_curItem = QWeakPointer< PipelineStatusItem >( new PipelineStatusItem );
m_curItem = QWeakPointer< PipelineStatusItem >( new PipelineStatusItem( p ) );
JobStatusView::instance()->model()->addJob( m_curItem.data() );
}
}

View File

@@ -28,7 +28,7 @@ class PipelineStatusItem : public JobStatusItem
{
Q_OBJECT
public:
explicit PipelineStatusItem();
explicit PipelineStatusItem( const Tomahawk::query_ptr& q );
virtual ~PipelineStatusItem();
virtual QString rightColumnText() const;

View File

@@ -107,16 +107,17 @@ void
DBSyncConnection::check()
{
qDebug() << Q_FUNC_INFO << this << m_source->id();
if ( m_state != UNKNOWN && m_state != SYNCED )
{
qDebug() << "Syncing in progress already.";
return;
}
if ( m_state == SHUTDOWN )
{
qDebug() << "Aborting sync due to shutdown.";
return;
}
if ( m_state != UNKNOWN && m_state != SYNCED )
{
qDebug() << "Syncing in progress already.";
return;
}
m_uscache.clear();
changeState( CHECKING );

View File

@@ -112,7 +112,7 @@ CustomPlaylistView::tracksGenerated( QList< query_ptr > tracks )
return;
m_model->clear();
m_model->append( newTracks );
m_model->appendQueries( newTracks );
}

View File

@@ -56,7 +56,10 @@ GridItemDelegate::GridItemDelegate( QAbstractItemView* parent, PlayableProxyMode
if ( m_view && m_view->metaObject()->indexOfSignal( "modelChanged()" ) > -1 )
connect( m_view, SIGNAL( modelChanged() ), this, SLOT( modelChanged() ) );
connect( m_view, SIGNAL( scrolledContents( int, int ) ), SLOT( onScrolled( int, int ) ) );
connect( proxy, SIGNAL( rowsAboutToBeInserted( QModelIndex, int, int ) ), SLOT( modelChanged() ) );
connect( proxy, SIGNAL( rowsAboutToBeRemoved( QModelIndex, int, int ) ), SLOT( modelChanged() ) );
connect( m_view, SIGNAL( scrolledContents( int, int ) ), SLOT( onViewChanged() ) );
connect( m_view, SIGNAL( resized() ), SLOT( onViewChanged() ) );
}
@@ -116,8 +119,8 @@ GridItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
m_covers.insert( index, QSharedPointer< Tomahawk::PixmapDelegateFader >( new Tomahawk::PixmapDelegateFader( item->query(), r.size(), TomahawkUtils::Grid ) ) );
}
_detail::Closure* closure = NewClosure( m_covers[ index ], SIGNAL( repaintRequest() ), const_cast<GridItemDelegate*>(this), SLOT( doUpdateIndex( QPersistentModelIndex ) ), QPersistentModelIndex( index ) );
closure->setAutoDelete( false );
NewClosure( m_covers[ index ], SIGNAL( repaintRequest() ),
const_cast<GridItemDelegate*>(this), SLOT( doUpdateIndex( QPersistentModelIndex ) ), QPersistentModelIndex( index ) )->setAutoDelete( false );
}
QSharedPointer< Tomahawk::PixmapDelegateFader > fader = m_covers[ index ];
@@ -237,14 +240,18 @@ GridItemDelegate::onPlayClicked( const QPersistentModelIndex& index )
PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) );
if ( item )
{
_detail::Closure* closure;
NewClosure( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ),
const_cast<GridItemDelegate*>(this), SLOT( onPlaybackStarted( QPersistentModelIndex ) ), QPersistentModelIndex( index ) );
closure = NewClosure( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ),
const_cast<GridItemDelegate*>(this), SLOT( onPlaybackStarted( QPersistentModelIndex ) ), QPersistentModelIndex( index ) );
m_closures.remove( index );
closure = NewClosure( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ),
const_cast<GridItemDelegate*>(this), SLOT( onPlaylistChanged( QPersistentModelIndex ) ), QPersistentModelIndex( index ) );
closure->setAutoDelete( false );
m_closures.insertMulti( index, NewClosure( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ),
const_cast<GridItemDelegate*>(this), SLOT( onPlaylistChanged( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ) );
m_closures.insertMulti( index, NewClosure( AudioEngine::instance(), SIGNAL( stopped() ),
const_cast<GridItemDelegate*>(this), SLOT( onPlaylistChanged( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ) );
foreach ( _detail::Closure* closure, m_closures.values( index ) )
closure->setAutoDelete( false );
connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackFinished() ) );
@@ -421,19 +428,22 @@ GridItemDelegate::doUpdateIndex( const QPersistentModelIndex& idx )
void
GridItemDelegate::onScrolled( int dx, int dy )
GridItemDelegate::onViewChanged()
{
foreach ( QWidget* widget, m_spinner.values() )
foreach ( const QPersistentModelIndex& index, m_spinner.keys() )
{
widget->move( widget->pos() + QPoint( dx, dy ) );
QRect rect = m_view->visualRect( index );
m_spinner.value( index )->move( rect.center() - QPoint( 23, 23 ) );
}
foreach ( ImageButton* button, m_playButton.values() )
foreach ( const QPersistentModelIndex& index, m_playButton.keys() )
{
button->move( button->pos() + QPoint( dx, dy ) );
QRect rect = m_view->visualRect( index );
m_playButton.value( index )->move( rect.center() - QPoint( 23, 23 ) );
}
foreach ( ImageButton* button, m_pauseButton.values() )
foreach ( const QPersistentModelIndex& index, m_pauseButton.keys() )
{
button->move( button->pos() + QPoint( dx, dy ) );
QRect rect = m_view->visualRect( index );
m_pauseButton.value( index )->move( rect.center() - QPoint( 23, 23 ) );
}
}
@@ -473,11 +483,19 @@ GridItemDelegate::onPlaylistChanged( const QPersistentModelIndex& index )
if ( finished )
{
foreach ( _detail::Closure* closure, m_closures.values( index ) )
closure->deleteLater();
if ( m_pauseButton.contains( index ) )
{
m_pauseButton[ index ]->deleteLater();
m_pauseButton.remove( index );
}
if ( m_spinner.contains( index ) )
{
m_spinner[ index ]->deleteLater();
m_spinner.remove( index );
}
}
}
}

View File

@@ -29,6 +29,10 @@ namespace Tomahawk {
class PixmapDelegateFader;
}
namespace _detail {
class Closure;
}
class QEvent;
class QTimeLine;
class PlayableProxyModel;
@@ -55,7 +59,7 @@ private slots:
void modelChanged();
void doUpdateIndex( const QPersistentModelIndex& idx );
void onScrolled( int dx, int dy );
void onViewChanged();
void onPlaybackStarted( const QPersistentModelIndex& index );
void onPlaybackFinished();
@@ -64,6 +68,7 @@ private slots:
void fadingFrameChanged( const QPersistentModelIndex& );
void fadingFrameFinished( const QPersistentModelIndex& );
private:
QTimeLine* createTimeline( QTimeLine::Direction direction );
@@ -81,8 +86,8 @@ private:
mutable QHash< QPersistentModelIndex, QWidget* > m_spinner;
mutable QHash< QPersistentModelIndex, ImageButton* > m_playButton;
mutable QHash< QPersistentModelIndex, ImageButton* > m_pauseButton;
mutable QHash< QPersistentModelIndex, QTimeLine* > m_hoverFaders;
mutable QHash< QPersistentModelIndex, _detail::Closure* > m_closures;
};
#endif // GRIDITEMDELEGATE_H

View File

@@ -77,9 +77,6 @@ GridView::GridView( QWidget* parent )
setAutoResize( false );
setProxyModel( new PlayableProxyModel( this ) );
/* m_overlay->setText( tr( "After you have scanned your music collection you will find your latest album additions right here." ) );
m_overlay->setText( tr( "This collection doesn't have any recent albums." ) );*/
connect( this, SIGNAL( doubleClicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) );
connect( this, SIGNAL( customContextMenuRequested( QPoint ) ), SLOT( onCustomContextMenu( QPoint ) ) );
@@ -208,6 +205,8 @@ GridView::resizeEvent( QResizeEvent* event )
{
QListView::resizeEvent( event );
layoutItems();
emit resized();
}

View File

@@ -78,6 +78,7 @@ public slots:
signals:
void modelChanged();
void scrolledContents( int dx, int dy );
void resized();
protected:
virtual void startDrag( Qt::DropActions supportedActions );

View File

@@ -89,12 +89,6 @@ PlayableItem::PlayableItem( const Tomahawk::query_ptr& query, PlayableItem* pare
connect( query.data(), SIGNAL( updated() ),
SIGNAL( dataChanged() ) );
connect( query.data(), SIGNAL( resultsAdded( QList<Tomahawk::result_ptr> ) ),
SLOT( onResultsChanged() ) );
connect( query.data(), SIGNAL( resultsRemoved( Tomahawk::result_ptr ) ),
SLOT( onResultsChanged() ) );
connect( query.data(), SIGNAL( resultsChanged() ),
SLOT( onResultsChanged() ) );
}
@@ -113,12 +107,6 @@ PlayableItem::PlayableItem( const Tomahawk::plentry_ptr& entry, PlayableItem* pa
connect( m_query.data(), SIGNAL( updated() ),
SIGNAL( dataChanged() ) );
connect( m_query.data(), SIGNAL( resultsAdded( QList<Tomahawk::result_ptr> ) ),
SLOT( onResultsChanged() ) );
connect( m_query.data(), SIGNAL( resultsRemoved( Tomahawk::result_ptr ) ),
SLOT( onResultsChanged() ) );
connect( m_query.data(), SIGNAL( resultsChanged() ),
SLOT( onResultsChanged() ) );
}
@@ -130,7 +118,7 @@ PlayableItem::init( PlayableItem* parent, int row )
m_fetchingMore = false;
m_isPlaying = false;
m_parent = parent;
if ( parent )
{
if ( row < 0 )
@@ -145,7 +133,7 @@ PlayableItem::init( PlayableItem* parent, int row )
this->model = parent->model;
}
if ( !m_query.isNull() )
{
onResultsChanged();

View File

@@ -46,7 +46,7 @@ PlayableModel::PlayableModel( QObject* parent, bool loading )
{
connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ), Qt::DirectConnection );
connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ), Qt::DirectConnection );
m_header << tr( "Artist" ) << tr( "Title" ) << tr( "Composer" ) << tr( "Album" ) << tr( "Track" ) << tr( "Duration" )
<< tr( "Bitrate" ) << tr( "Age" ) << tr( "Year" ) << tr( "Size" ) << tr( "Origin" ) << tr( "Score" ) << tr( "Name" );
@@ -200,11 +200,11 @@ PlayableModel::queryData( const query_ptr& query, int column, int role ) const
case Album:
return query->album();
break;
case Composer:
return query->composer();
break;
case Duration:
return TomahawkUtils::timeToString( query->duration() );
break;
@@ -223,7 +223,7 @@ PlayableModel::queryData( const query_ptr& query, int column, int role ) const
}
}
break;
default:
break;
}
@@ -256,7 +256,7 @@ PlayableModel::queryData( const query_ptr& query, int column, int role ) const
case Score:
return query->results().first()->score();
break;
default:
break;
}
@@ -305,7 +305,7 @@ PlayableModel::data( const QModelIndex& index, int role ) const
{
return albumData( entry->album(), role );
}
return QVariant();
}
@@ -508,6 +508,7 @@ PlayableModel::mimeData( const QModelIndexList &indexes ) const
// Ok... we have to use mixed
resultData.clear();
QDataStream mixedStream( &resultData, QIODevice::WriteOnly );
foreach ( const QModelIndex& i, indexes )
{
if ( i.column() > 0 || indexes.contains( i.parent() ) )
@@ -520,22 +521,22 @@ PlayableModel::mimeData( const QModelIndexList &indexes ) const
if ( !item->artist().isNull() )
{
const artist_ptr& artist = item->artist();
resultStream << QString( "application/tomahawk.metadata.artist" ) << artist->name();
mixedStream << QString( "application/tomahawk.metadata.artist" ) << artist->name();
}
else if ( !item->album().isNull() )
{
const album_ptr& album = item->album();
resultStream << QString( "application/tomahawk.metadata.album" ) << album->artist()->name() << album->name();
mixedStream << QString( "application/tomahawk.metadata.album" ) << album->artist()->name() << album->name();
}
else if ( !item->result().isNull() )
{
const result_ptr& result = item->result();
resultStream << QString( "application/tomahawk.result.list" ) << qlonglong( &result );
mixedStream << QString( "application/tomahawk.result.list" ) << qlonglong( &result );
}
else if ( !item->query().isNull() )
{
const query_ptr& query = item->query();
resultStream << QString( "application/tomahawk.query.list" ) << qlonglong( &query );
mixedStream << QString( "application/tomahawk.query.list" ) << qlonglong( &query );
}
}
@@ -576,20 +577,6 @@ PlayableModel::queries() const
}
template<typename T>
void
PlayableModel::insertInternal( const T& item, int row )
{
if ( item.isNull() )
return;
QList< T > list;
list << item;
insert( list, row );
}
template <typename T>
void
PlayableModel::insertInternal( const QList< T >& items, int row )
@@ -598,7 +585,7 @@ PlayableModel::insertInternal( const QList< T >& items, int row )
{
emit trackCountChanged( rowCount( QModelIndex() ) );
emit itemCountChanged( rowCount( QModelIndex() ) );
finishLoading();
return;
}
@@ -633,12 +620,12 @@ PlayableModel::insertInternal( const QList< T >& items, int row )
void
PlayableModel::remove( int row, bool moreToCome )
{
remove( index( row, 0, QModelIndex() ), moreToCome );
removeIndex( index( row, 0, QModelIndex() ), moreToCome );
}
void
PlayableModel::remove( const QModelIndex& index, bool moreToCome )
PlayableModel::removeIndex( const QModelIndex& index, bool moreToCome )
{
if ( QThread::currentThread() != thread() )
{
@@ -666,7 +653,7 @@ PlayableModel::remove( const QModelIndex& index, bool moreToCome )
void
PlayableModel::remove( const QList<QModelIndex>& indexes )
PlayableModel::removeIndexes( const QList<QModelIndex>& indexes )
{
QList<QPersistentModelIndex> pil;
foreach ( const QModelIndex& idx, indexes )
@@ -674,12 +661,12 @@ PlayableModel::remove( const QList<QModelIndex>& indexes )
pil << idx;
}
remove( pil );
removeIndexes( pil );
}
void
PlayableModel::remove( const QList<QPersistentModelIndex>& indexes )
PlayableModel::removeIndexes( const QList<QPersistentModelIndex>& indexes )
{
QList<QPersistentModelIndex> finalIndexes;
foreach ( const QPersistentModelIndex index, indexes )
@@ -691,7 +678,7 @@ PlayableModel::remove( const QList<QPersistentModelIndex>& indexes )
for ( int i = 0; i < finalIndexes.count(); i++ )
{
remove( finalIndexes.at( i ), i + 1 != finalIndexes.count() );
removeIndex( finalIndexes.at( i ), i + 1 != finalIndexes.count() );
}
}
@@ -828,84 +815,102 @@ PlayableModel::itemFromIndex( const QModelIndex& index ) const
void
PlayableModel::append( const Tomahawk::artist_ptr& artist )
PlayableModel::appendArtist( const Tomahawk::artist_ptr& artist )
{
insert( artist, rowCount( QModelIndex() ) );
QList< artist_ptr > artists;
artists << artist;
appendArtists( artists );
}
void
PlayableModel::append( const Tomahawk::album_ptr& album )
PlayableModel::appendAlbum( const Tomahawk::album_ptr& album )
{
insert( album, rowCount( QModelIndex() ) );
QList< album_ptr > albums;
albums << album;
appendAlbums( albums );
}
void
PlayableModel::append( const Tomahawk::query_ptr& query )
PlayableModel::appendQuery( const Tomahawk::query_ptr& query )
{
insert( query, rowCount( QModelIndex() ) );
QList< query_ptr > queries;
queries << query;
appendQueries( queries );
}
void
PlayableModel::append( const QList< Tomahawk::artist_ptr >& artists )
PlayableModel::appendArtists( const QList< Tomahawk::artist_ptr >& artists )
{
insert( artists, rowCount( QModelIndex() ) );
insertArtists( artists, rowCount( QModelIndex() ) );
}
void
PlayableModel::append( const QList< Tomahawk::album_ptr >& albums )
PlayableModel::appendAlbums( const QList< Tomahawk::album_ptr >& albums )
{
insert( albums, rowCount( QModelIndex() ) );
insertAlbums( albums, rowCount( QModelIndex() ) );
}
void
PlayableModel::append( const QList< Tomahawk::query_ptr >& queries )
PlayableModel::appendQueries( const QList< Tomahawk::query_ptr >& queries )
{
insert( queries, rowCount( QModelIndex() ) );
insertQueries( queries, rowCount( QModelIndex() ) );
}
void
PlayableModel::insert( const Tomahawk::artist_ptr& artist, int row )
PlayableModel::insertArtist( const Tomahawk::artist_ptr& artist, int row )
{
insertInternal( artist, row );
QList< artist_ptr > artists;
artists << artist;
insertArtists( artists, row );
}
void
PlayableModel::insert( const Tomahawk::album_ptr& album, int row )
PlayableModel::insertAlbum( const Tomahawk::album_ptr& album, int row )
{
insertInternal( album, row );
QList< album_ptr > albums;
albums << album;
insertAlbums( albums, row );
}
void
PlayableModel::insert( const Tomahawk::query_ptr& query, int row )
PlayableModel::insertQuery( const Tomahawk::query_ptr& query, int row )
{
insertInternal( query, row );
QList< query_ptr > queries;
queries << query;
insertQueries( queries, row );
}
void
PlayableModel::insert( const QList< Tomahawk::artist_ptr >& artists, int row )
PlayableModel::insertArtists( const QList< Tomahawk::artist_ptr >& artists, int row )
{
insertInternal( artists, row );
}
void
PlayableModel::insert( const QList< Tomahawk::album_ptr >& albums, int row )
PlayableModel::insertAlbums( const QList< Tomahawk::album_ptr >& albums, int row )
{
insertInternal( albums, row );
}
void
PlayableModel::insert( const QList< Tomahawk::query_ptr >& queries, int row )
PlayableModel::insertQueries( const QList< Tomahawk::query_ptr >& queries, int row )
{
insertInternal( queries, row );
}

Some files were not shown because too many files have changed in this diff Show More