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

Compare commits

...

567 Commits
0.8.3 ... qmlng

Author SHA1 Message Date
Michael Zanetti
23b477da19 revert back to static model for genre tag cloud 2013-08-04 22:29:44 +02:00
Michael Zanetti
1131840a23 added a completion list to InputField, use it for all genres input field 2013-08-04 22:27:53 +02:00
Michael Zanetti
439730ee8a changed startByGenre to according to the mockup 2013-08-04 21:38:44 +02:00
Michael Zanetti
745bbb8afb don't show save button while on page 1 2013-08-04 20:44:31 +02:00
Michael Zanetti
6198d55940 tweak input bubble a little 2013-08-04 20:41:48 +02:00
Michael Zanetti
9886a15760 change artist selection to according to design mockup 2013-08-04 20:41:29 +02:00
Michael Zanetti
ec6ec7833f fix inputbubble 2013-08-04 18:32:46 +02:00
Michael Zanetti
0b4c3cde67 Station is now a CoverFlow instead of a CoverFlip 2013-08-04 18:13:52 +02:00
Michael Zanetti
eb84ddc699 Merge branch 'qmlng' of github.com:tomahawk-player/tomahawk into qmlng
Conflicts:
	src/libtomahawk/playlist/PlayableModel.cpp
	src/tomahawk/sourcetree/SourcesModel.cpp
2013-07-19 00:45:22 +02:00
Michael Zanetti
26f581dc97 some more work on saving stations 2013-07-18 15:49:33 +02:00
Michael Zanetti
cee26a77c3 adjust station summaries to look the same everywhere 2013-07-18 15:49:33 +02:00
Michael Zanetti
d65de01847 fix loading state 2013-07-18 15:49:33 +02:00
Michael Zanetti
c161d5dc3d also add a description for byStation 2013-07-18 15:49:33 +02:00
Michael Zanetti
1d9b76efbc station summary does something again, at least for stations by artist 2013-07-18 15:49:33 +02:00
Christian Muehlhaeuser
6bb9ec7de3 * Fixed startFromGenre. 2013-07-18 15:49:33 +02:00
Michael Zanetti
53ba4aae93 generate does the real thing again 2013-07-18 15:49:33 +02:00
Christian Muehlhaeuser
952120a260 * Create EchonestParams out of the variant list. 2013-07-18 15:49:32 +02:00
Christian Muehlhaeuser
490f736a93 * Print out controls when creating a station. 2013-07-18 15:49:32 +02:00
Christian Muehlhaeuser
a4fee407a4 * Create those darned controls manually. 2013-07-18 15:49:32 +02:00
Christian Muehlhaeuser
6378a1658d * Fixed invoke. 2013-07-18 15:49:32 +02:00
Christian Muehlhaeuser
59003b88e9 * Show save button when we have a configured station. 2013-07-18 15:49:32 +02:00
Christian Muehlhaeuser
c946bd9b8d * Fixed displaying of back / save button. 2013-07-18 15:49:32 +02:00
Christian Muehlhaeuser
02f8eac1b3 * Radio mode needs to initialize a temporary station. 2013-07-18 15:49:32 +02:00
Christian Muehlhaeuser
75a1fce2d8 * Create dynamic playlist when needed - for temporary ones. 2013-07-18 15:49:32 +02:00
Christian Muehlhaeuser
a7152f83f4 * Style fix. 2013-07-18 15:49:32 +02:00
Michael Zanetti
6ab35323e8 more cleanup 2013-07-18 15:49:32 +02:00
Michael Zanetti
b402347bee fix playlist generation and clean up dynamicqmlwidget a bit 2013-07-18 15:49:32 +02:00
Michael Zanetti
1252b6618d fix merge 2013-07-18 15:49:32 +02:00
Uwe L. Korn
ff8e905599 Only setup a Connection once 2013-07-18 15:49:32 +02:00
Uwe L. Korn
cf93741079 Keep lazy offers lazy 2013-07-18 15:49:32 +02:00
Uwe L. Korn
45519110b9 Only match duplicates on inbound Connections 2013-07-18 15:49:32 +02:00
Uwe L. Korn
33cca96f00 Connections should be started in the thread they live 2013-07-18 15:49:32 +02:00
Teo Mrnjavac
8e0dcc69ed Update README.md 2013-07-18 15:49:32 +02:00
Uwe L. Korn
7f8bb31e23 Set nodeId on lazy offers 2013-07-18 15:49:31 +02:00
Uwe L. Korn
15704d8fbf Unbind from source if we are not responsible for it 2013-07-18 15:49:31 +02:00
Christian Muehlhaeuser
1554b638f6 * More debug output in DbCmd_SetPlaylistRevision. 2013-07-18 15:49:31 +02:00
Uwe L. Korn
7219f1035a Add Network Activity to ChangeLog 2013-07-18 15:49:31 +02:00
Dominik Schmidt
cb3889f37e Few minor fixes/improvements for Windows installer 2013-07-18 15:49:31 +02:00
Tomahawk CI
6ad4a8ce76 Automatic merge of Transifex translations 2013-07-18 15:49:31 +02:00
Uwe L. Korn
fbc8803c37 Don't try to acquire lock if we do not have a source anymore. 2013-07-18 15:49:31 +02:00
Uwe L. Korn
0be198fc49 Make selection of ControlConnection symmetric 2013-07-18 15:49:31 +02:00
Uwe L. Korn
4998852e5a Revert "Only display filename in JS resolver errors/as scriptname"
This reverts commit a6459f2823.
2013-07-18 15:49:31 +02:00
Uwe L. Korn
179dac3442 Only display filename in JS resolver errors/as scriptname
* The paths are internal ones
* Shortens error messages for JS resolvers so that they will most likely not 
   overflow anymore
2013-07-18 15:49:31 +02:00
Uwe L. Korn
22aa75f4bb Export JobStatusView 2013-07-18 15:49:31 +02:00
Uwe L. Korn
b0e352a5f5 Generate QxtSslServer fancy header 2013-07-18 15:49:31 +02:00
Uwe L. Korn
d41a9d8dce Update Qxt 2013-07-18 15:49:31 +02:00
Uwe L. Korn
f742066a7e Ensure that Servent still runs on all IPs with Qt 5.0 2013-07-18 15:49:31 +02:00
Uwe L. Korn
419a3f1cd2 Prefix HTTP API v1.0 members 2013-07-18 15:49:30 +02:00
Uwe L. Korn
a381c5e3f1 Use strongRef where strongRef requested 2013-07-18 15:49:30 +02:00
Uwe L. Korn
04e5b338c4 Add comment to prevent others from doing the same mistake 2013-07-18 15:49:30 +02:00
Uwe L. Korn
7daebc655a Performance++, Memory-- 2013-07-18 15:49:30 +02:00
Uwe L. Korn
546f54f196 Make WeakPeerHash more generic 2013-07-18 15:49:30 +02:00
Uwe L. Korn
cde07bc2b8 Write --verbose output to Tomahawk.log 2013-07-18 15:49:30 +02:00
Uwe L. Korn
09026a33fe Debug spam++ 2013-07-18 15:49:30 +02:00
Tomahawk CI
b4de7d6e90 Automatic merge of Transifex translations 2013-07-18 15:49:30 +02:00
Christian Muehlhaeuser
be364d582a * Added xhochy to AUTHORS / about-dialog. 2013-07-18 15:49:30 +02:00
Uwe L. Korn
1b1b88551d Improve Includes in ExternalResolvers.h 2013-07-18 15:49:30 +02:00
Uwe L. Korn
8d80b1e113 Improve includes in Resolver.h 2013-07-18 15:49:30 +02:00
Uwe L. Korn
9fa387e102 Dpointer JSResolver 2013-07-18 15:49:30 +02:00
Uwe L. Korn
7b6987418c Move implementations out of the header 2013-07-18 15:49:29 +02:00
Uwe L. Korn
2dac747a90 Remove unneed includes out of JSResolver.h 2013-07-18 15:49:29 +02:00
Uwe L. Korn
402a7ed6d4 Move JSResolverHelper to its own files 2013-07-18 15:49:29 +02:00
Uwe L. Korn
0403301c9a Move ScriptEngine into its own files 2013-07-18 15:49:29 +02:00
Tomahawk CI
10712c7efb Automatic merge of Transifex translations 2013-07-18 15:49:29 +02:00
Uwe L. Korn
1c62ec3358 Delete AudioEngine after MainWindow 2013-07-18 15:49:29 +02:00
Teo Mrnjavac
612d8874df Don't output secrets in log. 2013-07-18 15:49:29 +02:00
Teo Mrnjavac
56dd8e2572 Stay insecure if there's no other way. 2013-07-18 15:49:29 +02:00
Teo Mrnjavac
3adeee4140 Debug spam++ 2013-07-18 15:49:29 +02:00
Christian Muehlhaeuser
d829389e4e * Filter out tracks with bogus mtime when trying to load recent albums. 2013-07-18 15:49:29 +02:00
Christian Muehlhaeuser
1ecfc8aa9e * Load recent albums when SourceList is ready. 2013-07-18 15:49:29 +02:00
Christian Muehlhaeuser
a4505930b5 * Changed tomahawkLoaded handling. 2013-07-18 15:49:29 +02:00
Christian Muehlhaeuser
a6f8dc1830 * Get rid of passing tomahawkLoaded signal through TomahawkWindow and ViewManager. 2013-07-18 15:49:29 +02:00
Uwe L. Korn
ec17293d3d Do not queue ACL result if there are no sipInfos
* Temporary fix until nodeId is moved/refactored into PeerInfo out of SipInfo
2013-07-18 15:49:28 +02:00
Christian Muehlhaeuser
00e8d25da6 Revert "Put "out of %1" under the big number in StatsGauge"
This reverts commit 5634f5a4ca.
2013-07-18 15:49:28 +02:00
Lasse Liehu
483fa38f7b Put "out of %1" under the big number in StatsGauge
"[number]\nout of %1" flows better than "out of %1\n[number]".
2013-07-18 15:49:28 +02:00
Tomahawk CI
193d4b6a96 Automatic merge of Transifex translations 2013-07-18 15:49:28 +02:00
Christian Muehlhaeuser
ef00f9c21a This breaks too many things: Revert "Some dashboard design tweaks"
This reverts commit 22ce38adbb.
2013-07-18 15:49:28 +02:00
Christian Muehlhaeuser
42c0199f53 * Fixed incompatible signal/slot types. 2013-07-18 15:49:28 +02:00
Jason Herskowitz
61a99449f3 Some dashboard design tweaks 2013-07-18 15:49:28 +02:00
Christian Muehlhaeuser
6ed0879c7c * Respect results' online state when displaying. 2013-07-18 15:49:28 +02:00
Christian Muehlhaeuser
53ad9739ad * Query's resoltSorter needs to take into account the result's online state. 2013-07-18 15:49:28 +02:00
Christian Muehlhaeuser
8e48956c87 * Result now always returns the actual score regardless of the online state. 2013-07-18 15:49:28 +02:00
Christian Muehlhaeuser
776b1c9f2e * Pipeline only becomes ready when Database is entirely finished with init. 2013-07-18 15:49:28 +02:00
Christian Muehlhaeuser
42c03fd9ba * Don't emit Database::ready() just because the FuzzyIndex became ready. 2013-07-18 15:49:28 +02:00
Christian Muehlhaeuser
7a2d1cadec * Make sure JSResolver always has at least the default resolver icon set. 2013-07-18 15:49:28 +02:00
Christian Muehlhaeuser
21beba0881 * Style fixes. 2013-07-18 15:49:28 +02:00
Christian Muehlhaeuser
277edfe8ca * Don't reset the resolver's icon if we couldn't retrieve one in ResolverAccount. 2013-07-18 15:49:27 +02:00
Tomahawk CI
e48b4096b9 Automatic merge of Transifex translations 2013-07-18 15:49:27 +02:00
Tomahawk CI
0db80a9a61 Automatic merge of Transifex translations 2013-07-18 15:49:27 +02:00
Uwe L. Korn
e0bff794ab Fix slot/signal namespacing 2013-07-18 15:49:27 +02:00
Jason Herskowitz
47fc81b8c0 Don't forget to replace Fauna font on Album pages too. 2013-07-18 15:49:27 +02:00
Jason Herskowitz
c002eaf11c Try a different label font since Fauna One wasn't so great on Windows 2013-07-18 15:49:27 +02:00
Jeff Mitchell
c21de815a6 Re-mark proxy changes as needing restart 2013-07-18 15:49:27 +02:00
Jeff Mitchell
97da93afd5 Fix compiler warning 2013-07-18 15:49:27 +02:00
Uwe L. Korn
4002716159 Loosen destructor calls and empty source_ptr instead of deleting it. 2013-07-18 15:49:27 +02:00
Tomahawk CI
ab882608d8 Automatic merge of Transifex translations 2013-07-18 15:49:27 +02:00
Christian Muehlhaeuser
aad713d638 * Fixed compiling Hatchet. 2013-07-18 15:49:26 +02:00
Dominik Schmidt
a5f1e63ae3 Allow to set icon and text for externally added generic page items without instantiating them (aka fix lazy loading for vsxu widget) 2013-07-18 15:49:26 +02:00
Dominik Schmidt
be67d85f91 Revert "Add icon() method to ViewPage api and use that and title() for sidebar items"
We can't lazy load the page when we need its members to show the sidebar
entry...

