1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-09-11 14:40:52 +02:00

Compare commits

..

494 Commits

Author SHA1 Message Date
Michael Zanetti
a4d01685cf Merge branch 'master' into decltest 2012-08-03 22:19:56 +02:00
Michael Zanetti
c6101fb35b increase space around the toggle button's text 2012-08-03 22:08:15 +02:00
Michael Zanetti
467cb26006 add artist mode for stations 2012-08-03 21:53:56 +02:00
Michael Zanetti
8f20c828fa Merge branch 'master' into decltest
Conflicts:
	resources.qrc
	src/libtomahawk/CMakeLists.txt
	src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp
2012-08-03 20:45:26 +02:00
Michael Zanetti
76ccd71c51 decrease font sizes by 1 point 2012-08-03 19:10:06 +02:00
Michael Zanetti
bb95e33673 Merge branch 'master' of github.com:tomahawk-player/tomahawk into retina 2012-08-03 18:46:33 +02:00
Michael Zanetti
012bb49328 remove useless assert 2012-08-03 18:46:08 +02:00
Leo Franchi
3b083a2535 Handle case where attica load is super slow 2012-08-03 11:41:35 -04:00
Leo Franchi
2f8b23b908 Merge pull request #110 from teo/master
Settings dialog size and alignment fixes
2012-08-03 07:20:58 -07:00
Teo Mrnjavac
5d54f20bec Back to page 0. 2012-08-03 16:08:54 +02:00
Teo Mrnjavac
afba38f9ff Fixed alignment in Settings dialog, advanced page. 2012-08-03 16:03:37 +02:00
Teo Mrnjavac
0dd2cb5f15 Don't let the Settings dialog be shrunk too much. 2012-08-03 16:03:37 +02:00
Christian Muehlhaeuser
8b42e88a8d * Fixes for compiling new settings dialog on OSX. 2012-08-03 07:20:11 +02:00
Dominik Schmidt
70cb7bd92b QCA is not optional anymore for a long time 2012-08-03 01:28:03 +02:00
Tomahawk CI
87fc3563a1 Automatic merge of Transifex translations 2012-08-03 00:17:14 +02:00
Jeff Mitchell
95c48aa722 Massively improve/simplify the seek slider logic. Fails (kinda) when you seek after pausing, but this is a Phonon bug that needs an update, no real way to work around it 2012-08-02 17:33:21 -04:00
Christian Muehlhaeuser
6fadeab1dd Revert "Moved the settings categories to the left."
This reverts commit 2236b0ffb3.
2012-08-02 21:49:08 +02:00
Christian Muehlhaeuser
9d03d77068 * Style fix. 2012-08-02 21:24:45 +02:00
Christian Muehlhaeuser
585009bc16 Merge pull request #109 from teo/master
Settings Dialog UX changes
2012-08-02 12:23:27 -07:00
Teo Mrnjavac
a19198b206 Removed the annoying thin grey line from the Queue splitter widget.
Also made the ContextWidget header cursor a PointingHand because
consistency is good.
2012-08-02 19:01:30 +02:00
Leo Franchi
99d75636a9 Ignore preview-only URLs for now, until we properly handle them 2012-08-02 09:26:51 -04:00
Leo Franchi
eabefe438d Fix ambiguous if() statement 2012-08-02 09:26:46 -04:00
Teo Mrnjavac
7e47d0efcc Reenabled ProxyStyle under QtCurve, and fixed QSlider appearance. 2012-08-02 12:25:18 +02:00
Teo Mrnjavac
2236b0ffb3 Moved the settings categories to the left. 2012-08-02 12:25:18 +02:00
Teo Mrnjavac
67611d10d1 Added a styled separator line in the Settings Dialog. 2012-08-02 12:25:18 +02:00
Teo Mrnjavac
97e1d0fe3f Replace the list widget in the settings dialog with a horizontal thingy. 2012-08-02 12:25:18 +02:00
Jason Herskowitz
a9339caa8b Tweak subscribe icon 2012-08-01 20:55:21 -04:00
Jason Herskowitz
2b4e1c7d92 New subscribe icon 2012-08-01 20:55:21 -04:00
Tomahawk CI
9eaec0106b Automatic merge of Transifex translations 2012-08-02 00:17:36 +02:00
Leo Franchi
36fcbe83b7 Merge pull request #108 from teo/master
Workaround to force QtCurve to not draw branching primitives in SourceTreeView
2012-08-01 06:13:10 -07:00
Teo Mrnjavac
003b959482 Ensure that we do not draw branching primitives under QtCurve. 2012-08-01 12:52:26 +02:00
Leo Franchi
c7cbb47742 Re-enable button when fixing login 2012-07-31 22:57:18 -04:00
Leo Franchi
ea3f982415 Don't re-start already running animation 2012-07-31 22:21:44 -04:00
Leo Franchi
03121f95ff Fix oversight in debounce: Singleshot timer 2012-07-31 22:21:31 -04:00
Leo Franchi
18c50a3f02 Emit sizeHintChanged() when showing progressbar 2012-07-31 22:21:15 -04:00
Leo Franchi
eecceb134a Show UI if fetching from last.fm failed 2012-07-31 21:33:17 -04:00
Leo Franchi
a463c02273 Debounce updates to loved tracks model 2012-07-31 21:33:04 -04:00
Leo Franchi
ddfef98e20 Speed up the loved tracks model 2012-07-31 18:18:37 -04:00
Leo Franchi
0c4db907b3 UI tweaks for synchronizing last.fm loved tracks 2012-07-31 18:18:37 -04:00
Leo Franchi
26509493a2 Initial last.fm loved track syncing 2012-07-31 18:18:37 -04:00
Tomahawk CI
a70f14e7ab Automatic merge of Transifex translations 2012-08-01 00:17:58 +02:00
Leo Franchi
2c3e7492a5 Jump to and scroll to playing track in grid view on track page 2012-07-30 19:53:10 -04:00
Leo Franchi
adde983572 When double-clicking on a track in grid view, go to the track page 2012-07-30 19:53:10 -04:00
Tomahawk CI
527b4906c9 Automatic merge of Transifex translations 2012-07-31 00:18:08 +02:00
Leo Franchi
8e7c9d8130 Use the query that was used to play the track in AudioEngine 2012-07-29 22:50:18 -04:00
Leo Franchi
bfb10e385f Hide warning 2012-07-29 22:50:18 -04:00
Leo Franchi
e28d61935e Show playing icon when playing grid-view playlists 2012-07-29 22:50:18 -04:00
Leo Franchi
ea11f7c7be Show currently-playing speaker for GenericPageItems with children interfaces 2012-07-29 22:50:18 -04:00
Leo Franchi
cfbccb85cf TWK-1017: Show now-playing icon next to playlist in flat view mode 2012-07-29 22:50:18 -04:00
Tomahawk CI
643b2374a6 Automatic merge of Transifex translations 2012-07-30 00:16:59 +02:00
Tomahawk CI
d32307ca0f Automatic merge of Transifex translations 2012-07-28 22:16:57 +00:00
Michael Zanetti
952c563713 Merge branch 'master' into retina 2012-07-28 14:22:28 +02:00
Michael Zanetti
8e91ab63ca some more testing work for stations 2012-07-28 14:16:49 +02:00
Leo Franchi
d2ed4aeaf8 TWK-1009: Save spotify id from dragging in playlists to tracks 2012-07-27 18:55:33 -04:00
Tomahawk CI
111f569081 Automatic merge of Transifex translations 2012-07-27 22:16:58 +00:00
Hugo Lindström
6c7206c147 Add extra types 2012-07-27 22:42:51 +02:00
Leo Franchi
b35e6ce61d TWK-998: Stable sort in job view proxy, by creation date 2012-07-27 14:59:22 -04:00
Leo Franchi
3fbd58fcc9 Call playlist results if an updater has a custom deleter regardless 2012-07-26 22:41:50 -04:00
Leo Franchi
216759b214 Merge branch 'sourcetreepopup' 2012-07-26 22:06:30 -04:00
Leo Franchi
36c8621133 Allow playlist updaters to put custom questions in playlist delete dialogs 2012-07-26 22:05:44 -04:00
Leo Franchi
9d6b5e60fc Allow Closures to be created when running in a different thread from the receiver 2012-07-26 22:05:28 -04:00
Leo Franchi
70aa98753b Give each playlist a weak pointer to its own shared pointer 2012-07-26 22:05:09 -04:00
Leo Franchi
111de47023 Fix vertical positioning 2012-07-26 17:27:55 -04:00
Christian Muehlhaeuser
c45eec065d * Fixed accessing invalid query in DbCmd_PlaybackHistory. 2012-07-26 01:30:28 +02:00
Tomahawk CI
55fec99ce3 Automatic merge of Transifex translations 2012-07-25 22:17:42 +00:00
Leo Franchi
e62afc6ed7 Add debug 2012-07-25 17:58:31 -04:00
Leo Franchi
810c933e93 Include fix 2012-07-25 17:43:48 -04:00
Christian Muehlhaeuser
6861eb3000 * Readded images. 2012-07-25 22:39:02 +02:00
Christian Muehlhaeuser
8efa33e249 * Reverted broken commit. 2012-07-25 22:38:36 +02:00
Michael Zanetti
52d5dbaf4d some more work on the stations 2012-07-25 22:05:39 +02:00
Leo Franchi
92ae8ea352 Port new changelog entry to master 2012-07-25 09:41:21 -04:00
Christian Muehlhaeuser
ebe7063ec8 * Updated ChangeLog. 2012-07-25 14:41:45 +02:00
Christian Muehlhaeuser
a1155cd7fa Merge pull request #107 from TheOneRing/thumbbutton
update windows love button if the track is loved inside of tomahawk
2012-07-25 04:23:18 -07:00
Leo Franchi
3d1b7ac4cf Differentiate between setting subscribed and changing status 2012-07-24 22:37:08 -04:00
Leo Franchi
c1a1452c2f Toggle subscription on/off via icon 2012-07-24 22:14:08 -04:00
Jason Herskowitz
b642ca136b More subtle subscripton-on.png icon 2012-07-24 22:13:07 -04:00
Leo Franchi
ab5f2a8b5a Merge remote-tracking branch 'origin/master' into sourcetreepopup 2012-07-24 21:36:51 -04:00
Jason Herskowitz
1ba3f91cba Add toggleable subscribe icons for subscribable playlists 2012-07-24 21:27:22 -04:00
Leo Franchi
c8bda2ccbe differentiate between synced and subscribed updaters, and show icon 2012-07-24 21:12:34 -04:00
Tomahawk CI
4a0f91d052 Automatic merge of Transifex translations 2012-07-24 22:17:05 +00:00
Alejandro Wainzinger
51adf23cb9 Add context for translator on transfer status strings. 2012-07-24 22:17:42 +09:00
Dominik Schmidt
deca5bc70d Rename FindLibEchonest to FindEchonest, make it version aware and overall more state of the art :P 2012-07-24 12:28:10 +02:00
Dominik Schmidt
d97274be78 xmpp: check for error presences in AvatarManager 2012-07-24 12:06:16 +02:00
Leo Franchi
f4b1c5ba9f Only show original creator if it's not the same as the user herself 2012-07-23 17:59:47 -04:00
Leo Franchi
c2285dba84 Show creator of playlist in infobar if it exists 2012-07-23 17:46:00 -04:00
Leo Franchi
5441128473 Add workaround for Qt bug for Qt::Popup on OS X/Cocoa 2012-07-23 17:15:47 -04:00
Tomahawk CI
6790a10615 Automatic merge of Transifex translations 2012-07-22 22:16:56 +00:00
Hugo Lindström
e46a5f307f Set resulthint from resolver lookups 2012-07-22 20:45:18 +02:00
Leo Franchi
7690eddff3 New source tree popup widget for playlist delete confirmation 2012-07-22 14:09:41 -04:00
Leo Franchi
76a8e2b2b2 Pointer guards 2012-07-22 10:58:45 -04:00
Leo Franchi
7d5986e61f Add friend type declaration 2012-07-21 21:07:13 -04:00
Leo Franchi
813e657ee4 Show currently playing icon and support jumping for grid views 2012-07-21 20:11:41 -04:00
Michael Zanetti
cdfde7ecc3 Merge branch 'decltest' of github.com:tomahawk-player/tomahawk into decltest 2012-07-21 15:37:24 +02:00
Michael Zanetti
d5935b632f some more work on the station config 2012-07-21 15:37:08 +02:00
Christian Muehlhaeuser
e50c661496 Merge branch 'master' into decltest 2012-07-21 15:07:10 +02:00
Christian Muehlhaeuser
ecc6b679a7 Merge branch 'master' into decltest 2012-07-21 14:19:42 +02:00
Christian Muehlhaeuser
ee2670b813 * Mutex protect hash access. 2012-07-21 14:14:45 +02:00
Christian Muehlhaeuser
95b43964df * Use largest album cover size last.fm offers. 2012-07-21 10:48:40 +02:00
Christian Muehlhaeuser
e67653dbfd * Assert when trying to create an empty PlayableItem. 2012-07-21 10:10:43 +02:00
Christian Muehlhaeuser
125fa25d07 * Fixed getting artist covers from DeclarativeCoverArtProvider. 2012-07-21 09:22:14 +02:00
Leo Franchi
3e315f3a4a Fix osx compile 2012-07-20 18:22:45 -04:00
Tomahawk CI
ace52b0d28 Automatic merge of Transifex translations 2012-07-20 22:16:50 +00:00
Leo Franchi
9449fbf1bf Implement non-osx side of new search field For Compile Win 2012-07-20 17:52:18 -04:00
Leo Franchi
05f58b2dfe Update Qocoa QSearchField to latest, with hatstand's fix.
Now shortcuts work in the QSearchField, like c&p and select all
2012-07-20 17:31:31 -04:00
Leo Franchi
85618cc62b Bump libechonest required version to 2.0.0 2012-07-20 13:20:28 -04:00
Leo Franchi
b0b7aa426d Adapt to new libechonest v2 api 2012-07-20 13:20:28 -04:00
Leo Franchi
11bcdc9cb9 Remove steering from echonest stations 2012-07-20 13:20:28 -04:00
Christian Muehlhaeuser
c77aecd59f * Add an assert for Jason. 2012-07-20 14:42:22 +02:00
Christian Muehlhaeuser
d16ed39dbe * Fixed cover retrieval via DeclarativeCoverArtProvider. 2012-07-20 13:42:14 +02:00
Tomahawk CI
63dae07d44 Automatic merge of Transifex translations 2012-07-19 22:17:41 +00:00
Michael Zanetti
c1df1387f0 dunno why, but QML seems to dislike jumps in enums... remove the Qt::UserRole + 100 2012-07-19 22:40:06 +02:00
Michael Zanetti
6d67b129d2 fix warning 2012-07-19 22:39:59 +02:00
Michael Zanetti
07d91b1d58 fix compilation without -fpermissive 2012-07-19 21:39:15 +02:00
Michael Zanetti
87966d5636 - make the station stuff adapt to high DPIs
- more work on the config dialog
2012-07-19 21:38:15 +02:00
Christian Muehlhaeuser
83f9d86e1d * Work on image provider & unique cover IDs. 2012-07-19 21:35:54 +02:00
Christian Muehlhaeuser
7bb1eeb128 * Added code-signing to OS X build scripts. 2012-07-19 19:15:47 +02:00
Michael Zanetti
b02f8c0d9c make stations behave correctly (preload some tracks and switch to dynamic mode on play) 2012-07-19 18:27:44 +02:00
Leo Franchi
f4f5750cd4 Minor cleanup 2012-07-19 08:53:44 -04:00
Leo Franchi
3f9046d61d Make sure to call spotifyaccount in main thread 2012-07-19 08:29:14 -04:00
Michael Zanetti
cbc9d48a73 make the Recently played tracks list wider like it used to be 2012-07-19 01:02:46 +02:00
Hugo Lindström
14457750ff Send resulthint when we have it 2012-07-19 00:51:04 +02:00
Michael Zanetti
05b4f38cb5 fix minimum column widths for dynamic DPIs 2012-07-19 00:50:59 +02:00
Michael Zanetti
990462ddae fix the drag'n drop menu for scaled dpis 2012-07-19 00:39:41 +02:00
Michael Zanetti
b903dca9cf fix info icon with different DPIs 2012-07-19 00:28:58 +02:00
Tomahawk CI
454944d089 Automatic merge of Transifex translations 2012-07-18 22:17:33 +00:00
Michael Zanetti
5738b4f75d remove some old setPixelSize comments 2012-07-18 23:45:34 +02:00
Michael Zanetti
6c11a62fa4 fix QueueView hidden height with new font sizes 2012-07-18 23:45:12 +02:00
Michael Zanetti
33007cb05e replaced most of the remaining pixelsizes with pointsizes 2012-07-18 22:34:55 +02:00
Michael Zanetti
a62b09076c fix fonts in FlexibleHeader 2012-07-18 19:46:01 +02:00
Michael Zanetti
a438e08080 increase font sizes by one point in the sourcetree and welcomewidget 2012-07-18 19:38:29 +02:00
Michael Zanetti
53863e9155 fixed font sizes in the context page 2012-07-18 19:36:54 +02:00
Michael Zanetti
d44eb51034 and the InfoBar 2012-07-18 19:36:05 +02:00
Leo Franchi
6771d1c7d7 Pointer safety 2012-07-18 11:04:42 -04:00
Leo Franchi
ec10d9f723 Unsubscribe when deleting 2012-07-17 23:06:28 -04:00
Leo Franchi
4fa77e15c2 Fix some logic in the subscribing, and properly subscribe on initial drop 2012-07-17 23:06:28 -04:00
Leo Franchi
6194517eab Use a QHash to avoid a bunch of loops 2012-07-17 23:06:28 -04:00
Alejandro Wainzinger
74d6ccd47d Add default case to switch. 2012-07-18 08:59:17 +09:00
Alejandro Wainzinger
026b257fef An unsigned int will never be less than 0. 2012-07-18 08:51:08 +09:00
Tomahawk CI
bd635d6077 Automatic merge of Transifex translations 2012-07-17 22:17:45 +00:00
Michael Zanetti
ea497de3c4 also adjust the PlaylistDelegate 2012-07-17 23:10:43 +02:00
Leo Franchi
b09206d2b9 Pointer safety (Oops #20003) 2012-07-17 17:08:28 -04:00
Michael Zanetti
2a7fabf633 try with pointsizes instead of scaling pixelsizes 2012-07-17 22:17:17 +02:00
Michael Zanetti
a1f82f38bd make the SourceTreeView DPI aware. This makes it usable on Retina screens 2012-07-17 20:53:10 +02:00
Patrick von Reth
90e532395b compile fix 2012-07-17 18:42:07 +02:00
Patrick von Reth
349509d0b0 fixed connect/disconnect logic 2012-07-17 18:36:08 +02:00
Leo Franchi
cd7efebdf8 Default to synced + subscribed when dropping a spotify playlist 2012-07-17 10:10:15 -04:00
Leo Franchi
ba16ca9a72 Ask local resolver for playlist if running and logged in 2012-07-17 10:10:00 -04:00
Leo Franchi
a6134533be Only ask to delete synced non-subscribed playlists 2012-07-17 10:09:36 -04:00
Patrick von Reth
6626c7f877 update windows love button if the track is loved inside of tomahawk 2012-07-17 14:18:43 +02:00
Leo Franchi
9c0a3496a4 Minor cleanups and string changes 2012-07-16 22:19:58 -04:00
Christopher Reichert
0b860abffb Add Q_UNUSED to setCurrentTrack in PlaylistInterface. 2012-07-16 19:24:14 -05:00
Christopher Reichert
1f0c70e071 Implement forward/previous buttons in MetadataEditor. 2012-07-16 18:30:19 -05:00
Tomahawk CI
e38392f129 Automatic merge of Transifex translations 2012-07-16 22:17:47 +00:00
Hugo Lindström
5be300bd62 Stylefix 2012-07-16 01:55:07 +02:00
Tomahawk CI
d1f6a50e30 Automatic merge of Transifex translations 2012-07-15 22:17:47 +00:00
Hugo Lindström
a1c8b326ab Enable spotify subscriptions 2012-07-15 19:07:33 +02:00
Michael Zanetti
885c52a042 only fetch more track if they are finished resolving and there are not enough tracks available yet 2012-07-15 13:18:37 +02:00
Tomahawk CI
82ac16feb4 Automatic merge of Transifex translations 2012-07-14 22:17:33 +00:00
Michael Zanetti
68114e1f59 Merge branch 'decltest' of github.com:tomahawk-player/tomahawk into decltest 2012-07-14 16:20:12 +02:00
Michael Zanetti
710e570845 restructured QML 2012-07-14 16:19:35 +02:00
Christian Muehlhaeuser
ff44238d06 * Lock mutex when adding to the static hashes in Artist and Album. 2012-07-14 14:02:59 +02:00
Christian Muehlhaeuser
71eb1e916a * Added getByUniqueId( uuid ) methods to Artist, Album and Query. 2012-07-14 13:20:38 +02:00
Christian Muehlhaeuser
0314760451 * Disable infobar for stations. 2012-07-14 12:45:19 +02:00
Christian Muehlhaeuser
b9a909eb56 * Properly store / restore DynamicQmlWidgets. 2012-07-14 12:43:13 +02:00
Michael Zanetti
73f05971e4 add missing files 2012-07-14 11:55:16 +02:00
Michael Zanetti
c0c2cc6234 Merge branch 'decltest' of github.com:tomahawk-player/tomahawk into decltest 2012-07-14 11:54:02 +02:00
Michael Zanetti
ba6b14863c some more work on the station qml 2012-07-14 11:53:19 +02:00
Christian Muehlhaeuser
d5e6151eee * Use LovedTracksItem for Top Loved Tracks sidebar item. 2012-07-14 11:15:45 +02:00
Christian Muehlhaeuser
6a4bbb7ec1 * Handle top loved tracks in LovedTracksItem. 2012-07-14 11:15:15 +02:00
Christian Muehlhaeuser
124d31c542 * ViewManager doesn't handle topLoved widget anymore. 2012-07-14 11:14:36 +02:00
Christian Muehlhaeuser
98a196192e * Removed CustomPlaylistView. 2012-07-14 11:14:08 +02:00
Christian Muehlhaeuser
78aa6606f9 * Added LovedTracksModel. 2012-07-14 11:13:22 +02:00
Christian Muehlhaeuser
077e9ab84a * Use new grid view-mode icon and fix center icon background. 2012-07-14 10:36:38 +02:00
Christian Muehlhaeuser
e21f2a5e87 * Make global Recently Played a FlexibleView. 2012-07-14 10:30:21 +02:00
Christian Muehlhaeuser
d06b0e824d * Turn Latest Additions into a FlexibleView. 2012-07-14 10:25:35 +02:00
Christian Muehlhaeuser
6b5ef37724 * Add a little more left-margin. 2012-07-14 10:25:17 +02:00
Christian Muehlhaeuser
7ab179e23f * Use FlexibleHeader in FlexibleView. 2012-07-14 09:50:06 +02:00
Christian Muehlhaeuser
a62a4c354f * Use a FlexibleView for Recently Played playlists. 2012-07-14 09:49:39 +02:00
Christian Muehlhaeuser
2783651537 * Set PlaylistModel once its loaded only. 2012-07-14 09:49:11 +02:00
Christian Muehlhaeuser
aa82c276c9 * Added Flexibleheader and PlaylistHeader.ui. 2012-07-14 09:48:45 +02:00
Leo Franchi
96c6ebfe99 TWK-968: Part Two: Allow drop helper for mixed query/result lists. 2012-07-14 00:31:27 -04:00
Leo Franchi
bd0e347281 Remove unnecessary debug 2012-07-14 00:31:09 -04:00
Leo Franchi
4eb3359422 TWK-985: Log into spotify on return pressed in Spotify config 2012-07-14 00:08:35 -04:00
Christian Muehlhaeuser
fedb669041 * Fixed queue auto-collapsing when playing the last track in it. 2012-07-14 05:47:33 +02:00
Leo Franchi
b39dbe6880 Also allow multiple infoplugins to return data for artist top tracks 2012-07-13 23:19:56 -04:00
Christian Muehlhaeuser
14df0aef4a * Mute JobStatusModel and -View again. 2012-07-14 05:18:13 +02:00
Syd Lawrence
ab574a2a1c fixed anti alias on icons 2012-07-13 23:27:53 +01:00
Tomahawk CI
d1e230121e Automatic merge of Transifex translations 2012-07-13 22:23:20 +00:00
Leo Franchi
06a5cbc8bb Optional debug for help tracking done future race condition w/ IdThreadWorker 2012-07-13 18:22:06 -04:00
Syd Lawrence
d2d2678496 Merge branch 'master' of https://github.com/tomahawk-player/tomahawk 2012-07-13 23:17:37 +01:00
Syd Lawrence
bd071f472c improved grayscale icon 2012-07-13 23:17:18 +01:00
Leo Franchi
20759b9b1c Abuse^WMassage our use of QFutureInterface 2012-07-13 18:09:35 -04:00
Syd Lawrence
eef79f6fc2 Merge branch 'master' of https://github.com/tomahawk-player/tomahawk 2012-07-13 22:54:16 +01:00
Syd Lawrence
1d63867f58 slightly new take on the logo 2012-07-13 22:53:58 +01:00
Leo Franchi
866bf93721 Call sendMessage() with a QueuedConnection as it's cross-thread 2012-07-13 17:48:11 -04:00
Leo Franchi
4e3febcb5b Let AlbumPlaylistInterface accept results from first good infoplugin result 2012-07-13 17:48:10 -04:00
Leo Franchi
479262c846 Extra pointer safety 2012-07-13 17:48:10 -04:00
Syd Lawrence
5c2da3d835 added grid view icons 2012-07-13 22:00:03 +01:00
Leo Franchi
309a6843f0 Merge branch 'master' into decltest 2012-07-13 14:25:11 -04:00
Leo Franchi
6ee2e0fe14 TWK-968: Fix PlayableModel/DropJob for mixed mimetype 2012-07-13 13:07:32 -04:00
Leo Franchi
abf552e3a1 Try including qfutureinterface via QtCore/ to see if it helps the OS X slave 2012-07-13 11:51:48 -04:00
Leo Franchi
c064d27fb8 Less debug 2012-07-13 11:40:22 -04:00
Leo Franchi
a8fffe6fdc Experimental: Re-implement asynchronous artist/album ID.
No more boost::thread usage, using QFutureInterface instead.
Now we keep the same model as before but use the undocumented API
of QFutureInterface
2012-07-13 11:39:48 -04:00
Christian Muehlhaeuser
f39722c2f8 * Updated ChangeLog. 2012-07-13 11:03:48 +02:00
Christian Muehlhaeuser
ad3f981c9f * Fixed Windows shutdown. 2012-07-13 09:52:08 +02:00
Tomahawk CI
3d3c381dd7 Automatic merge of Transifex translations 2012-07-12 22:17:52 +00:00
Leo Franchi
6901a9f47e Pointer safety 2012-07-12 11:50:21 -04:00
Michael Zanetti
a89d20665f more work on the new station view 2012-07-12 16:40:19 +02:00
Christian Muehlhaeuser
f239473f0c * Style fixes. 2012-07-12 11:22:25 +02:00
Christian Muehlhaeuser
c09dcc74e3 * Updated ChangeLog. 2012-07-12 10:02:14 +02:00
Christian Muehlhaeuser
3f50bace71 * Really fix compiling on Windows. 2012-07-12 09:47:31 +02:00
Christian Muehlhaeuser
54e4391576 Merge pull request #106 from TheOneRing/master
Make the Thumb Buttons interactive
2012-07-12 00:22:05 -07:00
Christian Muehlhaeuser
daf895c53d * Try to fix compiling on mingw. 2012-07-12 09:14:33 +02:00
Christian Muehlhaeuser
a9dff282e3 * Cleaned up DiagnosticsDialog. 2012-07-12 08:40:17 +02:00
Christian Muehlhaeuser
f3d3f19ef8 * Provide convenience openUrl( url ) method in TomahawkUtilsGui, since QDesktopServices fail to work on Windows. 2012-07-12 08:35:29 +02:00
Christian Muehlhaeuser
81b9af0dc9 * Expose logfile's path in Logger. 2012-07-12 08:34:37 +02:00
Christian Muehlhaeuser
5f907258eb * Style updates and smaller fixes. 2012-07-12 07:23:54 +02:00
Christian Muehlhaeuser
09d89c3663 * Use a RAMDirectory if we can't open the regular lucene index file. 2012-07-12 07:23:54 +02:00
Tomahawk CI
26e5c302d8 Automatic merge of Transifex translations 2012-07-11 22:17:45 +00:00
Jeff Mitchell
c3474833b9 Increased pointer safety (oops 19400) 2012-07-10 23:31:58 -04:00
Jeff Mitchell
d2a5092862 Increased pointer safety (oops 19336) 2012-07-10 23:27:14 -04:00
Jeff Mitchell
e9314775aa Better PortFwdThread handling...separate out the thread controller from
the actual threaded worker
2012-07-10 21:09:07 -04:00
Jeff Mitchell
8dcf7d0db2 Potentially solve the 4-is-not-JSON bug 2012-07-10 19:23:12 -04:00
Jeff Mitchell
97ff1100d1 Fix stupid error, and hence fix this branch up 2012-07-10 18:23:32 -04:00
Jeff Mitchell
7b36ea323f Merge remote-tracking branch 'origin/master' into databaseworker-threadify 2012-07-10 18:20:20 -04:00
Tomahawk CI
c7e4fc777f Automatic merge of Transifex translations 2012-07-10 22:19:56 +00:00
Jeff Mitchell
e3165d8928 Merge remote-tracking branch 'origin/master' into databaseworker-threadify 2012-07-10 17:56:11 -04:00
Michael Zanetti
976a2eeb0a Merge branch 'master' of github.com:tomahawk-player/tomahawk into decltest 2012-07-10 19:39:31 +02:00
Jeff Mitchell
f7ffead6c2 More work 2012-07-10 07:02:17 -04:00
Michael Zanetti
6dea6dc0a5 a try to prefill the station with more songs 2012-07-10 07:54:56 +02:00
Hugo Lindström
1045269e6e Clear passwordEdit on logout in SpotifyAccount 2012-07-10 03:53:56 +02:00
Jeff Mitchell
c7002a1364 Properly threadify databaseworker, untested as of yet 2012-07-09 18:48:25 -04:00
Tomahawk CI
3d5c737651 Automatic merge of Transifex translations 2012-07-09 22:17:47 +00:00
Jeff Mitchell
8c8de62271 Changelogify 2012-07-09 09:57:28 -04:00
Jeff Mitchell
5e41e052ba Remove constant indexing jobs 2012-07-09 09:56:26 -04:00
Jeff Mitchell
a8a8218e93 Cleanup 2012-07-09 09:54:18 -04:00
Jeff Mitchell
c60e96b365 Fix weight sorting 2012-07-09 09:44:51 -04:00
Leo Franchi
f8d364af0f Set source model on proxy model 2012-07-09 09:32:00 -04:00
Jeff Mitchell
be2847740e Add a lot more debugging 2012-07-09 08:41:58 -04:00
Jeff Mitchell
d24ff66696 Add some methods to ensure that there is always at least one job that can be going with ACL checks, for debugging/verification 2012-07-08 21:18:09 -04:00
Jeff Mitchell
3e1310eac4 Initial work on weight for job view items, to keep predictable ordering (especially important for not having ACL checks jump around) 2012-07-08 15:52:53 -04:00
Patrick von Reth
375ae62f64 make code more readable 2012-07-08 16:53:19 +02:00
Tomahawk CI
ebb59b50c6 Automatic merge of Transifex translations 2012-07-07 22:17:48 +00:00
Michael Zanetti
6dc8e98003 connect also to resultsChanged 2012-07-07 21:27:28 +02:00
Patrick von Reth
0e36f77dd4 improved support for thumbnail buttons 2012-07-07 19:07:56 +03:00
Christian Muehlhaeuser
5e0390bd87 * We need to tell source to update the index in the right thread. 2012-07-07 03:22:34 +02:00
Christian Muehlhaeuser
493cf75470 * Removed scanningFinished's parameter. 2012-07-07 03:21:42 +02:00
Christian Muehlhaeuser
a2e94ef4a7 * Remove overlays when filter changed. 2012-07-07 02:49:28 +02:00
Christian Muehlhaeuser
64be53ab8a * Fixed crash in ContextMenu. 2012-07-07 02:26:17 +02:00
Christian Muehlhaeuser
18329b122d * Style fixes. 2012-07-07 02:17:00 +02:00
Christian Muehlhaeuser
7e6931f25a Merge pull request #104 from TheOneRing/master
Add support for Windows 7 Thumbnail Toolbars
2012-07-06 17:06:12 -07:00
Christian Muehlhaeuser
269488fdb7 * Add more debug info to SipHandler. 2012-07-07 01:36:40 +02:00
Tomahawk CI
a8c58705f4 Automatic merge of Transifex translations 2012-07-06 22:17:38 +00:00
Patrick von Reth
ef98ac41ce implemented love 2012-07-06 13:48:13 +03:00
Patrick von Reth
56db97fea5 remove accidentaly commited debug message 2012-07-06 12:37:35 +03:00
Patrick von Reth
cefd96664b add Windows taskbar thumbbutton support 2012-07-06 11:05:08 +03:00
Christian Muehlhaeuser
f6657845df * Added extra debug output to ControlConnection. 2012-07-06 07:58:48 +02:00
Christian Muehlhaeuser
b1955dd9b7 * Fixed FadingPixmap isn't initialized with m_isDefault being true. 2012-07-06 07:36:43 +02:00
Christian Muehlhaeuser
d571a79746 * Don't return unresolved queries when proxy-model is supposed to filter out offline / unplayable tracks. 2012-07-06 06:32:01 +02:00
Christian Muehlhaeuser
78e1f8236c * Don't return unresolved queries when proxy-model is supposed to filter out offline / unplayable tracks. 2012-07-06 06:30:34 +02:00
Christian Muehlhaeuser
457c916101 Merge branch 'master' into decltest 2012-07-06 06:21:02 +02:00
Christian Muehlhaeuser
d4def82cd1 * Refetch cover when underlying metadata changed in PixmapDelegateFader. 2012-07-06 06:09:32 +02:00
Christian Muehlhaeuser
06c5f2e84b * Hooking up to resultsChanged() is enough in PlayableItem. 2012-07-06 06:09:32 +02:00
Christian Muehlhaeuser
2004977b09 * Emit resultsChanged() after adding / removing results in a Query. 2012-07-06 06:09:32 +02:00
Leo Franchi
ad0be3aa3c Keep config UI in sync with resolver 2012-07-05 23:34:46 -04:00
Leo Franchi
35a0db7a07 Some more fixes 2012-07-05 23:34:46 -04:00
Leo Franchi
427a26e034 New spotify config 2012-07-05 23:34:46 -04:00
Christian Muehlhaeuser
b4fa46c3c7 * Moved properties context entry below the separator. 2012-07-06 04:39:41 +02:00
Christian Muehlhaeuser
7030d43e32 * Disable a bit of debug. 2012-07-06 04:39:41 +02:00
Leo Franchi
1a1106012b Add spotify infoplugin for album lookups 2012-07-05 22:38:20 -04:00
Christian Muehlhaeuser
56e73fb274 * No need to hook up to query's coverChanged() signal anymore. 2012-07-06 03:40:50 +02:00
Christian Muehlhaeuser
56dd8d47db Merge branch 'master' into decltest 2012-07-06 02:16:21 +02:00
Christian Muehlhaeuser
841cef878d * Updated ChangeLog. 2012-07-06 02:00:42 +02:00
Tomahawk CI
6f4782ba71 Automatic merge of Transifex translations 2012-07-05 22:17:36 +00:00
Leo Franchi
5960da1722 Don't confuse QFileInfo 2012-07-05 16:49:14 -04:00
Jeff Mitchell
4ca5cf456a along to you -> along with you 2012-07-05 14:49:19 -04:00
Jeff Mitchell
97e5b3a5c4 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:39:12 -04:00
Jeff Mitchell
0e5dd14bcf Guard first() calls in music scanner 2012-07-05 10:04:20 -04:00
Michael Zanetti
3c942b1249 played around with the QML path a bit... 2012-07-05 14:42:49 +02:00
Michael Zanetti
68de791e8c yay! we have album covers! 2012-07-05 13:58:28 +02:00
Christian Muehlhaeuser
41a37b4690 * Fixed clash between model & proxymodel user-roles. 2012-07-05 13:34:59 +02:00
Michael Zanetti
9e6dbcc7b1 fix covers again after using the proxymodel 2012-07-05 13:30:29 +02:00
Michael Zanetti
64f4445a01 use the proxymodel instead of the model directly 2012-07-05 13:17:12 +02:00
Christian Muehlhaeuser
e29dc4a8a6 * Filter tree-model based on query, not result. 2012-07-05 12:41:06 +02:00
Michael Zanetti
0a1f2304e9 Merge branch 'master' of github.com:tomahawk-player/tomahawk into decltest 2012-07-05 12:15:27 +02:00
Christian Muehlhaeuser
1d84f6ede6 * Should fix crash when filtering collection. 2012-07-05 12:13:07 +02:00
Michael Zanetti
8f465b2984 removed unneeded slot previously used for debugging 2012-07-05 11:47:34 +02:00
Michael Zanetti
2d32a2db90 added artwork to the stations view 2012-07-05 11:43:19 +02:00
Tomahawk CI
138381a61d Automatic merge of Transifex translations 2012-07-04 22:17:39 +00:00
Christian Muehlhaeuser
f5b3c20c4c * Merged master into decltest. 2012-07-04 22:44:33 +02:00
Michael Zanetti
abb8217286 more work on the station qml stuff 2012-07-04 17:54:01 +02:00
Dominik Schmidt
4bc38491e4 Use SipInfo class 2012-07-04 15:25:15 +02:00
Patrick von Reth
4973768078 fixed windows x64 build
Signed-off-by: Dominik Schmidt <dev@dominik-schmidt.de>
2012-07-04 15:25:15 +02:00
Dominik Schmidt
bbf7555089 Remove more unused VLC plugins from the windows package 2012-07-04 15:25:15 +02:00
Michael Zanetti
b48896157d Merge branch 'decltest' of github.com:tomahawk-player/tomahawk into decltest 2012-07-04 12:08:45 +02:00
Christian Muehlhaeuser
cd2fd37f84 * Prevent crash in ViewHeader. 2012-07-04 05:44:07 +02:00
Christian Muehlhaeuser
97a3d6fcd3 * Correctly unset pause / spinner on GridView when a new track is loading. 2012-07-04 05:37:07 +02:00
Christian Muehlhaeuser
1309334f99 * Adjust to new ViewPage interface. 2012-07-04 04:56:21 +02:00
Christian Muehlhaeuser
c99cfe54ed * Clean up ViewPage interface. 2012-07-04 04:49:47 +02:00
Christian Muehlhaeuser
d73cd9479c * Clean up ViewManager. 2012-07-04 04:49:28 +02:00
Christian Muehlhaeuser
2bb7f91e7d * New include path. 2012-07-04 04:48:49 +02:00
Christian Muehlhaeuser
a8105c3347 * Obsolete dependency. 2012-07-04 04:48:34 +02:00
Christian Muehlhaeuser
f23543217e * Remove TopBar from CMakeLists.txt. 2012-07-04 04:47:39 +02:00
Christian Muehlhaeuser
080b1b1817 * Remove TopBar and move SearchLineEdit into widgets/searchlineedit/. 2012-07-04 04:47:20 +02:00
Christian Muehlhaeuser
1f19a618a1 * Enable filter bar for loved tracks. 2012-07-04 04:19:59 +02:00
Christian Muehlhaeuser
f42a412bcc * Style fixes. 2012-07-04 00:26:24 +02:00
Christian Muehlhaeuser
8ddb295f06 * Fixed Last.fm history importing. 2012-07-04 00:26:24 +02:00
Tomahawk CI
3cc9da298d Automatic merge of Transifex translations 2012-07-03 22:17:34 +00:00
Leo Franchi
4ff1812526 Seed pipeline job item with query immediately 2012-07-03 17:55:29 -04:00
Christian Muehlhaeuser
692a4043e8 * Call startOnDemand() when initializing DynamicQmlWidget. Not sure if we need to wait for a revision to be loaded first, though. 2012-07-03 23:43:32 +02:00
Christian Muehlhaeuser
e81baf0eb7 * Added PlayableRoles and mapped them to the according column. 2012-07-03 23:42:56 +02:00
Christopher Reichert
118e6867ff MetadataEditor.ui strings cleanup. 2012-07-03 15:54:05 -05:00
Michael Zanetti
bbdb15c53e a very very basic pathview for covers 2012-07-03 18:06:19 +02:00
Jeff Mitchell
7fcb31dda7 Add vim swap files to gitignore 2012-07-03 12:04:27 -04:00
Jeff Mitchell
2a53f266fc Remove vim swap files 2012-07-03 12:03:55 -04:00
Jeff Mitchell
452ac9630a Merge remote-tracking branch 'origin/master' into specfilescanning 2012-07-03 11:58:31 -04:00
Christian Muehlhaeuser
5f61e3b1bd * Merged master into declspec. 2012-07-03 17:54:22 +02:00
Christian Muehlhaeuser
6bc9f88189 * Setup a DynamicQmlWidget when showing a station. 2012-07-03 17:07:08 +02:00
Christian Muehlhaeuser
92d7757e47 * Setup (proxy-)model and load dynamic playlist in DynamicQmlWidget. 2012-07-03 17:07:08 +02:00
Michael Zanetti
2fb8b57e25 added qml file template for stations 2012-07-03 16:51:35 +02:00
Christian Muehlhaeuser
c295514598 * Make DynamicQmlWidget a proper ViewPage. 2012-07-03 16:37:47 +02:00
Christian Muehlhaeuser
fc36c5ae91 * Return true after setting the filter. 2012-07-03 16:16:53 +02:00
Michael Zanetti
c05bae9e8c added DynamicQmlWidget (not doing anything yet) 2012-07-03 16:05:34 +02:00
Thierry Goeckel
9e5f5eb750 Nitpicky fix adding spaces left and right of 'und' in German Top Loved Tracks translation. 2012-07-03 15:27:47 +02:00
Stefan Derkits
3c30b08c36 quick & dirty fix for compilation issues (non-void methods not returning anything) 2012-07-03 13:36:13 +02:00
Christian Muehlhaeuser
658f0bf9bc * Removed obsolete loading methods in AlbumInfoWidget. 2012-07-03 04:15:28 +02:00
Christian Muehlhaeuser
5991467d40 * Show tracks on Album page collection-style again. 2012-07-03 03:47:01 +02:00
Christian Muehlhaeuser
392197608f * Removed obsolete 'unfilteredTrackCount' PlaylistInterface method / signal. 2012-07-03 03:31:03 +02:00
Christian Muehlhaeuser
2278f5d668 * Style fixes. 2012-07-03 03:13:55 +02:00
Christian Muehlhaeuser
b0c14d6217 * Don't load view states for empty guids. 2012-07-03 03:13:46 +02:00
Christian Muehlhaeuser
c32800c119 * Use new ViewPage API in ViewManager. 2012-07-03 02:50:17 +02:00
Christian Muehlhaeuser
b8cc0ddbcd * Don't load social actions twice. 2012-07-03 02:50:17 +02:00
Christian Muehlhaeuser
6a23954539 * Added setFilter methods to proxy models. 2012-07-03 02:50:17 +02:00
Christian Muehlhaeuser
dc0316018a * Fixed default implementation of ViewPage's setFilter method. 2012-07-03 02:50:17 +02:00
Christian Muehlhaeuser
752c1b38a0 * Implemented new ViewPage API for various classes. 2012-07-03 02:50:17 +02:00
Christian Muehlhaeuser
f5512d7b95 * Added filter/setFilter methods to ViewPage. 2012-07-03 02:50:17 +02:00
Christian Muehlhaeuser
a2f880d160 * Removed filter/setFilter methods from PlaylistInterfaces. 2012-07-03 02:50:17 +02:00
Tomahawk CI
f500efdaf9 Automatic merge of Transifex translations 2012-07-02 22:17:43 +00:00
Jeff Mitchell
ba34fd75a9 Merge remote-tracking branch 'origin/master' into specfilescanning 2012-07-02 17:55:02 -04:00
Christian Muehlhaeuser
1761f7af0c * Playlists are now displayed as FlexibleViews. 2012-07-02 23:11:11 +02:00
Christian Muehlhaeuser
01fb91ac59 * Use new model/view API. 2012-07-02 23:10:36 +02:00
Christian Muehlhaeuser
bd629e6178 * Moved itemSize from model to delegate. 2012-07-02 23:10:24 +02:00
Christian Muehlhaeuser
1860d7732a * Moved style/view specific model stuff into PlayableProxyModel. 2012-07-02 23:08:07 +02:00
Christian Muehlhaeuser
27df8fd3dc * Added FlexibleView widget. 2012-07-02 23:04:46 +02:00
Jeff Mitchell
690c480462 Merge remote-tracking branch 'origin/master' into specfilescanning 2012-07-02 11:56:22 -04:00
Christian Muehlhaeuser
868779c40c * Add a vertical spacer item to the DiagnosticsDialog, so contents don't move around. 2012-07-02 04:03:32 +02:00
Christian Muehlhaeuser
a1b24c1244 * Emit coverChanged() even when we couldn't get a cover, so the views update / trigger new requests. 2012-07-02 03:49:24 +02:00
Michael Zanetti
051282be06 moved qml file to rc to avoid path issues 2012-07-02 01:12:32 +02:00
Michael Zanetti
fb0a88aa98 make reflection look nice in pathview and remove it from gridview 2012-07-02 00:58:08 +02:00
Michael Zanetti
fc69e7d08d added an ugly but still impressive (for a proof of concept) mirror effect for cover art 2012-07-02 00:34:59 +02:00
Michael Zanetti
02708629ca and another one just to show it off to muesli 2012-07-02 00:19:45 +02:00
Tomahawk CI
558b902b62 Automatic merge of Transifex translations 2012-07-01 22:17:39 +00:00
Michael Zanetti
d894116e8e take that, QWidget! 2012-07-01 23:48:46 +02:00
Jeff Mitchell
8fcfed61bb Merge remote-tracking branch 'origin/master' into specfilescanning 2012-07-01 16:38:10 -04:00
Jeff Mitchell
6448a91d5c Merge branch 'master' into specfilescanning 2012-07-01 16:38:06 -04:00
Christian Muehlhaeuser
9c0a608e3e * Update ChangeLog. 2012-07-01 22:37:32 +02:00
Christopher Reichert
48961a822c Allow Metadata editor to edit year. 2012-07-01 14:32:57 -05:00
Christian Muehlhaeuser
c47c8894b0 * Indicate invalid PlaylistEntries. 2012-07-01 20:54:56 +02:00
Christian Muehlhaeuser
eaf48bcf51 * Fixed crashes in DbCmd_SetPlaylistRevision. 2012-07-01 20:54:31 +02:00
Christian Muehlhaeuser
53b00db602 * Don't ever accept invalid results coming from resolvers. 2012-07-01 20:54:06 +02:00
Michael Zanetti
5c47ae96ab testcomit for qtdeclarative 2012-07-01 16:37:46 +02:00
Christian Muehlhaeuser
bbec1dfbbe * Fixed cover loading in error case. 2012-07-01 08:56:57 +02:00
Christian Muehlhaeuser
064efb4570 * spotify -> Spotify. 2012-07-01 06:49:17 +02:00
Leo Franchi
0ef5a6675d Changelogify 2012-07-01 00:43:23 -04:00
Christian Muehlhaeuser
2d4f7c8898 * Remove debug output again. 2012-07-01 05:44:30 +02:00
Christian Muehlhaeuser
7946362dcf * Set m_coverLoaded to true even when we couldn't find any image. 2012-07-01 05:43:29 +02:00
Christian Muehlhaeuser
c1e7ef2ea3 * Set m_coverLoaded to true before emitting the coverChanged signal. 2012-07-01 02:51:10 +02:00
Christian Muehlhaeuser
faadb41054 * Don't crash when removing page in history. 2012-07-01 02:20:09 +02:00
Christopher Reichert
a928436eb5 Added more tag attributes from metadata editor. 2012-06-30 18:49:24 -05:00
Tomahawk CI
7f5c78ec9f Automatic merge of Transifex translations 2012-06-30 22:17:41 +00:00
Leo Franchi
8b9540cf9d No more libspotify in bundle 2012-06-30 17:55:39 -04:00
Christian Muehlhaeuser
afb624f8eb * Add 'Copy Artist/Album Link' context menu items. 2012-06-30 23:35:04 +02:00
Christopher Reichert
ac93b7e9f6 Format MetdataEditorDlg window title.
Added bitrate to MetadataEditorDlg.
Align tag editing fields to left.
2012-06-30 16:30:13 -05:00
Christian Muehlhaeuser
becb263635 * Be prepared for empty query_ptrs being returned from Query::get(). 2012-06-30 23:22:01 +02:00
Christian Muehlhaeuser
4d188af33e * Return empty query_ptr when query data is invalid. 2012-06-30 23:22:01 +02:00
Christian Muehlhaeuser
c1cb85fee6 * Use 'large' album covers from Last.fm. 2012-06-30 23:22:01 +02:00
Jeff Mitchell
76f7c303a1 Weird, how did I think that was a good idea :-) 2012-06-30 17:14:59 -04:00
Jeff Mitchell
238c07b8bd Fix compilation 2012-06-30 17:06:53 -04:00
Jeff Mitchell
01d17bde9b Fix compilation 2012-06-30 17:06:45 -04:00
Jeff Mitchell
51a956ec77 Merge branch 'master' into specfilescanning 2012-06-30 17:01:55 -04:00
Jeff Mitchell
3ff0897d72 Merge pull request #103 from nowrep/master
FdoNotifyPlugin: Fixed showing notifications with & character
2012-06-30 14:00:36 -07:00
Jeff Mitchell
1a333d85d6 Fix missing call to postOps after file scans 2012-06-30 16:58:25 -04:00
Jeff Mitchell
ba54b5ce8e Don't blindly queue scan paths, there may be some queued 2012-06-30 16:51:26 -04:00
Jeff Mitchell
4b6e1ea0d7 Don't start new scans before everything is cleaned up, put them onto the event loop 2012-06-30 16:47:16 -04:00
Christopher Reichert
5ad53e0af5 Manage queued scan type in ScanManager. 2012-06-30 15:34:00 -05:00
nowrep
6e612fa9dd FdoNotifyPlugin: Fixed showing notifications with & character 2012-06-30 21:44:21 +02:00
Jeff Mitchell
c1ec90b825 Some ScanController cleanup 2012-06-30 15:14:19 -04:00
Christopher Reichert
e7dda25cac Check thread when scanning. 2012-06-30 13:58:22 -05:00
Christopher Reichert
b0c9b86b3a Metadata editor initial commit. 2012-06-30 13:58:22 -05:00
Jeff Mitchell
a674570efd Merge branch 'master' into specfilescanning 2012-06-30 14:52:17 -04:00
Jeff Mitchell
67e18c3b9d Some more acl cleanup, and put Acl->ACL so we don't mess up peoples' existing configs 2012-06-30 14:44:06 -04:00
Stefan Derkits
5547a9741d Ubuntu 11.10 needs explicit pthread, reenable finding & linking them 2012-06-30 17:04:39 +02:00
Jeff Mitchell
9e62b812f7 Merge branch 'master' into specfilescanning 2012-06-29 19:28:03 -04:00
Tomahawk CI
22732d5c68 Automatic merge of Transifex translations 2012-06-29 22:16:56 +00:00
Leo Franchi
c5691fce9a Also remove saved resolver path when uninstalling 2012-06-29 17:49:24 -04:00
Leo Franchi
76600e015c Use headerpad_max_install_names on OS X builds 2012-06-29 17:07:57 -04:00
Leo Franchi
ceba1431f7 Don't copy to bundle any longer when installing binary resolvers on osx 2012-06-29 17:07:57 -04:00
Leo Franchi
900b836b1e Do our own attica download fetching since we send the tomahawk version as well 2012-06-29 17:07:56 -04:00
Jeff Mitchell
d786f5c13b Separate AclRegistry into lib/impl parts. Removes GUI dependency in lib,
among other things.
2012-06-29 15:29:55 -04:00
Jeff Mitchell
4f26b805d7 Fix warning 2012-06-29 10:07:38 -04:00
Jeff Mitchell
ca22cfd31d Fix another crash related to debug accessing null pointers 2012-06-29 10:05:55 -04:00
Jeff Mitchell
028f6b969e OK, really fix crash. Promise. 2012-06-29 10:04:53 -04:00
Jeff Mitchell
90de0237e0 Actually fix crash 2012-06-29 10:02:08 -04:00
Jeff Mitchell
a846d91bef Fix accessing playlist that could be invalid inside debug 2012-06-29 09:59:41 -04:00
Christian Muehlhaeuser
0b3c794cc9 * Use new Querylabel API. 2012-06-29 04:28:28 +02:00
Christian Muehlhaeuser
d890ea3b14 * Support setting Artist / Album on a QueryLabel directly. We need a proper 'CleverLabel' so badly. 2012-06-29 04:28:08 +02:00
Christian Muehlhaeuser
5ed6bb52b5 * Removed obsolete code. 2012-06-29 03:35:46 +02:00
Christian Muehlhaeuser
295f059e19 * No more dragsource.type. 2012-06-29 03:29:44 +02:00
Christian Muehlhaeuser
b25b611685 * Properly drag Artists / Albums from QueryLabel. 2012-06-29 03:29:32 +02:00
Christian Muehlhaeuser
6ec80761eb * Use new PlayableModel API throughout app. 2012-06-29 03:14:01 +02:00
Christian Muehlhaeuser
d907a9fbc8 * Adjust inheriting models to new PlayableModel API. 2012-06-29 03:13:31 +02:00
Christian Muehlhaeuser
0c00cccc1f * Resolved a bunch more hidden overloaded virtual methods in PlayableModel. 2012-06-29 03:12:09 +02:00
Christian Muehlhaeuser
a9bf18e17f * Use new PlayableModel API throughout app. 2012-06-29 02:28:02 +02:00
Christian Muehlhaeuser
47cb8deab1 * Adjust inheriting models to new PlayableModel API. 2012-06-29 02:27:41 +02:00
Christian Muehlhaeuser
bbc851fca2 * Resolved a bunch of hidden overloaded virtual methods in PlayableModel. 2012-06-29 02:25:35 +02:00
Christian Muehlhaeuser
fdcd2aa728 * Fixed text-width calculation after my latest patch. 2012-06-29 02:12:53 +02:00
Christian Muehlhaeuser
5827974b45 * Fix english translation plurals. 2012-06-29 00:34:25 +02:00
Tomahawk CI
9bfc9d3f0f Automatic merge of Transifex translations 2012-06-28 22:17:08 +00:00
Jeff Mitchell
e7c7737500 Merge remote-tracking branch 'origin/master' into specfilescanning 2012-06-28 16:04:36 -04:00
Christian Muehlhaeuser
dee2dad874 * Proper fix for QueryLabel's context menu. 2012-06-28 20:21:04 +02:00
Christian Muehlhaeuser
363becf9b9 * Show correct context menus for album / artist QueryLabels. 2012-06-28 20:14:17 +02:00
Tomahawk CI
95fa9a2b89 Automatic merge of Transifex translations 2012-06-27 22:17:27 +00:00
Christian Muehlhaeuser
35c9509477 * Only return online results via web API. 2012-06-27 07:25:26 +02:00
Christian Muehlhaeuser
4a97e057be * Properly sort artists & albums in search widget. 2012-06-27 05:22:01 +02:00
Christian Muehlhaeuser
d7d8c5940f * Moved levenshtein method to TomahawkUtils. 2012-06-27 05:21:22 +02:00
Christian Muehlhaeuser
23f47f82a6 * Retry on this sql error, too. 2012-06-27 05:11:21 +02:00
Christian Muehlhaeuser
393ec8a53d * Use new spinner integration API. 2012-06-27 03:26:27 +02:00
Christian Muehlhaeuser
7ba97a817d * No need to check all results for playability. Their sorted by that, so we just check the first one. 2012-06-27 02:18:41 +02:00
Christian Muehlhaeuser
dbeb46d513 * Allow to sort by composer and origin. 2012-06-27 02:17:55 +02:00
Christian Muehlhaeuser
ef80237d39 * Expose composer's sortname in Query's API. 2012-06-27 02:17:28 +02:00
Christian Muehlhaeuser
06e081b7a0 * Resolve dupe accelerator assignment. 2012-06-27 01:02:03 +02:00
Leo Franchi
403f80d721 Forcibly kill spotify resolver before starting out own in case it's an old one 2012-06-26 18:43:07 -04:00
Leo Franchi
9505e433bc Looks like paths with spaces need to be esaped everywhere with QProcess... 2012-06-26 18:24:20 -04:00
Leo Franchi
239601f637 Don't assert on quit anymore, served its debug purpose 2012-06-26 18:24:20 -04:00
Tomahawk CI
8909108516 Automatic merge of Transifex translations 2012-06-26 22:23:36 +00:00
Christian Muehlhaeuser
fac37debad * Updated ChangeLog. 2012-06-27 00:09:18 +02:00
Leo Franchi
cd9ba367af Style fix 2012-06-26 17:54:01 -04:00
Leo Franchi
e1416fce06 Always re-install spotify resolver if path is no longer valid 2012-06-26 17:54:01 -04:00
Leo Franchi
a7d90b16e7 We no longer remove accounts when uninstalling from attica 2012-06-26 17:54:01 -04:00
Christian Muehlhaeuser
4ef0d23900 * Don't accept empty queries from web API. 2012-06-26 23:15:26 +02:00
Christian Muehlhaeuser
937908766c * Assert when trying to setup a query without artist or track. 2012-06-26 23:14:43 +02:00
Christian Muehlhaeuser
9b09cbd11e * Call wipeIndex via a single-shot timer to avoid dead-locks. 2012-06-26 23:14:23 +02:00
Christian Muehlhaeuser
cb578a607a * Re-bind values for failed TomahawkSqlQueries. 2012-06-26 20:34:23 +02:00
Jeff Mitchell
856b6cc164 Convert some qDebug calls 2012-06-26 08:42:42 -04:00
Jeff Mitchell
2302f0eb41 Fix borked if-logic 2012-06-26 08:39:27 -04:00
Jeff Mitchell
c14984c647 Merge branch 'master' into specfilescanning 2012-06-26 08:19:50 -04:00
Jeff Mitchell
1369e838eb Revert "See if this fixes lfranchi's assert"
This reverts commit e6af7b03d7.

