mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-09-06 20:20:41 +02:00
Compare commits
567 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
23b477da19 | ||
|
1131840a23 | ||
|
439730ee8a | ||
|
745bbb8afb | ||
|
6198d55940 | ||
|
9886a15760 | ||
|
ec6ec7833f | ||
|
0b4c3cde67 | ||
|
eb84ddc699 | ||
|
26f581dc97 | ||
|
cee26a77c3 | ||
|
d65de01847 | ||
|
c161d5dc3d | ||
|
1d9b76efbc | ||
|
6bb9ec7de3 | ||
|
53ba4aae93 | ||
|
952120a260 | ||
|
490f736a93 | ||
|
a4fee407a4 | ||
|
6378a1658d | ||
|
59003b88e9 | ||
|
c946bd9b8d | ||
|
02f8eac1b3 | ||
|
75a1fce2d8 | ||
|
a7152f83f4 | ||
|
6ab35323e8 | ||
|
b402347bee | ||
|
1252b6618d | ||
|
ff8e905599 | ||
|
cf93741079 | ||
|
45519110b9 | ||
|
33cca96f00 | ||
|
8e0dcc69ed | ||
|
7f8bb31e23 | ||
|
15704d8fbf | ||
|
1554b638f6 | ||
|
7219f1035a | ||
|
cb3889f37e | ||
|
6ad4a8ce76 | ||
|
fbc8803c37 | ||
|
0be198fc49 | ||
|
4998852e5a | ||
|
179dac3442 | ||
|
22aa75f4bb | ||
|
b0e352a5f5 | ||
|
d41a9d8dce | ||
|
f742066a7e | ||
|
419a3f1cd2 | ||
|
a381c5e3f1 | ||
|
04e5b338c4 | ||
|
7daebc655a | ||
|
546f54f196 | ||
|
cde07bc2b8 | ||
|
09026a33fe | ||
|
b4de7d6e90 | ||
|
be364d582a | ||
|
1b1b88551d | ||
|
8d80b1e113 | ||
|
9fa387e102 | ||
|
7b6987418c | ||
|
2dac747a90 | ||
|
402a7ed6d4 | ||
|
0403301c9a | ||
|
10712c7efb | ||
|
1c62ec3358 | ||
|
612d8874df | ||
|
56dd8e2572 | ||
|
3adeee4140 | ||
|
d829389e4e | ||
|
1ecfc8aa9e | ||
|
a4505930b5 | ||
|
a6f8dc1830 | ||
|
ec17293d3d | ||
|
00e8d25da6 | ||
|
483fa38f7b | ||
|
193d4b6a96 | ||
|
ef00f9c21a | ||
|
42c0199f53 | ||
|
61a99449f3 | ||
|
6ed0879c7c | ||
|
53ad9739ad | ||
|
8e48956c87 | ||
|
776b1c9f2e | ||
|
42c03fd9ba | ||
|
7a2d1cadec | ||
|
21beba0881 | ||
|
277edfe8ca | ||
|
e48b4096b9 | ||
|
0db80a9a61 | ||
|
e0bff794ab | ||
|
47fc81b8c0 | ||
|
c002eaf11c | ||
|
c21de815a6 | ||
|
97da93afd5 | ||
|
4002716159 | ||
|
ab882608d8 | ||
|
aad713d638 | ||
|
a5f1e63ae3 | ||
|
be67d85f91 | ||
|
3debc10943 | ||
|
68812eb3a5 | ||
|
257395a1fe | ||
|
a928833373 | ||
|
6b69e50731 | ||
|
8817aa65c4 | ||
|
e5b418ac24 | ||
|
63a3339ca5 | ||
|
8128f1ea48 | ||
|
e0a6331142 | ||
|
68448db757 | ||
|
eaf1b58df6 | ||
|
187602c424 | ||
|
426dd354eb | ||
|
cb5916b42a | ||
|
4b29d34278 | ||
|
67fc355f16 | ||
|
ace775d6a6 | ||
|
4d43577eda | ||
|
8f7e2f1f8a | ||
|
96f28f53ce | ||
|
c2b54683d3 | ||
|
5afc5b0909 | ||
|
54e8ee172b | ||
|
ceb856acb2 | ||
|
69c2d603b8 | ||
|
bd0c3e29eb | ||
|
bfd5690af7 | ||
|
6e91080311 | ||
|
ed5cb1d93d | ||
|
1a5406bd44 | ||
|
5bf09cced0 | ||
|
bf48967305 | ||
|
611b108eb9 | ||
|
7efa2fd781 | ||
|
70706c9eb1 | ||
|
aaf4ced6db | ||
|
34196ec001 | ||
|
3d33c68778 | ||
|
bf5fcbd0b6 | ||
|
2ee369393c | ||
|
8824466840 | ||
|
d62bd306be | ||
|
29ba51b32c | ||
|
f074d4dea7 | ||
|
53e03f90e7 | ||
|
feaaa6c7cd | ||
|
f79744fb72 | ||
|
18d38f5a46 | ||
|
df4aa8ce13 | ||
|
d6fd70f1f1 | ||
|
9d90c07b70 | ||
|
bb69caed62 | ||
|
5300ddae2c | ||
|
4be8717525 | ||
|
30447cee2b | ||
|
b2db38db09 | ||
|
74972ca5e1 | ||
|
36ae09b698 | ||
|
06dca3111f | ||
|
10cb39dd2e | ||
|
5678f61211 | ||
|
1d74242670 | ||
|
ff08efbdf8 | ||
|
d1e97b1dec | ||
|
4145bf14f8 | ||
|
1af86b3257 | ||
|
8f7671ae65 | ||
|
5b3c297306 | ||
|
c014650628 | ||
|
dd28657dbc | ||
|
9b53ffc952 | ||
|
508c7ffc80 | ||
|
088d7ed3ae | ||
|
4926fcb239 | ||
|
c66300aa67 | ||
|
5fa5532fd2 | ||
|
0be6ec1a40 | ||
|
776c919445 | ||
|
6bf5d70b5c | ||
|
e7eea28d84 | ||
|
60ad0a016f | ||
|
786a5f4cd5 | ||
|
2203c7afcb | ||
|
ac5774a486 | ||
|
3df5ab3a41 | ||
|
ea7a21518d | ||
|
82705f63f7 | ||
|
6e84706d3e | ||
|
0e5e4e96e5 | ||
|
d875b8dccf | ||
|
99eae3c542 | ||
|
2781fafdf4 | ||
|
1b9b706fce | ||
|
2066214aef | ||
|
0492bbded4 | ||
|
865b7db1b8 | ||
|
13c87e0acc | ||
|
42640ef259 | ||
|
aa5e0fcecb | ||
|
6166eac485 | ||
|
0aade324ad | ||
|
d302850d51 | ||
|
d2f9d2d79c | ||
|
ae8ddb2144 | ||
|
d833f5fef2 | ||
|
8c671568bb | ||
|
7a4e4410a1 | ||
|
df56877403 | ||
|
e27396be63 | ||
|
082d86a127 | ||
|
1e89558c78 | ||
|
af5fe4b965 | ||
|
bd4e19fa32 | ||
|
d8311c0e41 | ||
|
555d3587d7 | ||
|
0cf881359c | ||
|
63ee2cbd59 | ||
|
a59971a74a | ||
|
7723cade58 | ||
|
815ec7cbe2 | ||
|
022efd5503 | ||
|
81d2278857 | ||
|
8dc56abbf6 | ||
|
a95276d960 | ||
|
f4bd8959e1 | ||
|
2b6da82805 | ||
|
9cc6c1fb35 | ||
|
cc62a458f5 | ||
|
b2ac6acb6e | ||
|
a883c7135f | ||
|
ff007d8595 | ||
|
a0b7c6e504 | ||
|
da8fd58aaa | ||
|
3ef99fbb32 | ||
|
0f45146ada | ||
|
bcd33932d0 | ||
|
4ea22ba054 | ||
|
8ac833bf97 | ||
|
7b62c3ed14 | ||
|
5c2cebb423 | ||
|
e8a48aafe4 | ||
|
d2f8bc2784 | ||
|
447c6c0217 | ||
|
d098c1cba7 | ||
|
53bdd2de6b | ||
|
d590fa4faa | ||
|
95e6efd26d | ||
|
7f64f25e59 | ||
|
812ca58674 | ||
|
a2406e8595 | ||
|
88dfad3298 | ||
|
fc4e42befa | ||
|
db56757bc8 | ||
|
2d6b8de76b | ||
|
81a406d1b5 | ||
|
b3b47398bc | ||
|
ddb66a5cfe | ||
|
b3dc65997c | ||
|
d800323afe | ||
|
980f56dbcf | ||
|
587568e026 | ||
|
18d488b0f1 | ||
|
aafab2e016 | ||
|
0a4a281027 | ||
|
c248ebb9e0 | ||
|
251ed6e555 | ||
|
2555ab7766 | ||
|
d14afb5a8f | ||
|
ca025e41b0 | ||
|
ca307d6922 | ||
|
0d2dade6da | ||
|
241a3a075b | ||
|
1a88203247 | ||
|
d6bb90fc25 | ||
|
f5dc808d4c | ||
|
27879a814e | ||
|
cc9687c407 | ||
|
9f9d01618e | ||
|
ce10b501a8 | ||
|
d52333893f | ||
|
6216ab1a79 | ||
|
d3f32f73c9 | ||
|
c3eca392f2 | ||
|
0f82e54f2a | ||
|
482b0288e7 | ||
|
7597dd5554 | ||
|
a2b20fa49e | ||
|
1227d40c26 | ||
|
090cc66fc7 | ||
|
d13f3f3c45 | ||
|
f3b660f123 | ||
|
e0ad9d48d8 | ||
|
aca0f51342 | ||
|
252b809fe4 | ||
|
4e83dbac2e | ||
|
9d92e2689c | ||
|
edd3759126 | ||
|
51e7fb4c18 | ||
|
9a9fac59e5 | ||
|
408d4486d2 | ||
|
45cc595010 | ||
|
7cd6af4933 | ||
|
d7629ff626 | ||
|
b4ccf7d6ea | ||
|
c4f48abf77 | ||
|
6b36f3a737 | ||
|
ff0c3d4bef | ||
|
4939ffb6d3 | ||
|
8a4caa4118 | ||
|
6b7dbedc45 | ||
|
371b8cff0e | ||
|
ee67518d47 | ||
|
e9c4d8118b | ||
|
6b6475f767 | ||
|
ad40c8efa9 | ||
|
42cf9375a6 | ||
|
268537bdc6 | ||
|
797fa8d21c | ||
|
91df437e62 | ||
|
fe7c1b1d73 | ||
|
81a9da23da | ||
|
b48b0127f8 | ||
|
da47c00813 | ||
|
7ea790d40b | ||
|
6af1be8fa7 | ||
|
5350330141 | ||
|
b37e0d801e | ||
|
84faa1671c | ||
|
530d5402a1 | ||
|
3e06803162 | ||
|
3de4042d6e | ||
|
004d84f1b0 | ||
|
62db235b3c | ||
|
f1483bfe3f | ||
|
89202ae445 | ||
|
1e579bc238 | ||
|
e11b1515a9 | ||
|
25f2c2db66 | ||
|
df7fafced1 | ||
|
e9a33e3ed4 | ||
|
b5090d2873 | ||
|
86e201673f | ||
|
0f3cfb210c | ||
|
74fdd6500c | ||
|
2e1a1385e1 | ||
|
b15622f275 | ||
|
02da2cba8d | ||
|
00662c2d8d | ||
|
5fc1d68a3c | ||
|
0a815e06df | ||
|
3e678c55ee | ||
|
250c76b53c | ||
|
b070ed8f82 | ||
|
03a84c574e | ||
|
58ee8b35f4 | ||
|
6ef3dc30af | ||
|
1da4cb83ca | ||
|
27fcb1c43f | ||
|
8c0b982852 | ||
|
9a2594c644 | ||
|
f8b2d792df | ||
|
f199f08288 | ||
|
183d7be141 | ||
|
213edc6d12 | ||
|
4ffbb06baa | ||
|
c808b0989b | ||
|
aa104fce10 | ||
|
991bacd667 | ||
|
b6109b9bf9 | ||
|
ca08729d24 | ||
|
4c6ed3d368 | ||
|
b951f1f4bc | ||
|
20df5ded1f | ||
|
de5ddc925d | ||
|
cc104598db | ||
|
e84316c325 | ||
|
efddc70b7f | ||
|
f300b4f617 | ||
|
062addd7e8 | ||
|
cfb04bb1d7 | ||
|
830d2c9391 | ||
|
d4d45220d1 | ||
|
c79a671802 | ||
|
a6113204d2 | ||
|
701c5ff61c | ||
|
a0d988e63a | ||
|
ee4186c51d | ||
|
795e525889 | ||
|
8c10a0c821 | ||
|
9d0c8e1b03 | ||
|
606a86e016 | ||
|
bd33824202 | ||
|
cae5e75f2a | ||
|
2b1df0e664 | ||
|
cb4816d662 | ||
|
1bbfe1599a | ||
|
13f8ad5daa | ||
|
ba23f701f8 | ||
|
0c1a10ec6a | ||
|
af0504fe41 | ||
|
a87b0268d4 | ||
|
72b326a3be | ||
|
1637b325d7 | ||
|
91feefc433 | ||
|
c3a1ee84a1 | ||
|
d440061228 | ||
|
8215e5be00 | ||
|
5e3d14c950 | ||
|
e7be3ac8a2 | ||
|
3fd379e81c | ||
|
8b63388ead | ||
|
7b7dffbf0a | ||
|
e8286b2995 | ||
|
926f42ed1f | ||
|
b9b24e8161 | ||
|
b362e2a9bd | ||
|
008b7e32a6 | ||
|
baaddf22a4 | ||
|
cad21c1712 | ||
|
b3549ac945 | ||
|
9723d7b4ce | ||
|
26f8270372 | ||
|
652a506922 | ||
|
3de5670de7 | ||
|
9d89f8a12e | ||
|
e974c08883 | ||
|
bc3c65a027 | ||
|
08fb69abb9 | ||
|
945cf58e78 | ||
|
c5731c20d5 | ||
|
a861943222 | ||
|
09f47fe11c | ||
|
e2f9dad471 | ||
|
e38be974e4 | ||
|
6c9ec62e7e | ||
|
f1ad4922ab | ||
|
f34dc1b75f | ||
|
35da957765 | ||
|
9c1100d180 | ||
|
d8bc1cc11d | ||
|
11f2c24966 | ||
|
a0c69ac45a | ||
|
785b616e07 | ||
|
df0fbbc96e | ||
|
1d82d0b80b | ||
|
1c4baee0d4 | ||
|
6172d50710 | ||
|
85c7b16fa1 | ||
|
d3afba1a90 | ||
|
2c86361190 | ||
|
b9e42a03e9 | ||
|
8b7dba77aa | ||
|
2a721e89a5 | ||
|
c42054ea5c | ||
|
073f6f5b7a | ||
|
2438485433 | ||
|
812b4f6ee3 | ||
|
0807a3ce4e | ||
|
c41c475852 | ||
|
cba83e5225 | ||
|
1ba923fd21 | ||
|
5272cd5f9e | ||
|
04a1f4e595 | ||
|
9a6850def5 | ||
|
39da04b843 | ||
|
8e4ccbee6d | ||
|
4aed8bf75e | ||
|
3e00b5c0e6 | ||
|
f64436f9bb | ||
|
da2308db33 | ||
|
45b6340952 | ||
|
ec4ac5210b | ||
|
aa5e9ea4f2 | ||
|
4c85b1d92d | ||
|
8798f2103e | ||
|
4497849d07 | ||
|
9d42209e96 | ||
|
2185b3ae5a | ||
|
2dee4ccca3 | ||
|
25be3d4ad7 | ||
|
cb10c59215 | ||
|
af2336b32f | ||
|
e4ab92b81f | ||
|
6da9b2937c | ||
|
30a4019c65 | ||
|
b006c56876 | ||
|
3f7c08fdb8 | ||
|
2d8ca57fee | ||
|
7c417f1076 | ||
|
a88816168b | ||
|
b12aba360c | ||
|
c35b63da71 | ||
|
24ad7ac701 | ||
|
641d28c932 | ||
|
8b972ca62e | ||
|
748c3106ea | ||
|
29c8b0bea9 | ||
|
8e16445b49 | ||
|
a129a54d1b | ||
|
e790fab9ae | ||
|
812f8cb250 | ||
|
481b16be89 | ||
|
c723160883 | ||
|
17f0606139 | ||
|
1bd7c18715 | ||
|
4beee033ac | ||
|
3ded897d55 | ||
|
bf49d2bec5 | ||
|
7c963e4c37 | ||
|
e35b2bcf43 | ||
|
7ca0786f02 | ||
|
045e4df526 | ||
|
02dee0ec06 | ||
|
8c5ec2bc23 | ||
|
c3995a0cc8 | ||
|
c2f3cff83a | ||
|
e99439ecca | ||
|
97c8b93d3c | ||
|
050503e8b5 | ||
|
c53800f0d3 | ||
|
fcc6f5c966 | ||
|
2e3785f92b | ||
|
2156466762 | ||
|
266de41624 | ||
|
bbeeac9935 | ||
|
99ef263ba2 | ||
|
f3a50bedbd | ||
|
2841593a85 | ||
|
c47d52b144 | ||
|
d03cb674c9 | ||
|
17eeae9a8f | ||
|
64fd91c0ca | ||
|
145cb67390 | ||
|
2045dcfaf7 | ||
|
d09fe0a5d6 | ||
|
fd2d0a53ed | ||
|
23f47f825a | ||
|
b211263ced | ||
|
ecab5b41b0 | ||
|
914f8ccdbb | ||
|
daff8101a0 | ||
|
3a822f22e9 | ||
|
d025e8f512 | ||
|
6b6fd9a6e2 | ||
|
b2a7b23590 | ||
|
656f621868 | ||
|
bafcb1c07e | ||
|
ad88242d3a | ||
|
fd0ee87208 | ||
|
65eec14a48 | ||
|
2dd0efc310 | ||
|
7b6c183bf7 | ||
|
541ad42b86 | ||
|
3f25010cd9 | ||
|
e7259f619e | ||
|
abd2957e0e | ||
|
e468ad2687 | ||
|
7ad06f5ee2 | ||
|
6cd680c388 | ||
|
3490975de5 | ||
|
aaebfe39c5 | ||
|
a52998d766 | ||
|
74ec938037 | ||
|
7a1ef2eba7 | ||
|
f42a5f461c | ||
|
2704f1261d | ||
|
91b562a98e |
@@ -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()
|
||||
|
@@ -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})
|
||||
|
145
data/images/inputfield-border.svg
Normal file
145
data/images/inputfield-border.svg
Normal 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 |
14
data/images/station-artist.svg
Normal file
14
data/images/station-artist.svg
Normal 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 |
18
data/images/station-genre.svg
Normal file
18
data/images/station-genre.svg
Normal 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 |
19
data/images/station-year.svg
Normal file
19
data/images/station-year.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 11 KiB |
21
data/qml/DeclarativeHeader.qml
Normal file
21
data/qml/DeclarativeHeader.qml
Normal 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
65
data/qml/QmlGridView.qml
Normal 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
35
data/qml/SpinnerTest.qml
Normal 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
165
data/qml/StationView.qml
Normal 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
|
||||
}
|
||||
}
|
74
data/qml/stations/CreateByArtist.qml
Normal file
74
data/qml/stations/CreateByArtist.qml
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
94
data/qml/stations/CreateByGenre.qml
Normal file
94
data/qml/stations/CreateByGenre.qml
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
89
data/qml/stations/CreateByYear.qml
Normal file
89
data/qml/stations/CreateByYear.qml
Normal 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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
79
data/qml/stations/StationConfig.qml
Normal file
79
data/qml/stations/StationConfig.qml
Normal 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
|
||||
}
|
||||
|
||||
}
|
65
data/qml/stations/StationCreatorPage1.qml
Normal file
65
data/qml/stations/StationCreatorPage1.qml
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
25
data/qml/stations/StationCreatorPage2.qml
Normal file
25
data/qml/stations/StationCreatorPage2.qml
Normal 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)
|
||||
}
|
||||
|
||||
}
|
37
data/qml/stations/StationItem.qml
Normal file
37
data/qml/stations/StationItem.qml
Normal 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
|
||||
}
|
||||
|
||||
}
|
58
data/qml/tomahawkimports/ArtistView.qml
Normal file
58
data/qml/tomahawkimports/ArtistView.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
52
data/qml/tomahawkimports/BusyIndicator.qml
Normal file
52
data/qml/tomahawkimports/BusyIndicator.qml
Normal 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
|
||||
}
|
||||
}
|
44
data/qml/tomahawkimports/Button.qml
Normal file
44
data/qml/tomahawkimports/Button.qml
Normal 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();
|
||||
}
|
||||
}
|
135
data/qml/tomahawkimports/CoverFlip.qml
Normal file
135
data/qml/tomahawkimports/CoverFlip.qml
Normal 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 }
|
||||
}
|
||||
|
||||
}
|
84
data/qml/tomahawkimports/CoverFlow.qml
Normal file
84
data/qml/tomahawkimports/CoverFlow.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
194
data/qml/tomahawkimports/CoverImage.qml
Normal file
194
data/qml/tomahawkimports/CoverImage.qml
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
225
data/qml/tomahawkimports/DoubleSlider.qml
Normal file
225
data/qml/tomahawkimports/DoubleSlider.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
223
data/qml/tomahawkimports/FlexibleHeader.qml
Normal file
223
data/qml/tomahawkimports/FlexibleHeader.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
7
data/qml/tomahawkimports/HeaderLabel.qml
Normal file
7
data/qml/tomahawkimports/HeaderLabel.qml
Normal file
@@ -0,0 +1,7 @@
|
||||
import QtQuick 1.1
|
||||
|
||||
Text {
|
||||
color: "white"
|
||||
font.pointSize: defaultFontSize + 5
|
||||
font.bold: true
|
||||
}
|
114
data/qml/tomahawkimports/InputBubble.qml
Normal file
114
data/qml/tomahawkimports/InputBubble.qml
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
162
data/qml/tomahawkimports/InputField.qml
Normal file
162
data/qml/tomahawkimports/InputField.qml
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
35
data/qml/tomahawkimports/PushButton.qml
Normal file
35
data/qml/tomahawkimports/PushButton.qml
Normal 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()
|
||||
}
|
||||
}
|
43
data/qml/tomahawkimports/RoundedButton.qml
Normal file
43
data/qml/tomahawkimports/RoundedButton.qml
Normal 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()
|
||||
}
|
||||
}
|
71
data/qml/tomahawkimports/ScrollBar.qml
Normal file
71
data/qml/tomahawkimports/ScrollBar.qml
Normal 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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
80
data/qml/tomahawkimports/TagCloud.qml
Normal file
80
data/qml/tomahawkimports/TagCloud.qml
Normal 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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
data/qml/tomahawkimports/ToggleViewButtons.qml
Normal file
34
data/qml/tomahawkimports/ToggleViewButtons.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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>
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
};
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
};
|
||||
|
@@ -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}
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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();
|
||||
|
@@ -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 )
|
||||
{
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
|
@@ -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 );
|
||||
|
@@ -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 )
|
||||
{
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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();
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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;
|
||||
|
@@ -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 )
|
||||
{
|
||||
|
@@ -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 ); }
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -23,7 +23,7 @@
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
DynamicPlaylistRevision::DynamicPlaylistRevision(const PlaylistRevision &other)
|
||||
DynamicPlaylistRevision::DynamicPlaylistRevision( const PlaylistRevision &other )
|
||||
{
|
||||
revisionguid = other.revisionguid;
|
||||
oldrevisionguid = other.oldrevisionguid;
|
||||
|
@@ -29,7 +29,7 @@ struct DLLEXPORT DynamicPlaylistRevision : PlaylistRevision
|
||||
{
|
||||
public:
|
||||
|
||||
QList< dyncontrol_ptr > controls;
|
||||
QVariantList controls;
|
||||
Tomahawk::GeneratorMode mode;
|
||||
QString type;
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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 );
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
|
||||
|
268
src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.cpp
Normal file
268
src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.cpp
Normal 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 );
|
||||
|
||||
}
|
||||
}
|
105
src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.h
Normal file
105
src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.h
Normal 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
|
142
src/libtomahawk/widgets/DeclarativeCoverArtProvider.cpp
Normal file
142
src/libtomahawk/widgets/DeclarativeCoverArtProvider.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
23
src/libtomahawk/widgets/DeclarativeCoverArtProvider.h
Normal file
23
src/libtomahawk/widgets/DeclarativeCoverArtProvider.h
Normal 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
|
58
src/libtomahawk/widgets/DeclarativeView.cpp
Normal file
58
src/libtomahawk/widgets/DeclarativeView.cpp
Normal 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()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
61
src/libtomahawk/widgets/DeclarativeView.h
Normal file
61
src/libtomahawk/widgets/DeclarativeView.h
Normal 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
|
@@ -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
|
||||
|
@@ -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();
|
||||
|
@@ -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() ) );
|
||||
|
@@ -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();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user