This reverts commit 1821b24391c33b2ea14fc0d094142395588075d9.
2013-07-18 15:49:26 +02:00
Dominik Schmidt
3debc10943 Clean up 2013-07-18 15:49:26 +02:00
Dominik Schmidt
68812eb3a5 Add icon() method to ViewPage api and use that and title() for sidebar items 2013-07-18 15:49:26 +02:00
Uwe L. Korn
257395a1fe Pimple ControlConnection 2013-07-18 15:49:26 +02:00
Dominik Schmidt
a928833373 Use XInitThreads() on X11 to enable loading the visualizer module 2013-07-18 15:49:26 +02:00
Dominik Schmidt
6b69e50731 Explicitly hide inactive view pages 2013-07-18 15:49:26 +02:00
Uwe L. Korn
8817aa65c4 Pimple Msg 2013-07-18 15:49:26 +02:00
Uwe L. Korn
e5b418ac24 More include cleanups 2013-07-18 15:49:26 +02:00
Dominik Schmidt
63a3339ca5 Add generic page item for new view pages 2013-07-18 15:49:26 +02:00
Uwe L. Korn
8128f1ea48 Clean up headers 2013-07-18 15:49:26 +02:00
Uwe L. Korn
e0a6331142 Pimple BufferIoDevice 2013-07-18 15:49:26 +02:00
Uwe L. Korn
68448db757 No need for QObject on Private classes 2013-07-18 15:49:26 +02:00
Dominik Schmidt
eaf1b58df6 Remove stub page from ViewManager implementation 2013-07-18 15:49:25 +02:00
Teo Mrnjavac
187602c424 GenericPageItem insertion fixage. 2013-07-18 15:49:25 +02:00
Dominik Schmidt
426dd354eb Move stub page adding from appendGroups to SourcesModel ctor 2013-07-18 15:49:25 +02:00
Dominik Schmidt
cb5916b42a Use QList < ViewPage* > in ViewManager to store simple view pages 2013-07-18 15:47:05 +02:00
Dominik Schmidt
4b29d34278 Add stub page to pull out again 2013-07-18 15:47:05 +02:00
Uwe L. Korn
67fc355f16 No more warnings in tomahawk code 2013-07-18 15:47:05 +02:00
Uwe L. Korn
ace775d6a6 Fight all compiler warnings in libtomahawk 2013-07-18 15:47:05 +02:00
Uwe L. Korn
4d43577eda Add missing include 2013-07-18 15:47:05 +02:00
Uwe L. Korn
8f7e2f1f8a Move includes from global headers into local .cpp 2013-07-18 15:47:05 +02:00
Uwe L. Korn
96f28f53ce Move implementations out of the header 2013-07-18 15:47:05 +02:00
Uwe L. Korn
c2b54683d3 Remove not needed includes in Query.h 2013-07-18 15:47:04 +02:00
Uwe L. Korn
5afc5b0909 Remove not needed includes 2013-07-18 15:47:04 +02:00
Uwe L. Korn
54e8ee172b Add missing include for OSX 2013-07-18 15:47:04 +02:00
Uwe L. Korn
ceb856acb2 Finish Connection pimpeling 2013-07-18 15:47:04 +02:00
Uwe L. Korn
69c2d603b8 Make access to Connection->nodeid thread-safe 2013-07-18 15:47:04 +02:00
Uwe L. Korn
bd0c3e29eb If a ControlConnection is not anymore responsible for a source, it should not touch it. 2013-07-18 15:47:04 +02:00
Uwe L. Korn
bfd5690af7 Move outbound, ready, onceonly into ConnectionPrivate 2013-07-18 15:47:04 +02:00
Christian Muehlhaeuser
6e91080311 * Fixed compiling. 2013-07-18 15:47:04 +02:00
Tomahawk CI
ed5cb1d93d Automatic merge of Transifex translations 2013-07-18 15:47:04 +02:00
Uwe L. Korn
1a5406bd44 Pimple SipStatusMessage 2013-07-18 15:47:04 +02:00
Uwe L. Korn
5bf09cced0 Rename Tomahawk::ACL -> Tomahawk::ACLStatus 2013-07-18 15:47:03 +02:00
Uwe L. Korn
bf48967305 Less (global) includes in/of SipPlugin.h 2013-07-18 15:47:03 +02:00
Uwe L. Korn
611b108eb9 Move peerport and msg into ConnectionPrivate 2013-07-18 15:47:03 +02:00
Uwe L. Korn
7efa2fd781 Tomahawk::ACL -> Tomahawk::ACL::Type 2013-07-18 15:47:03 +02:00
Uwe L. Korn
70706c9eb1 Move m_name into ConnectionPrivate 2013-07-18 15:47:03 +02:00
Uwe L. Korn
aaf4ced6db Remove not needed ControlConnection include 2013-07-18 15:47:03 +02:00
Uwe L. Korn
34196ec001 Pimple Source, remove some headers from Source.h and Connection.h 2013-07-18 15:47:03 +02:00
Uwe L. Korn
3d33c68778 Move all implementations out of the header 2013-07-18 15:47:03 +02:00
Uwe L. Korn
bf5fcbd0b6 Remove unused include 2013-07-18 15:47:03 +02:00
Uwe L. Korn
2ee369393c Unprefix Qt includes 2013-07-18 15:47:03 +02:00
Jason Herskowitz
8824466840 More padding in breadcrumb. Don't yet know how to make font bigger. 2013-07-18 15:47:03 +02:00
Uwe L. Korn
d62bd306be Remove unused qjson includes and member 2013-07-18 15:47:03 +02:00
Uwe L. Korn
29ba51b32c Move private members of Connection into a Dpointer 2013-07-18 15:47:03 +02:00
Uwe L. Korn
f074d4dea7 Set nodeid directly, not as a property 2013-07-18 15:47:03 +02:00
Christian Muehlhaeuser
53e03f90e7 * Draw a horizontal splitter. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
feaaa6c7cd * Adjust the splitter handle width. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
f79744fb72 * FlexibleView's GridView looks nicer with black background. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
18d38f5a46 * Change AudioEngine's state before emitting the signal. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
df4aa8ce13 * Trim the artist biography before showing it. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
d6fd70f1f1 * Fixed HistoryWidget's header color. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
9d90c07b70 * Dashboard should use the vanilla InfoBar. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
bb69caed62 * Made deprecated InfoBar look the same as the other headers. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
5300ddae2c * New layout for search page. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
4be8717525 * Set captions to non-bold in .ui. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
30447cee2b * Set captions to non-bold in .ui. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
b2db38db09 * Fixed inbox header color. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
74972ca5e1 * Removed .ui font definitions. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
36ae09b698 * New layout for Dashboard. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
06dca3111f * Nitpicky fix. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
10cb39dd2e * Fixed albums area on artist page growing too big. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
5678f61211 * New layout for Album page. 2013-07-18 15:47:02 +02:00
Christian Muehlhaeuser
1d74242670 * Clean up for Artist page. 2013-07-18 15:47:01 +02:00
Christian Muehlhaeuser
ff08efbdf8 * Clean up for Track page. 2013-07-18 15:47:01 +02:00
Christian Muehlhaeuser
d1e97b1dec * Moved Track page's font definitions to .ui file. 2013-07-18 15:47:01 +02:00
Christian Muehlhaeuser
4145bf14f8 * Fixed Artist page's header size and moved font definitions to .ui file. 2013-07-18 15:47:01 +02:00
Jason Herskowitz
1af86b3257 More font size tweaks 2013-07-18 15:47:01 +02:00
Tomahawk CI
8f7671ae65 Automatic merge of Transifex translations 2013-07-18 15:47:01 +02:00
Jason Herskowitz
5b3c297306 Update all the Spotify icons to their new logo, except the one in the resolvers which is apparently the only one that matters. 2013-07-18 15:47:01 +02:00
Jason Herskowitz
c014650628 Fix track number color 2013-07-18 15:47:01 +02:00
Thierry Goeckel
dd28657dbc Remove newline. 2013-07-18 15:47:01 +02:00
Thierry Goeckel
9b53ffc952 Style fix. 2013-07-18 15:47:01 +02:00
Jason Herskowitz
508c7ffc80 Bump up bio font a couple of point sizes 2013-07-18 15:47:01 +02:00
Thierry Goeckel
088d7ed3ae Don't sort alphabetically here. Makes sense as it is in the source code (week->month->year->overall).
Now someone make week the default. :p
2013-07-18 15:47:00 +02:00
Jason Herskowitz
4926fcb239 Pretty up the gauge a bit more 2013-07-18 15:47:00 +02:00
Jason Herskowitz
c66300aa67 More artist & track design plus some updated placeholder icons 2013-07-18 15:47:00 +02:00
Jason Herskowitz
5fa5532fd2 Unbreak OSX 2013-07-18 15:47:00 +02:00
Uwe L. Korn
0be6ec1a40 Remove unneeded include 2013-07-18 15:47:00 +02:00
Uwe L. Korn
776c919445 Correctly handle/display the different states of PeerInfos 2013-07-18 15:47:00 +02:00
Uwe L. Korn
6bf5d70b5c Use deleteLater so that peerinfo_ptr can be used in different threads. 2013-07-18 15:47:00 +02:00
Christian Muehlhaeuser
e7eea28d84 * Fixed page fonts. 2013-07-18 15:47:00 +02:00
Jason Herskowitz
60ad0a016f More Artist page design. 2013-07-18 15:47:00 +02:00
Christian Muehlhaeuser
786a5f4cd5 * Fixed ModeHeader's background color. 2013-07-18 15:47:00 +02:00
Christian Muehlhaeuser
2203c7afcb * Fixed Track page. 2013-07-18 15:47:00 +02:00
Christian Muehlhaeuser
ac5774a486 * Set the proper background color for the albums grid on the Artist page. 2013-07-18 15:47:00 +02:00
Christian Muehlhaeuser
3df5ab3a41 * Got rid of cover shadow / gradient. 2013-07-18 15:47:00 +02:00
Uwe L. Korn
ea7a21518d Only invoke Closure if receiver still exists 2013-07-18 15:47:00 +02:00
Christian Muehlhaeuser
82705f63f7 * Moved highlight color roles into TomahawkStyle. 2013-07-18 15:47:00 +02:00
Christian Muehlhaeuser
6e84706d3e * Use QPalette::Foreground for drawing AlbumItemDelegate's position figure. 2013-07-18 15:47:00 +02:00
Christian Muehlhaeuser
0e5e4e96e5 * Use new color roles on Artist page. 2013-07-18 15:46:59 +02:00
Christian Muehlhaeuser
d875b8dccf * StatsGauge retrieves color palette from TomahawkStyle. 2013-07-18 15:46:59 +02:00
Christian Muehlhaeuser
99eae3c542 * Fixed TomahawkUtils::prepareStyleOption(). 2013-07-18 15:46:59 +02:00
Christian Muehlhaeuser
2781fafdf4 * Added new color roles to TomahawkStyle. 2013-07-18 15:46:59 +02:00
Uwe L. Korn
1b9b706fce Keep a local strong reference to prevent deleting of the current object 2013-07-18 15:46:59 +02:00
Uwe L. Korn
2066214aef Do not rely on the object to be removed to be deleted after the callback 2013-07-18 15:46:59 +02:00
Christian Muehlhaeuser
0492bbded4 * A few more tweaks to artist page. 2013-07-18 15:46:59 +02:00
Tomahawk CI
865b7db1b8 Automatic merge of Transifex translations 2013-07-18 15:46:59 +02:00
Christian Muehlhaeuser
13c87e0acc * Fixed link color in header. 2013-07-18 15:46:59 +02:00
Christian Muehlhaeuser
42640ef259 * WIP: Artist page. 2013-07-18 15:46:59 +02:00
Christian Muehlhaeuser
aa5e0fcecb * Got rid of obsolete TomahawkStyle colors. 2013-07-18 15:46:59 +02:00
Christian Muehlhaeuser
6166eac485 * Cleaned up TomahawkStyle. 2013-07-18 15:46:59 +02:00
Christian Muehlhaeuser
0aade324ad * Added regular version of Titillium as resource. 2013-07-18 15:46:58 +02:00
Jason Herskowitz
d302850d51 Use a font that also has bold. WIP. 2013-07-18 15:46:58 +02:00
Jason Herskowitz
d2f9d2d79c A bunch of styling to the Arist Page. WIP. 2013-07-18 15:46:58 +02:00
Christian Muehlhaeuser
ae8ddb2144 * Use TomahawkStyle::HEADER_TEXT for captions. 2013-07-18 15:46:58 +02:00
Christian Muehlhaeuser
d833f5fef2 * Use Titillium Web for the labels on ArtistInfoWidget. 2013-07-18 15:46:58 +02:00
Christian Muehlhaeuser
8c671568bb * Load fonts on startup. 2013-07-18 15:46:58 +02:00
Christian Muehlhaeuser
7a4e4410a1 * TomahawkStyle::loadFonts() auto-loads all fonts in the data/fonts/ resource. 2013-07-18 15:46:58 +02:00
Christian Muehlhaeuser
df56877403 * Added example ttf font. 2013-07-18 15:46:58 +02:00
Christian Muehlhaeuser
e27396be63 * Further tweaks to artist-page layout. 2013-07-18 15:46:58 +02:00
Christian Muehlhaeuser
082d86a127 * Style fixes. 2013-07-18 15:46:58 +02:00
Christian Muehlhaeuser
1e89558c78 * Make boxes entirely transparent. 2013-07-18 15:46:58 +02:00
Christian Muehlhaeuser
af5fe4b965 * When a track starts playing, check if we need to update the sidebar's speaker-icon. 2013-07-18 15:46:58 +02:00
Christian Muehlhaeuser
bd4e19fa32 * Implemented LovedTracksItem's isBeingPlayed(). 2013-07-18 15:46:58 +02:00
Christian Muehlhaeuser
d8311c0e41 * Style fixes in GenericPageItems. 2013-07-18 15:46:58 +02:00
Christian Muehlhaeuser
555d3587d7 * Style fixes in SourcesModel. 2013-07-18 15:46:58 +02:00
Christian Muehlhaeuser
0cf881359c * Style fixes in SourceTreeView. 2013-07-18 15:46:58 +02:00
Christian Muehlhaeuser
63ee2cbd59 * Implemented Flexible(Tree)View's isBeingPlayed(). 2013-07-18 15:46:58 +02:00
Christian Muehlhaeuser
a59971a74a * Emit a signal when the currentTrackPlaylist changes in AudioEngine. 2013-07-18 15:46:57 +02:00
Christian Muehlhaeuser
7723cade58 * Removed obsolete png. 2013-07-18 15:46:57 +02:00
Christian Muehlhaeuser
815ec7cbe2 * Use TomahawkStyle's methods to apply stylesheets. 2013-07-18 15:46:57 +02:00
Christian Muehlhaeuser
022efd5503 * Moved stylesheet methods into TomahawkStyle. 2013-07-18 15:46:57 +02:00
Tomahawk CI
81d2278857 Automatic merge of Transifex translations 2013-07-18 15:46:57 +02:00
Christian Muehlhaeuser
8dc56abbf6 * Fixed RecentPlaylistsModel not respecting the set limit. 2013-07-18 15:46:57 +02:00
Christian Muehlhaeuser
a95276d960 * Auto-resize PlaylistWidget. 2013-07-18 15:46:57 +02:00
Christian Muehlhaeuser
f4bd8959e1 * Make hover-glow subtler. 2013-07-18 15:46:57 +02:00
Christian Muehlhaeuser
2b6da82805 * Give Dashboard a header. 2013-07-18 15:46:57 +02:00
Christian Muehlhaeuser
9cc6c1fb35 * Tweak page and header colors. 2013-07-18 15:46:57 +02:00
Christian Muehlhaeuser
cc62a458f5 * Draw divider below BasicHeader. 2013-07-18 15:46:57 +02:00
Christian Muehlhaeuser
b2ac6acb6e * Show 'kbps' next to the bitrate. 2013-07-18 15:46:57 +02:00
Christian Muehlhaeuser
a883c7135f * Fixed HistoryWidget's extra header. 2013-07-18 15:46:57 +02:00
Christian Muehlhaeuser
ff007d8595 * Make FlexibleView use new header style - to be consolidated. 2013-07-18 15:46:56 +02:00
Christian Muehlhaeuser
a0b7c6e504 * Init FilterHeader with parent. 2013-07-18 15:46:56 +02:00
Christian Muehlhaeuser
da8fd58aaa * Re-enable TreeView for collections. 2013-07-18 15:46:56 +02:00
Christian Muehlhaeuser
3ef99fbb32 * FlexibleHeader needs to set its own size. 2013-07-18 15:46:56 +02:00
Christian Muehlhaeuser
0f45146ada * Compact BasicHeader. 2013-07-18 15:46:56 +02:00
Christian Muehlhaeuser
bcd33932d0 * Added ModeHeader widget. 2013-07-18 15:46:56 +02:00
Christian Muehlhaeuser
4ea22ba054 * Show a default track cover until we retrieved the proper, new one. 2013-07-18 15:46:56 +02:00
Christian Muehlhaeuser
8ac833bf97 * Double-clicking in ColumnView opens the corresponding page. 2013-07-18 15:46:56 +02:00
Christian Muehlhaeuser
7b62c3ed14 * A few ColumnItemDelegate fixes. 2013-07-18 15:46:56 +02:00
Christian Muehlhaeuser
5c2cebb423 * Don't show empty labels in preview-widget. 2013-07-18 15:46:56 +02:00
Christian Muehlhaeuser
e8a48aafe4 * Show more info in the preview-widget. 2013-07-18 15:46:56 +02:00
Christian Muehlhaeuser
d2f8bc2784 * Removed header from ColumnView. 2013-07-18 15:46:56 +02:00
Christian Muehlhaeuser
447c6c0217 * Reset the model before applying a filter. 2013-07-18 15:46:56 +02:00
Christian Muehlhaeuser
d098c1cba7 * Use FlexibleTreeViews for showing collections. 2013-07-18 15:46:56 +02:00
Christian Muehlhaeuser
53bdd2de6b * Updated CMakeLists.txt. 2013-07-18 15:46:20 +02:00
Christian Muehlhaeuser
d590fa4faa * Added FlexibleTreeView. 2013-07-18 15:46:20 +02:00
Christian Muehlhaeuser
95e6efd26d * Added ColumnViewPreviewWidget. 2013-07-18 15:46:20 +02:00
Christian Muehlhaeuser
7f64f25e59 * Added ColumnView. 2013-07-18 15:46:20 +02:00
Christian Muehlhaeuser
812ca58674 * Added ColumnItemDelegate. 2013-07-18 15:46:20 +02:00
Christian Muehlhaeuser
a2406e8595 * Disconnect from previous query correctly. 2013-07-18 15:46:19 +02:00
Christian Muehlhaeuser
88dfad3298 * Style fix. 2013-07-18 15:46:19 +02:00
Christian Muehlhaeuser
fc4e42befa * Added custom UserRoles to access model's data. 2013-07-18 15:46:19 +02:00
Christian Muehlhaeuser
db56757bc8 * PlayableItem::forceUpdate() forces a repaint by emitting dataChanged(). 2013-07-18 15:41:38 +02:00
Christian Muehlhaeuser
2d6b8de76b * Caution for upcoming changes. 2013-07-18 15:41:38 +02:00
Christian Muehlhaeuser
81a406d1b5 * Style fixes for Servent. 2013-07-18 15:41:38 +02:00
Tomahawk CI
b3b47398bc Automatic merge of Transifex translations 2013-07-18 15:41:38 +02:00
Tomahawk CI
ddb66a5cfe Automatic merge of Transifex translations 2013-07-18 15:41:38 +02:00
Uwe L. Korn
b3dc65997c Do not squash Peers with no nodeid 2013-07-18 15:41:38 +02:00
Uwe L. Korn
d800323afe Do not try to access NULL-pointers instead search the whole hash for holes 2013-07-18 15:41:38 +02:00
Hugo Lindström
980f56dbcf TWK-1389: Utilize private sessions, if private 2013-07-18 15:41:38 +02:00
Hugo Lindström
587568e026 TWK-1377: Space Encoding on Imported M3Us 2013-07-18 15:41:38 +02:00
Hugo Lindström
18d488b0f1 Stylefix 2013-07-18 15:41:38 +02:00
Uwe L. Korn
aafab2e016 Group peers by (Account, nodeid) in the Diagnostics Dialog, add nodeid info 2013-07-18 15:41:38 +02:00
Uwe L. Korn
0a4a281027 Move all sockets to the Servent thread. 2013-07-18 15:41:38 +02:00
Uwe L. Korn
c248ebb9e0 Speed up connecting by sorting the SipInfos 2013-07-18 15:41:38 +02:00
Uwe L. Korn
251ed6e555 Documentation++, make ConnectionManager CTOR private 2013-07-18 15:41:37 +02:00
Uwe L. Korn
2555ab7766 Better debug spam on column restore 2013-07-18 15:41:37 +02:00
Christian Muehlhaeuser
d14afb5a8f * Tweak timeouts for the lazy-lists drop-down. 2013-07-18 15:41:37 +02:00
Christian Muehlhaeuser
ca025e41b0 * Style fixes. 2013-07-18 15:41:37 +02:00
Uwe L. Korn
ca307d6922 Do not kill used ControlConnection
* Debug spam ++
2013-07-18 15:41:37 +02:00
Christian Muehlhaeuser
0d2dade6da * Don't print out cache-value in log. 2013-07-18 15:41:37 +02:00
Christian Muehlhaeuser
241a3a075b * Delegates use the base-class impls for painting / handling. 2013-07-18 15:41:37 +02:00
Christian Muehlhaeuser
1a88203247 * Views handle leaveEvents now and inform the delegate to update itself when required. 2013-07-18 15:41:37 +02:00
Christian Muehlhaeuser
d6bb90fc25 * Handle source-icon and info-icon painting in the base delegate class. 2013-07-18 15:41:37 +02:00
Christian Muehlhaeuser
f5dc808d4c * Use TrackView's setPlaylistItemDelegate across Tomahawk. 2013-07-18 15:41:37 +02:00
Christian Muehlhaeuser
27879a814e * Moved some page-impl out of the headers. 2013-07-18 15:41:37 +02:00
Christian Muehlhaeuser
cc9687c407 * Fixed secondary text's color in PlaylistDelegate & PlaylistLargeItemDelegate. 2013-07-18 15:41:37 +02:00
Tomahawk CI
9f9d01618e Automatic merge of Transifex translations 2013-07-18 15:41:37 +02:00
Uwe L. Korn
ce10b501a8 Copy internal hash instead of trying to make a non-valid assignment 2013-07-18 15:41:37 +02:00
Uwe L. Korn
d52333893f Self cleaning peerInfo cache, fixes TWK-1396 2013-07-18 15:41:37 +02:00
Uwe L. Korn
6216ab1a79 No need for a pointer here 2013-07-18 15:41:37 +02:00
Uwe L. Korn
d3f32f73c9 Proxy the QtConncurrent call to a static function to preserve a strong ref 2013-07-18 15:41:36 +02:00
Uwe L. Korn
c3eca392f2 Less strong refs to ConnectionManagers if they are not used 2013-07-18 15:41:36 +02:00
Uwe L. Korn
0f82e54f2a Reconnect if ACL decision took too long 2013-07-18 15:41:36 +02:00
Christian Muehlhaeuser
482b0288e7 * Fixed coding style in AudioEngine. 2013-07-18 15:41:36 +02:00
Tomahawk CI
7597dd5554 Automatic merge of Transifex translations 2013-07-18 15:41:36 +02:00
Uwe L. Korn
a2b20fa49e Remove unused defines 2013-07-18 15:41:36 +02:00
Uwe L. Korn
1227d40c26 Lazyload Network Activities 2013-07-18 15:41:36 +02:00
Christian Muehlhaeuser
090cc66fc7 * Moved artist / track labels out of the PlayableCover. 2013-07-18 15:41:36 +02:00
Christian Muehlhaeuser
d13f3f3c45 * Don't consider artists with a playcount of 1 as part of the charts. 2013-07-18 15:41:36 +02:00
Christian Muehlhaeuser
f3b660f123 * Don't consider tracks with a playcount of 1 as part of the charts. 2013-07-18 15:41:36 +02:00
Christian Muehlhaeuser
e0ad9d48d8 * Added gauge for track chart position. 2013-07-18 15:41:36 +02:00
Christian Muehlhaeuser
aca0f51342 * Shrink font size for bigger figures. 2013-07-18 15:41:36 +02:00
Christian Muehlhaeuser
252b809fe4 * Expose track stats in Track(-Data). 2013-07-18 15:41:35 +02:00
Christian Muehlhaeuser
4e83dbac2e * Read chart position when loading TrackStats. 2013-07-18 15:41:35 +02:00
Christian Muehlhaeuser
9d92e2689c * Unspectacular performance improvement. 2013-07-18 15:41:35 +02:00
Christian Muehlhaeuser
edd3759126 * Correctly set initial alternating-row-color setting, so we don't rely on the proxymodel activating it for us on filling. 2013-07-18 15:41:35 +02:00
Christian Muehlhaeuser
51e7fb4c18 * Style the extra header a bit. 2013-07-18 15:41:35 +02:00
Christian Muehlhaeuser
9a9fac59e5 * Get rid of the header gradient. 2013-07-18 15:41:35 +02:00
Christian Muehlhaeuser
408d4486d2 * Slightly different tooltips for the gauges. 2013-07-18 15:41:35 +02:00
Christian Muehlhaeuser
45cc595010 * SourceItem now uses HistoryWidget to display recently played tracks of Sources. 2013-07-18 15:41:35 +02:00
Christian Muehlhaeuser
7cd6af4933 * Forgot to add HistoryWidget to CMakeLists.txt. 2013-07-18 15:41:35 +02:00
Christian Muehlhaeuser
d7629ff626 * HistoryWidget is a FlexibleView with date range input fields as an extra header. 2013-07-18 15:41:35 +02:00
Christian Muehlhaeuser
b4ccf7d6ea * RecentlyPlayedModel can now deal with date ranges. 2013-07-18 15:41:35 +02:00
Christian Muehlhaeuser
c4f48abf77 * DbCmd_PlaybackHistory can now deal with date ranges. 2013-07-18 15:41:35 +02:00
Christian Muehlhaeuser
6b36f3a737 * PlayableModel::ensureResolved() passes queries in one batch to the Pipeline now. 2013-07-18 15:41:35 +02:00
Christian Muehlhaeuser
ff0c3d4bef * QueueView waits for the Pipeline to become ready. 2013-07-18 15:41:35 +02:00
Christian Muehlhaeuser
4939ffb6d3 * FlexibleView now can be initialized with an additional header widget. 2013-07-18 15:41:35 +02:00
Christian Muehlhaeuser
8a4caa4118 * Emit a signal when the Pipeline gets started. 2013-07-18 15:41:34 +02:00
Christian Muehlhaeuser
6b7dbedc45 * Extra (optional) CTOR param for RecentlyPlayedModel: maxItems. 2013-07-18 15:41:34 +02:00
Christian Muehlhaeuser
371b8cff0e * Style for the vertical scrollbars. 2013-07-18 15:41:34 +02:00
Christian Muehlhaeuser
ee67518d47 * WelcomeWidget => Dashboard. 2013-07-18 15:41:34 +02:00
Christian Muehlhaeuser
e9c4d8118b * Renamed and pagified Dashboard. 2013-07-18 15:41:34 +02:00
Christian Muehlhaeuser
6b6475f767 * Don't enforce resolving of similar tracks. 2013-07-18 15:41:34 +02:00
Christian Muehlhaeuser
ad40c8efa9 * Style clean up. 2013-07-18 15:41:34 +02:00
Christian Muehlhaeuser
42cf9375a6 * Don't enforce resolving of incoming Artist's top-tracks. 2013-07-18 15:41:34 +02:00
Tomahawk CI
268537bdc6 Automatic merge of Transifex translations 2013-07-18 15:41:34 +02:00
Uwe L. Korn
797fa8d21c Dpointerize PeerInfo 2013-07-18 15:41:34 +02:00
Uwe L. Korn
91df437e62 Dpointerize NetworkActivityWidget 2013-07-18 15:41:34 +02:00
Uwe L. Korn
fe7c1b1d73 Introduce the Dpointer concept to ConnectionManager 2013-07-18 15:41:34 +02:00
Uwe L. Korn
81a9da23da Delete d_ptr in Servent desctructor 2013-07-18 15:41:34 +02:00
Uwe L. Korn
b48b0127f8 Add Boost_INCLUDE_DIR and make less usage of boost in headers
* Make Servent member more private
2013-07-18 15:41:34 +02:00
Christian Muehlhaeuser
da47c00813 * Made StatsGauge animation smooth and use QProgressBar's own inverted state handling. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
7ea790d40b * Fixed a bunch of compiler warnings. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
6af1be8fa7 * Init needs to wait for InfoSystem to be ready. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
5350330141 * InfoSystem now emits ready() when init is done. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
b37e0d801e * Fixed typos. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
84faa1671c * CreateIndex isn't the right place to connect signals. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
530d5402a1 * Fix Logger with Qt5. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
3e06803162 * Fixed creating QPixmaps in the wrong thread. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
3de4042d6e * Fixed Accounts stuff causing QLayout warning. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
004d84f1b0 * Fixed broken png causing libpng warning. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
62db235b3c * Set pen color correctly for Inbox. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
f1483bfe3f * Adapted Track page to new style. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
89202ae445 * Fixed Artist page. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
1e579bc238 * Adapt Album page to new style. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
e11b1515a9 * Offer inverted gauge animations. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
25f2c2db66 * Changed PAGE_BACKGROUND color. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
df7fafced1 * Don't try animating with bogus values. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
e9a33e3ed4 * Start animating the gauge with value 1. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
b5090d2873 * Chart values need to be always initialized. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
86e201673f * Added StatsGauge. 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
0f3cfb210c * Work on artist page. Better layout / design? 2013-07-18 15:41:33 +02:00
Christian Muehlhaeuser
74fdd6500c * Properly set pen before painting figure ovals. 2013-07-18 15:41:32 +02:00
Christian Muehlhaeuser
2e1a1385e1 * Fixed pen settings for drawBackgroundAndNumbers. 2013-07-18 15:41:32 +02:00
Christian Muehlhaeuser
b15622f275 * TrackView should restore externally set alternating-row-color setting. 2013-07-18 15:41:32 +02:00
Christian Muehlhaeuser
02da2cba8d * Mutex protect TrackData. 2013-07-18 15:41:32 +02:00
Christian Muehlhaeuser
00662c2d8d * Load artist-stats. 2013-07-18 15:41:32 +02:00
Tomahawk CI
5fc1d68a3c Automatic merge of Transifex translations 2013-07-18 15:41:32 +02:00
Florian Richter
0a815e06df Fix signal signature 2013-07-18 15:41:32 +02:00
Tomahawk CI
3e678c55ee Automatic merge of Transifex translations 2013-07-18 15:41:32 +02:00
Christian Muehlhaeuser
250c76b53c * When redirecting a request, make sure HEAD ops don't become a GET. 2013-07-18 15:41:32 +02:00
Christian Muehlhaeuser
b070ed8f82 * Style fixes. 2013-07-18 15:41:32 +02:00
Christian Muehlhaeuser
03a84c574e * Cache avatar instead of trying to get it from the cache over and over. 2013-07-18 15:41:32 +02:00
Christian Muehlhaeuser
58ee8b35f4 * Style fixes and removed spamy logging from TomahawkCache. 2013-07-18 15:41:32 +02:00
Uwe L. Korn
6ef3dc30af Use peerName instead of peerAddress
* If connecting to a non-IP host, peerAddress is an empty string,
  peerName contains the DNS name