Conflicts:

	src/libtomahawk/database/DatabaseImpl.cpp
2012-06-26 08:19:39 -04:00
Jeff Mitchell
09f84fe9e6 Merge branch 'master' into specfilescanning 2012-06-26 08:15:04 -04:00
Jeff Mitchell
31fda52bcf Unify file metadata handler location -- tag changing code should go in
here too
2012-06-26 08:14:16 -04:00
Jeff Mitchell
cede202e96 Move ScanManager into libtomahawk. It's core functionality, non-GUI, and
this lets things in libtomahawk call scan functions easily
2012-06-26 08:09:06 -04:00
Christian Muehlhaeuser
7efaa62038 * Elide temporary page's text when showing the delete button. 2012-06-26 05:16:00 +02:00
Christian Muehlhaeuser
f303fcbebc * Spit out error messages when we couldn't resolve a track, album or artist. 2012-06-26 05:02:28 +02:00
Christian Muehlhaeuser
d0fdff760e * Remove spinner when AudioEngine stopped. 2012-06-26 05:01:39 +02:00
Christian Muehlhaeuser
3a5acb721c * Style cleanup. 2012-06-26 05:01:18 +02:00
Christian Muehlhaeuser
03695c2bc4 * Set m_finished when tracks are loaded in Artist- & AlbumPlaylistInterface. 2012-06-26 05:00:26 +02:00
Christian Muehlhaeuser
3a580faa1d * Added a isFinished and m_finished to PlaylistInterface. 2012-06-26 04:59:46 +02:00
Christian Muehlhaeuser
6fc4f2a89a * Auto re-prepare query on weird 'no query' error. 2012-06-26 04:03:03 +02:00
Christian Muehlhaeuser
dbd137a561 * Don't scale now playing icon decoration when expanding a playlist item. 2012-06-26 03:44:03 +02:00
Christian Muehlhaeuser
fa52f8a75c * Don't expand LovedTracksItem. 2012-06-26 03:33:35 +02:00
Christian Muehlhaeuser
5bd616e59d Merge pull request #100 from creichert/twk932-drag-loved-tracks
Allow dragging tracks into loved tracks playlist.
2012-06-25 18:14:29 -07:00
Christian Muehlhaeuser
e4e3b0f825 * Use new RecentlyPlayedModel API. 2012-06-26 03:05:28 +02:00
Christian Muehlhaeuser
035e59e0b5 * Use new Recently- Played/Added -Model's API. 2012-06-26 02:58:12 +02:00
Christian Muehlhaeuser
e316534dc0 * Split up CTOR and setSource methods. 2012-06-26 02:57:12 +02:00
Christian Muehlhaeuser
8fc89f3a2b * Split up CTOR and setSource methods. 2012-06-26 02:56:47 +02:00
Christian Muehlhaeuser
972a57bfeb * Show loading spinner when loading charts. 2012-06-26 02:28:40 +02:00
Christian Muehlhaeuser
0dad8b9218 * Show a loading spinner when loading a collection. 2012-06-26 02:16:57 +02:00
Christian Muehlhaeuser
2f07c92fdd * Remove comments. 2012-06-26 02:16:38 +02:00
Christian Muehlhaeuser
e5439c7775 * Don't show an info button for empty items. 2012-06-26 02:12:09 +02:00
Christian Muehlhaeuser
dc9e3728f5 * Automatically adjust crash-reporter's window size. 2012-06-26 02:05:11 +02:00
Christian Muehlhaeuser
0f7291368f * Don't reset current viewpage when the new page is the same as the current one. 2012-06-26 01:57:22 +02:00
Jeff Mitchell
18be2f5f7e Some refactoring, and allow running scans on specific files only. 2012-06-25 18:59:42 -04:00
Christian Muehlhaeuser
ee6e3c9e69 * Make sure script-resolvers are executable before trying to execute them. 2012-06-25 23:04:32 +02:00
Christian Muehlhaeuser
b453d80808 * Re-center play/pause buttons when resizing GridView. 2012-06-25 22:56:03 +02:00
Christian Muehlhaeuser
7fb6701e3e * No need to manuall set fake query's results. 2012-06-25 21:16:31 +02:00
Christian Muehlhaeuser
a9e0c3c460 * Respond to pings from external resolver. 2012-06-25 21:12:55 +02:00
Jeff Mitchell
2fd970d24d Add verbose logging on sendmsg to try to track down JSON issue 2012-06-25 13:34:52 -04:00
Christian Muehlhaeuser
d39378b599 * Don't show resolver errors when built with RelWithDebInfo. 2012-06-25 19:16:53 +02:00
Christian Muehlhaeuser
037a5dab12 * Temporary fix for compiling madness. 2012-06-25 17:57:52 +02:00
Christian Muehlhaeuser
38735cb248 Revert "* Let's see if it's just an issue with typedef."
This reverts commit cf01330778.
2012-06-25 17:55:03 +02:00
Christian Muehlhaeuser
cf01330778 * Let's see if it's just an issue with typedef. 2012-06-25 17:50:20 +02:00
Tomahawk CI
6f8676feec Automatic merge of Transifex translations 2012-06-24 22:16:53 +00:00
Christian Muehlhaeuser
f9de027557 * Fixed compiling on Windows. I hope. 2012-06-25 00:01:05 +02:00
Christian Muehlhaeuser
f2101c2986 * Style cleanup. 2012-06-24 23:55:08 +02:00
Christian Muehlhaeuser
746914844e * Bump version to 0.5.99. 2012-06-24 23:55:07 +02:00
Christopher Reichert
021546cb73 Allow dragging tracks into loved tracks playlist.
Fix for TWK-932.
2012-06-24 14:10:01 -05:00
Jeff Mitchell
7dd88208a7 Add ChangeLog entries 2012-06-24 14:46:05 -04:00
Christian Muehlhaeuser
f134e48a49 * Fixed OSX linking. 2012-06-24 18:48:18 +02:00
Christian Muehlhaeuser
88da871f6a * Fixed Windows includes. 2012-06-24 18:37:19 +02:00
Christian Muehlhaeuser
a54e5fbf46 * Fixed compiling on OSX. 2012-06-24 18:30:53 +02:00
Christian Muehlhaeuser
d3eb5c3f88 * Updated breakpad to latest version. 2012-06-24 18:25:34 +02:00
Christian Muehlhaeuser
0a3a9a7e97 * Mutex protect logging. 2012-06-24 11:16:20 +02:00
Christian Muehlhaeuser
9171de999b * Init Database earlier. 2012-06-24 11:15:54 +02:00
Christian Muehlhaeuser
f8ca1ac994 * While not a bug, this shutdown check would have never been triggered. 2012-06-24 11:15:17 +02:00
Tomahawk CI
5cc86b7876 Automatic merge of Transifex translations 2012-06-23 22:16:52 +00:00
301 changed files with 18098 additions and 6999 deletions