2013-07-18 15:41:32 +02:00
Christian Muehlhaeuser
1da4cb83ca * The mutex isn't needed. 2013-07-18 15:41:32 +02:00
Christian Muehlhaeuser
27fcb1c43f * Style fixes for NetworkActivityWidget. 2013-07-18 15:41:32 +02:00
Christian Muehlhaeuser
8c0b982852 * Fixed building without breakpad. Thanks to Dinar Valeev. 2013-07-18 15:41:32 +02:00
Christian Muehlhaeuser
9a2594c644 * Style fixes for build system. 2013-07-18 15:41:31 +02:00
Christian Muehlhaeuser
f8b2d792df * Style fixes for build system. 2013-07-18 15:41:31 +02:00
Tomahawk CI
f199f08288 Automatic merge of Transifex translations 2013-07-18 15:41:31 +02:00
Uwe L. Korn
183d7be141 Do not delete connection if PeerInfo disappers during connect 2013-07-18 15:41:31 +02:00
Uwe L. Korn
213edc6d12 Hide InfoBar and report isBeingPlayed status. 2013-07-18 15:41:31 +02:00
Uwe L. Korn
4ffbb06baa NetworkActivity now features Charts 2013-07-18 15:41:31 +02:00
Uwe L. Korn
c808b0989b Add NetworkCharts Database Command 2013-07-18 15:41:31 +02:00
Uwe L. Korn
aa104fce10 Add empty NetworkActivity page 2013-07-18 15:41:31 +02:00
Uwe L. Korn
991bacd667 Add network-activity.svg to resources 2013-07-18 15:40:55 +02:00
Tomahawk CI
b6109b9bf9 Automatic merge of Transifex translations 2013-07-18 15:40:55 +02:00
Uwe L. Korn
ca08729d24 Show DBID/nodeId in DiagnosticsDialog 2013-07-18 15:40:55 +02:00
Uwe L. Korn
4c6ed3d368 Remove hack to avoid resetting firstMessage on parallel connection 2013-07-18 15:40:55 +02:00
Christian Muehlhaeuser
b951f1f4bc * Improvements to item-delegates. 2013-07-18 15:40:55 +02:00
Christian Muehlhaeuser
20df5ded1f * Style fixes for FdoNotifyPlugin. 2013-07-18 15:40:55 +02:00
Tomahawk CI
de5ddc925d Automatic merge of Transifex translations 2013-07-18 15:40:54 +02:00
Florian Richter
cc104598db listen to media key events of gnome settings daemon
* add shortcuthandler, which listens to the media key event
  provided by the gnome settings daemon via dbus
  (https://github.com/GNOME/gnome-settings-daemon/blob/master/plugins/media-keys/README.media-keys-API)
* fixes TWK-983
2013-07-18 15:40:54 +02:00
Christian Muehlhaeuser
e84316c325 * Fixed liben comment. 2013-07-18 15:40:54 +02:00
Teo Mrnjavac
efddc70b7f Bump Echonest version. 2013-07-18 15:40:54 +02:00
Tomahawk CI
f300b4f617 Automatic merge of Transifex translations 2013-07-18 15:40:54 +02:00
Kevin Funk
062addd7e8 Fix some compiler/runtime warnings 2013-07-18 15:40:54 +02:00
Uwe L. Korn
cfb04bb1d7 Delay resuming as we will most likely fail connecting directly 2013-07-18 15:40:54 +02:00
Uwe L. Korn
830d2c9391 Add support for UPower 2013-07-18 15:40:54 +02:00
Florian Richter
d4d45220d1 use autogenerated dbus interface for fdonotify 2013-07-18 15:40:54 +02:00
Jason Herskowitz
c79a671802 Add Network Activity icon for sidebar 2013-07-18 15:40:54 +02:00
Uwe L. Korn
a6113204d2 Fix time in spelling 2013-07-18 15:40:54 +02:00
Uwe L. Korn
701c5ff61c Add SIP improvements to ChangeLog 2013-07-18 15:40:53 +02:00
Florian Richter
a0d988e63a autogenerate dbus adaptors for mpris 2013-07-18 15:40:53 +02:00
Tomahawk CI
ee4186c51d Automatic merge of Transifex translations 2013-07-18 15:40:53 +02:00
Jeff Mitchell
795e525889 Add hatchet plugin to master 2013-07-18 15:40:53 +02:00
Christian Muehlhaeuser
8c10a0c821 * Try simpler OverlayWidget layout. 2013-07-18 15:40:53 +02:00
Christian Muehlhaeuser
9d0c8e1b03 * Fixed AnimatedSpinner flickering when resizing window. 2013-07-18 15:40:53 +02:00
Christian Muehlhaeuser
606a86e016 * Disable / enable alternate row colors when required. 2013-07-18 15:40:53 +02:00
Tomahawk CI
bd33824202 Automatic merge of Transifex translations 2013-07-18 15:40:53 +02:00
Teo Mrnjavac
cae5e75f2a Only show the mark as listened action if unlistened tracks are selected. 2013-07-18 15:40:53 +02:00
Christian Muehlhaeuser
2b1df0e664 * x.y.999 is invalid on OSX. 2013-07-18 15:40:52 +02:00
Teo Mrnjavac
cb4816d662 Replaced GenericSelect with a proper dbcmd.
Consequences:
* we avoid the use of QObject properties, which are not thread safe
* we get social actions right away, without having to wait for
  every track's loadSocialActions to finish
2013-07-18 15:40:52 +02:00
Teo Mrnjavac
1bbfe1599a Remove debug spam. 2013-07-18 15:40:52 +02:00
Tomahawk CI
13f8ad5daa Automatic merge of Transifex translations 2013-07-18 15:40:52 +02:00
Uwe L. Korn
ba23f701f8 Make private things private 2013-07-18 15:40:52 +02:00
Uwe L. Korn
0c1a10ec6a Copy-Constructor is automatically called 2013-07-18 15:40:52 +02:00
Uwe L. Korn
af0504fe41 Bump Version to 0.7.999 2013-07-18 15:40:52 +02:00
Uwe L. Korn
a87b0268d4 Remove usage of QSharedPointer around SipInfo 2013-07-18 15:40:52 +02:00
Uwe L. Korn
72b326a3be We are handling a set, so we need no duplicate detection. 2013-07-18 15:40:52 +02:00
Teo Mrnjavac
1637b325d7 Add "Mark as Listened" to Inbox. 2013-07-18 15:40:52 +02:00
Uwe L. Korn
91feefc433 Fix compilation 2013-07-18 15:40:52 +02:00
Uwe L. Korn
c3a1ee84a1 Even more race precautions
* It did not break yet, but I could not sleep without this commit.
2013-07-18 15:40:52 +02:00
Tomahawk CI
d440061228 Automatic merge of Transifex translations 2013-07-18 15:40:52 +02:00
Teo Mrnjavac
8215e5be00 Send tracks via context menu. 2013-07-18 15:40:51 +02:00
Uwe L. Korn
5e3d14c950 Lock setControlConnection to prevent races 2013-07-18 15:40:51 +02:00
Teo Mrnjavac
e7be3ac8a2 Make tracks sending more discoverable. 2013-07-18 15:40:51 +02:00
Uwe L. Korn
3fd379e81c Detect duplicate ControlConnections 2013-07-18 15:40:51 +02:00
Uwe L. Korn
8b63388ead Remove trailing semicolons 2013-07-18 15:40:51 +02:00
Uwe L. Korn
7b7dffbf0a Credits to me 2013-07-18 15:40:51 +02:00
Uwe L. Korn
e8286b2995 Change ContolContection* to QPointer 2013-07-18 15:40:51 +02:00
Uwe L. Korn
926f42ed1f Set interval to timeout 2013-07-18 15:40:51 +02:00
Uwe L. Korn
b9b24e8161 readyRead is not used as a Slot/Signal 2013-07-18 15:40:51 +02:00
Uwe L. Korn
b362e2a9bd Wait for versionString in Xmpp until telling Servent SipInfos 2013-07-18 15:40:51 +02:00
Uwe L. Korn
008b7e32a6 Weaken references to PeerInfos 2013-07-18 15:40:51 +02:00
Uwe L. Korn
baaddf22a4 Introduce ConnectionManager for outgoing connections 2013-07-18 15:40:51 +02:00
Uwe L. Korn
cad21c1712 Make less usage of QHostAddress when dealing with DNS records. 2013-07-18 15:40:51 +02:00
Uwe L. Korn
b3549ac945 Connection should be able to shutdown even if the socket already disappeared 2013-07-18 15:40:51 +02:00
Uwe L. Korn
9723d7b4ce Do not delete the Connection in Socket cleanup, we take care of this at another stage. 2013-07-18 15:40:51 +02:00
Uwe L. Korn
26f8270372 More logging to find error causes 2013-07-18 15:40:51 +02:00
Uwe L. Korn
652a506922 For old clients, just connect if the magic sort says we should. 2013-07-18 15:40:50 +02:00
Uwe L. Korn
3de5670de7 Sent old tomahawk versions SipInfos like before. 2013-07-18 15:40:50 +02:00
Uwe L. Korn
9d89f8a12e Only destroy existing ControlConnection if it does not run anymore 2013-07-18 15:40:50 +02:00
Uwe L. Korn
e974c08883 Make more use of peerInfoDebug 2013-07-18 15:40:50 +02:00
Uwe L. Korn
bc3c65a027 Split up log messages to know the real cause 2013-07-18 15:40:50 +02:00
Uwe L. Korn
08fb69abb9 Lazily create ControlConnection for offers 2013-07-18 15:40:50 +02:00
Uwe L. Korn
945cf58e78 Add const to arguments in getLocalSipInfos 2013-07-18 15:40:50 +02:00
Uwe L. Korn
c5731c20d5 Refactor the creation of local SipInfos into its own method 2013-07-18 15:40:50 +02:00
Uwe L. Korn
a861943222 Add more verbose logging 2013-07-18 15:40:50 +02:00
Uwe L. Korn
09f47fe11c Remove assert and fix logging 2013-07-18 15:40:50 +02:00
Uwe L. Korn
e2f9dad471 Add more logging to connection handling 2013-07-18 15:40:50 +02:00
Uwe L. Korn
e38be974e4 Add a bit of logging to XmppMessage serialzation 2013-07-18 15:40:50 +02:00
Uwe L. Korn
6c9ec62e7e Handle disconnects during connection attempts (i.e. vanishing connection objects) 2013-07-18 15:40:50 +02:00
Uwe L. Korn
f1ad4922ab Sent non-IP hostname as a last hostname too (these are the user-supplied ones) 2013-07-18 15:40:50 +02:00
Uwe L. Korn
f34dc1b75f Add ASSERTs again 2013-07-18 15:40:50 +02:00
Uwe L. Korn
35da957765 Use nodeId instead of id 2013-07-18 15:40:50 +02:00
Uwe L. Korn
9c1100d180 Some more style changes 2013-07-18 15:40:49 +02:00
Uwe L. Korn
d8bc1cc11d Rename sipInfo to sipInfos at various places 2013-07-18 15:40:49 +02:00
Uwe L. Korn
11f2c24966 Clear up (Control)Connections if connecting failed. 2013-07-18 15:40:49 +02:00
Uwe L. Korn
a0c69ac45a Do nothing in handleSipInfo if we have not received valid SipInfo 2013-07-18 15:40:49 +02:00
Uwe L. Korn
785b616e07 Change comment style to gobal default 2013-07-18 15:40:49 +02:00
Uwe L. Korn
df0fbbc96e Always try next SipInfo 2013-07-18 15:40:49 +02:00
Uwe L. Korn
1d82d0b80b Fix multiple ip connection mechanism 2013-07-18 15:40:49 +02:00
Uwe L. Korn
1c4baee0d4 Correctly ignore IPv4-as-IPv6 localhost 2013-07-18 15:40:49 +02:00
Uwe L. Korn
6172d50710 Do not try link-local addresses. 2013-07-18 15:40:49 +02:00
Uwe L. Korn
85c7b16fa1 Ignore IPv4 localhost even if written as IPv6 address 2013-07-18 15:40:49 +02:00
Uwe L. Korn
d3afba1a90 Add missing writeEndElement 2013-07-18 15:40:49 +02:00
Uwe L. Korn
2c86361190 Rename sipInfoList to sipInfo 2013-07-18 15:40:49 +02:00
Uwe L. Korn
b9e42a03e9 Better way to get the id of a peer 2013-07-18 15:40:49 +02:00
Uwe L. Korn
8b7dba77aa Get back accidently deleted registerOffer 2013-07-18 15:40:49 +02:00
Uwe L. Korn
2a721e89a5 Ignore Zeroconf messages sent by ourselves 2013-07-18 15:40:49 +02:00
Uwe L. Korn
c42054ea5c Create SipInfo with the correct information. 2013-07-18 15:40:49 +02:00
Uwe L. Korn
073f6f5b7a Always return SipInfo, even if not visible 2013-07-18 15:40:49 +02:00
Uwe L. Korn
2438485433 Remove asserts in getters as this makes debugging harder 2013-07-18 15:40:49 +02:00
Uwe L. Korn
812b4f6ee3 Support multiple SipInfos per peer 2013-07-18 15:40:49 +02:00
Uwe L. Korn
0807a3ce4e Change option description to reflect new functionality 2013-07-18 15:40:48 +02:00
Uwe L. Korn
c41c475852 Servent should listen to IPv6 too 2013-07-18 15:40:48 +02:00
Christian Muehlhaeuser
cba83e5225 Revert "Add missing emit ready()"
This reverts commit cc336e9d45.
2013-07-18 15:40:48 +02:00
Christian Muehlhaeuser
1ba923fd21 Revert "* Some fixes to InfoSystem and loading."
This reverts commit 8460d8f522.
2013-07-18 15:40:48 +02:00
Dominik Schmidt
5272cd5f9e Add missing emit ready() 2013-07-18 15:40:48 +02:00
Christian Muehlhaeuser
04a1f4e595 * Some fixes to InfoSystem and loading. 2013-07-18 15:40:48 +02:00
Tomahawk CI
9a6850def5 Automatic merge of Transifex translations 2013-07-18 15:40:48 +02:00
Uwe L. Korn
39da04b843 Display friend's avatars on Dashboard even when they are offline
* Fixes TWK-398
2013-07-18 15:40:48 +02:00
Tomahawk CI
8e4ccbee6d Automatic merge of Transifex translations 2013-07-18 15:40:48 +02:00
Uwe L. Korn
4aed8bf75e Add desktop notifications for received tracks 2013-07-18 15:40:47 +02:00
Dominik Schmidt
3e00b5c0e6 Revert "listen to media key events of gnome settings daemon"
This reverts commit 966ab37b94.
2013-07-18 15:40:47 +02:00
Uwe L. Korn
f64436f9bb Add the possibility for JSResolvers to specify that a given URL is checked/valid. 2013-07-18 15:40:47 +02:00
Florian Richter
da2308db33 listen to media key events of gnome settings daemon
* add shortcuthandler, which listens to the media key event
  provided by the gnome settings daemon via dbus
  (https://github.com/GNOME/gnome-settings-daemon/blob/master/plugins/media-keys/README.media-keys-API)
2013-07-18 15:40:47 +02:00
Dominik Schmidt
45b6340952 Forgotten files are forgotten 2013-07-18 15:40:47 +02:00
Dominik Schmidt
ec4ac5210b Pimple AudioEngine 2013-07-18 15:40:47 +02:00
Teo Mrnjavac
aa5e9ea4f2 Useless entry is useless. 2013-07-18 15:40:47 +02:00
Tomahawk CI
4c85b1d92d Automatic merge of Transifex translations 2013-07-18 15:40:47 +02:00
Teo Mrnjavac
8798f2103e Avoid crash when propagating dbcmd_ShareTrack. 2013-07-18 15:40:47 +02:00
Jeff Mitchell
4497849d07 Fix spelling 2013-07-18 15:40:47 +02:00
Jeff Mitchell
9d42209e96 Use removeOne, not removeAll, as there won't be more than one 2013-07-18 15:40:47 +02:00
Teo Mrnjavac
2185b3ae5a Fix loading of playlist updaters. 2013-07-18 15:40:46 +02:00
Uwe L. Korn
2dee4ccca3 Use QKeySequence::Find to focus the search widget 2013-07-18 15:40:46 +02:00
Dominik Schmidt
25be3d4ad7 Move src/breakdpad/CrashReporter to src/crashreporter 2013-07-18 15:40:46 +02:00
Dominik Schmidt
cb10c59215 Build all subdirs of src/ automatically 2013-07-18 15:40:46 +02:00
Dominik Schmidt
af2336b32f Adjust cmake to build again and fix include errors
These are partly hacks - I split the commit for referencing the hacks
afterwards
2013-07-18 15:40:46 +02:00
Dominik Schmidt
e4ab92b81f Move application target from src/ to src/tomahawk/ 2013-07-18 15:40:46 +02:00
Tomahawk CI
6da9b2937c Automatic merge of Transifex translations 2013-07-18 15:40:46 +02:00
Teo Mrnjavac
30a4019c65 Try to fix startup issue. 2013-07-18 15:40:46 +02:00
Teo Mrnjavac
b006c56876 Make AccountModel loading asynchronous.
AccountManager starts up in 3 steps, first waiting for credentials and
then for Servent to be ready. During this time an AccountModel could be
instantiated in the GUI thread, which needs AccountManager, and if the
latter is not ready at that time, the former cannot be populated with
sane data.
This commit splits the AccountModel ctor so that it waits for
AccountManager to be ready before hooking up to its signals and
performing the initial model reset.
2013-07-18 15:40:46 +02:00
Teo Mrnjavac
3f7c08fdb8 Debug spam++ 2013-07-18 15:40:46 +02:00
Teo Mrnjavac
2d8ca57fee Use outbox icon when sending tracks. 2013-07-18 15:40:45 +02:00
Teo Mrnjavac
7c417f1076 Notify sender of track that an inbox entry has been sent. 2013-07-18 15:40:25 +02:00
Jason Herskowitz
a88816168b Add outbox SVG 2013-07-18 15:40:25 +02:00
Dominik Schmidt
b12aba360c Link privately against qtkeychain 2013-07-18 15:40:25 +02:00
Teo Mrnjavac
c35b63da71 Rename QtScriptResolver to JSResolver because JS != QtScript. 2013-07-18 15:40:25 +02:00
Teo Mrnjavac
24ad7ac701 Enable AccountModel debug spam. 2013-07-18 15:40:25 +02:00
Teo Mrnjavac
641d28c932 Fix issue with not all accountIds being carried over to loading phase. 2013-07-18 15:40:25 +02:00
Teo Mrnjavac
8b972ca62e *** Restore v14 config file before running to avoid losing accounts ***
Change QtKeychain's user-visible service name to "Tomahawk".
2013-07-18 15:40:25 +02:00
Tomahawk CI
748c3106ea Automatic merge of Transifex translations 2013-07-18 15:40:25 +02:00
Dominik Schmidt
29c8b0bea9 Add libqtkeychain.dll to windows installer 2013-07-18 15:40:24 +02:00
Dominik Schmidt
8e16445b49 Fix config file for build tree usage 2013-07-18 15:40:24 +02:00
Teo Mrnjavac
a129a54d1b Enable config upgrade path. 2013-07-18 15:40:24 +02:00
Teo Mrnjavac
e790fab9ae Also write credentials to QtKeychain through CredentialsManager. 2013-07-18 15:40:24 +02:00
Teo Mrnjavac
812f8cb250 Load Account credentials from CredentialsManager. 2013-07-18 15:40:24 +02:00
Teo Mrnjavac
481b16be89 Wait for both Servent and AccountManager to be ready for initSIP. 2013-07-18 15:40:24 +02:00
Teo Mrnjavac
c723160883 Added CredentialsManager as a QtKeychain credentials cache. 2013-07-18 15:40:24 +02:00
Teo Mrnjavac
17f0606139 Upgrade config. 2013-07-18 15:40:24 +02:00
Teo Mrnjavac
1bd7c18715 Build with QtKeychain. 2013-07-18 15:40:24 +02:00
Dominik Schmidt
4beee033ac hack until Qt5: Make external modules/projects automatically act as gui modules/projects 2013-07-18 15:40:24 +02:00
Dominik Schmidt
3ded897d55 Remove TomahawkVersion.h and QtCrypto includes from public QtScriptResolver header 2013-07-18 15:39:40 +02:00
Tomahawk CI
bf49d2bec5 Automatic merge of Transifex translations 2013-07-18 15:39:40 +02:00
Christian Muehlhaeuser
7c963e4c37 * Try to work-around translated error messages. Loathing. 2013-07-18 15:39:39 +02:00
Christian Muehlhaeuser
e35b2bcf43 * Show QSqlError's number() when a query fails. 2013-07-18 15:39:39 +02:00
Christian Muehlhaeuser
7ca0786f02 * Need to actually load controls. 2013-07-18 15:39:39 +02:00
Christian Muehlhaeuser
045e4df526 * DbCmd_SetDynamicPlaylistRevision should check if its parent's exec() succeeded. 2013-07-18 15:39:39 +02:00
Christian Muehlhaeuser
02dee0ec06 * Don't retry on empty SQL error. 2013-07-18 15:39:39 +02:00
Tomahawk CI
8c5ec2bc23 Automatic merge of Transifex translations 2013-07-18 15:39:39 +02:00
Hugo Lindström
c3995a0cc8 Sort by rank if possible 2013-07-18 15:39:39 +02:00
Hugo Lindström
c2f3cff83a Bump charts and newreleases version 2013-07-18 15:39:39 +02:00
Michael Zanetti
e99439ecca some more work on start by year 2013-07-18 15:39:39 +02:00
Michael Zanetti
97c8b93d3c add animation to FlexibleHeader 2013-07-18 15:39:39 +02:00
Christian Muehlhaeuser
050503e8b5 * Behave, Qt4. 2013-07-18 15:39:39 +02:00
Michael Zanetti
c53800f0d3 create station wizard: workaround slow fist scrolling of the ListView 2013-07-18 15:39:38 +02:00
Michael Zanetti
fcc6f5c966 some more work on stations merged 2013-07-18 15:39:38 +02:00
Christian Muehlhaeuser
2e3785f92b * Disable 'Create new station' item. 2013-07-18 15:39:38 +02:00
Christian Muehlhaeuser
2156466762 * Added itemFromIndex to PlayableModel. 2013-07-18 15:39:38 +02:00
Christian Muehlhaeuser
266de41624 * Fixed PlayableItem & added properties. 2013-07-18 15:39:38 +02:00
Christian Muehlhaeuser
bbeeac9935 * Bring back Radio sidebar item. 2013-07-18 15:39:38 +02:00
Christian Muehlhaeuser
99ef263ba2 * Use DynamicQmlWidget for stations. 2013-07-18 15:39:38 +02:00
Christian Muehlhaeuser
f3a50bedbd * Stations shouldn't depend on widgets / controls. 2013-07-18 15:39:38 +02:00
Christian Muehlhaeuser
2841593a85 * Added model specific roles and updated data methods. 2013-07-18 15:39:38 +02:00
Christian Muehlhaeuser
c47d52b144 * Added coverID() related methods to Artist, Album, Track. 2013-07-18 15:39:38 +02:00
Christian Muehlhaeuser
d03cb674c9 * Imported QML specific widgets / views / providers. 2013-07-18 15:39:38 +02:00
Christian Muehlhaeuser
17eeae9a8f * Imported QML resources. 2013-07-18 15:39:38 +02:00
Michael Zanetti
64fd91c0ca some more work on saving stations 2013-07-01 21:03:33 +02:00
Michael Zanetti
145cb67390 adjust station summaries to look the same everywhere 2013-06-29 22:24:50 +02:00
Michael Zanetti
2045dcfaf7 fix loading state 2013-06-29 22:00:10 +02:00
Michael Zanetti
d09fe0a5d6 also add a description for byStation 2013-06-29 22:00:01 +02:00
Michael Zanetti
fd2d0a53ed station summary does something again, at least for stations by artist 2013-06-29 21:42:41 +02:00
Christian Muehlhaeuser
23f47f825a * Fixed startFromGenre. 2013-06-29 21:51:10 +02:00
Michael Zanetti
b211263ced generate does the real thing again 2013-06-29 21:07:35 +02:00
Christian Muehlhaeuser
ecab5b41b0 * Create EchonestParams out of the variant list. 2013-06-29 21:15:51 +02:00
Christian Muehlhaeuser
914f8ccdbb * Print out controls when creating a station. 2013-06-29 19:47:12 +02:00
Christian Muehlhaeuser
daff8101a0 * Create those darned controls manually. 2013-06-29 19:46:55 +02:00
Christian Muehlhaeuser
3a822f22e9 * Fixed invoke. 2013-06-29 19:46:31 +02:00
Christian Muehlhaeuser
d025e8f512 * Show save button when we have a configured station. 2013-06-29 19:46:16 +02:00
Christian Muehlhaeuser
6b6fd9a6e2 * Fixed displaying of back / save button. 2013-06-29 19:05:08 +02:00
Christian Muehlhaeuser
b2a7b23590 * Radio mode needs to initialize a temporary station. 2013-06-29 19:05:08 +02:00
Christian Muehlhaeuser
656f621868 * Create dynamic playlist when needed - for temporary ones. 2013-06-29 19:05:08 +02:00
Christian Muehlhaeuser
bafcb1c07e * Style fix. 2013-06-29 19:05:08 +02:00
Michael Zanetti
ad88242d3a more cleanup 2013-06-29 18:55:29 +02:00
Michael Zanetti
fd0ee87208 fix playlist generation and clean up dynamicqmlwidget a bit 2013-06-29 18:48:18 +02:00
Michael Zanetti
65eec14a48 fix merge 2013-06-29 17:06:54 +02:00
Christian Muehlhaeuser
2dd0efc310 * Merged master into qmlng. 2013-06-29 17:09:19 +02:00
Christian Muehlhaeuser
7b6c183bf7 * Need to actually load controls. 2013-05-20 20:05:56 +02:00
Michael Zanetti
541ad42b86 some more work on start by year 2013-05-19 04:40:17 +02:00
Michael Zanetti
3f25010cd9 add animation to FlexibleHeader 2013-05-19 04:40:16 +02:00
Christian Muehlhaeuser
e7259f619e * Behave, Qt4. 2013-05-19 02:38:44 +02:00
Michael Zanetti
abd2957e0e create station wizard: workaround slow fist scrolling of the ListView 2013-05-19 02:36:11 +02:00
Michael Zanetti
e468ad2687 some more work on stations merged 2013-05-19 00:40:12 +02:00
Christian Muehlhaeuser
7ad06f5ee2 * Disable 'Create new station' item. 2013-05-19 00:32:31 +02:00
Christian Muehlhaeuser
6cd680c388 * Added itemFromIndex to PlayableModel. 2013-05-19 00:31:40 +02:00
Christian Muehlhaeuser
3490975de5 * Fixed PlayableItem & added properties. 2013-05-19 00:31:15 +02:00
Christian Muehlhaeuser
aaebfe39c5 * Bring back Radio sidebar item. 2013-05-18 23:55:30 +02:00
Christian Muehlhaeuser
a52998d766 * Use DynamicQmlWidget for stations. 2013-05-18 22:56:51 +02:00
Christian Muehlhaeuser
74ec938037 * Stations shouldn't depend on widgets / controls. 2013-05-18 22:56:28 +02:00
Christian Muehlhaeuser
7a1ef2eba7 * Added model specific roles and updated data methods. 2013-05-18 22:55:09 +02:00
Christian Muehlhaeuser
f42a5f461c * Added coverID() related methods to Artist, Album, Track. 2013-05-18 22:54:42 +02:00
Christian Muehlhaeuser
2704f1261d * Imported QML specific widgets / views / providers. 2013-05-18 22:53:56 +02:00
Christian Muehlhaeuser
91b562a98e * Imported QML resources. 2013-05-18 22:53:18 +02:00
75 changed files with 3679 additions and 291 deletions

View File

@@ -179,6 +179,7 @@ if( NOT Qt5Core_DIR )
set(QT_USE_QTNETWORK TRUE)
set(QT_USE_QTXML TRUE)
set(QT_USE_QTWEBKIT TRUE)
set(QT_USE_QTDECLARATIVE TRUE)
include( ${QT_USE_FILE} )
endmacro()

View File

@@ -1,11 +1,11 @@
#FIXME: this only handles qt4 and duplicates top level cmakelists: how can we reduce code duplication?
find_package(Qt4 COMPONENTS QtNetwork QtCore QtGui QtSql REQUIRED)
find_package(Qt4 COMPONENTS QtNetwork QtCore QtGui QtSql QtDeclarative REQUIRED)
include( ${QT_USE_FILE} )
set(NEEDED_QT4_COMPONENTS "QtCore" "QtXml" "QtNetwork")
if(BUILD_GUI OR NOT DEFINED BUILD_GUI)
list(APPEND NEEDED_QT4_COMPONENTS "QtGui" "QtWebkit" "QtUiTools" "QtSvg")
list(APPEND NEEDED_QT4_COMPONENTS "QtGui" "QtWebkit" "QtUiTools" "QtSvg" "QtDeclarative")
endif()
find_package(Qt4 4.7.0 COMPONENTS ${NEEDED_QT4_COMPONENTS})

View File

@@ -0,0 +1,145 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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"
height="32"
version="1.1"
viewBox="0 0 32 32"
width="32"
x="0px"
y="0px"
id="svg2"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="inputfield-border.svg">
<metadata
id="metadata18">
<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="defs16">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 22 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="44 : 22 : 1"
inkscape:persp3d-origin="22 : 14.666667 : 1"
id="perspective2836" />
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2880"
inkscape:window-height="1720"
id="namedview14"
showgrid="true"
inkscape:zoom="22.627417"
inkscape:cx="27.047196"
inkscape:cy="19.278199"
inkscape:window-x="-12"
inkscape:window-y="45"
inkscape:window-maximized="1"
inkscape:current-layer="svg2">
<inkscape:grid
type="xygrid"
id="grid2990"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<g
id="g4599">
<path
style="opacity:0.06466699;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:8;stroke-opacity:1"
d="M 4.65625,2.53125 C 0.01699841,4.4354339 3.6476695,11.37715 2.5,15.15625 c 0.9104726,4.415191 -1.74364624,10.215434 1.125,13.9375 7.922985,0.877493 16.321668,0.399451 24.3125,0.1875 C 31.683761,26.34472 28.403491,19.966164 29.5,15.84375 28.337107,11.830292 31.896487,5.0854716 27.625,2.59375 19.995242,2.3871025 12.300962,2.5260218 4.65625,2.53125 z"
id="path4601"
inkscape:connector-curvature="0" />
<path
style="opacity:0.06466699;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:8;stroke-opacity:1"
d="M 4.78125,2.15625 C -0.50384498,3.6307191 3.3089847,11.154694 2.15625,15 c 0.9229661,4.546013 -1.76090684,10.511754 1.125,14.3125 7.901377,1.296184 16.629903,0.28974 24.6875,0.375 C 32.275546,27.028776 28.653465,20.168522 29.84375,16 28.645472,11.822061 32.315037,4.9433197 27.90625,2.3125 20.331149,1.9143664 12.389796,2.2847244 4.78125,2.15625 z"
id="path4605"
inkscape:connector-curvature="0" />
<path
style="opacity:0.06466699;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:8;stroke-opacity:1"
d="m 4.71875,1.8125 c -5.60622152,1.4178135 -1.8407007,9.335986 -2.9375,13.3125 1.0422893,4.584739 -2.09676889,11.02483 1.5625,14.625 8.081978,0.980787 16.725347,0.518622 24.875,0.1875 4.402595,-2.83693 0.856871,-9.769091 2,-14.0625 -1.179633,-4.234007 2.610959,-11.6624143 -2.4375,-14 C 20.11261,1.665057 12.395997,1.8099213 4.71875,1.8125 z"
id="path4609"
inkscape:connector-curvature="0" />
<path
style="opacity:0.06466699;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:8;stroke-opacity:1"
d="M 4.34375,1.46875 C -1.4013281,3.6570978 2.6368879,11.554337 1.4375,16.09375 2.5716902,20.523565 -1.4013805,28.864524 4.59375,30.53125 12.624379,30.017378 21.200972,31.58868 28.96875,30 32.860269,25.890157 29.400879,19.01996 30.5625,13.90625 29.907854,10.034046 32.893088,1.9946986 26.90625,1.4375 19.397406,1.4612481 11.795029,1.3918794 4.34375,1.46875 z"
id="path4613"
inkscape:connector-curvature="0" />
<path
style="opacity:0.06466699;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:8;stroke-opacity:1"
d="m 4.625,1.09375 c -6.2068547,1.3257477 -2.6318919,9.686262 -3.5625,13.96875 1.1448342,4.811525 -2.4458629,11.943183 2.09375,15.40625 8.111337,1.130173 16.686474,0.284334 24.90625,0.3125 5.588519,-2.412228 1.736328,-10.285499 2.875,-14.84375 C 29.823429,11.396143 33.723745,3.1822192 27.75,1.125 20.050017,0.99409221 12.327794,1.0658584 4.625,1.09375 z"
id="path4617"
inkscape:connector-curvature="0" />
<path
style="opacity:0.06466699;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:8;stroke-opacity:1"
d="M 4.59375,0.75 C -0.61385497,1.3040672 0.78718888,7.8712117 0.71875,11.459821 1.1629644,17.279444 -0.11932148,23.455713 1.25,29.09375 c 2.821567,4.196632 8.916358,1.349939 13.066963,2.1875 C 19.332991,30.61559 25.044407,32.586609 29.6875,30.375 33.051694,26.90515 30.469139,21.267325 31.28125,16.968751 30.597411,12.179526 32.636881,6.6229625 30.3125,2.25 26.821643,-1.0138505 21.248342,1.5206042 16.968751,0.71875 12.844428,0.74314509 8.7159665,0.67222023 4.59375,0.75 z"
id="path4621"
inkscape:connector-curvature="0" />
<path
style="opacity:0.06466699;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:8;stroke-opacity:1"
d="M 4.53125,0.375 C 1.3894018,0.60024126 -0.18415805,3.9813327 0.34375,6.8169646 0.40966407,13.865499 0.21403433,20.929441 0.4375,27.96875 c 0.5865041,3.066072 3.9812099,4.147942 6.7366076,3.6875 6.9294814,-0.06599 13.8743884,0.129817 20.7946424,-0.09375 3.066072,-0.586504 4.147942,-3.98121 3.6875,-6.736608 C 31.590265,17.896411 31.786067,10.951504 31.5625,4.03125 30.975996,0.96517848 27.58129,-0.11669206 24.825892,0.34375 18.061449,0.36541598 11.293922,0.30095384 4.53125,0.375 z"
id="path4625"
inkscape:connector-curvature="0" />
<path
id="path4629"
d="m 5,0 22,0 c 2.77,0 5,2.23 5,5 l 0,22 c 0,2.77 -2.23,5 -5,5 L 5,32 C 2.23,32 0,29.77 0,27 L 0,5 C 0,2.23 2.23,0 5,0 z"
style="opacity:0.064667;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:8;stroke-opacity:1" />
<path
style="opacity:0.06466699;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:8;stroke-opacity:1"
d="M 4.46875,-0.3125 C 0.98344595,-0.12851319 -0.95137919,3.548349 -0.34375,6.7857146 -0.21552288,13.997692 -0.59536534,21.254525 -0.16338012,28.44023 0.58057677,31.627772 4.1300096,32.842509 7.1428576,32.34375 14.235767,32.215407 21.373601,32.595537 28.44023,32.16338 31.627772,31.419423 32.842509,27.86999 32.34375,24.857142 32.215407,17.764233 32.595537,10.626399 32.16338,3.5597705 31.419423,0.37222754 27.86999,-0.84250881 24.857142,-0.34375 18.061422,-0.32218456 11.26281,-0.38641136 4.46875,-0.3125 z"
id="path4631"
inkscape:connector-curvature="0" />
<path
style="opacity:0.06466699;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:8;stroke-opacity:1"
d="m 4.46875,-0.6875 c -4.88903887,0.31100674 -5.938444,6.0477797 -5.1875,9.9732151 0.41575444,6.5986889 -0.7714644,13.4654919 0.46875,19.9330349 2.5002101,5.615111 9.8337653,2.870216 14.535716,3.5 5.227227,-0.673134 11.102211,1.356807 15.964284,-1 4.618144,-3.665229 1.605796,-10.45511 2.46875,-15.433038 C 31.834965,11.207777 34.77447,4.6031 30.625,0.5625 26.002847,-2.3037853 19.99663,0.03815215 14.857141,-0.71875 11.394973,-0.69362162 7.9291701,-0.76635345 4.46875,-0.6875 z"
id="path4635"
inkscape:connector-curvature="0" />
<path
style="opacity:0.06466699;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:8;stroke-opacity:1"
d="M 4.4375,-1.03125 C -2.4288841,-0.40966905 -1.3119005,8.2085409 -1.0625,13 0.16788472,19.074593 -3.8317535,27.473817 1.59375,32.0625 8.5628736,34.728281 16.662641,32.170927 24,33.0625 29.022589,34.430248 34.293748,30.315663 33.0625,25 32.365371,17.457535 34.334575,9.3983493 32.34375,2.09375 28.430894,-3.9134302 19.817453,0.11168301 14,-1.0625 c -3.186531,0.031844 -6.3778449,-0.056838 -9.5625,0.03125 z"
id="path4639"
inkscape:connector-curvature="0" />
<path
style="opacity:0.06466699;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:8;stroke-opacity:1"
d="M 4.40625,-1.40625 C -2.6356932,-0.73578486 -1.8066321,7.9924057 -1.4375,13 -0.23753983,19.199171 -4.2465159,27.811194 1.46875,32.40625 8.5086357,35.093269 16.607199,32.562499 24,33.4375 29.206688,34.80078 34.643458,30.487912 33.4375,25 32.720722,17.386853 34.764131,9.2829251 32.65625,1.90625 28.669603,-4.2590766 19.946075,-0.32351915 14,-1.4375 c -3.196957,0.031744 -6.3986661,-0.056723 -9.59375,0.03125 z"
id="path4643"
inkscape:connector-curvature="0" />
<path
style="opacity:0.06466699;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:8;stroke-opacity:1"
d="M 4.375,-1.75 C -2.3899272,-1.2431511 -2.4446337,7.0084439 -1.78125,12 -0.57839019,18.49983 -4.4259935,26.910214 0.625,32.21875 6.6149095,35.870482 14.375511,32.750815 21,33.78125 26.00645,34.811355 33.908351,33.579761 33.78125,27 33.025646,18.677041 35.173733,9.8203103 32.96875,1.75 28.969659,-4.6437363 20.059663,-0.68188005 14,-1.78125 10.792617,-1.7496477 7.5805122,-1.8377839 4.375,-1.75 z"
id="path4647"
inkscape:connector-curvature="0" />
<path
style="opacity:0.06466699;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:8;stroke-opacity:1"
d="M 4.875,-2.125 C -1.8309464,-2.1825575 -3.2026722,5.8349656 -2.15625,11 -1.080826,17.712074 -4.3881621,25.748049 -0.375,31.6875 4.9763374,36.782756 13.437274,32.97527 20,34.15625 25.186853,34.907535 33.649994,34.582135 34.09375,27.625 33.532181,19.108316 35.431584,10.074869 33.375,1.78125 29.243722,-5.2757831 19.506448,-0.97339883 13,-2.15625 10.294719,-2.1339361 7.5677947,-2.1998142 4.875,-2.125 z"
id="path4651"
inkscape:connector-curvature="0" />
<path
style="opacity:0.06466699;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:8;stroke-opacity:1"
d="M 4.34375,-2.46875 C -2.8099687,-2.0064215 -3.3295148,6.5980666 -2.5,12 -1.2963625,18.720406 -5.2816016,27.573393 0.3125,32.875 6.7337709,36.640288 14.932728,33.450664 22,34.5 27.257415,35.699243 34.692301,33.44159 34.5,27 33.751825,18.586732 35.895885,9.6625663 33.65625,1.5 29.388001,-5.6000779 19.620414,-1.344641 13,-2.5 c -2.884405,0.032599 -5.7737456,-0.058009 -8.65625,0.03125 z"
id="path4655"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="500px" height="500px" viewBox="0 0 500 500" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<title>station-artist</title>
<description>Created with Sketch (http://www.bohemiancoding.com/sketch)</description>
<defs>
<linearGradient x1="50%" y1="50%" x2="50%" y2="170.589844%" id="linearGradient-1">
<stop stop-color="rgb(254,255,254)" offset="0%"></stop>
<stop stop-color="rgb(0,0,0)" offset="100%"></stop>
</linearGradient>
</defs>
<g id="Page 1" fill="rgb(215,215,215)" fill-rule="evenodd">
<path d="M245.48466,91 C161.807243,91 94,158.187218 94,241.021267 C94,323.885705 161.807243,391 245.48466,391 C329.137526,391 397,323.885699 397,241.021267 C397.006157,158.188001 329.137415,91 245.48466,91 L245.48466,91 L245.48466,91 M328.597284,221.910531 L283.447689,255.452489 L299.857913,308.566669 C300.496157,310.61443 299.741311,312.856636 297.986141,314.126613 C297.090145,314.776792 296.034589,315.10492 294.966758,315.10492 C293.960297,315.10492 292.947699,314.807174 292.076251,314.211683 L245.496742,282.462275 L198.929509,314.211683 C197.155929,315.433048 194.774789,315.390513 193.019619,314.126613 C191.264449,312.856637 190.515741,310.620506 191.147847,308.566669 L207.551935,255.452489 L162.408476,221.910531 C160.671717,220.616248 159.947556,218.374041 160.610347,216.320204 C161.279276,214.254214 163.187869,212.850556 165.378763,212.801944 L222.071977,211.671726 L240.673094,159.213801 C241.397255,157.190346 243.32426,155.8353 245.490606,155.8353 C247.656952,155.8353 249.602368,157.190346 250.320392,159.213801 L268.92151,211.671726 L325.614723,212.801944 C327.793343,212.850556 329.708074,214.254214 330.377002,216.320204 C331.052217,218.375335 330.334166,220.616913 328.597284,221.910531 C328.597284,221.910531 330.334166,220.616913 328.597284,221.910531 L328.597284,221.910531" id="Shape" stroke="rgb(150,150,150)" stroke-width="1" fill="url(#linearGradient-1)"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="500px" height="500px" viewBox="0 0 500 500" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<title>station-genre</title>
<description>Created with Sketch (http://www.bohemiancoding.com/sketch)</description>
<defs>
<linearGradient x1="50%" y1="50%" x2="50%" y2="170.589844%" id="linearGradient-1">
<stop stop-color="rgb(254,255,254)" offset="0%"></stop>
<stop stop-color="rgb(0,0,0)" offset="100%"></stop>
</linearGradient>
</defs>
<g id="Page 1" fill="rgb(215,215,215)" fill-rule="evenodd">
<g id="Group" fill="rgb(0,0,0)">
<path d="M389.045442,230.429716 C383.570272,224.959128 241.528204,83.1885389 241.528204,83.1885389 L179.981162,84.9885389 L160.691354,104.235598 C166.349226,110.976775 171.677056,117.782657 175.749546,123.859127 C179.185524,122.035598 183.098886,121.000304 187.259779,121.000304 C200.856353,121.000304 211.871525,132.006186 211.871525,145.576774 C211.871525,159.14148 200.850461,170.141481 187.259779,170.141481 C173.669099,170.141481 162.648034,159.141481 162.648034,145.576774 C162.648034,142.612068 163.19614,139.788539 164.1568,137.159127 C158.104056,132.623833 151.208523,126.559127 144.560523,120.34148 L129.631991,135.24148 L129.631991,198.565012 L276.789714,345.447361 C276.789714,345.447361 281.192246,351.47089 287.22731,345.447361 C293.262374,339.423831 389.045432,243.817946 389.045432,243.817946 C389.045432,243.817946 394.514592,235.894158 389.045442,230.429716 C389.045442,230.429716 394.514592,235.894158 389.045442,230.429716 L389.045442,230.429716" id="Shape" stroke="rgb(150,150,150)" stroke-width="1" fill="url(#linearGradient-1)"></path>
<path d="M178.83767,140.964384 C179.008585,140.964384 179.309159,140.952619 179.427032,140.82909 C182.916053,137.346737 161.374883,108.893797 132.325244,78.5584992 C131.523712,78.4114404 129.867605,78.1349698 127.975755,78.1349698 C125.512223,78.1349698 122.20001,78.5996757 120.437818,80.8290875 C118.940839,82.7173229 118.622584,85.7232053 119.506627,89.7761465 C138.165813,109.723719 170.456964,140.964384 178.83767,140.964384 C178.83767,140.964384 170.456964,140.964384 178.83767,140.964384 L178.83767,140.964384" id="Shape" stroke="rgb(150,150,150)" stroke-width="1" fill="url(#linearGradient-1)"></path>
<path d="M141.000749,228.394014 L196.30056,367.023423 C196.30056,367.023423 197.726815,373.270482 204.551624,370.576364 C207.793113,369.288128 233.895943,358.911658 260.440793,348.358717 L260.423112,348.364599 L141.000749,228.394014 L141.000749,228.394014 L141.000749,228.394014" id="Shape" stroke="rgb(150,150,150)" stroke-width="1" fill="url(#linearGradient-1)"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,21 @@
import QtQuick 1.1
import tomahawk 1.0
import "tomahawkimports"
// Only to be used together with DeclarativeHeader C++ class
// If you want to use the header in QML, use FlexibleHeader
Item {
anchors.fill: parent
FlexibleHeader {
anchors.fill: parent
icon: iconSource
title: caption
subtitle: description
buttonModel: buttonList
onSearchTextChanged: mainView.setFilterText(searchText)
onCurrentButtonIndexChanged: mainView.viewModeSelected(currentButtonIndex)
}
}

65
data/qml/QmlGridView.qml Normal file
View File

@@ -0,0 +1,65 @@
import QtQuick 1.1
//import tomahawk 1.0
import "tomahawkimports"
Rectangle {
anchors.fill: parent
color: "black"
Text {
id: fontMetrics
text: "Here's some sample text"
opacity: 0
}
GridView {
id: gridView
anchors.fill: parent
//anchors.rightMargin: scrollBar.width
cellHeight: cellWidth
cellWidth: calculateCoverSize(gridView.width - 3)
cacheBuffer: cellHeight * 5
function calculateCoverSize(rectWidth) {
var itemWidth = fontMetrics.width;
var itemsPerRow = Math.max( 1, Math.floor( rectWidth / itemWidth ) );
var remSpace = rectWidth - ( itemsPerRow * itemWidth );
var extraSpace = remSpace / itemsPerRow;
return itemWidth + extraSpace;
}
model: mainModel
delegate: CoverImage {
height: gridView.cellHeight// * 0.95
width: gridView.cellWidth// * 0.95
showLabels: true
showMirror: false
artistName: model.artistName
trackName: model.trackName
artworkId: model.coverID
showPlayButton: true
currentlyPlaying: isPlaying
smooth: !gridView.moving
onClicked: {
rootView.onItemClicked(index)
}
onPlayClicked: {
rootView.onItemPlayClicked(index)
}
}
}
ScrollBar {
id: scrollBar
listView: gridView
orientation: Qt.Vertical
margin: -width
}
}

35
data/qml/SpinnerTest.qml Normal file
View File

@@ -0,0 +1,35 @@
import QtQuick 1.1
import "tomahawkimports"
Rectangle {
width: 1400
height: 900
color: "black"
BusyIndicator {
anchors.centerIn: parent
anchors.horizontalCenterOffset: 200
height: 200
width: 200
count: 11
}
Image {
id: svgSpinner
source: "../images/loading-animation.svg"
smooth: true
height: 200
width: 200
anchors.centerIn: parent
anchors.horizontalCenterOffset: -200
Timer {
running: true
repeat: true
interval: 200
onTriggered: svgSpinner.rotation += 360 / 12
}
}
}

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

@@ -0,0 +1,165 @@
import QtQuick 1.1
import tomahawk 1.0
import "tomahawkimports"
import "stations"
Rectangle {
id: scene
color: "black"
anchors.fill: parent
state: "list"
FlexibleHeader {
id: header
anchors {
left: parent.left
top: parent.top
right: parent.right
}
height: defaultFontHeight * 4
width: parent.width
icon: "../images/station.svg"
title: mainView.title
subtitle: generator.summary
showSearchField: false
showBackButton: stationListView.currentIndex > 0
showNextButton: mainView.configured && stationListView.currentIndex == 2
nextButtonText: "Save"
backButtonText: "Back"
z: 1 //cover albumcovers that may leave their area
onBackPressed: {
inputBubble.opacity = 0
stationListView.decrementCurrentIndex()
switch (stationListView.currentIndex) {
case 0:
subtitle = ""
break;
case 1:
subtitle = modeModel.get(stationCreator.modeIndex).headerSubtitle + "..."
break;
}
}
// In our case the next button is the save button
onNextPressed: {
inputBubble.opacity = 1
inputBubble.forceActiveFocus();
}
}
ListModel {
id: modeModel
ListElement { label: "By Artist"; image: "../../images/station-artist.svg"; creatorContent: "stations/CreateByArtist.qml"; headerSubtitle: "Songs from" }
ListElement { label: "By Genre"; image: "../../images/station-genre.svg"; creatorContent: "stations/CreateByGenre.qml"; headerSubtitle: "Songs of genre" }
ListElement { label: "By Year"; image: "../../images/station-year.svg"; creatorContent: "stations/CreateByYear.qml"; headerSubtitle: "Songs from" }
}
VisualItemModel {
id: stationVisualModel
StationCreatorPage1 {
height: scene.height - header.height
width: scene.width
model: modeModel
onItemClicked: {
stationCreator.modeIndex = index
// FIXME: This is a workaround for the ListView scrolling too slow on the first time
// Lets reinitialize the current index to something invalid and back to 0 (what it already is) before scrolling over to page 1
stationListView.currentIndex = -1
stationListView.currentIndex = 0
stationListView.incrementCurrentIndex()
header.subtitle = modeModel.get(index).headerSubtitle + "..."
}
}
StationCreatorPage2 {
id: stationCreator
height: stationListView.height
width: stationListView.width
property int modeIndex
content: modeModel.get(modeIndex).creatorContent
onNext: {
stationListView.incrementCurrentIndex()
header.subtitle = modeModel.get(modeIndex).headerSubtitle + " " + text
}
}
StationItem {
id: stationItem
height: stationListView.height
width: stationListView.width
}
}
VisualItemModel {
id: configuredStationVisualModel
StationItem {
id: cfgstationItem
height: stationListView.height
width: stationListView.width
}
}
ListView {
id: stationListView
anchors {
left: parent.left
top: header.bottom
right: parent.right
bottom: parent.bottom
}
contentHeight: height
contentWidth: width
orientation: ListView.Horizontal
//model: mainView.configured ? configuredStationVisualModel : stationVisualModel
interactive: false
highlightMoveDuration: 300
onHeightChanged: {
contentHeight = scene.height
}
onWidthChanged: {
contentWidth = scene.width
}
Component.onCompleted: {
model = mainView.configured ? configuredStationVisualModel : stationVisualModel
}
onModelChanged: print("ccccccccccccc", mainView.configured)
}
InputBubble {
id: inputBubble
text: "Station name:"
width: defaultFontHeight * 18
anchors.top: header.bottom
anchors.right: parent.right
anchors.rightMargin: defaultFontHeight / 2
anchors.topMargin: -defaultFontHeight / 2
z: 2
opacity: 0
arrowPosition: 0.95
onAccepted: {
mainView.title = inputBubble.inputText
inputBubble.opacity = 0
header.showNextButton = false
header.showBackButton = false
inputBubble.opacity = 0
}
onRejected: inputBubble.opacity = 0
}
}

View File

@@ -0,0 +1,74 @@
import QtQuick 1.1
import tomahawk 1.0
import "../tomahawkimports"
Item {
id: root
anchors.fill: parent
signal done(string text)
function createStation(artist) {
mainView.startStationFromArtist(artist)
root.done(artist)
}
Column {
id: upperColumn
anchors.fill: parent
anchors.margins: defaultFontHeight
spacing: defaultFontHeight
HeaderLabel {
id: headerText
text: "Pick one of your top artists,"
}
Item {
height: parent.height - headerText.height*2 - artistInputField.height - parent.spacing * 3
width: parent.width
ArtistView {
id: artistView
height: parent.height
width: parent.width
model: artistChartsModel
clip: true
cellWidth: defaultFontHeight * 12
cellHeight: defaultFontHeight * 12
spacing: defaultFontHeight / 2
onItemClicked: {
createStation(artistChartsModel.itemFromIndex(index).artistName);
}
}
ScrollBar {
listView: artistView
}
}
HeaderLabel {
text: "Or enter an artist name"
}
Row {
height: artistInputField.height
width: Math.min(defaultFontHeight * 30, parent.width)
spacing: defaultFontHeight * 0.5
anchors.horizontalCenter: parent.horizontalCenter
InputField {
id: artistInputField
width: parent.width - createFromInputButton.width - parent.spacing
onAccepted: createStation(text)
}
PushButton {
id: createFromInputButton
text: "Create station"
enabled: artistInputField.text.length > 2
onClicked: createStation(artistInputField.text)
}
}
}
}

View File

@@ -0,0 +1,94 @@
import QtQuick 1.1
import tomahawk 1.0
import "../tomahawkimports"
Item {
id: root
anchors.fill: parent
signal done(string text)
function createStation(genre) {
mainView.startStationFromGenre(genre)
root.done(genre)
}
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" }
}
Column {
id: upperColumn
anchors.fill: parent
anchors.bottomMargin: defaultFontHeight
spacing: defaultFontHeight
HeaderLabel {
id: headerText
text: "Enter a genre,"
}
Row {
width: Math.min(defaultFontHeight * 30, parent.width)
height: parent.height * 0.2
spacing: defaultFontHeight * 0.5
anchors.horizontalCenter: parent.horizontalCenter
z: 2
InputField {
id: genreInputField
width: parent.width - createFromInputButton.width - parent.spacing
completionModel: allGenres
onAccepted: createStation(text);
}
PushButton {
id: createFromInputButton
text: "Create station"
height: genreInputField.height
enabled: genreInputField.text.length > 2
onClicked: createStation(genreInputField.text)
}
}
HeaderLabel {
text: "Or, pick one of your most listened genres"
}
Item {
height: parent.height - y
width: parent.width
clip: true
TagCloud {
anchors.fill: parent
anchors.margins: parent.width / 6
model: styleModel
onTagClicked: {
root.createStation(tag);
}
}
}
}
}

View File

@@ -0,0 +1,89 @@
import QtQuick 1.1
import tomahawk 1.0
import "../tomahawkimports"
Item {
id: root
anchors.fill: parent
signal done(string text)
function createStationFromYear(year) {
mainView.startStationFromYear(year)
root.done(year)
}
function createStationFromTo(yearFrom, yearTo) {
mainView.startStationFromTo(yearFrom, yearTo)
root.done(yearFrom + " to " + yearTo)
}
Column {
id: upperColumn
anchors.horizontalCenter: parent.horizontalCenter
height: parent.height
width: defaultFontHeight * 30
anchors.bottomMargin: defaultFontHeight
spacing: defaultFontHeight
HeaderLabel {
id: headerText
text: "Enter a year or pick a range"
}
Row {
height: yearInputField.height
width: parent.width
spacing: defaultFontHeight * 0.5
Text {
text: "Year:"
color: "white"
anchors.verticalCenter: parent.verticalCenter
}
InputField {
id: yearInputField
width: parent.width - createFromInputButton.width - parent.spacing
onAccepted: createStation(text)
}
}
DoubleSlider {
id: yearSlider
width: parent.width
height: defaultFontHeight * 4
min: 1960
max: new Date().getFullYear()
lowerSliderPos: 1990
upperSliderPos: 2010
minMaxLabelsVisible: false
opacity: yearInputField.text.length > 0 ? 0.3 : 1
Behavior on opacity {
NumberAnimation { duration: 200 }
}
}
PushButton {
id: createFromInputButton
text: "Go!"
enabled: yearInputField.text.length == 0 || (yearInputField.text >= yearSlider.min && yearInputField.text <= yearSlider.max)
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
if (yearInputField.text.length > 0) {
createStationFromYear(yearInputField.text)
} else {
createStationFromTo(yearSlider.lowerSliderPos, yearSlider.upperSliderPos)
}
}
// TODO: move some disabled look/animation to the button itself
opacity: enabled ? 1 : 0.3
Behavior on opacity {
NumberAnimation { duration: 200 }
}
}
}
}

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
}
}

View File

@@ -0,0 +1,65 @@
import QtQuick 1.1
import tomahawk 1.0
import "../tomahawkimports"
Item {
id: root
property alias model: gridView.model
property int spacing: 10
signal itemClicked(int index)
GridView {
id: gridView
anchors.centerIn: parent
width: root.width * 9 / 10
height: cellHeight
interactive: false
cellWidth: (width - 1) / 3
cellHeight: cellWidth //* 10 / 16
delegate: Image {
width: gridView.cellWidth - root.spacing
height: gridView.cellHeight - root.spacing
source: image
smooth: true
Rectangle {
id: textBackground
anchors {
left: parent.left
bottom: parent.bottom
right: parent.right
}
height: parent.height / 5
color: "black"
opacity: .5
}
Text {
anchors.centerIn: textBackground
text: label
color: "white"
font.bold: true
}
Rectangle {
id: hoverShade
anchors.fill: parent
color: "white"
opacity: mouseArea.containsMouse ? .2 : 0
Behavior on opacity {
NumberAnimation { easing.type: Easing.Linear; duration: 300 }
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: root.itemClicked(index)
}
}
}
}

View File

@@ -0,0 +1,25 @@
import QtQuick 1.1
import tomahawk 1.0
import "../tomahawkimports"
Item {
id: root
property int margins: defaultFontHeight * 2
property alias content: contentLoader.source
signal next(string text)
Loader {
id: contentLoader
anchors.fill: parent
anchors.margins: root.margins
}
Connections {
target: contentLoader.item
onDone: root.next(text)
}
}

View File

@@ -0,0 +1,37 @@
import QtQuick 1.1
import tomahawk 1.0
import "../tomahawkimports"
Item {
id: stationItem
CoverFlow {
id: coverView
interactive: false
anchors.fill: parent
backgroundColor: scene.color
model: dynamicModel
currentIndex: currentlyPlayedIndex
onItemPlayPauseClicked: {
mainView.playItem(index)
}
onItemClicked: {
mainView.playItem(index)
}
}
BusyIndicator {
id: busyIndicator
anchors.centerIn: parent
height: defaultFontHeight * 4
width: height
// count: 12
opacity: mainView.loading ? 1 : 0
running: mainView.loading
}
}

View File

@@ -0,0 +1,58 @@
import QtQuick 1.1
import tomahawk 1.0
GridView {
id: root
signal itemClicked(int index)
property int spacing
delegate: Item {
width: root.cellWidth - root.spacing / 2
height: root.cellHeight - root.spacing / 2
Rectangle {
id: background
anchors.fill: parent
radius: defaultFontHeight / 2
opacity: 0.5
gradient: Gradient {
GradientStop { position: 0.0; color: "#00FFFFFF" }
GradientStop { position: 1.0; color: "#AAFFFFFF" }
}
states: [
State {
name: "hovered"; when: mouseArea.containsMouse
PropertyChanges { target: background; opacity: 1 }
}
]
transitions: [
Transition {
from: "*"; to: "hovered"
NumberAnimation { properties: "opacity"; duration: 100 }
},
Transition {
from: "hovered"; to: "*"
NumberAnimation { properties: "opacity"; duration: 600 }
}
]
}
CoverImage {
id: coverImage
height: parent.height
width: height
showLabels: true
artworkId: model.coverID
artistName: model.artistName
}
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: root.itemClicked(index)
hoverEnabled: true
}
}
}

View File

@@ -0,0 +1,52 @@
import QtQuick 1.1
Item {
id: busyIndicator
width: 100
height: width
property int barWidth: width / 10
property int barHeight: height / 4
property int count: 12
property color color: "white"
property int currentHighlight: 0
property bool running: true
property int interval: 200
Behavior on opacity {
NumberAnimation { duration: 500 }
}
Repeater {
model: busyIndicator.count
Item {
height: parent.height
width: busyIndicator.barWidth
anchors.centerIn: parent
Rectangle {
anchors {
top: parent.top
left: parent.left
right: parent.right
}
height: busyIndicator.barHeight
radius: width / 2
color: busyIndicator.color
}
rotation: 360 / busyIndicator.count * index
opacity: 1 - ((index > busyIndicator.currentHighlight ? busyIndicator.currentHighlight + busyIndicator.count : busyIndicator.currentHighlight) - index) / busyIndicator.count
Behavior on opacity {
NumberAnimation { duration: busyIndicator.interval }
}
}
}
Timer {
interval: busyIndicator.interval
running: busyIndicator.running
repeat: true
onTriggered: parent.currentHighlight = (parent.currentHighlight + 1) % busyIndicator.count
}
}

View File

@@ -0,0 +1,44 @@
import QtQuick 1.1
Rectangle {
id: root
height: contentRow.height + defaultFontHeight / 2
width: contentRow.width + defaultFontHeight / 2
property alias text: buttonText.text
property alias imageSource: image.source
property bool enabled: true
color: "transparent"
border.width: defaultFontHeight / 16
border.color: buttonMouseArea.containsMouse ? "lightblue" : "transparent"
radius: defaultFontHeight / 4
signal clicked()
Row {
id: contentRow
spacing: defaultFontHeight / 4
width: childrenRect.width
height: childrenRect.height
anchors.centerIn: parent
Image {
id: image
height: defaultFontHeight
width: source.length == 0 ? 0 : height
}
Text {
id: buttonText
color: root.enabled ? "black" : "grey"
}
}
MouseArea {
id: buttonMouseArea
anchors.fill: parent
hoverEnabled: root.enabled
enabled: root.enabled
onClicked: root.clicked();
}
}

View File

@@ -0,0 +1,135 @@
import QtQuick 1.1
import tomahawk 1.0
PathView {
id: coverView
// The start coordinates for the covers
// Default is left, centered in height
property int pathStartX: 0
property int pathStartY: height
// The size of the covers in the path
property int coverSize: height
property color backgroundColor: "black"
// emitted when a cover is clicked
signal itemClicked(int index)
// emitted when a cover is clicked
signal itemPlayPauseClicked(int index)
preferredHighlightBegin: 0.2 // scene.width / 11000
preferredHighlightEnd: preferredHighlightBegin
pathItemCount: 5
//highlightMoveDuration: 500
property bool itemHovered: false
delegate: Item {
id: delegateItem
height: coverView.coverSize
width: coverView.coverSize
scale: PathView.itemScale
// itemBrightness: PathView.itemBrightness - ((coverView.itemHovered && !coverDelegate.containsMouse) ? .4 : 0)
property double itemBrightness: PathView.itemBrightness
property double itemOpacity: PathView.itemOpacity
property int _origZ
z: coverView.width - x
CoverImage {
id: coverDelegate
height: coverView.coverSize
width: coverView.coverSize
anchors {
top: parent.top
right: parent.right
}
showLabels: true
showMirror: true
artistName: model.artistName
trackName: model.trackName
artworkId: model.coverID
showPlayButton: true
currentlyPlaying: isPlaying
smooth: true
// itemBrightness: PathView.itemBrightness - ((coverView.itemHovered && !coverDelegate.containsMouse) ? .4 : 0)
itemBrightness: coverDelegate.containsMouse ? 1 : parent.itemBrightness * (coverView.itemHovered ? .5 : 1)
opacity: parent.itemOpacity
z: coverView.width - x
onPlayClicked: {
console.log("***************")
coverView.itemPlayPauseClicked(index)
}
onClicked: {
coverView.itemClicked(index)
}
onContainsMouseChanged: {
if (containsMouse) {
delegateItem._origZ = delegateItem.z;
coverView.itemHovered = true
} else {
coverView.itemHovered = false
}
}
}
states: [
State {
name: "hovered"; when: coverDelegate.containsMouse && !coverView.moving && index !== currentIndex
PropertyChanges {
target: delegateItem
width: coverView.coverSize * 2
z: delegateItem._origZ
}
}
]
transitions: [
Transition {
NumberAnimation {
properties: "width"
duration: 300
easing.type: Easing.InOutSine
}
}
]
}
path: Path {
startX: coverView.pathStartX
startY: coverView.pathStartY
PathAttribute { name: "itemOpacity"; value: 0 }
PathAttribute { name: "itemBrightness"; value: 0 }
PathAttribute { name: "itemScale"; value: 1.3 }
PathLine { x: coverView.width / 4; y: coverView.height / 4 * 3}
PathPercent { value: 0.1 }
PathAttribute { name: "itemOpacity"; value: 0 }
PathAttribute { name: "itemBrightness"; value: 1 }
PathAttribute { name: "itemScale"; value: 1.0 }
PathLine { x: coverView.width / 2; y: coverView.height / 2}
PathPercent { value: 0.2 }
PathAttribute { name: "itemOpacity"; value: 1 }
PathAttribute { name: "itemBrightness"; value: 1 }
PathAttribute { name: "itemScale"; value: 0.5 }
PathLine { x: coverView.width; y: 0 }
PathPercent { value: 1 }
PathAttribute { name: "itemOpacity"; value: 1 }
PathAttribute { name: "itemBrightness"; value: 0 }
PathAttribute { name: "itemScale"; value: 0.1 }
}
}

View File

@@ -0,0 +1,84 @@
import QtQuick 1.1
import tomahawk 1.0
ListView {
id: coverView
property color backgroundColor: "black"
property int coverSize: height / 2
// emitted when a cover is clicked
signal itemClicked(int index)
// emitted when a cover is clicked
signal itemPlayPauseClicked(int index)
preferredHighlightBegin: (width / 2) - (coverSize / 4)
preferredHighlightEnd: preferredHighlightBegin + coverSize / 2
snapMode: ListView.SnapToItem
highlightRangeMode: ListView.StrictlyEnforceRange
highlightMoveDuration: 200
property bool itemHovered: false
orientation: ListView.Horizontal
delegate: Item {
id: delegateItem
height: parent.height
width: coverView.coverSize / 2
anchors.verticalCenter: ListView.view.verticalCenter
property real distanceFromLeftEdge: -coverView.contentX + index*width
property real distanceFromRightEdge: coverView.contentX + coverView.width - (index+1)*width
property real distanceFromEdge: Math.max(distanceFromLeftEdge, distanceFromRightEdge)
scale: 2 - (distanceFromEdge / (coverView.width))
property double itemBrightness: (1.3 - (distanceFromEdge / (coverView.width))) - ((coverView.itemHovered && !coverDelegate.containsMouse) ? .4 : 0)
property double itemOpacity: coverView.itemHovered && !coverDelegate.containsMouse ? 0.4 : 1
property int _origZ
z: -Math.abs(currentIndex - index)
CoverImage {
id: coverDelegate
height: coverView.coverSize / 2
width: parent.width
anchors {
verticalCenter: parent.verticalCenter
right: parent.right
}
showLabels: true
showMirror: false
artistName: model.artistName
trackName: model.trackName
artworkId: model.coverID
showPlayButton: true
currentlyPlaying: isPlaying
smooth: true
itemBrightness: coverDelegate.containsMouse ? 1 : parent.itemBrightness * (coverView.itemHovered ? .5 : 1)
opacity: parent.itemOpacity
z: coverView.width - x
onPlayClicked: {
console.log("***************")
coverView.itemPlayPauseClicked(index)
}
onClicked: {
coverView.itemClicked(index)
}
onContainsMouseChanged: {
if (containsMouse) {
delegateItem._origZ = delegateItem.z;
coverView.itemHovered = true
} else {
coverView.itemHovered = false
}
}
}
}
}