2
.gitignore vendored
View File

@@ -5,6 +5,8 @@ build/*
*.o
._*
*.user
*.swp
*.swo
Makefile*
moc_*
*~

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 4 )
SET( TOMAHAWK_VERSION_PATCH 99 )
#SET( TOMAHAWK_VERSION_RC 0 )
@@ -88,7 +88,7 @@ IF( NOT BUILD_GUI )
MESSAGE( STATUS "Building Tomahawk ${TOMAHAWK_VERSION} in HEADLESS mode ***" )
ELSE()
MESSAGE( STATUS "Building Tomahawk ${TOMAHAWK_VERSION} full GUI version ***" )
LIST(APPEND NEEDED_QT4_COMPONENTS "QtGui" "QtWebkit" "QtUiTools" )
LIST(APPEND NEEDED_QT4_COMPONENTS "QtGui" "QtWebkit" "QtUiTools" "QtDeclarative" )
ENDIF()
IF( BUILD_GUI AND UNIX AND NOT APPLE )
@@ -104,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")
@@ -118,11 +118,11 @@ macro_log_feature(TAGLIB_FOUND "TagLib" "Audio Meta-Data Library" "http://develo
include( CheckTagLibFileName )
check_taglib_filename( COMPLEX_TAGLIB_FILENAME )
macro_optional_find_package(Boost)
macro_optional_find_package( Boost )
macro_log_feature(Boost_FOUND "Boost" "Provides free peer-reviewed portable C++ source libraries" "http://www.boost.org" TRUE "" "") #FIXME: give useful explaination
macro_optional_find_package(QCA2)
macro_log_feature(QCA2_FOUND "QCA2" "Provides encryption and signing functions required for Grooveshark resolver" "http://delta.affinix.com/qca/" FALSE "" "")
macro_log_feature(QCA2_FOUND "QCA2" "Provides encryption and signing functions required for Grooveshark resolver" "http://delta.affinix.com/qca/" TRUE "" "")
macro_optional_find_package(LibAttica 0.4.0)
macro_log_feature(LIBATTICA_FOUND "libattica" "Provides support for automatic fetching and managing of resolvers from the tomahawk website" "https://projects.kde.org/projects/kdesupport/attica" TRUE "" "")

147
CMakeLists.txt.user.2.3pre1 Normal file
View File

@@ -0,0 +1,147 @@
<!DOCTYPE QtCreatorProject>
<qtcreator>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value key="EditorConfiguration.AutoIndent" type="bool">true</value>
<value key="EditorConfiguration.AutoSpacesForTabs" type="bool">false</value>
<value key="EditorConfiguration.Codec" type="QByteArray">UTF-8</value>
<value key="EditorConfiguration.DoubleIndentBlocks" type="bool">false</value>
<value key="EditorConfiguration.IndentBraces" type="bool">false</value>
<value key="EditorConfiguration.IndentSize" type="int">4</value>
<value key="EditorConfiguration.MouseNavigation" type="bool">true</value>
<value key="EditorConfiguration.PaddingMode" type="int">1</value>
<value key="EditorConfiguration.ScrollWheelZooming" type="bool">true</value>
<value key="EditorConfiguration.SmartBackspace" type="bool">false</value>
<value key="EditorConfiguration.SpacesForTabs" type="bool">true</value>
<value key="EditorConfiguration.TabKeyBehavior" type="int">0</value>
<value key="EditorConfiguration.TabSize" type="int">8</value>
<value key="EditorConfiguration.UseGlobal" type="bool">true</value>
<value key="EditorConfiguration.Utf8BomBehavior" type="int">1</value>
<value key="EditorConfiguration.addFinalNewLine" type="bool">true</value>
<value key="EditorConfiguration.cleanIndentation" type="bool">true</value>
<value key="EditorConfiguration.cleanWhitespace" type="bool">true</value>
<value key="EditorConfiguration.inEntireDocument" type="bool">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Desktop</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">CMakeProjectManager.DefaultCMakeTarget</value>
<value key="ProjectExplorer.Target.ActiveBuildConfiguration" type="int">0</value>
<value key="ProjectExplorer.Target.ActiveDeployConfiguration" type="int">0</value>
<value key="ProjectExplorer.Target.ActiveRunConfiguration" type="int">0</value>
<valuemap key="ProjectExplorer.Target.BuildConfiguration.0" type="QVariantMap">
<value key="CMakeProjectManager.CMakeBuildConfiguration.BuildDirectory" type="QString">/home/micha/Develop/tomahawk-build</value>
<value key="CMakeProjectManager.CMakeBuildConfiguration.ToolChain" type="QString">ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-64bit.</value>
<value key="ProjectExplorer.BuildCOnfiguration.ToolChain" type="QString">ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-64bit.</value>
<valuemap key="ProjectExplorer.BuildConfiguration.BuildStepList.0" type="QVariantMap">
<valuemap key="ProjectExplorer.BuildStepList.Step.0" type="QVariantMap">
<value key="CMakeProjectManager.MakeStep.AdditionalArguments" type="QString"></value>
<valuelist key="CMakeProjectManager.MakeStep.BuildTargets" type="QVariantList"/>
<value key="CMakeProjectManager.MakeStep.Clean" type="bool">false</value>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Make</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">CMakeProjectManager.MakeStep</value>
</valuemap>
<value key="ProjectExplorer.BuildStepList.StepsCount" type="int">1</value>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Build</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap key="ProjectExplorer.BuildConfiguration.BuildStepList.1" type="QVariantMap">
<valuemap key="ProjectExplorer.BuildStepList.Step.0" type="QVariantMap">
<value key="CMakeProjectManager.MakeStep.AdditionalArguments" type="QString">clean</value>
<valuelist key="CMakeProjectManager.MakeStep.BuildTargets" type="QVariantList"/>
<value key="CMakeProjectManager.MakeStep.Clean" type="bool">true</value>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Make</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">CMakeProjectManager.MakeStep</value>
</valuemap>
<value key="ProjectExplorer.BuildStepList.StepsCount" type="int">1</value>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Clean</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value key="ProjectExplorer.BuildConfiguration.BuildStepListCount" type="int">2</value>
<value key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment" type="bool">false</value>
<valuelist key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges" type="QVariantList"/>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">all</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<value key="ProjectExplorer.Target.BuildConfigurationCount" type="int">1</value>
<valuemap key="ProjectExplorer.Target.DeployConfiguration.0" type="QVariantMap">
<valuemap key="ProjectExplorer.BuildConfiguration.BuildStepList.0" type="QVariantMap">
<value key="ProjectExplorer.BuildStepList.StepsCount" type="int">0</value>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Deploy</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value key="ProjectExplorer.BuildConfiguration.BuildStepListCount" type="int">1</value>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">No deployment</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value key="ProjectExplorer.Target.DeployConfigurationCount" type="int">1</value>
<valuemap key="ProjectExplorer.Target.RunConfiguration.0" type="QVariantMap">
<valuelist key="Analyzer.Valgrind.AddedSupressionFiles" type="QVariantList"/>
<value key="Analyzer.Valgrind.FilterExternalIssues" type="bool">true</value>
<value key="Analyzer.Valgrind.NumCallers" type="int">25</value>
<valuelist key="Analyzer.Valgrind.RemovedSupressionFiles" type="QVariantList"/>
<value key="Analyzer.Valgrind.TrackOrigins" type="bool">true</value>
<value key="Analyzer.Valgrind.ValgrindExecutable" type="QString">valgrind</value>
<valuelist key="Analyzer.Valgrind.VisibleErrorKinds" type="QVariantList">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value key="CMakeProjectManager.BaseEnvironmentBase" type="int">2</value>
<value key="CMakeProjectManager.CMakeRunConfiguation.Title" type="QString">tomahawk</value>
<value key="CMakeProjectManager.CMakeRunConfiguration.Arguments" type="QString">--verbose</value>
<value key="CMakeProjectManager.CMakeRunConfiguration.UseTerminal" type="bool">false</value>
<valuelist key="CMakeProjectManager.CMakeRunConfiguration.UserEnvironmentChanges" type="QVariantList">
<value type="QString">Q_FATAL_WARNINGS=1</value>
</valuelist>
<value key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">tomahawk</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">CMakeProjectManager.CMakeRunConfiguration.</value>
<value key="RunConfiguration.QmlDebugServerPort" type="uint">3768</value>
<value key="RunConfiguration.UseCppDebugger" type="bool">true</value>
<value key="RunConfiguration.UseQmlDebugger" type="bool">false</value>
</valuemap>
<value key="ProjectExplorer.Target.RunConfigurationCount" type="int">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
<value type="QString">{6caf061d-47d5-4e4f-a8d8-0d83c14e4267}</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">9</value>
</data>
</qtcreator>

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,21 @@
Version 0.6.0:
* Access Control queries now stay on the bottom of the job view,
removing the tendency to jump away from the mouse.
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.

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

@@ -49,10 +49,33 @@ tar xvjf pvlc.tar.bz2
# libtaglib_plugin.dll
# this is for vlc-1.2
# rm -rvf video_*/ gui/ */libold* */libvcd* */libdvd* */liblibass* */libx264* */libschroe* */liblibmpeg2* \
# */libstream_out_* */libmjpeg_plugin* */libh264_plugin* */libzvbi_plugin* */lib*sub* \
# services_discover/ visualization/ control/ misc/
# this is for vlc-2.x
rm -rvf \
video_*/ \
gui/ \
**/libold* \
**/libvcd* \
**/libdvd* \
**/liblibass* \
**/libx264* \
**/libschroe* \
**/liblibmpeg2* \
**/libstream_out_* \
**/libmjpeg_plugin* \
**/libh264_plugin* \
**/libzvbi_plugin* \
**/lib*sub* \
services_discovery/ \
visualization/ \
control/ \
misc/ \
**/libi420* \
**/libi422* \
mux/ \
stream_filter/ \
**/libtheora_plugin* \
**/liblibbluray_plugin* \
**/libdtv_plugin*
echo "Downloaded and stripped VLC"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@@ -1,80 +1,101 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Layer_1"
x="0px"
y="0px"
width="606.2478"
height="595.49866"
viewBox="0 0 606.24779 595.49863"
enable-background="new 0 0 841.89 595.28"
xml:space="preserve"
inkscape:version="0.48.2 r9819"
sodipodi:docname="tomahawk-icon.svg"><metadata
id="metadata15"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs13" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1440"
inkscape:window-height="794"
id="namedview11"
showgrid="false"
inkscape:zoom="1"
inkscape:cx="431.12548"
inkscape:cy="336.94553"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="Layer_1"
inkscape:snap-page="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"><sodipodi:guide
position="-3.5728101e-05,-1.501866e-05"
orientation="0,841.89001"
id="guide2994" /><sodipodi:guide
position="841.88997,-1.501866e-05"
orientation="-595.28003,0"
id="guide2996" /><sodipodi:guide
position="841.88997,595.28001"
orientation="0,-841.89001"
id="guide2998" /><sodipodi:guide
position="-3.5728101e-05,595.28001"
orientation="595.28003,0"
id="guide3000" /></sodipodi:namedview>
<g
id="g3"
transform="matrix(7.3080643,0,0,7.1790074,-2773.1692,-1839.0104)">
<g
id="g5">
<path
d="m 420.947,265.168 c -17.911,0 -32.477,14.565 -32.477,32.472 0,17.906 14.565,32.476 32.477,32.476 2.568,0 5.06,-0.318 7.459,-0.888 v -28.011 l -22.338,15.806 c -0.198,0.135 -0.444,0.213 -0.681,0.213 -0.184,0 -0.372,-0.039 -0.541,-0.136 -0.396,-0.202 -0.642,-0.608 -0.642,-1.043 v -37.053 c 0,-0.435 0.246,-0.845 0.642,-1.053 0.396,-0.193 0.864,-0.159 1.222,0.092 l 22.338,15.807 v -16.028 h 0.951 8.945 v 47.234 c 9.076,-5.764 15.121,-15.888 15.121,-27.417 10e-4,-17.905 -14.569,-32.471 -32.476,-32.471 z"
id="path7"
inkscape:connector-curvature="0"
style="fill:none" />
<path
d="m 420.947,256.165 c -22.874,0 -41.48,18.606 -41.48,41.475 0,22.87 18.606,41.475 41.48,41.475 22.869,0 41.476,-18.605 41.476,-41.475 0,-22.869 -18.607,-41.475 -41.476,-41.475 z m 17.356,68.892 v -47.234 h -8.945 -0.951 v 16.028 l -22.338,-15.807 c -0.357,-0.251 -0.826,-0.285 -1.222,-0.092 -0.396,0.208 -0.642,0.618 -0.642,1.053 v 37.053 c 0,0.435 0.246,0.841 0.642,1.043 0.169,0.097 0.357,0.136 0.541,0.136 0.236,0 0.482,-0.078 0.681,-0.213 l 22.338,-15.806 v 28.011 c -2.399,0.569 -4.891,0.888 -7.459,0.888 -17.911,0 -32.477,-14.57 -32.477,-32.476 0,-17.906 14.565,-32.472 32.477,-32.472 17.906,0 32.477,14.565 32.477,32.472 -0.001,11.528 -6.046,21.652 -15.122,27.416 z"
id="path9"
inkscape:connector-curvature="0"
style="fill:#e63e30" />
</g>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="606.248px" height="595.5px" viewBox="0 0 606.248 595.5" enable-background="new 0 0 606.248 595.5" xml:space="preserve">
<g id="Layer_3">
<rect x="-20.376" y="-15.75" stroke="#E63E30" stroke-miterlimit="10" width="688" height="700"/>
</g>
<g id="Layer_2">
<path id="path9_1_" inkscape:connector-curvature="0" fill="none" stroke="#E63E30" stroke-miterlimit="10" d="M429.977,493.576
V154.483h-65.371h-6.949v115.065L194.409,156.07c-2.608-1.802-6.036-2.046-8.93-0.661c-2.895,1.493-4.692,4.437-4.692,7.56v266.003
c0,3.123,1.798,6.037,4.692,7.488c1.234,0.695,2.608,0.977,3.953,0.977c1.725,0,3.522-0.561,4.977-1.529l163.248-113.472v201.091
c-17.532,4.084-35.744,6.375-54.511,6.375c-130.896,0-237.345-104.598-237.345-233.146c0-128.547,106.442-233.117,237.345-233.117
c130.858,0,237.344,104.562,237.344,233.116C540.482,379.515,496.305,452.197,429.977,493.576L429.977,493.576z"/>
<ellipse fill="#FFFFFF" stroke="#E63E30" stroke-miterlimit="10" cx="318.624" cy="295.75" rx="286" ry="270.5"/>
</g>
<g id="Layer_1" sodipodi:docname="tomahawk-icon.svg" inkscape:version="0.48.2 r9819" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape">
<sodipodi:namedview fit-margin-bottom="0" fit-margin-right="0" inkscape:snap-page="false" inkscape:current-layer="Layer_1" inkscape:window-maximized="0" inkscape:window-y="0" inkscape:window-x="0" inkscape:window-height="794" inkscape:window-width="1440" inkscape:pageshadow="2" inkscape:pageopacity="0" fit-margin-left="0" fit-margin-top="0" inkscape:cy="336.94553" inkscape:cx="431.12548" inkscape:zoom="1" showgrid="false" guidetolerance="10" gridtolerance="10" objecttolerance="10" bordercolor="#666666" pagecolor="#ffffff" borderopacity="1" id="namedview11">
<sodipodi:guide orientation="0,841.89001" position="-3.5728101e-05,-1.501866e-05" id="guide2994"></sodipodi:guide>
<sodipodi:guide orientation="-595.28003,0" position="841.88997,-1.501866e-05" id="guide2996"></sodipodi:guide>
<sodipodi:guide orientation="0,-841.89001" position="841.88997,595.28001" id="guide2998"></sodipodi:guide>
<sodipodi:guide orientation="595.28003,0" position="-3.5728101e-05,595.28001" id="guide3000"></sodipodi:guide>
</sodipodi:namedview>
<g id="g3_1_" transform="matrix(7.3080643,0,0,7.1790074,-2773.1692,-1839.0104)">
<g>
<g enable-background="new ">
<g>
<polygon fill="#4C1410" points="430.355,293.516 429.444,293.909 429.416,279.061 430.323,277.603 "/>
</g>
<g>
<polygon fill="#4C1410" points="430.428,328.913 429.507,326.921 429.457,300.757 430.371,300.856 "/>
</g>
<g enable-background="new ">
<defs>
<path id="SVGID_1_" enable-background="new " d="M440.229,324.595l-1.574-1.692c2.083-1.367,3.987-2.983,5.669-4.803
c1.678-1.816,3.136-3.836,4.332-6.018c1.194-2.177,2.127-4.516,2.758-6.973c0.63-2.454,0.959-5.028,0.945-7.679
c-0.022-4.114-0.867-8.035-2.377-11.605c-1.51-3.571-3.686-6.797-6.372-9.519c-2.69-2.726-5.895-4.949-9.458-6.505
c-3.573-1.561-7.51-2.454-11.652-2.511c-4.16-0.058-8.14,0.731-11.777,2.212c-3.65,1.486-6.953,3.668-9.739,6.386
c-2.795,2.728-5.069,5.995-6.649,9.637c-1.584,3.651-2.47,7.677-2.486,11.907c-0.016,4.236,0.842,8.276,2.405,11.95
c1.563,3.673,3.829,6.974,6.627,9.736c2.794,2.757,6.114,4.973,9.791,6.483c3.666,1.506,7.683,2.31,11.88,2.251
c0.601-0.008,1.197-0.036,1.787-0.08c0.59-0.045,1.176-0.107,1.756-0.186c0.58-0.079,1.154-0.174,1.723-0.286
c0.569-0.111,1.132-0.238,1.689-0.379l0.921,1.992c-0.597,0.152-1.201,0.288-1.81,0.408c-0.61,0.12-1.226,0.223-1.847,0.308
c-0.622,0.085-1.249,0.153-1.883,0.201c-0.634,0.049-1.272,0.078-1.917,0.088c-4.502,0.068-8.811-0.79-12.745-2.404
c-3.946-1.618-7.511-3.994-10.51-6.951c-3.004-2.963-5.437-6.506-7.115-10.448c-1.678-3.944-2.599-8.28-2.58-12.827
c0.018-4.54,0.971-8.86,2.673-12.777c1.698-3.907,4.139-7.409,7.141-10.333c2.99-2.913,6.534-5.249,10.45-6.838
c3.9-1.583,8.167-2.424,12.626-2.357c4.439,0.066,8.656,1.027,12.483,2.703c3.815,1.671,7.247,4.055,10.127,6.976
c2.875,2.916,5.205,6.373,6.822,10.198c1.616,3.824,2.522,8.023,2.548,12.43c0.016,2.84-0.335,5.597-1.008,8.226
c-0.674,2.633-1.672,5.139-2.949,7.472c-1.279,2.338-2.839,4.504-4.636,6.452C444.498,321.393,442.46,323.127,440.229,324.595
z"/>
</defs>
<clipPath id="SVGID_2_">
<use xlink:href="#SVGID_1_" overflow="visible"/>
</clipPath>
<g clip-path="url(#SVGID_2_)" enable-background="new ">
<path fill="#4D1510" d="M440.229,324.595l-1.574-1.692c2.083-1.367,3.987-2.983,5.669-4.803
c1.678-1.816,3.136-3.836,4.332-6.018c1.194-2.177,2.127-4.516,2.758-6.973c0.63-2.454,0.959-5.028,0.945-7.679
c-0.022-4.114-0.867-8.035-2.377-11.605c-1.51-3.571-3.686-6.797-6.372-9.519c-2.69-2.726-5.895-4.949-9.458-6.505
c-3.573-1.561-7.51-2.454-11.652-2.511c-4.16-0.058-8.14,0.731-11.777,2.212c-3.65,1.486-6.953,3.668-9.739,6.386
c-2.795,2.728-5.069,5.995-6.649,9.637c-1.584,3.651-2.47,7.677-2.486,11.907c-0.016,4.236,0.842,8.276,2.405,11.95
c1.563,3.673,3.829,6.974,6.627,9.736c2.794,2.757,6.114,4.973,9.791,6.483c3.666,1.506,7.683,2.31,11.88,2.251
c0.601-0.008,1.197-0.036,1.787-0.08c0.59-0.045,1.176-0.107,1.756-0.186c0.58-0.079,1.154-0.174,1.723-0.286
c0.569-0.111,1.132-0.238,1.689-0.379l0.921,1.992c-0.597,0.152-1.201,0.288-1.81,0.408c-0.61,0.12-1.226,0.223-1.847,0.308
c-0.622,0.085-1.249,0.153-1.883,0.201c-0.634,0.049-1.272,0.078-1.917,0.088c-4.502,0.068-8.811-0.79-12.745-2.404
c-3.946-1.618-7.511-3.994-10.51-6.951c-3.004-2.963-5.437-6.506-7.115-10.448c-1.678-3.944-2.599-8.28-2.58-12.827
c0.018-4.54,0.971-8.86,2.673-12.777c1.698-3.907,4.139-7.409,7.141-10.333c2.99-2.913,6.534-5.249,10.45-6.838
c3.9-1.583,8.167-2.424,12.626-2.357c4.439,0.066,8.656,1.027,12.483,2.703c3.815,1.671,7.247,4.055,10.127,6.976
c2.875,2.916,5.205,6.373,6.822,10.198c1.616,3.824,2.522,8.023,2.548,12.43c0.016,2.84-0.335,5.597-1.008,8.226
c-0.674,2.633-1.672,5.139-2.949,7.472c-1.279,2.338-2.839,4.504-4.636,6.452C444.498,321.393,442.46,323.127,440.229,324.595
"/>
</g>
</g>
<g>
<path fill="#E53E30" d="M422.903,256.08c5.658,0.108,11.029,1.353,15.897,3.504c4.85,2.143,9.21,5.189,12.868,8.915
c3.65,3.717,6.608,8.117,8.662,12.983c2.053,4.864,3.208,10.204,3.247,15.808c0.04,5.613-1.043,10.98-3.039,15.883
c-2.002,4.92-4.927,9.381-8.565,13.159c-3.654,3.795-8.032,6.904-12.92,9.095c-4.913,2.202-10.344,3.478-16.073,3.588
c-5.761,0.111-11.281-0.966-16.325-3.014c-5.064-2.056-9.641-5.088-13.494-8.871c-3.862-3.792-6.988-8.332-9.143-13.388
c-2.155-5.058-3.333-10.622-3.302-16.455c0.032-5.822,1.266-11.358,3.463-16.374c2.19-4.998,5.333-9.474,9.191-13.203
c3.84-3.711,8.385-6.68,13.4-8.69C411.761,257.022,417.213,255.972,422.903,256.08z M440.229,324.595
c2.231-1.468,4.269-3.201,6.069-5.154c1.796-1.948,3.356-4.114,4.636-6.452c1.277-2.334,2.274-4.84,2.949-7.472
c0.673-2.629,1.024-5.386,1.008-8.226c-0.025-4.407-0.931-8.606-2.548-12.43c-1.617-3.826-3.947-7.282-6.822-10.198
c-2.88-2.922-6.312-5.305-10.127-6.976c-3.827-1.676-8.044-2.637-12.483-2.703c-4.458-0.067-8.726,0.775-12.626,2.357
c-3.916,1.589-7.46,3.925-10.45,6.838c-3.001,2.924-5.443,6.426-7.141,10.333c-1.702,3.917-2.655,8.237-2.673,12.777
c-0.018,4.547,0.902,8.884,2.58,12.827c1.678,3.942,4.111,7.485,7.115,10.448c2.999,2.957,6.563,5.333,10.51,6.951
c3.934,1.613,8.243,2.471,12.745,2.404c0.644-0.01,1.283-0.039,1.917-0.088c0.633-0.049,1.261-0.116,1.883-0.201
c0.622-0.085,1.237-0.188,1.847-0.308c0.609-0.12,1.213-0.256,1.81-0.408l-0.057-28.056l-22.413,16.004
c-0.051,0.034-0.104,0.065-0.16,0.092c-0.056,0.027-0.113,0.05-0.172,0.069c-0.059,0.019-0.119,0.033-0.179,0.043
c-0.06,0.01-0.121,0.016-0.18,0.016c-0.047,0.001-0.094-0.001-0.141-0.006c-0.047-0.005-0.094-0.012-0.14-0.023
c-0.046-0.011-0.092-0.024-0.137-0.041c-0.045-0.017-0.089-0.037-0.132-0.061c-0.1-0.05-0.191-0.114-0.271-0.187
c-0.08-0.074-0.149-0.157-0.205-0.249c-0.056-0.091-0.1-0.19-0.13-0.294s-0.045-0.212-0.045-0.322l0.06-37.332
c0-0.109,0.016-0.216,0.046-0.319c0.03-0.103,0.074-0.201,0.13-0.292c0.056-0.091,0.125-0.175,0.205-0.249
c0.08-0.074,0.17-0.138,0.27-0.189c0.043-0.02,0.087-0.038,0.131-0.053s0.09-0.028,0.135-0.037
c0.046-0.01,0.091-0.017,0.137-0.022c0.046-0.005,0.092-0.007,0.138-0.006c0.061,0.001,0.122,0.006,0.183,0.015
c0.06,0.01,0.12,0.024,0.178,0.042c0.058,0.018,0.116,0.042,0.171,0.069c0.055,0.027,0.109,0.059,0.161,0.095l22.346,15.897
l-0.033-15.913l0.94,0.009l8.801,0.081L440.229,324.595"/>
</g>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -0,0 +1,139 @@
import QtQuick 1.1
Rectangle {
color: "black"
anchors.fill: parent
// height: 200
// width: 200
Component {
id: pathDelegate
Item {
width: 100; height: 100
scale: PathView.iconScale
// TODO: Use Image provider here
Image {
id: originalImage
width: 80
height: 80
source: index % 2 === 0 ? "http://www.muktware.com/sites/default/files/images/applications/tomahawk_icon.png" : "http://cloud.ohloh.net/attachments/53867/tomahawk-icon-64x64_med.png"
}
// mirror image - album art and a gradient filled rectangle for darkening
Item {
width: originalImage.width; height: originalImage.height
anchors.horizontalCenter: originalImage.horizontalCenter
// transform this item (the image and rectangle) to create the
// mirror image using the values from the Path
transform : [
Rotation {
angle: 180; origin.y: originalImage.height
axis.x: 1; axis.y: 0; axis.z: 0
},
Rotation {
angle: PathView.rotateY; origin.x: originalImage.width/2
axis.x: 0; axis.y: 1; axis.z: 0
},
Scale {
xScale: PathView.scaleArt; yScale: PathView.scaleArt
origin.x: originalImage.width/2; origin.y: originalImage.height/2
}
]
// mirror image
Image {
width: originalImage.width; height: originalImage.height
source: originalImage.source
anchors.horizontalCenter: parent.horizontalCenter
}
// mirror image dimming gradient filled rectangle
Rectangle {
width: originalImage.width+4; height: originalImage.height
anchors.horizontalCenter: parent.horizontalCenter
gradient: Gradient {
// TODO: no clue how to get the RGB component of the container rectangle color
GradientStop { position: 1.0; color: Qt.rgba(0,0,0,0.4) }
GradientStop { position: 0.3; color: reflectionContainer.color }
}
}
}
Text {
anchors { top: myIcon.bottom; horizontalCenter: parent.horizontalCenter }
text: label
smooth: true
color: "white"
}
MouseArea {
anchors.fill: parent
onClicked: view.currentIndex = index
}
}
}
PathView {
id: view
anchors { left: parent.left; top: parent.top; right: parent.right }
height: 300
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
focus: true
model: albumsModel
delegate: pathDelegate
pathItemCount: 8
path: Path {
startX: 10
startY: 50
PathAttribute { name: "iconScale"; value: 0.5 }
PathQuad { x: view.width/2; y: 150; controlX: 50; controlY: 200 }
PathAttribute { name: "iconScale"; value: 1.0 }
PathQuad { x: view.width; y: 50; controlX: view.width; controlY: 200 }
PathAttribute { name: "iconScale"; value: 0.5 }
}
}
Component {
id: gridDelegate
Item {
width: 100; height: 100
scale: PathView.iconScale
// TODO: Use Image provider here
Image {
id: originalImage
width: 80
height: 80
source: index % 2 === 0 ? "http://www.muktware.com/sites/default/files/images/applications/tomahawk_icon.png" : "http://cloud.ohloh.net/attachments/53867/tomahawk-icon-64x64_med.png"
}
Text {
anchors { top: myIcon.bottom; horizontalCenter: parent.horizontalCenter }
text: label
smooth: true
color: "white"
}
MouseArea {
anchors.fill: parent
onClicked: view.currentIndex = index
}
}
}
GridView {
id: grid
anchors { left: parent.left; top: view.bottom; right: parent.right; bottom: parent.bottom }
model: albumsModel
delegate: gridDelegate
}
}

155
data/qml/CoverImage.qml Normal file
View File