View File

@@ -0,0 +1,194 @@
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
// if this is true, the play button will be swapped by a pause button
property bool currentlyPlaying: false
// Should the mirror be painted?
property bool showMirror: false
// Labels & Cover
property string artistName
property string trackName
property string artworkId
// The border color for the cover image
property color borderColor: "black"
// The border width for the cover image
property int borderWidth: 2
// sets the brightness for the item and its mirror (1: brightest, 0: darkest)
property double itemBrightness: 1
property double mirrorBrightness: .5
// set this to true if you want to smoothly scale the cover (be aware of performance impacts)
property bool smooth: false
// will be emitted when the on hower play button is clicked
signal playClicked()
// will be emitted when the cover is clicked
signal clicked()
// will be emitted when the cover is hovered by the mouse
property alias containsMouse: mouseArea.containsMouse
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
print("Cover clicked");
root.clicked();
}
}
Rectangle {
id: itemShadow
color: "black"
anchors.fill: parent
//opacity: 1 - itemBrightness
Behavior on opacity {
NumberAnimation { easing.type: Easing.Linear; duration: 300 }
}
}
Component {
id: coverImage
Item {
property bool isMirror: false
Image {
anchors.fill: parent
source: "image://albumart/" + artworkId + (isMirror ? "-mirror" : "") + (showLabels ? "-labels" : "")
smooth: root.smooth
opacity: itemBrightness
Behavior on opacity {
NumberAnimation { duration: 300 }
}
}
Rectangle {
id: itemGlow
anchors.fill: parent
anchors.topMargin: isMirror ? parent.height / 2 : 0
opacity: (mouseArea.containsMouse ? .2 : 0)
Gradient {
id: glowGradient
GradientStop { position: 0.0; color: "white" }
GradientStop { position: 0.7; color: "white" }
GradientStop { position: 0.8; color: "#00000000" }
GradientStop { position: 1.0; color: "#00000000" }
}
Gradient {
id: mirrorGlowGradient
GradientStop { position: 0.0; color: "#00000000" }
GradientStop { position: 0.5; color: "#00000000" }
GradientStop { position: 1.0; color: "#44FFFFFF" }
}
states: [
State {
name: "mirrored"; when: isMirror
PropertyChanges {
target: itemGlow
gradient: mirrorGlowGradient
}
},
State {
name: "normal"; when: !isMirror
PropertyChanges {
target: itemGlow
gradient: glowGradient
}
}
]
Behavior on opacity {
NumberAnimation { easing.type: Easing.Linear; duration: 300 }
}
}
Text {
id: trackText
color: "white"
font.bold: true
text: trackName
anchors { left: parent.left; right: parent.right; bottom: artistText.top }
anchors.margins: 2
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
opacity: showLabels ? itemBrightness * (isMirror ? 0.5 : 1): 0
font.pixelSize: root.height / 15
Behavior on opacity {
NumberAnimation { duration: 300 }
}
}
Text {
id: artistText
color: "white"
font.bold: trackText.text.length == 0
text: artistName
anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
anchors.margins: root.height / 20
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
opacity: showLabels ? itemBrightness * (isMirror ? 0.5 : 1) : 0
font.pixelSize: trackText.text.length == 0 ? root.height / 10 : root.height / 15
Behavior on opacity {
NumberAnimation { duration: 300 }
}
}
}
}
Loader {
sourceComponent: coverImage
anchors.fill: parent
}
Loader {
id: mirroredCover
sourceComponent: parent.showMirror ? coverImage : undefined
anchors.fill: parent
onLoaded: {
item.isMirror = true
}
transform : [
Rotation {
angle: 180; origin.y: root.height
axis.x: 1; axis.y: 0; axis.z: 0
}
]
}
Image {
id: playButton
visible: showPlayButton ? (mouseArea.containsMouse || currentlyPlaying) : false
source: currentlyPlaying ? "../../images/pause-rest.svg" : "../../images/play-rest.svg"
anchors.centerIn: parent
height: mirroredCover.height / 5
width: height
smooth: root.smooth
MouseArea {
anchors.fill: parent
onClicked: {
print("Play button clicked");
root.playClicked();
}
}
}
}

View File

@@ -0,0 +1,225 @@
import QtQuick 1.1
Item {
id: root
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 bool minMaxLabelsVisible: true
property int lowerSliderPos: 25
property int upperSliderPos: 75
onUpperSliderPosChanged: print("fooooooooo", upperSliderPos)
signal valueChanged()
QtObject {
id: priv
property int steps: root.max - root.min + 1
property int sliderHeight: root.height / 3
property int sliderWidth: sliderHeight / 2
}
Row {
anchors.fill: parent
anchors.topMargin: defaultFontHeight * 1.2
anchors.bottomMargin: defaultFontHeight * 1.2
spacing: 10
Text {
id: minText
text: root.minLabel.length > 0 ? root.minLabel : min
color: "white"
visible: root.minMaxLabelsVisible
}
Item {
id: sliderRect
height: root.height / 4
property int maxWidth: parent.width - (minText.visible ? minText.width : 0) - (maxText.visible ? maxText.width : 0) - parent.spacing * 2
width: maxWidth - (maxWidth % priv.steps)
anchors.horizontalCenter: parent.horizontalCenter
function sliderPosToValue( sliderPos ) {
var percent = sliderPos * 100 / (sliderRect.width - priv.sliderWidth/2);
return Math.floor(percent * (priv.steps-1) / 100) + root.min
}
function valueToSloderPos( value ) {
var percent = (value - root.min) * 100 / (priv.steps-1)
return percent * (sliderRect.width - priv.sliderWidth/2) / 100
}
Rectangle {
id: sliderBase
height: parent.height
width: parent.width + defaultFontHeight * 1.5
color: "white"
radius: height / 2
anchors.centerIn: parent
gradient: Gradient {
GradientStop { position: 0.0; color: "#ffffffff" }
GradientStop { position: 1.0; color: "#aaffffff" }
}
Rectangle {
anchors.fill: sliderBase
anchors.leftMargin: lowerSlider.x + priv.sliderWidth
anchors.rightMargin: sliderBase.width - upperSlider.x - priv.sliderWidth
gradient: Gradient {
GradientStop { position: 0.0; color: "#aa962c26" }
GradientStop { position: 1.0; color: "#962c26" }
}
}
Row {
id: stepRow
anchors.fill: parent
anchors.leftMargin: defaultFontHeight - lineWidth/2
anchors.rightMargin: defaultFontHeight - lineWidth/2
property int stepCount: root.max - root.min + 1
property int lineHeight: height
property int lineWidth: lineHeight / 15
spacing: (width - (stepCount * lineWidth)) / stepCount
Repeater {
model: stepRow.stepCount
Rectangle {
id: marker
height: stepRow.lineHeight * (isHighlight ? 1.2 : 1)
width: stepRow.lineWidth
color: "black"
property bool isHighlight: index % 10 === 0
gradient: Gradient {
GradientStop { position: 0.0; color: marker.isHighlight ? "white" : "black" }
GradientStop { position: 1.0; color: marker.isHighlight ? "#aaffffff" : "black" }
}
Text {
text: root.min + index
visible: marker.isHighlight
anchors.horizontalCenter: marker.horizontalCenter
anchors.top: marker.bottom
anchors.topMargin: defaultFontHeight / 2
color: "white"
}
}
}
}
}
Rectangle {
id: lowerSlider
height: priv.sliderHeight
width: priv.sliderWidth
anchors.verticalCenter: sliderBase.verticalCenter
radius: height/4
border.color: "black"
border.width: 2
x: sliderRect.valueToSloderPos(root.lowerSliderPos) - priv.sliderWidth/2
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 - priv.sliderWidth) / 2
radius: height / 8
Text {
id: lowerFloatingText
anchors.centerIn: parent
text: sliderRect.sliderPosToValue(lowerSlider.x + priv.sliderWidth/2)
}
}
}
MouseArea {
id: lowerSliderMouseArea
anchors.fill: lowerSlider
drag.target: lowerSlider
drag.axis: "XAxis"
drag.minimumX: -priv.sliderWidth / 2
drag.maximumX: upperSlider.x - priv.sliderWidth
onReleased: {
root.lowerSliderPos = sliderRect.sliderPosToValue( lowerSlider.x + priv.sliderWidth/2 );
root.valueChanged();
}
}
Rectangle {
id: upperSlider
height: priv.sliderHeight
width: priv.sliderWidth
anchors.verticalCenter: sliderBase.verticalCenter
radius: height / 4
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 - priv.sliderWidth) / 2
Text {
id: upperFloatingText
anchors.centerIn: parent
text: sliderRect.sliderPosToValue(upperSlider.x + priv.sliderWidth/2)
}
}
}
MouseArea {
id: upperSliderMouseArea
anchors.fill: upperSlider
onClicked: print("button pressed")
drag.target: upperSlider
drag.axis: "XAxis"
drag.minimumX: lowerSlider.x + priv.sliderWidth
drag.maximumX: parent.width - priv.sliderWidth
onReleased: {
root.upperSliderPos = sliderRect.sliderPosToValue( upperSlider.x + priv.sliderWidth/2 );
root.valueChanged();
}
}
}
Text {
id: maxText
text: root.maxLabel.length > 0 ? root.maxLabel : max
color: "white"
visible: root.minMaxLabelsVisible
}
}
}

View File

@@ -0,0 +1,223 @@
import QtQuick 1.1
import tomahawk 1.0
Rectangle {
id: root
// The icon
property alias icon: iconImage.source
// The title
property alias title: titleItem.titleText
// The subtitle/description
property alias subtitle: subtitleText.text
// The model for the ToggleViewButtons.
// "modelData" role name holds the iconSource
// => You can use a QStringList or StandardListModel here
property alias buttonModel: toggleViewButtons.model
// The index of the currently selected item
property alias currentButtonIndex: toggleViewButtons.currentIndex
// Should we show the searchfield?
property bool showSearchField: true
// The SearchFields text
property alias searchText: searchField.text
property bool showBackButton: false
property bool showNextButton: false
property string backButtonText: "Back"
property string nextButtonText: "Next"
// Layout spacing
property int spacing: defaultFontHeight * 0.5
signal backPressed()
signal nextPressed()
signal savePressed()
gradient: Gradient {
GradientStop { position: 0.0; color: "#615858" }
GradientStop { position: 1.0; color: "#231F1F" }
}
Row {
id: leftRow
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
right: rightRow.left
}
anchors.margins: root.spacing
spacing: root.spacing
Image {
id: iconImage
height: parent.height * 0.8
width: height
anchors.verticalCenter: parent.verticalCenter
smooth: true
}
Column {
height: childrenRect.height
width: parent.width - iconImage.width - parent.spacing
anchors.verticalCenter: parent.verticalCenter
Item {
id: titleItem
height: captionText1.height
width: parent.width
clip: true
property string titleText
onTitleTextChanged: {
if(captionText1.text.length > 0) {
captionText2.text = titleText;
renewTitleAnimation.start();
} else {
captionText1.text = titleText;
}
}
ParallelAnimation {
id: renewTitleAnimation
property int duration: 500
property variant easingType: Easing.OutBounce;
NumberAnimation { target: captionText2; property: "anchors.topMargin"; to: 0; duration: renewTitleAnimation.duration; easing.type: renewTitleAnimation.easingType }
NumberAnimation { target: captionText1; property: "anchors.topMargin"; to: captionText1.height * 2; duration: renewTitleAnimation.duration; easing.type: renewTitleAnimation.easingType }
onCompleted: {
captionText1.text = titleItem.titleText
captionText2.anchors.topMargin = -captionText2.height * 2
captionText1.anchors.topMargin = 0
}
}
Text {
id: captionText1
color: "white"
anchors.left: parent.left
anchors.top: parent.top
font.pointSize: defaultFontSize * 1.5
font.bold: true
width: parent.width
elide: Text.ElideRight
}
Text {
id: captionText2
color: "white"
anchors.left: parent.left
anchors.top: parent.top
anchors.topMargin: -height * 2
font.pointSize: defaultFontSize * 1.5
font.bold: true
width: parent.width
elide: Text.ElideRight
}
}
Text {
id: subtitleText
color: "white"
font.pointSize: defaultFontSize * 1.2
width: parent.width
elide: Text.ElideRight
height: text.length > 0 ? defaultFontHeight : 0
opacity: text.length > 0 ? 1 : 0
Behavior on height {
NumberAnimation { duration: 200 }
}
Behavior on opacity {
NumberAnimation { duration: 200 }
}
onTextChanged: {
if (text.length > 0) {
animationText.text = text
}
}
Text {
id: animationText
color: parent.color
font: parent.font
elide: parent.elide
anchors.fill: parent
}
}
}
}
Row {
id: rightRow
anchors {
top: parent.top
right: parent.right
rightMargin: -backButton.width - root.spacing - nextButton.width
bottom: parent.bottom
margins: root.spacing
}
width: childrenRect.width
spacing: root.spacing
layoutDirection: Qt.RightToLeft
states: [
State {
name: "oneVisible"; when: root.showBackButton && !root.showNextButton
PropertyChanges {
target: rightRow
anchors.rightMargin: -nextButton.width
}
},
State {
name: "bothVisible"; when: root.showBackButton && root.showNextButton
PropertyChanges {
target: rightRow
anchors.rightMargin: root.spacing
}
}
]
Behavior on anchors.rightMargin {
NumberAnimation { duration: 200 }
}
PushButton {
id: nextButton
anchors.verticalCenter: parent.verticalCenter
text: root.nextButtonText
onClicked: root.nextPressed();
}
PushButton {
id: backButton
anchors.verticalCenter: parent.verticalCenter
text: root.backButtonText
onClicked: root.backPressed();
}
InputField {
id: searchField
visible: root.showSearchField
anchors.verticalCenter: parent.verticalCenter
placeholderText: "Search..."
showSearchIcon: true
}
ToggleViewButtons {
id: toggleViewButtons
anchors.verticalCenter: parent.verticalCenter
height: defaultFontHeight * 1.5
}
}
}

View File

@@ -0,0 +1,7 @@
import QtQuick 1.1
Text {
color: "white"
font.pointSize: defaultFontSize + 5
font.bold: true
}

View File

@@ -0,0 +1,114 @@
import QtQuick 1.1
import tomahawk 1.0
FocusScope {
id: root
property alias text: messageText.text
property alias inputText: inputField.text
property real arrowPosition: 1
height: contentColumn.height + defaultFontHeight * 2
signal accepted()
signal rejected()
onFocusChanged: {
if (focus) {
inputField.forceActiveFocus()
}
}
Behavior on opacity {
NumberAnimation { duration: 200 }
}
MouseArea {
anchors.fill: parent
anchors.margins: -999999999
hoverEnabled: root.opacity > 0
enabled: root.opacity > 0
onClicked: root.rejected();
}
Item {
id: backgroundItem
anchors.fill: parent
opacity: 0.9
Rectangle {
id: background
anchors.fill: parent
color: "white"
border.color: "black"
border.width: defaultFontHeight / 10
radius: defaultFontHeight / 2
anchors.topMargin: defaultFontHeight / 4
}
Item {
clip: true
anchors.bottom: backgroundItem.top
anchors.bottomMargin: -background.border.width*3
height: defaultFontHeight
width: height
x: defaultFontHeight - arrowRect.width/2 + (root.width - defaultFontHeight*2) * arrowPosition
Rectangle {
id: arrowRect
height: defaultFontHeight / 1.8
width: height
rotation: 45
color: "white"
anchors.centerIn: parent
anchors.verticalCenterOffset: parent.height/2
border.color: "black"
border.width: defaultFontHeight / 10
}
}
}
Column {
id: contentColumn
width: parent.width - defaultFontHeight
height: childrenRect.height
anchors.centerIn: parent
anchors.verticalCenterOffset: defaultFontHeight / 4
spacing: defaultFontHeight / 2
Row {
width: parent.width
height: childrenRect.height
spacing: defaultFontHeight / 2
Text {
id: messageText
wrapMode: Text.WordWrap
anchors.verticalCenter: parent.verticalCenter
}
InputField {
id: inputField
width: parent.width - x
anchors.verticalCenter: parent.verticalCenter
}
}
Row {
height: childrenRect.height
anchors.right: parent.right
spacing: defaultFontHeight
Button {
text: "OK"
imageSource: "qrc:///data/images/ok.svg"
enabled: inputField.text.length > 0
onClicked: root.accepted()
}
Button {
text: "Cancel"
imageSource: "qrc:///data/images/cancel.svg"
onClicked: {
inputField.text = ""
root.rejected()
}
}
}
}
}

View File

@@ -0,0 +1,162 @@
import QtQuick 1.1
Rectangle {
id: root
color: "white"
border.color: "black"
border.width: defaultFontHeight * 0.1
radius: defaultFontHeight * 0.25
height: textInput.height * 1.4
width: 300
property bool showSearchIcon: false
property string text: ""
property string placeholderText: ""
property variant completionModel
property int spacing: defaultFontHeight * 0.2
signal accepted( string text )
onFocusChanged: {
if(focus) {
textInput.forceActiveFocus();
}
}
Image {
id: searchIcon
anchors {
left: parent.left
leftMargin: root.spacing
verticalCenter: parent.verticalCenter
}
height: parent.height * 0.6
width: root.showSearchIcon ? height : 1
opacity: root.showSearchIcon ? 1 : 0
smooth: true
source: "../../images/search-icon.svg"
}
Item {
id: textItem
anchors.left: searchIcon.right
anchors.leftMargin: root.spacing
anchors.right: clearIcon.right
anchors.rightMargin: root.spacing
height: textInput.height
anchors.verticalCenter: parent.verticalCenter
TextInput {
id: textInput
width: parent.width
anchors.centerIn: parent
text: root.text
font.pointSize: defaultFontSize
onAccepted: root.accepted( text );
onTextChanged: {
root.text = text;
realCompletionListModel.clear();
for (var i in completionModel) {
if (completionModel[i].indexOf(text) == 0) {
realCompletionListModel.append({modelData: completionModel[i]})
}
}
}
}
Text {
width: parent.width
anchors.centerIn: parent
text: root.text.length === 0 ? root.placeholderText : ""
color: "lightgray"
font.pointSize: defaultFontSize
}
}
Image {
id: clearIcon
anchors {
right: parent.right
rightMargin: root.spacing
verticalCenter: parent.verticalCenter
}
height: parent.height * 0.8
width: (root.showSearchIcon && root.text.length > 0) ? height : 1
opacity: (root.showSearchIcon && root.text.length > 0) ? 1 : 0
smooth: true
source: "../../images/search-box-dismiss-x.svg"
MouseArea {
anchors.fill: parent
onClicked: textInput.text = ""
}
}
Image {
// source: "../../images/inputfield-border.svg"
anchors.fill: parent
anchors.margins: root.radius * 0.1
clip: true
}
Rectangle {
anchors {
top: parent.bottom
left: parent.left
right: parent.right
}
height: Math.min(completionListView.count, 10) * completionListView.delegateHeight
color: "white"
ListView {
id: completionListView
anchors.fill: parent
anchors.rightMargin: scrollBar.width + scrollBar.margin
clip: true
model: ListModel {
id: realCompletionListModel
}
property int delegateHeight: defaultFontHeight * 1.25
delegate: Rectangle {
height: completionListView.delegateHeight
color: delegateMouseArea.containsMouse ? "lightblue" : "transparent"
width: parent.width
Text {
anchors {
left: parent.left
right: parent.right
verticalCenter: parent.verticalCenter
margins: defaultFontHeight / 4
}
text: modelData
}
MouseArea {
id: delegateMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
textInput.text = modelData
realCompletionListModel.clear();
}
}
}
}
ScrollBar {
id: scrollBar
listView: completionListView
color: "black"
margin: 0
}
}
MouseArea {
anchors.fill: parent
anchors.margins: -99999999
z: -1
enabled: completionListView.count > 0
onClicked: {
realCompletionListModel.clear();
}
}
}

View File

@@ -0,0 +1,35 @@
import QtQuick 1.1
//import tomahawk 1.0
Rectangle {
id: root
height: buttonText.height * 1.4
width: buttonText.width + (spacing * 2)
radius: defaultFontHeight * 0.25
// border.width: defaultFontHeight * 0.05
// border.color: "#a7a7a7"
color: "white"
/* gradient: Gradient {
GradientStop { position: 0.0; color: mouseArea.pressed ? "#040404" : "#fbfbfb" }
GradientStop { position: 1.0; color: mouseArea.pressed ? "#8e8f8e" : "#787878" }
}*/
property int spacing: defaultFontHeight * 0.5
property alias text: buttonText.text
signal clicked()
Text {
id: buttonText
anchors.centerIn: root
font.pointSize: defaultFontSize
color: mouseArea.pressed ? "grey" : "black"
}
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: root.clicked()
}
}

View File

@@ -0,0 +1,43 @@
import QtQuick 1.1
import tomahawk 1.0
Rectangle {
id: root
border.width: 4
border.color: enabled ? "white" : "grey"
radius: height / 2
color: (buttonMouseArea.containsMouse && enabled) ? "#22ffffff" : "black"
opacity: hidden ? 0 : 1
height: defaultFontHeight * 2
width: height
property string text
property bool enabled: true
property bool hidden: false
signal clicked()
Behavior on opacity {
NumberAnimation { duration: 200 }
}
Behavior on color {
ColorAnimation { duration: 200 }
}
Text {
anchors.centerIn: parent
text: parent.text
color: root.border.color
font.pixelSize: parent.height * .75
font.bold: true
}
MouseArea {
id: buttonMouseArea
anchors.fill: parent
hoverEnabled: true
enabled: root.enabled
onClicked: parent.clicked()
}
}

View File

@@ -0,0 +1,71 @@
import QtQuick 1.1
Item {
id: scrollBar
width: defaultFontHeight / 2
// the ListView where to attach this scrollbar
property variant listView
// the orientation of the scrollbar
property variant orientation : Qt.Vertical
property int margin: defaultFontHeight * 0.25
property color color: "white"
states: [
State {
name: "hidden"; when: !listView.moving
PropertyChanges { target: scrollBar; opacity: 0 }
},
State {
name: "visible"; when: listView.moving
PropertyChanges { target: scrollBar; opacity: 1 }
}
]
transitions: [
Transition {
from: "hidden"
to: "visible"
NumberAnimation { properties: "opacity"; duration: 200 }
},
Transition {
from: "visible"
to: "hidden"
NumberAnimation { properties: "opacity"; duration: 2000 }
}
]
anchors {
left: orientation == Qt.Vertical ? listView.right : listView.left
leftMargin: orientation == Qt.Vertical ? scrollBar.margin : 0
top: orientation == Qt.Vertical ? listView.top : listView.bottom
topMargin: orientation == Qt.Vertical ? 0 : scrollBar.margin
bottom: orientation == Qt.Vertical ? listView.bottom : undefined
right: orientation == Qt.Vertical ? undefined : listView.right
}
// A light, semi-transparent background
Rectangle {
id: background
anchors.fill: parent
radius: orientation == Qt.Vertical ? (width/2 - 1) : (height/2 - 1)
color: scrollBar.color
opacity: 0.2
clip: true
// Size the bar to the required size, depending upon the orientation.
Rectangle {
property real position: orientation == Qt.Vertical ? (listView.contentY / listView.contentHeight) : (listView.contentX / listView.contentWidth)
property real pageSize: orientation == Qt.Vertical ? (listView.height / listView.contentHeight) : (listView.width / listView.contentWidth)
x: orientation == Qt.Vertical ? 1 : (position * (scrollBar.width-2) + 1)
y: orientation == Qt.Vertical ? (position * (scrollBar.height-2) + 1) : 1
width: orientation == Qt.Vertical ? (parent.width-2) : (pageSize * (scrollBar.width-2))
height: orientation == Qt.Vertical ? (pageSize * (scrollBar.height-2)) : (parent.height-2)
radius: orientation == Qt.Vertical ? (width/2 - 1) : (height/2 - 1)
color: scrollBar.color
opacity: 1
}
}
}

View File

@@ -0,0 +1,80 @@
import QtQuick 1.1
import tomahawk 1.0
Item {
id: tagCloud
property variant model: 10
signal tagClicked( string tag )
function randomNumber(min, max) {
var date = new Date();
return (max - min) * Math.random(date.getSeconds()) + min
}
Flow {
anchors.centerIn: parent
width: parent.width
spacing: defaultFontSize
Repeater {
id: cloudRepeater
model: tagCloud.model
delegate: Item {
id: cloudItem
width: delegateText.width * 1.1
height: delegateText.height
property double itemScale: tagCloud.randomNumber(0.5, 1.2)
scale: itemScale
Text {
id: delegateText
color: "gray"
//text: controlModel.controlAt( index ).summary
text: modelData
font.pixelSize: defaultFontHeight * 1.8
anchors.verticalCenter: parent.verticalCenter
//anchors.verticalCenterOffset: tagCloud.randomNumber(0, 15)
states: [
State {
name: "hovered"; when: cloudItemMouseArea.containsMouse
PropertyChanges {
target: delegateText
color: "white"
}
}
]
transitions: [
Transition {
from: "*"
to: "hovered"
ColorAnimation {
duration: 200
}
},
Transition {
from: "hovered"
to: "*"
ColorAnimation {
duration: 1000
}
}
]
}
MouseArea {
id: cloudItemMouseArea
hoverEnabled: true
anchors.fill: parent
onClicked: tagCloud.tagClicked( modelData )
}
Behavior on scale {
NumberAnimation { easing: Easing.Linear; duration: 1000 }
}
}
}
}
}

View File

@@ -0,0 +1,34 @@
import QtQuick 1.1
import tomahawk 1.0
Row {
id: root
width: repeater.width
property alias model: repeater.model
property int currentIndex: 0
Repeater {
id: repeater
height: root.height
width: count * height
delegate: Image {
height: repeater.height
width: height
source: "../../images/view-toggle-" + (index === root.currentIndex ? "active-" : "inactive-" ) + (index === 0 ? "left" : ( index === repeater.count - 1 ? "right" : "centre" )) + ".svg"
smooth: true
Image {
anchors.fill: parent
source: "../../images/" + modelData + (index === root.currentIndex ? "-active.svg" : "-inactive.svg")
}
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: root.currentIndex = index
}
}
}
}

View File