@@ -0,0 +1,155 @@
import QtQuick 1.1
Item {
id: root
// Should the artist + track labels be painted
property bool showLabels: true
// Should the play button be painted on mouse hover?
property bool showPlayButton: false
// Should the mirror be painted?
property bool showMirror: false
// Labels & Cover
property string artistName
property string trackName
property string artworkId
onArtworkIdChanged: print("!*!*!*!*!* artworkId", artworkId)
// The border color for the cover image
property color borderColor: "black"
// The border width for the cover image
property int borderWidth: 2
// needed to adjust the shadow
property color backgroundColor: "black"
// sets the brightness for the item and its mirror (1: brightest, 0: darkest)
property double itemBrightness: 1
property double mirrorBrightness: .5
// will be emitted when the on hower play button is clicked
signal playClicked()
// will be emitted when the cover is clicked
signal clicked()
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: root.clicked();
}
Component {
id: coverImage
Rectangle {
color: "white"
border.color: borderColor
border.width: borderWidth
Image {
anchors.fill: parent
//anchors.margins: borderWidth
source: "image://albumart/" + artworkId
}
Rectangle {
id: textBackground
anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
height: 32
anchors.margins: 5
color: "black"
opacity: showLabels ? 0.5 : 0
radius: 3
}
Text {
color: "white"
font.bold: true
text: trackName
anchors { left: textBackground.left; right: textBackground.right; top: textBackground.top }
anchors.margins: 2
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
opacity: showLabels ? 1 : 0
}
Text {
color: "white"
text: artistName
anchors { left: textBackground.left; right: textBackground.right; bottom: textBackground.bottom }
anchors.margins: 2
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
opacity: showLabels ? 1 : 0
}
}
}
Loader {
sourceComponent: coverImage
anchors.fill: parent
}
Loader {
id: mirroredCover
sourceComponent: parent.showMirror ? coverImage : undefined
anchors.fill: parent
transform : [
Rotation {
angle: 180; origin.y: root.height
axis.x: 1; axis.y: 0; axis.z: 0
}
]
}
Rectangle {
id: itemShadow
color: backgroundColor
anchors.fill: parent
anchors.bottomMargin: - parent.height
// scaling might be off a pixel... make sure that the shadow is at least as large as the image
anchors.leftMargin: -2
anchors.rightMargin: -2
anchors.topMargin: -2
opacity: 1 - itemBrightness + (mouseArea.containsMouse ? .2 : 0)
Behavior on opacity {
NumberAnimation { easing.type: Easing.Linear; duration: 300 }
}
}
Rectangle {
id: mirrorShadow
color: parent.backgroundColor
height: parent.height + 2
width: parent.width + 4
anchors.centerIn: parent
anchors.verticalCenterOffset: parent.height
gradient: Gradient {
// TODO: no clue how to get the RGB component of the container rectangle color
// For now the Qt.rgba needs to be manually updated to match the backgroundColor
GradientStop { position: 0.0; color: Qt.rgba(0, 0, 0, 1-mirrorBrightness) }
GradientStop { position: 0.5; color: backgroundColor }
}
}
Image {
id: playButton
visible: showPlayButton ? mouseArea.containsMouse : false
source: "../images/play-rest.png"
anchors.centerIn: parent
MouseArea {
anchors.fill: parent
onClicked: root.playClicked();
}
}
}

View File

@@ -0,0 +1,79 @@
import QtQuick 1.1
import tomahawk 1.0
import "tomahawkimports"
Item {
id: fineTuneView
property color textColor: "white"
signal done();
Grid {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.margins: 50
anchors.horizontalCenter: parent.horizontalCenter
width: scene.width / 2
spacing: 50
columns: 2
Text {
color: fineTuneView.textColor
text: "Name:"
}
InputField {
text: echonestStation.name
onAccepted: {
print("text changed!!!")
echonestStation.name = text;
}
}
Text {
id: tempoText
text: "Tempo:"
color: "white"
}
DoubleSlider {
width: 500
height: tempoText.height
min: 0
max: 500
lowerSliderPos: echonestStation.minTempo
upperSliderPos: echonestStation.maxTempo
onValueChanged: echonestStation.setTempo( lowerSliderPos, upperSliderPos )
}
Text {
id: hotnessText
text: "Hotness:"
color: "white"
}
DoubleSlider {
width: 500
height: hotnessText.height
min: 0
max: 100
minLabel: "Less"
maxLabel: "More"
showFloatingLabel: false
lowerSliderPos: echonestStation.minHotttness * 100
upperSliderPos: echonestStation.maxHotttness * 100
onValueChanged: echonestStation.setHotttness( 1.0 * lowerSliderPos / 100, 1.0 * upperSliderPos / 100 )
}
}
Button {
id: configureButton
onClicked: fineTuneView.done();
text: "configure"
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
anchors.horizontalCenter: parent.horizontalCenter
}
}

158
data/qml/StationScene.qml Normal file
View File

@@ -0,0 +1,158 @@
import QtQuick 1.1
import tomahawk 1.0
import "tomahawkimports"
Rectangle {
id: scene
color: "black"
anchors.fill: parent
state: echonestStation.configured ? "list" : "configure"
ListModel {
id: styleModel
ListElement { modelData: "acoustic" }
ListElement { modelData: "alternative" }
ListElement { modelData: "alternative rock" }
ListElement { modelData: "classic" }
ListElement { modelData: "folk" }
ListElement { modelData: "indie" }
ListElement { modelData: "pop" }
ListElement { modelData: "rock" }
ListElement { modelData: "hip-hop" }
ListElement { modelData: "punk" }
ListElement { modelData: "grunge" }
ListElement { modelData: "indie" }
ListElement { modelData: "electronic" }
ListElement { modelData: "country" }
ListElement { modelData: "jazz" }
ListElement { modelData: "psychodelic" }
ListElement { modelData: "soundtrack" }
ListElement { modelData: "reggae" }
ListElement { modelData: "house" }
ListElement { modelData: "drum and base" }
}
ListModel {
id: dummyArtistModel
ListElement { modelData: "Pink Floyd" }
ListElement { modelData: "Tool" }
ListElement { modelData: "Cake" }
ListElement { modelData: "Metallica" }
ListElement { modelData: "Red Hot Chili Peppers" }
ListElement { modelData: "Korn" }
ListElement { modelData: "Prodigy" }
ListElement { modelData: "Otto Waalkes" }
}
VisualItemModel {
id: stationVisualModel
Column {
height: scene.height
width: scene.width
Row {
height: scene.height / 2
width: scene.width
spacing: width * .1
Item {
height: parent.height
width: (parent.width - orText.width - parent.spacing * 2 ) * 2 / 3
GridView {
id: gridView
anchors.fill: parent
anchors.margins: cellWidth / 2
model: dummyArtistModel
cellWidth: gridView.width / 4 - 1 // -1 to make sure there is space for 4 items even with rounding error
cellHeight: cellWidth
delegate: Item {
height: gridView.cellHeight * .9
width: height
CoverImage {
artistName: modelData
anchors.fill: parent
onClicked: {
echonestStation.setMainControl( EchonestStation.StationTypeArtist, modelData );
stationListView.incrementCurrentIndex();
}
}
}
}
}
}
Row {
height: scene.height / 2
width: scene.width * .9
anchors.horizontalCenter: parent.horizontalCenter
spacing: width * .1
TagCloud {
height: parent.height
width: (parent.width - orText.width - parent.spacing * 2 ) * 2 / 3
model: styleModel//generator.styles()
opacity: echonestStation.configured ? 0 : 1
onTagClicked: {
echonestStation.setMainControl( EchonestStation.StationTypeStyle, item );
stationListView.incrementCurrentIndex();
}
Behavior on opacity {
NumberAnimation { duration: 300 }
}
}
Text {
id: orText
text: "or"
color: "white"
anchors.verticalCenter: parent.verticalCenter
}
InputField {
anchors.verticalCenter: parent.verticalCenter
width: (parent.width - orText.width - parent.spacing * 2 ) * 1 / 3
}
}
}
StationView {
coverSize: Math.min(scene.height, scene.width) / 2
height: scene.height
width: scene.width
onConfigure: stationListView.incrementCurrentIndex();
}
StationConfig {
height: scene.height
width: scene.width
onDone: stationListView.decrementCurrentIndex();
}
}
ListView {
id: stationListView
anchors.fill: parent
contentHeight: scene.height
contentWidth: scene.width
orientation: ListView.Horizontal
model: stationVisualModel
interactive: false
highlightMoveDuration: 400
Component.onCompleted: {
if ( echonestStation.configured ) {
currentIndex = 1
}
}
}
}

188
data/qml/StationView.qml Normal file
View File

@@ -0,0 +1,188 @@
import QtQuick 1.1
import tomahawk 1.0
import "tomahawkimports"
Item {
id: root
property int coverSize
signal configure()
PathView {
id: coverView
anchors.fill: parent
anchors.rightMargin: parent.width / 3
preferredHighlightBegin: 0.2 // scene.width / 11000
preferredHighlightEnd: preferredHighlightBegin
pathItemCount: 5
//highlightMoveDuration: 500
model: dynamicModel
currentIndex: currentlyPlayedIndex
property int pathStartX: width / 2
property int pathStartY: height / 2
delegate: CoverImage {
height: root.coverSize
width: root.coverSize
showLabels: false
showMirror: true
//artistName: model.artistName
//trackName: model.trackName
artworkId: model.coverID
scale: PathView.itemScale
itemBrightness: PathView.itemBrightness
opacity: PathView.itemOpacity
z: x
onClicked: {
if ( currentlyPlayedIndex !==-1 ) {
echonestStation.playItem( index )
}
}
}
path: Path {
startX: coverView.pathStartX
startY: coverView.pathStartY
PathAttribute { name: "itemOpacity"; value: 0 }
PathAttribute { name: "itemBrightness"; value: 0 }
PathAttribute { name: "itemScale"; value: 1.5 }
PathLine { x: coverView.pathStartX * 0.9 ; y: coverView.pathStartY * 0.9 }
PathPercent { value: .2 }
PathAttribute { name: "itemOpacity"; value: 1 }
PathAttribute { name: "itemBrightness"; value: 1 }
PathAttribute { name: "itemScale"; value: 1 }
PathLine { x: coverView.pathStartX * .5; y: coverView.pathStartY * .5}
PathPercent { value: .3 }
PathAttribute { name: "itemOpacity"; value: 1 }
PathAttribute { name: "itemBrightness"; value: 1 }
PathAttribute { name: "itemScale"; value: 0.5 }
// PathLine { x: coverView.pathStartX * .25 ; y: coverView.pathStartY * .25 }
// PathPercent { value: .75 }
// PathAttribute { name: "itemOpacity"; value: 1 }
// PathAttribute { name: "itemBrightness"; value: .5 }
// PathAttribute { name: "itemScale"; value: 0.4 }
PathLine { x: 0; y: 0 }
PathPercent { value: 1 }
PathAttribute { name: "itemOpacity"; value: 1 }
PathAttribute { name: "itemBrightness"; value: 0 }
PathAttribute { name: "itemScale"; value: 0.1 }
}
}
Item {
anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
anchors.margins: 50
width: scene.width / 3
Column {
anchors { left: parent.left; top: parent.top; right: parent.right }
Text {
color: "white"
font.pointSize: 12
width: parent.width
elide: Text.ElideRight
text: "Station:"
}
Text {
color: "white"
font.pointSize: 14
font.bold: true
width: parent.width
elide: Text.ElideRight
text: echonestStation.name
}
}
Column {
anchors.right: parent.right
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: scene.width / 3
Text {
color: "white"
font.pointSize: 12
width: parent.width
elide: Text.ElideRight
text: "Now Playing:"
visible: currentlyPlayedIndex !== -1
}
Rectangle {
height: image.height + image.height / 5
width: image.width + startPlayingText.width * 1.2
radius: height / 2
border.width: 2
border.color: "white"
color: startPlayingMouseArea.containsMouse ? "blue" : "gray"
visible: currentlyPlayedIndex === -1
Image {
id: image
source: "../images/play-rest.png"
anchors.left: parent.left
anchors.margins: 10
anchors.verticalCenter: parent.verticalCenter
}
Text {
id: startPlayingText
color: "white"
font.pointSize: 20
anchors.left: image.right
anchors.margins: height / 5
anchors.verticalCenter: parent.verticalCenter
//width: parent.width - 30 - image.width
elide: Text.ElideRight
text: "Start playing"
}
MouseArea {
id: startPlayingMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: echonestStation.playItem( 0 );
}
}
Text {
color: "white"
font.pointSize: 16
width: parent.width
elide: Text.ElideRight
text: currentlyPlayedIndex > -1 ? coverView.model.itemFromIndex( currentlyPlayedIndex ).name : ""
}
Text {
color: "white"
font.pointSize: 14
width: parent.width
elide: Text.ElideRight
text: currentlyPlayedIndex > -1 ? coverView.model.itemFromIndex( currentlyPlayedIndex ).artistName : ""
}
Text {
color: "white"
font.pointSize: 14
width: parent.width
elide: Text.ElideRight
text: currentlyPlayedIndex > -1 ? coverView.model.itemFromIndex( currentlyPlayedIndex ).albumName : ""
}
}
}
Button {
id: configureButton
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
anchors.horizontalCenter: parent.horizontalCenter
text: "configure"
onClicked: root.configure();
}
}

53
data/qml/TagCloud.qml Normal file
View File

@@ -0,0 +1,53 @@
import QtQuick 1.1
import tomahawk 1.0
Item {
id: tagCloud
property variant model: 10
signal tagClicked( string item )
function randomNumber(min, max) {
var date = new Date();
return (max - min) * Math.random(date.getSeconds()) + min
}
Flow {
anchors.centerIn: parent
width: parent.width
spacing: 3
Repeater {
id: cloudRepeater
model: tagCloud.model
delegate: Item {
id: cloudItem
width: delegateText.width * 1.1
height: delegateText.height
property double itemScale: Math.random() + .3
scale: itemScale
Text {
id: delegateText
color: "white"
//text: controlModel.controlAt( index ).summary
text: modelData
font.pointSize: 16
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: tagCloud.randomNumber(0, 15)
}
MouseArea {
hoverEnabled: true
anchors.fill: parent
onClicked: tagCloud.tagClicked( modelData )
}
Behavior on scale {
NumberAnimation { easing: Easing.Linear; duration: 1000 }
}
}
}
}
}

View File

@@ -0,0 +1,29 @@
import QtQuick 1.1
Rectangle {
id: root
color: buttonMouseArea.containsMouse ? "blue" : "gray"
border.width: 2
border.color: "white"
radius: height/2
height: buttonText.height * 1.2
width: buttonText.width * 1.5
property alias text: buttonText.text
property color textColor: "white"
signal clicked()
Text {
id: buttonText
anchors.centerIn: parent
color: root.textColor
}
MouseArea {
id: buttonMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: root.clicked();
}
}

View File

@@ -0,0 +1,151 @@
import QtQuick 1.1
Item {
id: root
width: 500
height: 10
property int min: 0
property int max: 100
/** The labels next to the slider
* if empty, min and max values are used
*/
property string minLabel: ""
property string maxLabel: ""
/** Should the floating label indicating the current position be shown? */
property bool showFloatingLabel: true
property int lowerSliderPos: 25
property int upperSliderPos: 75
signal valueChanged()
Row {
anchors.fill: parent
spacing: 10
Text {
id: minText
text: root.minLabel.length > 0 ? root.minLabel : min
color: "white"
}
Item {
id: sliderRect
height: root.height
width: parent.width - minText.width - maxText.width - parent.spacing * 2
function sliderPosToValue( sliderPos ) {
var percent = sliderPos * 100 / (sliderRect.width - lowerSlider.width);
return Math.floor(percent * (root.max - root.min) / 100) + root.min
}
function valueToSloderPos( value ) {
var percent = (value - root.min) * 100 / (root.max - root.min)
return percent * (sliderRect.width - lowerSlider.width) / 100
}
Rectangle {
id: sliderBase
height: root.height / 5
width: parent.width
color: "white"
radius: height / 2
anchors.centerIn: parent
}
Rectangle {
id: lowerSlider
height: root.height
width: height
anchors.top: root.top
radius: height/2
border.color: "black"
border.width: 2
x: sliderRect.valueToSloderPos(root.lowerSliderPos)
Rectangle {
id: lowerFloatingRect
color: "white"
anchors.bottom: lowerSlider.top
anchors.bottomMargin: 10
visible: root.showFloatingLabel && lowerSliderMouseArea.pressed
width: lowerFloatingText.width * 1.2
height: lowerFloatingText.height + height * 1.2
x: -(width - lowerSlider.width) / 2
radius: height / 4
Text {
id: lowerFloatingText
anchors.centerIn: parent
text: sliderRect.sliderPosToValue(lowerSlider.x)
}
}
}
MouseArea {
id: lowerSliderMouseArea
anchors.fill: lowerSlider
drag.target: lowerSlider
drag.axis: "XAxis"
drag.minimumX: 0
drag.maximumX: upperSlider.x - lowerSlider.width
onReleased: {
root.lowerSliderPos = sliderRect.sliderPosToValue( lowerSlider.x );
root.valueChanged();
}
}
Rectangle {
id: upperSlider
height: root.height
width: height
anchors.top: root.top
radius: height/2
border.color: "black"
border.width: 2
x: sliderRect.valueToSloderPos(root.upperSliderPos)
Rectangle {
id: upperFloatingRect
color: "white"
anchors.bottom: upperSlider.top
anchors.bottomMargin: 10
visible: root.showFloatingLabel && upperSliderMouseArea.pressed
width: upperFloatingText.width * 1.2
height: upperFloatingText.height + height * 1.2
radius: height / 4
x: -(width - upperSlider.width) / 2
Text {
id: upperFloatingText
anchors.centerIn: parent
text: sliderRect.sliderPosToValue(upperSlider.x)
}
}
}
MouseArea {
id: upperSliderMouseArea
anchors.fill: upperSlider
onClicked: print("button pressed")
drag.target: upperSlider
drag.axis: "XAxis"
drag.minimumX: lowerSlider.x + lowerSlider.width
drag.maximumX: parent.width - upperSlider.width
onReleased: {
root.upperSliderPos = sliderRect.sliderPosToValue( upperSlider.x );
root.valueChanged();
}
}
}
Text {
id: maxText
text: root.maxLabel.length > 0 ? root.maxLabel : max
color: "white"
}
}
}

View File

@@ -0,0 +1,23 @@
import QtQuick 1.1
Rectangle {
id: root
color: "white"
border.color: "black"
border.width: 2
height: textInput.height + 4
width: 300
property alias text: textInput.text
signal accepted( string text )
TextInput {
id: textInput
width: parent.width
anchors.centerIn: parent
onAccepted: root.accepted( text );
}
}

View File

@@ -10,7 +10,7 @@ QRadioButton {
padding:0;
background-repeat: none;
/*width:0; height:0;*/
}
}
QRadioButton::indicator {
width: 29px;
@@ -18,15 +18,15 @@ QRadioButton::indicator {
}
QRadioButton::indicator::unchecked {
background-image: url(:/data/images/view-toggle-inactive-right.png);
background-image: url(:/data/images/view-toggle-inactive-centre.png);
image: url(:/data/images/view-toggle-icon-list-inactive.png);
}
QRadioButton::indicator::checked {
background-image: url(:/data/images/view-toggle-active-right.png);
background-image: url(:/data/images/view-toggle-active-centre.png);
image: url(:/data/images/view-toggle-icon-list-active.png);
}
QRadioButton::indicator::pressed {
background-image: url(:/data/images/view-toggle-pressed-right.png);
background-image: url(:/data/images/view-toggle-pressed-centre.png);
image: url(:/data/images/view-toggle-icon-list-active.png);
}
QRadioButton#radioNormal::indicator::unchecked {
@@ -43,13 +43,13 @@ QRadioButton#radioNormal::indicator::pressed {
}
QRadioButton#radioCloud::indicator::unchecked {
background-image: url(:/data/images/view-toggle-inactive-right.png);
image: url(:/data/images/view-toggle-icon-cloud-inactive.png);
image: url(:/data/images/view-toggle-icon-grid-inactive.png);
}
QRadioButton#radioCloud::indicator::checked {
background-image: url(:/data/images/view-toggle-active-right.png);
image: url(:/data/images/view-toggle-icon-cloud-active.png);
image: url(:/data/images/view-toggle-icon-grid-active.png);
}
QRadioButton#radioCloud::indicator::pressed {
background-image: url(:/data/images/view-toggle-pressed-right.png);
image: url(:/data/images/view-toggle-icon-cloud-active.png);
image: url(:/data/images/view-toggle-icon-grid-active.png);
}

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

4096
lang/tomahawk_lt.ts Normal file

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

@@ -45,6 +45,8 @@
<file>data/images/view-toggle-icon-artist-inactive.png</file>
<file>data/images/view-toggle-icon-cloud-active.png</file>
<file>data/images/view-toggle-icon-cloud-inactive.png</file>
<file>data/images/view-toggle-icon-grid-active.png</file>
<file>data/images/view-toggle-icon-grid-inactive.png</file>
<file>data/images/view-toggle-icon-list-active.png</file>
<file>data/images/view-toggle-icon-list-inactive.png</file>
<file>data/images/view-toggle-inactive-centre.png</file>
@@ -146,5 +148,16 @@
<file>data/images/jump-link.png</file>
<file>data/images/scrollbar-vertical-handle.png</file>
<file>data/images/scrollbar-horizontal-handle.png</file>
<file>data/images/subscribe-on.png</file>
<file>data/images/subscribe-off.png</file>
<file>data/qml/ArtistInfoScene.qml</file>
<file>data/qml/StationScene.qml</file>
<file>data/qml/CoverImage.qml</file>
<file>data/qml/TagCloud.qml</file>
<file>data/qml/StationConfig.qml</file>
<file>data/qml/StationView.qml</file>
<file>data/qml/tomahawkimports/InputField.qml</file>
<file>data/qml/tomahawkimports/Button.qml</file>
<file>data/qml/tomahawkimports/DoubleSlider.qml</file>
</qresource>
</RCC>

273
src/AclRegistryImpl.cpp Normal file
View File

@@ -0,0 +1,273 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.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 "AclRegistryImpl.h"
#include <QThread>
#include <QVariant>
#include "TomahawkSettings.h"
#include "TomahawkApp.h"
#include "Source.h"
#ifndef ENABLE_HEADLESS
#include "accounts/AccountManager.h"
#include "accounts/Account.h"
#include "jobview/AclJobItem.h"
#include "jobview/JobStatusView.h"
#include "jobview/JobStatusModel.h"
#endif
#include "utils/Logger.h"
ACLRegistryImpl::ACLRegistryImpl( QObject* parent )
: ACLRegistry( parent )
, m_jobCount( 0 )
{
ACLRegistry::setInstance( this );
load();
}
ACLRegistryImpl::~ACLRegistryImpl()
{
save();
}
ACLRegistry::ACL
ACLRegistryImpl::isAuthorizedUser( const QString& dbid, const QString &username, ACLRegistry::ACL globalType, bool skipEmission )
{
tLog() << Q_FUNC_INFO;
if ( QThread::currentThread() != TOMAHAWK_APPLICATION::instance()->thread() )
{
if ( !skipEmission )
QMetaObject::invokeMethod( this, "isAuthorizedUser", Qt::QueuedConnection, Q_ARG( const QString&, dbid ), Q_ARG( const QString &, username ), Q_ARG( ACLRegistry::ACL, globalType ), Q_ARG( bool, skipEmission ) );
return ACLRegistry::NotFound;
}
#ifndef ENABLE_HEADLESS
if ( Tomahawk::Accounts::AccountManager::instance() )
{
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Checking account friendly names against" << username;
Tomahawk::Accounts::AccountManager* accountManager = Tomahawk::Accounts::AccountManager::instance();
QList< Tomahawk::Accounts::Account* > accounts = accountManager->accounts();
foreach( Tomahawk::Accounts::Account* account, accounts )
{
if ( !( account->types() & Tomahawk::Accounts::SipType ) )
continue;
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Checking against account friendly name" << account->accountFriendlyName();
if ( account->accountFriendlyName() == username )
{
if ( !skipEmission )
emit aclResult( dbid, username, ACLRegistry::Stream );
return ACLRegistry::Stream;
}
}
}
#endif
bool found = false;
QMutableListIterator< ACLRegistry::User > i( m_cache );
while ( i.hasNext() )
{
ACLRegistry::User user = i.next();
foreach ( QString knowndbid, user.knownDbids )
{
if ( dbid == knowndbid )
{
if ( !user.knownAccountIds.contains( username ) )
user.knownAccountIds.append( username );
found = true;
}
}
foreach ( QString knownaccountid, user.knownAccountIds )
{
if ( username == knownaccountid )
{
if ( !user.knownDbids.contains( dbid ) )
user.knownDbids.append( dbid );
found = true;
}
}
if ( found )
{
if ( !skipEmission )
emit aclResult( dbid, username, user.acl );
i.setValue( user );
return user.acl;
}
}
if ( skipEmission )
return ACLRegistry::NotFound;
// User was not found, create a new user entry
ACLRegistry::User user;
user.knownDbids.append( dbid );
user.knownAccountIds.append( username );
if ( globalType != ACLRegistry::NotFound )
user.acl = globalType;
#ifdef ENABLE_HEADLESS
user.acl = ACLRegistry::Stream;
#else
if ( !TomahawkUtils::headless() )
{
getUserDecision( user, username );
return ACLRegistry::NotFound;
}
else
user.acl = ACLRegistry::Stream;
#endif
m_cache.append( user );
save();
emit aclResult( dbid, username, user.acl );
return user.acl;
}
#ifndef ENABLE_HEADLESS
void
ACLRegistryImpl::getUserDecision( ACLRegistry::User user, const QString &username )
{
if ( TomahawkUtils::headless() )
return;
tLog() << Q_FUNC_INFO;
ACLJobItem* job = new ACLJobItem( user, username );
m_jobQueue.enqueue( job );
QTimer::singleShot( 0, this, SLOT( queueNextJob() ) );
}
void
ACLRegistryImpl::userDecision( ACLRegistry::User user )
{
if ( TomahawkUtils::headless() )
return;
tLog() << Q_FUNC_INFO;
m_cache.append( user );
save();
emit aclResult( user.knownDbids.first(), user.knownAccountIds.first(), user.acl );
m_jobCount--;
if ( !m_jobQueue.isEmpty() )
QTimer::singleShot( 0, this, SLOT( queueNextJob() ) );
}
void
ACLRegistryImpl::queueNextJob()
{
if ( TomahawkUtils::headless() )
return;
if ( QThread::currentThread() != TOMAHAWK_APPLICATION::instance()->thread() )
{
QMetaObject::invokeMethod( this, "queueNextJob", Qt::QueuedConnection );
return;
}
tLog() << Q_FUNC_INFO << "jobCount =" << m_jobCount;
tLog() << Q_FUNC_INFO << "jobQueue size =" << m_jobQueue.length();
if ( m_jobCount != 0 )
return;
if ( !m_jobQueue.isEmpty() )
{
ACLJobItem* job = m_jobQueue.dequeue();
ACLRegistry::User user = job->user();
bool found = false;
foreach( QString dbid, user.knownDbids )
{
ACLRegistry::ACL acl = isAuthorizedUser( dbid, job->username(), ACLRegistry::NotFound, true );
if ( acl != ACLRegistry::NotFound )
{
tLog() << Q_FUNC_INFO << "Found existing acl entry for =" << user.knownAccountIds.first();
found = true;
break;
}
}
if ( found )
{
tLog() << Q_FUNC_INFO << "deleting job, already have ACL for" << user.knownAccountIds.first();
delete job;
QTimer::singleShot( 0, this, SLOT( queueNextJob() ) );
return;
}
else
{
tLog() << Q_FUNC_INFO << "activating job for user" << user.knownAccountIds.first();
m_jobCount++;
JobStatusView::instance()->model()->addJob( job );
connect( job, SIGNAL( userDecision( ACLRegistry::User ) ), this, SLOT( userDecision( ACLRegistry::User ) ) );
}
}
}
#endif
void
ACLRegistryImpl::wipeEntries()
{
ACLRegistry::wipeEntries();
save();
}
void
ACLRegistryImpl::load()
{
tLog() << Q_FUNC_INFO;
QVariantList entryList = TomahawkSettings::instance()->aclEntries();
foreach ( QVariant entry, entryList )
{
if ( !entry.isValid() || !entry.canConvert< ACLRegistry::User >() )
{
tLog() << Q_FUNC_INFO << "entry is invalid";
continue;
}
ACLRegistry::User entryUser = entry.value< ACLRegistry::User >();
if ( entryUser.knownAccountIds.empty() || entryUser.knownDbids.empty() )
{
tLog() << Q_FUNC_INFO << "user known account/dbids is empty";
continue;
}
m_cache.append( entryUser );
}
}
void
ACLRegistryImpl::save()
{
tLog() << Q_FUNC_INFO;
QVariantList entryList;
foreach ( ACLRegistry::User user, m_cache )
{
tLog() << Q_FUNC_INFO << "user is" << user.uuid << "with known name" << user.knownAccountIds.first();
QVariant val = QVariant::fromValue< ACLRegistry::User >( user );
if ( val.isValid() )
entryList.append( val );
}
TomahawkSettings::instance()->setAclEntries( entryList );
}

80
src/AclRegistryImpl.h Normal file
View File

@@ -0,0 +1,80 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.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 TOMAHAWK_ACLREGISTRYIMPL_H
#define TOMAHAWK_ACLREGISTRYIMPL_H
#include <QObject>
#include <QString>
#include <QHash>
#include <QTimer>
#include <QMutex>
#include <QVariant>
#include <QQueue>
#include <QStringList>
#include <QUuid>
#include "AclRegistry.h"
#include "HeadlessCheck.h"
#include "DllMacro.h"
class ACLJobItem;
class ACLRegistryImpl : public ACLRegistry
{
Q_OBJECT
public:
ACLRegistryImpl( QObject *parent = 0 );
virtual ~ACLRegistryImpl();
signals:
void aclResult( QString nodeid, QString username, ACLRegistry::ACL peerStatus );
public slots:
/**
* @brief Checks if peer is authorized; optionally, can authorize peer with given type if not found
*
* @param dbid DBID of peer
* @param globalType Global ACL to store if peer not found; if ACLRegistry::NotFound, does not store the peer Defaults to ACLRegistry::NotFound.
* @param username If not empty, will store the given username along with the new ACL value. Defaults to QString().
* @return ACLRegistry::ACL
**/
virtual ACLRegistry::ACL isAuthorizedUser( const QString &dbid, const QString &username, ACLRegistry::ACL globalType = ACLRegistry::NotFound, bool skipEmission = false );
virtual void wipeEntries();
protected:
virtual void load();
virtual void save();
#ifndef ENABLE_HEADLESS
void getUserDecision( ACLRegistry::User user, const QString &username );
private slots:
void userDecision( ACLRegistry::User user );
void queueNextJob();
#endif
private:
QQueue< ACLJobItem* > m_jobQueue;
int m_jobCount;
};
#endif // TOMAHAWK_ACLREGISTRYIMPL_H

View File

@@ -37,6 +37,8 @@
#include "ViewManager.h"
#include "Source.h"
const static int ALLOWED_MAX_DIVERSION = 300;
using namespace Tomahawk;
@@ -205,22 +207,20 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result )
ui->seekSlider->setValue( 0 );
ui->seekSlider->setEnabled( AudioEngine::instance()->canSeek() );
m_phononTickCheckTimer.stop();
m_sliderTimeLine.stop();
m_sliderTimeLine.setDuration( duration );
m_sliderTimeLine.setFrameRange( 0, duration );
m_sliderTimeLine.setCurveShape( QTimeLine::LinearCurve );
m_sliderTimeLine.setCurrentTime( 0 );
m_seekMsecs = -1;
m_seeked = false;
ui->seekSlider->setVisible( true );
int updateRate = (double)1000 / ( (double)ui->seekSlider->contentsRect().width() / (double)( duration / 1000 ) );
m_sliderTimeLine.setUpdateInterval( qBound( 40, updateRate, 500 ) );
m_noTimeChange = false;
m_lastSliderCheck = 0;
m_phononTickCheckTimer.start( 500 );
}
@@ -326,18 +326,15 @@ AudioControls::onPlaybackResumed()
{
tDebug( LOGEXTRA ) << Q_FUNC_INFO;
ui->stackedLayout->setCurrentWidget( ui->pauseButton );
m_sliderTimeLine.resume();
}
void
AudioControls::onPlaybackSeeked( qint64 msec )
{
tDebug( LOGEXTRA ) << Q_FUNC_INFO << " setting current timer to " << msec;
m_sliderTimeLine.setPaused( true );
m_sliderTimeLine.setCurrentTime( msec );
m_lastSliderCheck = msec;
m_seekMsecs = msec;
tDebug( LOGEXTRA ) << Q_FUNC_INFO;
m_seeked = true;
onPlaybackTimer( msec );
}
@@ -356,7 +353,8 @@ AudioControls::onPlaybackStopped()
ui->seekSlider->setVisible( false );
m_sliderTimeLine.stop();
m_sliderTimeLine.setCurrentTime( 0 );
m_phononTickCheckTimer.stop();
ui->stackedLayout->setCurrentWidget( ui->playPauseButton );
ui->loveButton->setEnabled( false );
ui->loveButton->setVisible( false );
@@ -368,65 +366,90 @@ AudioControls::onPlaybackStopped()
void
AudioControls::onPlaybackTimer( qint64 msElapsed )
{
//tDebug() << Q_FUNC_INFO;
m_phononTickCheckTimer.stop();
if ( m_currentTrack.isNull() )
{
m_sliderTimeLine.stop();
return;
}
const int seconds = msElapsed / 1000;
if ( seconds != m_lastTextSecondShown && !m_currentTrack.isNull() )
if ( seconds != m_lastTextSecondShown )
{
ui->timeLabel->setText( TomahawkUtils::timeToString( seconds ) );
ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( m_currentTrack->duration() - seconds ) );
m_lastTextSecondShown = seconds;
}
//tDebug( LOGEXTRA ) << Q_FUNC_INFO << "msElapsed =" << msElapsed << "and timer current time =" << m_sliderTimeLine.currentTime() << "and m_seekMsecs =" << m_seekMsecs;
if ( msElapsed > 0 && msElapsed != m_lastSliderCheck && m_seekMsecs == -1 && msElapsed - 500 < m_lastSliderCheck )
m_phononTickCheckTimer.start( 500 );
if ( msElapsed == 0 )
return;
m_lastSliderCheck = msElapsed;
if ( m_currentTrack.isNull() )
{
m_sliderTimeLine.stop();
return;
}
ui->seekSlider->blockSignals( true );
if ( sender() != &m_phononTickCheckTimer )
m_phononTickCheckTimer.start( 1000 );
int currentTime = m_sliderTimeLine.currentTime();
if ( m_noTimeChange )
//tDebug( LOGEXTRA ) << Q_FUNC_INFO << "msElapsed =" << msElapsed << "and timer current time =" << m_sliderTimeLine.currentTime();
// First condition checks for the common case where
// 1) the track has been started
// 2) we haven't seeked,
// 3) the timeline is pretty close to the actual time elapsed, within ALLOWED_MAX_DIVERSIONmsec, so no adustment needed, and
// 4) The audio engine is actually currently running
if ( msElapsed > 0
&& !m_seeked
&& qAbs( msElapsed - currentTime ) <= ALLOWED_MAX_DIVERSION
&& AudioEngine::instance()->state() == AudioEngine::Playing )
{
if ( currentTime != msElapsed )
if ( m_sliderTimeLine.state() != QTimeLine::Running )
m_sliderTimeLine.resume();
m_lastSliderCheck = msElapsed;
return;
}
else
{
//tDebug() << Q_FUNC_INFO << "Fallthrough";
// If we're in here we're offset, so we need to do some munging around
ui->seekSlider->blockSignals( true );
// First handle seeks
if ( m_seeked )
{
//tDebug() << Q_FUNC_INFO << "Seeked";
m_sliderTimeLine.setPaused( true );
m_noTimeChange = false;
m_sliderTimeLine.setCurrentTime( msElapsed );
m_seekMsecs = -1;
m_sliderTimeLine.resume();
m_seeked = false;
if ( AudioEngine::instance()->state() == AudioEngine::Playing )
m_sliderTimeLine.resume();
}
// Next handle falling behind by too much, or getting ahead by too much (greater than allowed amount, which would have been sorted above)
// However, a Phonon bug means that after a seek we'll actually have AudioEngine's state be Playing, when it ain't, so have to detect that
else if ( AudioEngine::instance()->state() == AudioEngine::Playing )
{
//tDebug() << Q_FUNC_INFO << "AudioEngine playing";
m_sliderTimeLine.setPaused( true );
m_sliderTimeLine.setCurrentTime( msElapsed );
if ( msElapsed != m_lastSliderCheck )
m_sliderTimeLine.resume();
}
// Finally, the case where the audioengine isn't playing; if the timeline is still running, pause it and catch up
else if ( AudioEngine::instance()->state() != AudioEngine::Playing )
{
//tDebug() << Q_FUNC_INFO << "AudioEngine not playing";
if ( msElapsed != currentTime || m_sliderTimeLine.state() == QTimeLine::Running)
{
m_sliderTimeLine.setPaused( true );
m_sliderTimeLine.setCurrentTime( msElapsed );
}
}
else
{
tDebug() << Q_FUNC_INFO << "What to do? How could we even get here?";
}
m_lastSliderCheck = msElapsed;
ui->seekSlider->blockSignals( false );
}
else if ( currentTime >= msElapsed || m_seekMsecs != -1 )
{
m_sliderTimeLine.setPaused( true );
m_noTimeChange = false;
if ( currentTime == msElapsed )
m_noTimeChange = true;
m_sliderTimeLine.setCurrentTime( msElapsed );
m_seekMsecs = -1;
if ( AudioEngine::instance()->state() != AudioEngine::Paused && sender() != &m_phononTickCheckTimer )
m_sliderTimeLine.resume();
}
else if ( m_sliderTimeLine.duration() > msElapsed && m_sliderTimeLine.state() == QTimeLine::NotRunning && AudioEngine::instance()->state() == AudioEngine::Playing )
{
m_sliderTimeLine.start();
}
else if ( m_sliderTimeLine.state() == QTimeLine::Paused && AudioEngine::instance()->state() != AudioEngine::Paused )
{
m_sliderTimeLine.resume();
}
ui->seekSlider->blockSignals( false );
}

View File

@@ -101,9 +101,8 @@ private:
QTimer m_phononTickCheckTimer;
QTimeLine m_sliderTimeLine;
qint64 m_seekMsecs;
bool m_seeked;
qint64 m_lastSliderCheck;
bool m_noTimeChange;
qint64 m_lastTextSecondShown;
QWidget* m_parent;

View File

@@ -37,9 +37,8 @@ ENDIF()
SET( tomahawkSources ${tomahawkSources}
web/Api_v1.cpp
MusicScanner.cpp
AclRegistryImpl.cpp
ShortcutHandler.cpp
ScanManager.cpp
UbuntuUnityHack.cpp
TomahawkApp.cpp
main.cpp
@@ -62,6 +61,7 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
sourcetree/items/PlaylistItems.cpp
sourcetree/items/CategoryItems.cpp
sourcetree/items/GenericPageItems.cpp
sourcetree/items/LovedTracksItem.cpp
sourcetree/items/TemporaryPageItem.cpp
sourcetree/items/GroupItem.cpp
sourcetree/items/HistoryItem.cpp
@@ -70,7 +70,6 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
AudioControls.cpp
SettingsDialog.cpp
DiagnosticsDialog.cpp
SettingsListDelegate.cpp
TomahawkWindow.cpp
LoadXSPFDialog.cpp
SocialWidget.cpp
@@ -113,8 +112,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}/..
)
@@ -200,7 +198,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

@@ -3,6 +3,7 @@
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
* Copyright 2012, Teo Mrnjavac <teo@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
@@ -28,20 +29,18 @@
#include <QtNetwork/QNetworkProxy>
#include <QtGui/QVBoxLayout>
#include <QtGui/QSizeGrip>
#include <QtGui/QToolBar>
#include "AtticaManager.h"
#include "AclRegistry.h"
#include "TomahawkApp.h"
#include "TomahawkSettings.h"
#include "accounts/DelegateConfigWrapper.h"
#include "MusicScanner.h"
#include "Pipeline.h"
#include "Resolver.h"
#include "ExternalResolverGui.h"
#include "utils/TomahawkUtilsGui.h"
#include "utils/GuiHelpers.h"
#include "ScanManager.h"
#include "SettingsListDelegate.h"
#include "accounts/AccountDelegate.h"
#include "database/Database.h"
#include "network/Servent.h"
@@ -74,11 +73,23 @@ SettingsDialog::SettingsDialog( QWidget *parent )
TomahawkSettings* s = TomahawkSettings::instance();
TomahawkUtils::unmarginLayout( layout() );
ui->stackedWidget->setContentsMargins( 4, 4, 4, 0 );
#ifdef Q_WS_X11
ui->stackedWidget->setContentsMargins( 4, 4, 4, 4 );
#else
ui->stackedWidget->setContentsMargins( 4, 4, 4, 0 );
#endif
ui->checkBoxReporter->setChecked( s->crashReporterEnabled() );
ui->checkBoxHttp->setChecked( s->httpEnabled() );
QFrame *sepLine = new QFrame( this );
sepLine->setFrameShape( QFrame::HLine );
sepLine->setFrameShadow( QFrame::Sunken );
ui->horizontalLayout->insertWidget( 0, sepLine );
m_toolBar = new QToolBar( tr( "Tomahawk Settings" ), this );
ui->horizontalLayout->insertWidget( 0, m_toolBar );
m_toolBar->setToolButtonStyle( Qt::ToolButtonTextUnderIcon );
//Network settings
TomahawkSettings::ExternalAddressMode mode = TomahawkSettings::instance()->externalAddressMode();
@@ -104,29 +115,16 @@ SettingsDialog::SettingsDialog( QWidget *parent )
createIcons();
#ifdef Q_WS_X11
ui->listWidget->setFrameShape( QFrame::StyledPanel );
ui->listWidget->setFrameShadow( QFrame::Sunken );
setContentsMargins( 4, 4, 4, 4 );
#else
setContentsMargins( 0, 4, 4, 4 );
#endif
#ifdef Q_WS_MAC
ui->listWidget->setFixedWidth( 83 );
#endif
#ifdef Q_WS_MAC
// Avoid resize handles on sheets on osx
m_proxySettings.setSizeGripEnabled( true );
QSizeGrip* p = m_proxySettings.findChild< QSizeGrip* >();
p->setFixedSize( 0, 0 );
ui->groupBoxNetworkAdvanced->layout()->removeItem( ui->verticalSpacer );
ui->groupBoxNetworkAdvanced->layout()->removeItem( ui->verticalSpacer_2 );
ui->groupBoxNetworkAdvanced->layout()->removeItem( ui->verticalSpacer_4 );
delete ui->verticalSpacer;
delete ui->verticalSpacer_2;
delete ui->verticalSpacer_4;
#endif
// Accounts
@@ -195,6 +193,13 @@ SettingsDialog::SettingsDialog( QWidget *parent )
{
ui->dirTree->checkPath( dir, Qt::Checked );
}
ui->advancedPage->setMinimumSize( ui->advancedPage->sizeHint() );
int buttonsWidth = qMax( ui->proxyButton->sizeHint().width(),
ui->aclEntryClearButton->sizeHint().width() );
ui->proxyButton->setFixedWidth( buttonsWidth );
ui->aclEntryClearButton->setFixedWidth( buttonsWidth );
// NOW PLAYING
// #ifdef Q_WS_MAC
@@ -212,9 +217,6 @@ SettingsDialog::SettingsDialog( QWidget *parent )
connect( ui->upnpRadioButton, SIGNAL( toggled(bool) ), SLOT( toggleRemoteMode() ) );
connect( ui->enableProxyCheckBox, SIGNAL( toggled(bool) ), SLOT( toggleProxyEnabled() ) );
connect( this, SIGNAL( rejected() ), SLOT( onRejected() ) );
ui->listWidget->setCurrentRow( 0 );
ui->listWidget->setItemDelegate(new SettingsListDelegate());
}
@@ -282,56 +284,67 @@ SettingsDialog::serventReady()
void
SettingsDialog::createIcons()
{
/// Not fun but QListWidget sucks. Do our max-width calculation manually
/// so the icons arre lined up.
// Resolvers is the longest string... in english. fml.
ensurePolished();
int maxlen = 0;
QFontMetrics fm( font() );
QListWidgetItem *accountsButton = new QListWidgetItem( ui->listWidget );
accountsButton->setIcon( QIcon( RESPATH "images/account-settings.png" ) );
accountsButton->setText( tr( "Services" ) );
accountsButton->setTextAlignment( Qt::AlignHCenter );
accountsButton->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
maxlen = fm.width( accountsButton->text() );
m_settingsGroup = new QActionGroup( m_toolBar );
QListWidgetItem *musicButton = new QListWidgetItem( ui->listWidget );
musicButton->setIcon( QIcon( RESPATH "images/music-settings.png" ) );
musicButton->setText( tr( "Collection" ) );
musicButton->setTextAlignment( Qt::AlignHCenter );
musicButton->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
maxlen = qMax( fm.width( musicButton->text() ), maxlen );
QWidget *leftSpacer = new QWidget( m_toolBar );
leftSpacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
m_toolBar->addWidget( leftSpacer );
QListWidgetItem *advancedButton = new QListWidgetItem( ui->listWidget );
advancedButton->setIcon( QIcon( RESPATH "images/advanced-settings.png" ) );
advancedButton->setText( tr( "Advanced" ) );
advancedButton->setTextAlignment( Qt::AlignHCenter );
advancedButton->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
maxlen = qMax( fm.width( advancedButton->text() ), maxlen );
QAction *accountsAction = new QAction( QIcon( RESPATH "images/account-settings.png" ),
tr( "Services" ),
m_toolBar );
accountsAction->setCheckable( true );
accountsAction->setToolTip( tr( "<b>Services</b><br>"
"Configure the accounts and services used by Tomahawk "
"to search and retrieve music, find your friends and "
"update your status." ) );
m_settingsGroup->addAction( accountsAction );
maxlen += 15; // padding
accountsButton->setSizeHint( QSize( maxlen, 60 ) );
musicButton->setSizeHint( QSize( maxlen, 60 ) );
advancedButton->setSizeHint( QSize( maxlen, 60 ) );
QAction *musicAction = new QAction( QIcon( RESPATH "images/music-settings.png" ),
tr( "Collection" ),
m_toolBar );
musicAction->setCheckable( true );
musicAction->setToolTip( tr( "<b>Collection</b><br>"
"Manage how Tomahawk finds music on your computer." ) );
m_settingsGroup->addAction( musicAction );
#ifndef Q_WS_MAC
// doesn't listen to sizehint...
ui->listWidget->setFixedWidth( maxlen + 8 );
#endif
connect( ui->listWidget, SIGNAL( currentItemChanged( QListWidgetItem*, QListWidgetItem* ) ), SLOT( changePage( QListWidgetItem*, QListWidgetItem* ) ) );
QAction *advancedAction = new QAction( QIcon( RESPATH "images/advanced-settings.png" ),
tr( "Advanced" ),
m_toolBar );
advancedAction->setCheckable( true );
advancedAction->setToolTip( tr( "<b>Advanced</b><br>"
"Configure Tomahawk's advanced settings, including "
"network connectivity settings, browser interaction "
"and more." ) );
m_settingsGroup->addAction( advancedAction );
m_settingsGroup->setExclusive( true );
m_toolBar->addActions( m_settingsGroup->actions() );
QWidget *rightSpacer = new QWidget( m_toolBar );
rightSpacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
m_toolBar->addWidget( rightSpacer );
connect( m_settingsGroup, SIGNAL( triggered( QAction * ) ),
this, SLOT( changePage( QAction * ) ) );
accountsAction->setChecked( true );
changePage( accountsAction );
}
void
SettingsDialog::changePage( QListWidgetItem* current, QListWidgetItem* previous )
SettingsDialog::changePage( QAction *action )
{
if ( !current )
current = previous;
ui->stackedWidget->setCurrentIndex( ui->listWidget->row(current) );
int index = m_settingsGroup->actions().indexOf( action );
if( ui->stackedWidget->currentIndex() != index )
{
ui->stackedWidget->setCurrentIndex( index );
}
}

View File

@@ -3,6 +3,7 @@
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
* Copyright 2012, Teo Mrnjavac <teo@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
@@ -23,6 +24,8 @@
#include <QtGui/QDialog>
#include <QtCore/QModelIndex>
#include <QtGui/QActionGroup>
#include <QtGui/QToolBar>
#include "config.h"
@@ -94,7 +97,7 @@ private slots:
void updateScanOptionsView();
void changePage( QListWidgetItem*, QListWidgetItem* );
void changePage( QAction *action );
void serventReady();
void aclEntryClearButtonClicked();
@@ -106,6 +109,9 @@ private:
Ui_StackedSettingsDialog* ui;
QToolBar *m_toolBar;
QActionGroup *m_settingsGroup;
ProxyDialog m_proxySettings;
bool m_rejected;
bool m_restartRequired;

View File

@@ -1,74 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011, Michael Zanetti <mzanetti@kde.org>
* Copyright 2011, 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 "SettingsListDelegate.h"
#include "utils/Logger.h"
#include <QPainter>
#include <QIcon>
#include <QApplication>
SettingsListDelegate::SettingsListDelegate(QObject *parent) :
QStyledItemDelegate(parent)
{
}
void SettingsListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
painter->save();
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, QModelIndex() );
qApp->style()->drawControl( QStyle::CE_ItemViewItem, &opt, painter );
#if defined(Q_WS_MAC) || defined(Q_WS_WIN)
// On mac draw our own selection rect as we don't get one from osx (around the whole icon or around just text)
if ( opt.state & QStyle::State_Selected )
{
painter->setRenderHint( QPainter::Antialiasing );
QPainterPath p;
p.addRoundedRect( opt.rect.adjusted( 2, 1, -1, -1 ), 5, 5 );
QColor fill( 214, 214, 214 );
QColor border( 107, 107, 107 );
painter->setPen( border );
painter->drawPath( p );
painter->fillPath( p, fill );
}
#else
if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected )
{
painter->setPen( option.palette.color( QPalette::HighlightedText ) );
}
#endif
int horizontalOffset = ( option.rect.width() - option.decorationSize.width() ) /2;
QRect iconRect = option.rect.adjusted( horizontalOffset, 6, -horizontalOffset, -option.rect.height() + 6 + option.decorationSize.height() );
QPixmap avatar = index.data( Qt::DecorationRole ).value<QIcon>().pixmap( iconRect.size() );
painter->drawPixmap( iconRect, avatar );
QRect textRect = option.rect.adjusted( 6, iconRect.height() + 8, -6, 0 );
QString text = painter->fontMetrics().elidedText( index.data( Qt::DisplayRole ).toString(), Qt::ElideRight, textRect.width() );
QTextOption to( Qt::AlignHCenter );
painter->drawText( textRect, text, to );
painter->restore();
}

View File

@@ -18,74 +18,11 @@
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListWidget" name="listWidget">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="autoScroll">
<bool>true</bool>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="movement">
<enum>QListView::Static</enum>
</property>
<property name="resizeMode">
<enum>QListView::Adjust</enum>
</property>
<property name="layoutMode">
<enum>QListView::Batched</enum>
</property>
<property name="spacing">
<number>1</number>
</property>
<property name="viewMode">
<enum>QListView::IconMode</enum>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>1</width>
<height>4</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<layout class="QVBoxLayout" name="horizontalLayout">
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>2</number>
<number>0</number>
</property>
<widget class="QWidget" name="accountsPage">
<layout class="QVBoxLayout" name="verticalLayout_11">
@@ -93,9 +30,12 @@
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Internet Services</string>
<widget class="QFrame" name="frame_4">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_8">
<property name="margin">
@@ -153,11 +93,17 @@
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Local Music Information</string>
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_17">
<property name="margin">
<number>2</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
@@ -234,17 +180,23 @@
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBoxNetworkAdvanced">
<widget class="QFrame" name="frameNetworkAdvanced">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Advanced Settings</string>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_13">
<property name="spacing">
<number>-1</number>
</property>
<property name="margin">
<number>2</number>
</property>
@@ -342,10 +294,13 @@
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<height>10</height>
</size>
</property>
</spacer>
@@ -363,8 +318,30 @@
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="proxyButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Proxy Settings...</string>
</property>
@@ -378,10 +355,13 @@
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<height>10</height>
</size>
</property>
</spacer>
@@ -395,7 +375,7 @@
<item>
<widget class="QCheckBox" name="checkBoxHttp">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Allow web browsers to interact with Tomahawk (recommended)</string>
@@ -408,7 +388,7 @@
<item>
<widget class="QCheckBox" name="checkBoxReporter">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Send reports after Tomahawk crashed</string>
@@ -425,6 +405,9 @@
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>

View File