@@ -90,6 +90,32 @@
<file>data/images/star-unstarred.svg</file>
<file>data/images/apply-check.svg</file>
<file>data/stylesheets/topbar-radiobuttons.css</file>
<file>data/qml/tomahawkimports/CoverImage.qml</file>
<file>data/qml/tomahawkimports/ArtistView.qml</file>
<file>data/qml/tomahawkimports/HeaderLabel.qml</file>
<file>data/qml/tomahawkimports/TagCloud.qml</file>
<file>data/qml/tomahawkimports/ScrollBar.qml</file>
<file>data/qml/tomahawkimports/InputField.qml</file>
<file>data/qml/tomahawkimports/Button.qml</file>
<file>data/qml/tomahawkimports/DoubleSlider.qml</file>
<file>data/qml/tomahawkimports/RoundedButton.qml</file>
<file>data/qml/tomahawkimports/PushButton.qml</file>
<file>data/qml/tomahawkimports/CoverFlip.qml</file>
<file>data/qml/tomahawkimports/CoverFlow.qml</file>
<file>data/qml/tomahawkimports/BusyIndicator.qml</file>
<file>data/qml/tomahawkimports/InputBubble.qml</file>
<file>data/qml/StationView.qml</file>
<file>data/qml/stations/StationItem.qml</file>
<file>data/qml/stations/StationCreatorPage1.qml</file>
<file>data/qml/stations/StationCreatorPage2.qml</file>
<file>data/qml/stations/CreateByArtist.qml</file>
<file>data/qml/stations/CreateByYear.qml</file>
<file>data/qml/stations/StationConfig.qml</file>
<file>data/qml/QmlGridView.qml</file>
<file>data/qml/stations/CreateByGenre.qml</file>
<file>data/qml/tomahawkimports/FlexibleHeader.qml</file>
<file>data/qml/tomahawkimports/ToggleViewButtons.qml</file>
<file>data/qml/DeclarativeHeader.qml</file>
<file>data/icons/tomahawk-icon-16x16.png</file>
<file>data/icons/tomahawk-icon-32x32.png</file>
<file>data/icons/tomahawk-icon-64x64.png</file>
@@ -151,6 +177,12 @@
<file>data/images/refresh.svg</file>
<file>data/images/inbox.svg</file>
<file>data/images/new-inbox.svg</file>
<file>data/images/inputfield-border.svg</file>
<file>data/images/search-box-dismiss-x.svg</file>
<file>data/images/loading-animation.svg</file>
<file>data/images/station-artist.svg</file>
<file>data/images/station-genre.svg</file>
<file>data/images/station-year.svg</file>
<file>data/images/outbox.svg</file>
<file>data/images/inbox-512x512.png</file>
<file>data/images/network-activity.svg</file>

View File

@@ -37,6 +37,7 @@ using namespace Tomahawk;
QHash< QString, album_wptr > Album::s_albumsByName = QHash< QString, album_wptr >();
QHash< unsigned int, album_wptr > Album::s_albumsById = QHash< unsigned int, album_wptr >();
QHash< QString, album_ptr > Album::s_albumsByCoverId = QHash< QString, album_ptr >();
static QMutex s_nameCacheMutex;
static QReadWriteLock s_idMutex;
@@ -79,6 +80,7 @@ Album::get( const Tomahawk::artist_ptr& artist, const QString& name, bool autoCr
album->setWeakRef( album.toWeakRef() );
album->loadId( autoCreate );
s_albumsByName.insert( key, album );
s_albumsByCoverId.insert( album->coverId(), album );
return album;
}
@@ -110,6 +112,7 @@ Album::get( unsigned int id, const QString& name, const Tomahawk::artist_ptr& ar
album_ptr a = album_ptr( new Album( id, name, artist ), &Album::deleteLater );
a->setWeakRef( a.toWeakRef() );
s_albumsByName.insert( key, a );
s_albumsByCoverId.insert( a->coverId(), a );
if ( id > 0 )
{
@@ -122,6 +125,18 @@ Album::get( unsigned int id, const QString& name, const Tomahawk::artist_ptr& ar
}
album_ptr
Album::getByCoverId( const QString& uuid )
{
QMutexLocker lock( &s_nameCacheMutex );
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 )
@@ -327,6 +342,10 @@ Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData,
m_coverBuffer = ba;
}
s_albumsByCoverId.remove( coverId() );
m_coverId = uuid();
s_albumsByCoverId.insert( m_coverId, m_ownRef.toStrongRef() );
m_coverLoaded = true;
emit coverChanged();
}
@@ -383,3 +402,13 @@ Album::infoid() const
return m_uuid;
}
QString
Album::coverId() const
{
if ( m_coverId.isEmpty() )
m_coverId = uuid();
return m_coverId;
}

View File

@@ -45,12 +45,14 @@ 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 );
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;
QString coverId() const;
QString name() const { return m_name; }
QString sortname() const { return m_sortname; }
@@ -98,6 +100,7 @@ private:
mutable bool m_coverLoaded;
mutable bool m_coverLoading;
mutable QString m_uuid;
mutable QString m_coverId;
mutable QByteArray m_coverBuffer;
#ifndef ENABLE_HEADLESS
@@ -110,6 +113,7 @@ private:
static QHash< QString, album_wptr > s_albumsByName;
static QHash< unsigned int, album_wptr > s_albumsById;
static QHash< QString, album_ptr > s_albumsByCoverId;
friend class ::IdThreadWorker;
};

View File

@@ -40,6 +40,7 @@ using namespace Tomahawk;
QHash< QString, artist_wptr > Artist::s_artistsByName = QHash< QString, artist_wptr >();
QHash< unsigned int, artist_wptr > Artist::s_artistsById = QHash< unsigned int, artist_wptr >();
QHash< QString, artist_ptr > Artist::s_artistsByCoverId = QHash< QString, artist_ptr >();
static QMutex s_nameCacheMutex;
static QReadWriteLock s_idMutex;
@@ -79,6 +80,7 @@ Artist::get( const QString& name, bool autoCreate )
artist->setWeakRef( artist.toWeakRef() );
artist->loadId( autoCreate );
s_artistsByName.insert( key, artist );
s_artistsByCoverId.insert( artist->coverId(), artist );
return artist;
}
@@ -112,6 +114,7 @@ Artist::get( unsigned int id, const QString& name )
artist_ptr a = artist_ptr( new Artist( id, name ), &Artist::deleteLater );
a->setWeakRef( a.toWeakRef() );
s_artistsByName.insert( key, a );
s_artistsByCoverId.insert( a->coverId(), a );
if ( id > 0 )
{
@@ -124,6 +127,18 @@ Artist::get( unsigned int id, const QString& name )
}
artist_ptr
Artist::getByCoverId( const QString& uuid )
{
QMutexLocker lock( &s_nameCacheMutex );
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 )
@@ -525,6 +540,10 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari
m_coverBuffer = ba;
}
s_artistsByCoverId.remove( coverId() );
m_coverId = uuid();
s_artistsByCoverId.insert( m_coverId, m_ownRef.toStrongRef() );
m_coverLoaded = true;
emit coverChanged();
}
@@ -686,3 +705,13 @@ Artist::infoid() const
return m_uuid;
}
QString
Artist::coverId() const
{
if ( m_coverId.isEmpty() )
m_coverId = uuid();
return m_coverId;
}

View File

@@ -44,12 +44,14 @@ 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 );
Artist( unsigned int id, const QString& name );
explicit Artist( const QString& name );
virtual ~Artist();
unsigned int id() const;
QString coverId() const;
QString name() const { return m_name; }
QString sortname() const { return m_sortname; }
@@ -122,6 +124,7 @@ private:
bool m_biographyLoaded;
mutable QString m_uuid;
mutable QString m_coverId;
mutable int m_infoJobs;
QList<Tomahawk::album_ptr> m_databaseAlbums;
@@ -144,6 +147,7 @@ private:
static QHash< QString, artist_wptr > s_artistsByName;
static QHash< unsigned int, artist_wptr > s_artistsById;
static QHash< QString, artist_ptr > s_artistsByCoverId;
friend class ::IdThreadWorker;
};

View File

@@ -80,19 +80,21 @@ set( libGuiSources
playlist/PlayableItem.cpp
playlist/SingleTrackPlaylistInterface.cpp
playlist/dynamic/GeneratorInterface.cpp
playlist/dynamic/DynamicPlaylist.cpp
playlist/dynamic/DynamicView.cpp
playlist/dynamic/DynamicModel.cpp
playlist/dynamic/echonest/EchonestGenerator.cpp
playlist/dynamic/echonest/EchonestControl.cpp
playlist/dynamic/echonest/EchonestSteerer.cpp
playlist/dynamic/widgets/DynamicWidget.cpp
# playlist/dynamic/echonest/EchonestSteerer.cpp
# playlist/dynamic/widgets/DynamicWidget.cpp
playlist/dynamic/widgets/DynamicQmlWidget.cpp
playlist/dynamic/widgets/DynamicControlWrapper.cpp
playlist/dynamic/widgets/DynamicControlList.cpp
# playlist/dynamic/widgets/DynamicControlList.cpp
playlist/dynamic/widgets/ReadOrWriteWidget.cpp
playlist/dynamic/widgets/MiscControlWidgets.cpp
playlist/dynamic/widgets/CollapsibleControls.cpp
playlist/dynamic/widgets/DynamicSetupWidget.cpp
# playlist/dynamic/widgets/CollapsibleControls.cpp
# playlist/dynamic/widgets/DynamicSetupWidget.cpp
resolvers/ExternalResolverGui.cpp
resolvers/ScriptResolver.cpp
@@ -126,6 +128,8 @@ set( libGuiSources
utils/ResultUrlChecker.cpp
utils/NetworkReply.cpp
widgets/DeclarativeCoverArtProvider.cpp
widgets/DeclarativeView.cpp
widgets/AnimatedCounterLabel.cpp
widgets/BasicHeader.cpp
widgets/FilterHeader.cpp
@@ -329,7 +333,7 @@ list(APPEND libSources
playlist/dynamic/GeneratorInterface.cpp
playlist/dynamic/DynamicPlaylistRevision.cpp
playlist/XspfUpdater.cpp
playlist/dynamic/database/DatabaseGenerator.cpp
# playlist/dynamic/database/DatabaseGenerator.cpp
playlist/dynamic/database/DatabaseControl.cpp
playlist/dynamic/DynamicControl.cpp
@@ -519,6 +523,7 @@ TARGET_LINK_LIBRARIES( tomahawklib
${QT_QTXML_LIBRARY}
${QT_QTSVG_LIBRARY}
${QT_QTCORE_LIBRARY}
${QT_QTDECLARATIVE_LIBRARY}
${OS_SPECIFIC_LINK_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${LINK_LIBRARIES}

View File

@@ -228,7 +228,10 @@ GlobalActionManager::copyPlaylistToClipboard( const dynplaylist_ptr& playlist )
TomahawkUtils::urlAddQueryItem( link, "type", "echonest" );
TomahawkUtils::urlAddQueryItem( link, "title", playlist->title() );
QList< dyncontrol_ptr > controls = playlist->generator()->controls();
Q_ASSERT( false );
//FIXME
/*
QVariantList controls = playlist->generator()->controls();
foreach ( const dyncontrol_ptr& c, controls )
{
if ( c->selectedType() == "Artist" )
@@ -255,7 +258,7 @@ GlobalActionManager::copyPlaylistToClipboard( const dynplaylist_ptr& playlist )
TomahawkUtils::urlAddQueryItem( link, name, c->input() );
}
}
}*/
QClipboard* cb = QApplication::clipboard();
QByteArray data = percentEncode( link );
@@ -889,7 +892,8 @@ GlobalActionManager::loadDynamicPlaylist( const QUrl& url, bool station )
return Tomahawk::dynplaylist_ptr();
}
if ( parts[ 0 ] == "create" )
Q_ASSERT( false );
/* if ( parts[ 0 ] == "create" )
{
if ( !urlHasQueryItem( url, "title" ) || !urlHasQueryItem( url, "type" ) )
{
@@ -1060,7 +1064,7 @@ GlobalActionManager::loadDynamicPlaylist( const QUrl& url, bool station )
ViewManager::instance()->show( pl );
return pl;
}
}*/
return Tomahawk::dynplaylist_ptr();
}

View File

@@ -528,10 +528,25 @@ Track::coverLoaded() const
return m_artistPtr->coverLoaded();
}
#endif
QString
Track::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();
}
QList<Tomahawk::query_ptr>
Track::similarTracks() const
{

View File

@@ -86,6 +86,7 @@ public:
QPixmap cover( const QSize& size, bool forceLoad = true ) const;
#endif
bool coverLoaded() const;
QString coverId() const;
void setLoved( bool loved, bool postToInfoSystem = true );
bool loved();

View File

@@ -44,7 +44,8 @@
#include "playlist/InboxView.h"
#include "playlist/PlaylistLargeItemDelegate.h"
#include "playlist/RecentlyPlayedModel.h"
#include "playlist/dynamic/widgets/DynamicWidget.h"
//#include "playlist/dynamic/widgets/DynamicWidget.h"
#include "playlist/dynamic/widgets/DynamicQmlWidget.h"
#include "widgets/NewReleasesWidget.h"
#include "widgets/Dashboard.h"
@@ -85,6 +86,7 @@ ViewManager::ViewManager( QObject* parent )
, m_newReleasesWidget( 0 )
, m_recentPlaysWidget( 0 )
, m_inboxWidget( 0 )
, m_radioView( 0 )
, m_networkActivityWidget( 0 )
, m_currentPage( 0 )
{
@@ -195,8 +197,8 @@ ViewManager::playlistForPage( ViewPage* page ) const
{
p = dynamic_cast< PlaylistView* >( page )->playlistModel()->playlist();
}
else if ( dynamic_cast< DynamicWidget* >( page ) )
p = dynamic_cast< DynamicWidget* >( page )->playlist();
else if ( dynamic_cast< DynamicQmlWidget* >( page ) )
p = dynamic_cast< DynamicQmlWidget* >( page )->playlist();
return p;
}
@@ -230,7 +232,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();
}
@@ -387,6 +389,22 @@ ViewManager::showSuperCollection()
}
Tomahawk::ViewPage*
ViewManager::showRadioPage()
{
if ( !m_radioView )
{
dynplaylist_ptr playlist = DynamicPlaylist::create( SourceList::instance()->getLocal(), uuid(), QString(), "", SourceList::instance()->getLocal()->friendlyName(), OnDemand, false, QString(), false, true );
playlist->setMode( OnDemand );
m_radioView = new Tomahawk::DynamicQmlWidget( playlist, m_stack );
}
setPage( m_radioView );
return m_radioView;
}
void
ViewManager::playlistInterfaceChanged( Tomahawk::playlistinterface_ptr interface )
{
@@ -830,7 +848,7 @@ ViewManager::playlistForInterface( Tomahawk::playlistinterface_ptr interface ) c
Tomahawk::dynplaylist_ptr
ViewManager::dynamicPlaylistForInterface( Tomahawk::playlistinterface_ptr interface ) const
{
foreach ( QPointer<DynamicWidget> view, m_dynamicWidgets.values() )
foreach ( QPointer<DynamicQmlWidget> view, m_dynamicWidgets.values() )
{
if ( !view.isNull() && view.data()->playlistInterface() == interface )
{

View File

@@ -64,7 +64,7 @@ class NetworkActivityWidget;
namespace Tomahawk
{
class DynamicWidget;
class DynamicQmlWidget;
}
class DLLEXPORT ViewManager : public QObject
@@ -139,6 +139,7 @@ signals:
void viewPageAdded( const QString& pageName, const QString& text, const QIcon& icon );
public slots:
Tomahawk::ViewPage* showRadioPage();
Tomahawk::ViewPage* showSuperCollection();
Tomahawk::ViewPage* showDashboard();
Tomahawk::ViewPage* showWhatsHotPage();
@@ -200,6 +201,7 @@ private:
NewReleasesWidget* m_newReleasesWidget;
Tomahawk::ViewPage* m_recentPlaysWidget;
Tomahawk::ViewPage* m_inboxWidget;
Tomahawk::DynamicQmlWidget* m_radioView;
InboxModel* m_inboxModel;
NetworkActivityWidget* m_networkActivityWidget;
@@ -208,7 +210,7 @@ private:
QList< Tomahawk::collection_ptr > m_superCollections;
QHash< Tomahawk::dynplaylist_ptr, QPointer<Tomahawk::DynamicWidget> > m_dynamicWidgets;
QHash< Tomahawk::dynplaylist_ptr, QPointer<Tomahawk::DynamicQmlWidget> > m_dynamicWidgets;
QHash< Tomahawk::collection_ptr, QPointer<FlexibleTreeView> > m_collectionViews;
QHash< Tomahawk::artist_ptr, QPointer<ArtistInfoWidget> > m_artistViews;
QHash< Tomahawk::album_ptr, QPointer<AlbumInfoWidget> > m_albumViews;

View File

@@ -52,7 +52,7 @@ DatabaseCommand_LoadDynamicPlaylistEntries::exec( DatabaseImpl* dbi )
QString type;
GeneratorMode mode;
QList< QVariantMap > controls;
QVariantList controls;
QString playlist_guid;
// qDebug() << "Loading controls..." << revisionGuid();
// qDebug() << "SELECT playlist_revision.playlist, controls, plmode, pltype "
@@ -72,7 +72,7 @@ DatabaseCommand_LoadDynamicPlaylistEntries::exec( DatabaseImpl* dbi )
mode = static_cast<GeneratorMode>( controlsQuery.value( 2 ).toInt() );
QStringList controlIds = v.toStringList();
// qDebug() << "Got controls in dynamic playlist, loading:" << controlIds << controlsQuery.value(1);
tDebug() << "Got controls in dynamic playlist, loading:" << controlIds << controlsQuery.value(1);
foreach( const QString& controlId, controlIds )
{
TomahawkSqlQuery controlQuery = dbi->newquery();

View File

@@ -47,14 +47,14 @@ signals:
void done( QString,
bool,
QString,
QList< QVariantMap>,
QVariantList,
bool );
// used when loading a static playlist
void done( QString,
QList< QString >,
QList< QString >,
QString,
QList< QVariantMap>,
QVariantList,
bool,
QMap< QString, Tomahawk::plentry_ptr >,
bool );

View File

@@ -41,7 +41,7 @@ DatabaseCommand_SetDynamicPlaylistRevision::DatabaseCommand_SetDynamicPlaylistRe
const QList<plentry_ptr>& entries,
const QString& type,
GeneratorMode mode,
const QList< dyncontrol_ptr >& controls )
const QVariantList& controls )
: DatabaseCommand_SetPlaylistRevision( s, playlistguid, newrev, oldrev, orderedguids, addedentries, entries )
, m_type( type )
, m_mode( mode )
@@ -58,7 +58,7 @@ DatabaseCommand_SetDynamicPlaylistRevision::DatabaseCommand_SetDynamicPlaylistRe
const QString& oldrev,
const QString& type,
GeneratorMode mode,
const QList< dyncontrol_ptr >& controls )
const QVariantList& controls )
: DatabaseCommand_SetPlaylistRevision( s, playlistguid, newrev, oldrev, QStringList(), QList< plentry_ptr >(), QList< plentry_ptr >() )
, m_type( type )
, m_mode( mode )
@@ -72,18 +72,7 @@ DatabaseCommand_SetDynamicPlaylistRevision::DatabaseCommand_SetDynamicPlaylistRe
QVariantList
DatabaseCommand_SetDynamicPlaylistRevision::controlsV()
{
if ( m_controls.isEmpty() )
return m_controlsV;
if ( !m_controls.isEmpty() && m_controlsV.isEmpty() )
{
foreach ( const dyncontrol_ptr& control, m_controls )
{
m_controlsV << QJson::QObjectHelper::qobject2qvariant( control.data() );
}
}
return m_controlsV;
return m_controls;
}
@@ -126,7 +115,7 @@ DatabaseCommand_SetDynamicPlaylistRevision::postCommitHook()
return;
}
if ( !m_controlsV.isEmpty() && m_controls.isEmpty() )
/* if ( !m_controlsV.isEmpty() && m_controls.isEmpty() )
{
QList<QVariantMap> controlMap;
foreach( const QVariant& v, m_controlsV )
@@ -148,7 +137,7 @@ DatabaseCommand_SetDynamicPlaylistRevision::postCommitHook()
m_addedmap,
m_applied );
}
else
else*/
{
if ( m_mode == OnDemand )
rawPl->setRevision( newrev(),
@@ -180,19 +169,9 @@ DatabaseCommand_SetDynamicPlaylistRevision::exec( DatabaseImpl* lib )
return;
QVariantList newcontrols;
if ( m_controlsV.isEmpty() && !m_controls.isEmpty() )
foreach( const QVariant& v, m_controls )
{
foreach( const dyncontrol_ptr& control, m_controls )
{
newcontrols << control->id();
}
}
else if( !m_controlsV.isEmpty() )
{
foreach( const QVariant& v, m_controlsV )
{
newcontrols << v.toMap().value( "id" );
}
newcontrols << v.toMap().value( "id" );
}
QJson::Serializer ser;
@@ -220,34 +199,18 @@ DatabaseCommand_SetDynamicPlaylistRevision::exec( DatabaseImpl* lib )
TomahawkSqlQuery controlsQuery = lib->newquery();
controlsQuery.prepare( "INSERT INTO dynamic_playlist_controls( id, playlist, selectedType, match, input ) "
"VALUES( ?, ?, ?, ?, ? )" );
if ( m_controlsV.isEmpty() && !m_controls.isEmpty() )
{
foreach ( const dyncontrol_ptr& control, m_controls )
{
qDebug() << "inserting dynamic control:" << control->id() << m_playlistguid << control->selectedType() << control->match() << control->input();
controlsQuery.addBindValue( control->id() );
controlsQuery.addBindValue( m_playlistguid );
controlsQuery.addBindValue( control->selectedType() );
controlsQuery.addBindValue( control->match() );
controlsQuery.addBindValue( control->input() );
controlsQuery.exec();
}
}
else
foreach ( const QVariant& v, m_controls )
{
foreach ( const QVariant& v, m_controlsV )
{
QVariantMap control = v.toMap();
qDebug() << "inserting dynamic control from JSON:" << control.value( "id" ) << m_playlistguid << control.value( "selectedType" ) << control.value( "match" ) << control.value( "input" );
controlsQuery.addBindValue( control.value( "id" ) );
controlsQuery.addBindValue( m_playlistguid );
controlsQuery.addBindValue( control.value( "selectedType" ) );
controlsQuery.addBindValue( control.value( "match" ) );
controlsQuery.addBindValue( control.value( "input" ) );
QVariantMap control = v.toMap();
qDebug() << "inserting dynamic control from JSON:" << control.value( "id" ) << m_playlistguid << control.value( "selectedType" ) << control.value( "match" ) << control.value( "input" );
controlsQuery.addBindValue( control.value( "id" ) );
controlsQuery.addBindValue( m_playlistguid );
controlsQuery.addBindValue( control.value( "selectedType" ) );
controlsQuery.addBindValue( control.value( "match" ) );
controlsQuery.addBindValue( control.value( "input" ) );
controlsQuery.exec();
}
controlsQuery.exec();
}
if ( m_applied )
@@ -263,6 +226,7 @@ DatabaseCommand_SetDynamicPlaylistRevision::exec( DatabaseImpl* lib )
}
}
void
DatabaseCommand_SetDynamicPlaylistRevision::setPlaylist( DynamicPlaylist* pl )
{

View File

@@ -45,7 +45,7 @@ public:
const QList<plentry_ptr>& entries,
const QString& type,
GeneratorMode mode,
const QList< dyncontrol_ptr >& controls );
const QVariantList& controls );
explicit DatabaseCommand_SetDynamicPlaylistRevision( const source_ptr& s,
const QString& playlistguid,
@@ -53,7 +53,7 @@ public:
const QString& oldrev,
const QString& type,
GeneratorMode mode,
const QList< dyncontrol_ptr >& controls );
const QVariantList& controls );
QString commandname() const { return "setdynamicplaylistrevision"; }
@@ -64,7 +64,7 @@ public:
void setControlsV( const QVariantList& vlist )
{
m_controlsV = vlist;
m_controls = vlist;
}
QVariantList controlsV();
@@ -80,8 +80,7 @@ public:
private:
QString m_type;
GeneratorMode m_mode;
QList< dyncontrol_ptr > m_controls;
QList< QVariant > m_controlsV;
QVariantList m_controls;
// ARG i hate sharedpointers sometimes
DynamicPlaylist* m_playlist; // Only used if setting revision of a non-autoloaded playlist, as those aren't able to be looked up by guid

View File

@@ -207,6 +207,14 @@ PlayableItem::artistName() const
{
return m_query->track()->artist();
}
else if ( !m_album.isNull() )
{
return m_album->artist()->name();
}
else if ( !m_artist.isNull() )
{
return m_artist->name();
}
return QString();
}

View File

@@ -31,6 +31,10 @@
class DLLEXPORT PlayableItem : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name NOTIFY dataChanged)
Q_PROPERTY(QString artistName READ artistName NOTIFY dataChanged)
Q_PROPERTY(QString albumName READ albumName NOTIFY dataChanged)
Q_PROPERTY(bool isPlaying READ isPlaying NOTIFY dataChanged)
public:
~PlayableItem();

View File

@@ -46,6 +46,13 @@ PlayableModel::PlayableModel( QObject* parent, bool loading )
, m_readOnly( true )
, m_loading( loading )
{
QHash<int, QByteArray> roleNames;
roleNames.insert( ArtistRole, "artistName" );
roleNames.insert( TrackRole, "trackName" );
roleNames.insert( CoverIDRole, "coverID" );
roleNames.insert( IsPlayingRole, "isPlaying" );
setRoleNames( roleNames );
connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ), Qt::DirectConnection );
connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ), Qt::DirectConnection );
@@ -143,6 +150,12 @@ PlayableModel::parent( const QModelIndex& child ) const
QVariant
PlayableModel::artistData( const artist_ptr& artist, int role ) const
{
if ( role == CoverIDRole )
{
artist->cover( QSize( 0, 0 ) );
return artist->coverId();
}
if ( role != Qt::DisplayRole ) // && role != Qt::ToolTipRole )
return QVariant();
@@ -153,6 +166,12 @@ PlayableModel::artistData( const artist_ptr& artist, int role ) const
QVariant
PlayableModel::albumData( const album_ptr& album, int role ) const
{
if ( role == CoverIDRole )
{
album->cover( QSize( 0, 0 ) );
return album->coverId();
}
if ( role != Qt::DisplayRole ) // && role != Qt::ToolTipRole )
return QVariant();
@@ -163,6 +182,13 @@ PlayableModel::albumData( const album_ptr& album, int role ) const
QVariant
PlayableModel::queryData( const query_ptr& query, int column, int role ) const
{
if ( role == CoverIDRole )
{
query->track()->cover( QSize( 0, 0 ) );
return query->track()->coverId();
}
tDebug() << Q_FUNC_INFO << role;
if ( role != Qt::DisplayRole ) // && role != Qt::ToolTipRole )
return QVariant();
@@ -300,6 +326,11 @@ PlayableModel::data( const QModelIndex& index, int role ) const
switch ( role )
{
case IsPlayingRole:
{
return entry->isPlaying();
break;
}
case Qt::TextAlignmentRole:
{
return QVariant( columnAlignment( index.column() ) );
@@ -809,6 +840,13 @@ PlayableModel::finishLoading()
}
PlayableItem*
PlayableModel::itemFromIndex( int itemIndex ) const
{
return itemFromIndex( index( itemIndex, 0, QModelIndex() ) );
}
PlayableItem*
PlayableModel::itemFromIndex( const QModelIndex& index ) const
{

View File

@@ -120,6 +120,7 @@ public:
virtual void ensureResolved();
Q_INVOKABLE PlayableItem* itemFromIndex( int itemIndex ) const;
virtual PlayableItem* itemFromIndex( const QModelIndex& index ) const;
virtual PlayableItem* itemFromQuery( const Tomahawk::query_ptr& query ) const;
virtual PlayableItem* itemFromResult( const Tomahawk::result_ptr& result ) const;

View File

@@ -627,6 +627,15 @@ PlayableProxyModel::setFilter( const QString& pattern )
}
PlayableItem*
PlayableProxyModel::itemFromIndex( int itemIndex ) const
{
// qDebug() << "returning item" << sourceModel()->itemFromIndex( itemIndex )->name();
QModelIndex modelIndex = index( itemIndex, 0 );
return sourceModel()->itemFromIndex( mapToSource( modelIndex ) );
}
void
PlayableProxyModel::setCurrentIndex( const QModelIndex& index )
{

View File

@@ -36,7 +36,7 @@ public:
{ Detailed = 0, Short = 1, ShortWithAvatars = 2, Large = 3, Collection = 4 };
enum PlayableProxyModelRole
{ StyleRole = Qt::UserRole + 1, TypeRole };
{ StyleRole = Qt::UserRole + 100, TypeRole };
explicit PlayableProxyModel ( QObject* parent = 0 );
virtual ~PlayableProxyModel() {}
@@ -68,6 +68,7 @@ public:
virtual int maxVisibleItems() const { return m_maxVisibleItems; }
virtual void setMaxVisibleItems( int items );
Q_INVOKABLE virtual PlayableItem* itemFromIndex( int itemIndex ) const;
virtual PlayableItem* itemFromIndex( const QModelIndex& index ) const { return sourceModel()->itemFromIndex( index ); }
virtual PlayableItem* itemFromQuery( const Tomahawk::query_ptr& query ) const { return sourceModel()->itemFromQuery( query ); }
virtual PlayableItem* itemFromResult( const Tomahawk::result_ptr& result ) const { return sourceModel()->itemFromResult( result ); }

View File

@@ -151,17 +151,22 @@ DynamicPlaylist::create( const Tomahawk::source_ptr& author,
GeneratorMode mode,
bool shared,
const QString& type,
bool autoLoad
bool autoLoad,
bool temporary
)
{
dynplaylist_ptr dynplaylist = Tomahawk::dynplaylist_ptr( new DynamicPlaylist( author, guid, title, info, creator, type, mode, shared, autoLoad ), &QObject::deleteLater );
dynplaylist->setWeakSelf( dynplaylist.toWeakRef() );
DatabaseCommand_CreateDynamicPlaylist* cmd = new DatabaseCommand_CreateDynamicPlaylist( author, dynplaylist, autoLoad );
connect( cmd, SIGNAL(finished()), dynplaylist.data(), SIGNAL(created()) );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
if ( autoLoad )
dynplaylist->reportCreated( dynplaylist );
if ( !temporary )
{
DatabaseCommand_CreateDynamicPlaylist* cmd = new DatabaseCommand_CreateDynamicPlaylist( author, dynplaylist, autoLoad );
connect( cmd, SIGNAL(finished()), dynplaylist.data(), SIGNAL(created()) );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
if ( autoLoad )
dynplaylist->reportCreated( dynplaylist );
}
return dynplaylist;
}
@@ -185,7 +190,7 @@ void
DynamicPlaylist::createNewRevision( const QString& newrev,
const QString& oldrev,
const QString& type,
const QList< dyncontrol_ptr>& controls,
const QVariantList& controls,
const QList< plentry_ptr >& entries )
{
Q_ASSERT( m_source->isLocal() || newrev == oldrev );
@@ -233,7 +238,7 @@ void
DynamicPlaylist::createNewRevision( const QString& newrev,
const QString& oldrev,
const QString& type,
const QList< dyncontrol_ptr>& controls )
const QVariantList& controls )
{
Q_ASSERT( m_source->isLocal() || newrev == oldrev );
@@ -271,23 +276,26 @@ DynamicPlaylist::loadRevision( const QString& rev )
setBusy( true );
DatabaseCommand_LoadDynamicPlaylistEntries* cmd = new DatabaseCommand_LoadDynamicPlaylistEntries( rev.isEmpty() ? currentrevision() : rev );
if ( m_generator->mode() == OnDemand ) {
if ( m_generator->mode() == OnDemand )
{
connect( cmd, SIGNAL( done( QString,
bool,
QString,
QList< QVariantMap >,
QVariantList,
bool ) ),
SLOT( setRevision( QString,
bool,
QString,
QList< QVariantMap >,
QVariantList,
bool) ) );
} else if ( m_generator->mode() == Static ) {
}
else if ( m_generator->mode() == Static )
{
connect( cmd, SIGNAL( done( QString,
QList< QString >,
QList< QString >,
QString,
QList< QVariantMap >,
QVariantList,
bool,
QMap< QString, Tomahawk::plentry_ptr >,
bool ) ),
@@ -295,7 +303,7 @@ DynamicPlaylist::loadRevision( const QString& rev )
QList< QString >,
QList< QString >,
QString,
QList< QVariantMap >,
QVariantList,
bool,
QMap< QString, Tomahawk::plentry_ptr >,
bool ) ) );
@@ -376,7 +384,7 @@ DynamicPlaylist::setRevision( const QString& rev,
const QList< QString >& neworderedguids,
const QList< QString >& oldorderedguids,
const QString& type,
const QList< dyncontrol_ptr >& controls,
const QVariantList& controls,
bool is_newest_rev,
const QMap< QString, plentry_ptr >& addedmap,
bool applied )
@@ -391,7 +399,7 @@ DynamicPlaylist::setRevision( const QString& rev,
Q_ARG( QList<QString> , neworderedguids ),
Q_ARG( QList<QString> , oldorderedguids ),
Q_ARG( QString , type ),
QGenericArgument( "QList< Tomahawk::dyncontrol_ptr > " , (const void*)&controls ),
Q_ARG( QVariantList , controls ),
Q_ARG( bool, is_newest_rev ),
QGenericArgument( "QMap< QString,Tomahawk::plentry_ptr > " , (const void*)&addedmap ),
Q_ARG( bool, applied ) );
@@ -402,6 +410,7 @@ DynamicPlaylist::setRevision( const QString& rev,
m_generator = GeneratorFactory::create( type );
}
tDebug() << Q_FUNC_INFO << controls;
m_generator->setControls( controls );
m_generator->setMode( Static );
@@ -421,42 +430,11 @@ DynamicPlaylist::setRevision( const QString& rev,
}
void
DynamicPlaylist::setRevision( const QString& rev,
const QList< QString >& neworderedguids,
const QList< QString >& oldorderedguids,
const QString& type,
const QList< QVariantMap>& controlsV,
bool is_newest_rev,
const QMap< QString, Tomahawk::plentry_ptr >& addedmap,
bool applied )
{
if ( QThread::currentThread() != thread() )
{
QMetaObject::invokeMethod( this,
"setRevision",
Qt::BlockingQueuedConnection,
Q_ARG( QString, rev ),
Q_ARG( QList<QString> , neworderedguids ),
Q_ARG( QList<QString> , oldorderedguids ),
Q_ARG( QString , type ),
QGenericArgument( "QList< QVariantMap > " , (const void*)&controlsV ),
Q_ARG( bool, is_newest_rev ),
QGenericArgument( "QMap< QString,Tomahawk::plentry_ptr > " , (const void*)&addedmap ),
Q_ARG( bool, applied ) );
return;
}
QList<dyncontrol_ptr> controls = variantsToControl( controlsV );
setRevision( rev, neworderedguids, oldorderedguids, type, controls, is_newest_rev, addedmap, applied );
}
void
DynamicPlaylist::setRevision( const QString& rev,
bool is_newest_rev,
const QString& type,
const QList< dyncontrol_ptr >& controls,
const QVariantList& controls,
bool applied )
{
if ( QThread::currentThread() != thread() )
@@ -467,7 +445,7 @@ DynamicPlaylist::setRevision( const QString& rev,
Q_ARG( QString, rev ),
Q_ARG( bool, is_newest_rev ),
Q_ARG( QString, type ),
QGenericArgument( "QList< Tomahawk::dyncontrol_ptr >" , (const void*)&controls ),
Q_ARG( QVariantList, controls ),
Q_ARG( bool, applied ) );
return;
}
@@ -478,6 +456,7 @@ DynamicPlaylist::setRevision( const QString& rev,
m_generator = geninterface_ptr( GeneratorFactory::create( type ) );
}
tDebug() << Q_FUNC_INFO << controls;
m_generator->setControls( controls );
m_generator->setMode( OnDemand );
@@ -498,32 +477,7 @@ DynamicPlaylist::setRevision( const QString& rev,
}
void
DynamicPlaylist::setRevision( const QString& rev,
bool is_newest_rev,
const QString& type,
const QList< QVariantMap >& controlsV,
bool applied )
{
if ( QThread::currentThread() != thread() )
{
QMetaObject::invokeMethod( this,
"setRevision",
Qt::BlockingQueuedConnection,
Q_ARG( QString, rev ),
Q_ARG( bool, is_newest_rev ),
Q_ARG( QString, type ),
QGenericArgument( "QList< QVariantMap >" , (const void*)&controlsV ),
Q_ARG( bool, applied ) );
return;
}
QList<dyncontrol_ptr> controls = variantsToControl( controlsV );
setRevision( rev, is_newest_rev, type, controls, applied );
}
QList< dyncontrol_ptr >
/*QList< dyncontrol_ptr >
DynamicPlaylist::variantsToControl( const QList< QVariantMap >& controlsV )
{
QList<dyncontrol_ptr> realControls;
@@ -534,7 +488,7 @@ DynamicPlaylist::variantsToControl( const QList< QVariantMap >& controlsV )
realControls << control;
}
return realControls;
}
}*/
void

View File

@@ -49,10 +49,10 @@ class DatabaseCommand_LoadDynamicPlaylist;
struct DynQueueItem : RevisionQueueItem
{
QString type;
QList <dyncontrol_ptr> controls;
QVariantList controls;
int mode;
DynQueueItem( const QString& nRev, const QString& oRev, const QString& typ, const QList< dyncontrol_ptr >& ctrls, int m, const QList< plentry_ptr >& e, bool latest ) :
DynQueueItem( const QString& nRev, const QString& oRev, const QString& typ, const QVariantList& ctrls, int m, const QList< plentry_ptr >& e, bool latest ) :
RevisionQueueItem( nRev, oRev, e, latest ), type( typ ), controls( ctrls ), mode( m ) {}
};
@@ -85,7 +85,8 @@ public:
GeneratorMode mode,
bool shared,
const QString& type = QString(),
bool autoLoad = true
bool autoLoad = true,
bool temporary = false
);
static void remove( const dynplaylist_ptr& playlist );
@@ -125,9 +126,9 @@ public slots:
// want to update the playlist from the model?
// generate a newrev using uuid() and call this:
// if this is a static playlist, pass it a new list of entries. implicitly sets mode to static
void createNewRevision( const QString& newrev, const QString& oldrev, const QString& type, const QList< dyncontrol_ptr>& controls, const QList< plentry_ptr >& entries );
void createNewRevision( const QString& newrev, const QString& oldrev, const QString& type, const QVariantList& controls, const QList< plentry_ptr >& entries );
// if it is ondemand, no entries are needed implicitly sets mode to ondemand
void createNewRevision( const QString& newrev, const QString& oldrev, const QString& type, const QList< dyncontrol_ptr>& controls );
void createNewRevision( const QString& newrev, const QString& oldrev, const QString& type, const QVariantList& controls );
void reportCreated( const Tomahawk::dynplaylist_ptr& self );
void reportDeleted( const Tomahawk::dynplaylist_ptr& self );
@@ -142,15 +143,7 @@ public slots:
const QList<QString>& neworderedguids,
const QList<QString>& oldorderedguids,
const QString& type,
const QList< QVariantMap >& controls,
bool is_newest_rev,
const QMap< QString, Tomahawk::plentry_ptr >& addedmap,
bool applied );
void setRevision( const QString& rev,
const QList<QString>& neworderedguids,
const QList<QString>& oldorderedguids,
const QString& type,
const QList< Tomahawk::dyncontrol_ptr >& controls,
const QVariantList& controls,
bool is_newest_rev,
const QMap< QString, Tomahawk::plentry_ptr >& addedmap,
bool applied );
@@ -158,13 +151,9 @@ public slots:
void setRevision( const QString& rev,
bool is_newest_rev,
const QString& type,
const QList< QVariantMap>& controls,
bool applied );
void setRevision( const QString& rev,
bool is_newest_rev,
const QString& type,
const QList< Tomahawk::dyncontrol_ptr>& controls,
const QVariantList& controls,
bool applied );
private:
// called from loadAllPlaylists DB cmd via databasecollection (in GUI thread)
explicit DynamicPlaylist( const source_ptr& src,
@@ -192,8 +181,6 @@ private:
void checkRevisionQueue();
QList< dyncontrol_ptr > variantsToControl( const QList< QVariantMap >& controlsV );
geninterface_ptr m_generator;
bool m_autoLoad;

View File

@@ -23,7 +23,7 @@
using namespace Tomahawk;
DynamicPlaylistRevision::DynamicPlaylistRevision(const PlaylistRevision &other)
DynamicPlaylistRevision::DynamicPlaylistRevision( const PlaylistRevision &other )
{
revisionguid = other.revisionguid;
oldrevisionguid = other.oldrevisionguid;

View File

@@ -29,7 +29,7 @@ struct DLLEXPORT DynamicPlaylistRevision : PlaylistRevision
{
public:
QList< dyncontrol_ptr > controls;
QVariantList controls;
Tomahawk::GeneratorMode mode;
QString type;

View File

@@ -40,14 +40,14 @@ GeneratorFactory::create ( const QString& type )
}
dyncontrol_ptr
/*dyncontrol_ptr
GeneratorFactory::createControl( const QString& generatorType, const QString& controlType )
{
if( generatorType.isEmpty() || !s_factories.contains( generatorType ) )
return dyncontrol_ptr();
return s_factories.value( generatorType )->createControl( controlType );
}
}*/
void

View File

@@ -46,7 +46,7 @@ public:
* Create a control for this generator, not tied to this generator itself. Used when loading dynamic
* playlists from a dbcmd.
*/
virtual dyncontrol_ptr createControl( const QString& controlType = QString() ) = 0;
// virtual dyncontrol_ptr createControl( const QString& controlType = QString() ) = 0;
virtual QStringList typeSelectors() const = 0;
};
@@ -59,7 +59,7 @@ class DLLEXPORT GeneratorFactory
public:
static geninterface_ptr create( const QString& type );
// only used when loading from dbcmd
static dyncontrol_ptr createControl( const QString& generatorType, const QString& controlType = QString() );
// static dyncontrol_ptr createControl( const QString& generatorType, const QString& controlType = QString() );
static void registerFactory( const QString& type, GeneratorFactoryInterface* interface );
static QStringList types();

View File

@@ -34,17 +34,6 @@ Tomahawk::GeneratorInterface::~GeneratorInterface()
}
QList< Tomahawk::dyncontrol_ptr >
Tomahawk::GeneratorInterface::controls()
{
// if( m_controls.isEmpty() ) { // return a default control (so the user can add more)
// return QList< Tomahawk::dyncontrol_ptr >() << createControl();
// }
return m_controls;
}
QPixmap
Tomahawk::GeneratorInterface::logo()
{
@@ -52,38 +41,15 @@ Tomahawk::GeneratorInterface::logo()
}
void
Tomahawk::GeneratorInterface::addControl( const Tomahawk::dyncontrol_ptr& control )
QVariantList
Tomahawk::GeneratorInterface::controls() const
{
m_controls << control;
return m_controls;
}
void
Tomahawk::GeneratorInterface::clearControls()
{
m_controls.clear();
}
void
Tomahawk::GeneratorInterface::setControls( const QList< Tomahawk::dyncontrol_ptr >& controls )
Tomahawk::GeneratorInterface::setControls( const QVariantList& controls )
{
m_controls = controls;
}
void
Tomahawk::GeneratorInterface::removeControl( const Tomahawk::dyncontrol_ptr& control )
{
m_controls.removeAll( control );
}
Tomahawk::dyncontrol_ptr
Tomahawk::GeneratorInterface::createControl( const QString& type )
{
Q_UNUSED( type );
Q_ASSERT( false );
return dyncontrol_ptr();
}

View File

@@ -47,6 +47,7 @@ class DLLEXPORT GeneratorInterface : public QObject
{
Q_OBJECT
Q_PROPERTY( QString type READ type )
Q_PROPERTY( QString summary READ sentenceSummary)
/// oh qjson.
Q_PROPERTY( int mode READ mode WRITE setMode )
@@ -55,12 +56,6 @@ public:
explicit GeneratorInterface( QObject* parent = 0 );
virtual ~GeneratorInterface();
// Can't make it pure otherwise we can't shove it in QVariants :-/
// empty QString means use default
/// The generator will keep track of all the controls it creates. No need to tell it about controls
/// you ask it to create
virtual dyncontrol_ptr createControl( const QString& type = QString() );
/// A logo to display for this generator, if it has one
virtual QPixmap logo();
@@ -98,17 +93,17 @@ public:
*/
virtual bool onDemandSteerable() const { return false; }
/**
* Returns a widget used to steer the OnDemand dynamic playlist.
* If this generator doesn't support this (and returns false for
* \c onDemandSteerable) this will be null. The generator is responsible
* for reacting to changes in the widget.
*
* Steering widgets may emit a \c steeringChanged() signal, which will cause the model to toss any
* upcoming tracks and re-fetch them.
*
* Returns the controls for this station.
*/
virtual QWidget* steeringWidget() { return 0; }
virtual QVariantList controls() const;
/**
* Sets the controls (for example when loaded from database)
*/
virtual void setControls( const QVariantList& controls );
/// The type of this generator
QString type() const { return m_type; }
@@ -116,22 +111,22 @@ public:
int mode() const { return (int)m_mode; }
void setMode( int mode ) { m_mode = (GeneratorMode)mode; }
// control functions
QList< dyncontrol_ptr > controls();
void addControl( const dyncontrol_ptr& control );
void clearControls();
void setControls( const QList< dyncontrol_ptr>& controls );
void removeControl( const dyncontrol_ptr& control );
virtual bool startFromTrack( const Tomahawk::query_ptr& query ) = 0;
virtual bool startFromArtist( const Tomahawk::artist_ptr& artist ) = 0;
virtual bool startFromGenre( const QString& genre ) = 0;
virtual bool startFromYear( int year ) = 0;
virtual bool startFromTo( int yearFrom, int yearTo) = 0;
signals:
void error( const QString& title, const QString& body);
void generated( const QList< Tomahawk::query_ptr>& queries );
void nextTrackGenerated( const Tomahawk::query_ptr& track );
void summaryChanged();
protected:
QString m_type;
GeneratorMode m_mode;
QList< dyncontrol_ptr > m_controls;
QVariantList m_controls;
};
typedef QSharedPointer<GeneratorInterface> geninterface_ptr;

View File

@@ -36,10 +36,10 @@ namespace Tomahawk
DatabaseFactory() {}
virtual GeneratorInterface* create();
virtual dyncontrol_ptr createControl( const QString& controlType = QString() );
// virtual dyncontrol_ptr createControl( const QString& controlType = QString() );
// TO create a special SQL resolver that consists of a pre-baked SQL query and a description of it
virtual dyncontrol_ptr createControl( const QString& sql, DatabaseCommand_GenericSelect::QueryType type, const QString& summary );
// virtual dyncontrol_ptr createControl( const QString& sql, DatabaseCommand_GenericSelect::QueryType type, const QString& summary );
virtual QStringList typeSelectors() const;
};
@@ -55,8 +55,8 @@ namespace Tomahawk
explicit DatabaseGenerator( QObject* parent = 0 );
virtual ~DatabaseGenerator();
virtual dyncontrol_ptr createControl( const QString& type = QString() );
virtual dyncontrol_ptr createControl( const QString& sql, DatabaseCommand_GenericSelect::QueryType type, const QString& summary );
/* virtual dyncontrol_ptr createControl( const QString& type = QString() );
virtual dyncontrol_ptr createControl( const QString& sql, DatabaseCommand_GenericSelect::QueryType type, const QString& summary );*/
virtual QPixmap logo();
virtual void generate ( int number = -1 );

View File

@@ -61,11 +61,11 @@ EchonestFactory::create()
}
dyncontrol_ptr
/*dyncontrol_ptr
EchonestFactory::createControl( const QString& controlType )
{
return dyncontrol_ptr( new EchonestControl( controlType, typeSelectors() ) );
}
}*/
QStringList
@@ -160,12 +160,12 @@ EchonestGenerator::setupCatalogs()
// qDebug() << "ECHONEST:" << m_logo.size();
}
dyncontrol_ptr
/*dyncontrol_ptr
EchonestGenerator::createControl( const QString& type )
{
m_controls << dyncontrol_ptr( new EchonestControl( type, GeneratorFactory::typeSelectors( m_type ) ) );
return m_controls.last();
}
}*/
QPixmap EchonestGenerator::logo()
@@ -176,11 +176,11 @@ QPixmap EchonestGenerator::logo()
void
EchonestGenerator::knownCatalogsChanged()
{
// Refresh all contrls
/* // Refresh all contrls
foreach( const dyncontrol_ptr& control, m_controls )
{
control.staticCast< EchonestControl >()->updateWidgetsFromData();
}
}*/
}
@@ -188,10 +188,7 @@ void
EchonestGenerator::generate( int number )
{
// convert to an echonest query, and fire it off
qDebug() << Q_FUNC_INFO;
qDebug() << "Generating playlist with" << m_controls.size();
foreach( const dyncontrol_ptr& ctrl, m_controls )
qDebug() << ctrl->selectedType() << ctrl->match() << ctrl->input();
tDebug() << "Generating playlist with" << m_controls.size();
setProperty( "number", number ); //HACK
@@ -226,6 +223,126 @@ EchonestGenerator::startOnDemand()
}
bool
EchonestGenerator::startFromTrack( const Tomahawk::query_ptr& query )
{
tDebug() << "Generating station content by query:" << query->toString();
Echonest::DynamicPlaylist::PlaylistParamData data;
data.first = Echonest::DynamicPlaylist::SongId;
data.second = query->track()->artist() + " " + query->track()->track();
Echonest::DynamicPlaylist::PlaylistParams params;
params.append( Echonest::DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::SongRadioType ) );
params << data;
// FIXME!
return true;
}
bool
EchonestGenerator::startFromArtist( const Tomahawk::artist_ptr& artist )
{
tDebug() << "Generating station content by artist:" << artist->name();
if ( !m_dynPlaylist->sessionId().isNull() )
{
// Running session, delete it
QNetworkReply* deleteReply = m_dynPlaylist->deleteSession();
connect( deleteReply, SIGNAL( finished() ), deleteReply, SLOT( deleteLater() ) );
}
connect( this, SIGNAL( paramsGenerated( Echonest::DynamicPlaylist::PlaylistParams ) ), this, SLOT( doStartOnDemand( Echonest::DynamicPlaylist::PlaylistParams ) ) );
Echonest::DynamicPlaylist::PlaylistParamData data;
data.first = Echonest::DynamicPlaylist::Artist;
data.second = artist->name();
Echonest::DynamicPlaylist::PlaylistParams params;
params << data;
/* Q_PROPERTY( QString type READ type WRITE setType ) // the generator type associated with this control
Q_PROPERTY( QString id READ id WRITE setId )
Q_PROPERTY( QString selectedType READ selectedType WRITE setSelectedType )
Q_PROPERTY( QString match READ match WRITE setMatch )
Q_PROPERTY( QString input READ input WRITE setInput )
Q_PROPERTY( QString summary READ summary ) // a summary of the control in phrase form*/
QVariantMap controlsList;
controlsList[ "id" ] = uuid();
controlsList[ "selectedType" ] = "echonest";
controlsList[ "match" ] = QString::number( data.first );
controlsList[ "input" ] = data.second;
controlsList[ "summary" ] = tr("Songs from %1").arg(data.second.toString());
setControls( QVariantList() << controlsList );
// params.append( Echonest::DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::SongRadioType ) );
emit paramsGenerated( params );
return true;
}
bool
EchonestGenerator::startFromGenre( const QString& genre )
{
tDebug() << "Generating station content by genre:" << genre;
if ( !m_dynPlaylist->sessionId().isNull() )
{
// Running session, delete it
QNetworkReply* deleteReply = m_dynPlaylist->deleteSession();
connect( deleteReply, SIGNAL( finished() ), deleteReply, SLOT( deleteLater() ) );
}
connect( this, SIGNAL( paramsGenerated( Echonest::DynamicPlaylist::PlaylistParams ) ), this, SLOT( doGenerate( Echonest::DynamicPlaylist::PlaylistParams ) ) );
setProperty( "number", 20 );
Echonest::DynamicPlaylist::PlaylistParamData data;
data.first = Echonest::DynamicPlaylist::Description;
data.second = genre;
Echonest::DynamicPlaylist::PlaylistParams params;
params << data;
QVariantList controlsList;
QVariantMap controlsMap;
controlsMap[ "id" ] = uuid();
controlsMap[ "selectedType" ] = "echonest";
controlsMap[ "match" ] = QString::number( data.first );
controlsMap[ "input" ] = data.second;
controlsMap[ "summary" ] = tr("Songs of genre %1").arg(data.second.toString());
controlsList << controlsMap;
params.append( Echonest::DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::ArtistDescriptionType ) );
controlsMap[ "id" ] = uuid();
controlsMap[ "match" ] = QString::number( Echonest::DynamicPlaylist::Type );
controlsMap[ "input" ] = QString::number( Echonest::DynamicPlaylist::ArtistDescriptionType );
controlsList << controlsMap;
setControls( controlsList );
emit paramsGenerated( params );
return true;
}
bool EchonestGenerator::startFromYear(int year)
{
//TODO: libechonest doesn't support filtering for year yet...
return false;
}
bool EchonestGenerator::startFromTo(int yearFrom, int yearTo)
{
//TODO: libechonest doesn't support filtering for year yet...
return false;
}
void
EchonestGenerator::doGenerate( const Echonest::DynamicPlaylist::PlaylistParams& paramsIn )
{
@@ -307,22 +424,40 @@ EchonestGenerator::staticFinished()
void
EchonestGenerator::getParams() throw( std::runtime_error )
{
/*Echonest::DynamicPlaylist::PlaylistParamData data;
data.first = Echonest::DynamicPlaylist::Artist;
data.second = artist->name();
Echonest::DynamicPlaylist::PlaylistParams params;
foreach( const dyncontrol_ptr& control, m_controls ) {
params.append( control.dynamicCast<EchonestControl>()->toENParam() );
params << data;
*/
Echonest::DynamicPlaylist::PlaylistParams params;
foreach( const QVariant& control, m_controls )
{
QVariantMap controlMap = control.toMap();
Echonest::DynamicPlaylist::PlaylistParamData data;
data.first = (Echonest::DynamicPlaylist::PlaylistParam)controlMap[ "match" ].toUInt();
data.second = controlMap[ "input" ].toString();
params.append( data );
}
if( appendRadioType( params ) == Echonest::DynamicPlaylist::SongRadioType ) {
if ( appendRadioType( params ) == Echonest::DynamicPlaylist::SongRadioType )
{
// we need to do another pass, converting all song queries to song-ids.
m_storedParams = params;
qDeleteAll( m_waiting );
m_waiting.clear();
// one query per track
for( int i = 0; i < params.count(); i++ ) {
for( int i = 0; i < params.count(); i++ )
{
const Echonest::DynamicPlaylist::PlaylistParamData param = params.value( i );
if( param.first == Echonest::DynamicPlaylist::SongId ) { // this is a song type enum
if ( param.first == Echonest::DynamicPlaylist::SongId )
{
// this is a song type enum
QString text = param.second.toString();
Echonest::Song::SearchParams q;
@@ -336,12 +471,14 @@ EchonestGenerator::getParams() throw( std::runtime_error )
}
}
if( m_waiting.isEmpty() ) {
if ( m_waiting.isEmpty() )
{
m_storedParams.clear();
emit paramsGenerated( params );
}
} else {
}
else
{
emit paramsGenerated( params );
}
}
@@ -440,7 +577,7 @@ EchonestGenerator::userCatalogs()
return s_catalogs->catalogs().keys();
}
bool
/*bool
EchonestGenerator::onlyThisArtistType( Echonest::DynamicPlaylist::ArtistTypeEnum type ) const throw( std::runtime_error )
{
bool only = true;
@@ -460,7 +597,7 @@ EchonestGenerator::onlyThisArtistType( Echonest::DynamicPlaylist::ArtistTypeEnum
}
return false;
}
}*/
Echonest::DynamicPlaylist::ArtistTypeEnum
@@ -477,7 +614,7 @@ EchonestGenerator::appendRadioType( Echonest::DynamicPlaylist::PlaylistParams& p
/// 3. artist-description: If all the artist entries are Description. If some were but not all, error out.
/// 4. artist-radio: If all the artist entries are Similar To. If some were but not all, error out.
/// 5. song-radio: If all the artist entries are Similar To. If some were but not all, error out.
bool someCatalog = false;
/* bool someCatalog = false;
bool genreType = false;
foreach( const dyncontrol_ptr& control, m_controls ) {
if ( control->selectedType() == "User Radio" )
@@ -498,7 +635,7 @@ EchonestGenerator::appendRadioType( Echonest::DynamicPlaylist::PlaylistParams& p
else if( onlyThisArtistType( Echonest::DynamicPlaylist::SongRadioType ) )
params.append( Echonest::DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::SongRadioType ) );
else // no artist or song or description types. default to artist-description
params.append( Echonest::DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::ArtistDescriptionType ) );
params.append( Echonest::DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::ArtistDescriptionType ) );*/
return static_cast< Echonest::DynamicPlaylist::ArtistTypeEnum >( params.last().second.toInt() );
}
@@ -529,7 +666,10 @@ EchonestGenerator::sentenceSummary()
* NOTE / TODO: In order for the sentence to be grammatically correct, we must follow the EN API rules. That means we can't have multiple of some types of filters,
* and all Artist types must be the same. The filters aren't checked at the moment until Generate / Play is pressed. Consider doing a check on hide as well.
*/
QList< dyncontrol_ptr > allcontrols = m_controls;
// Keeping this for now to make stuff backwards compatible
/* QList< dyncontrol_ptr > allcontrols = m_controls;
QString sentence = "Songs ";
/// 1. Collect all required filters
@@ -612,7 +752,12 @@ EchonestGenerator::sentenceSummary()
sentence += "and " + sorting.dynamicCast< EchonestControl >()->summary() + ".";
}
return sentence;
return sentence;*/
if (m_controls.isEmpty()) {
return "";
}
return m_controls.first().toMap().value("summary").toString();
}
void

View File

@@ -60,7 +60,7 @@ public:
EchonestFactory();
virtual GeneratorInterface* create();
virtual dyncontrol_ptr createControl( const QString& controlType = QString() );
// virtual dyncontrol_ptr createControl( const QString& controlType = QString() );
virtual QStringList typeSelectors() const;
};
@@ -71,7 +71,7 @@ public:
explicit EchonestGenerator( QObject* parent = 0 );
virtual ~EchonestGenerator();
virtual dyncontrol_ptr createControl( const QString& type = QString() );
// virtual dyncontrol_ptr createControl( const QString& type = QString() );
virtual QPixmap logo();
virtual void generate ( int number = -1 );
virtual void startOnDemand();
@@ -80,6 +80,12 @@ public:
virtual bool onDemandSteerable() const { return false; }
virtual QWidget* steeringWidget() { return 0; }
virtual bool startFromTrack( const Tomahawk::query_ptr& query );
virtual bool startFromArtist( const Tomahawk::artist_ptr& artist );
virtual bool startFromGenre( const QString& genre );
virtual bool startFromYear( int year );
virtual bool startFromTo( int yearFrom, int yearTo );
static QStringList styles();
static QStringList moods();
static QStringList genres();
@@ -118,7 +124,7 @@ private:
query_ptr queryFromSong( const Echonest::Song& song );
Echonest::DynamicPlaylist::ArtistTypeEnum appendRadioType( Echonest::DynamicPlaylist::PlaylistParams& params ) const throw( std::runtime_error );
bool onlyThisArtistType( Echonest::DynamicPlaylist::ArtistTypeEnum type ) const throw( std::runtime_error );
// bool onlyThisArtistType( Echonest::DynamicPlaylist::ArtistTypeEnum type ) const throw( std::runtime_error );
void loadStylesMoodsAndGenres();

View File

@@ -0,0 +1,268 @@
#include "DynamicQmlWidget.h"
#include "playlist/dynamic/DynamicModel.h"
#include "playlist/PlayableProxyModel.h"
#include "playlist/dynamic/DynamicModel.h"
#include "playlist/dynamic/echonest/EchonestControl.h"
#include "playlist/dynamic/GeneratorInterface.h"
#include "playlist/PlayableItem.h"
#include "Source.h"
#include "SourceList.h"
#include "audio/AudioEngine.h"
#include "database/Database.h"
#include "database/DatabaseCommand_CreateDynamicPlaylist.h"
#include "database/DatabaseCommand_PlaybackCharts.h"
#include "widgets/DeclarativeCoverArtProvider.h"
#include "utils/TomahawkUtilsGui.h"
#include "utils/Logger.h"
#include "utils/TomahawkCache.h"
#include <QUrl>
#include <QSize>
#include <qdeclarative.h>
#include <QDeclarativeContext>
namespace Tomahawk
{
DynamicQmlWidget::DynamicQmlWidget( const dynplaylist_ptr& playlist, QWidget* parent )
: DeclarativeView( parent )
, m_playlist( playlist )
, m_playNextResolved( false )
{
m_model = new DynamicModel( this );
m_proxyModel = new PlayableProxyModel( this );
m_proxyModel->setSourcePlayableModel( m_model );
m_proxyModel->setShowOfflineResults( false );
m_model->loadPlaylist( m_playlist );
m_artistChartsModel = new PlayableModel( this );
qmlRegisterUncreatableType<GeneratorInterface>("tomahawk", 1, 0, "Generator", "you cannot create it on your own - should be set in context");
rootContext()->setContextProperty( "dynamicModel", m_proxyModel );
rootContext()->setContextProperty( "artistChartsModel", m_artistChartsModel );
rootContext()->setContextProperty( "generator", m_playlist->generator().data() );
rootContext()->setContextProperty( "currentlyPlayedIndex", QVariant::fromValue( 0 ) );
setSource( QUrl( "qrc" RESPATH "qml/StationView.qml" ) );
connect( m_model, SIGNAL( currentIndexChanged()), SLOT( currentIndexChanged() ) );
connect( m_model, SIGNAL( changed() ), SIGNAL( titleChanged() ) );
connect( m_playlist->generator().data(), SIGNAL( generated( QList<Tomahawk::query_ptr> ) ), this, SLOT( tracksGenerated( QList<Tomahawk::query_ptr> ) ) );
connect( m_playlist->generator().data(), SIGNAL( nextTrackGenerated( Tomahawk::query_ptr ) ), this, SLOT( nextTrackGenerated( Tomahawk::query_ptr ) ) );
connect( m_playlist.data(), SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ), this, SLOT( onRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ) );
connect( m_playlist->generator().data(), SIGNAL( error( QString, QString )), SLOT( error(QString,QString) ) );
if (configured()) {
m_playlist->generator()->generate( 20 );
} else {
// TODO: only load if needed, i.e. the user clicks on start station by artist
loadArtistCharts();
rootContext()->setContextProperty("allGenres", TomahawkUtils::Cache::instance()->getData( "EchonesGenerator", "genres"));
}
}
DynamicQmlWidget::~DynamicQmlWidget()
{
}
Tomahawk::playlistinterface_ptr
DynamicQmlWidget::playlistInterface() const
{
return m_proxyModel->playlistInterface();
}
QString
DynamicQmlWidget::title() const
{
if ( !m_playlist->title().isEmpty() ) {
return m_playlist->title();
}
return "Listen to radio";
}
void
DynamicQmlWidget::setTitle( const QString& title )
{
m_model->setTitle( title );
m_playlist->setTitle( title );
m_model->playlist()->setTitle( title );
if ( !m_playlist->loaded() )
{
tDebug() << "CONTROLS ARE SAVED:" << m_playlist->generator()->controls();
DatabaseCommand_CreateDynamicPlaylist* cmd = new DatabaseCommand_CreateDynamicPlaylist( SourceList::instance()->getLocal(), m_playlist, true );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
m_playlist->reportCreated( m_playlist );
m_playlist->createNewRevision( uuid(), m_playlist->currentrevision(), m_playlist->type(), m_playlist->generator()->controls() );
emit titleChanged();
}
}
QString
DynamicQmlWidget::description() const
{
return m_model->description();
}
QString
DynamicQmlWidget::iconSource() const
{
return QLatin1String( RESPATH "images/station.png" );
}
bool
DynamicQmlWidget::jumpToCurrentTrack()
{
return true;
}
playlist_ptr DynamicQmlWidget::playlist() const
{
return m_model->playlist();
}
bool DynamicQmlWidget::loading()
{
// Why does isLoading() not reset to true when cleared and station started again?
// return m_model->isLoading();
return m_playNextResolved && m_proxyModel->rowCount() == 0;
}
bool DynamicQmlWidget::configured()
{
// return true;
return !m_playlist->generator()->controls().isEmpty();
}
void DynamicQmlWidget::playItem(int index)
{
tDebug() << "playItem called for cover" << index;
AudioEngine::instance()->playItem( m_proxyModel->playlistInterface(), m_proxyModel->itemFromIndex( index )->result() );
}
void DynamicQmlWidget::pause()
{
AudioEngine::instance()->pause();
}
void DynamicQmlWidget::startStationFromArtist(const QString &artist)
{
m_model->clear();
m_playNextResolved = true;
m_playlist->generator()->startFromArtist(Artist::get(artist));
emit loadingChanged();
emit configuredChanged();
}
void DynamicQmlWidget::startStationFromGenre(const QString &genre)
{
tDebug() << "should start startion from genre" << genre;
m_model->clear();
m_playNextResolved = true;
m_playlist->generator()->startFromGenre( genre );
emit loadingChanged();
emit configuredChanged();
}
void DynamicQmlWidget::startStationFromYear(int year)
{
tDebug() << "should start startion from year" << year;
m_model->clear();
m_playNextResolved = true;
m_playlist->generator()->startFromYear( year );
emit loadingChanged();
emit configuredChanged();
}
void DynamicQmlWidget::startStationFromTo(int yearFrom, int yearTo)
{
tDebug() << "should start startion from years" << yearFrom << "to" << yearTo;
m_model->clear();
m_playNextResolved = true;
m_playlist->generator()->startFromTo( yearFrom, yearTo );
emit loadingChanged();
emit configuredChanged();
}
void DynamicQmlWidget::currentIndexChanged()
{
tDebug() << "current index is" << m_model->currentItem().row();
rootContext()->setContextProperty( "currentlyPlayedIndex", m_proxyModel->mapFromSource( m_model->currentItem() ).row() );
}
void
DynamicQmlWidget::tracksGenerated( const QList< query_ptr >& queries )
{
m_model->tracksGenerated( queries, queries.count() );
m_playlist->resolve();
}
void DynamicQmlWidget::nextTrackGenerated(const query_ptr &track)
{
tDebug() << Q_FUNC_INFO << track->toString();
m_model->tracksGenerated( QList<query_ptr>() << track );
m_playlist->resolve();
connect( track.data(), SIGNAL( resolvingFinished( bool )), SLOT( resolvingFinished( bool ) ) );
}
void DynamicQmlWidget::error(const QString &title, const QString &body)
{
tDebug() << "got a generator error:" << title << body;
}
void DynamicQmlWidget::onRevisionLoaded(DynamicPlaylistRevision)
{
m_playlist->resolve();
}
void DynamicQmlWidget::resolvingFinished(bool hasResults)
{
Q_UNUSED(hasResults)
tDebug() << "next track generated" << m_proxyModel->rowCount() << m_proxyModel->currentIndex().row();
if( m_proxyModel->rowCount() <= m_proxyModel->currentIndex().row() + 8 ) {
tDebug() << "fetching next one";
m_playlist->generator()->fetchNext();
}
if( m_playNextResolved && m_proxyModel->rowCount() > 0 ) {
emit loadingChanged();
playItem( 0 );
m_playNextResolved = false;
}
}
void
DynamicQmlWidget::loadArtistCharts()
{
DatabaseCommand_PlaybackCharts* cmd = new DatabaseCommand_PlaybackCharts( SourceList::instance()->getLocal(), this );
cmd->setLimit( 15 );
connect( cmd, SIGNAL( artists( QList<Tomahawk::artist_ptr> ) ), SLOT( onArtistCharts( QList< Tomahawk::artist_ptr > ) ), Qt::UniqueConnection );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
}
void
DynamicQmlWidget::onArtistCharts( const QList< Tomahawk::artist_ptr >& artists )
{
m_artistChartsModel->clear();
m_artistChartsModel->appendArtists( artists );
}
}

View File

@@ -0,0 +1,105 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2012, Michael Zanetti <mzanetti@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DYNAMIC_QML_WIDGET_H
#define DYNAMIC_QML_WIDGET_H
#include "ViewPage.h"
#include "Typedefs.h"
#include "widgets/DeclarativeView.h"
#include <QDeclarativeImageProvider>
class PlayableModel;
class PlayableProxyModel;
namespace Tomahawk
{
class DynamicModel;
class DynamicQmlWidget : public DeclarativeView, public Tomahawk::ViewPage
{
Q_OBJECT
Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged)
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
Q_PROPERTY(bool configured READ configured NOTIFY configuredChanged)
public:
explicit DynamicQmlWidget( const dynplaylist_ptr& playlist, QWidget* parent = 0 );
virtual ~DynamicQmlWidget();
virtual QWidget* widget() { return this; }
virtual Tomahawk::playlistinterface_ptr playlistInterface() const;
virtual QString title() const;
virtual void setTitle(const QString &title);
virtual QString description() const;
virtual QString iconSource() const;
virtual bool showInfoBar() const { return false; }
virtual bool showModes() const { return false; }
virtual bool showFilter() const { return false; }
virtual bool jumpToCurrentTrack();
playlist_ptr playlist() const;
bool loading();
bool configured();
signals:
void loadingChanged();
void configuredChanged();
void titleChanged();
public slots:
void playItem(int index);
void pause();
void startStationFromArtist(const QString &artist);
void startStationFromGenre(const QString &genre);
void startStationFromYear(int year);
void startStationFromTo(int yearFrom, int yearTo);
private slots:
void currentIndexChanged();
void tracksGenerated( const QList< Tomahawk::query_ptr>& queries );
void nextTrackGenerated( const Tomahawk::query_ptr& track );
void error( const QString& title, const QString& body);
void onRevisionLoaded( Tomahawk::DynamicPlaylistRevision );
void resolvingFinished( bool hasResults );
void loadArtistCharts();
void onArtistCharts( const QList< Tomahawk::artist_ptr >& artists );
private:
DynamicModel* m_model;
PlayableProxyModel* m_proxyModel;
dynplaylist_ptr m_playlist;
PlayableModel* m_artistChartsModel;
bool m_playNextResolved;
};
}
#endif // DYNAMIC_QML_WIDGET_H