@@ -31,8 +31,9 @@
#include <QtCore/QFileInfo>
#include <QTranslator>
#include "Artist.h"
#include "AclRegistryImpl.h"
#include "Album.h"
#include "Artist.h"
#include "Collection.h"
#include "infosystem/InfoSystem.h"
#include "accounts/AccountManager.h"
@@ -50,11 +51,10 @@
#include "web/Api_v1.h"
#include "SourceList.h"
#include "ShortcutHandler.h"
#include "ScanManager.h"
#include "libtomahawk/filemetadata/ScanManager.h"
#include "TomahawkSettings.h"
#include "GlobalActionManager.h"
#include "database/LocalCollection.h"
#include "MusicScanner.h"
#include "Pipeline.h"
#include "DropJob.h"
#include "EchonestCatalogSynchronizer.h"
@@ -205,6 +205,8 @@ TomahawkApp::init()
TomahawkSettings* s = TomahawkSettings::instance();
new ACLRegistryImpl( this );
tDebug( LOGINFO ) << "Setting NAM.";
// Cause the creation of the nam, but don't need to address it directly, so prevent warning
Q_UNUSED( TomahawkUtils::nam() );
@@ -319,7 +321,7 @@ TomahawkApp::init()
if ( arguments().contains( "--filescan" ) )
{
m_scanManager.data()->runScan( true );
m_scanManager.data()->runFullRescan();
}
// Set up echonest catalog synchronizer
@@ -360,47 +362,38 @@ 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";
delete dynamic_cast< ACLRegistryImpl* >( ACLRegistry::instance() );
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();
#ifndef ENABLE_HEADLESS
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.";
@@ -726,6 +719,27 @@ TomahawkApp::loadUrl( const QString& url )
}
bool
TomahawkApp::notify( QObject *receiver, QEvent *e )
{
try
{
return TOMAHAWK_APPLICATION::notify( receiver, e );
}
catch ( const std::exception& e )
{
qWarning( "TomahawkApp::notify caught a std exception in a Qt event handler: " );
qFatal( e.what() );
}
catch ( ... )
{
qFatal( "TomahawkApp::notify caught a non-std-exception from a Qt event handler. Aborting." );
}
return false;
}
void
TomahawkApp::instanceStarted( KDSingleApplicationGuard::Instance instance )
{

View File

@@ -98,7 +98,10 @@ public:
virtual bool loadUrl( const QString& url );
bool isTomahawkLoaded() const { return m_loaded; }
// reimplemented from QApplication/QCoreApplication
virtual bool notify( QObject* receiver, QEvent* e );
signals:
void tomahawkLoaded();

View File

@@ -67,12 +67,15 @@
#include "TomahawkSettings.h"
#include "SourceList.h"
#include "TomahawkTrayIcon.h"
#include "ScanManager.h"
#include "libtomahawk/filemetadata/ScanManager.h"
#include "TomahawkApp.h"
#include "LoadXSPFDialog.h"
#ifdef Q_WS_WIN
#include <qtsparkle/Updater>
#ifdef Q_OS_WIN
#include <qtsparkle/Updater>
#ifndef THBN_CLICKED
#define THBN_CLICKED 0x1800
#endif
#endif
#include "utils/Logger.h"
@@ -80,8 +83,13 @@
using namespace Tomahawk;
using namespace Accounts;
TomahawkWindow::TomahawkWindow( QWidget* parent )
: QMainWindow( parent )
#ifdef Q_OS_WIN
, m_buttonCreatedID( RegisterWindowMessage( L"TaskbarButtonCreated" ) )
, m_taskbarList(0)
#endif
, ui( new Ui::TomahawkWindow )
, m_searchWidget( 0 )
, m_audioControls( new AudioControls( this ) )
@@ -95,6 +103,9 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
connect( vm, SIGNAL( hideQueueRequested() ), SLOT( hideQueue() ) );
connect( APP, SIGNAL( tomahawkLoaded() ), vm, SLOT( setTomahawkLoaded() ) ); // Pass loaded signal into libtomahawk so components in there can connect to ViewManager
#ifdef Q_OS_WIN
connect( AudioEngine::instance(), SIGNAL( stateChanged( AudioState, AudioState) ), SLOT( audioStateChanged( AudioState, AudioState) ) );
#endif
ui->setupUi( this );
ui->menuApp->insertAction( ui->actionCreatePlaylist, ActionCollection::instance()->getAction( "togglePrivacy" ) );
@@ -191,11 +202,7 @@ TomahawkWindow::saveSettings()
void
TomahawkWindow::applyPlatformTweaks()
{
// HACK QtCurve causes an infinite loop on startup. This is because setStyle calls setPalette, which calls ensureBaseStyle,
// which loads QtCurve. QtCurve calls setPalette, which creates an infinite loop. The UI will look like CRAP with QtCurve, but
// the user is asking for it explicitly... so he's gonna be stuck with an ugly UI.
if ( !QString( qApp->style()->metaObject()->className() ).toLower().contains( "qtcurve" ) )
qApp->setStyle( new ProxyStyle() );
qApp->setStyle( new ProxyStyle() );
#ifdef Q_OS_MAC
setUnifiedTitleAndToolBarOnMac( true );
@@ -237,7 +244,7 @@ TomahawkWindow::setupToolBar()
m_searchWidget->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
m_searchWidget->setMaximumWidth( 340 );
connect( m_searchWidget, SIGNAL( returnPressed() ), this, SLOT( onFilterEdited() ) );
toolbar->addWidget( m_searchWidget );
}
@@ -258,7 +265,9 @@ TomahawkWindow::setupSideBar()
m_sourcetree = new SourceTreeView( this );
JobStatusView* jobsView = new JobStatusView( m_sidebar );
m_jobsModel = new JobStatusModel( jobsView );
JobStatusModel* sourceModel = new JobStatusModel( jobsView );
m_jobsModel = new JobStatusSortModel( jobsView );
m_jobsModel->setJobModel( sourceModel );
jobsView->setModel( m_jobsModel );
m_queueView = new QueueView( m_sidebar );
@@ -321,6 +330,71 @@ TomahawkWindow::setupUpdateCheck()
}
#ifdef Q_OS_WIN
bool
TomahawkWindow::setupWindowsButtons()
{
const GUID IID_ITaskbarList3 = { 0xea1afb91,0x9e28,0x4b86, { 0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf } };
HRESULT hr = S_OK;
QPixmap play( RESPATH "images/play-rest.png" );
QPixmap back( RESPATH "images/back-rest.png" );
QPixmap love( RESPATH "images/not-loved.png" );
QTransform transform;
transform.rotate( 180 );
QPixmap next( back.transformed( transform ) );
THUMBBUTTONMASK dwMask = THUMBBUTTONMASK( THB_ICON | THB_TOOLTIP | THB_FLAGS );
m_thumbButtons[TP_PREVIOUS].dwMask = dwMask;
m_thumbButtons[TP_PREVIOUS].iId = TP_PREVIOUS;
m_thumbButtons[TP_PREVIOUS].hIcon = back.toWinHICON();
m_thumbButtons[TP_PREVIOUS].dwFlags = THBF_ENABLED;
m_thumbButtons[TP_PREVIOUS].szTip[ tr( "Back" ).toWCharArray( m_thumbButtons[TP_PREVIOUS].szTip ) ] = 0;
m_thumbButtons[TP_PLAY_PAUSE].dwMask = dwMask;
m_thumbButtons[TP_PLAY_PAUSE].iId = TP_PLAY_PAUSE;
m_thumbButtons[TP_PLAY_PAUSE].hIcon = play.toWinHICON();
m_thumbButtons[TP_PLAY_PAUSE].dwFlags = THBF_ENABLED;
m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
m_thumbButtons[TP_NEXT].dwMask = dwMask;
m_thumbButtons[TP_NEXT].iId = TP_NEXT;
m_thumbButtons[TP_NEXT].hIcon = next.toWinHICON();
m_thumbButtons[TP_NEXT].dwFlags = THBF_ENABLED;
m_thumbButtons[TP_NEXT].szTip[ tr( "Next" ).toWCharArray( m_thumbButtons[TP_NEXT].szTip ) ] = 0;
m_thumbButtons[3].dwMask = dwMask;
m_thumbButtons[3].iId = -1;
m_thumbButtons[3].hIcon = 0;
m_thumbButtons[3].dwFlags = THBF_NOBACKGROUND | THBF_DISABLED;
m_thumbButtons[3].szTip[0] = 0;
m_thumbButtons[TP_LOVE].dwMask = dwMask;
m_thumbButtons[TP_LOVE].iId = TP_LOVE;
m_thumbButtons[TP_LOVE].hIcon = love.toWinHICON();
m_thumbButtons[TP_LOVE].dwFlags = THBF_DISABLED;
m_thumbButtons[TP_LOVE].szTip[ tr( "Love" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
if ( S_OK == CoCreateInstance( CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void **)&m_taskbarList ) )
{
hr = m_taskbarList->HrInit();
if ( SUCCEEDED( hr ) )
{
hr = m_taskbarList->ThumbBarAddButtons( winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
}
else
{
m_taskbarList->Release();
m_taskbarList = 0;
}
}
return SUCCEEDED( hr );
}
#endif
void
TomahawkWindow::setupSignals()
{
@@ -334,6 +408,7 @@ TomahawkWindow::setupSignals()
connect( AudioEngine::instance(), SIGNAL( error( AudioEngine::AudioErrorCode ) ), SLOT( onAudioEngineError( AudioEngine::AudioErrorCode ) ) );
connect( AudioEngine::instance(), SIGNAL( loading( const Tomahawk::result_ptr& ) ), SLOT( onPlaybackLoading( const Tomahawk::result_ptr& ) ) );
connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( audioStarted() ) );
connect( AudioEngine::instance(), SIGNAL( finished(Tomahawk::result_ptr) ), SLOT( audioFinished() ) );
connect( AudioEngine::instance(), SIGNAL( resumed()), SLOT( audioStarted() ) );
connect( AudioEngine::instance(), SIGNAL( paused() ), SLOT( audioPaused() ) );
connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( audioStopped() ) );
@@ -380,7 +455,7 @@ TomahawkWindow::setupSignals()
connect( account->sipPlugin(), SIGNAL( addMenu( QMenu* ) ), this, SLOT( pluginMenuAdded( QMenu* ) ) );
connect( account->sipPlugin(), SIGNAL( removeMenu( QMenu* ) ), this, SLOT( pluginMenuRemoved( QMenu* ) ) );
}
connect( ViewManager::instance(), SIGNAL( historyBackAvailable( bool ) ), SLOT( onHistoryBackAvailable( bool ) ) );
connect( ViewManager::instance(), SIGNAL( historyForwardAvailable( bool ) ), SLOT( onHistoryForwardAvailable( bool ) ) );
}
@@ -492,6 +567,123 @@ TomahawkWindow::keyPressEvent( QKeyEvent* e )
}
#ifdef Q_OS_WIN
bool
TomahawkWindow::winEvent( MSG* msg, long* result )
{
#define TB_PRESSED Q_FUNC_INFO << "Taskbar Button Pressed:"
switch( msg->message )
{
case WM_COMMAND:
if ( HIWORD( msg->wParam ) == THBN_CLICKED )
{
switch( TB_STATES(LOWORD( msg->wParam )) )
{
case TP_PREVIOUS:
tLog() << TB_PRESSED << "Previous";
AudioEngine::instance()->previous();
break;
case TP_PLAY_PAUSE:
tLog() << TB_PRESSED << "Play/Pause";
AudioEngine::instance()->playPause();
break;
case TP_NEXT:
tLog() << TB_PRESSED << "Next";
AudioEngine::instance()->next();
break;
case TP_LOVE:
tLog() << TB_PRESSED << "Love";
if ( !AudioEngine::instance()->currentTrack().isNull() )
{
AudioEngine::instance()->currentTrack()->toQuery()->setLoved( !AudioEngine::instance()->currentTrack()->toQuery()->loved() );
updateWindowsLoveButton();
}
break;
}
return true;
}
break;
}
if ( msg->message == m_buttonCreatedID )
return setupWindowsButtons();
return false;
}
void
TomahawkWindow::audioStateChanged( AudioState newState, AudioState oldState )
{
if ( m_taskbarList == 0 )
return;
switch ( newState )
{
case AudioEngine::Playing:
{
QPixmap pause( RESPATH "images/pause-rest.png" );
m_thumbButtons[TP_PLAY_PAUSE].hIcon = pause.toWinHICON();
m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Pause" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
updateWindowsLoveButton();
}
break;
case AudioEngine::Paused:
{
QPixmap play( RESPATH "images/play-rest.png" );
m_thumbButtons[TP_PLAY_PAUSE].hIcon = play.toWinHICON();
m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
}
break;
case AudioEngine::Stopped:
{
if ( !AudioEngine::instance()->currentTrack().isNull() )
{
disconnect(AudioEngine::instance()->currentTrack()->toQuery().data(),SIGNAL(socialActionsLoaded()),this,SLOT(updateWindowsLoveButton()));
}
QPixmap play( RESPATH "images/play-rest.png" );
m_thumbButtons[TP_PLAY_PAUSE].hIcon = play.toWinHICON();
m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
QPixmap not_loved( RESPATH "images/not-loved.png" );
m_thumbButtons[TP_LOVE].hIcon = not_loved.toWinHICON();
m_thumbButtons[TP_LOVE].dwFlags = THBF_DISABLED;
}
break;
default:
return;
}
m_taskbarList->ThumbBarUpdateButtons( winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
}
void
TomahawkWindow::updateWindowsLoveButton()
{
if ( !AudioEngine::instance()->currentTrack().isNull() && AudioEngine::instance()->currentTrack()->toQuery()->loved() )
{
QPixmap loved( RESPATH "images/loved.png" );
m_thumbButtons[TP_LOVE].hIcon = loved.toWinHICON();
m_thumbButtons[TP_LOVE].szTip[ tr( "Unlove" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
}
else
{
QPixmap not_loved( RESPATH "images/not-loved.png" );
m_thumbButtons[TP_LOVE].hIcon = not_loved.toWinHICON();
m_thumbButtons[TP_LOVE].szTip[ tr( "Love" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
}
m_thumbButtons[TP_LOVE].dwFlags = THBF_ENABLED;
m_taskbarList->ThumbBarUpdateButtons( winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
}
#endif
void
TomahawkWindow::onHistoryBackAvailable( bool avail )
{
@@ -514,7 +706,7 @@ TomahawkWindow::showSettingsDialog()
}
void
void
TomahawkWindow::showDiagnosticsDialog()
{
DiagnosticsDialog win;
@@ -533,7 +725,7 @@ void
TomahawkWindow::updateCollectionManually()
{
if ( TomahawkSettings::instance()->hasScannerPaths() )
ScanManager::instance()->runScan();
ScanManager::instance()->runNormalScan();
}
@@ -541,7 +733,7 @@ void
TomahawkWindow::rescanCollectionManually()
{
if ( TomahawkSettings::instance()->hasScannerPaths() )
ScanManager::instance()->runScan( true );
ScanManager::instance()->runFullRescan();
}
@@ -838,6 +1030,18 @@ TomahawkWindow::audioStarted()
ui->actionPlay->setText( tr( "Pause" ) );
ActionCollection::instance()->getAction( "stop" )->setEnabled( true );
#ifdef Q_OS_WIN
connect( AudioEngine::instance()->currentTrack()->toQuery().data(), SIGNAL( socialActionsLoaded() ), SLOT( updateWindowsLoveButton() ) );
#endif
}
void
TomahawkWindow::audioFinished()
{
#ifdef Q_OS_WIN
disconnect( AudioEngine::instance()->currentTrack()->toQuery().data(), SIGNAL( socialActionsLoaded() ), this, SLOT( updateWindowsLoveButton() ) );
#endif
}
@@ -853,7 +1057,7 @@ TomahawkWindow::audioStopped()
{
audioPaused();
ActionCollection::instance()->getAction( "stop" )->setEnabled( false );
m_currentTrack = result_ptr();
setWindowTitle( m_windowTitle );
}

View File

@@ -31,13 +31,19 @@
#include "audio/AudioEngine.h"
#include "utils/XspfLoader.h"
namespace Tomahawk {
namespace Accounts {
class Account;
}
#ifdef Q_OS_WIN
#include <shobjidl.h>
#endif
namespace Tomahawk
{
namespace Accounts
{
class Account;
}
}
class JobStatusModel;
class JobStatusSortModel;
class QSearchField;
class SourceTreeView;
class QAction;
@@ -75,6 +81,10 @@ protected:
void hideEvent( QHideEvent* e );
void keyPressEvent( QKeyEvent* e );
#ifdef Q_OS_WIN
bool winEvent( MSG* message, long* result );
#endif
public slots:
void createAutomaticPlaylist( QString );
void createStation();
@@ -85,8 +95,8 @@ public slots:
void legalInfo();
void updateCollectionManually();
void rescanCollectionManually();
void pluginMenuAdded(QMenu*);
void pluginMenuRemoved(QMenu*);
void pluginMenuAdded( QMenu* );
void pluginMenuRemoved( QMenu* );
void showOfflineSources();
void fullScreenEntered();
@@ -111,6 +121,7 @@ private slots:
void onPlaybackLoading( const Tomahawk::result_ptr& result );
void audioStarted();
void audioFinished();
void audioPaused();
void audioStopped();
@@ -132,6 +143,11 @@ private slots:
void crashNow();
#ifdef Q_OS_WIN
void audioStateChanged( AudioState newState, AudioState oldState );
void updateWindowsLoveButton();
#endif
private:
void loadSettings();
void saveSettings();
@@ -142,6 +158,14 @@ private:
void setupSideBar();
void setupUpdateCheck();
#ifdef Q_OS_WIN
bool setupWindowsButtons();
const unsigned int m_buttonCreatedID;
ITaskbarList3 *m_taskbarList;
THUMBBUTTON m_thumbButtons[5];
enum TB_STATES{ TP_PREVIOUS = 0,TP_PLAY_PAUSE = 1,TP_NEXT = 2,TP_LOVE = 4 };
#endif
Ui::TomahawkWindow* ui;
QSearchField* m_searchWidget;
AudioControls* m_audioControls;
@@ -151,7 +175,7 @@ private:
QPushButton* m_queueButton;
QueueView* m_queueView;
AnimatedSplitter* m_sidebar;
JobStatusModel* m_jobsModel;
JobStatusSortModel* m_jobsModel;
QAction* m_backAction;
QAction* m_forwardAction;

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

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

View File

@@ -42,7 +42,7 @@ NewReleasesPlugin::NewReleasesPlugin()
: InfoPlugin()
, m_nrFetchJobs ( 0 )
{
m_nrVersion = "0";
m_nrVersion = "0.1";
m_supportedGetTypes << InfoNewReleaseCapabilities << InfoNewRelease;
}
@@ -54,8 +54,10 @@ NewReleasesPlugin::~NewReleasesPlugin()
void
NewReleasesPlugin::init()
{
QVariantList source_qvarlist = TomahawkUtils::Cache::instance()->getData( "NewReleasesPlugin", "nr_sources" ).toList();
foreach( const QVariant & source, source_qvarlist ) {
foreach( const QVariant & source, source_qvarlist )
{
m_nrSources.append( source.toString() );
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "fetched source from cache" << source.toString();
@@ -79,21 +81,28 @@ void NewReleasesPlugin::getInfo ( InfoRequestData requestData )
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
bool foundSource = false;
switch ( requestData.type ) {
switch ( requestData.type )
{
case InfoNewRelease:
/// We need something to check if the request is actually ment to go to this plugin
if ( !hash.contains ( "nr_source" ) ) {
if ( !hash.contains ( "nr_source" ) )
{
tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "Hash did not contain required param!";
dataError ( requestData );
break;
} else {
foreach ( QString resource, m_nrSources ) {
if ( resource == hash["nr_source"] ) {
}
else
{
foreach ( QString resource, m_nrSources )
{
if ( resource == hash["nr_source"] )
{
foundSource = true;
}
}
if ( !foundSource ) {
if ( !foundSource )
{
dataError ( requestData );
break;
}
@@ -112,7 +121,8 @@ void NewReleasesPlugin::getInfo ( InfoRequestData requestData )
void NewReleasesPlugin::fetchNRFromCache ( InfoRequestData requestData )
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) {
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
dataError ( requestData );
return;
}
@@ -121,7 +131,8 @@ void NewReleasesPlugin::fetchNRFromCache ( InfoRequestData requestData )
Tomahawk::InfoSystem::InfoStringHash criteria;
/// Each request needs to contain both a id and source
if ( !hash.contains ( "nr_id" ) && !hash.contains ( "nr_source" ) ) {
if ( !hash.contains ( "nr_id" ) && !hash.contains ( "nr_source" ) )
{
tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "Hash did not contain required params!";
dataError ( requestData );
return;
@@ -136,7 +147,8 @@ void NewReleasesPlugin::fetchNRFromCache ( InfoRequestData requestData )
void NewReleasesPlugin::fetchNRCapabilitiesFromCache ( InfoRequestData requestData )
{
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) {
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
{
tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "Could not convert requestData to InfoStringHash!";
dataError ( requestData );
return;
@@ -150,15 +162,18 @@ void NewReleasesPlugin::fetchNRCapabilitiesFromCache ( InfoRequestData requestDa
void NewReleasesPlugin::notInCacheSlot ( InfoStringHash criteria, InfoRequestData requestData )
{
switch ( requestData.type ) {
case InfoNewRelease: {
switch ( requestData.type )
{
case InfoNewRelease:
{
tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "InfoNewRelease not in cache! Fetching...";
fetchNR ( requestData, criteria["nr_source"], criteria["nr_id"] );
return;
}
case InfoNewReleaseCapabilities: {
case InfoNewReleaseCapabilities:
{
tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChartCapabilities not in cache! Fetching...";
fetchNRSourcesList( false );
m_cachedRequests.append ( requestData );
@@ -166,7 +181,8 @@ void NewReleasesPlugin::notInCacheSlot ( InfoStringHash criteria, InfoRequestDat
return;
}
default: {
default:
{
tLog() << Q_FUNC_INFO << "Couldn't figure out what to do with this type of request after cache miss";
emit info ( requestData, QVariant() );
return;
@@ -191,19 +207,22 @@ void NewReleasesPlugin::nrSourcesList()
tDebug ( LOGVERBOSE ) << "Got newreleases sources list";
QNetworkReply* reply = qobject_cast<QNetworkReply*> ( sender() );
if ( reply->error() == QNetworkReply::NoError ) {
if ( reply->error() == QNetworkReply::NoError )
{
QJson::Parser p;
bool ok;
const QVariantMap res = p.parse ( reply, &ok ).toMap();
const QVariantList sources = res.value ( "sources" ).toList();
if ( !ok ) {
if ( !ok )
{
tLog() << "Failed to parse sources" << p.errorString() << "On line" << p.errorLine();
return;
}
m_nrSources.clear();
foreach ( const QVariant &source, sources ) {
foreach ( const QVariant &source, sources )
{
m_nrSources << source.toString();
}
TomahawkUtils::Cache::instance()->putData( "NewReleasesPlugin", 172800000 /* 2 days */, "nr_sources", m_nrSources );
@@ -214,9 +233,11 @@ void NewReleasesPlugin::nrSourcesList()
void NewReleasesPlugin::fetchAllNRSources()
{
if ( !m_nrSources.isEmpty() && m_allNRsMap.isEmpty() ) {
if ( !m_nrSources.isEmpty() && m_allNRsMap.isEmpty() )
{
tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "InfoNewRelease fetching source data";
foreach ( QString source, m_nrSources ) {
foreach ( QString source, m_nrSources )
{
QUrl url = QUrl ( QString ( CHART_URL "newreleases/%1" ).arg ( source ) );
QNetworkReply* reply = TomahawkUtils::nam()->get ( QNetworkRequest ( url ) );
reply->setProperty ( "nr_source", source );
@@ -246,12 +267,14 @@ void NewReleasesPlugin::nrList()
tDebug ( LOGVERBOSE ) << "Got newreleases list result";
QNetworkReply* reply = qobject_cast<QNetworkReply*> ( sender() );
if ( reply->error() == QNetworkReply::NoError ) {
if ( reply->error() == QNetworkReply::NoError )
{
QJson::Parser p;
bool ok;
const QVariantMap res = p.parse ( reply, &ok ).toMap();
if ( !ok ) {
if ( !ok )
{
tLog() << "Failed to parse resources" << p.errorString() << "On line" << p.errorLine();
return;
@@ -267,31 +290,53 @@ void NewReleasesPlugin::nrList()
// Building:
// [Source] - New Release
QList< InfoStringHash > albumNRs;
foreach ( const QVariant &nrObj, res.values() ) {
if ( !nrObj.toMap().isEmpty() ) {
QHash< QString, QVariantMap > extraType;
foreach ( const QVariant &nrObj, res.values() )
{
if ( !nrObj.toMap().isEmpty() )
{
const QVariantMap nrMap = nrObj.toMap();
const QString type = nrMap.value ( "type" ).toString();
const QString extra = nrMap.value( "extra" ).toString();
InfoStringHash nr;
nr["id"] = nrMap.value ( "id" ).toString();
nr["label"] = nrMap.value ( "name" ).toString();
nr["date"] = nrMap.value ( "date" ).toString();
if ( type == "Album" ) {
if ( type == "Album" )
{
nr[ "type" ] = "album";
albumNRs.append ( nr );
} else {
if( !extra.isEmpty() )
{
qDebug() << "FOUND EXTRA!! " << extra;
QList< Tomahawk::InfoSystem::InfoStringHash > extraTypeData = extraType[ extra ][ type ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >();
extraTypeData.append( nr );
extraType[ extra ][ type ] = QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > >( extraTypeData );
}
else
albumNRs.append ( nr );
}
else
{
tLog() << "Unknown newrelease type " << type;
continue;
}
}
foreach( const QString& c, extraType.keys() )
{
newreleases[ c ] = extraType[ c ];
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "extraType has types:" << c;
}
}
if ( !albumNRs.isEmpty() )
newreleases.insert ( tr ( "Albums" ), QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > > ( albumNRs ) );
/// @note For displaying purposes, upper the first letter
/// @note Remeber to lower it when fetching this!
nrName = source;
@@ -306,8 +351,10 @@ void NewReleasesPlugin::nrList()
}
m_nrFetchJobs--;
if ( !m_cachedRequests.isEmpty() && m_nrFetchJobs == 0 ) {
foreach ( InfoRequestData request, m_cachedRequests ) {
if ( !m_cachedRequests.isEmpty() && m_nrFetchJobs == 0 )
{
foreach ( InfoRequestData request, m_cachedRequests )
{
emit info ( request, m_allNRsMap );
// update cache
Tomahawk::InfoSystem::InfoStringHash criteria;
@@ -325,12 +372,14 @@ void NewReleasesPlugin::nrReturned()
QNetworkReply* reply = qobject_cast<QNetworkReply*> ( sender() );
QVariantMap returnedData;
if ( reply->error() == QNetworkReply::NoError ) {
if ( reply->error() == QNetworkReply::NoError )
{
QJson::Parser p;
bool ok;
QVariantMap res = p.parse ( reply, &ok ).toMap();
if ( !ok ) {
if ( !ok )
{
tLog() << "Failed to parse json from chart lookup:" << p.errorString() << "On line" << p.errorLine();
return;
}
@@ -339,9 +388,11 @@ void NewReleasesPlugin::nrReturned()
QVariantList albumList = res.value ( "list" ).toList();
QList< Tomahawk::InfoSystem::InfoStringHash > newreleases;
foreach( const QVariant & albumObj, albumList ) {
foreach( const QVariant & albumObj, albumList )
{
QVariantMap albumMap = albumObj.toMap();
if(!albumMap.isEmpty()) {
if( !albumMap.isEmpty() )
{
const QString album = albumMap.value("album").toString();
const QString artist = albumMap.value("artist").toString();
const QString date = albumMap.value("date").toString();

View File

@@ -22,18 +22,6 @@
#include <QThread>
#include <QVariant>
#include "TomahawkSettings.h"
#include "TomahawkApp.h"
#include "Source.h"
#ifndef ENABLE_HEADLESS
#include "accounts/AccountManager.h"
#include "accounts/Account.h"
#include "jobview/AclJobItem.h"
#include "jobview/JobStatusView.h"
#include "jobview/JobStatusModel.h"
#endif
#include "utils/Logger.h"
@@ -89,21 +77,23 @@ ACLRegistry* ACLRegistry::s_instance = 0;
ACLRegistry*
ACLRegistry::instance()
{
if( !s_instance )
new ACLRegistry();
return s_instance;
}
void
ACLRegistry::setInstance( ACLRegistry* instance )
{
s_instance = instance;
}
ACLRegistry::ACLRegistry( QObject* parent )
: QObject( parent )
, m_jobCount( 0 )
{
s_instance = this;
qRegisterMetaType< ACLRegistry::ACL >( "ACLRegistry::ACL" );
qRegisterMetaType< ACLRegistry::User >( "ACLRegistry::User" );
qRegisterMetaTypeStreamOperators< ACLRegistry::User >( "ACLRegistry::User" );
load();
}
@@ -112,220 +102,15 @@ ACLRegistry::~ACLRegistry()
}
ACLRegistry::ACL
ACLRegistry::isAuthorizedUser( const QString& dbid, const QString &username, ACLRegistry::ACL globalType, bool skipEmission )
{
tLog() << Q_FUNC_INFO;
if ( QThread::currentThread() != TOMAHAWK_APPLICATION::instance()->thread() )
{
if ( !skipEmission )
QMetaObject::invokeMethod( this, "isAuthorizedUser", Qt::QueuedConnection, Q_ARG( const QString&, dbid ), Q_ARG( const QString &, username ), Q_ARG( ACLRegistry::ACL, globalType ), Q_ARG( bool, skipEmission ) );
return ACLRegistry::NotFound;
}
#ifndef ENABLE_HEADLESS
if ( Tomahawk::Accounts::AccountManager::instance() )
{
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Checking account friendly names against" << username;
Tomahawk::Accounts::AccountManager* accountManager = Tomahawk::Accounts::AccountManager::instance();
QList< Tomahawk::Accounts::Account* > accounts = accountManager->accounts();
foreach( Tomahawk::Accounts::Account* account, accounts )
{
if ( !( account->types() & Tomahawk::Accounts::SipType ) )
continue;
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Checking against account friendly name" << account->accountFriendlyName();
if ( account->accountFriendlyName() == username )
{
if ( !skipEmission )
emit aclResult( dbid, username, ACLRegistry::Stream );
return ACLRegistry::Stream;
}
}
}
#endif
bool found = false;
QMutableListIterator< ACLRegistry::User > i( m_cache );
while ( i.hasNext() )
{
ACLRegistry::User user = i.next();
foreach ( QString knowndbid, user.knownDbids )
{
if ( dbid == knowndbid )
{
if ( !user.knownAccountIds.contains( username ) )
user.knownAccountIds.append( username );
found = true;
}
}
foreach ( QString knownaccountid, user.knownAccountIds )
{
if ( username == knownaccountid )
{
if ( !user.knownDbids.contains( dbid ) )
user.knownDbids.append( dbid );
found = true;
}
}
if ( found )
{
if ( !skipEmission )
emit aclResult( dbid, username, user.acl );
i.setValue( user );
return user.acl;
}
}
if ( skipEmission )
return ACLRegistry::NotFound;
// User was not found, create a new user entry
ACLRegistry::User user;
user.knownDbids.append( dbid );
user.knownAccountIds.append( username );
if ( globalType != ACLRegistry::NotFound )
user.acl = globalType;
#ifdef ENABLE_HEADLESS
user.acl = ACLRegistry::Stream;
#else
if ( !TomahawkUtils::headless() )
{
getUserDecision( user, username );
return ACLRegistry::NotFound;
}
else
user.acl = ACLRegistry::Stream;
#endif
m_cache.append( user );
save();
emit aclResult( dbid, username, user.acl );
return user.acl;
}
#ifndef ENABLE_HEADLESS
void
ACLRegistry::getUserDecision( ACLRegistry::User user, const QString &username )
{
if ( TomahawkUtils::headless() )
return;
tLog() << Q_FUNC_INFO;
AclJobItem* job = new AclJobItem( user, username );
m_jobQueue.enqueue( job );
QTimer::singleShot( 0, this, SLOT( queueNextJob() ) );
}
void
ACLRegistry::userDecision( ACLRegistry::User user )
{
if ( TomahawkUtils::headless() )
return;
tLog() << Q_FUNC_INFO;
m_cache.append( user );
save();
emit aclResult( user.knownDbids.first(), user.knownAccountIds.first(), user.acl );
m_jobCount--;
if ( !m_jobQueue.isEmpty() )
QTimer::singleShot( 0, this, SLOT( queueNextJob() ) );
}
void
ACLRegistry::queueNextJob()
{
if ( TomahawkUtils::headless() )
return;
if ( QThread::currentThread() != TOMAHAWK_APPLICATION::instance()->thread() )
{
QMetaObject::invokeMethod( this, "queueNextJob", Qt::QueuedConnection );
return;
}
tLog() << Q_FUNC_INFO << "jobCount = " << m_jobCount;
tLog() << Q_FUNC_INFO << "jobQueue size = " << m_jobQueue.length();
if ( m_jobCount != 0 )
return;
if ( !m_jobQueue.isEmpty() )
{
AclJobItem* job = m_jobQueue.dequeue();
ACLRegistry::User user = job->user();
bool found = false;
foreach( QString dbid, user.knownDbids )
{
ACLRegistry::ACL acl = isAuthorizedUser( dbid, job->username(), ACLRegistry::NotFound, true );
if ( acl != ACLRegistry::NotFound )
{
tLog() << Q_FUNC_INFO << "Found existing acl entry for = " << user.knownAccountIds.first();
found = true;
break;
}
}
if ( found )
{
tLog() << Q_FUNC_INFO << "deleting job, already have ACL for " << user.knownAccountIds.first();
delete job;
QTimer::singleShot( 0, this, SLOT( queueNextJob() ) );
return;
}
else
{
tLog() << Q_FUNC_INFO << "activating job for user" << user.knownAccountIds.first();
m_jobCount++;
JobStatusView::instance()->model()->addJob( job );
connect( job, SIGNAL( userDecision( ACLRegistry::User ) ), this, SLOT( userDecision( ACLRegistry::User ) ) );
}
}
}
#endif
void
ACLRegistry::load()
{
tLog() << Q_FUNC_INFO;
QVariantList entryList = TomahawkSettings::instance()->aclEntries();
foreach ( QVariant entry, entryList )
{
if ( !entry.isValid() || !entry.canConvert< ACLRegistry::User >() )
{
tLog() << Q_FUNC_INFO << "entry is invalid";
continue;
}
tLog() << Q_FUNC_INFO << "loading entry";
ACLRegistry::User entryUser = entry.value< ACLRegistry::User >();
if ( entryUser.knownAccountIds.empty() || entryUser.knownDbids.empty() )
{
tLog() << Q_FUNC_INFO << "user known account/dbids is empty";
continue;
}
m_cache.append( entryUser );
}
}
void
ACLRegistry::save()
{
tLog() << Q_FUNC_INFO;
QVariantList entryList;
foreach ( ACLRegistry::User user, m_cache )
{
tLog() << Q_FUNC_INFO << "user is " << user.uuid << " with known name " << user.knownAccountIds.first();
QVariant val = QVariant::fromValue< ACLRegistry::User >( user );
if ( val.isValid() )
entryList.append( val );
}
TomahawkSettings::instance()->setAclEntries( entryList );
}
@@ -334,5 +119,5 @@ ACLRegistry::wipeEntries()
{
tLog() << Q_FUNC_INFO;
m_cache.clear();
save();
}

View File

@@ -35,8 +35,6 @@
#define ACLUSERVERSION 1
class AclJobItem;
class DLLEXPORT ACLRegistry : public QObject
{
Q_OBJECT
@@ -44,6 +42,7 @@ class DLLEXPORT ACLRegistry : public QObject
public:
static ACLRegistry* instance();
static void setInstance( ACLRegistry* instance );
enum ACL {
NotFound = 0,
@@ -88,7 +87,7 @@ public:
};
ACLRegistry( QObject *parent = 0 );
~ACLRegistry();
virtual ~ACLRegistry();
signals:
void aclResult( QString nodeid, QString username, ACLRegistry::ACL peerStatus );
@@ -102,33 +101,21 @@ public slots:
* @param username If not empty, will store the given username along with the new ACL value. Defaults to QString().
* @return ACLRegistry::ACL
**/
ACLRegistry::ACL isAuthorizedUser( const QString &dbid, const QString &username, ACLRegistry::ACL globalType = ACLRegistry::NotFound, bool skipEmission = false );
void wipeEntries();
#ifndef ENABLE_HEADLESS
void getUserDecision( ACLRegistry::User user, const QString &username );
private slots:
void userDecision( ACLRegistry::User user );
void queueNextJob();
#endif
virtual ACLRegistry::ACL isAuthorizedUser( const QString &dbid, const QString &username, ACLRegistry::ACL globalType = ACLRegistry::NotFound, bool skipEmission = false ) = 0;
virtual void wipeEntries();
private:
protected:
/**
* @brief Saves the cache.
*
* @return void
**/
void save();
void load();
virtual void save();
virtual void load();
QList< ACLRegistry::User > m_cache;
static ACLRegistry* s_instance;
QQueue< AclJobItem* > m_jobQueue;
int m_jobCount;
};
Q_DECLARE_METATYPE( ACLRegistry::ACL );

View File

@@ -23,21 +23,28 @@
#include "AlbumPlaylistInterface.h"
#include "database/Database.h"
#include "database/DatabaseImpl.h"
#include "database/IdThreadWorker.h"
#include "Query.h"
#include "Source.h"
#include "utils/Logger.h"
#include <QReadWriteLock>
using namespace Tomahawk;
QHash< QString, album_ptr > Album::s_albumsByName = QHash< QString, album_ptr >();
QHash< unsigned int, album_ptr > Album::s_albumsById = QHash< unsigned int, album_ptr >();
QHash< QString, album_ptr > Album::s_albumsByCoverId = QHash< QString, album_ptr >();
Album::~Album()
static QMutex s_mutex;
static QReadWriteLock s_idMutex;
inline QString
albumCacheKey( const Tomahawk::artist_ptr& artist, const QString& albumName )
{
m_ownRef.clear();
#ifndef ENABLE_HEADLESS
delete m_cover;
#endif
return QString( "%1\t\t%2" ).arg( artist->name() ).arg( albumName );
}
@@ -47,11 +54,23 @@ Album::get( const Tomahawk::artist_ptr& artist, const QString& name, bool autoCr
if ( !Database::instance() || !Database::instance()->impl() )
return album_ptr();
int albid = Database::instance()->impl()->albumId( artist->id(), name, autoCreate );
if ( albid < 1 && autoCreate )
return album_ptr();
QMutexLocker l( &s_mutex );
return Album::get( albid, name, artist );
const QString key = albumCacheKey( artist, name );
if ( s_albumsByName.contains( key ) )
{
return s_albumsByName[ key ];
}
// qDebug() << "LOOKING UP ALBUM:" << artist->name() << name;
album_ptr album = album_ptr( new Album( name, artist ) );
album->setWeakRef( album.toWeakRef() );
album->loadId( autoCreate );
s_albumsByCoverId[ album->coverId() ] = album;
s_albumsByName[ key ] = album;
return album;
}
@@ -59,26 +78,40 @@ album_ptr
Album::get( unsigned int id, const QString& name, const Tomahawk::artist_ptr& artist )
{
static QHash< unsigned int, album_ptr > s_albums;
static QMutex s_mutex;
QMutexLocker lock( &s_mutex );
if ( s_albums.contains( id ) )
if ( s_albumsById.contains( id ) )
{
return s_albums.value( id );
return s_albumsById.value( id );
}
album_ptr a = album_ptr( new Album( id, name, artist ), &QObject::deleteLater );
a->setWeakRef( a.toWeakRef() );
s_albumsByCoverId[ a->coverId() ] = a;
s_albumsByName[ albumCacheKey( artist, name ) ] = a;
if ( id > 0 )
s_albums.insert( id, a );
s_albumsById.insert( id, a );
return a;
}
album_ptr
Album::getByCoverId( const QString& uuid )
{
QMutexLocker lock( &s_mutex );
if ( s_albumsByCoverId.contains( uuid ) )
return s_albumsByCoverId.value( uuid );
return album_ptr();
}
Album::Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr& artist )
: QObject()
, m_waitingForId( false )
, m_id( id )
, m_name( name )
, m_artist( artist )
@@ -92,6 +125,37 @@ Album::Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr&
}
Album::Album( const QString& name, const Tomahawk::artist_ptr& artist )
: QObject()
, m_waitingForId( true )
, m_name( name )
, m_artist( artist )
, m_coverLoaded( false )
, m_coverLoading( false )
#ifndef ENABLE_HEADLESS
, m_cover( 0 )
#endif
{
m_sortname = DatabaseImpl::sortname( name );
}
Album::~Album()
{
QMutexLocker lock( &s_mutex );
s_albumsByName.remove( albumCacheKey( artist(), name() ) );
s_albumsByCoverId.remove( coverId() );
/* if ( id() > 0 )
s_albumsById.remove( id() );*/
m_ownRef.clear();
#ifndef ENABLE_HEADLESS
delete m_cover;
#endif
}
void
Album::onTracksLoaded( Tomahawk::ModelMode mode, const Tomahawk::collection_ptr& collection )
{
@@ -106,6 +170,50 @@ Album::artist() const
}
void
Album::loadId( bool autoCreate )
{
Q_ASSERT( m_waitingForId );
IdThreadWorker::getAlbumId( m_ownRef.toStrongRef(), autoCreate );
}
void
Album::setIdFuture( QFuture<unsigned int> future )
{
m_idFuture = future;
}
unsigned int
Album::id() const
{
s_idMutex.lockForRead();
const bool waiting = m_waitingForId;
unsigned int finalId = m_id;
s_idMutex.unlock();
if ( waiting )
{
finalId = m_idFuture.result();
s_idMutex.lockForWrite();
m_id = finalId;
m_waitingForId = false;
if ( m_id > 0 )
{
QMutexLocker lock( &s_mutex );
s_albumsById[ m_id ] = m_ownRef.toStrongRef();
}
s_idMutex.unlock();
}
return finalId;
}
#ifndef ENABLE_HEADLESS
QPixmap
Album::cover( const QSize& size, bool forceLoad ) const
@@ -120,7 +228,7 @@ Album::cover( const QSize& size, bool forceLoad ) const
trackInfo["album"] = name();
Tomahawk::InfoSystem::InfoRequestData requestData;
requestData.caller = infoid();
requestData.caller = uniqueId();
requestData.type = Tomahawk::InfoSystem::InfoAlbumCoverArt;
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo );
requestData.customData = QVariantMap();
@@ -168,7 +276,7 @@ Album::cover( const QSize& size, bool forceLoad ) const
void
Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData, const QVariant& output )
{
if ( requestData.caller != infoid() ||
if ( requestData.caller != uniqueId() ||
requestData.type != Tomahawk::InfoSystem::InfoAlbumCoverArt )
{
return;
@@ -187,7 +295,13 @@ Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData,
m_coverBuffer = ba;
}
m_coverLoaded = true;
{
QMutexLocker lock( &s_mutex );
m_coverLoaded = true;
s_albumsByCoverId.remove( coverId() );
m_coverId = uuid();
s_albumsByCoverId[ m_coverId ] = m_ownRef.toStrongRef();
}
emit coverChanged();
}
}
@@ -196,7 +310,7 @@ Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData,
void
Album::infoSystemFinished( const QString& target )
{
if ( target != infoid() )
if ( target != uniqueId() )
return;
disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
@@ -237,10 +351,20 @@ Album::tracks( ModelMode mode, const Tomahawk::collection_ptr& collection )
QString
Album::infoid() const
Album::uniqueId() const
{
if ( m_uuid.isEmpty() )
m_uuid = uuid();
return m_uuid;
}
}
QString
Album::coverId() const
{
if ( m_coverId.isEmpty() )
m_coverId = uuid();
return m_coverId;
}

View File

@@ -27,6 +27,7 @@
#ifndef ENABLE_HEADLESS
#include <QtGui/QPixmap>
#endif
#include <QFuture>
#include "Typedefs.h"
#include "PlaylistInterface.h"
@@ -34,6 +35,8 @@
#include "Collection.h"
#include "infosystem/InfoSystem.h"
class IdThreadWorker;
namespace Tomahawk
{
@@ -44,13 +47,17 @@ Q_OBJECT
public:
static album_ptr get( const Tomahawk::artist_ptr& artist, const QString& name, bool autoCreate = false );
static album_ptr get( unsigned int id, const QString& name, const Tomahawk::artist_ptr& artist );
static album_ptr getByCoverId( const QString& uuid );
explicit Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr& artist );
Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr& artist );
Album( const QString& name, const Tomahawk::artist_ptr& artist );
virtual ~Album();
unsigned int id() const { return m_id; }
unsigned int id() const;
QString name() const { return m_name; }
QString sortname() const { return m_sortname; }
QString uniqueId() const;
QString coverId() const;
artist_ptr artist() const;
#ifndef ENABLE_HEADLESS
@@ -64,6 +71,7 @@ public:
QWeakPointer< Tomahawk::Album > weakRef() { return m_ownRef; }
void setWeakRef( QWeakPointer< Tomahawk::Album > weakRef ) { m_ownRef = weakRef; }
void loadId( bool autoCreate );
signals:
void tracksAdded( const QList<Tomahawk::query_ptr>& tracks, Tomahawk::ModelMode mode, const Tomahawk::collection_ptr& collection );
void updated();
@@ -77,9 +85,11 @@ private slots:
private:
Q_DISABLE_COPY( Album )
QString infoid() const;
void setIdFuture( QFuture<unsigned int> future );
unsigned int m_id;
mutable bool m_waitingForId;
mutable QFuture<unsigned int> m_idFuture;
mutable unsigned int m_id;
QString m_name;
QString m_sortname;
@@ -89,6 +99,7 @@ private:
bool m_coverLoaded;
mutable bool m_coverLoading;
mutable QString m_uuid;
mutable QString m_coverId;
#ifndef ENABLE_HEADLESS
mutable QPixmap* m_cover;
@@ -98,6 +109,12 @@ private:
QHash< Tomahawk::ModelMode, QHash< Tomahawk::collection_ptr, Tomahawk::playlistinterface_ptr > > m_playlistInterface;
QWeakPointer< Tomahawk::Album > m_ownRef;
static QHash< QString, album_ptr > s_albumsByName;
static QHash< unsigned int, album_ptr > s_albumsById;
static QHash< QString, album_ptr > s_albumsByCoverId;
friend class ::IdThreadWorker;
};
} // ns

View File

@@ -92,6 +92,31 @@ AlbumPlaylistInterface::hasNextItem()
}
bool
AlbumPlaylistInterface::hasPreviousItem()
{
int p = m_currentTrack;
p--;
if ( p < 0 || p >= m_queries.count() )
return false;
return true;
}
bool
AlbumPlaylistInterface::setCurrentTrack( unsigned int albumpos )
{
albumpos--;
if ( albumpos >= m_queries.count() )
return false;
m_currentTrack = albumpos;
m_currentItem = m_queries.at( albumpos )->results().first();
return true;
}
QList< Tomahawk::query_ptr >
AlbumPlaylistInterface::tracks()
{
@@ -114,6 +139,10 @@ 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 )
{
@@ -178,9 +207,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 )
{

View File

@@ -43,11 +43,11 @@ public:
QList<Tomahawk::query_ptr> tracks();
virtual int trackCount() const { return m_queries.count(); }
virtual int unfilteredTrackCount() const { return m_queries.count(); }
virtual Tomahawk::result_ptr siblingItem( int itemsAway );
virtual bool hasNextItem();
virtual bool hasPreviousItem();
virtual Tomahawk::result_ptr currentItem() const;
virtual PlaylistModes::RepeatMode repeatMode() const { return PlaylistModes::NoRepeat; }
@@ -55,8 +55,7 @@ public:
virtual void setRepeatMode( PlaylistModes::RepeatMode ) {}
virtual void setShuffled( bool ) {}
virtual void setFilter( const QString& /*pattern*/ ) {}
virtual bool setCurrentTrack( unsigned int albumpos );
signals:
void tracksLoaded( Tomahawk::ModelMode mode, const Tomahawk::collection_ptr& collection );
@@ -64,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:
QList< Tomahawk::query_ptr > m_queries;

View File

@@ -25,61 +25,88 @@
#include "database/DatabaseImpl.h"
#include "database/DatabaseCommand_AllAlbums.h"
#include "database/DatabaseCommand_TrackStats.h"
#include "database/IdThreadWorker.h"
#include "Source.h"
#include "utils/Logger.h"
#include <QReadWriteLock>
#define ID_THREAD_DEBUG 0
using namespace Tomahawk;
QHash< QString, artist_ptr > Artist::s_artistsByName = QHash< QString, artist_ptr >();
QHash< unsigned int, artist_ptr > Artist::s_artistsById = QHash< unsigned int, artist_ptr >();
QHash< QString, artist_ptr > Artist::s_artistsByCoverId = QHash< QString, artist_ptr >();
Artist::~Artist()
{
m_ownRef.clear();
#ifndef ENABLE_HEADLESS
delete m_cover;
#endif
}
static QMutex s_mutex;
static QReadWriteLock s_idMutex;
artist_ptr
Artist::get( const QString& name, bool autoCreate )
{
if ( name.isEmpty() )
return artist_ptr();
QMutexLocker lock( &s_mutex );
if ( s_artistsByName.contains( name ) )
return s_artistsByName.value( name );
if ( !Database::instance() || !Database::instance()->impl() )
return artist_ptr();
int artid = Database::instance()->impl()->artistId( name, autoCreate );
if ( artid < 1 && autoCreate )
return artist_ptr();
#if ID_THREAD_DEBUG
qDebug() << "Creating artist:" << name;
#endif
artist_ptr artist = artist_ptr( new Artist( name ), &QObject::deleteLater );
artist->setWeakRef( artist.toWeakRef() );
artist->loadId( autoCreate );
return Artist::get( artid, name );
s_artistsByCoverId[ artist->coverId() ] = artist;
s_artistsByName[ name ] = artist;
return artist;
}
artist_ptr
Artist::get( unsigned int id, const QString& name )
{
static QHash< unsigned int, artist_ptr > s_artists;
static QMutex s_mutex;
QMutexLocker lock( &s_mutex );
if ( s_artists.contains( id ) )
if ( s_artistsById.contains( id ) )
{
return s_artists.value( id );
return s_artistsById.value( id );
}
artist_ptr a = artist_ptr( new Artist( id, name ), &QObject::deleteLater );
a->setWeakRef( a.toWeakRef() );
s_artistsByCoverId[ a->coverId() ] = a;
s_artistsByName[ name ] = a;
if ( id > 0 )
s_artists.insert( id, a );
s_artistsById.insert( id, a );
return a;
}
artist_ptr
Artist::getByCoverId( const QString& uuid )
{
QMutexLocker lock( &s_mutex );
if ( s_artistsByCoverId.contains( uuid ) )
return s_artistsByCoverId.value( uuid );
return artist_ptr();
}
Artist::Artist( unsigned int id, const QString& name )
: QObject()
, m_waitingForFuture( false )
, m_id( id )
, m_name( name )
, m_coverLoaded( false )
@@ -95,6 +122,40 @@ Artist::Artist( unsigned int id, const QString& name )
}
Artist::Artist( const QString& name )
: QObject()
, m_waitingForFuture( true )
, m_id( 0 )
, m_name( name )
, m_coverLoaded( false )
, m_coverLoading( false )
, m_simArtistsLoaded( false )
, m_biographyLoaded( false )
, m_infoJobs( 0 )
#ifndef ENABLE_HEADLESS
, m_cover( 0 )
#endif
{
m_sortname = DatabaseImpl::sortname( name, true );
}
Artist::~Artist()
{
QMutexLocker lock( &s_mutex );
s_artistsByName.remove( name() );
s_artistsByCoverId.remove( coverId() );
/* if ( id() > 0 )
s_artistsById.remove( id() );*/
m_ownRef.clear();
#ifndef ENABLE_HEADLESS
delete m_cover;
#endif
}
void
Artist::onTracksLoaded( Tomahawk::ModelMode mode, const Tomahawk::collection_ptr& collection )
{
@@ -129,7 +190,7 @@ Artist::albums( ModelMode mode, const Tomahawk::collection_ptr& collection ) con
artistInfo["artist"] = name();
Tomahawk::InfoSystem::InfoRequestData requestData;
requestData.caller = infoid();
requestData.caller = uniqueId();
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo );
requestData.type = Tomahawk::InfoSystem::InfoArtistReleases;
@@ -169,7 +230,7 @@ Artist::similarArtists() const
artistInfo["artist"] = name();
Tomahawk::InfoSystem::InfoRequestData requestData;
requestData.caller = infoid();
requestData.caller = uniqueId();
requestData.customData = QVariantMap();
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo );
@@ -192,13 +253,70 @@ Artist::similarArtists() const
}
void
Artist::loadId( bool autoCreate )
{
Q_ASSERT( m_waitingForFuture );
IdThreadWorker::getArtistId( m_ownRef.toStrongRef(), autoCreate );
}
void
Artist::setIdFuture( QFuture<unsigned int> future )
{
m_idFuture = future;
}
unsigned int
Artist::id() const
{
s_idMutex.lockForRead();
const bool waiting = m_waitingForFuture;
unsigned int finalid = m_id;
s_idMutex.unlock();
if ( waiting )
{
#if ID_THREAD_DEBUG
qDebug() << Q_FUNC_INFO << "Asked for artist ID and NOT loaded yet" << m_name << m_idFuture.isFinished();
#endif
m_idFuture.waitForFinished();
#if ID_THREAD_DEBUG
qDebug() << "DONE WAITING:" << m_idFuture.resultCount() << m_idFuture.isResultReadyAt(0) << m_idFuture.isCanceled() << m_idFuture.isFinished() << m_idFuture.isPaused() << m_idFuture.isRunning() << m_idFuture.isStarted();
#endif
finalid = m_idFuture.result();
#if ID_THREAD_DEBUG
qDebug() << Q_FUNC_INFO << "Got loaded artist:" << m_name << finalid;
#endif
s_idMutex.lockForWrite();
m_id = finalid;
m_waitingForFuture = false;
if ( m_id > 0 )
{
QMutexLocker lock( &s_mutex );
s_artistsById[ m_id ] = m_ownRef.toStrongRef();
}
s_idMutex.unlock();
}
return m_id;
}
QString
Artist::biography() const
{
if ( !m_biographyLoaded )
{
Tomahawk::InfoSystem::InfoRequestData requestData;
requestData.caller = infoid();
requestData.caller = uniqueId();
requestData.customData = QVariantMap();
requestData.input = name();
@@ -286,7 +404,7 @@ Artist::onAlbumsFound( const QList< album_ptr >& albums, const QVariant& data )
void
Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output )
{
if ( requestData.caller != infoid() )
if ( requestData.caller != uniqueId() )
return;
QVariantMap returnedData = output.value< QVariantMap >();
@@ -327,7 +445,13 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari
m_coverBuffer = ba;
}
m_coverLoaded = true;
{
QMutexLocker lock( &s_mutex );
m_coverLoaded = true;
s_artistsByCoverId.remove( coverId() );
m_coverId = uuid();
s_artistsByCoverId[ m_coverId ] = m_ownRef.toStrongRef();
}
emit coverChanged();
}
@@ -375,7 +499,7 @@ Artist::infoSystemFinished( QString target )
{
Q_UNUSED( target );
if ( target != infoid() )
if ( target != uniqueId() )
return;
if ( --m_infoJobs == 0 )
@@ -406,7 +530,7 @@ Artist::cover( const QSize& size, bool forceLoad ) const
trackInfo["artist"] = name();
Tomahawk::InfoSystem::InfoRequestData requestData;
requestData.caller = infoid();
requestData.caller = uniqueId();
requestData.type = Tomahawk::InfoSystem::InfoArtistImages;
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo );
requestData.customData = QVariantMap();
@@ -479,10 +603,20 @@ Artist::tracks( ModelMode mode, const Tomahawk::collection_ptr& collection )
QString
Artist::infoid() const
Artist::uniqueId() const
{
if ( m_uuid.isEmpty() )
m_uuid = uuid();
return m_uuid;
}
QString
Artist::coverId() const
{
if ( m_coverId.isEmpty() )
m_coverId = uuid();
return m_coverId;
}

View File

@@ -27,10 +27,15 @@
#include <QtGui/QPixmap>
#endif
#include <QFuture>
#include "Typedefs.h"
#include "DllMacro.h"
#include "Query.h"
class IdThreadWorker;
namespace Tomahawk
{
@@ -41,13 +46,17 @@ Q_OBJECT
public:
static artist_ptr get( const QString& name, bool autoCreate = false );
static artist_ptr get( unsigned int id, const QString& name );
static artist_ptr getByCoverId( const QString& uuid );
explicit Artist( unsigned int id, const QString& name );
Artist( unsigned int id, const QString& name );
explicit Artist( const QString& name );
virtual ~Artist();
unsigned int id() const { return m_id; }
unsigned int id() const;
QString name() const { return m_name; }
QString sortname() const { return m_sortname; }
QString uniqueId() const;
QString coverId() const;
QList<Tomahawk::album_ptr> albums( ModelMode mode = Mixed, const Tomahawk::collection_ptr& collection = Tomahawk::collection_ptr() ) const;
QList<Tomahawk::artist_ptr> similarArtists() const;
@@ -59,7 +68,7 @@ public:
QList< Tomahawk::PlaybackLog > playbackHistory( const Tomahawk::source_ptr& source = Tomahawk::source_ptr() ) const;
void setPlaybackHistory( const QList< Tomahawk::PlaybackLog >& playbackData );
unsigned int playbackCount( const Tomahawk::source_ptr& source = Tomahawk::source_ptr() );
QString biography() const;
#ifndef ENABLE_HEADLESS
@@ -72,6 +81,7 @@ public:
QWeakPointer< Tomahawk::Artist > weakRef() { return m_ownRef; }
void setWeakRef( QWeakPointer< Tomahawk::Artist > weakRef ) { m_ownRef = weakRef; }
void loadId( bool autoCreate );
signals:
void tracksAdded( const QList<Tomahawk::query_ptr>& tracks, Tomahawk::ModelMode mode, const Tomahawk::collection_ptr& collection );
void albumsAdded( const QList<Tomahawk::album_ptr>& albums, Tomahawk::ModelMode mode );
@@ -91,9 +101,13 @@ private slots:
private:
Artist();
QString infoid() const;
unsigned int m_id;
void setIdFuture( QFuture<unsigned int> idFuture );
mutable bool m_waitingForFuture;
mutable QFuture<unsigned int> m_idFuture;
mutable unsigned int m_id;
QString m_name;
QString m_sortname;
@@ -104,6 +118,7 @@ private:
bool m_biographyLoaded;
mutable QString m_uuid;
mutable QString m_coverId;
mutable int m_infoJobs;
QList<Tomahawk::album_ptr> m_databaseAlbums;
@@ -121,8 +136,14 @@ private:
#endif
QHash< Tomahawk::ModelMode, QHash< Tomahawk::collection_ptr, Tomahawk::playlistinterface_ptr > > m_playlistInterface;
QWeakPointer< Tomahawk::Artist > m_ownRef;
static QHash< QString, artist_ptr > s_artistsByName;
static QHash< unsigned int, artist_ptr > s_artistsById;
static QHash< QString, artist_ptr > s_artistsByCoverId;
friend class ::IdThreadWorker;
};
} // ns

View File

@@ -112,6 +112,10 @@ 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 )
{
@@ -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 )
{

View File

@@ -42,7 +42,6 @@ public:
virtual QList<Tomahawk::query_ptr> tracks();
virtual int trackCount() const { return m_queries.count(); }
virtual int unfilteredTrackCount() const { return m_queries.count(); }
virtual Tomahawk::result_ptr siblingItem( int itemsAway );
@@ -55,14 +54,13 @@ public:
virtual void setRepeatMode( PlaylistModes::RepeatMode ) {}
virtual void setShuffled( bool ) {}
virtual void setFilter( const QString& /*pattern*/ ) {}
signals:
void tracksLoaded( Tomahawk::ModelMode mode, const Tomahawk::collection_ptr& collection );
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

@@ -48,6 +48,8 @@ set( libGuiSources
infobar/InfoBar.cpp
playlist/FlexibleHeader.cpp
playlist/FlexibleView.cpp
playlist/TreeModel.cpp
playlist/TreeProxyModel.cpp
playlist/TreeProxyModelPlaylistInterface.cpp
@@ -65,13 +67,14 @@ set( libGuiSources
playlist/GridItemDelegate.cpp
playlist/GridView.cpp
playlist/TreeView.cpp
playlist/CustomPlaylistView.cpp
playlist/ViewHeader.cpp
playlist/LovedTracksModel.cpp
playlist/RecentlyAddedModel.cpp
playlist/RecentlyPlayedModel.cpp
playlist/PlaylistLargeItemDelegate.cpp
playlist/PlaylistChartItemDelegate.cpp
playlist/PlayableItem.cpp
playlist/SingleTrackPlaylistInterface.h
playlist/dynamic/DynamicPlaylist.cpp
playlist/dynamic/DynamicView.cpp
@@ -79,7 +82,9 @@ set( libGuiSources
playlist/dynamic/echonest/EchonestGenerator.cpp
playlist/dynamic/echonest/EchonestControl.cpp
playlist/dynamic/echonest/EchonestSteerer.cpp
playlist/dynamic/echonest/EchonestStation.cpp
playlist/dynamic/widgets/DynamicWidget.cpp
playlist/dynamic/widgets/DynamicQmlWidget.cpp
playlist/dynamic/widgets/DynamicControlWrapper.cpp
playlist/dynamic/widgets/DynamicControlList.cpp
playlist/dynamic/widgets/ReadOrWriteWidget.cpp
@@ -87,12 +92,6 @@ set( libGuiSources
playlist/dynamic/widgets/CollapsibleControls.cpp
playlist/dynamic/widgets/DynamicSetupWidget.cpp
playlist/topbar/TopBar.cpp
playlist/topbar/ClearButton.cpp
playlist/topbar/SearchLineEdit.cpp
playlist/topbar/LineEdit.cpp
playlist/topbar/SearchButton.cpp
ExternalResolverGui.cpp
resolvers/ScriptResolver.cpp
resolvers/QtScriptResolver.cpp
@@ -118,6 +117,8 @@ set( libGuiSources
utils/SharedTimeLine.cpp
widgets/AnimatedCounterLabel.cpp
widgets/Breadcrumb.cpp
widgets/BreadcrumbButton.cpp
widgets/CheckDirTree.cpp
widgets/QueryLabel.cpp
widgets/ImageButton.cpp
@@ -141,12 +142,17 @@ set( libGuiSources
widgets/ToggleButton.cpp
widgets/FadingPixmap.cpp
widgets/SocialPlaylistWidget.cpp
widgets/DeclarativeCoverArtProvider.cpp
widgets/SourceTreePopupDialog.cpp
widgets/infowidgets/SourceInfoWidget.cpp
widgets/infowidgets/ArtistInfoWidget.cpp
widgets/infowidgets/AlbumInfoWidget.cpp
widgets/infowidgets/TrackInfoWidget.cpp
widgets/Breadcrumb.cpp
widgets/BreadcrumbButton.cpp
widgets/infowidgets/AlbumArtImageProvider.cpp
widgets/searchlineedit/ClearButton.cpp
widgets/searchlineedit/LineEdit.cpp
widgets/searchlineedit/SearchButton.cpp
widgets/searchlineedit/SearchLineEdit.cpp
)
IF(QCA2_FOUND)
@@ -256,11 +262,23 @@ set( libSources
database/DatabaseCommand_SetTrackAttributes.cpp
database/Database.cpp
database/TomahawkSqlQuery.cpp
database/IdThreadWorker.cpp
infosystem/InfoSystem.cpp
infosystem/InfoSystemCache.cpp
infosystem/InfoSystemWorker.cpp
filemetadata/MusicScanner.cpp
filemetadata/ScanManager.cpp
filemetadata/taghandlers/tag.cpp
filemetadata/taghandlers/apetag.cpp
filemetadata/taghandlers/asftag.cpp
filemetadata/taghandlers/id3v1tag.cpp
filemetadata/taghandlers/id3v2tag.cpp
filemetadata/taghandlers/mp4tag.cpp
filemetadata/taghandlers/oggtag.cpp
filemetadata/MetadataEditor.cpp
network/BufferIoDevice.cpp
network/MsgProcessor.cpp
network/StreamConnection.cpp
@@ -281,14 +299,6 @@ set( libSources
playlist/dynamic/database/DatabaseControl.cpp
playlist/dynamic/DynamicControl.cpp
taghandlers/tag.cpp
taghandlers/apetag.cpp
taghandlers/asftag.cpp
taghandlers/id3v1tag.cpp
taghandlers/id3v2tag.cpp
taghandlers/mp4tag.cpp
taghandlers/oggtag.cpp
utils/TomahawkUtils.cpp
utils/Logger.cpp
utils/Qnr_IoDeviceStream.cpp
@@ -314,8 +324,9 @@ set( libUI ${libUI}
widgets/infowidgets/ArtistInfoWidget.ui
widgets/infowidgets/AlbumInfoWidget.ui
widgets/infowidgets/TrackInfoWidget.ui
playlist/topbar/TopBar.ui
playlist/QueueView.ui
playlist/PlaylistHeader.ui
filemetadata/MetadataEditor.ui
context/ContextWidget.ui
infobar/InfoBar.ui
accounts/AccountFactoryWrapper.ui
@@ -327,8 +338,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}
@@ -385,7 +395,8 @@ IF( APPLE )
SET( libSources ${libSources}
utils/TomahawkUtils_Mac.mm
mac/FileHelpers.mm
thirdparty/Qocoa/qsearchfield_mac.mm )
thirdparty/Qocoa/qsearchfield_mac.mm
widgets/SourceTreePopupDialog_mac.mm )
SET_SOURCE_FILES_PROPERTIES(utils/TomahawkUtils_Mac.mm PROPERTIES COMPILE_FLAGS "-fvisibility=default")
@@ -440,7 +451,7 @@ TARGET_LINK_LIBRARIES( tomahawklib
${PHONON_LIBS}
${TAGLIB_LIBRARIES}
${CLUCENE_LIBRARIES}
${LIBECHONEST_LIBRARY}
${ECHONEST_LIBRARIES}
${QT_QTSQL_LIBRARY}
${QT_QTUITOOLS_LIBRARY}
${QT_QTGUI_LIBRARY}
@@ -449,6 +460,7 @@ TARGET_LINK_LIBRARIES( tomahawklib
${QT_QTNETWORK_LIBRARY}
${QT_QTXML_LIBRARY}
${QT_QTCORE_LIBRARY}
${QT_QTDECLARATIVE_LIBRARY}
${OS_SPECIFIC_LINK_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${LINK_LIBRARIES}

View File

@@ -23,11 +23,15 @@
#include "PlaylistView.h"
#include "ViewManager.h"
#include "Query.h"
#include "Result.h"
#include "Collection.h"
#include "Source.h"
#include "Artist.h"
#include "Album.h"
#include "utils/Logger.h"
#include "audio/AudioEngine.h"
#include "filemetadata/MetadataEditor.h"
using namespace Tomahawk;
@@ -39,7 +43,7 @@ ContextMenu::ContextMenu( QWidget* parent )
m_sigmap = new QSignalMapper( this );
connect( m_sigmap, SIGNAL( mapped( int ) ), SLOT( onTriggered( int ) ) );
m_supportedActions = ActionPlay | ActionQueue | ActionCopyLink | ActionLove | ActionStopAfter | ActionPage;
m_supportedActions = ActionPlay | ActionQueue | ActionCopyLink | ActionLove | ActionStopAfter | ActionPage | ActionEditMetadata;
}
@@ -109,6 +113,19 @@ ContextMenu::setQueries( const QList<Tomahawk::query_ptr>& queries )
addSeparator();
if ( m_supportedActions & ActionEditMetadata && itemCount() == 1 )
{
if ( m_queries.first()->results().isEmpty() )
return;
Tomahawk::result_ptr result = m_queries.first()->results().first();
if ( result->collection() && result->collection()->source() &&
result->collection()->source()->isLocal() )
{
m_sigmap->setMapping( addAction( tr( "Properties..." ) ), ActionEditMetadata );
}
}
if ( m_supportedActions & ActionDelete )
m_sigmap->setMapping( addAction( queries.count() > 1 ? tr( "&Delete Items" ) : tr( "&Delete Item" ) ), ActionDelete );
@@ -243,6 +260,13 @@ ContextMenu::onTriggered( int action )
AudioEngine::instance()->setStopAfterTrack( m_queries.first() );
break;
case ActionEditMetadata:
if ( !m_queries.first()->results().isEmpty() ) {
MetadataEditor* d = new MetadataEditor( m_queries.first()->results().first(), this );
d->show();
}
break;
default:
emit triggered( action );
}
@@ -312,12 +336,12 @@ ContextMenu::onSocialActionsLoaded()
if ( m_queries.isEmpty() || m_queries.first().isNull() )
return;
if ( m_queries.first()->loved() )
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

@@ -42,7 +42,8 @@ public:
ActionCopyLink = 8,
ActionLove = 16,
ActionStopAfter = 32,
ActionPage = 64
ActionPage = 64,
ActionEditMetadata = 128
};
explicit ContextMenu( QWidget* parent = 0 );

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;

View File

@@ -43,7 +43,6 @@
#ifndef ENABLE_HEADLESS
#include "ViewManager.h"
#include "playlist/topbar/TopBar.h"
#include "playlist/PlaylistView.h"
#include "widgets/SearchWidget.h"

View File

@@ -60,7 +60,10 @@ public slots:
/// Takes a spotify link and performs the default open action on it
bool openRdioLink( const QString& link );
/// Creates a link from the requested data and copies it to the clipboard
void copyToClipboard( const Tomahawk::query_ptr& query );
QString copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist );
void savePlaylistToFile( const Tomahawk::playlist_ptr& playlist, const QString& filename );

View File

@@ -37,7 +37,9 @@
#include "PlaylistPlaylistInterface.h"
#include "utils/Logger.h"
#include "utils/Closure.h"
#include "PlaylistUpdaterInterface.h"
#include "widgets/SourceTreePopupDialog.h"
using namespace Tomahawk;
@@ -179,16 +181,14 @@ Playlist::create( const source_ptr& author,
p->setGuid( uuid() );
p->setDuration( query->duration() );
p->setLastmodified( 0 );
QString annotation = "";
if ( !query->property( "annotation" ).toString().isEmpty() )
annotation = query->property( "annotation" ).toString();
p->setAnnotation( annotation );
p->setAnnotation( query->property( "annotation" ).toString() );
p->setQuery( query );
entries << p;
}
playlist_ptr playlist( new Playlist( author, guid, title, info, creator, shared, entries ), &QObject::deleteLater );
playlist->setWeakSelf( playlist.toWeakRef() );
// save to DB in the background
// Watch for the created() signal if you need to be sure it's written.
@@ -310,6 +310,83 @@ Playlist::removeUpdater( PlaylistUpdaterInterface* updater )
}
bool
Playlist::hasCustomDeleter() const
{
foreach ( PlaylistUpdaterInterface* updater, m_updaters )
{
if ( updater->hasCustomDeleter() )
return true;
}
return false;
}
void
Playlist::customDelete( const QPoint& leftCenter )
{
if ( !hasCustomDeleter() )
return;
Tomahawk::PlaylistDeleteQuestions questions;
foreach ( PlaylistUpdaterInterface* updater, m_updaters )
{
if ( updater->deleteQuestions().isEmpty() )
continue;
questions.append( updater->deleteQuestions() );
}
SourceTreePopupDialog* dialog = new SourceTreePopupDialog;
NewClosure( dialog, SIGNAL( result( bool ) ), this, SLOT( onDeleteResult( SourceTreePopupDialog* ) ), dialog );
dialog->setMainText( tr( "Would you like to delete the playlist <b>\"%2\"</b>?", "e.g. Would you like to delete the playlist named Foobar?" )
.arg( title() ) );
dialog->setOkButtonText( tr( "Delete" ) );
dialog->setExtraQuestions( questions );
dialog->move( leftCenter.x() - dialog->offset(), leftCenter.y() - dialog->sizeHint().height() / 2. );
dialog->show();
}
void
Playlist::onDeleteResult( SourceTreePopupDialog* dialog )
{
dialog->deleteLater();
const bool ret = dialog->resultValue();
if ( !ret )
return;
playlist_ptr p = m_weakSelf.toStrongRef();
if ( p.isNull() )
{
qWarning() << "Got null m_weakSelf weak ref in Playlsit::onDeleteResult!!";
Q_ASSERT( false );
return;
}
const QMap< int, bool > questionResults = dialog->questionResults();
foreach ( PlaylistUpdaterInterface* updater, m_updaters )
{
updater->setQuestionResults( questionResults );
}
dynplaylist_ptr dynpl = p.dynamicCast< DynamicPlaylist >();
if ( !dynpl.isNull() )
{
DynamicPlaylist::remove( dynpl );
}
else
{
remove( p );
}
}
void
Playlist::loadRevision( const QString& rev )
{
@@ -508,7 +585,7 @@ Playlist::setNewRevision( const QString& rev,
tDebug() << "m_entries" << m_entries;
tLog() << "Playlist error for playlist with guid" << guid() << "from source" << author()->friendlyName();
Q_ASSERT( false ); // XXX
// Q_ASSERT( false ); // XXX
}
}
@@ -710,6 +787,13 @@ Playlist::checkRevisionQueue()
}
void
Playlist::setWeakSelf( QWeakPointer< Playlist > self )
{
m_weakSelf = self;
}
Tomahawk::playlistinterface_ptr
Playlist::playlistInterface()
{

View File

@@ -35,6 +35,7 @@
#include "DllMacro.h"
class SourceTreePopupDialog;
class DatabaseCommand_LoadAllPlaylists;
class DatabaseCommand_LoadAllSortedPlaylists;
class DatabaseCommand_SetPlaylistRevision;
@@ -194,6 +195,18 @@ public:
void removeUpdater( PlaylistUpdaterInterface* updater );
QList<PlaylistUpdaterInterface*> updaters() const { return m_updaters; }
/**
* Some updaters might have custom deleters in order to perform more actions that require
* user prompting on delete.
*/
bool hasCustomDeleter() const;
/**
* If this playlist has a custom deleter, let it do the deleting itself.
*
* If it needs user prompting, use the \param customDeleter as the right-most center point.
*/
void customDelete( const QPoint& rightCenter );
Tomahawk::playlistinterface_ptr playlistInterface();
signals:
@@ -249,6 +262,7 @@ public slots:
void resolve();
void setWeakSelf( QWeakPointer< Playlist > self );
protected:
// called from loadAllPlaylists DB cmd:
explicit Playlist( const source_ptr& src,
@@ -282,6 +296,7 @@ private slots:
void onResultsFound( const QList<Tomahawk::result_ptr>& results );
void onResolvingFinished();
void onDeleteResult( SourceTreePopupDialog* );
private:
Playlist();
void init();
@@ -289,6 +304,7 @@ private:
void setBusy( bool b );
void checkRevisionQueue();
QWeakPointer< Playlist > m_weakSelf;
source_ptr m_source;
QString m_currentrevision;
QString m_guid, m_title, m_info, m_creator;

View File

@@ -42,12 +42,12 @@ public:
virtual QList< Tomahawk::query_ptr > tracks() = 0;
virtual bool isFinished() const { return m_finished; }
virtual int unfilteredTrackCount() const = 0;
virtual int trackCount() const = 0;
virtual Tomahawk::result_ptr currentItem() const = 0;
virtual Tomahawk::result_ptr previousItem();
virtual bool hasNextItem() { return true; }
virtual bool hasPreviousItem() { return true; }
virtual Tomahawk::result_ptr nextItem();
virtual Tomahawk::result_ptr siblingItem( int itemsAway ) = 0;
@@ -66,8 +66,7 @@ public:
virtual PlaylistModes::LatchMode latchMode() const { return m_latchMode; }
virtual void setLatchMode( PlaylistModes::LatchMode latchMode ) { m_latchMode = latchMode; }
virtual QString filter() const { return m_filter; }
virtual void setFilter( const QString& pattern ) { m_filter = pattern; }
virtual bool setCurrentTrack( unsigned int albumpos ) { Q_UNUSED( albumpos ); return false; }
virtual void reset() {}
@@ -81,10 +80,9 @@ public slots:
virtual void setShuffled( bool enabled ) = 0;
signals:
void trackCountChanged( unsigned int tracks );
void repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode mode );
void shuffleModeChanged( bool enabled );
void trackCountChanged( unsigned int tracks );
void sourceTrackCountChanged( unsigned int tracks );
void latchModeChanged( Tomahawk::PlaylistModes::LatchMode mode );
void nextTrackReady();

View File

@@ -40,13 +40,6 @@ PlaylistPlaylistInterface::~PlaylistPlaylistInterface()
}
int
PlaylistPlaylistInterface::unfilteredTrackCount() const
{
return ( m_playlist.isNull() ? 0 : m_playlist.data()->entries().count() );
}
int
PlaylistPlaylistInterface::trackCount() const
{

View File

@@ -44,7 +44,6 @@ public:
virtual QList<Tomahawk::query_ptr> tracks();
virtual int unfilteredTrackCount() const;
virtual int trackCount() const;
virtual bool hasNextItem() { return false; }
@@ -55,8 +54,6 @@ public:
virtual PlaylistModes::RepeatMode repeatMode() const { return PlaylistModes::NoRepeat; }
virtual bool shuffled() const { return false; }
virtual void setFilter( const QString& /*pattern*/ ) {}
public slots:
virtual void setRepeatMode( PlaylistModes::RepeatMode ) {}
virtual void setShuffled( bool ) {}

View File

@@ -82,8 +82,11 @@ 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() )
if ( artist.trimmed().isEmpty() || track.trimmed().isEmpty() )
{
Q_ASSERT( false );
return query_ptr();
}
if ( qid.isEmpty() )
autoResolve = false;
@@ -150,6 +153,7 @@ Query::Query( const QString& query, const QID& qid )
Query::~Query()
{
QMutexLocker lock( &m_mutex );
m_ownRef.clear();
m_results.clear();
}
@@ -349,6 +353,22 @@ Query::id() const
}
QString
Query::coverId() const
{
if ( m_albumPtr && m_albumPtr->coverLoaded() && !m_albumPtr->cover( QSize( 0, 0 ) ).isNull() )
{
return m_albumPtr->coverId();
}
else if ( m_artistPtr )
{
return m_artistPtr->coverId();
}
return QString();
}
void
Query::setPlayedBy( const Tomahawk::source_ptr& source, unsigned int playtime )
{
@@ -459,14 +479,19 @@ Query::checkResults()
bool
Query::equals( const Tomahawk::query_ptr& other ) const
Query::equals( const Tomahawk::query_ptr& other, bool ignoreCase ) const
{
if ( other.isNull() )
return false;
return ( artist() == other->artist() &&
album() == other->album() &&
track() == other->track() );
if ( ignoreCase )
return ( artist().toLower() == other->artist().toLower() &&
album().toLower() == other->album().toLower() &&
track().toLower() == other->track().toLower() );
else
return ( artist() == other->artist() &&
album() == other->album() &&
track() == other->track() );
}
@@ -502,7 +527,7 @@ Query::howSimilar( const Tomahawk::result_ptr& r )
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 = r->album()->sortname();

View File

@@ -95,6 +95,7 @@ public:
unsigned int numResults() const;
QID id() const;
QString coverId() const;
/// sorter for list of results
static bool resultSorter( const result_ptr& left, const result_ptr& right );
@@ -122,7 +123,7 @@ public:
void setAlbumPos( unsigned int albumpos ) { m_albumpos = albumpos; }
void setDiscNumber( unsigned int discnumber ) { m_discnumber = discnumber; }
bool equals( const Tomahawk::query_ptr& other ) const;
bool equals( const Tomahawk::query_ptr& other, bool ignoreCase = false ) const;
QVariant toVariant() const;
QString toString() const;

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

@@ -292,10 +292,8 @@ Source::scanningProgress( unsigned int files )
void
Source::scanningFinished( unsigned int files )
Source::scanningFinished()
{
Q_UNUSED( files );
m_textStatus = QString();
if ( m_updateIndexWhenSynced )

View File

@@ -80,7 +80,7 @@ public:
void setControlConnection( ControlConnection* cc );
void scanningProgress( unsigned int files );
void scanningFinished( unsigned int files );
void scanningFinished();
unsigned int trackCount() const;

View File

@@ -42,7 +42,6 @@ public:
QList<Tomahawk::query_ptr> tracks();
virtual int trackCount() const { return 1; }
virtual int unfilteredTrackCount() const { return 1; }
virtual Tomahawk::result_ptr siblingItem( int itemsAway );
virtual bool sourceValid();
@@ -59,7 +58,6 @@ public:
virtual void setLatchMode( PlaylistModes::LatchMode latchMode ) { m_latchMode = latchMode; emit latchModeChanged( latchMode ); }
virtual bool shuffled() const { return false; }
virtual void setFilter( const QString& /*pattern*/ ) {}
virtual QWeakPointer< Tomahawk::Source > source() const;

View File

@@ -98,6 +98,9 @@ namespace Tomahawk
typedef QMultiHash< QString, SerializedUpdater > SerializedUpdaters;
typedef QList< SerializedUpdater > SerializedUpdaterList;
// Yes/no questions with an associated enum value
typedef QPair< QString, int > PlaylistDeleteQuestion;
typedef QList< PlaylistDeleteQuestion > PlaylistDeleteQuestions;
namespace InfoSystem
{

View File

@@ -2,6 +2,7 @@
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
* Copyright 2010-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
@@ -25,8 +26,8 @@
#include "audio/AudioEngine.h"
#include "context/ContextWidget.h"
#include "infobar/InfoBar.h"
#include "topbar/TopBar.h"
#include "FlexibleView.h"
#include "TreeModel.h"
#include "PlaylistModel.h"
#include "PlaylistView.h"
@@ -38,10 +39,10 @@
#include "SourceList.h"
#include "TomahawkSettings.h"
#include "CustomPlaylistView.h"
#include "PlaylistLargeItemDelegate.h"
#include "RecentlyPlayedModel.h"
#include "dynamic/widgets/DynamicWidget.h"
#include "dynamic/widgets/DynamicQmlWidget.h"
#include "widgets/NewReleasesWidget.h"
#include "widgets/WelcomeWidget.h"
@@ -75,10 +76,8 @@ ViewManager::ViewManager( QObject* parent )
, m_welcomeWidget( new WelcomeWidget() )
, m_whatsHotWidget( new WhatsHotWidget() )
, m_newReleasesWidget( new NewReleasesWidget() )
, m_topLovedWidget( 0 )
, m_recentPlaysWidget( 0 )
, m_currentPage( 0 )
, m_currentMode( PlaylistModes::Tree )
, m_loaded( false )
{
s_instance = this;
@@ -94,15 +93,11 @@ ViewManager::ViewManager( QObject* parent )
m_widget->layout()->addWidget( m_contextWidget );
m_superCollectionView = new TreeView();
m_superCollectionView->proxyModel()->setStyle( PlayableProxyModel::Collection );
m_superCollectionModel = new TreeModel( m_superCollectionView );
m_superCollectionView->setTreeModel( m_superCollectionModel );
m_superCollectionView->setShowModes( false );
// m_superCollectionView->proxyModel()->setShowOfflineResults( false );
m_superGridView = new GridView();
m_superAlbumModel = new AlbumModel( m_superGridView );
m_superGridView->setPlayableModel( m_superAlbumModel );
m_stack->setContentsMargins( 0, 0, 0, 0 );
m_widget->setContentsMargins( 0, 0, 0, 0 );
m_widget->layout()->setContentsMargins( 0, 0, 0, 0 );
@@ -130,23 +125,27 @@ ViewManager::~ViewManager()
delete m_whatsHotWidget;
delete m_newReleasesWidget;
delete m_welcomeWidget;
delete m_topLovedWidget;
delete m_recentPlaysWidget;
delete m_contextWidget;
delete m_widget;
}
PlaylistView*
ViewManager::createPageForPlaylist( const playlist_ptr& pl )
FlexibleView*
ViewManager::createPageForPlaylist( const playlist_ptr& playlist )
{
PlaylistView* view = new PlaylistView();
FlexibleView* view = new FlexibleView();
PlaylistModel* model = new PlaylistModel();
view->setPlaylistModel( model );
model->loadPlaylist( pl );
pl->resolve();
m_playlistViews.insert( pl, view );
PlaylistView* pv = new PlaylistView();
pv->setPlaylistModel( model );
view->setDetailedView( pv );
view->setPixmap( pv->pixmap() );
model->loadPlaylist( playlist );
view->setPlayableModel( model );
playlist->resolve();
return view;
}
@@ -170,11 +169,12 @@ ViewManager::playlistForPage( ViewPage* page ) const
Tomahawk::ViewPage*
ViewManager::show( const Tomahawk::playlist_ptr& playlist )
{
PlaylistView* view;
FlexibleView* view;
if ( !m_playlistViews.contains( playlist ) || m_playlistViews.value( playlist ).isNull() )
{
view = createPageForPlaylist( playlist );
m_playlistViews.insert( playlist, view );
}
else
{
@@ -182,9 +182,6 @@ ViewManager::show( const Tomahawk::playlist_ptr& playlist )
}
setPage( view );
emit numSourcesChanged( SourceList::instance()->count() );
return view;
}
@@ -194,7 +191,7 @@ ViewManager::show( const Tomahawk::dynplaylist_ptr& playlist )
{
if ( !m_dynamicWidgets.contains( playlist ) || m_dynamicWidgets.value( playlist ).isNull() )
{
m_dynamicWidgets[ playlist ] = new Tomahawk::DynamicWidget( playlist, m_stack );
m_dynamicWidgets[ playlist ] = new Tomahawk::DynamicQmlWidget( playlist, m_stack );
playlist->resolve();
}
@@ -206,8 +203,6 @@ ViewManager::show( const Tomahawk::dynplaylist_ptr& playlist )
else
showQueue();*/
emit numSourcesChanged( SourceList::instance()->count() );
return m_dynamicWidgets.value( playlist ).data();
}
@@ -272,82 +267,32 @@ ViewManager::show( const Tomahawk::query_ptr& query )
Tomahawk::ViewPage*
ViewManager::show( const Tomahawk::collection_ptr& collection )
{
qDebug() << Q_FUNC_INFO << m_currentMode;
m_currentCollection = collection;
ViewPage* shown = 0;
if ( m_currentMode == PlaylistModes::Flat )
TreeView* view;
if ( !m_treeViews.contains( collection ) || m_treeViews.value( collection ).isNull() )
{
/* CollectionView* view;
if ( !m_collectionViews.contains( collection ) || m_collectionViews.value( collection ).isNull() )
{
view = new CollectionView();
CollectionFlatModel* model = new CollectionFlatModel();
view->setPlayableModel( model );
view = new TreeView();
view->proxyModel()->setStyle( PlayableProxyModel::Collection );
TreeModel* model = new TreeModel();
view->setTreeModel( model );
model->addCollection( collection );
m_collectionViews.insert( collection, view );
}
if ( collection && collection->source()->isLocal() )
view->setEmptyTip( tr( "After you have scanned your music collection you will find your tracks right here." ) );
else
{
view = m_collectionViews.value( collection ).data();
}
view->setEmptyTip( tr( "This collection is empty." ) );
shown = view;
setPage( view );*/
model->addCollection( collection );
m_treeViews.insert( collection, view );
}
else
{
view = m_treeViews.value( collection ).data();
}
if ( m_currentMode == PlaylistModes::Tree )
{
TreeView* view;
if ( !m_treeViews.contains( collection ) || m_treeViews.value( collection ).isNull() )
{
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
view->setEmptyTip( tr( "This collection is empty." ) );
model->addCollection( collection );
m_treeViews.insert( collection, view );
}
else
{
view = m_treeViews.value( collection ).data();
}
shown = view;
setPage( view );
}
if ( m_currentMode == PlaylistModes::Album )
{
GridView* aview;
if ( !m_collectionGridViews.contains( collection ) || m_collectionGridViews.value( collection ).isNull() )
{
aview = new GridView();
AlbumModel* amodel = new AlbumModel( aview );
aview->setPlayableModel( amodel );
amodel->addCollection( collection );
m_collectionGridViews.insert( collection, aview );
}
else
{
aview = m_collectionGridViews.value( collection ).data();
}
shown = aview;
setPage( aview );
}
emit numSourcesChanged( 1 );
return shown;
setPage( view );
return view;
}
@@ -396,28 +341,9 @@ ViewManager::showSuperCollection()
m_superCollectionModel->setTitle( tr( "SuperCollection" ) );
m_superCollectionModel->setDescription( tr( "Combined libraries of all your online friends" ) );
m_superAlbumModel->setTitle( tr( "All available albums" ) );
ViewPage* shown = 0;
if ( m_currentMode == PlaylistModes::Tree )
{
shown = m_superCollectionView;
setPage( m_superCollectionView );
}
else if ( m_currentMode == PlaylistModes::Flat )
{
shown = m_superCollectionView;
setPage( m_superCollectionView );
}
else if ( m_currentMode == PlaylistModes::Album )
{
shown = m_superGridView;
setPage( m_superGridView );
}
emit numSourcesChanged( m_superCollections.count() );
return shown;
setPage( m_superCollectionView );
return m_superCollectionView;
}
@@ -459,40 +385,24 @@ ViewManager::showNewReleasesPage()
}
Tomahawk::ViewPage*
ViewManager::showTopLovedPage()
{
if ( !m_topLovedWidget )
{
CustomPlaylistView* view = new CustomPlaylistView( CustomPlaylistView::TopLovedTracks, source_ptr(), m_widget );
PlaylistLargeItemDelegate* del = new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::LovedTracks, view, view->proxyModel() );
connect( del, SIGNAL( updateIndex( QModelIndex ) ), view, SLOT( update( QModelIndex ) ) );
view->setItemDelegate( del );
m_topLovedWidget = view;
}
return show( m_topLovedWidget );
}
Tomahawk::ViewPage*
ViewManager::showRecentPlaysPage()
{
if ( !m_recentPlaysWidget )
{
PlaylistView* pv = new PlaylistView( m_widget );
FlexibleView* pv = new FlexibleView( m_widget );
pv->setPixmap( QPixmap( RESPATH "images/recently-played.png" ) );
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 );
PlaylistLargeItemDelegate* del = new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::RecentlyPlayed, pv, pv->proxyModel() );
connect( del, SIGNAL( updateIndex( QModelIndex ) ), pv, SLOT( update( QModelIndex ) ) );
pv->setItemDelegate( del );
PlaylistLargeItemDelegate* del = new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::RecentlyPlayed, pv->trackView(), pv->trackView()->proxyModel() );
connect( del, SIGNAL( updateIndex( QModelIndex ) ), pv->trackView(), SLOT( update( QModelIndex ) ) );
pv->trackView()->setItemDelegate( del );
pv->setPlaylistModel( raModel );
pv->setPlayableModel( raModel );
pv->setEmptyTip( tr( "Sorry, we could not find any recent plays!" ) );
raModel->setSource( source_ptr() );
m_recentPlaysWidget = pv;
@@ -502,48 +412,6 @@ ViewManager::showRecentPlaysPage()
}
void
ViewManager::setTableMode()
{
qDebug() << Q_FUNC_INFO;
m_currentMode = PlaylistModes::Flat;
if ( isSuperCollectionVisible() )
showSuperCollection();
else
show( m_currentCollection );
}
void
ViewManager::setTreeMode()
{
qDebug() << Q_FUNC_INFO;
m_currentMode = PlaylistModes::Tree;
if ( isSuperCollectionVisible() )
showSuperCollection();
else
show( m_currentCollection );
}
void
ViewManager::setAlbumMode()
{
qDebug() << Q_FUNC_INFO;
m_currentMode = PlaylistModes::Album;
if ( isSuperCollectionVisible() )
showSuperCollection();
else
show( m_currentCollection );
}
void
ViewManager::setFilter( const QString& filter )
{
@@ -559,8 +427,8 @@ ViewManager::setFilter( const QString& filter )
void
ViewManager::applyFilter()
{
if ( currentPlaylistInterface() && currentPlaylistInterface()->filter() != m_filter )
currentPlaylistInterface()->setFilter( m_filter );
if ( m_currentPage )
m_currentPage->setFilter( m_filter );
}
@@ -716,17 +584,11 @@ ViewManager::unlinkPlaylist()
{
if ( currentPlaylistInterface() )
{
disconnect( currentPlaylistInterface().data(), SIGNAL( sourceTrackCountChanged( unsigned int ) ),
this, SIGNAL( numTracksChanged( unsigned int ) ) );
disconnect( currentPlaylistInterface().data(), SIGNAL( trackCountChanged( unsigned int ) ),
this, SIGNAL( numShownChanged( unsigned int ) ) );
disconnect( currentPlaylistInterface().data(), SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ),
this, SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ) );
this, SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ) );
disconnect( currentPlaylistInterface().data(), SIGNAL( shuffleModeChanged( bool ) ),
this, SIGNAL( shuffleModeChanged( bool ) ) );
this, SIGNAL( shuffleModeChanged( bool ) ) );
}
}
@@ -737,12 +599,16 @@ ViewManager::saveCurrentPlaylistSettings()
TomahawkSettings* s = TomahawkSettings::instance();
Tomahawk::playlist_ptr pl = playlistForInterface( currentPlaylistInterface() );
if ( !pl.isNull() ) {
if ( !pl.isNull() )
{
s->setShuffleState( pl->guid(), currentPlaylistInterface()->shuffled() );
s->setRepeatMode( pl->guid(), currentPlaylistInterface()->repeatMode() );
} else {
}
else
{
Tomahawk::dynplaylist_ptr dynPl = dynamicPlaylistForInterface( currentPlaylistInterface() );
if ( !dynPl.isNull() ) {
if ( !dynPl.isNull() )
{
s->setShuffleState( dynPl->guid(), currentPlaylistInterface()->shuffled() );
s->setRepeatMode( dynPl->guid(), currentPlaylistInterface()->repeatMode() );
}
@@ -755,33 +621,16 @@ ViewManager::updateView()
{
if ( currentPlaylistInterface() )
{
connect( currentPlaylistInterface().data(), SIGNAL( sourceTrackCountChanged( unsigned int ) ),
SIGNAL( numTracksChanged( unsigned int ) ) );
connect( currentPlaylistInterface().data(), SIGNAL( trackCountChanged( unsigned int ) ),
SIGNAL( numShownChanged( unsigned int ) ) );
connect( currentPlaylistInterface().data(), SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ),
SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ) );
connect( currentPlaylistInterface().data(), SIGNAL( shuffleModeChanged( bool ) ),
SIGNAL( shuffleModeChanged( bool ) ) );
m_infobar->setFilter( currentPlaylistInterface()->filter() );
}
if ( currentPage()->showStatsBar() && currentPlaylistInterface() )
{
emit numTracksChanged( currentPlaylistInterface()->unfilteredTrackCount() );
if ( !currentPlaylistInterface()->filter().isEmpty() )
emit numShownChanged( currentPlaylistInterface()->trackCount() );
else
emit numShownChanged( currentPlaylistInterface()->unfilteredTrackCount() );
m_infobar->setFilter( currentPage()->filter() );
emit repeatModeChanged( currentPlaylistInterface()->repeatMode() );
emit shuffleModeChanged( currentPlaylistInterface()->shuffled() );
emit modeChanged( currentPlaylistInterface()->viewMode() );
}
/* if ( currentPage()->queueVisible() )
@@ -789,18 +638,10 @@ ViewManager::updateView()
else
hideQueue();*/
emit statsAvailable( currentPage()->showStatsBar() );
emit modesAvailable( currentPage()->showModes() );
emit filterAvailable( currentPage()->showFilter() );
/* if ( !currentPage()->showStatsBar() && !currentPage()->showModes() && !currentPage()->showFilter() )
m_topbar->setVisible( false );
else
m_topbar->setVisible( true );*/
m_infobar->setVisible( currentPage()->showInfoBar() );
m_infobar->setCaption( currentPage()->title() );
m_infobar->setUpdaters( currentPage()->updaters() );
switch( currentPage()->descriptionType() )
@@ -977,7 +818,7 @@ ViewManager::currentPage() const
Tomahawk::playlist_ptr
ViewManager::playlistForInterface( Tomahawk::playlistinterface_ptr interface ) const
{
foreach ( QWeakPointer<PlaylistView> view, m_playlistViews.values() )
foreach ( QWeakPointer<FlexibleView> view, m_playlistViews.values() )
{
if ( !view.isNull() && view.data()->playlistInterface() == interface )
{
@@ -992,7 +833,7 @@ ViewManager::playlistForInterface( Tomahawk::playlistinterface_ptr interface ) c
Tomahawk::dynplaylist_ptr
ViewManager::dynamicPlaylistForInterface( Tomahawk::playlistinterface_ptr interface ) const
{
foreach ( QWeakPointer<DynamicWidget> view, m_dynamicWidgets.values() )
foreach ( QWeakPointer<DynamicQmlWidget> view, m_dynamicWidgets.values() )
{
if ( !view.isNull() && view.data()->playlistInterface() == interface )
{
@@ -1004,27 +845,11 @@ ViewManager::dynamicPlaylistForInterface( Tomahawk::playlistinterface_ptr interf
}
Tomahawk::collection_ptr
ViewManager::collectionForInterface( Tomahawk::playlistinterface_ptr interface ) const
{
foreach ( QWeakPointer<GridView> view, m_collectionGridViews.values() )
{
if ( view.data()->playlistInterface() == interface )
{
return m_collectionGridViews.key( view );
}
}
return collection_ptr();
}
bool
ViewManager::isSuperCollectionVisible() const
{
return ( currentPage() != 0 &&
( currentPage()->playlistInterface() == m_superCollectionView->playlistInterface() ||
currentPage()->playlistInterface() == m_superGridView->playlistInterface() ) );
( currentPage()->playlistInterface() == m_superCollectionView->playlistInterface() ) );
}
@@ -1037,19 +862,6 @@ ViewManager::showCurrentTrack()
{
setPage( page );
page->jumpToCurrentTrack();
// reset the correct mode, if the user has changed it since
if ( dynamic_cast< TrackView* >( page ) )
m_currentMode = PlaylistModes::Flat;
else if ( dynamic_cast< GridView* >( page ) )
m_currentMode = PlaylistModes::Album;
else if ( dynamic_cast< TreeView* >( page ) )
m_currentMode = PlaylistModes::Tree;
else
return;
emit modeChanged( (PlaylistModes::ViewMode)m_currentMode );
}
}
@@ -1075,13 +887,6 @@ ViewManager::newReleasesWidget() const
}
Tomahawk::ViewPage*
ViewManager::topLovedWidget() const
{
return m_topLovedWidget;
}
Tomahawk::ViewPage*
ViewManager::recentPlaysWidget() const
{

View File

@@ -40,6 +40,7 @@ class ArtistInfoWidget;
class TreeView;
class CollectionModel;
class ContextWidget;
class FlexibleView;
class PlaylistModel;
class PlaylistView;
class TrackProxyModel;
@@ -49,7 +50,6 @@ class TreeModel;
class TrackView;
class SourceInfoWidget;
class InfoBar;
class TopBar;
class TrackInfoWidget;
class NewReleasesWidget;
class WelcomeWidget;
@@ -59,6 +59,7 @@ class QPushButton;
namespace Tomahawk
{
class DynamicWidget;
class DynamicQmlWidget;
}
class DLLEXPORT ViewManager : public QObject
@@ -90,7 +91,6 @@ public:
Tomahawk::ViewPage* welcomeWidget() const;
Tomahawk::ViewPage* whatsHotWidget() const;
Tomahawk::ViewPage* newReleasesWidget() const;
Tomahawk::ViewPage* topLovedWidget() const;
Tomahawk::ViewPage* recentPlaysWidget() const;
TreeView* superCollectionView() const;
@@ -104,23 +104,15 @@ public:
// only use this is you need to create a playlist and show it directly and want it to be
// linked to the sidebar. call it right after creating the playlist
PlaylistView* createPageForPlaylist( const Tomahawk::playlist_ptr& pl );
FlexibleView* createPageForPlaylist( const Tomahawk::playlist_ptr& playlist );
bool isTomahawkLoaded() const { return m_loaded; }
signals:
void numSourcesChanged( unsigned int sources );
void numTracksChanged( unsigned int tracks );
void numArtistsChanged( unsigned int artists );
void numShownChanged( unsigned int shown );
void repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode mode );
void shuffleModeChanged( bool enabled );
void statsAvailable( bool b );
void modesAvailable( bool b );
void filterAvailable( bool b );
void modeChanged( Tomahawk::PlaylistModes::ViewMode mode );
void playClicked();
void pauseClicked();
@@ -132,7 +124,7 @@ signals:
void hideQueueRequested();
void tomahawkLoaded();
void historyBackAvailable( bool avail );
void historyForwardAvailable( bool avail );
@@ -141,7 +133,6 @@ public slots:
Tomahawk::ViewPage* showWelcomePage();
Tomahawk::ViewPage* showWhatsHotPage();
Tomahawk::ViewPage* showNewReleasesPage();
Tomahawk::ViewPage* showTopLovedPage();
Tomahawk::ViewPage* showRecentPlaysPage();
void showCurrentTrack();
@@ -156,17 +147,13 @@ public slots:
void historyBack();
void historyForward();
QList< Tomahawk::ViewPage* > historyPages() const;
void destroyPage( Tomahawk::ViewPage* page );
void showQueue() { emit showQueueRequested(); }
void hideQueue() { emit hideQueueRequested(); }
void setTreeMode();
void setTableMode();
void setAlbumMode();
void setRepeatMode( Tomahawk::PlaylistModes::RepeatMode mode );
void setShuffled( bool enabled );
@@ -193,7 +180,6 @@ private:
Tomahawk::playlist_ptr playlistForInterface( Tomahawk::playlistinterface_ptr plInterface ) const;
Tomahawk::dynplaylist_ptr dynamicPlaylistForInterface( Tomahawk::playlistinterface_ptr plInterface ) const;
Tomahawk::collection_ptr collectionForInterface( Tomahawk::playlistinterface_ptr plInterface ) const;
QWidget* m_widget;
InfoBar* m_infobar;
@@ -201,26 +187,22 @@ private:
QStackedWidget* m_stack;
AnimatedSplitter* m_splitter;
AlbumModel* m_superAlbumModel;
GridView* m_superGridView;
TreeModel* m_superCollectionModel;
TreeView* m_superCollectionView;
QueueView* m_queue;
WelcomeWidget* m_welcomeWidget;
WhatsHotWidget* m_whatsHotWidget;
NewReleasesWidget* m_newReleasesWidget;
Tomahawk::ViewPage* m_topLovedWidget;
Tomahawk::ViewPage* m_recentPlaysWidget;
QList< Tomahawk::collection_ptr > m_superCollections;
QHash< Tomahawk::dynplaylist_ptr, QWeakPointer<Tomahawk::DynamicWidget> > m_dynamicWidgets;
QHash< Tomahawk::dynplaylist_ptr, QWeakPointer<Tomahawk::DynamicQmlWidget> > m_dynamicWidgets;
QHash< Tomahawk::collection_ptr, QWeakPointer<TreeView> > m_treeViews;
QHash< Tomahawk::collection_ptr, QWeakPointer<GridView> > m_collectionGridViews;
QHash< Tomahawk::artist_ptr, QWeakPointer<ArtistInfoWidget> > m_artistViews;
QHash< Tomahawk::album_ptr, QWeakPointer<AlbumInfoWidget> > m_albumViews;
QHash< Tomahawk::query_ptr, QWeakPointer<TrackInfoWidget> > m_trackViews;
QHash< Tomahawk::playlist_ptr, QWeakPointer<PlaylistView> > m_playlistViews;
QHash< Tomahawk::playlist_ptr, QWeakPointer<FlexibleView> > m_playlistViews;
QHash< Tomahawk::source_ptr, QWeakPointer<SourceInfoWidget> > m_sourceViews;
QList<Tomahawk::ViewPage*> m_pageHistoryBack;
@@ -228,7 +210,6 @@ private:
Tomahawk::ViewPage* m_currentPage;
Tomahawk::collection_ptr m_currentCollection;
int m_currentMode;
QTimer m_filterTimer;
QString m_filter;

View File

@@ -23,3 +23,10 @@
using namespace Tomahawk;
bool
ViewPage::setFilter( const QString& filter )
{
m_filter = filter;
return false;
}

View File

@@ -58,12 +58,13 @@ public:
virtual QString longDescription() const { return QString(); }
virtual QPixmap pixmap() const { return QPixmap( RESPATH "icons/tomahawk-icon-128x128.png" ); }
virtual bool showStatsBar() const { return true; }
virtual bool showInfoBar() const { return true; }
virtual bool showModes() const { return false; }
virtual bool showFilter() const { return false; }
virtual bool queueVisible() const { return true; }
virtual QString filter() const { return m_filter; }
virtual bool setFilter( const QString& filter );
virtual bool jumpToCurrentTrack() = 0;
virtual bool isTemporaryPage() const { return false; }
@@ -82,6 +83,9 @@ public:
*
* See DynamicWidget for an example
*/
private:
QString m_filter;
};
}; // ns

View File

@@ -38,8 +38,9 @@ using namespace Accounts;
AccountModel::AccountModel( QObject* parent )
: QAbstractListModel( parent )
, m_waitingForAtticaLoaded( true )
{
connect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( loadData() ) );
connect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( atticaLoaded() ) );
connect( AtticaManager::instance(), SIGNAL( startedInstalling( QString ) ), this, SLOT( onStartedInstalling( QString ) ) );
connect( AtticaManager::instance(), SIGNAL( resolverInstalled( QString ) ), this, SLOT( onFinishedInstalling( QString ) ) );
connect( AtticaManager::instance(), SIGNAL( resolverInstallationFailed( QString ) ), this, SLOT( resolverInstallFailed( QString ) ) );
@@ -51,6 +52,15 @@ AccountModel::AccountModel( QObject* parent )
loadData();
}
void
AccountModel::atticaLoaded()
{
m_waitingForAtticaLoaded = false;
loadData();
}
void
AccountModel::loadData()
{
@@ -644,7 +654,8 @@ AccountModel::accountAdded( Account* account )
if ( ResolverAccount* resolver = qobject_cast< ResolverAccount* >( account ) )
{
qDebug() << "Plain old manual resolver added, appending at end";
Q_ASSERT( qobject_cast< AtticaResolverAccount* >( account ) == 0 ); // should NOT get attica accounts here, should be caught above
if ( !m_waitingForAtticaLoaded )
Q_ASSERT( qobject_cast< AtticaResolverAccount* >( account ) == 0 ); // should NOT get attica accounts here, should be caught above
const int count = m_accounts.size();
beginInsertRows( QModelIndex(), count, count );
m_accounts << new AccountModelNode( resolver );

View File

@@ -100,6 +100,7 @@ signals:
void errorInstalling( const QPersistentModelIndex& idx );
private slots:
void atticaLoaded();
void loadData();
void accountAdded( Tomahawk::Accounts::Account* );
@@ -112,6 +113,7 @@ private slots:
private:
QModelIndex indexForAtticaId( const QString& resolverId ) const;
bool m_waitingForAtticaLoaded;
QList< AccountModelNode* > m_accounts;
QSet< QString > m_waitingForAtticaInstall;
};

View File

@@ -26,6 +26,7 @@
#include <attica/content.h>
#include <QObject>
#include <QSet>
namespace Tomahawk {
class ExternalResolverGui;

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