View File

@@ -0,0 +1,142 @@
#include "DeclarativeCoverArtProvider.h"
#include "playlist/PlayableItem.h"
#include "playlist/PlayableProxyModel.h"
#include "Query.h"
#include "Album.h"
#include "Artist.h"
#include "utils/TomahawkUtilsGui.h"
#include "utils/Logger.h"
#include <QDeclarativeImageProvider>
#include <QModelIndex>
#include <QDebug>
#include <QPainter>
namespace Tomahawk
{
DeclarativeCoverArtProvider::DeclarativeCoverArtProvider( )
: QDeclarativeImageProvider( QDeclarativeImageProvider::Pixmap )
{
}
DeclarativeCoverArtProvider::~DeclarativeCoverArtProvider()
{
}
QPixmap DeclarativeCoverArtProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
{
// We always can generate it in the requested size
int width = requestedSize.width() > 0 ? requestedSize.width() : 230;
int height = requestedSize.height() > 0 ? requestedSize.height() : 230;
if( size )
*size = QSize( width, height );
QPixmap cover;
tDebug() << "DeclarativeCoverArtprovider: Getting album art by id:" << id << requestedSize;
bool mirrored = false;
bool labeled = false;
QString coverId = id;
if(coverId.contains("-mirror")) {
coverId.remove("-mirror");
mirrored = true;
}
if(coverId.contains("-labels")) {
coverId.remove("-labels");
labeled = true;
}
artist_ptr artist = Artist::getByCoverId( coverId );
if ( !artist.isNull() )
{
tDebug() << "Returning artist cover:" << artist->cover( *size ).isNull();
cover = artist->cover( *size );
if ( cover.isNull() )
{
tDebug() << Q_FUNC_INFO << "Returning default artist image";
cover = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultArtistImage, TomahawkUtils::Original, *size );
}
}
if ( cover.isNull() )
{
album_ptr album = Album::getByCoverId( coverId );
if ( !album.isNull() )
{
tDebug() << "Returning album cover:" << album->cover( *size ).isNull();
cover = album->cover( *size );
if ( cover.isNull() )
{
tDebug() << Q_FUNC_INFO << "Returning default album image";
cover = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::Original, *size );
}
}
}
if ( cover.isNull() )
{
tDebug() << Q_FUNC_INFO << "Returning default track image";
cover = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultTrackImage, TomahawkUtils::Original, *size );
}
QImage image(*size, QImage::Format_ARGB32);
if(labeled) {
QImage coverImage(*size, QImage::Format_RGB32);
QPainter bgPainter(&coverImage);
bgPainter.drawPixmap(0, 0, size->width(), size->height(), cover);
QColor c1;
c1.setRgb( 0, 0, 0 );
c1.setAlphaF( 0.00 );
QColor c2;
c2.setRgb( 0, 0, 0 );
c2.setAlphaF( 0.88 );
QLinearGradient gradient( QPointF( 0, 0 ), QPointF( 0, 1 ) );
gradient.setCoordinateMode( QGradient::ObjectBoundingMode );
gradient.setColorAt( 0.0, c1 );
gradient.setColorAt( 0.6, c2 );
gradient.setColorAt( 1.0, c2 );
bgPainter.setPen( Qt::transparent );
bgPainter.setBrush(QBrush(gradient));
bgPainter.drawRect(0, size->height() * 0.7, size->width(), size->height() * 0.3);
cover = QPixmap::fromImage(coverImage);
}
QPainter painter(&image);
if(!mirrored) {
image.fill(Qt::white);
painter.drawPixmap(0, 0, size->width(), size->height(), cover);
} else {
image.fill(QColor(0, 0, 0, 0));
// Lets paint half of the image in a fragment per line
int mirrorHeight = size->height() / 2;
int fragmentCount = mirrorHeight;
int fragmentHeight = mirrorHeight / fragmentCount;
QPainter::PixmapFragment fragments[fragmentCount];
qreal fragmentOpacity = 0;
int fragmentStartY = size->height() - mirrorHeight;
for(int i = 0; i < fragmentCount; ++i) {
QPointF point = QPointF(size->width() / 2, fragmentStartY + (fragmentHeight / 2));
QRectF sourceRect = QRectF(0, fragmentStartY, size->width(), fragmentHeight);
fragments[i] = QPainter::PixmapFragment::create(point, sourceRect, 1, 1, 0, fragmentOpacity);
fragmentOpacity += 0.5 / fragmentCount;
fragmentStartY += fragmentHeight;
}
painter.drawPixmapFragments(fragments, fragmentCount, cover);
}
return QPixmap::fromImage(image);
}
}

View File

@@ -0,0 +1,23 @@
#ifndef DECLARATIVECOVERARTPROVIDER_H
#define DECLARATIVECOVERARTPROVIDER_H
#include "playlist/PlayableProxyModel.h"
#include <QDeclarativeImageProvider>
namespace Tomahawk
{
class DeclarativeCoverArtProvider: public QDeclarativeImageProvider
{
public:
DeclarativeCoverArtProvider();
~DeclarativeCoverArtProvider();
QPixmap requestPixmap( const QString &id, QSize *size, const QSize &requestedSize );
};
}
#endif // DECLARATIVECOVERARTPROVIDER_H

View File

@@ -0,0 +1,58 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2012, Michael Zanetti <mzanetti@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 "DeclarativeView.h"
#include "playlist/PlayableItem.h"
#include "DeclarativeCoverArtProvider.h"
#include "utils/TomahawkUtilsGui.h"
#include <qdeclarative.h>
#include <QDeclarativeEngine>
#include <QDeclarativeContext>
namespace Tomahawk
{
DeclarativeView::DeclarativeView( QWidget *parent ):
QDeclarativeView( parent )
{
// Needed to make the QML contents scale with tomahawk
setResizeMode( QDeclarativeView::SizeRootObjectToView );
// This types seem to be needed everywhere anyways, lets the register here
qmlRegisterType<PlayableItem>( "tomahawk", 1, 0, "PlayableItem");
// qmlRegisterType<SearchFieldQmlProxy>("tomahawk", 1, 0, "SearchField");
// QML image providers will be deleted by the view
engine()->addImageProvider( "albumart", new DeclarativeCoverArtProvider() );
// Register the view itself to make it easy to invoke the view's slots from QML
rootContext()->setContextProperty( "mainView", this );
rootContext()->setContextProperty( "defaultFontSize", TomahawkUtils::defaultFontSize() );
rootContext()->setContextProperty( "defaultFontHeight", TomahawkUtils::defaultFontHeight() );
}
DeclarativeView::~DeclarativeView()
{
}
}

View File

@@ -0,0 +1,61 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2012, Michael Zanetti <mzanetti@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DECLARATIVEVIEW_H
#define DECLARATIVEVIEW_H
#include <QDeclarativeView>
class QAbstractItemModel;
/**
* @class This is the main class for Tomahawk's declarative views
*
* DeclarativeView inherits from QDeclarativeView and registers some
* common types, properties and functions used by all of Tomhawk's
* declarative views:
*
* Registered Types:
* - PlayableItem
*
* Set context properties:
* - mainView: This view, so you can invoke this view's slots from QML
* - defaultFontSize: system default font point size
* - defaultFontHeight: system default font pixel height
*
* It also registers an albumart image provider. You can access album art
* in QML with the source url "image://albumart/<coverid>".
* The cover id can be obtained by the CoverIdRole in PlayableModels
*
* After subclassing this, all you have to do is call setSource() to
* load the QML file and optionally setModel().
*/
namespace Tomahawk
{
class DeclarativeView: public QDeclarativeView
{
Q_OBJECT
public:
DeclarativeView(QWidget *parent = 0);
~DeclarativeView();
};
}
#endif

View File

@@ -40,7 +40,7 @@
#include "database/DatabaseResolver.h"
#include "playlist/dynamic/GeneratorFactory.h"
#include "playlist/dynamic/echonest/EchonestGenerator.h"
#include "playlist/dynamic/database/DatabaseGenerator.h"
//#include "playlist/dynamic/database/DatabaseGenerator.h"
#include "playlist/XspfUpdater.h"
#include "network/Servent.h"
#include "network/DbSyncConnection.h"
@@ -228,8 +228,8 @@ TomahawkApp::init()
tDebug() << "Init Echonest Factory.";
GeneratorFactory::registerFactory( "echonest", new EchonestFactory );
#endif
tDebug() << "Init Database Factory.";
GeneratorFactory::registerFactory( "database", new DatabaseFactory );
/* tDebug() << "Init Database Factory.";
GeneratorFactory::registerFactory( "database", new DatabaseFactory );*/
// Register shortcut handler for this platform
#ifdef Q_WS_MAC

View File

@@ -313,8 +313,13 @@ SourcesModel::appendGroups()
sc->setSortValue( 1 );
// browse section
GenericPageItem* radio = new GenericPageItem( this, m_browse, tr( "Radio" ), ImageRegistry::instance()->icon( RESPATH "images/station.svg" ),
boost::bind( &ViewManager::showRadioPage, ViewManager::instance() ),
boost::bind( &ViewManager::recentPlaysWidget, ViewManager::instance() ) );
radio->setSortValue( 2 );
LovedTracksItem* loved = new LovedTracksItem( this, m_browse );
loved->setSortValue( 2 );
loved->setSortValue( 3 );
GenericPageItem* networkActivity = new GenericPageItem( this, m_browse, tr( "Network Activity" ), TomahawkUtils::defaultPixmap( TomahawkUtils::NetworkActivity, TomahawkUtils::Original ),
boost::bind( &ViewManager::showNetworkActivityPage, ViewManager::instance() ),
@@ -341,7 +346,6 @@ SourcesModel::appendGroups()
inbox->setSortValue( 7 );
m_collectionsGroup = new GroupItem( this, m_rootItem, tr( "Friends" ), 4 );
m_cloudGroup = new GroupItem( this, m_rootItem, tr( "Cloud" ), 5 );
endInsertRows();

View File

@@ -163,7 +163,7 @@ CategoryAddItem::dropMimeData( const QMimeData* data, Qt::DropAction )
QString firstArtist;
// now we want to add each artist as a filter...
QList< dyncontrol_ptr > contrls;
/* QList< dyncontrol_ptr > contrls;
while ( !stream.atEnd() )
{
QString artist;
@@ -183,7 +183,7 @@ CategoryAddItem::dropMimeData( const QMimeData* data, Qt::DropAction )
QString name = firstArtist.isEmpty() ? tr( "New Station" ) : tr( "%1 Station" ).arg( firstArtist );
newpl->createNewRevision( uuid(), newpl->currentrevision(), newpl->type(), contrls );
newpl->setProperty( "newname", name );
connect( newpl.data(), SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ), this, SLOT( playlistToRenameLoaded() ) );
connect( newpl.data(), SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ), this, SLOT( playlistToRenameLoaded() ) );*/
ViewManager::instance()->show( newpl );
return true;
@@ -295,7 +295,7 @@ CategoryAddItem::parsedDroppedTracks( const QList< query_ptr >& tracks )
newpl->setMode( OnDemand );
// now we want to add each query as a song or similar artist filter...
QList< dyncontrol_ptr > controls;
/* QList< dyncontrol_ptr > controls;
foreach ( const Tomahawk::query_ptr& q, tracks )
{
dyncontrol_ptr c = newpl->generator()->createControl( "Song" );
@@ -303,7 +303,7 @@ CategoryAddItem::parsedDroppedTracks( const QList< query_ptr >& tracks )
controls << c;
}
newpl->createNewRevision( uuid(), newpl->currentrevision(), newpl->type(), controls );
newpl->createNewRevision( uuid(), newpl->currentrevision(), newpl->type(), controls );*/
ViewManager::instance()->show( newpl );
connect( newpl.data(), SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ), this, SLOT( playlistToRenameLoaded() ) );

View File

@@ -107,7 +107,7 @@ SourceItem::SourceItem( SourcesModel* mdl, SourceTreeItem* parent, const Tomahaw
}
if ( !stations.isEmpty() || source->isLocal() )
{
m_stations = new CategoryItem( model(), this, SourcesModel::StationsCategory, source->isLocal() );
m_stations = new CategoryItem( model(), this, SourcesModel::StationsCategory, false /* source->isLocal() */ );
onStationsAdded( stations );
}
@@ -338,14 +338,14 @@ void
SourceItem::playlistsAddedInternal( SourceTreeItem* parent, const QList< dynplaylist_ptr >& playlists )
{
QList< SourceTreeItem* > items;
int addOffset = playlists.first()->author()->isLocal() ? 1 : 0;
int addOffset = 0; //playlists.first()->author()->isLocal() ? 1 : 0;
int from = parent->children().count() - addOffset;
parent->beginRowsAdded( from, from + playlists.count() - 1 );
foreach ( const dynplaylist_ptr& p, playlists )
{
DynamicPlaylistItem* plItem = new DynamicPlaylistItem( model(), parent, p, parent->children().count() - addOffset );
// qDebug() << "Dynamic Playlist added:" << p->title() << p->creator() << p->info();
// tDebug() << "Dynamic Playlist added:" << p->title() << p->creator() << p->info();
p->loadRevision();
items << plItem;
@@ -515,7 +515,7 @@ SourceItem::onStationsAdded( const QList< dynplaylist_ptr >& stations )
// add the category too
int cur = children().count();
beginRowsAdded( cur, cur );
m_stations = new CategoryItem( model(), this, SourcesModel::StationsCategory, source()->isLocal() );
m_stations = new CategoryItem( model(), this, SourcesModel::StationsCategory, false /* source()->isLocal() */ );
endRowsAdded();
}